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:
parent
bc652ec7d3
commit
219e40cd91
18 changed files with 664 additions and 1108 deletions
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue