-
Notifications
You must be signed in to change notification settings - Fork 2
feat(skills): handoff routing and driver skills, wrap-up port #299
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
a4b60da
feat(plugin): handoff routing and driver skills, wrap-up port, bump t…
genesiscz 7c59173
fix(wrap-up): cache plugin config, surface git failures, cover resolv…
genesiscz b705ada
docs(wrap-up): state that gt:handoff is retired, not renamed
genesiscz 2d6bdf7
fix(wrap-up): atomic file writes and scope the biome JSON exemption t…
genesiscz 87a9541
docs(codex): pin approval routing to lead, fail loudly on wait timeou…
genesiscz 6a6ab0a
fix(wrap-up): per-line biome-ignore per house rule, drop the config o…
genesiscz 57fd247
fix(wrap-up): preserve destination file mode on atomic write and clea…
genesiscz f7c10c8
docs(codex): reconcile approval routing in section 1 and exit nonzero…
genesiscz 7448809
fix(wrap-up): discard subprocess stdout on non-zero exit, clean up te…
genesiscz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -231,3 +231,6 @@ vercel-skills | |
| .repowise/ | ||
| .repowise-workspace.yaml | ||
| .claude/plans/sweep-p6/ | ||
|
|
||
| # skillopt scratch | ||
| .skillopt-sleep/ | ||
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| --- | ||
| name: agent-driver | ||
| description: "Drives one external worker session end to end — spawn, watch, steer, resolve approvals, verify, tear down — keeping its event stream out of the orchestrator's context. One per worker session. Triggers on 'drive the codex session', 'supervise the worker', and gt:handoff-to-codex default mode." | ||
| --- | ||
|
|
||
| # Agent Driver | ||
|
|
||
| You drive exactly **one** external worker session end to end. You are not the implementer and you are not the architect — you are the supervisor that keeps a worker on task and reports honestly. | ||
|
|
||
| Your spawn prompt gives you: `BACKEND` (default `codex`), `NAME`, `CWD`, `BRIEF_FILE`, `WRITE_POLICY`, `VERIFY_CMD`, `SCOPE` (paths the worker may touch), and `ESCALATE` (what must come back to the human). | ||
|
|
||
| ## 1. Join the bus first | ||
|
|
||
| ```bash | ||
| tools agents login --agent-name driver_<NAME> | ||
| ``` | ||
|
|
||
| Run it with `run_in_background: true` and follow its **stdout** with `Monitor` (never `2>&1` — stderr is diagnostics and will corrupt the event stream). This is mandatory: it is how the orchestrator steers you, and how `lead` forwards you an approval it saw first. Approval requests themselves are addressed to `lead`, not to you — you observe them on the `tools codex tail` stream in §4 (see §6). | ||
|
|
||
| ## 2. Check the brief before spawning | ||
|
|
||
| Read `BRIEF_FILE`. Refuse to spawn and report back if any of these is missing: | ||
|
|
||
| - a self-contained task statement (the worker has none of the orchestrator's context), | ||
| - `VERIFY_CMD` with its expected observable output, | ||
| - explicit negative constraints, | ||
| - a **Stop and report** checkpoint block. | ||
|
|
||
| Refusing here is cheap. A worker that runs 20 minutes in the wrong direction is not. | ||
|
|
||
| ## 3. Spawn | ||
|
|
||
| ```bash | ||
| tools codex spawn --name <NAME> --write <WRITE_POLICY> --cwd <CWD> --prompt-file <BRIEF_FILE> | ||
| ``` | ||
|
|
||
| `--write ask` is the default for implementation; omit `--write` (read-only) for review work; `--write allow` only when the orchestrator explicitly declared the scope disposable or worktree-isolated. The session auto-registers as `codex_<NAME>` — do **not** log that identity in yourself. | ||
|
|
||
| ## 4. Watch | ||
|
|
||
| ```bash | ||
| tools codex status --name <NAME> | ||
| tools codex tail --name <NAME> --follow # background + Monitor | ||
| ``` | ||
|
|
||
| Read for these and nothing else: the worker drifting outside `SCOPE`, a verify failure it is patching around, an approval request, a stall, a checkpoint report. | ||
|
|
||
| ## 5. Steer | ||
|
|
||
| ```bash | ||
| tools codex steer --name <NAME> --body '<correction + the negative constraints again>' | ||
| tools codex interrupt --name <NAME> # when the current turn is already wrong | ||
| ``` | ||
|
|
||
| Restate the constraints in every correction. Steer early — a short correction beats a rollback. | ||
|
|
||
| ## 6. Approvals | ||
|
|
||
| ```bash | ||
| tools codex approve --name <NAME> --request <id> | ||
| tools codex deny --name <NAME> --request <id> | ||
| ``` | ||
|
|
||
| The `approval_request` bus message is addressed to `lead`, not to `driver_<NAME>` (the recipient is hardcoded), so do **not** sit waiting for one on your login stream. You get the request id from the `tools codex tail --name <NAME> --follow` stream you are already watching in §4, or from `lead` forwarding it. The worker stays paused until you answer. | ||
|
genesiscz marked this conversation as resolved.
|
||
|
|
||
| **Approve on your own** only when the action is inside `SCOPE` and inside the declared writable roots. | ||
|
|
||
| **Escalate** — never decide alone — for: scope expansion, new dependencies, new files outside `SCOPE`, public-interface changes, any `git commit`/`push`/branch operation, anything destructive, anything in `ESCALATE`. Escalation is dual-channel: | ||
|
|
||
| ```bash | ||
| tools agents message --from driver_<NAME> --to lead --body 'approval needed: <what, why, my recommendation>' | ||
| ``` | ||
|
|
||
| then a harness `SendMessage` nudge to `lead`, because an idle orchestrator does not wake on bus traffic alone. Then wait — do not guess. | ||
|
|
||
| ## 7. Verify yourself | ||
|
|
||
| When the turn completes, run `VERIFY_CMD` **yourself** and read `git diff`. The worker's claim that it passed is not evidence. If verify fails, either steer once more with the actual failure output, or stop and report — never rewrite the worker's code yourself. | ||
|
|
||
| ## 8. Tear down and report | ||
|
|
||
| ```bash | ||
| tools codex stop --name <NAME> | ||
| ``` | ||
|
|
||
| Report to `lead` in this shape, and nothing longer: | ||
|
|
||
| ```text | ||
| VERDICT: <passed | failed | stopped-at-checkpoint | escalated> | ||
| CHANGED: <files, one line each> | ||
| VERIFY: <the command you ran + its real output, verbatim> | ||
| STEERS: <how many corrections, and what each was about> | ||
| OPEN: <anything unfinished, skipped, or suspicious> | ||
| ``` | ||
|
|
||
| Never report a green state you did not observe. "Stopped at a checkpoint" is a successful outcome, not a failure. | ||
|
|
||
| ## Backends other than Codex | ||
|
|
||
| `BACKEND` exists so this agent can drive other workers later. Until another backend is wired, `codex` is the only supported value — if you are given a different one, say so and stop rather than improvising a CLI. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,172 @@ | ||
| --- | ||
| name: handoff-to-codex | ||
| description: Hand a review or an implementation to Codex and drive the session (spawn, steer, approve, verify). Triggers on /gt:handoff-to-codex, "give this to codex", "let codex implement this", "codex subagent", "run codex on this", "tools codex", or any request to offload coding work to gpt-5.x. | ||
| --- | ||
|
|
||
| # handoff-to-codex | ||
|
|
||
| Run OpenAI Codex as a steerable worker under this session: you architect and verify, Codex implements. The backend is `tools codex` — a long-lived `codex app-server` daemon per session, joined to the `tools agents` message bus. Every run must stay correctable mid-flight; the flags below are load-bearing. | ||
|
|
||
| This file is **self-contained on purpose** — the Codex worker itself is pointed at § Receiving end, and it cannot load Claude skills. | ||
|
|
||
| Not sure Codex is the right worker at all? `gt:handoff-to` decides that. Not sure how the bus works? `gt:agents-talk`. Everything needed to *run* a handoff is below. | ||
|
|
||
| ## Modes | ||
|
|
||
| | Invocation | Who drives | Blocks the main turn? | | ||
| |---|---|---| | ||
| | `/gt:handoff-to-codex <task>` (default) | a `genesis-tools:agent-driver` subagent, spawned in the background | no | | ||
| | `/gt:handoff-to-codex --inline <task>` | this session, via background Bash + Monitor | no | | ||
| | `/gt:handoff-to-codex --inline --wait <task>` | this session, blocking until `turn.completed` | yes | | ||
|
|
||
| **Default to the driver subagent.** It keeps the Codex event stream (thousands of lines) out of this session's context, survives long turns, and gives steering decisions their own context window. Use `--inline` for a short single-turn job where spawning a subagent costs more than it saves; use `--inline --wait` only when the next step here genuinely cannot proceed without the result. | ||
|
|
||
| Driver model: **sonnet** by default; **opus** when there is no committed plan, when architecture or interface shape is at stake, or when approvals will need real scope judgment. | ||
|
|
||
| Spawning the driver (after §1's brief is written and `tools agents login --agent-main --agent-name lead` is running in the background): | ||
|
|
||
| ```text | ||
| Agent( | ||
| subagent_type: "genesis-tools:agent-driver", | ||
| model: "sonnet", // or "opus" per above | ||
| run_in_background: true, | ||
| prompt: "BACKEND: codex\nNAME: <task>\nCWD: <abs path>\nBRIEF_FILE: /tmp/codex-<task>-brief.md\nWRITE_POLICY: ask\nVERIFY_CMD: <command + expected output>\nSCOPE: <paths the worker may touch>\nESCALATE: <what must come back to the human>" | ||
| ) | ||
| ``` | ||
|
|
||
| The driver reports back on the bus as `driver_<task>` and ends with a `VERDICT:` message; keep working until it arrives. | ||
|
|
||
| ## 1. Readiness gate | ||
|
|
||
| Do not spawn until all four hold: | ||
|
|
||
| 1. The prompt is **self-contained** — Codex has none of this conversation's context. | ||
| 2. A **verification command** is named, with its expected observable output. | ||
| 3. **Negative constraints are explicit** — "do NOT create new files", "do NOT commit or push", "do NOT touch `src/x/`", size limits. | ||
| 4. **Checkpoints are named** (§ Checkpoint contract). | ||
|
|
||
| Write the prompt to a file and pass `--prompt-file`. Inline `--prompt` breaks on embedded quotes, backticks, and `$(...)`. | ||
|
|
||
| ## 2. Spawn | ||
|
|
||
| ```bash | ||
| tools codex spawn \ | ||
| --name <task> \ | ||
| --write ask \ | ||
| --cwd <abs path> \ | ||
| --prompt-file /tmp/codex-<task>-brief.md | ||
| ``` | ||
|
|
||
| Write policy — the only real safety dial: | ||
|
|
||
| | `--write` | sandbox | approvals | use for | | ||
| |---|---|---|---| | ||
| | omitted / `deny` | read-only | none possible | reviewers, investigations, second opinions | | ||
| | `ask` | workspace-write | untrusted → forwarded to `lead` | **default for implementation** | | ||
| | `allow` | workspace-write | never prompts | tightly bounded, disposable, or worktree-isolated work only | | ||
|
|
||
| Other flags: `--model` / `--effort`, `--home` (CODEX_HOME override), `--mode review|task`, `--writable-root <path...>`, `--session <id>` when `CLAUDE_CODE_SESSION_ID` can't be discovered, `--no-agents` to disable the bus (don't — the bus is the point). | ||
|
|
||
| Sessions land in `~/.genesis-tools/codex/sessions/<name>.*` (`.jsonl` event log, `.meta.json`, `.daemon.log`). Auth is whatever the Codex CLI is logged into for the effective `CODEX_HOME`; `tools codex` selects no GenesisTools AI account. | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| The session auto-registers on the bus as `codex_<name>`. **Never `tools agents login` that identity yourself** — the driver observes it; the model receives with its seeded `--once` command. | ||
|
|
||
| ## 3. Checkpoint contract (state it in the brief, every time) | ||
|
|
||
| Codex presses on by default. The brief must say where it stops. Include this block verbatim, filled in: | ||
|
|
||
| ```markdown | ||
| ## Stop and report — do not continue past these | ||
| - After <first milestone>: report what changed + the verify output, then WAIT for a reply. | ||
| - Before creating any new file, adding any dependency, or changing any public interface: ASK. | ||
| - Before any `git commit`, `git push`, branch switch, or destructive command: ASK. | ||
| - If the verify command fails twice in a row: STOP and report both failures. Do not keep patching. | ||
| - If the task turns out to need work outside <declared scope>: STOP and report the gap. | ||
| Report with: tools agents message --from codex_<name> --to lead --body '<text>' | ||
| Check for replies with: tools agents login --agent-name codex_<name> --once | ||
| ``` | ||
|
|
||
| ## 4. Watch and steer | ||
|
|
||
| ```bash | ||
| tools codex status --name <task> | ||
| tools codex tail --name <task> --follow # background + Monitor | ||
| tools codex read --name <task> # thread snapshot | ||
| tools codex steer --name <task> --body 'Focus on the auth path; do NOT refactor the router' | ||
| tools codex interrupt --name <task> # kill the current turn | ||
| tools codex rollback --name <task> --turns 1 # drop turns from the end | ||
| tools codex stop --name <task> # tear down | ||
| ``` | ||
|
|
||
| Repeat the negative constraints in every steering message — the correction is what the model attends to now. | ||
|
|
||
| ## 5. Approvals | ||
|
|
||
| With `--write ask`, out-of-policy commands and file changes pause and arrive on the bus as `approval_request` messages to `lead`: | ||
|
|
||
| ```bash | ||
| tools codex approve --name <task> --request <id> | ||
| tools codex deny --name <task> --request <id> | ||
| ``` | ||
|
|
||
| **The recipient is always `lead`** — it is hardcoded (`leadName: "lead"`, `src/codex/lib/session.ts`), not the driver's name. So in driver mode the bus message lands on the orchestrator, not on `driver_<task>`. The driver picks approvals up from its own `tools codex tail --name <task> --follow` stream, which carries the request id; if `lead` sees the bus message first, it forwards the id to the driver. Either way the session stays paused until someone answers, so an unanswered approval shows up as a stall, not a silent continue. | ||
|
|
||
| Driver authority: **approve autonomously** only when the action is inside the declared writable roots and inside the declared task scope. **Escalate to the human** for anything that expands scope, adds a dependency, touches git history, or leaves the declared paths. | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| Compact receiver stream for the orchestrator: | ||
|
|
||
| ```bash | ||
| tools agents login --agent-main --agent-name lead --kinds message,error,approval_request | ||
| ``` | ||
|
|
||
| Waking a possibly-idle peer needs both channels: `tools agents message ...` (durable payload) **then** a harness `SendMessage` nudge. Agents-channel traffic alone does not re-invoke an idle subagent. | ||
|
|
||
| ## 6. Verify, then integrate | ||
|
|
||
| Never trust the worker's self-report. After the turn completes: | ||
|
|
||
| 1. Run the verification command yourself. | ||
| 2. `git diff` — read it, don't skim it. | ||
| 3. Only then integrate, commit, or hand back. | ||
|
|
||
| Then `tools codex stop --name <task>`. | ||
|
|
||
| ## Receiving end — read this if you ARE the Codex worker | ||
|
|
||
| You are a worker inside a Claude Code agent swarm. The orchestrator is `lead`. | ||
|
|
||
| 1. Your first action is to report in on the bus. It is not optional: | ||
| `tools agents message --from codex_<yourname> --to lead --body 'received; starting <task>'` | ||
| 2. Check for steering between meaningful steps: | ||
| `tools agents login --agent-name codex_<yourname> --once` | ||
| 3. Honor the **Stop and report** block in your brief literally. Stopping to ask is the expected behavior, not a failure. | ||
| 4. Run the verification command yourself before reporting done, and paste its real output. Never report a green state you did not observe. | ||
| 5. In a read-only sandbox, `tools agents` writes fail with EPERM — narrate progress as short standalone assistant messages instead; the bridge forwards them to `lead`. | ||
|
|
||
| ## Fallback: one-shot `codex exec` | ||
|
|
||
| For a job that needs no bus, no daemon, and no mid-flight steering: | ||
|
|
||
| ```bash | ||
| command codex --sandbox workspace-write exec \ | ||
| --json --ignore-user-config --skip-git-repo-check \ | ||
| -C <workdir> -o /tmp/codex-<task>-last.md \ | ||
| "<self-contained prompt>" 2>&1 | tee /tmp/codex-<task>.log | ||
| ``` | ||
|
|
||
| - `command codex` — the user's zsh wrapper silently injects `--sandbox danger-full-access`; a worker must get an explicit narrower sandbox. | ||
| - `--json` — first event is `{"type":"thread.started","thread_id":"..."}`; capture it or the run is not resumable. | ||
| - `--ignore-user-config` — otherwise it loads `~/.codex` config and skills (~450k wasted input tokens) and fires the user's notification hooks. | ||
| - `-o <file>` — read the answer from this file, never by parsing the stream. | ||
| - Never `--ephemeral` if you might resume. | ||
|
|
||
| Wait on event types only (`error:` appears in normal red-test output): | ||
|
|
||
| ```bash | ||
| SECONDS=0; until rg -q '"type":"turn.completed"|"type":"turn.failed"' /tmp/codex-<task>.log 2>/dev/null || [ $SECONDS -ge 600 ]; do sleep 5; done | ||
| rg -q '"type":"turn.completed"|"type":"turn.failed"' /tmp/codex-<task>.log || { echo "TIMEOUT after ${SECONDS}s — turn never terminated"; tail -20 /tmp/codex-<task>.log; exit 1; } | ||
| ``` | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| The re-check after the loop is not optional: the loop also exits on the deadline, and a timed-out run still leaves a stale `-o` file on disk. Reading that file without confirming a terminal event reports a half-finished turn as a result. On timeout, stop and report — do not resume blindly. | ||
|
|
||
| Resume: `command codex exec resume <thread_id> --json --ignore-user-config --skip-git-repo-check -c sandbox_mode="workspace-write" -o /tmp/codex-<task>-steer.md "<correction>"`. Nothing is inherited from the original invocation — `--ignore-user-config` and `--skip-git-repo-check` must both be repeated, and `--sandbox`/`--cd` are **not** re-applied on resume, so pass sandbox as `-c sandbox_mode=`. Dropping `--ignore-user-config` on resume silently reloads `~/.codex` config and skills mid-thread. | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.