feat(execute)!: hand waves over as session orders, never start Claude Code (green)

Operator decision 27.09.2026: Voyage works the PM way, so nothing in it
starts Claude Code. Work that needs another session becomes an order plus
a starter line the user gives a session they open themselves; Voyage
never starts the session.

/trekexecute's multi-session path (Phase 2.6) now prepares one wave at a
time: worktree per session, then lib/util/session-orders.mjs writes one
order per session (worktree, steps, done-condition, starter) plus
orders/wave.json, and the run stops. Running the same command again reads
each session's progress file (status mode), merges sequentially with
push-before-cleanup as before, and prepares the next wave. Phase 2.5 skips
the destructive pre-flight while a wave is in flight. Phase 7.6 recovery is
handed over the same way. Hard rule 21: never start Claude Code.

Removed with it, because they existed only for launched children: the
ANTHROPIC_API_KEY billing check (and its dry-run line and Hard rule 1
exception), the hooks-fire version precheck, the safety preamble, the
scoped-tool/turn/budget flags, templates/headless-launch-template.md, the
decomposer's launch.sh (now orders.md), /trekplan's "launch", the README
billing and MCP tuning sections, and scripts/q3-cache-prefix-experiment.mjs
(an experiment that spawned the binary; its results stay in docs/).
/trekresearch's deep-research pre-gate no longer runs the binary for its
version; the post-hoc check was already the authoritative guard.

Chose orders + starters over in-session subagents because the order's done
criterion asks for exactly that, and because /trekexecute disallows the
Agent tool on purpose (Hard rule 10); reopening that is a separate change.

Gate: 54 -> 0 hit lines outside EXEMPT. npm test 1250 (1245 pass, 0 fail,
5 skipped: 3 are the retired-reference scan without its local list).
verify.sh 7/0. The fixture run (tests/lib/session-orders.test.mjs) writes
two orders and wave.json for wave 1 and leaves a trap binary untouched.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-09-27 15:35:22 +02:00
commit 219e40cd91
Signed by: ktg
SSH key fingerprint: SHA256:JakMjO6FTBBzN0Bhfj9saOoEjaFxlSdYuZQQpM/lF9Q
18 changed files with 664 additions and 1108 deletions

View file

