Files
Agent-System-Dev/docs/superpowers/plans/2026-10-15-project-agent-execution.md
T
weichen 05e45a9044 Plan project execution agent routing
Why: Turn the approved multi-CLI routing design into independently testable Cursor implementation units without another manual plan gate.

Evidence: The plan self-review found R1-R10 coverage, stable interfaces, five review-focus tests, and no placeholders or whitespace errors.

Impact: Authorizes U1-U5 execution through fresh Cursor Agent runs while the host retains scope, verification, integration, and delivery control.

Refs: docs/superpowers/specs/2026-10-15-project-agent-execution-design.md
2026-10-15 01:51:04 +00:00

23 KiB
Raw Blame History

Project Agent Execution Routing Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Build a project-local, Markdown-configured execution router that delegates repository-writing work to ordered Agent CLI profiles and authorizes host-model fallback only after every candidate is safely unavailable.

Architecture: A small agent-exec CLI is the external seam. It parses one agent-execution block from AGENT-EXECUTION.md, validates profiles against built-in or controlled custom adapters, runs each implementation attempt in a fresh detached worktree, and emits a bounded JSON receipt plus a host-owned transport commit. The host remains responsible for scope review, authoritative verification, integration, commits, PRs, CI, merge, and cleanup.

Tech Stack: Python 3 standard library, Git worktrees and plumbing commands, unittest, existing make test-governance discovery, Markdown with a constrained YAML subset.

Spec: docs/superpowers/specs/2026-10-15-project-agent-execution-design.md

Global Constraints

  • Preserve goal-first delivery, strict no-scope-expansion, usable-first sequencing, evidence provenance, platform admission, and high-consequence dual keys.
  • Use no new third-party runtime dependency. The parser accepts only the documented YAML subset.
  • Every implementation task below uses one fresh Cursor CLI run. Cursor workers do not commit, push, open PRs, merge, deploy, or clean canonical worktrees.
  • The host creates canonical commits only after inspecting actual changes and running the task's authoritative tests.
  • run-everything removes per-command prompts inside the isolated unit; it never expands user authorization or grants canonical Git authority.
  • model: auto omits the model flag instead of passing the string auto.
  • Shell command templates, secret values, unknown placeholders, and implicit environment inheritance are rejected.
  • failed-unknown, scope-expansion, invalid-config, and safety failures never authorize host fallback.
  • A normal worker return is bounded by summary_bytes; raw logs remain outside the repository.

Review Focus

  • A CLI exits nonzero after touching files: preserve evidence, prove exact cleanup, then classify failed-clean; otherwise return failed-unknown.
  • A custom adapter places a placeholder inside a larger argv string: reject it instead of interpolating or invoking a shell.
  • A role lists several missing or incompatible profiles: exhaust them in order and issue exactly one host-fallback-authorized receipt.
  • A worker creates untracked or binary files: include them in the host-owned transport and changed-path inventory without modifying the canonical checkout.
  • A worker changes HEAD, .git, a disallowed path, or an external object: fail-stop and retain the attempt for reconciliation.

File Map

Path Responsibility
AGENT-EXECUTION.md Human-readable project configuration and the single machine-readable agent-execution block
scripts/agent_exec_config.py Markdown extraction, constrained YAML parsing, schema validation, and immutable configuration types
scripts/agent_exec_adapters.py Built-in adapter registry, custom adapter validation, capability probes, and argv construction
scripts/agent_exec.py validate/run CLI, selection state machine, detached worktrees, process supervision, transport commits, receipts, cleanup, and host fallback authorization
tests/test_agent_exec_config.py Configuration parser and schema contract
tests/test_agent_exec_adapters.py Adapter argv, model, permission, output, and custom-adapter contract
tests/test_agent_exec.py Real temporary-Git execution, fallback, scope, transport, recovery, timeout, redaction, and process lifecycle
AGENTS.md Short context pointer to AGENT-EXECUTION.md; no duplicated CLI mappings
policy/delivery.md Project-level agent-per-unit execution and fallback authority
policy/governance.md Receipts, isolation, evidence ownership, and recovery rules
policy/adoption.md Adoption status and current capability limit
policy/tool-adaptation-matrix.md Manual/enforced capability classification and verification entrypoints
scripts/task.sh New task-card execution routing and receipt fields
tests/test_task.py Generated task-card contract
Makefile agent-exec-validate target and help text
.task/feature-goal-first-delivery.md Scope, Cursor attempt receipts, stage state, and exact evidence references

