Parent Epic
Part of #52 — Sequential stacked PR chains
Summary
Implement the autopilot chain CLI command with two input modes:
autopilot chain --epic <N> — fetch sub-issues from GitHub issue #N via GraphQL, run as sequential stacked chain
autopilot chain --issues 51,52,53 — explicit list of issue numbers, run as sequential stacked chain
Each sub-issue becomes a task that runs the full review-fix loop. Tasks execute one at a time in order, with each PR targeting the previous task's branch (stacked PRs). Uses standard git checkout for branch switching (no worktrees).
CLI Design
autopilot chain --epic 52 # all sub-issues of #52
autopilot chain --issues 51,52,53 # explicit issue list
autopilot chain --epic 52 --only 51,53 # subset of epic's sub-issues
autopilot chain --epic 52 --plan # plan mode for all tasks
autopilot chain --epic 52 --model gpt-4.1 # model override for all tasks
autopilot chain --epic 52 --max-iters 3 # iteration limit per task
Changes
github_api.py
- Add
get_sub_issues(issue_number) via GraphQL (issue.subIssues connection)
- Returns list of dicts:
[{number, title, body, state}] in GitHub's order
- Handle GraphQL errors gracefully — if
subIssues field is not available, raise clear error
cli.py
- Add
cmd_chain(args) function
- For each issue in order:
- Create task with prompt from issue body
- Set
parent_task_id to previous task's ID (NULL for first)
- Set
epic_id to a generated chain ID
- Set
base_branch: first task = get_default_branch(), subsequent = previous task's branch
- Sequential runner:
git checkout <branch>, launch task in tmux, wait for COMPLETE, repeat
- Task FAILED mid-chain: stop, report which failed, remaining stay in INIT
cli_parser.py
- Add
chain subcommand with --epic, --issues, --only, --plan, --model, --max-iters, --dry-run
chain.py (new module)
run_chain(tasks, config) — sequential runner: launch each task, poll for completion, start next
- Chain state tracking and failure handling
persistence.py
Depends On
Error Handling
--epic N where #N has no sub-issues: clear message suggesting --issues
- Sub-issues API unavailable: clear fallback message
- Task failure mid-chain: stop, report, remaining in INIT
- Must provide
--epic or --issues (not both, not neither)
--only only valid with --epic
Testing
--epic fetches sub-issues via GraphQL mock, creates correct chain
--issues creates tasks in specified order
--only filters subset of epic sub-issues
- Correct base_branch chain, parent_task_id chain, shared epic_id
- Sequential runner: task 1 COMPLETE triggers task 2 (with branch checkout)
- Task failure: remaining tasks stay in INIT
- No sub-issues: clear error
- Dry run shows plan without executing
Parent Epic
Part of #52 — Sequential stacked PR chains
Summary
Implement the
autopilot chainCLI command with two input modes:autopilot chain --epic <N>— fetch sub-issues from GitHub issue #N via GraphQL, run as sequential stacked chainautopilot chain --issues 51,52,53— explicit list of issue numbers, run as sequential stacked chainEach sub-issue becomes a task that runs the full review-fix loop. Tasks execute one at a time in order, with each PR targeting the previous task's branch (stacked PRs). Uses standard
git checkoutfor branch switching (no worktrees).CLI Design
Changes
github_api.pyget_sub_issues(issue_number)via GraphQL (issue.subIssuesconnection)[{number, title, body, state}]in GitHub's ordersubIssuesfield is not available, raise clear errorcli.pycmd_chain(args)functionparent_task_idto previous task's ID (NULL for first)epic_idto a generated chain IDbase_branch: first task =get_default_branch(), subsequent = previous task's branchgit checkout <branch>, launch task in tmux, wait for COMPLETE, repeatcli_parser.pychainsubcommand with--epic,--issues,--only,--plan,--model,--max-iters,--dry-runchain.py(new module)run_chain(tasks, config)— sequential runner: launch each task, poll for completion, start nextpersistence.pycreate_task()acceptsparent_task_id,epic_id,base_branch(from Schema: parent_task_id, epic_id, base_branch, upstream_sha columns #55)get_chain_tasks(epic_id)— list tasks in chain order (from Schema: parent_task_id, epic_id, base_branch, upstream_sha columns #55)Depends On
Error Handling
--epic Nwhere #N has no sub-issues: clear message suggesting--issues--epicor--issues(not both, not neither)--onlyonly valid with--epicTesting
--epicfetches sub-issues via GraphQL mock, creates correct chain--issuescreates tasks in specified order--onlyfilters subset of epic sub-issues