@ -116,7 +116,7 @@ An optional architect step can sit between research and plan — `/trekplan` aut
- You're working in an unfamiliar codebase and need a map before you start
- The implementation has non-obvious dependencies, ordering constraints, or risks
- You want a reviewable plan before committing to an approach
- You need autonomous headless execution without human intervention
- You want execution that asks no questions — every recovery decision comes from the plan
- You need to research a technology, library, or approach before deciding
**Don't use it when:**
@ -305,46 +305,35 @@ Per step: apply Changes exactly as written → run Verify (exit code is truth)
| **Project** | `/trekexecute --project <dir>` | Read `{dir}/plan.md`, write `{dir}/progress.json` |
| **Plan path** | `/trekexecute plan.md` | Execute a specific plan file |
| **Resume** | `/trekexecute --project <dir> --resume` | Resume from last progress checkpoint |
| **Dry run** | `/trekexecute --project <dir> --dry-run` | Validate plan structure + preview sessions and billing |
| **Dry run** | `/trekexecute --project <dir> --dry-run` | Validate plan structure + preview sessions and their starters |
| **Validate** | `/trekexecute --project <dir> --validate` | Schema-only check — parse steps + manifests, report `READY \| FAIL`, no execution |
| **Single step** | `/trekexecute --project <dir> --step 3` | Execute only step 3 |
| **Foreground** | `/trekexecute --project <dir> --fg` | Force sequential, ignore Execution Strategy |
| **Single session** | `/trekexecute --project <dir> --session 2` | Execute only session 2 from Execution Strategy |
| **Profile** | `/trekexecute --profile <name> --project <dir>` | (v4.1.0) Pin model profile for execution. Plan-frontmatter `profile:` is honored when this flag is omitted. See [Profile system](#profile-system-v410). |
### Session-aware parallel execution (worktree-isolated)
### Multi-session execution through session orders (worktree-isolated)
When a plan has an `## Execution Strategy` section (auto-generated by `/trekplan` for plans with > 5 steps), `/trekexecute` automatically:
Voyage never starts a Claude Code session. When a plan has an `## Execution Strategy` section (auto-generated by `/trekplan` for plans with > 5 steps), `/trekexecute` works one wave at a time:
1. **Pre-flight checks** — validates clean working tree, plan file tracked in git, no scope fence overlaps between parallel sessions, no stale worktrees
2. **Creates git worktrees** — each parallel session gets its own isolated worktree and branch (`trek/{slug}/session-{N}`)
3. Launches `claude -p` per session per wave, each in its own worktree
4. **Merges branches back** sequentially with `--no-ff` after each wave completes
5. **Cleans up** worktrees and branches unconditionally (even on failure)
6. Runs master verification on the merged result
2. **Creates git worktrees** — each session in the wave gets its own isolated worktree and branch (`trek/{slug}/session-{N}`)
3. **Writes a session order per session** — the worktree to open, the steps, the done-condition, and a one-line starter (`/trekexecute --session N <plan>`) — then stops
4. **You open each session yourself** in the directory its order names and give it the starter
5. **Run the same `/trekexecute` command again** — it reads every session's progress file, merges the branches back sequentially with `--no-ff`, cleans up, and writes the next wave's orders
6. After the last wave: master verification on the merged result; worktrees and branches are cleaned up unconditionally (even on failure)
```
Wave 1: Session 1 (worktree-1) + Session 2 (worktree-2) -- parallel
↓ both complete → sequential merge to main
Wave 2: Session 3 (worktree-3) -- sequential
↓ complete → merge to main
Wave 1 orders: Session 1 (worktree-1) + Session 2 (worktree-2) -- you run them, in parallel
↓ re-run /trekexecute: both complete → sequential merge to main
Wave 2 orders: Session 3 (worktree-3)
↓ re-run /trekexecute: complete → merge to main
Cleanup worktrees + Master verification
```
Each session operates in complete filesystem isolation — no shared git index, no race conditions, no data loss. If a merge produces conflicts, the merge is aborted and conflicting files are reported.
Use `--fg` to force sequential execution even when a plan has an Execution Strategy.
### Billing safety
Before launching parallel `claude -p` sessions, `/trekexecute` checks whether `ANTHROPIC_API_KEY` is set in your environment. If it is, parallel sessions will bill your **API account** (pay-per-token), not your Claude subscription (Max/Pro). This can be expensive — parallel Opus sessions can cost $50-100+ per run.
When an API key is detected, you are asked how to proceed:
- **Use --fg instead** (recommended) — run sequentially in the current session using your subscription
- **Continue with API billing** — launch parallel sessions on your API account
- **Stop** — cancel and unset the API key first
If no API key is set, parallel sessions use your subscription and proceed without asking.
Use `--fg` to run every step sequentially in the current session instead, even when a plan has an Execution Strategy.
### Failure recovery
@ -356,12 +345,11 @@ If no API key is set, parallel sessions use your subscription and proceed withou
### Security hardening
The executor implements defense-in-depth security across four layers:
The executor implements defense-in-depth security across three layers:
1. **Plugin hooks** — `pre-bash-executor.mjs` blocks 13 categories of destructive commands (rm -rf /, chmod 777, pipe-to-shell, eval injection, disk wipe, shutdown, fork bombs, cron persistence, process killing, history destruction) with bash evasion normalization. `pre-write-executor.mjs` blocks writes to `.git/hooks/`, `.claude/settings.json`, shell configs, `.ssh/`, `.aws/`, and `.env` files
2. **Prompt-level denylist** — Security rules embedded in the executor command and session spec template that work even in headless `claude -p` sessions where hooks don't run
2. **Prompt-level denylist** — Security rules embedded in the executor command and session spec template that hold even if a hook does not fire
3. **Pre-execution plan scan** — Phase 2.4 scans all `Verify:` and `Checkpoint:` commands against the denylist before execution begins, catching dangerous commands before they reach the executor
4. **Scoped tool access** — Headless child sessions use `--allowedTools "Read,Write,Edit,Bash,Glob,Grep"` instead of `--dangerously-skip-permissions`, blocking Agent spawning, MCP tools, and web access in parallel sessions
#### Recommended: disable Skill shell execution (CC v2.1.91+)
@ -380,35 +368,19 @@ prompt-injection vector that the plugin's own hooks cannot fully mitigate
(Skills can fire before `pre-bash-executor` matches). See
[SECURITY.md](SECURITY.md) for the full hardening list.
### Headless execution
### Unattended execution
`/trekexecute` is designed for `claude -p` headless sessions:
`/trekexecute` runs without asking questions:
- **No questions asked** — all recovery decisions come from the plan
- **Progress file** — crash recovery via `{project_dir}/progress.json` (or `.trekexecute-progress-{slug}.json` for legacy plans)
- **Scope fence enforcement** — never touches files outside the session's scope
- **JSON summary** — machine-parseable `trekexecute_summary` block for log parsing
#### Headless multi-session tuning (CC v2.1.89+)
When running multiple parallel `claude -p` sessions (decomposed plans
or wave-based execution), set `MCP_CONNECTION_NONBLOCKING=true` in the
launching environment so MCP server connection latency does not
serialize startup across waves:
```bash
export MCP_CONNECTION_NONBLOCKING=true
bash .claude/projects/{slug}/sessions/launch.sh
```
Without this, each child session can spend 1-3 s blocking on MCP
connect, multiplying across waves. Setting it lets MCP connect lazily
on first tool call.
### Session titles for voyage commands (CC v2.1.94+)
A `UserPromptSubmit` hook (`hooks/scripts/session-title.mjs`) sets the
session title to `voyage:<command>:<slug>` whenever you invoke one of
the four voyage commands. This makes multi-session headless runs and
the four voyage commands. This makes the sessions of a multi-session run and
session-picker output trivially identifiable. Slug derivation:
| Invocation | Session title |
@ -669,7 +641,7 @@ flowchart TB
PLG --> PLS --> PLC
end
subgraph EX["/trekexecute · no sub-agents"]
EXI["inline step-loop + claude -p worktrees<br/>+ Phase 7.5/7.6 manifest audit (deterministic)"]
EXI["inline step-loop + session orders per wave (worktrees)<br/>+ Phase 7.5/7.6 manifest audit (deterministic)"]
end
subgraph RV["/trekreview"]
RVR["Phase 5 — parallel · code-correctness-reviewer · brief-conformance-reviewer*"]
@ -732,7 +704,7 @@ An opt-in upstream architect plugin (not bundled) can insert a Claude-Code-speci
**Dry run + validate before executing:**
```bash
/trekexecute --project <dir> --validate # schema check, no execution
/trekexecute --project <dir> --dry-run # preview sessions and billing
/trekexecute --project <dir> --dry-run # preview sessions and starters
/trekexecute --project <dir> # execute
```
@ -891,7 +863,7 @@ synthesis.
The command orchestrators pin no model: `/trekbrief`, `/trekresearch`,
`/trekplan`, and `/trekexecute` run on whatever model the session runs on.
To run them on Sonnet for cost or latency, start the session on Sonnet
(`claude --model sonnet`) or switch with `/model` inside the session.
or switch with `/model` inside the session.
The exploration and review sub-agents are chosen separately, at the spawn
sites: brief `phase_signals` first, then the profile's `phase_models`, with the