From 8799a9c2fdad4ad003ef7946d2bcb0f7b2fd1d48 Mon Sep 17 00:00:00 2001 From: catlog22 Date: Sun, 1 Mar 2026 15:06:06 +0800 Subject: [PATCH] refactor(team-planex): redesign skill with inverted control and beat model - Delete executor agent (main flow IS the executor now) - Rewrite SKILL.md: delegated planning + inline execution - Input accepts issues.jsonl / roadmap session from roadmap-with-file - Single reusable planner agent via send_input (Pattern 2.3) - Interleaved plan-execute loop with eager delegation - Follow codex v3 conventions (decision tables, placeholders) - Remove complexity assessment and dynamic splitting --- .codex/skills/team-planex/SKILL.md | 608 +++++++++++++------ .codex/skills/team-planex/agents/executor.md | 210 ------- 2 files changed, 425 insertions(+), 393 deletions(-) delete mode 100644 .codex/skills/team-planex/agents/executor.md diff --git a/.codex/skills/team-planex/SKILL.md b/.codex/skills/team-planex/SKILL.md index b65970bf..193f8e60 100644 --- a/.codex/skills/team-planex/SKILL.md +++ b/.codex/skills/team-planex/SKILL.md @@ -1,261 +1,503 @@ --- name: team-planex description: | - Inline planning + delegated execution pipeline. Main flow does planning directly, - spawns Codex executor per issue immediately. All execution via Codex CLI only. + Plan-and-execute pipeline with inverted control. Accepts issues.jsonl or roadmap + session from roadmap-with-file. Delegates planning to issue-plan-agent (background), + executes inline (main flow). Interleaved plan-execute loop. --- -# Team PlanEx (Codex) +# Team PlanEx -主流程内联规划 + 委托执行。SKILL.md 自身完成规划(不再 spawn planner agent),每完成一个 issue 的 solution 后立即 spawn executor agent 并行实现,无需等待所有规划完成。 +接收 `issues.jsonl` 或 roadmap session 作为输入,委托规划 + 内联执行。Spawn issue-plan-agent 后台规划下一个 issue,主流程内联执行当前已规划的 issue。交替循环:规划 → 执行 → 规划下一个 → 执行 → 直到所有 issue 完成。 ## Architecture ``` -┌────────────────────────────────────────┐ -│ SKILL.md (主流程 = 规划 + 节拍控制) │ -│ │ -│ Phase 1: 解析输入 + 初始化 session │ -│ Phase 2: 逐 issue 规划循环 (内联) │ -│ ├── issue-plan → 写 solution artifact │ -│ ├── spawn executor agent ────────────┼──> [executor] 实现 -│ └── continue (不等 executor) │ -│ Phase 3: 等待所有 executors │ -│ Phase 4: 汇总报告 │ -└────────────────────────────────────────┘ +┌────────────────────────────────────────────────────┐ +│ SKILL.md (主流程 = 内联执行 + 循环控制) │ +│ │ +│ Phase 1: 加载 issues.jsonl / roadmap session │ +│ Phase 2: 规划-执行交替循环 │ +│ ├── 取下一个未规划 issue → spawn planner (bg) │ +│ ├── 取下一个已规划 issue → 内联执行 │ +│ │ ├── 内联实现 (Read/Edit/Write/Bash) │ +│ │ ├── 验证测试 + 自修复 (max 3 retries) │ +│ │ └── git commit │ +│ └── 循环直到所有 issue 规划+执行完毕 │ +│ Phase 3: 汇总报告 │ +└────────────────────────────────────────────────────┘ + +Planner (single reusable agent, background): + issue-plan-agent spawn once → send_input per issue → write solution JSON → write .ready marker ``` +## Beat Model (Interleaved Plan-Execute Loop) + +``` +Interleaved Loop (Phase 2, single planner reused via send_input): +═══════════════════════════════════════════════════════════════ +Beat 1 Beat 2 Beat 3 +| | | +spawn+plan(A) send_input(C) (drain) + ↓ ↓ ↓ +poll → A.ready poll → B.ready poll → C.ready + ↓ ↓ ↓ +exec(A) exec(B) exec(C) + ↓ ↓ ↓ +send_input(B) send_input(done) done + (eager delegate) (all delegated) +═══════════════════════════════════════════════════════════════ + +Planner timeline (never idle between issues): +───────────────────────────────────────────────────────────── +Planner: ├─plan(A)─┤├─plan(B)─┤├─plan(C)─┤ done +Main: 2a(spawn) ├─exec(A)──┤├─exec(B)──┤├─exec(C)──┤ + ^2f→send(B) ^2f→send(C) +───────────────────────────────────────────────────────────── + +Single Beat Detail: +─────────────────────────────────────────────────────────────── + 1. Delegate next 2. Poll ready 3. Execute 4. Verify + commit + (2a or 2f eager) solutions inline + eager delegate + | | | | + send_input(bg) Glob(*.ready) Read/Edit/Write test → commit + │ → send_input(next) + wait if none ready +─────────────────────────────────────────────────────────────── +``` + +--- + ## Agent Registry -| Agent | Role File | Responsibility | -|-------|-----------|----------------| -| `executor` | `~/.codex/agents/planex-executor.md` | Codex CLI implementation per issue | +| Agent | Role File | Responsibility | Pattern | +|-------|-----------|----------------|---------| +| `issue-plan-agent` | `~/.codex/agents/issue-plan-agent.md` | Explore codebase + generate solutions, single instance reused via send_input | 2.3 Deep Interaction | -> Executor agent must be deployed to `~/.codex/agents/` before use. -> Source: `.codex/skills/team-planex/agents/` +> **COMPACT PROTECTION**: Agent files are execution documents. When context compression occurs and agent instructions are reduced to summaries, **you MUST immediately `Read` the corresponding agent.md to reload before continuing execution**. --- -## Input Parsing +## Subagent API Reference -Supported input types (parse from `$ARGUMENTS`): - -| Type | Detection | Handler | -|------|-----------|---------| -| Issue IDs | `ISS-\d{8}-\d{6}` regex | Use directly for planning | -| Text | `--text '...'` flag | Create issue(s) first via CLI | -| Plan file | `--plan ` flag | Read file, parse phases, batch create issues | - -### Issue Creation (when needed) - -For `--text` input: -```bash -ccw issue create --data '{"title":"","description":"<description>"}' --json -``` - -For `--plan` input: -- Match `## Phase N: Title`, `## Step N: Title`, or `### N. Title` -- Each match → one issue (title + description from section content) -- Fallback: no structure found → entire file as single issue - ---- - -## Session Setup - -Before processing issues, initialize session directory: +### spawn_agent ```javascript -const slug = toSlug(inputDescription).slice(0, 20) -const date = new Date().toISOString().slice(0, 10).replace(/-/g, '') -const sessionDir = `.workflow/.team/PEX-${slug}-${date}` -const artifactsDir = `${sessionDir}/artifacts/solutions` - -Bash(`mkdir -p "${artifactsDir}"`) - -Write({ - file_path: `${sessionDir}/team-session.json`, - content: JSON.stringify({ - session_id: `PEX-${slug}-${date}`, - input_type: inputType, - input: rawInput, - status: "running", - started_at: new Date().toISOString(), - executors: [] - }, null, 2) -}) -``` - ---- - -## Phase 1: Parse Input + Initialize - -1. Parse `$ARGUMENTS` to determine input type -2. Create issues if needed (--text / --plan) -3. Collect all issue IDs -4. Initialize session directory - ---- - -## Phase 2: Inline Planning Loop - -For each issue, execute planning inline (no planner agent): - -### 2a. Generate Solution via issue-plan-agent - -```javascript -const planAgent = spawn_agent({ +const agentId = spawn_agent({ message: ` ## TASK ASSIGNMENT ### MANDATORY FIRST STEPS (Agent Execute) 1. **Read role definition**: ~/.codex/agents/issue-plan-agent.md (MUST read first) +2. Read: .workflow/project-tech.json +3. Read: .workflow/project-guidelines.json --- -issue_ids: ["${issueId}"] -project_root: "${projectRoot}" - -## Requirements -- Generate solution for this issue -- Auto-bind single solution -- Output solution JSON when complete +${taskContext} ` }) - -const result = wait({ ids: [planAgent], timeout_ms: 600000 }) -close_agent({ id: planAgent }) ``` -### 2b. Write Solution Artifact +### wait ```javascript -const solution = parseSolution(result) - -Write({ - file_path: `${artifactsDir}/${issueId}.json`, - content: JSON.stringify({ - session_id: sessionId, - issue_id: issueId, - solution: solution, - planned_at: new Date().toISOString() - }, null, 2) +const result = wait({ + ids: [agentId], + timeout_ms: 600000 // 10 minutes }) ``` -### 2c. Spawn Executor Immediately +### send_input + +Continue interaction with active agent (reuse for next issue). ```javascript -const executorId = spawn_agent({ +send_input({ + id: agentId, + message: ` +## NEXT ISSUE + +issue_ids: ["<nextIssueId>"] + +## Output Requirements +1. Generate solution for this issue +2. Write solution JSON to: <artifactsDir>/<nextIssueId>.json +3. Write ready marker to: <artifactsDir>/<nextIssueId>.ready +` +}) +``` + +### close_agent + +```javascript +close_agent({ id: agentId }) +``` + +--- + +## Input + +Accepts output from `roadmap-with-file` or direct `issues.jsonl` path. + +Supported input forms (parse from `$ARGUMENTS`): + +| Form | Detection | Example | +|------|-----------|---------| +| Roadmap session | `RMAP-` prefix or `--session` flag | `team-planex --session RMAP-auth-20260301` | +| Issues JSONL path | `.jsonl` extension | `team-planex .workflow/issues/issues.jsonl` | +| Issue IDs | `ISS-\d{8}-\d{3,6}` regex | `team-planex ISS-20260301-001 ISS-20260301-002` | + +### Input Resolution + +| Input Form | Resolution | +|------------|------------| +| `--session RMAP-*` | Read `.workflow/.roadmap/<sessionId>/roadmap.md` → extract issue IDs from Roadmap table → load issue data from `.workflow/issues/issues.jsonl` | +| `.jsonl` path | Read file → parse each line as JSON → collect all issues | +| Issue IDs | Use directly → fetch details via `ccw issue status <id> --json` | + +### Issue Record Fields Used + +| Field | Usage | +|-------|-------| +| `id` | Issue identifier for planning and execution | +| `title` | Commit message and reporting | +| `status` | Skip if already `completed` | +| `tags` | Wave ordering: `wave-1` before `wave-2` | +| `extended_context.notes.depends_on_issues` | Execution ordering | + +### Wave Ordering + +Issues are sorted by wave tag for execution order: + +| Priority | Rule | +|----------|------| +| 1 | Lower wave number first (`wave-1` before `wave-2`) | +| 2 | Within same wave: issues without `depends_on_issues` first | +| 3 | Within same wave + no deps: original order from JSONL | + +--- + +## Session Setup + +Initialize session directory before processing: + +| Item | Value | +|------|-------| +| Slug | `toSlug(<first issue title>)` truncated to 20 chars | +| Date | `YYYYMMDD` format | +| Session dir | `.workflow/.team/PEX-<slug>-<date>` | +| Solutions dir | `<sessionDir>/artifacts/solutions` | + +Create directories: + +```bash +mkdir -p "<sessionDir>/artifacts/solutions" +``` + +Write `<sessionDir>/team-session.json`: + +| Field | Value | +|-------|-------| +| `session_id` | `PEX-<slug>-<date>` | +| `input_type` | `roadmap` / `jsonl` / `issue_ids` | +| `source_session` | Roadmap session ID (if applicable) | +| `issue_ids` | Array of all issue IDs to process (wave-sorted) | +| `status` | `"running"` | +| `started_at` | ISO timestamp | + +--- + +## Phase 1: Load Issues + Initialize + +1. Parse `$ARGUMENTS` to determine input form +2. Resolve issues (see Input Resolution table) +3. Filter out issues with `status: completed` +4. Sort by wave ordering +5. Collect into `<issueQueue>` (ordered list of issue IDs to process) +6. Initialize session directory and `team-session.json` +7. Set `<plannedSet>` = {} , `<executedSet>` = {} , `<plannerAgent>` = null (single reusable planner) + +--- + +## Phase 2: Plan-Execute Loop + +Interleaved loop that keeps planner agent busy at all times. Each beat: (1) delegate next issue to planner if idle, (2) poll for ready solutions, (3) execute inline, (4) after execution completes, immediately delegate next issue to planner before polling again. + +### Loop Entry + +Set `<queueIndex>` = 0 (pointer into `<issueQueue>`). + +### 2a. Delegate Next Issue to Planner + +Single planner agent is spawned once and reused via `send_input` for subsequent issues. + +| Condition | Action | +|-----------|--------| +| `<plannerAgent>` is null AND `<queueIndex>` < `<issueQueue>.length` | Spawn planner (first issue), advance `<queueIndex>` | +| `<plannerAgent>` exists, idle AND `<queueIndex>` < `<issueQueue>.length` | `send_input` next issue, advance `<queueIndex>` | +| `<plannerAgent>` is busy | Skip (wait for current planning to finish) | +| `<queueIndex>` >= `<issueQueue>.length` | No more issues to plan | + +**First issue — spawn planner**: + +```javascript +const plannerAgent = spawn_agent({ message: ` ## TASK ASSIGNMENT ### MANDATORY FIRST STEPS (Agent Execute) -1. **Read role definition**: ~/.codex/agents/planex-executor.md (MUST read first) +1. **Read role definition**: ~/.codex/agents/issue-plan-agent.md (MUST read first) +2. Read: .workflow/project-tech.json +3. Read: .workflow/project-guidelines.json --- -## Issue -Issue ID: ${issueId} -Solution file: ${artifactsDir}/${issueId}.json -Session: ${sessionDir} +issue_ids: ["<issueId>"] +project_root: "<projectRoot>" -## Execution -Load solution from file → implement via Codex CLI → verify tests → commit → report. +## Output Requirements +1. Generate solution for this issue +2. Write solution JSON to: <artifactsDir>/<issueId>.json +3. Write ready marker to: <artifactsDir>/<issueId>.ready + - Marker content: {"issue_id":"<issueId>","task_count":<task_count>,"file_count":<file_count>} + +## Multi-Issue Mode +You will receive additional issues via follow-up messages. After completing each issue, +output results and wait for next instruction. ` }) - -executorIds.push(executorId) -executorIssueMap[executorId] = issueId ``` -### 2d. Continue to Next Issue +**Subsequent issues — send_input**: -Do NOT wait for executor. Proceed to next issue immediately. +```javascript +send_input({ + id: plannerAgent, + message: ` +## NEXT ISSUE + +issue_ids: ["<nextIssueId>"] + +## Output Requirements +1. Generate solution for this issue +2. Write solution JSON to: <artifactsDir>/<nextIssueId>.json +3. Write ready marker to: <artifactsDir>/<nextIssueId>.ready + - Marker content: {"issue_id":"<nextIssueId>","task_count":<task_count>,"file_count":<file_count>} +` +}) +``` + +Record `<planningIssueId>` = current issue ID. + +### 2b. Poll for Ready Solutions + +Poll `<artifactsDir>/*.ready` using Glob. + +| Condition | Action | +|-----------|--------| +| New `.ready` found (not in `<executedSet>`) | Load `<issueId>.json` solution → proceed to 2c | +| `<plannerAgent>` busy, no `.ready` yet | Check planner: `wait({ ids: [<plannerAgent>], timeout_ms: 30000 })` | +| Planner finished current issue | Mark planner idle, re-poll | +| Planner timed out (30s wait) | Re-poll (planner still working) | +| No `.ready`, planner idle, all issues delegated | Exit loop → Phase 3 | +| Idle >5 minutes total | Exit loop → Phase 3 | + +### 2c. Inline Execution + +Main flow implements the solution directly. For each task in `solution.tasks`, ordered by `depends_on` sequence: + +| Step | Action | Tool | +|------|--------|------| +| 1. Read context | Read all files referenced in current task | Read | +| 2. Identify patterns | Note imports, naming conventions, existing structure | — (inline reasoning) | +| 3. Apply changes | Modify existing files or create new files | Edit (prefer) / Write (new files) | +| 4. Build check | Run project build command if available | Bash | + +Build verification: + +```bash +npm run build 2>&1 || echo BUILD_FAILED +``` + +| Build Result | Action | +|--------------|--------| +| Success | Proceed to 2d | +| Failure | Analyze error → fix source → rebuild (max 3 retries) | +| No build command | Skip, proceed to 2d | + +### 2d. Verify Tests + +Detect test command: + +| Priority | Detection | +|----------|-----------| +| 1 | `package.json` → `scripts.test` | +| 2 | `package.json` → `scripts.test:unit` | +| 3 | `pytest.ini` / `setup.cfg` (Python) | +| 4 | `Makefile` test target | + +Run tests. If tests fail → self-repair loop: + +| Attempt | Action | +|---------|--------| +| 1–3 | Analyze test output → diagnose → fix source code → re-run tests | +| After 3 | Mark issue as failed, log to `<sessionDir>/errors.json`, continue | + +### 2e. Git Commit + +Stage and commit changes for this issue: + +```bash +git add -A +git commit -m "feat(<issueId>): <solution-title>" +``` + +| Outcome | Action | +|---------|--------| +| Commit succeeds | Record commit hash | +| Commit fails (nothing to commit) | Warn, continue | +| Pre-commit hook fails | Attempt fix once, then warn and continue | + +### 2f. Update Status + Eagerly Delegate Next + +Update issue status: + +```bash +ccw issue update <issueId> --status completed +``` + +Add `<issueId>` to `<executedSet>`. + +**Eager delegation**: Immediately check planner state and delegate next issue before returning to poll: + +| Planner State | Action | +|---------------|--------| +| Idle AND more issues in queue | `send_input` next issue → advance `<queueIndex>` | +| Busy (still planning) | Skip — planner already working | +| All issues delegated | Skip — nothing to delegate | + +This ensures planner is never idle between beats. Return to 2b for next beat. --- -## Phase 3: Wait All Executors +## Phase 3: Report + +### 3a. Cleanup + +Close the planner agent. Ignore cleanup failures. ```javascript -if (executorIds.length > 0) { - const execResults = wait({ ids: executorIds, timeout_ms: 1800000 }) +if (plannerAgent) { + try { close_agent({ id: plannerAgent }) } catch {} +} +``` - if (execResults.timed_out) { - const pending = executorIds.filter(id => !execResults.status[id]?.completed) - if (pending.length > 0) { - const pendingIssues = pending.map(id => executorIssueMap[id]) - Write({ - file_path: `${sessionDir}/pending-executors.json`, - content: JSON.stringify({ pending_issues: pendingIssues, executor_ids: pending }, null, 2) - }) - } - } +### 3b. Generate Report - // Collect summaries - const summaries = executorIds.map(id => ({ - issue_id: executorIssueMap[id], - status: execResults.status[id]?.completed ? 'completed' : 'timeout', - output: execResults.status[id]?.completed ?? null - })) +Update `<sessionDir>/team-session.json`: - // Cleanup - executorIds.forEach(id => { - try { close_agent({ id }) } catch { /* already closed */ } - }) +| Field | Value | +|-------|-------| +| `status` | `"completed"` | +| `completed_at` | ISO timestamp | +| `results.total` | Total issues in queue | +| `results.completed` | Count in `<executedSet>` | +| `results.failed` | Count of failed issues | + +Output summary: + +``` +## Pipeline Complete + +**Total issues**: <total> +**Completed**: <completed> +**Failed**: <failed> + +<per-issue status list> + +Session: <sessionDir> +``` + +--- + +## File-Based Coordination Protocol + +| File | Writer | Reader | Purpose | +|------|--------|--------|---------| +| `<artifactsDir>/<issueId>.json` | planner | main flow | Solution data | +| `<artifactsDir>/<issueId>.ready` | planner | main flow | Atomicity signal | + +### Ready Marker Format + +```json +{ + "issue_id": "<issueId>", + "task_count": "<task_count>", + "file_count": "<file_count>" } ``` --- -## Phase 4: Report +## Session Directory -```javascript -const completed = summaries.filter(s => s.status === 'completed').length -const failed = summaries.filter(s => s.status === 'timeout').length - -// Update session -Write({ - file_path: `${sessionDir}/team-session.json`, - content: JSON.stringify({ - ...session, - status: "completed", - completed_at: new Date().toISOString(), - results: { total: executorIds.length, completed, failed } - }, null, 2) -}) - -return ` -## Pipeline Complete - -**Total issues**: ${executorIds.length} -**Completed**: ${completed} -**Timed out**: ${failed} - -${summaries.map(s => `- ${s.issue_id}: ${s.status}`).join('\n')} - -Session: ${sessionDir} -` +``` +.workflow/.team/PEX-<slug>-<date>/ +├── team-session.json +├── artifacts/ +│ └── solutions/ +│ ├── <issueId>.json +│ └── <issueId>.ready +└── errors.json ``` --- -## User Commands +## Lifecycle Management -During execution, the user may issue: +### Timeout Protocol -| Command | Action | -|---------|--------| -| `check` / `status` | Show executor progress summary | -| `resume` / `continue` | Urge stalled executor | +| Phase | Default Timeout | On Timeout | +|-------|-----------------|------------| +| Phase 1 (Load) | 60s | Report error, stop | +| Phase 2 (Planner wait) | 600s per issue | Skip issue, write `.error` marker | +| Phase 2 (Execution) | No timeout | Self-repair up to 3 retries | +| Phase 2 (Loop idle) | 5 min total idle | Break loop → Phase 3 | + +### Cleanup Protocol + +At workflow end, close the planner agent: + +```javascript +if (plannerAgent) { + try { close_agent({ id: plannerAgent }) } catch { /* already closed */ } +} +``` --- ## Error Handling -| Scenario | Resolution | -|----------|------------| -| issue-plan-agent timeout (>10 min) | Skip issue, log error, continue to next | -| issue-plan-agent failure | Retry once, then skip with error log | -| Solution file not written | Executor reports error, logs to `${sessionDir}/errors.json` | -| Executor (Codex CLI) failure | Executor handles resume; logs CLI resume command | -| No issues to process | Report error: no issues found | +| Phase | Scenario | Resolution | +|-------|----------|------------| +| 1 | Invalid input (no issues, bad JSONL) | Report error, stop | +| 1 | Roadmap session not found | Report error, stop | +| 1 | Issue fetch fails | Retry once, then skip issue | +| 2 | Planner spawn fails | Retry once, then skip issue | +| 2 | issue-plan-agent timeout (>10 min) | Skip issue, write `.error` marker, continue | +| 2 | Solution file corrupt / unreadable | Skip, log to `errors.json`, continue | +| 2 | Implementation error | Self-repair up to 3 retries per task | +| 2 | Tests failing after 3 retries | Mark issue failed, log, continue | +| 2 | Git commit fails | Warn, mark completed anyway | +| 2 | Polling idle >5 minutes | Break loop → Phase 3 | +| 3 | Agent cleanup fails | Ignore | + +--- + +## User Commands + +| Command | Action | +|---------|--------| +| `check` / `status` | Show progress: planned / executing / completed / failed counts | +| `resume` / `continue` | Re-enter loop from Phase 2 | diff --git a/.codex/skills/team-planex/agents/executor.md b/.codex/skills/team-planex/agents/executor.md deleted file mode 100644 index 62c47873..00000000 --- a/.codex/skills/team-planex/agents/executor.md +++ /dev/null @@ -1,210 +0,0 @@ ---- -name: planex-executor -description: | - PlanEx executor agent. Loads solution from artifact file → implements via Codex CLI - (ccw cli --tool codex --mode write) → verifies tests → commits → reports. - Deploy to: ~/.codex/agents/planex-executor.md -color: green ---- - -# PlanEx Executor - -Single-issue implementation agent. Loads solution from JSON artifact, executes -implementation via Codex CLI, verifies with tests, commits, and outputs a structured -completion report. - -## Identity - -- **Tag**: `[executor]` -- **Backend**: Codex CLI only (`ccw cli --tool codex --mode write`) -- **Granularity**: One issue per agent instance - -## Core Responsibilities - -| Action | Allowed | -|--------|---------| -| Read solution artifact from disk | Yes | -| Implement via Codex CLI | Yes | -| Run tests for verification | Yes | -| git commit completed work | Yes | -| Create or modify issues | No | -| Spawn subagents | No | -| Interact with user (AskUserQuestion) | No | - ---- - -## Execution Flow - -### Step 1: Load Context - -After reading role definition: -- Extract issue ID, solution file path, session dir from task message - -### Step 2: Load Solution - -Read solution artifact: - -```javascript -const solutionData = JSON.parse(Read(solutionFile)) -const solution = solutionData.solution -``` - -If file not found or invalid: -- Log error: `[executor] ERROR: Solution file not found: ${solutionFile}` -- Output: `EXEC_FAILED:${issueId}:solution_file_missing` -- Stop execution - -Verify solution has required fields: -- `solution.bound.title` or `solution.title` -- `solution.bound.tasks` or `solution.tasks` - -### Step 3: Update Issue Status - -```bash -ccw issue update ${issueId} --status executing -``` - -### Step 4: Codex CLI Execution - -Build execution prompt and invoke Codex: - -```bash -ccw cli -p "$(cat <<'PROMPT_EOF' -## Issue -ID: ${issueId} -Title: ${solution.bound.title} - -## Solution Plan -${JSON.stringify(solution.bound, null, 2)} - -## Implementation Requirements -1. Follow the solution plan tasks in order -2. Write clean, minimal code following existing patterns -3. Run tests after each significant change -4. Ensure all existing tests still pass -5. Do NOT over-engineer - implement exactly what the solution specifies - -## Quality Checklist -- [ ] All solution tasks implemented -- [ ] No TypeScript/linting errors (run: npx tsc --noEmit) -- [ ] Existing tests pass -- [ ] New tests added where specified in solution -- [ ] No security vulnerabilities introduced -PROMPT_EOF -)" --tool codex --mode write --id planex-${issueId} -``` - -**STOP after spawn** — Codex CLI executes in background. Do NOT poll or wait inside this agent. The CLI process handles implementation autonomously. - -Wait for CLI completion signal before proceeding to Step 5. - -### Step 5: Verify Tests - -Detect and run project test command: - -```javascript -// Detection priority: -// 1. package.json scripts.test -// 2. package.json scripts.test:unit -// 3. pytest.ini / setup.cfg (Python) -// 4. Makefile test target - -const testCmd = detectTestCommand() - -if (testCmd) { - const testResult = Bash(`${testCmd} 2>&1 || echo TEST_FAILED`) - - if (testResult.includes('TEST_FAILED') || testResult.includes('FAIL')) { - const resumeCmd = `ccw cli -p "Fix failing tests" --resume planex-${issueId} --tool codex --mode write` - - Write({ - file_path: `${sessionDir}/errors.json`, - content: JSON.stringify({ - issue_id: issueId, - type: 'test_failure', - test_output: testResult.slice(0, 2000), - resume_cmd: resumeCmd, - timestamp: new Date().toISOString() - }, null, 2) - }) - - Output: `EXEC_FAILED:${issueId}:tests_failing` - Stop. - } -} -``` - -### Step 6: Commit - -```bash -git add -A -git commit -m "feat(${issueId}): ${solution.bound.title}" -``` - -If commit fails (nothing to commit, pre-commit hook error): -- Log warning: `[executor] WARN: Commit failed for ${issueId}, continuing` -- Still proceed to Step 7 - -### Step 7: Update Issue & Report - -```bash -ccw issue update ${issueId} --status completed -``` - -Output completion report: - -``` -## [executor] Implementation Complete - -**Issue**: ${issueId} -**Title**: ${solution.bound.title} -**Backend**: codex -**Tests**: ${testCmd ? 'passing' : 'skipped (no test command found)'} -**Commit**: ${commitHash} -**Status**: resolved - -EXEC_DONE:${issueId} -``` - ---- - -## Resume Protocol - -If Codex CLI execution fails or times out: - -```bash -ccw cli -p "Continue implementation from where stopped" \ - --resume planex-${issueId} \ - --tool codex --mode write \ - --id planex-${issueId}-retry -``` - -Resume command is always logged to `${sessionDir}/errors.json` on any failure. - ---- - -## Error Handling - -| Scenario | Resolution | -|----------|------------| -| Solution file missing | Output `EXEC_FAILED:<id>:solution_file_missing`, stop | -| Solution JSON malformed | Output `EXEC_FAILED:<id>:solution_invalid`, stop | -| Issue status update fails | Log warning, continue | -| Codex CLI failure | Log resume command to errors.json, output `EXEC_FAILED:<id>:codex_failed` | -| Tests failing | Log test output + resume command, output `EXEC_FAILED:<id>:tests_failing` | -| Commit fails | Log warning, still output `EXEC_DONE:<id>` (implementation complete) | -| No test command found | Skip test step, proceed to commit | - -## Key Reminders - -**ALWAYS**: -- Output `EXEC_DONE:<issueId>` on its own line when implementation succeeds -- Output `EXEC_FAILED:<issueId>:<reason>` on its own line when implementation fails -- Log resume command to errors.json on any failure -- Use `[executor]` prefix in all status messages - -**NEVER**: -- Use any execution backend other than Codex CLI -- Create, modify, or read issues beyond the assigned issueId -- Spawn subagents -- Ask the user for clarification (fail fast with structured error)