Browse Source

docs(skills): fleetflow — manifest & resume, cache-root, scripts table, contracts

SKILL.md:
- add ff-run.sh + ff-clean.sh to the Scripts table; note ff-collect's fence-strip
  + --repair and ff-status's manifest summary
- expand the Resume paragraph into "Manifest & resume" (manifest.json shape,
  ff-run resume semantics, the frozen-snapshot rationale) and add a
  "Cache & tmp redirect" paragraph (FLEETFLOW_CACHE_ROOT knob, why litter must
  land outside lanes, pass the same root to ff-clean)

worker-contracts.md:
- update the result layout (manifest.json, main-baseline.txt, <id>.transcript.jsonl,
  <id>.invalid.txt)
- new §6: effort lever mapping table (glm/codex/anthropic) + cache/tmp redirect +
  transcript archiving paths (glm config-dir newest jsonl; anthropic session_id ->
  ~/.claude/projects/<encoded-workdir>/<sid>.jsonl with the [:\/.]->- encoding)

Co-Authored-By: Claude <noreply@anthropic.com>
0xDarkMatter 2 weeks ago
parent
commit
ee253667a2
2 changed files with 79 additions and 8 deletions
  1. 33 7
      skills/fleetflow/SKILL.md
  2. 46 1
      skills/fleetflow/references/worker-contracts.md

+ 33 - 7
skills/fleetflow/SKILL.md

@@ -115,11 +115,35 @@ sandbox is confined to the lane, so out-of-repo specs are unreadable anyway.
 
 **Resume.** The journal (`.fleetflow/<run>/journal.jsonl`) uses the native
 tool's mechanism: each spawn is keyed by a content hash of
-`(brain, prompt, opts)`. Re-running `ff-spawn` with an unchanged packet returns
-the cached result instantly (exit 3 + path); change the prompt and only that
-lane re-runs. Corollary (same reason the native tool bans `Date.now()`): keep
-timestamps and random values OUT of packet prompts, or the key changes and the
-cache never hits.
+`(brain, prompt, opts)` — and `opts` includes `--effort`, so changing only the
+effort lever is a cache miss (a different run). Re-running `ff-spawn` with an
+unchanged packet returns the cached result instantly (exit 3 + path); change
+the prompt and only that lane re-runs. Corollary (same reason the native tool
+bans `Date.now()`): keep timestamps and random values OUT of packet prompts, or
+the key changes and the cache never hits.
+
+**Manifest & resume.** Each spawn also upserts a packet into
+`.fleetflow/<run>/manifest.json` (`{run, base, created_by, phases[], packets[]}`,
+one entry per id — idempotent — carrying `{id, brain, phase, prompt_file,
+worktree, max_turns, effort, schema, key}`). It is the orchestrator-side plan,
+distinct from the per-spawn journal: it records *what was intended* so a whole
+run can be replayed. `ff-run.sh resume --run NAME` snapshots the manifest's
+packets once, then replays each through `ff-spawn` in manifest order — unchanged
+packets cache-hit (`"cached"`), changed or new ones run live; per-lane summary
+to stderr, a JSON result list on stdout, exit 0 if all ok/cached, 10 if any
+lane failed. `ff-run status --run NAME` is an alias for `ff-status`. Snapshots
+matter: ff-spawn re-orders the live manifest on each upsert (remove-then-append),
+so the replay reads from a frozen copy. When you're done,
+`ff-clean.sh --run NAME [--force]` reclaims zero-commit lanes (worktree + branch
+deleted), keeps committed ones, and removes the run's cache dirs.
+
+**Cache & tmp redirect.** Workers' `UV_CACHE_DIR`, `TMPDIR`, `TMP`, and `TEMP`
+are pointed at `${FLEETFLOW_CACHE_ROOT:-$HOME/.fleet-worker/cache}/<run>-<id>/`
+(created before launch), so pytest/uv litter and codex's AppContainer-ACL'd
+sandbox dirs land OUTSIDE the repo and lanes — never inside a worktree that
+`git worktree remove` later needs to delete. Set `FLEETFLOW_CACHE_ROOT` once for
+the whole run and pass the same value to `ff-clean` so it can find and remove
+those dirs.
 
 ## Patterns ported from the native Workflow tool
 
@@ -196,8 +220,10 @@ default the script-author follows, not an option — and real runs routinely hit
 |---|---|
 | [scripts/ff-doctor.sh](scripts/ff-doctor.sh) | `--offline` structural preflight; `--live` probes GLM endpoint, Codex auth, Anthropic models, reports orchestrator tier (fable/opus) |
 | [scripts/ff-spawn.sh](scripts/ff-spawn.sh) | uniform spawner: worktree lane + guard preamble + journal + per-brain launch (GLM via fleet-worker, Codex via `codex exec`, Anthropic via `claude -p`) |
