Executor Abstraction
A reusable abstraction for running implementation work in an isolated
workspace, independent of which agent host (Claude Code, Codex) or which
mechanism is available. Lifecycle skills speak one vocabulary of operations;
this skill maps each operation to a concrete recipe per mode. It is consumed as
a library by /aep-launch, /aep-build, and /aep-autopilot, and can be
invoked standalone to dry-run detection (see Standalone Usage).
Native-first: Claude Code launches use a native in-process background subagent
(native-bg-subagent, the default) or — where the claude --bg flag exists —
native background sessions (claude-bg); Codex launches use native subagents
(codex-subagent) or headless exec workers (codex-exec). tmux+cmux is the
legacy mode — selected only by explicit pin
(git config aep.executor-backend tmux) or on generic hosts. Every mode runs its
worker in an AEP-created git worktree at .feature-workspaces/<ws>.
How Other Skills Use This
| Skill |
What it uses |
Operations |
/aep-launch |
Start the implementation agent + expose it for review |
detect, spawn, present |
/aep-build Phase 5 |
Spawn the evaluator in the right execution context |
detect, spawn_evaluator |
/aep-build |
Raise a human decision mid-build |
gate |
/aep-autopilot |
Run the periodic tick check cheaply; steer workspaces |
detect, check, nudge, liveness, gate |
/aep-wrap |
Tear down the worker + worktree after merge |
teardown |
/aep-dispatch |
Resolve the handoff mode; route "…with workflow" runs |
detect |
The Operation Contract
Every consumer speaks these verbs. The recipe files supply the implementation
per mode.
| Op |
Purpose |
detect() |
Resolve host + native capabilities + pin, select a mode |
spawn(ws, branch, prompt) |
Start an implementation agent bound to the AEP worktree |
spawn_evaluator(ws, role) |
Start an evaluator agent (worktree-bound) in the mode's eval context; accepts an optional tier-derived effort hint (see backends.md) |
nudge(ws, msg) |
Send a mid-flight instruction (steerable modes; pull-based under claude-bg) |
liveness(ws) |
Is the agent actively working? (mode-specific signal + git-diff corroboration) |
gate(ws) |
Surface a worker's human decision: needs-human.md + the mode's transport, answered hub-and-spoke through the main agent (block-in-place or gate-and-park) |
check(prompt, schema) |
Run a read-only analysis prompt in a cheap, context-isolated agent; return its JSON result — keeps a long-lived orchestrator session's context small |
monitor(ws) |
Read .dev-workflow/signals/status.json — host-independent, never changes |
present(ws) |
Human review surface (TaskOutput / claude attach / Codex thread / cmux tab / signals) |
teardown(ws) |
Worker + worktree cleanup |
monitor() is already abstract. Progress is reported through signal files
at phase boundaries regardless of the executor. Native push channels
(SendMessage, send_input) are an acceleration layer — the signal files remain
the durable, host-agnostic source of truth.
The Modes (summary)
| Mode |
Lifetime |
Selected when |
| native-bg-subagent |
session-bound |
Claude Code default + long-lived orchestrator |
| claude-bg |
OS-bound |
Claude Code, claude --bg present (cron driver / OS-bound need) |
| codex-subagent |
session-bound |
Codex with a living main thread (desktop app or interactive CLI) |
| codex-exec |
OS-bound |
Codex + cron driver, or hard isolation demanded |
| legacy |
OS-bound |
explicit pin (aep.executor-backend tmux), or generic host w/ tmux |
| workflow |
session-bound |
explicit opt-in ("…with workflow") + Claude Code (see /aep-workflow) |
| headless |
session-bound |
last resort |
Read references/backends.md for each mode's mechanism, the detection recipe,
the full selection order, the driver × backend compatibility matrix, the
human-gate protocol, and orphan re-adoption.
Reference Files
| File |
Contents |
When to read |
references/backends.md |
Mode matrix, detection, selection order, driver compatibility, gate protocol, orphan re-adoption, check() |
Always, before spawning or steering |
references/claude-native.md |
native-bg-subagent (default) + claude-bg recipes, --bg availability note |
When the selected mode is a Claude native one |
references/codex-native.md |
codex-subagent + codex-exec recipes, aep-builder/aep-evaluator role TOMLs, desktop app mapping |
When the selected mode is a Codex one |
references/tmux-session.md |
legacy recipes (tmux spawn/nudge/liveness, cmux tab ladder) |
When legacy is pinned or selected |
references/dogfood-validation.md |
dogfood_method() host × mode detection, e2e_tool(), target_url() resolution |
When running dogfood validation (consumed by /aep-build, /aep-launch, /aep-watch, the autopilot post-merge guard) |
The skill also ships two probes, so the exact bash lives in one place instead of
being retyped from a reference:
scripts/detect-backend.sh [--lifetime long|ephemeral] [--opt-in workflow|tmux] [--json]
— host, executor commands, native capabilities, pin, presentation surface, and
the selected MODE. eval "$(bash scripts/detect-backend.sh)" to use it.
scripts/spawn-liveness-probe.sh <name> <agent_id> — the post-spawn liveness
probe every spawner runs (references/backends.md § Post-Spawn Liveness Probe).
Standalone Usage
Invoked directly, this skill reports what would happen:
- Run
bash scripts/detect-backend.sh (add --lifetime ephemeral when this
invocation is a cron/launchd one-shot — the script cannot probe that).
- Report each field it prints, and say why that
MODE won: which earlier
rule in the selection order did not match.
- If the user asked "why not workflow / why not tmux", explain the opt-in/pin
gates.
This does not spawn anything — it is a dry-run of detect().
Rationale
Why native modes come first and tmux is a pinned legacy mode, why AEP owns the
worktree, why session-bound vs OS-bound is a first-class axis, why human gates are
hub-and-spoke, and why autopilot drives only steerable modes are recorded in
docs/decisions/native-first-executor.md,
docs/decisions/host-agnostic-executor.md, and
docs/decisions/remove-claude-team.md.
Next Step
After detecting/spawning, control returns to the calling skill:
/aep-launch → the bootstrap was the spawn prompt (native modes) or sent over
tmux (legacy), then /aep-build runs in the workspace
/aep-autopilot → resumes its tick loop
/aep-dispatch → completes the handoff
1---2name: aep-executor3description: Spawns and steers workspace agents across Claude Code and Codex backends. Use for backend choice, launch mode, or host detection; other skills call it.4---56# Executor Abstraction78A reusable abstraction for **running implementation work in an isolated9workspace**, independent of which agent host (Claude Code, Codex) or which10mechanism is available. Lifecycle skills speak one vocabulary of operations;11this skill maps each operation to a concrete recipe per mode. It is consumed as12a library by `/aep-launch`, `/aep-build`, and `/aep-autopilot`, and can be13invoked standalone to dry-run detection (see [Standalone Usage](#standalone-usage)).1415**Native-first:** Claude Code launches use a native in-process background subagent16(`native-bg-subagent`, the default) or — where the `claude --bg` flag exists —17native background sessions (`claude-bg`); Codex launches use native subagents18(`codex-subagent`) or headless exec workers (`codex-exec`). tmux+cmux is the19**`legacy`** mode — selected only by explicit pin20(`git config aep.executor-backend tmux`) or on generic hosts. Every mode runs its21worker in an AEP-created git worktree at `.feature-workspaces/<ws>`.2223---2425## How Other Skills Use This2627| Skill | What it uses | Operations |28| -------------------- | ----------------------------------------------------- | ---------------------------------------------- |29| `/aep-launch` | Start the implementation agent + expose it for review | `detect`, `spawn`, `present` |30| `/aep-build` Phase 5 | Spawn the evaluator in the right execution context | `detect`, `spawn_evaluator` |31| `/aep-build` | Raise a human decision mid-build | `gate` |32| `/aep-autopilot` | Run the periodic tick check cheaply; steer workspaces | `detect`, `check`, `nudge`, `liveness`, `gate` |33| `/aep-wrap` | Tear down the worker + worktree after merge | `teardown` |34| `/aep-dispatch` | Resolve the handoff mode; route "…with workflow" runs | `detect` |3536---3738## The Operation Contract3940Every consumer speaks these verbs. The recipe files supply the implementation41per mode.4243| Op | Purpose |44| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------- |45| `detect()` | Resolve host + native capabilities + pin, select a mode |46| `spawn(ws, branch, prompt)` | Start an implementation agent bound to the AEP worktree |47| `spawn_evaluator(ws, role)` | Start an evaluator agent (worktree-bound) in the mode's eval context; accepts an optional tier-derived **effort hint** (see backends.md) |48| `nudge(ws, msg)` | Send a mid-flight instruction _(steerable modes; pull-based under claude-bg)_ |49| `liveness(ws)` | Is the agent actively working? _(mode-specific signal + git-diff corroboration)_ |50| `gate(ws)` | Surface a worker's human decision: `needs-human.md` + the mode's transport, answered hub-and-spoke through the main agent (block-in-place or gate-and-park) |51| `check(prompt, schema)` | Run a read-only analysis prompt in a **cheap, context-isolated** agent; return its JSON result — keeps a long-lived orchestrator session's context small |52| `monitor(ws)` | Read `.dev-workflow/signals/status.json` — **host-independent, never changes** |53| `present(ws)` | Human review surface (`TaskOutput` / `claude attach` / Codex thread / cmux tab / signals) |54| `teardown(ws)` | Worker + worktree cleanup |5556> **`monitor()` is already abstract.** Progress is reported through signal files57> at phase boundaries regardless of the executor. Native push channels58> (SendMessage, send_input) are an acceleration layer — the signal files remain59> the durable, host-agnostic source of truth.6061---6263## The Modes (summary)6465| Mode | Lifetime | Selected when |66| ---------------------- | ------------- | ---------------------------------------------------------------------- |67| **native-bg-subagent** | session-bound | **Claude Code default** + long-lived orchestrator |68| **claude-bg** | OS-bound | Claude Code, `claude --bg` present (cron driver / OS-bound need) |69| **codex-subagent** | session-bound | Codex with a living main thread (desktop app or interactive CLI) |70| **codex-exec** | OS-bound | Codex + cron driver, or hard isolation demanded |71| **legacy** | OS-bound | explicit pin (`aep.executor-backend tmux`), or generic host w/ tmux |72| **workflow** | session-bound | explicit opt-in ("…with workflow") + Claude Code (see `/aep-workflow`) |73| **headless** | session-bound | last resort |7475Read `references/backends.md` for each mode's mechanism, the detection recipe,76the full selection order, the driver × backend compatibility matrix, the77human-gate protocol, and orphan re-adoption.7879---8081## Reference Files8283| File | Contents | When to read |84| ---------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |85| [`references/backends.md`](references/backends.md) | Mode matrix, detection, selection order, driver compatibility, gate protocol, orphan re-adoption, `check()` | Always, before spawning or steering |86| [`references/claude-native.md`](references/claude-native.md) | `native-bg-subagent` (default) + `claude-bg` recipes, `--bg` availability note | When the selected mode is a Claude native one |87| [`references/codex-native.md`](references/codex-native.md) | `codex-subagent` + `codex-exec` recipes, `aep-builder`/`aep-evaluator` role TOMLs, desktop app mapping | When the selected mode is a Codex one |88| [`references/tmux-session.md`](references/tmux-session.md) | `legacy` recipes (tmux spawn/nudge/liveness, cmux tab ladder) | When `legacy` is pinned or selected |89| [`references/dogfood-validation.md`](references/dogfood-validation.md) | `dogfood_method()` host × mode detection, `e2e_tool()`, `target_url()` resolution | When running dogfood validation (consumed by `/aep-build`, `/aep-launch`, `/aep-watch`, the autopilot post-merge guard) |9091The skill also ships two probes, so the exact bash lives in one place instead of92being retyped from a reference:9394- `scripts/detect-backend.sh [--lifetime long|ephemeral] [--opt-in workflow|tmux] [--json]`95 — host, executor commands, native capabilities, pin, presentation surface, and96 the selected `MODE`. `eval "$(bash scripts/detect-backend.sh)"` to use it.97- `scripts/spawn-liveness-probe.sh <name> <agent_id>` — the post-spawn liveness98 probe every spawner runs (`references/backends.md` § Post-Spawn Liveness Probe).99100---101102## Standalone Usage103104Invoked directly, this skill reports what would happen:1051061. Run `bash scripts/detect-backend.sh` (add `--lifetime ephemeral` when this107 invocation is a cron/launchd one-shot — the script cannot probe that).1082. Report each field it prints, and say **why** that `MODE` won: which earlier109 rule in the selection order did not match.1103. If the user asked "why not workflow / why not tmux", explain the opt-in/pin111 gates.112113This does not spawn anything — it is a dry-run of `detect()`.114115---116117## Rationale118119Why native modes come first and tmux is a pinned `legacy` mode, why AEP owns the120worktree, why session-bound vs OS-bound is a first-class axis, why human gates are121hub-and-spoke, and why autopilot drives only steerable modes are recorded in122`docs/decisions/native-first-executor.md`,123`docs/decisions/host-agnostic-executor.md`, and124`docs/decisions/remove-claude-team.md`.125126---127128## Next Step129130After detecting/spawning, control returns to the calling skill:131132- `/aep-launch` → the bootstrap was the spawn prompt (native modes) or sent over133 tmux (legacy), then `/aep-build` runs in the workspace134- `/aep-autopilot` → resumes its tick loop135- `/aep-dispatch` → completes the handoff