# Missions: Goal-Oriented Autonomous Threads

**Date:** 2026-03-24
**Status:** Design → Implementation
**Depends on:** Engine v2 Phases 1-6 (all done)

---

## What a Mission Is

A Mission is a **Project with intent** — a persistent goal that spawns threads, accumulates knowledge, adapts its approach, and tracks progress toward completion.

Unlike routines (fixed prompt, stateless, mechanical), Missions evolve:
- Each thread is informed by all previous threads via Project-scoped MemoryDocs
- The prompt is generated (not fixed) based on accumulated knowledge
- The approach changes when something fails
- The Mission can detect completion

## Core Types

```rust
pub struct Mission {
    pub id: MissionId,
    pub project_id: ProjectId,
    pub goal: String,
    pub status: MissionStatus,         // Active, Paused, Completed, Failed

    // Trigger
    pub cadence: MissionCadence,       // Cron, OnEvent, Manual

    // Evolving strategy
    pub current_focus: Option<String>, // what the next thread should work on
    pub approach_history: Vec<String>, // what we've tried

    // Progress
    pub success_criteria: Option<String>,
    pub thread_history: Vec<ThreadId>,

    // Budget
    pub max_threads_per_day: u32,
    pub max_total_threads: Option<u32>,
}
```

Already defined in `crates/ironclaw_engine/src/types/mission.rs`.

## Trigger Types

The engine defines trigger *types*. The bridge implements the actual infrastructure:

| Trigger | Engine type | Bridge implementation |
|---|---|---|
| Cron schedule | `MissionCadence::Cron { expression, timezone }` | Tokio interval task, cron parser |
| Channel message | `MissionCadence::OnEvent { event_pattern }` | Regex match in `handle_message` before routing |
| System event | `MissionCadence::OnSystemEvent { source, event_type }` | Match events from `event_emit` tool |
| Webhook | `MissionCadence::Webhook { path, secret }` | Register HTTP endpoint on webhook server |
| Manual | `MissionCadence::Manual` | `mission_fire` tool or API call |

**Webhook-based integrations** (GitHub, email, etc.) use the generic `Webhook` cadence. The webhook payload is stored as `mission.last_trigger_payload` and injected into the thread's context:

```python
# Inside the mission's thread, the trigger payload is accessible:
payload = state["trigger_payload"]
# For a GitHub webhook: payload["action"], payload["issue"]["title"], etc.
# For email: payload["from"], payload["subject"], payload["body"]
```

This means GitHub issues, PRs, email, Slack events, etc. all work through the same webhook mechanism — no special-casing in the engine.

## Architecture

```
MissionManager (runtime/mission.rs)
  │
  ├── Cron ticker (tokio interval task)
  │   └── For each Active mission with Cron cadence:
  │       check if due → spawn_mission_thread()
  │
  ├── Event listener (optional)
  │   └── Match event patterns → spawn_mission_thread()
  │
  └── spawn_mission_thread(mission):
      1. Load Project's MemoryDocs (lessons, playbooks, issues)
      2. Generate meta-prompt from goal + focus + docs + approach history
      3. ThreadManager.spawn_thread_with_history(meta_prompt, ...)
      4. join_thread() → outcome
      5. Reflection runs automatically (ThreadManager handles this)
      6. Update mission: current_focus, approach_history, thread_history
      7. Check success criteria → maybe mark Completed
```

## Meta-Prompt Generation

The key differentiator from routines. Before each thread, the Mission builds a prompt:

```
Goal: {mission.goal}

## What we know (from prior threads)
{retrieved lessons, playbooks, issues from Project MemoryDocs}

## Current focus
{mission.current_focus or "Determine the first step toward the goal"}

## Previous approaches
{mission.approach_history — what we've tried and what happened}

## Instructions
Based on the above context, take the next step toward the goal.
Use tools to gather information, analyze data, or take actions.
When you've completed this step, call FINAL() with:
1. What you accomplished
2. What you recommend as the next focus
3. Whether the goal has been achieved
```

The response is parsed to extract:
- Accomplishment → becomes a Summary doc
- Next focus → updates `mission.current_focus`
- Goal achieved → transitions mission to Completed

## Implementation Plan

### Step 1: MissionManager with cron trigger

`crates/ironclaw_engine/src/runtime/mission.rs` — already has types, needs execution logic:

- `MissionManager::new(thread_manager, store)` — holds refs to spawn threads
- `MissionManager::start_cron_ticker()` — spawns a tokio task that checks missions every 60s
- `MissionManager::spawn_mission_thread(mission)` — the core: build prompt, spawn thread, process result
- `MissionManager::create_mission(goal, cadence, project_id)` — creates and stores a mission
- `MissionManager::pause/resume/cancel_mission(id)` — lifecycle management

### Step 2: Meta-prompt builder

`crates/ironclaw_engine/src/runtime/mission_prompt.rs`:

- Load MemoryDocs from project via RetrievalEngine
- Build the structured prompt from mission state + docs
- Parse the thread's FINAL() response to extract next_focus and goal_status

### Step 3: Wire into bridge router

`src/bridge/router.rs`:

- `EngineState` holds `Arc<MissionManager>`
- On init, load existing missions from store, start cron ticker
- Unblock `mission_create`, `mission_list`, `mission_pause` tools (or expose as special functions in CodeAct)

### Step 4: Mission tools for CodeAct

The model can create and manage missions from code:

```python
# Create a mission
mission_create(
    goal="Monitor and improve API response times",
    cadence="0 9 * * *",  # daily at 9am
    success_criteria="p95 latency under 200ms for 7 days"
)

# List missions
missions = mission_list()

# Pause/resume
mission_pause(id="...")
mission_resume(id="...")
```

### Step 5: Progress tracking + adaptation

After each mission thread completes:
1. Parse FINAL() for next_focus recommendation
2. If the same error appears 3+ times → change approach (add to approach_history, clear current_focus, let the next thread try fresh)
3. If success_criteria is met → mark Completed, notify user
4. If max_threads exceeded → mark Failed, notify user

### Step 6: Mission persistence

Missions stored via `Store::save_mission/load_mission/list_missions` (trait methods already defined). The HybridStore needs to persist missions to workspace (like MemoryDocs) so they survive restarts.

## How This Replaces Routines

| Routine feature | Mission equivalent |
|---|---|
| Cron schedule | `MissionCadence::Cron("0 9 * * *")` |
| Event trigger | `MissionCadence::OnEvent { pattern }` |
| Manual fire | `MissionCadence::Manual` + `mission_fire(id)` |
| Fixed prompt | Meta-prompt generated from goal + project docs |
| Notification on completion | Thread outcome → channel notification |
| Lightweight execution | Thread with `max_iterations: 1` |
| Full job execution | Thread with full iteration budget |
| Guardrails (max concurrent, timeout) | `ThreadConfig` on spawned threads |

The v1 `RoutineEngine` can stay for backward compatibility. New missions use the engine v2 `MissionManager`.

## Example: Daily Tech News Briefing

```python
mission_create(
    goal="Deliver a daily tech news briefing covering AI, crypto, and software engineering",
    cadence="0 8 * * *",
    success_criteria=None  # ongoing, never "done"
)
```

Thread 1 (day 1):
- Searches for news, summarizes top stories
- Reflection: Playbook("Use web_search with freshness='pd', then llm_context for details")

Thread 2 (day 2):
- Uses the Playbook from day 1 (faster, more efficient)
- Reflection: Lesson("Bloomberg paywalled, use Reuters/AP instead")

Thread 3 (day 3):
- Avoids Bloomberg (learned), uses Reuters
- Reflection: Lesson("User prefers bullet points over paragraphs")

Each day the briefing improves because the Mission accumulates knowledge.

## Example: Improve Test Coverage

```python
mission_create(
    goal="Increase IronClaw test coverage from 60% to 80%",
    cadence="0 10 * * 1-5",  # weekdays at 10am
    success_criteria="coverage >= 80% in cargo tarpaulin report"
)
```

Thread 1: Runs `cargo tarpaulin`, identifies uncovered modules
Thread 2: Writes tests for the most uncovered module
Thread 3: Runs coverage again, checks progress, picks next module
Thread N: Coverage hits 80% → Mission Completed

## What Already Exists vs What's New

| Component | Status |
|---|---|
| `Mission` type + `MissionCadence` + `MissionStatus` | ✅ Exists |
| `Store` trait: save/load/list/update missions | ✅ Exists |
| `MissionManager` struct | ✅ Exists (shell) |
| `ThreadManager.spawn_thread()` | ✅ Exists |
| `RetrievalEngine` (project-scoped doc retrieval) | ✅ Exists |
| Reflection pipeline (produces docs) | ✅ Exists |
| `HybridStore` persistence for MemoryDocs | ✅ Exists |
| Cron ticker loop | ❌ NEW |
| Meta-prompt generation from mission state + docs | ❌ NEW |
| FINAL() response parsing for next_focus | ❌ NEW |
| Progress tracking + adaptation | ❌ NEW |
| Mission persistence to workspace | ❌ NEW (extend HybridStore) |
| Mission tools for CodeAct | ❌ NEW |