-| [scripts/ff-collect.sh](scripts/ff-collect.sh) | per-brain result gate; `--check-main-clean` escape guard |
-| [scripts/ff-status.sh](scripts/ff-status.sh) | run status as JSON (lane state, elapsed, commits, tools, tokens, activity); `--watch N --out status.json` feeds the live monitor |
+| [scripts/ff-collect.sh](scripts/ff-collect.sh) | per-brain result gate; strips ```json fences before `--schema` validation; `--repair` respawns a `<id>-repair` lane on validation failure; `--check-main-clean` escape guard |
+| [scripts/ff-status.sh](scripts/ff-status.sh) | run status as JSON (lane state, elapsed, commits, tools, tokens, activity, manifest summary); `--watch N --out status.json` feeds the live monitor |
+| [scripts/ff-run.sh](scripts/ff-run.sh) | `resume --run NAME` replays every manifest packet through ff-spawn in order (unchanged = cached, changed/new = live); `status --run NAME` aliases ff-status |
+| [scripts/ff-clean.sh](scripts/ff-clean.sh) | `--run NAME [--force]` reclaims zero-commit lanes (worktree remove + branch -D), keeps committed lanes, removes the run's cache dirs; reports locked ACL-litter dirs |
 
 **Live monitor** ([assets/ff-monitor.html](assets/ff-monitor.html)): a
 zero-dependency page reproducing the native /workflows progress surface — run

+ 46 - 1
skills/fleetflow/references/worker-contracts.md

@@ -109,11 +109,15 @@ judge", applied to yourself).
 
 ```
 <repo>/.fleetflow/<run>/
-├── journal.jsonl        # started/result records, v2 content-hash keys
+├── journal.jsonl        # started/result records, v2 content-hash keys (v: FF_VERSION)
+├── manifest.json        # orchestrator plan: {run,base,created_by,phases[],packets[]}
+├── main-baseline.txt    # main-checkout status snapshot (escape-guard baseline)
 ├── <id>.prompt.txt      # guard preamble + packet (what was actually sent)
 ├── <id>.result.json     # claude JSON envelope (glm/anthropic brains)
 ├── <id>.last.txt        # codex last-message (codex brain)
 ├── <id>.events.jsonl    # codex --json event stream (codex brain)
+├── <id>.transcript.jsonl# archived session transcript (claude-brain lanes; best-effort)
+├── <id>.invalid.txt     # last failed schema output (only when --repair ran)
 ├── <id>.err             # stderr
 └── wt-<id>/             # the lane worktree (branch fleetflow/<run>/<id>)
 ```
@@ -121,3 +125,44 @@ judge", applied to yourself).
 `.fleetflow/` sits at the repo top (never under `.claude/` — Claude Code's
 sensitive-file guard fires there before `bypassPermissions`) and must be
 gitignored; `ff-spawn` appends it to `.git/info/exclude` if absent.
+
+## 6. Effort lever, cache redirect, transcript archiving (Wave 1)
+
+**Effort lever** (`ff-spawn --effort low|medium|high|max`). Default unset =
+inherit the brain's own. The mapping (effort IS part of the cache-key OPTS
+string, so changing only effort is a cache miss):
+
+| Brain | How effort is applied |
+|---|---|
+| glm (fleet-worker) | `FLEET_WORKER_EFFORT=<v>` in the worker env |
+| codex (`codex exec`) | `-c model_reasoning_effort="<v>"` |
+| sonnet/opus/haiku/fable | `claude -p --settings '{"effortLevel":"<v>"}'` |
+
+Doctrine (carried from the native tool): reach for the effort lever before the
+model lever. Effort is recorded in the manifest packet, so `ff-run resume`
+replays each lane at its captured effort.
+
+**Cache & tmp redirect.** Every worker launch exports `UV_CACHE_DIR`,
+`TMPDIR`, `TMP`, `TEMP` into the worker env pointing at
+`${FLEETFLOW_CACHE_ROOT:-$HOME/.fleet-worker/cache}/<run>-<id>/` (created
+pre-launch). This keeps uv/pytest cache and codex sandbox litter OUT of the
+repo and lanes — the AppContainer-ACL'd dirs codex leaves behind resist
+unelevated deletion and would otherwise block `git worktree remove` (the
+`sandbox litter gotcha`, §2). Set `FLEETFLOW_CACHE_ROOT` once for the whole run
+and pass the same value to `ff-clean` so it can reclaim the dirs.
+
+**Transcript archiving** (best-effort, never fails the lane). After a
+non-dry-run claude-brain lane, the session transcript is copied to
+`<rundir>/<id>.transcript.jsonl`:
+
+- **glm**: newest `projects/*/*.jsonl` under the worker's isolated config dir
+  (`FLEET_WORKER_CONFIG_DIR`, default `$HOME/.fleet-worker/cfg-ff-<id>`).
+- **sonnet/opus/haiku/fable**: the result envelope's `session_id` resolves to
+  `$HOME/.claude/projects/<encoded-workdir>/<session_id>.jsonl`, where the
+  encoding is per-char `[:\\/.]` → `-` (verified empirically: `C:\Users\Mack`
+  → `C--Users-Mack`). Falls back to a `<session_id>.jsonl` search across all
+  project dirs if the encoded path misses.
+
+If the source transcript can't be found, the lane logs a `transcript source
+not found ... skipped (non-fatal)` warning and continues — the transcript is a
+convenience for inspection/audit, not a gate.