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

@ -894,8 +894,6 @@ topic.
> levels deep), so a delegated redesign is under evaluation (see
> `docs/cc-upgrade-2.1.181-decision-matrix.md`, W1/CC-26). Until then,
> running each research pass inline in main context keeps the swarm intact.
> For true parallel execution, use `claude -p` invocations in separate
> terminal windows.
### Step 6c — Verify all briefs landed

View file

@ -1,6 +1,6 @@
---
name: trekexecute
description: Disciplined plan executor — single-session or multi-session with parallel orchestration, failure recovery, and headless support
description: Disciplined plan executor — single-session, or multi-session through session orders the user starts, with failure recovery
argument-hint: "[--project <dir>] [--fg | --resume | --dry-run | --validate | --step N | --session N] [plan.md]"
allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion
disallowed-tools: Agent, TeamCreate
@ -10,9 +10,11 @@ disallowed-tools: Agent, TeamCreate
Disciplined executor for trekplan plans. Reads a plan file, detects if it has
an Execution Strategy (multi-session), and either executes directly or
orchestrates parallel headless sessions — all to realize one plan.
prepares one session order per session, wave by wave — all to realize one plan.
Designed to work identically in interactive and headless (`claude -p`) mode.
Voyage never starts a Claude Code session. Work that needs another session
becomes an order plus a starter line the user gives a session they open
themselves (Phase 2.6).
## Phase 1 — Parse mode and validate input
@ -329,20 +331,6 @@ pre-execution summary. Report them in the final output under "Security advisorie
**If clean:** Report `Security scan: PASS ({N} commands checked)` and continue.
### Hooks-fire precheck (advisory)
Verify the operator's Claude Code version supports cross-model hook firing
(v2.1.117+ shipped the cross-model malware-reminder fix per research/04 D4
+ R5 + research/06 R1). Run `claude --version` (or read
`${CLAUDE_CODE_VERSION}` if available) and compare against `2.1.117`.
If unavailable or older: WARN (do not block) —
`Hooks-fire precheck: CC version {X} predates v2.1.117. Plugin hooks may
not fire reliably in headless child sessions; the in-prompt safety
preamble (Phase 2.6 Step 2b) is the primary defense for affected runs.`
If version >= 2.1.117 or unparseable: continue silently.
## Phase 2.5 — Execution strategy decision
Determine how to execute this plan:
@ -366,7 +354,10 @@ Determine how to execute this plan:
- All sessions are in different waves (no parallelism, but still separate sessions)
For single-session: continue to Phase 3.
For multi-session: jump to Phase 2.6.
For multi-session: if `.claude/trekplan-sessions/{slug}/orders/wave.json`
exists, a wave is awaiting its sessions — skip Phase 2.55 (its clean-tree and
stale-worktree checks would destroy the live worktrees) and jump to Phase 2.6,
which collects the wave. Otherwise run Phase 2.55, then Phase 2.6.
Report:
```
@ -508,91 +499,59 @@ After all 4 checks pass:
Pre-flight: PASS (clean tree, plan reaches worktrees, no overlaps, no stale worktrees)
```
## Phase 2.6 — Multi-session orchestration (worktree-isolated)
## Phase 2.6 — Multi-session orchestration (worktree-isolated, session orders)
**Only runs for multi-session execution.** This phase creates isolated git
worktrees for each parallel session, launches headless child sessions in their
own worktrees, merges results back sequentially, and cleans up. After this
phase, jump directly to Phase 8 (final report).
**Only runs for multi-session execution.** Voyage never starts a Claude Code
session. This phase prepares ONE wave at a time: it creates an isolated git
worktree for each session in the wave, writes a **session order** for each
(the worktree, the steps, the done-condition) plus a one-line **starter**, and
stops. The user opens each session themselves, in the directory the order
names, and gives it the starter. Running the same `/trekexecute` command again
in the main checkout collects the wave: it reads every session's progress file,
merges the session branches back sequentially, cleans up, and prepares the next
wave. After the last wave, jump to Phase 8 (final report).
**CRITICAL SAFETY RULE:** Every parallel `claude -p` session MUST run in its own
git worktree. Never launch two sessions in the same working directory. This rule
exists because parallel git operations in a shared worktree cause index corruption,
race conditions, and repository destruction.
**CRITICAL SAFETY RULE:** Every session MUST run in its own git worktree. Never
run two sessions in the same working directory. This rule exists because
parallel git operations in a shared worktree cause index corruption, race
conditions, and repository destruction. Each order names its own worktree.
### Step 0 — Billing safety check (MANDATORY)
Before launching ANY `claude -p` process, check the environment:
```bash
echo "${ANTHROPIC_API_KEY:+SET}"
```
If the result is `SET`, **STOP** and warn the user. `claude -p` sessions with
`ANTHROPIC_API_KEY` in the environment bill the **API account** (pay-per-token),
not the user's Claude subscription (Max/Pro). Parallel Opus sessions can cost
$50–100+ per run.
Use AskUserQuestion with these options:
**Question:** "ANTHROPIC_API_KEY is set in your environment. Parallel `claude -p`
sessions will bill your API account, not your Claude subscription. How do you
want to proceed?"
| Option | Description |
|--------|-------------|
| **Use --fg instead (Recommended)** | Run all steps sequentially in this session using your subscription. No extra cost. |
| **Continue with API billing** | Launch parallel sessions. Each session bills your API account at token rates. |
| **Stop** | Cancel execution. Unset ANTHROPIC_API_KEY first, then re-run. |
If the user chooses `--fg`: restart execution with mode = foreground (jump back
to Phase 3, single-session).
If the user chooses `Continue`: proceed with Phase 2.6 Step 1.
If the user chooses `Stop`: report "Execution cancelled — billing safety check"
and stop.
If `ANTHROPIC_API_KEY` is NOT set: proceed silently to Step 1.
### Step 1 — Create session infrastructure
### Step 0 — Resolve paths and detect a wave in flight
```bash
REPO_ROOT="$(git rev-parse --show-toplevel)"
SESSION_DIR="$REPO_ROOT/.claude/trekplan-sessions/{slug}"
WORKTREE_DIR="$SESSION_DIR/worktrees"
LOG_DIR="$SESSION_DIR/logs"
mkdir -p "$WORKTREE_DIR" "$LOG_DIR"
ORDERS_DIR="$SESSION_DIR/orders"
ORIGINAL_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
# Resolve the plugin root ONCE (same reason as Phase 7: the variable is
# substituted in this command's text but EMPTY in the Bash tool's env).
VOYAGE_ROOT="${CLAUDE_PLUGIN_ROOT:-}"
case "$VOYAGE_ROOT" in
/*) ;;
*) VOYAGE_ROOT="$(ls -d "$HOME"/.claude/plugins/cache/*/voyage 2>/dev/null | head -1)" ;;
esac
if [ ! -f "$VOYAGE_ROOT/lib/util/session-orders.mjs" ]; then
echo "[voyage] session orders cannot be written - plugin root unresolved." >&2
exit 2
fi
if [ -f "$ORDERS_DIR/wave.json" ]; then echo "WAVE_IN_FLIGHT"; else echo "NO_WAVE"; fi
```
Record `REPO_ROOT`, `WORKTREE_DIR`, `LOG_DIR`, and `ORIGINAL_BRANCH` for use
in subsequent steps. All paths must be absolute.
Record `REPO_ROOT`, `SESSION_DIR`, `WORKTREE_DIR`, `ORDERS_DIR`, `VOYAGE_ROOT`
and `ORIGINAL_BRANCH` for the later steps. All paths must be absolute.
### Step 2 — Execute waves with worktree isolation
- `WAVE_IN_FLIGHT` → read the wave number `W` from `$ORDERS_DIR/wave.json` and
jump to **Step 3** (collect). Phase 2.55 was skipped for this run (Phase 2.5).
- `NO_WAVE` → prepare the first wave of the Execution Strategy: `W` = the lowest
wave number. Continue to Step 1.
For each wave (in order):
**2a-pre. Build shared context + budget caps (runs once per wave, before
worktree creation):**
### Step 1 — Create worktrees for wave W
```bash
WORKTREE_BASE="$(realpath "${WORKTREE_BASE:-${SESSION_DIR:-$REPO_ROOT}/worktrees}")"
mkdir -p "${WORKTREE_BASE}"
SHARED_CONTEXT_FILE="${WORKTREE_BASE}/.shared-context.md"
cat "${PROJECT_DIR}/brief.md" > "${SHARED_CONTEXT_FILE}"
if [ -f "${PROJECT_DIR}/architecture/overview.md" ]; then
printf '\n\n---\n\n' >> "${SHARED_CONTEXT_FILE}"
cat "${PROJECT_DIR}/architecture/overview.md" >> "${SHARED_CONTEXT_FILE}"
fi
MAX_TURNS="${TREKEXECUTE_MAX_TURNS:-50}"
MAX_BUDGET_USD="${TREKEXECUTE_MAX_BUDGET_USD:-5}"
mkdir -p "$WORKTREE_DIR" "$ORDERS_DIR"
```
The budget caps default to safe values for normal-length steps. Operators may
override for long runs:
`TREKEXECUTE_MAX_TURNS=120 TREKEXECUTE_MAX_BUDGET_USD=20 /trekexecute --project ...`
**2a. Create worktrees for this wave's sessions:**
For each session N in this wave:
@ -623,11 +582,11 @@ plugin-in-monorepo + gitignored-state topology):**
`git worktree add` clones HEAD only. The plugin's `.gitignore` excludes
`.claude/projects/`, so the project directory (brief.md, plan.md, research/)
is missing in the freshly-created worktree. Each child session needs to read
is missing in the freshly-created worktree. Each session needs to read
`brief.md`, `plan.md`, and `research/*` from `${PROJECT_DIR}` to do real work.
Insert this block AFTER the worktree-creation loop and BEFORE wave dispatch
(Step 2b):
Insert this block AFTER the worktree-creation loop and BEFORE the orders are
written (Step 2):
```bash
PROJECT_SOURCE="$(realpath "${PROJECT_DIR}")"
@ -658,7 +617,7 @@ Do not "improve" the relpath line into `realpath --relative-to=...`. That flag
is GNU coreutils only; BSD `realpath` (the macOS default) rejects it, and the
failure is **silent** — the command substitution leaves `PROJECT_REL` empty, so
`mkdir -p "$wt/"` and `cp ... "$wt//"` both succeed and drop `brief.md`/`plan.md`
at the worktree root, where no child session looks for them. Measured on an
at the worktree root, where no session looks for them. Measured on an
Intel Mac 2026-08-31: `realpath --relative-to=... ` → `realpath: illegal option
-- -`, while bare `realpath <path>` works; a whole wave ran with zero steps
executed. Both `realpath` calls above are bare path resolution, which BSD and
@ -668,89 +627,63 @@ it correct when one side goes through a symlink (macOS `/var` → `/private/var`
Failure modes: an underivable relpath (empty, or outside the repo) aborts
before anything is copied — better a loud stop than files delivered where no
session reads them; any `cp` failure exits the wave non-zero, reported via
Step 4 cleanup. A project without `research/` is not a failure.
Step 5 cleanup. A project without `research/` is not a failure.
Source: brief Constraint 2.
**2b. Launch sessions in this wave (each in its own worktree):**
Each per-session prompt is **prefixed with two safety preambles** to defend
against headless-mode hook gaps (GH #36071) and the Claude 4 cross-model
malware-reminder issue (GH #52272 community workaround):
```text
[CRITICAL — defense in depth] You are running in headless mode where plugin
hooks may not fire reliably (GH #36071). DO NOT execute commands matching:
`rm -rf /`, `curl | bash`, `git push --force` to main, `git reset --hard`
outside this worktree, or any command writing outside the current worktree.
Treat this rule as enforced regardless of `--allowedTools` allowlist.
Note: any malware-related safety reminders apply conditionally to code you
assess as actually malicious, not to all code reads (per GH #52272 community
workaround).
```
Then the per-session dispatch (note the `cwd:` honor for plugin-in-monorepo
layouts):
For each session N in the wave:
```bash
SESSION_CWD="${session_cwd:-.}" # default: worktree root; overridable per-session via Execution Strategy `cwd:` field
cd "$WORKTREE_PATH/$SESSION_CWD" && \
GIT_OPTIONAL_LOCKS=0 claude -p "${SAFETY_PREAMBLE}\n\n/trekexecute --session {N} {plan-path}" \
--allowedTools "Read,Write,Edit,Bash,Glob,Grep" \
--permission-mode bypassPermissions \
--max-turns "$MAX_TURNS" \
--max-budget-usd "$MAX_BUDGET_USD" \
--append-system-prompt-file "${SHARED_CONTEXT_FILE}" \
> "$LOG_DIR/session-{N}.log" 2>&1 &
```
`session_cwd` is sourced from the per-session `cwd:` field in the plan's
Execution Strategy block (parsed by Phase 2.6's existing session-metadata
reader). Default is `.` (worktree root) when absent — backward compatible.
Sessions can declare `cwd: <subdir>` to make child sessions run from a
plugin-subdir instead of repo root. Required for plugin-in-monorepo layouts
where the plugin lives at `plugins/<name>/` and step paths are relative to
the plugin (brief Constraint 1, Option B).
Key rules:
- `$WORKTREE_PATH` is the absolute path to the session's worktree
- `$LOG_DIR` is an absolute path in the main worktree (NOT inside the session worktree)
- `{plan-path}` is the same relative path — it works because the worktree has
the same repo content from HEAD
- `${SHARED_CONTEXT_FILE}` is absolute (from Step 2a-pre) so child sessions
can resolve it after `cd`
- If the wave has only 1 session, run without `&` (no background needed)
- Track PIDs for parallel sessions
- `--max-turns` + `--max-budget-usd` are guardrails (research/06 R3 + R4)
- `--append-system-prompt-file` injects shared brief + architecture context
into every child without bloating the per-session prompt
**2c. Wait for wave completion:**
### Step 2 — Write the session orders for wave W, then stop
```bash
wait {PID1} {PID2} ...
node "$VOYAGE_ROOT/lib/util/session-orders.mjs" write \
--plan "{plan-path}" --wave "{W}" --session-dir "$SESSION_DIR"
```
**2d. Check results after each wave:**
`{plan-path}` is repo-relative (the tool refuses an absolute path): each
session resolves it inside its own worktree, which has the same repo content
from HEAD. The tool writes `$ORDERS_DIR/wave-{W}-session-{N}.md` per session
and `$ORDERS_DIR/wave.json` (`status: awaiting-sessions`), and prints, per
session, the directory to open and the starter line
(`/trekexecute --session {N} {plan-path}`). A session's per-session `cwd:`
field in the Execution Strategy moves the directory it opens in to that
subdirectory of its worktree (plugin-in-monorepo layouts, brief Constraint 1,
Option B); default `.` is the worktree root.
For each session in the wave, read its log file (in `$LOG_DIR`, always accessible
from the main worktree) and grep for `"trekexecute_summary"`. Parse the JSON to
determine:
- Did the session complete? (`result: "completed"`)
- Did it fail? (`result: "failed"` or `"stopped"`)
Show the tool's output to the user verbatim, then report and **stop**:
If ANY session in the wave failed:
```
Wave {W} FAILED: Session {N} failed at step {S}.
Stopping — later waves depend on this wave.
See log: {LOG_DIR}/session-{N}.log
Wave {W}: {N} session order(s) written in {ORDERS_DIR}. Awaiting sessions.
Open each session yourself in the directory its order names and give it the
starter line. When every session is done, run this same /trekexecute command
again here to merge the wave.
```
Do NOT merge. Do NOT start later waves. Jump to Step 4 (cleanup), then Phase 8.
If all sessions in the wave passed: continue to Step 2e.
This run ends here. It writes no Phase 8 report: the plan is not finished, and
the orders are the hand-over.
**2e. Merge session branches back (SEQUENTIAL, one at a time):**
### Step 3 — Collect wave W (a later run)
```bash
node "$VOYAGE_ROOT/lib/util/session-orders.mjs" status \
--plan "{plan-path}" --wave "{W}" --session-dir "$SESSION_DIR"
```
The JSON names each session's progress file (the file `--session N` writes,
Phase 3) and its `status`: `completed`, `failed`, `stopped`, `pending` (no
progress file yet) or `unreadable`.
- **Any `pending`:** the wave is still running. Report which sessions are
pending, point at their order files (`$ORDERS_DIR/wave-{W}-session-{N}.md`),
and stop. Do not merge, do not clean up.
- **Any `failed`, `stopped` or `unreadable`:**
```
Wave {W} FAILED: Session {N} ended {status}.
Stopping — later waves depend on this wave.
See its order: {ORDERS_DIR}/wave-{W}-session-{N}.md
```
Do NOT merge. Do NOT prepare later waves. Jump to Step 5 (cleanup), then Phase 8.
- **`all_completed: true`:** if `gates_mode` is true, pause for operator
confirmation before merge-back. Then continue with the merge.
**Merge session branches back (SEQUENTIAL, one at a time):**
Return to the main worktree:
```bash
@ -781,13 +714,13 @@ Wave {W} MERGE CONFLICT: Session {N} branch conflicts with merged state.
Conflicting files:
{CONFLICTS}
Session {N} log: {LOG_DIR}/session-{N}.log
Session {N} order: {ORDERS_DIR}/wave-{W}-session-{N}.md
Aborting further merges. Sessions already merged in this wave are preserved.
```
Mark remaining sessions as "merge-failed". Jump to Step 4 (cleanup), then Phase 8.
Mark remaining sessions as "merge-failed". Jump to Step 5 (cleanup), then Phase 8.
**2f. Remove worktrees for completed wave:**
**Remove worktrees for the merged wave:**
After successful merge of all sessions in the wave:
```bash
@ -796,21 +729,26 @@ for each session N in the wave:
GIT_OPTIONAL_LOCKS=0 git branch -d "trek/{slug}/session-{N}"
done
GIT_OPTIONAL_LOCKS=0 git worktree prune
rm -f "$ORDERS_DIR/wave.json"
```
Report: `Wave {W}: {N} sessions merged, worktrees cleaned up.`
Continue to the next wave.
**Next wave:** if the Execution Strategy has a later wave, set `W` to it and go
back to Step 1 — this run prepares that wave's orders and stops again. If wave
W was the last, continue to Step 4.
### Step 3 — Run master verification
### Step 4 — Run master verification
After all waves complete and merge successfully, run the plan's `## Verification`
section commands to verify the integrated result.
### Step 4 — Cleanup (ALWAYS runs, even on failure)
### Step 5 — Cleanup (ALWAYS runs when the run ends, even on failure)
This step MUST execute regardless of how Step 2 exited — success, failure, or
merge conflict. It is the worktree equivalent of a `finally` block.
This step MUST execute whenever this phase ends the run with a failure, a merge
conflict, or after the last wave — never while a wave is awaiting its sessions
(Step 2 and a `pending` Step 3 stop without it). It is the worktree equivalent
of a `finally` block.
```bash
cd "$REPO_ROOT"
@ -826,7 +764,8 @@ GIT_OPTIONAL_LOCKS=0 git branch --list "trek/{slug}/*" | while read branch; do
GIT_OPTIONAL_LOCKS=0 git branch -D "$branch" 2>/dev/null
done
# Clean up empty directories
# Clean up empty directories and the wave marker
rm -f "$ORDERS_DIR/wave.json"
rmdir "$WORKTREE_DIR" 2>/dev/null
```
@ -841,9 +780,9 @@ Warning: failed to remove worktree {path}. Manual cleanup:
git worktree remove {path} --force && git worktree prune
```
### Step 5 — Aggregate results
### Step 6 — Aggregate results
Collect all session summaries into an aggregated report. Jump to Phase 8.
Collect every session's progress file into an aggregated report. Jump to Phase 8.
### --session N mode
@ -855,12 +794,13 @@ When mode = `session N`:
5. Enforce the session's scope fence as if it were a session spec's scope fence
6. Report results for those steps only
This mode is used internally by Phase 2.6 when launching child sessions.
It can also be used manually to re-run a specific session.
This mode is what each session order's starter runs, in a session the user
opened in that order's worktree. It can also be used manually to re-run a
specific session.
When `--session N` is invoked inside a git worktree (as done by Phase 2.6), all
git operations (add, commit) apply to the worktree's branch. The session does not
need to know it is in a worktree — git handles this transparently.
When `--session N` runs inside a git worktree (as each session order sets up),
all git operations (add, commit) apply to the worktree's branch. The session does
not need to know it is in a worktree — git handles this transparently.
## Phase 3 — Progress file setup
@ -1010,16 +950,11 @@ If `has_execution_strategy = true`, show a preview of multi-session orchestratio
```
**Sessions:** {S} across {W} waves
| Wave | Session | Steps | Depends on | Command |
| Wave | Session | Steps | Depends on | Starter (the user runs it in a session they open) |
|------|---------|-------|------------|---------|
| 1 | Session 1: {title} | {nums} | none | `claude -p "/trekexecute --session 1 {path}"` |
| 1 | Session 2: {title} | {nums} | none | `claude -p "/trekexecute --session 2 {path}"` |
| 2 | Session 3: {title} | {nums} | S1, S2 | `claude -p "/trekexecute --session 3 {path}"` |
```
Check billing status via `echo "${ANTHROPIC_API_KEY:+SET}"` and report:
```
Billing: ANTHROPIC_API_KEY is {SET — parallel sessions will bill API account | NOT SET — sessions will use subscription}
| 1 | Session 1: {title} | {nums} | none | `/trekexecute --session 1 {path}` |
| 1 | Session 2: {title} | {nums} | none | `/trekexecute --session 2 {path}` |
| 2 | Session 3: {title} | {nums} | S1, S2 | `/trekexecute --session 3 {path}` |
```
### Verdict
@ -1245,7 +1180,7 @@ depends on what was executed:
Phase 4's entry-condition skip for trekplans stands — a plan carries no entry
condition. The exit side is not symmetrical: a trekplan's `## Verification`
section is where the brief's success criteria land, and it used to run only on
the multi-session wave path (Phase 2.6 Step 3). A single-session run therefore
the multi-session wave path (Phase 2.6 Step 4). A single-session run therefore
reported `completed` without ever executing the criteria it was measured
against. It no longer does.
@ -1443,17 +1378,20 @@ the user for manual resolution.
4. Prepend the synthetic Step 0 pre-flight (same as normal session specs).
5. Set `recovery_dispatched = true` in parent progress file.
**Invoke the recovery session:**
**Hand the recovery session over as an order (Voyage does not start it):**
```bash
cd "$WORKTREE_PATH" && claude -p "/trekexecute --session {N} {recovery spec path}" \
--allowedTools "Read,Write,Edit,Bash,Glob,Grep" \
--permission-mode bypassPermissions \
> "$LOG_DIR/session-{N}-recovery-{depth}.log" 2>&1
Report the recovery spec as a session order and stop the run as `partial`:
```
Recovery order: session {N}, depth {depth}
Open a Claude Code session yourself in {WORKTREE_PATH} and give it:
/trekexecute --session {N} {recovery spec path}
When it is done, run this same /trekexecute command again: it re-runs the
Phase 7.5 audit.
```
Wait for the recovery session to complete. After it returns, re-run Phase
7.5 audit one more time. If it still drifts at `recovery_depth=2`:
On that later run, re-run the Phase 7.5 audit one more time. If it still
drifts at `recovery_depth=2`:
```
RECOVERY EXHAUSTED: session {N} drifted after 2 recovery attempts.
@ -1466,8 +1404,7 @@ Do NOT dispatch a third recovery. Report to the user.
### Iteration caps + global recovery/retry budget
Every recovery/retry loop in this executor has a documented numeric bound.
These are **three distinct axes** — not one nested counter — plus a separate
child turn cap:
These are **three distinct axes** — not one nested counter:
- **Per-step retry cap** — `attempts ≤ 3` (initial + **maximum 2 retries**;
Hard Rule 5 / Sub-step E). Bounds the retries of a *single* step.
@ -1482,14 +1419,10 @@ child turn cap:
enforced via the `iterations_remaining` counter (Phase 3 schema; decremented
on every recovery/retry iteration; reconciled at the Phase 7.5 completion
gate).
- **Child turn cap** — `--max-turns` (`TREKEXECUTE_MAX_TURNS`, default 50)
bounds model turns inside a single `-p` child; a *different* axis from the
three above.
Default **25** is an independent value from the cap research (practitioner range
10–50; OWASP Agentic ASI08 financial-DoS), tuned down from the research ~50
starting point for a tighter backstop. It is **not** a reconciliation with
`--max-turns` (50) — the axes are incomparable. Operators may override:
starting point for a tighter backstop. Operators may override:
`TREKEXECUTE_MAX_RECOVERY_ITERATIONS=10 /trekexecute --project ...`. The
`effort=='low'` single-foreground-loop path and the wave path are both subject to
this aggregate ceiling; it is an execution-spec ceiling (enforced via the
@ -1703,7 +1636,7 @@ To resume: /trekexecute --resume {path}
}
```
The `trekexecute_summary` key makes it grep-able in log files from headless runs.
The `trekexecute_summary` key makes it grep-able in a session's output.
## Phase 9 — Stats tracking
@ -1823,8 +1756,7 @@ code-path.
1. **No AskUserQuestion for execution decisions.** All execution decisions come
from the plan's On failure clauses. If the plan says escalate, stop and
report — never ask. **Exception:** the billing safety check in Phase 2.6
Step 0 MUST ask before spending money on the user's API account.
report — never ask.
2. **No scope creep.** Only touch files listed in the step's `Files:` field.
If a file outside the list seems to need changing, record it as a finding
@ -1855,9 +1787,9 @@ code-path.
which removes both tools from the pool — `allowed-tools` alone does not,
since omission leaves a tool callable (CC 2.1.152).
11. **Worktree isolation is mandatory for parallel execution.** Every parallel
`claude -p` session MUST run in its own git worktree. Never launch two or
more sessions in the same working directory. This rule has no exceptions.
11. **Worktree isolation is mandatory for multi-session execution.** Every
session order names its own git worktree. Never run two or more sessions
in the same working directory. This rule has no exceptions.
Sequential (single-session) execution does not require worktrees.
12. **Worktree cleanup is unconditional.** Before producing the final report
@ -1921,6 +1853,11 @@ code-path.
20. **Three distinct iteration axes.** Per-step `attempts` (≤3), per-session
`recovery_depth` (<2), and the global `TREKEXECUTE_MAX_RECOVERY_ITERATIONS`
budget (default 25 — aggregate recovery+retry backstop) are independent
bounds, not one nested counter; child `--max-turns` (50) is a fourth,
separate axis. Every recovery/retry loop is bounded by at least one of them.
See "Iteration caps + global recovery/retry budget".
bounds, not one nested counter. Every recovery/retry loop is bounded by at
least one of them. See "Iteration caps + global recovery/retry budget".
21. **Never start Claude Code.** No `claude` CLI invocation, no Agent SDK, no
background process that runs a session — not for waves, not for recovery,
not for a test. Work that needs another session becomes a session order
plus a starter line the user gives a session they open themselves
(Phase 2.6, Phase 7.6).

View file

@ -297,7 +297,7 @@ The session-decomposer will:
4. Identify which sessions can run in parallel (waves)
5. Generate one session spec file per session
6. Generate a dependency diagram (mermaid)
7. Generate a launch script (`launch.sh`)
7. Write the session orders (`orders.md`): one starter line per session, wave by wave
When the session-decomposer completes, present the summary to the user:
@ -318,16 +318,16 @@ When the session-decomposer completes, present the summary to the user:
- Session specs: .claude/trekplan-sessions/{slug}/session-*.md
- Dependency graph: .claude/trekplan-sessions/{slug}/dependency-graph.md
- Launch script: .claude/trekplan-sessions/{slug}/launch.sh
- Session orders: .claude/trekplan-sessions/{slug}/orders.md
You can:
- Review individual session specs before running
- Run all sessions: `bash .claude/trekplan-sessions/{slug}/launch.sh`
- Run a single session: `claude -p "$(cat .claude/trekplan-sessions/{slug}/session-1-*.md)"`
- Say **"launch"** to start headless execution from here
- Run the sessions yourself, wave by wave: open a Claude Code session per spec
and give it the starter line from orders.md (`/trekexecute <spec>`). Run the
sessions of one wave in parallel only in separate git worktrees.
```
If the user says **"launch"**: run the launch script via Bash.
Voyage does not start these sessions.
Then **stop**. Do not continue to any subsequent phase.
@ -372,8 +372,7 @@ Then continue to the next phase inline.
> can spawn sub-agents (up to 5 levels deep), so that block no longer holds —
> a delegated redesign is under evaluation (see
> `docs/cc-upgrade-2.1.181-decision-matrix.md`, W1/CC-26). Until then, running
> the phases inline in main context keeps the swarm intact. Use `claude -p`
> in a separate terminal window for long-running headless work.
> the phases inline in main context keeps the swarm intact.
---

View file

@ -245,8 +245,7 @@ Then continue to the next phase inline.
> deep), so that block no longer holds — a delegated redesign is under
> evaluation (see `docs/cc-upgrade-2.1.181-decision-matrix.md`, W1/CC-26).
> Until then, running the phases inline in main context keeps the swarm
> intact. Use `claude -p` in a separate terminal window for long-running
> headless work.
> intact.
---
@ -331,26 +330,21 @@ changes nothing (SC1). Keep the native-swarm anchors intact ("in parallel",
**engine = deep-research:**
1. **Coarse pre-gate (best-effort, NOT a trust signal).** `Bash: claude --version`;
parse the leading `X.Y.Z` (e.g. from `2.1.196 (Claude Code)`) and compare
numerically against **both ends** of the supported window
`2.1.154 <= version < 2.1.218` — split each on `.` and compare major, then minor,
then patch as integers (do NOT string-compare; lexical comparison mis-orders
multi-digit patch numbers). If the version is `< 2.1.154` (below the
dynamic-workflows floor), OR `>= 2.1.218` (the ceiling: `/deep-research` starts
only when the operator invokes it, and the Skill tool refuses a model invocation
with `disable-model-invocation` — see step 4's reason token), OR if
`disableWorkflows: true` / `CLAUDE_CODE_DISABLE_WORKFLOWS=1` is set, skip to the
fallback (step 4). **If `claude` is not on PATH inside the Bash tool (possible
under `claude -p`) or the version cannot be parsed, treat the pre-gate as
*indeterminate* and proceed to step 2 — do NOT hard-fail.** There is no positive
1. **Coarse pre-gate (best-effort, NOT a trust signal).** The supported window is
`2.1.154 <= version < 2.1.218`: below `2.1.154` there are no dynamic workflows,
and from `2.1.218` (the ceiling) `/deep-research` starts only when the operator
invokes it, and the Skill tool refuses a model invocation with
`disable-model-invocation` — see step 4's reason token. Voyage does not run the
Claude Code binary to read its version (it never calls Claude Code), so the
version is *indeterminate* here. If `disableWorkflows: true` /
`CLAUDE_CODE_DISABLE_WORKFLOWS=1` is set, skip to the fallback (step 4);
otherwise proceed to step 2 — do NOT hard-fail. There is no positive
availability probe (research Dim 4), so a passing pre-gate does not guarantee the
workflow runs; the post-hoc check (step 3) is the authoritative guard.
2. **Run.** Instruct Claude (in prose, this turn) to run
`/deep-research <research question>` and request per-claim citations. Note:
interactive default/acceptEdits triggers a per-run approval prompt; `claude -p` /
SDK / bypass runs immediately.
interactive default/acceptEdits triggers a per-run approval prompt.
3. **Post-hoc presence + provenance check (the real guard).** Verify a real, cited
`/deep-research` report actually landed in context — substantive findings with
@ -366,8 +360,8 @@ changes nothing (SC1). Keep the native-swarm anchors intact ("in parallel",
`Engine: deep-research → swarm (fallback: <reason>)` and carry the reason into the
Phase-8 Present summary and the brief's `## Executive Summary`. Known reason
tokens: `disable-model-invocation` (CC >= 2.1.218 — the expected reason on any
current Claude Code), `version-below-floor`, `workflows-disabled`,
`no-cited-report`. **NEVER fabricate
current Claude Code), `workflows-disabled`, `no-cited-report` (also what a
Claude Code below the `2.1.154` floor produces, since no version is read). **NEVER fabricate
or synthesize a substitute report** — a structurally-valid-but-invented brief
passes the structure-only validator and silently poisons `/trekplan`; that is the
worst outcome of this feature.