# Workflow: compass:run

You are the orchestrator. Mission: execute the plan stage-by-stage with parallel Colleagues, track progress, handle failures.

**Principles:** Orchestrator does NOT write documents — only dispatch, monitor, report. Each Colleague runs in fresh context. Never stop after one Colleague — always continue to the next. Escalate failures, don't hide them.

**Purpose**: Execute the collab plan stage-by-stage. Each Colleague runs in a fresh context window with only its briefing. Track status, handle escalation, run post-stage consistency checks.

**Input**: Latest `plan.json` from session
**Output**: Documents generated by each Colleague

---

Apply the UX rules from `core/shared/ux-rules.md`.

---

## Step 0 — Resolve active project

Apply the shared snippet from `core/shared/resolve-project.md`. It sets up `$PROJECT_ROOT`, `$CONFIG`, and `$PROJECT_NAME` for downstream steps and prints the "Using: <name>" banner.

From `$CONFIG`, extract `lang`, `spec_lang`, `naming`, and `model_routing`.
If config missing → prompt user to run `/compass:init` first.

All user-facing messages in `lang`. All generated document content in `spec_lang`. AI translates runtime per ux-rules Language Policy.

---

## Step 1: Load plan

- Scan session directory for `plan.json` (newest by mtime wins if multiple exist)
- Run `compass-cli validate plan <path-to-plan.json>` before any other check. If exit non-zero → halt here, surface the validator's violations, and tell the user to re-run `/compass:plan`. Do NOT attempt to auto-fix a malformed plan in this workflow.
- Validate plan (in-workflow sanity pass, in addition to the CLI validator):
  - `plan_version` is exactly `"1.0"`
  - `memory_ref` is present (canonical: `.compass/.state/project-memory.json`)
  - Every task has a non-empty `context_pointers` array (1..30 entries)
  - All `colleague` values exist in `~/.compass/colleagues/manifest.json`
  - Each stage has at least one task
  - Dependencies reference valid task IDs from earlier stages
- If no `plan.json` found → tell user to run `/compass:plan` first, stop here
- If validation fails → show which entries are invalid, ask user to fix or skip

### 1a. Read auto-chain mode + complexity

```bash
AUTO_MODE=$(jq -r '.auto_mode // "manual"' "$SESSION_DIR/context.json" 2>/dev/null)
COMPLEXITY=$(jq -r '.complexity // "medium"' "$SESSION_DIR/context.json" 2>/dev/null)
STAGE_COUNT=$(jq -r '.stages // [] | length' "$SESSION_DIR/plan.json" 2>/dev/null)
```

`AUTO_MODE`:
- `"auto"` → skip end-of-workflow gate; auto-invoke `/compass:check` after run completes
- `"manual"` or missing → show 3-option gate at end

### 1b. MINIMAL mode selection

Decide execution flow from complexity + stages:

- **MINIMAL mode** — trigger when `STAGE_COUNT ≤ 2` AND `COMPLEXITY ∈ {"small", "medium"}`. Single-stage or 2-stage plans don't need per-stage review gates between stages.
- **FULL mode** — otherwise. Keep existing per-stage review behavior.

Print: `✓ Run mode: <minimal|full>`.

**MINIMAL mode changes**:
- Step 2 confirm: unchanged (still ask once before starting)
- Step 3 execution: run all stages sequentially without per-stage pause. Show progress inline.
- Step 4 escalation: unchanged (only trigger on actual failures)
- Step 6 report + Step 7 hand-off: unchanged.

**FULL mode**: unchanged from current behavior (per-stage review gates).

---

## Step 2: Confirm execution

Show the plan summary and ask user to confirm before running.

Display format:
```
Ready to execute: <plan name>
  Colleagues : <N>
  Stages      : <N>
  Budget     : <total> tokens

  Stage 1 (parallel):
    [C-01] Research Aggregator    [medium]
    [C-02] Market Analyst         [medium]
  Stage 2:
    [C-03] Product Writer         [high]  ← depends on C-01, C-02
  Stage 3:
    [C-04] Story Breaker          [medium] ← depends on C-03
  ...
```

**AskUserQuestion**:
```json
{
  "questions": [{
    "question": "Confirm plan execution?",
    "header": "Ready to run",
    "multiSelect": false,
    "options": [
      {"label": "Proceed", "description": "Start executing all stages now"},
      {"label": "Edit plan", "description": "Go back and adjust before running"},
      {"label": "Cancel", "description": "Stop — do not run"}
    ]
  }]
}
```

(AI translates per `$LANG` — see `core/shared/ux-rules.md` Language Policy.)

If user picks **Cancel** → exit cleanly.
If user picks **Edit plan** → instruct them to re-run `/compass:plan`.

---

