Skip to main content

headless-run

Run a Claude Code skill or command headlessly in an isolated subprocess — fresh session id, clean HOME and config dir, scrubbed env, JSON result, timeout. Use for scripted one-shot invocations and benchmark-harness cases (e.g. running /code-review once per case), to run an isolated claude -p, or to avoid a nested run reusing the parent Remote session identity or tool surface. Trigger phrases include "run a skill headlessly", "isolated claude -p", "benchmark harness invocation", "run /code-review headlessly", "run it once per case", and "avoid nested session reuse".

Source facts

Repository
bdfinst/agentic-dev-team
Last source activity
August 1, 2026 at 14:33
Detected SKILL.md language
English
Stars
299
Forks
36

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
2 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
headless-run
description
Run a Claude Code skill or command headlessly in an isolated subprocess — fresh session id, clean HOME and config dir, scrubbed env, JSON result, timeout. Use for scripted one-shot invocations and benchmark-harness cases (e.g. running /code-review once per case), to run an isolated claude -p, or to avoid a nested run reusing the parent Remote session identity or tool surface. Trigger phrases include "run a skill headlessly", "isolated claude -p", "benchmark harness invocation", "run /code-review headlessly", "run it once per case", and "avoid nested session reuse".
argument-hint
<prompt-or-slash-command> [--cwd DIR] [--model MODEL] [--timeout SECS]
user-invocable
true
allowed-tools
Read, Bash
# Headless Run Role: worker. This skill runs one Claude Code prompt in a maximally isolated subprocess and returns its JSON result — it does not review, plan, or edit. ## When to use it Use it for **scripted, one-shot headless invocations** — above all a benchmark harness that shells out to `claude -p` per case (the #821 harness that runs `/code-review` once per fixture). A plain nested `claude -p` launched inside a live Claude Code Remote session inherits the parent's identity and tool surface (see `docs/using-plugin-skills-in-the-web-environment.md` and issue #842): - **Reused `session_id`** — the nested run reports the *same* session id as the parent, so runs are not independent. - **Remote-injected tool surface** — the nested run sees Remote-runtime MCP tools a local CLI session never exposes, changing the tool set under test. This skill is the reusable workaround for that #842 constraint. ## Isolation guarantees The helper builds each dispatch to leak as little parent state as possible: - **Fresh session id.** A new `uuid.uuid4()` is passed as `--session-id <uuid>`, so the nested run cannot reuse the parent `session_id`. This is the key fix. - **Clean HOME + config.** A throwaway temp `HOME` and `CLAUDE_CONFIG_DIR` — no shared config, `.claude/memory/`, or telemetry state carries over. - **Scrubbed env.** Inherited `CLAUDE_*` session/Remote identity vars (e.g. `CLAUDE_SESSION_ID`, `CLAUDE_CODE_SESSION_ID`, `CLAUDE_CODE_ENTRYPOINT`, `CLAUDE_CODE_REMOTE`) are removed, then `IS_SANDBOX=1` and `DEV_TEAM_TELEMETRY=off` are set fresh. - **No resume.** The command never uses `--resume`/`-r` or `--fork-session`. - **JSON result + timeout.** Runs with `--output-format json` and a hard subprocess timeout; prints the verified `session_id`, cost, and token usage. ## Auth vs. isolation (#957) The fresh `HOME` also wipes Claude Code's login state, so a dispatch reports "Not logged in" unless `ANTHROPIC_API_KEY` is set. `~/.claude.json` alone does **not** fix this — confirmed empirically, twice — something under `~/.claude/` itself gates the login check ahead of Claude Code's actual (Keychain-backed) OAuth token lookup. Pass `--preserve-auth` to copy `~/.claude.json` and most of `~/.claude/` into the cell home first, restoring login for operators who authenticate via `claude login` rather than an API key. This is a real tradeoff, not free: it carries over `settings.json`, `projects/`, `sessions/`, `mcpServers`, `plugins/`, and other app state — `copy_auth_state()`'s `_CLAUDE_DIR_EXCLUDE` skips the clearly bulky, clearly-not-auth-related pieces (`history.jsonl`, `file-history/`, `session-env/`, `paste-cache/`, `shell-snapshots/`, `debug/`, `telemetry/`, `downloads/`), but everything else rides along since we don't have a confirmed narrower answer for exactly which piece satisfies the login check. Off by default; the code-review-benchmark harness (`runner.make_isolated_dispatch_fn()`) turns it on unconditionally, since running that harness at all presupposes the operator's own subscription. It improves on the existing precedent in `scripts/run_tdd_experiment.py` (`make_cell_home` / `cell_env` / `dispatch`), which does `env = dict(os.environ)` and does **not** scrub identity vars. ## Honest upstream caveat The `session_id` and **tool-surface** inheritance is an **upstream Claude Code / Remote-runtime behavior — not fixable in this plugin repo**. This skill removes env-carried identity and forces a fresh session id, but **Remote-injected MCP tools are not env-carried and cannot be scrubbed here**. The fully-supported path for a benchmark harness therefore stays a **plain local CLI checkout, not a run nested inside a Remote session**. Use this skill to maximize isolation when a local checkout is not available; treat its results as best-effort under that caveat. ## How to invoke the helper Run the shipped script, passing the prompt (a slash command works) and optional `--cwd` / `--model` / `--timeout`: ```bash python3 "${CLAUDE_PLUGIN_ROOT}/skills/headless-run/scripts/isolated_dispatch.py" \ "/code-review" --cwd "$TARGET_REPO" --model sonnet --timeout 900 [--preserve-auth] ``` It prints one JSON object (`session_id`, `cost_usd`, token counts, `num_turns`, `is_error`) and exits non-zero on error or timeout — parse that in the harness. When running from files without the plugin loaded, substitute the in-repo path `plugins/dev-team/skills/headless-run/scripts/isolated_dispatch.py`. ## Output Report the printed JSON result (or the timeout/error line) and the fresh `session_id` the dispatch used. Be concise — do not restate the script body.
View on GitHub