Skip to content

obra/external-subagents

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

71 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

codex-subagent-cli

A TypeScript CLI for launching and managing Codex subagents without bloating the primary agent's context. Threads run via codex exec --json, with metadata stored under .codex-subagent.

Getting Started

cd dev
npm install
npm run build

All commands assume Node 20+ and npm 10+. The build outputs codex-subagent to the repo root.

CLI Usage

codex-subagent <command> [options]

Installing as a Codex Skill

Clone this repository to ~/.codex/skills/using-subagents-as-codex/:

git clone https://github.com/obra/external-subagents ~/.codex/skills/using-subagents-as-codex
cd ~/.codex/skills/using-subagents-as-codex/dev
npm install
npm run build

Codex will use the relative path codex-subagent when invoking the CLI from the skill.

Global flags

  • --root <path>: override the default .codex-subagent root.
  • --controller-id <id>: override the auto-detected controlling Codex session (use this when multiple Codex windows should share the same subagent state).
Command Purpose
start Launch a new Codex exec thread with explicit role/policy (defaults to detached, so it returns immediately; add --wait to block).
send Resume an existing thread with a new prompt (defaults to detached, add --wait to block).
peek Show the newest unseen assistant message (read-only; --verbose prints last-activity info).
log View the stored NDJSON history (supports --tail, --raw, --verbose).
status Summarize the latest activity for a thread (latest message, idle time, optional log tail).
watch Continuously peek a thread at an interval (use --duration-ms to exit cleanly).
wait Block until specific threads (or labels/all threads) reach a stopped state; optional timeout + “follow last assistant” output.
archive Move completed thread logs/state into .codex-subagent/archive/... (with --yes/--dry-run).
label Attach/update a friendly label for a thread so list is easier to scan.
list List every thread owned by the current controller (and show a “Launch diagnostics” section when detached start/send attempts are still pending or have failed, including error logs).

Per-command notes:

  • start requires --role, --policy, and --prompt-file (write prompts to files to avoid shell quoting issues). Policies are mapped to safe --sandbox / --profile combinations automatically.
  • start --manifest tasks.json (or --manifest-stdin) launches multiple prompts from a single JSON payload. Each task entry accepts prompt, role, policy, cwd, label, persona, outputLast, and wait. This is the fastest way to spin up a whole squad of helpers; reference prompts inline in JSON so you don’t have to create dozens of temp files.
  • start --json prompt.json (or --json - with stdin) accepts a single structured payload: { "prompt": "...", "role": "researcher", "policy": "workspace-write", "cwd": "/repo", "label": "Task", "persona": "reviewer", "output_last": "last.txt", "wait": true }. Fields mirror the CLI flags, so you can drop prompt files entirely for ad-hoc work.
  • send --json followup.json works the same way for resume turns (prompt, cwd, persona, output_last, wait).
  • start warns that long-running Codex sessions may take minutes or hours. Use the default detached mode when you just want the work to continue in the background, and --wait when you truly need to stream the run inline.
  • start/send accept --cwd <path> to automatically prepend “work inside /path” instructions, --label to tag new threads, and --persona <name> to merge Anthropic-style agent personas (project .codex/agents/, ~/.codex/agents/, superpowers agents/). Model aliases (haiku, sonnet, opus, inherit) are mapped onto safe Codex policies; if a persona sets model: sonnet, we’ll use workspace-write, etc.
  • send needs --thread + --prompt-file and, like start, runs detached unless you pass --wait. If a persona was set when the thread started, later send calls reuse the same persona automatically unless you override it with --persona.
  • peek, log, watch all require --thread and never call Codex (they read the local log/registry). peek/log accept --verbose to print last activity timestamps even when nothing changed; watch adds --duration-ms so you can stop polling automatically instead of relying on Ctrl+C.
  • status --thread <id> [--tail 5] [--stale-minutes 15] gives a one-shot summary (latest assistant turn, idle duration, and a suggestion to nudge if the thread has been idle longer than the threshold).
  • wait --threads id1,id2 --follow-last polls the registry/logs until every selected thread stops. Use --labels label-a,label-b or --all-controller to track batches launched via manifests, --interval-ms to tune polling frequency, and --timeout-ms to fail fast instead of waiting forever. When --follow-last is set you’ll also see the final assistant reply for each thread as it finishes.
  • --print-prompt shows the fully composed prompt (persona + working directory instructions) before launching Codex. Add --dry-run to skip the Codex invocation entirely after printing—handy for sanity-checking inputs.
  • label --thread <id> --label "Task X" lets you rename an existing thread after the fact (pass an empty string to clear it).
  • archive --thread <id> --yes moves a completed thread into the archive. Use --completed --yes to archive all completed threads, or --dry-run to preview.
  • list now prints a Launch diagnostics section whenever a detached start/send attempt hasn’t reached Codex yet or failed immediately. Failed launches appear with NOT RUNNING plus the captured error message and a pointer to .codex-subagent/state/launch-errors/<launch-id>.log; pending launches older than ~2 minutes emit a “still waiting for Codex” warning so you know to investigate.