Task 1: U1 Configuration Contract

Files:

  • Create: AGENT-EXECUTION.md
  • Create: scripts/agent_exec_config.py
  • Create: tests/test_agent_exec_config.py
  • Modify: Makefile

Interfaces:

  • Produces: ExecutionConfig, ExecutionPolicy, Profile, CustomAdapter, ConfigError, load_config(repo: Path) -> ExecutionConfig, validate_config(repo: Path) -> list[str]

  • Consumes: Python 3 standard library only

  • Step 1: Write the failing parser and schema tests

Create tests/test_agent_exec_config.py with temporary repository fixtures and these cases:

def test_loads_single_agent_execution_block(): ...
def test_rejects_missing_or_duplicate_blocks(): ...
def test_rejects_unknown_schema_and_unknown_keys(): ...
def test_role_order_does_not_follow_profile_order(): ...
def test_model_auto_is_preserved_as_none(): ...
def test_rejects_unknown_profile_reference(): ...
def test_rejects_shell_command_and_secret_shaped_values(): ...
def test_custom_placeholders_must_fill_whole_argv_items(): ...
def test_numeric_limits_are_positive_and_bounded(): ...
  • Step 2: Run the parser tests red

Run: python3 -m unittest tests.test_agent_exec_config -v

Expected: FAIL because scripts.agent_exec_config does not exist.

  • Step 3: Implement immutable configuration types

In scripts/agent_exec_config.py, define:

@dataclass(frozen=True)
class ExecutionPolicy:
    fresh_process_per_unit: bool
    permission: str
    fallback_to_host: str
    max_parallel: int
    timeout_seconds: int
    summary_bytes: int
    raw_output_bytes: int

@dataclass(frozen=True)
class Profile:
    name: str
    adapter: str
    executable: str
    model: str | None
    enabled: bool

@dataclass(frozen=True)
class CustomAdapter:
    name: str
    base_argv: tuple[str, ...]
    run_everything_argv: tuple[str, ...]
    workspace_argv: tuple[str, ...]
    model_argv: tuple[str, ...]
    prompt_transport: str
    output_format: str

@dataclass(frozen=True)
class ExecutionConfig:
    schema: str
    execution: ExecutionPolicy
    roles: Mapping[str, tuple[str, ...]]
    profiles: Mapping[str, Profile]
    custom_adapters: Mapping[str, CustomAdapter]

model: auto becomes None. Reject unknown keys, duplicate mapping keys, tabs, anchors, aliases, tags, multiline scalars, implicit dates, shell metacharacter templates, credential-looking keys/values, and placeholders other than the four spec placeholders.

  • Step 4: Implement the constrained YAML parser

Support two-space-indented mappings, inline scalar lists, booleans, integers, null, and quoted/unquoted safe strings. The parser does not implement general YAML. Extract exactly one fenced block whose opening marker is ```agent-execution and whose closing marker is ```.

  • Step 5: Add the initial project configuration

Create AGENT-EXECUTION.md using the spec's example with role order:

implementation: cursor -> antigravity -> claude -> codex -> pi -> kimi -> opencode
repair: cursor -> antigravity -> codex -> claude
test: pi -> antigravity -> codex
review: claude -> codex -> pi

Set permission: run-everything, fallback_to_host: all-unavailable, model: auto for every profile, and no custom adapters.

  • Step 6: Add validation entrypoint

Add make agent-exec-validate, running:

python3 scripts/agent_exec.py validate --repo .

In U1 the target runs python3 -m unittest tests.test_agent_exec_config -v. Task 3 replaces that recipe with the final agent_exec.py validate command.

  • Step 7: Run U1 green

Run: python3 -m unittest tests.test_agent_exec_config -v

Expected: PASS with all parser and schema cases.

  • Step 8: Host integration commit

The Cursor worker leaves its tree uncommitted. The host inspects changed paths, runs the same test, and commits only the four U1 paths with subject Add project execution agent configuration and the repository-required four body sections.

Task 2: U2 Adapter Seam

Files:

  • Create: scripts/agent_exec_adapters.py
  • Create: tests/test_agent_exec_adapters.py
  • Modify: scripts/agent_exec_config.py

Interfaces:

  • Consumes: Profile, CustomAdapter, ExecutionPolicy

  • Produces: AdapterSpec, AdapterProbe, Invocation, probe_adapter(profile, config) -> AdapterProbe, build_invocation(profile, config, workspace, unit_packet, result_path) -> Invocation

  • Step 1: Write adapter contract tests red

Cover Cursor, agy, Claude, Codex, PI, Kimi, OpenCode, and custom profiles:

def test_cursor_run_everything_and_auto_model_argv(): ...
def test_antigravity_run_everything_argv(): ...
def test_claude_run_everything_argv(): ...
def test_codex_uses_noninteractive_workspace_sandbox(): ...
def test_pi_and_kimi_auto_model_omit_model_flag(): ...
def test_missing_opencode_is_unavailable(): ...
def test_fixed_model_uses_only_adapter_model_flag(): ...
def test_custom_adapter_builds_direct_argv_without_shell(): ...
def test_unverified_run_everything_capability_is_unavailable(): ...
  • Step 2: Run adapter tests red

Run: python3 -m unittest tests.test_agent_exec_adapters -v

Expected: FAIL because the adapter registry does not exist.

  • Step 3: Implement adapter types and registry

Define:

@dataclass(frozen=True)
class AdapterSpec:
    name: str
    noninteractive_argv: tuple[str, ...]
    run_everything_argv: tuple[str, ...]
    workspace_flag: str | None
    model_flag: str | None
    output_argv: tuple[str, ...]
    prompt_transport: str

@dataclass(frozen=True)
class AdapterProbe:
    available: bool
    reason: str | None
    executable: str
    observed_version: str | None

@dataclass(frozen=True)
class Invocation:
    argv: tuple[str, ...]
    cwd: Path
    stdin: bytes | None
    sanitized_display: tuple[str, ...]

Use direct argv with no shell. Probe via executable lookup plus bounded --version/--help inspection. Do not contact a provider during validate.

  • Step 4: Implement built-in mappings

Map the currently observed CLI interfaces from the spec. Cursor uses sandboxed --force; Codex uses exec, workspace-write sandbox, and never-ask approval rather than disabling outer isolation; OpenCode returns unavailable until its installed help proves the required interface. A missing or incompatible required flag returns unavailable rather than silently choosing a weaker posture.

  • Step 5: Implement custom adapter expansion

Substitute only whole-argument placeholders. Build stdin or positional prompts according to prompt_transport. Inherit only an allowlist of environment variables required for locale, PATH, HOME, temporary storage, and provider credential discovery by the CLI; never serialize values into receipts.

  • Step 6: Run U2 green

Run: python3 -m unittest tests.test_agent_exec_config tests.test_agent_exec_adapters -v

Expected: PASS.

  • Step 7: Host integration commit

Commit only U2 files with subject Add execution CLI adapter registry after host review and tests.

Task 3: U3 Execution Controller

Files:

  • Create: scripts/agent_exec.py
  • Create: tests/test_agent_exec.py
  • Modify: Makefile

Interfaces:

  • Consumes: ExecutionConfig, adapter Invocation, a unit packet JSON document

  • Produces: CLI commands validate and run; receipt schema agent-exec-receipt/v1; transport ref refs/agent-exec/<run-id>/<attempt-id>

  • Step 1: Write end-to-end controller tests red

Build temporary real Git repositories and fake executables. Cover:

def test_validate_does_not_contact_provider(): ...
def test_run_uses_fresh_process_and_worktree_per_attempt(): ...
def test_missing_profiles_fall_through_in_declared_order(): ...
def test_all_unavailable_authorizes_host_fallback_once(): ...
def test_failed_clean_can_continue_after_exact_restore(): ...
def test_failed_unknown_blocks_fallback(): ...
def test_scope_expansion_preserves_workspace_and_blocks(): ...
def test_worker_commit_or_head_move_is_rejected(): ...
def test_untracked_and_binary_files_enter_transport_inventory(): ...
def test_timeout_kills_process_group_and_records_receipt(): ...
def test_summary_and_raw_log_caps_are_enforced(): ...
def test_receipt_redacts_environment_secrets(): ...
def test_success_creates_base_parented_transport_without_touching_canonical_head(): ...
  • Step 2: Run controller tests red

Run: python3 -m unittest tests.test_agent_exec -v

Expected: FAIL because scripts/agent_exec.py does not exist.

  • Step 3: Implement unit packet validation

The JSON packet requires unit_id, goal, allowed_paths, verification, constraints, network, external_cost, and timeout_seconds. Reject absolute allowed paths, .., .git, secret files, an empty goal, or a timeout above project policy.

  • Step 4: Implement private run state

Create /tmp/agent-exec-<uid>/<run-id>/ with mode 0700. Record config digest, base HEAD/tree, unit digest, attempts, worktree paths, process metadata, receipts, raw logs, transport refs, and cleanup state. Refuse symlinked or foreign-owned roots.

  • Step 5: Implement candidate selection and fresh worktrees

For each role profile, create a new detached worktree from the fixed base, build the adapter invocation, launch a new process group, and never reuse a session. Missing/incompatible candidates become unavailable receipts without creating a provider request.

  • Step 6: Implement supervision and bounded output

Capture stdout/stderr to private files, enforce idle/total timeout, terminate the process group, preserve exact exit state, and write bounded sanitized summaries. A process exit alone never proves no external side effect.

  • Step 7: Implement scope and transport checks

Verify HEAD/base did not move, inventory tracked and untracked changes, reject paths outside allowed_paths, then create a host-owned synthetic transport commit with the recorded base as sole parent. Worker output never writes the canonical index or branch.

  • Step 8: Implement state classification and fallback

Classify success, unavailable, failed-clean, failed-unknown, scope-expansion, invalid-config, and cancelled. Emit host-fallback-authorized only after every configured candidate is unavailable for the unit and every attempt has exact cleanup evidence.

  • Step 9: Finalize CLI and Make target

Implement:

python3 scripts/agent_exec.py validate --repo <path>
python3 scripts/agent_exec.py run --repo <path> --role <role> --unit <packet> --receipt <path>

Return stable exit codes for success, host fallback, invalid configuration, blocked/unknown state, and ordinary unavailable exhaustion. Update make agent-exec-validate to call the final CLI.

  • Step 10: Run U3 green

Run: python3 -m unittest tests.test_agent_exec_config tests.test_agent_exec_adapters tests.test_agent_exec -v

Expected: PASS.

  • Step 11: Run governance regression

Run: make test-governance

Expected: PASS with no tracked worktree changes.

  • Step 12: Host integration commit

Commit U3 files with subject Add recoverable execution agent controller after inspecting transport and authoritative test output.

Task 4: U4 Project Governance Integration

Files:

  • Modify: AGENTS.md
  • Modify: policy/delivery.md
  • Modify: policy/governance.md
  • Modify: policy/adoption.md
  • Modify: policy/tool-adaptation-matrix.md
  • Modify: scripts/task.sh
  • Modify: tests/test_task.py
  • Modify: .task/feature-goal-first-delivery.md

Interfaces:

  • Consumes: agent-exec validate/run, receipt schema, AGENT-EXECUTION.md

  • Produces: agent-per-unit repository rule, task-card profile/attempt/fallback fields, and adoption/verification entrypoints

  • Step 1: Change task-card tests red

Update test_start_imports_precheck_and_creates_four_part_commit to require:

实施执行:agent-per-unit(配置:AGENT-EXECUTION.md)
配置摘要、角色、候选顺序、attempt、CLI/模型、终态、transport、fallback 与收据路径

Require the generated card to reject the obsolete fixed-Cursor wording.

  • Step 2: Run the focused task test red

Run: python3 -m unittest tests.test_task.TaskLifecycleTests.test_start_imports_precheck_and_creates_four_part_commit -v

Expected: FAIL because the template still says cursor-per-unit.

  • Step 3: Replace fixed-Cursor policy with the configuration pointer

Keep AGENTS.md short: require reading AGENT-EXECUTION.md when routing implementation, repair, test, or review work. Move adapter and fallback detail to the config/design and policy. Replace, rather than layer on, the current cursor-per-unit authority.

  • Step 4: Update delivery and governance policy

State that external agents implement per bounded unit, host owns planning and delivery, and current-host implementation is permitted only with a valid host-fallback-authorized receipt. Preserve goal-first, evidence, Review, CI, merge, cleanup, and dual-key rules.

  • Step 5: Update task generator and capability records

Generate the agent-per-unit fields and keep all initial attempt states NOT_RUN. Mark config parsing/controller tests as local enforced behavior, real provider/model identity as SELF unless independently attested, and remote platform admission as GATE.

  • Step 6: Run U4 green

Run:

python3 -m unittest tests.test_task.TaskLifecycleTests.test_start_imports_precheck_and_creates_four_part_commit -v
python3 scripts/agent_exec.py validate --repo .
make test-governance

Expected: PASS.

  • Step 7: Host integration commit

Commit only U4 paths with subject Route project work through configured agents.

Task 5: U5 Real CLI Probes and Combination Acceptance

Files:

  • Create: tests/fixtures/agent-exec/README.md
  • Modify: tests/test_agent_exec.py
  • Modify: .task/feature-goal-first-delivery.md

Interfaces:

  • Consumes: installed CLI profiles and agent-exec run

  • Produces: source-external probe receipts, final requirements mapping, and an adoption recommendation

  • Step 1: Add opt-in real-probe harness tests

Add a harness gated by RUN_REAL_AGENT_EXEC=1. It creates a temporary Git repository and a one-file unit packet. Each installed CLI is asked to create an exact marker file in its isolated workspace. The host verifies content, transport parent, changed paths, cleanup, model receipt status, and canonical-tree preservation. Missing OpenCode is expected unavailable.

  • Step 2: Run fake and full local regression

Run:

python3 -m unittest tests.test_agent_exec_config tests.test_agent_exec_adapters tests.test_agent_exec -v
make test-governance
make test
make build

Expected: PASS; any pre-existing build warning remains non-blocking unless it affects the requested capability.

  • Step 3: Run installed CLI probes one profile at a time

Use source-external receipts and a fixed temporary repository. Run Cursor first as the implementation acceptance path, then agy, Claude, PI, Codex, and Kimi. Do not run profiles concurrently against the same target. A provider quota or auth failure is recorded as unavailable for that probe and does not become a false PASS.

  • Step 4: Exercise host fallback

Use a configuration whose candidates are deterministic missing executables. Verify host-fallback-authorized, then let the current host create the marker strictly inside the receipt's allowed scope. Run the authoritative verification and record the fallback attempt separately from external-agent success.

  • Step 5: Verify R1-R10 and migration

Map every spec requirement to config/parser/adapter/controller/governance tests and exact receipts. Confirm no active fixed-Cursor authority remains, no task outside this scope was modified, and no CLI received commit/push/PR/merge/deploy authority.

  • Step 6: Commit acceptance records

Commit only tracked fixtures and task-card management metadata with subject Record execution agent acceptance evidence. Raw CLI logs and source-external receipts remain outside Git.

  • Step 7: Enter normal delivery gates

Run make task-sync before formal acceptance, Review request, and merge. Obtain an independent code-review receipt, push one PR, wait for exact-HEAD test, test-pg, and svc-realcombo, merge through Gitea with force_merge=false, verify the actual main tree, and safely close the task.

Requirements Trace

Requirement Owning task and proof
R1 project-level single configuration Task 1 parser/schema tests; Task 4 AGENTS.md pointer and task-card contract
R2 declarative role routing Task 1 role-order tests; Task 3 ordered selection tests
R3 optional model Task 1 auto -> None; Task 2 auto/fixed-model argv tests
R4 run-everything priority Task 2 permission mapping tests; Task 5 installed-CLI probes
R5 multi-CLI adapters Task 2 fake contracts for seven adapters; Task 5 real installed-CLI outcomes
R6 safe host fallback Task 3 exhaustion, restoration, unknown-state and fallback tests; Task 5 real fallback drill
R7 low host-model consumption Task 3 output-cap tests; Task 5 receipt and raw-log boundary review
R8 strict scope Task 3 allowed-path, HEAD movement, transport, and retained-workspace tests
R9 controlled custom adapter Task 1 placeholder/shell rejection; Task 2 direct-argv custom adapter tests
R10 recoverable evidence Task 3 attempt/transport/cleanup receipts; Task 4 task-card fields; Task 5 evidence mapping

Definition of Done

  • R1-R10 have code, tests, and exact evidence mappings.
  • AGENT-EXECUTION.md validates and is the only project execution-routing authority.
  • Cursor implements every repository-writing task in this plan unless a recorded all-unavailable receipt authorizes host fallback.
  • Every successful worker result is scope-inspected, authoritatively tested, and committed by the host.
  • Fake adapters cover all built-in routes; installed real CLIs have source-external probe outcomes.
  • Full local test/build pass on the fixed candidate, independent Review has no blocking findings, and exact-HEAD CI passes before merge.
  • No deployment, platform-protection change, secret persistence, or unrelated cleanup occurs.