## Step 3: Execute stage-by-stage

### Initialization (Stage 1 only)

Before the first stage begins, initialize `collab-memory.json` in the session directory:
```json
{ "decisions": [], "artifacts": [], "conflicts": [] }
```

Then load cross-session memory from the v1.0 project-memory store:

1. Call `compass-cli memory get "$PROJECT_ROOT"` to fetch `$PROJECT_ROOT/.compass/.state/project-memory.json` (resolved via the plan's `memory_ref`). If the CLI returns a "not found" signal → call `compass-cli memory init "$PROJECT_ROOT"` first, then `get` again. This guarantees every run starts with a schema-v1.0-conformant memory file.
2. From the returned JSON, extract the **top-level aggregates digest**:
   - `decisions` — durable architectural / product decisions from prior sessions
   - `discovered_conventions` — conventions learned across past work
   - `resolved_ambiguities` — previously-answered clarification questions
   - `glossary` — project-specific term definitions
   This digest MUST be included verbatim in every Colleague briefing emitted in Step 3 (see the worker prompt template). Do NOT dump the full `sessions[]` FIFO array into briefings — pass only the aggregates digest, to keep Colleague context tight.
3. Also keep the legacy `$PROJECT_ROOT/.compass/.state/colleague-memory.json` read as a fallback for pre-v1.0 projects: if `compass-cli memory get` reports the store was just initialized (no prior data) AND `colleague-memory.json` exists, prepend its `decisions` into the aggregates digest so Colleagues still see historical context during the migration window.
4. Store the digest in memory (one canonical copy for this run) — every Colleague briefing in every stage reads from this same digest object.

### For each stage

**Emit delegation plan** — apply Pattern 2 from `core/shared/progress.md` before spawning. Stage transitions follow Step C format from that module. The v1.0 memory/context-scope concerns below wrap this existing progress-pattern emission — they do NOT replace it.

1. **Pre-spawn context resolution (per task, v1.0):** for each task in the stage:
   - Resolve `task.context_pointers` against the project root (handle both exact paths and globs).
   - For any pointer that matches **zero** files on disk at this moment → halt dispatch for that task and escalate to the user via AskUserQuestion (see "Missing context_pointer escalation" below). Do NOT silently skip the task, do NOT widen scope to compensate, do NOT drop the pointer.
   - Pointers that were produced by an earlier stage in this same run will now exist — that is expected. Only pointers that resolve to zero matches *at the moment the stage starts* are errors.
2. Print stage plan with all colleagues marked `🔄` and their 3-6 word job description (existing progress pattern).
3. **Dispatch Colleagues (parallel execution required).** **Call the `Agent` tool once per Colleague in a single assistant message.** All `Agent` calls for a stage MUST be emitted together so they execute concurrently.

   For each Colleague in the stage, emit one call with this shape:

   ```
   Agent(
     description: "Colleague <name> — <task.name>",
     subagent_type: "general-purpose",
     prompt: <rendered Colleague worker prompt template>
   )
   ```

   The `prompt` (briefing) MUST contain ONLY:
   - that task's `briefing_notes` + structured `briefing` fields (constraints, stakeholders, deadline)
   - the files resolved from that task's `context_pointers`
   - the top-level aggregates digest from `project-memory.json` (loaded in Initialization)
   - the shared base rules

   Do NOT pass files from other tasks, other sessions, or unrelated areas of the repo — strict scope is a v1.0 guarantee.
4. **Parallelism requirement.** If the stage has N Colleagues, your message MUST contain N `Agent` tool calls. Never emit them sequentially across multiple messages — that breaks parallelism and violates the v1.0 execution contract.
5. As each Colleague finishes, emit `✓ <colleague name> (<elapsed>s)` live to main chat (existing progress pattern) — do NOT wait for stage end to report.
6. When all Colleagues in the current stage finish, emit stage-transition separator (`─── Stage N complete (total, artifacts) ───`) (existing progress pattern).
7. Run post-stage consistency check (Step 5).
8. Update session-local `collab-memory.json` with outputs and decisions (unchanged legacy behavior).
9. **Persist stage outputs to `project-memory.json` (v1.0):** call
   ```bash
   compass-cli memory update "$PROJECT_ROOT" --session "<session_id>" --from-stage <stage-number> --inputs <path-to-collab-memory.json-or-stage-outputs>
   ```
   so that new decisions, discovered conventions, resolved ambiguities, and glossary additions from this stage are merged into the project-memory store. The CLI handles schema-v1.0 shape + FIFO rotation internally; this workflow only needs to invoke it after each stage completes.
10. Proceed to next stage.

### Colleague worker prompt template

Each Colleague subagent receives ONLY this briefing — no other context. The `Context files` list MUST be exactly the files resolved from that task's `context_pointers` (nothing more, nothing less). The `Project Memory Digest` block MUST be the top-level aggregates loaded from `project-memory.json` in Initialization — NOT the full FIFO `sessions[]` array.

```
You are a Compass Colleague — <colleague.name>.

## Your Assignment
Task     : <name>
ID       : <task_id>
Role     : <colleague>
Workspace: <workspace_dir>

## Briefing Notes
<task.briefing_notes>

## Context Files (authoritative scope — read these first, nothing outside this list)
<files resolved from task.context_pointers>

## Structured Briefing
Constraints:
<task.briefing.constraints>

Stakeholders:
<task.briefing.stakeholders>

Deadline:
<task.briefing.deadline>

## Project Memory Digest (from project-memory.json — top-level aggregates)
Decisions:
<project-memory.decisions>

Discovered Conventions:
<project-memory.discovered_conventions>

Resolved Ambiguities:
<project-memory.resolved_ambiguities>

Glossary:
<project-memory.glossary>

## Shared Memory (this session only)
<collab-memory.json contents>

## Output
Write to       : <output_pattern resolved with slug>
Follow template: <template path>
Language       : <spec_lang>

## Acceptance Criteria
<acceptance.criteria>

## Rules
<base-rules.md contents>
```

**Scope guarantee:** the orchestrator passes ONLY `context_pointers`-resolved files + `briefing_notes` + the project-memory digest. If the Colleague needs additional files to complete the task, it MUST surface that gap back to the orchestrator rather than reading outside scope — `/compass:plan` is the place to widen `context_pointers`, not the Colleague.

### Status tracking

Each Colleague moves through these states:
`pending → running → completed → failed → blocked → skipped`

Live status display after each stage completes:
```
Stage 1:
  ✅ C-01 — Research Aggregator    [completed]
  ✅ C-02 — Market Analyst         [completed]
Stage 2:
  🔄 C-03 — Product Writer         [running...]
Stage 3:
  ⬜ C-04 — Story Breaker          [pending]
```

Persist status to `run-status.json` in session directory after every state change.

### Shared memory updates

After each Colleague completes:
1. Read its output files
2. Extract any decisions, artifact paths, or constraints noted
3. Append to `collab-memory.json`
4. Next stage's Colleagues receive the updated shared memory in their briefing

---

## Step 4: Escalation ladder

When a Colleague fails or times out, escalate in order:

1. **Retry** — same prompt, fresh attempt (1×)
2. **Retry enriched** — add error details + related reference docs to context (1×)
3. **Model escalation** — switch to a more capable model per `model_routing.escalation` in config (1×)
4. **PO intervention** — Colleague still unresolved; ask user via AskUserQuestion:

```json
{
  "questions": [{
    "question": "C-03 Product Writer failed after 3 retries. What do you want to do?",
    "header": "Escalation — C-03",
    "multiSelect": false,
    "options": [
      {"label": "Provide guidance", "description": "Give me context and I'll retry with it"},
      {"label": "Skip", "description": "Continue without this Colleague's output"},
      {"label": "Stop", "description": "Halt the entire run now"},
      {"label": "Mark as done", "description": "I'll fix the output manually — mark completed"}
    ]
  }]
}
```

- **Provide guidance** → collect user's note, retry with enriched context
- **Skip** → set status to `skipped`, continue run; note dependency impact
- **Stop** → save all current status, print partial report, exit
- **Mark as done** → set status to `completed`, move to next stage

### Missing context_pointer escalation (v1.0)

If, during "Pre-spawn context resolution" (Step 3.1), a task's `context_pointers` entry resolves to **zero matches** on disk at the moment the stage starts, the orchestrator MUST NOT:

- silently drop the pointer,
- replace it with a different file,
- widen the Colleague's scope to "whatever is nearby",
- or mark the task as skipped on its own authority.

Instead, halt dispatch for that task and ask the user via AskUserQuestion:

```json
{
  "questions": [{
    "question": "Task <task_id> references '<pointer>' but no file matches. How do you want to proceed?",
    "header": "Missing context — <task_id>",
    "multiSelect": false,
    "options": [
      {"label": "Skip this task", "description": "Mark <task_id> as skipped and continue the run; downstream tasks depending on its output will be flagged."},
      {"label": "Abort the run", "description": "Stop now; fix the plan in /compass:plan (adjust context_pointers) and re-run."},
      {"label": "Provide an alternative path", "description": "Give me a real file path or glob to substitute in for this one missing pointer, just for this run."}
    ]
  }]
}
```

- **Skip this task** → set its status to `skipped`, record the missing pointer in `collab-memory.json` under `conflicts`, continue the run. Downstream tasks whose `depends_on` includes this task MUST be flagged (and may themselves escalate as `blocked`).
- **Abort the run** → persist `run-status.json`, print a partial report noting the missing pointer, exit cleanly.
- **Provide an alternative path** → accept the user-supplied path/glob, substitute it ONLY for this task in this run (do NOT rewrite `plan.json`), and continue. Note the substitution in `collab-memory.json` so the final report can show it.

This escalation applies on a **per-pointer** basis — if only 1 of 5 pointers is missing, the other 4 still resolve normally and the user's choice applies only to the missing one.

---

## Step 5: Post-stage consistency check

After every stage completes, verify before starting the next stage:

- All expected output files exist at the declared paths
- Cross-references are valid (e.g., if Writer finished, Stories must reference the PRD slug)
- No conflicting decisions in `collab-memory.json` (same key set to different values)
- File naming follows `config.naming` patterns
- No Colleague left in `running` state (detect hangs)

If a conflict is found in shared memory → flag to user with AskUserQuestion before continuing.

---

## Step 5.5: Persist cross-session memory

After all stages complete (before printing the final report), persist durable decisions:

1. Read the session's `collab-memory.json` (final state after all Colleagues ran)
2. Read `$PROJECT_ROOT/.compass/.state/colleague-memory.json` if it exists; otherwise start with the empty structure below
3. Identify NEW decisions from the session: entries in `collab-memory.json` whose `persistence` field is `"persistent"` AND whose `key` does not already exist in `$PROJECT_ROOT/.compass/.state/colleague-memory.json`
4. Append only those new entries to the persistent file's `decisions` array — never overwrite or remove existing entries
5. Write the updated persistent file back to `$PROJECT_ROOT/.compass/.state/colleague-memory.json`

Persistent file format:
```json
{
  "version": "0.4.0",
  "decisions": [
    {
      "key": "auth_approach",
      "value": "OAuth2 + PKCE",
      "decided_by": "C-01 (Research Aggregator)",
      "session": "<session-id>",
      "reason": "User feedback strongly prefers SSO",
      "timestamp": "<ISO-8601>"
    }
  ],
  "conventions": {}
}
```

- The `session` field is the plan name or a `<task>-<date>` slug derived from the plan
- The `timestamp` is the UTC time the decision was appended
- If `$PROJECT_ROOT/.compass/.state/` directory does not exist, create it before writing

---

## Step 6: Final report

After all stages complete, print the final summary:

```
Done!
  Colleagues : <N>/<N> completed
  Files created:
    - <path-1>
    - <path-2>
  Shared memory: <N> decisions recorded (<M> saved to cross-session memory)
  Budget used  : <X>k / <Y>k tokens
```

(AI translates per `$LANG` — see `core/shared/ux-rules.md` Language Policy.)

---

## Step 7 — Hand-off (adaptive per `auto_mode`)

Read `AUTO_MODE` from Step 1a.

**If `AUTO_MODE = "auto"`** → skip gate. Print `⚡ Auto-chain: invoking /compass:check...` and immediately invoke `/compass:check` inline (read and execute `~/.compass/core/workflows/check.md`).

**If `AUTO_MODE = "manual"` or `"stop"`** → show 3-option gate:

```json
{"questions": [{"question": "Run done. Next?", "header": "Next", "multiSelect": false, "options": [
  {"label": "Continue to /compass:check (Recommended)", "description": "Validate outputs + deliver to integrations — ask again at next checkpoint"},
  {"label": "Auto-chain check", "description": "Run /compass:check without more prompts"},
  {"label": "Stop here", "description": "I'll run /compass:check manually later"}
]}]}
```

AI translates per `$LANG` — see ux-rules Language Policy.

**Branch**:
- **Continue** → invoke `/compass:check` inline (persist `auto_mode` unchanged).
- **Auto-chain** → set `auto_mode="auto"` in context.json, invoke `/compass:check`.
- **Stop** → print `✓ Run /compass:check when ready.` and stop.

Persistence:
```bash
TMP=$(mktemp)
jq --arg mode "<manual|auto>" '.auto_mode = $mode' "$SESSION_DIR/context.json" > "$TMP" && mv "$TMP" "$SESSION_DIR/context.json"
```

---

## Edge cases

| Situation | Behavior |
|---|---|
| Colleague timeout | Treat as failure → trigger escalation ladder |
| Shared memory conflict | Flag to PO before next stage starts |
| All Colleagues in a stage fail | Print clean status report, halt run |
| PO cancels mid-run | Save `run-status.json` with partial progress; can resume later |
| Dependency's output missing | Blocked Colleague → set status `blocked`, escalate to PO |
| Plan has only 1 stage with 1 Colleague | Run normally — no parallel needed, still do consistency check |