JSON prompt payloads

Skip ad-hoc prompt files by piping JSON straight into start or send:

cat <<'JSON' | codex-subagent start \
  --role researcher \
  --policy workspace-write \
  --json - \
  --print-prompt
{
  "prompt": "List open bugs, then propose a fix.",
  "cwd": "/Users/jesse/repos/service",
  "label": "Bug sweep",
  "persona": "triage",
  "output_last": "/tmp/bugs-last.txt",
  "wait": true
}
JSON

The same schema works for send:

codex-subagent send --thread 019... --json followup.json --wait

Relative paths inside the JSON payload are resolved against the file’s directory (or the current working directory when using stdin), so you can keep everything self-contained beside your manifest/prompt files.

Launch diagnostics & troubleshooting

  • Where errors live: Every detached start/send attempt writes a record to .codex-subagent/state/launches.json until Codex produces a thread turn. If launch fails (missing profile, sandbox denial, etc.), the CLI preserves the full stderr/stack under .codex-subagent/state/launch-errors/<launch-id>.log and list marks the attempt as NOT RUNNING.
  • How to detect issues: Run codex-subagent list after launching helpers. If the Launch diagnostics section shows a pending attempt with the warning “still waiting for Codex (no thread yet),” Codex hasn’t even started—re-run the prompt or inspect the log file. Failed entries include the exact error plus the log path so you can fix the root cause before retrying.
  • Thread failures after resume: When a detached send fails, the owning thread’s status flips to NOT RUNNING and the reason appears via list + status. status --thread <id> now prints the failure message directly, so you can summarize the issue without re-reading the log.
  • Home directory sandboxing: If the environment blocks writes to ~/.codex (common under workspace-only sandboxes), codex-subagent automatically runs codex exec with CODEX_HOME=./.codex-home (created in the current working directory) and best-effort copies ~/.codex/auth.json + ~/.codex/config.toml into it. .codex-home/ is gitignored but contains credentials—treat it like a secret.
  • Claude backend (optional): Claude support is behind a feature flag. Set CODEX_SUBAGENT_ENABLE_CLAUDE=1 to use --backend claude.

Demo

npm run demo spins up a throwaway thread and then attaches watch so you can see updates flow through without any manual wiring.

Development

  • Format: npm run format:fix
  • Lint: npm run lint
  • Type-check: npm run typecheck
  • Tests: npm run test
  • Build bundle: npm run build

peek/log/watch share NDJSON logs under .codex-subagent/logs/<thread>.ndjson. Registry metadata lives in .codex-subagent/state/threads.json (commit this file only when intentionally sharing test fixtures).

Policies & Safety

Subagents must never run in "allow everything" mode. The CLI enforces this by refusing dangerous policies and mapping safe ones to explicit --sandbox/--profile parameters when invoking codex exec. Every thread is also tagged with the controller session ID (auto-detected from the parent Codex process or supplied via --controller-id), and commands refuse to act on threads owned by some other controller.

About

Codex subagent CLI and tooling

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •