| name | apd-finish |
| description | MANDATORY after every successful APD pipeline commit on Codex — when apd:apd_pipeline_state shows next_step='commit' and a commit was made. Verify tests from a clean state, show the pipeline report, present four options (push, push+PR, keep local, discard), execute only after the user picks. Triggers on "after commit", "push", "PR", "pull request", "deploy", "next", "pipeline done", "shipped", commit hash present in pipeline state. |
APD Finish (Codex)
Run through this BEFORE push, PR, or moving to the next task.
When to use / When to skip
Use when:
- A pipeline cycle just produced a successful commit
- All four pipeline phases are complete;
apd:apd_pipeline_state() reports next_step: "commit"
- The user has not yet made a push/PR/keep/discard decision
Skip when:
- The pipeline failed before commit — go to
apd-debug, not finish
- The user has already pushed — there is nothing to decide
- This is a hotfix outside the pipeline — different decision flow, don't apply pipeline summary template
The Iron Law
NO PUSH WITHOUT USER DECISION FIRST
The pipeline produced a commit. The user — not you — decides what happens
next. Never auto-push, never assume.
Process
Step 1 — verify
Re-run the project verifier to confirm nothing slipped through:
apd:apd_verify_step() # runs .codex/bin/verify-all.sh
If it fails, stop — loop back into debug. Do NOT present finish options
on red tests.
Step 2 — show what the pipeline did
Pull apd:apd_pipeline_state() and summarize for the user:
- Task name (from spec)
- Which steps completed, timing if available
- Spec criteria count
- Adversarial outcome (total / accepted / dismissed) if present
- Reviewed files count
Step 2b — did this run teach the project anything?
If the run ACCEPTED any adversarial finding, ask one question before moving on:
does it generalize? A finding is an instance; the class is what is worth
keeping. The fix already landed in code — that part is done.
If the same shape can appear in another module, another handler, another task,
record it once:
apd pipeline lesson "<the rule, as a class>" "<what it cost>"
apd pipeline show lessons
Builders are told to read .apd/lessons.md before they start, so a recorded
class becomes education that arrives automatically on every future dispatch.
Write the RULE, not the patch — if it only makes sense for one file it belongs
in a code comment. Do not record one per finding: past ~20 entries the file
gets skimmed rather than read, and then it teaches nothing. Commit it; it is
team knowledge, not session state.
Step 3 — present options
Pipeline complete. What would you like to do?
1. Push to remote (current branch)
2. Push and create a Pull Request
3. Keep local (I'll handle it)
4. Discard this work
Wait for the user's choice. Do not preemptively execute option 1.
Step 4 — execute
Option 1 — push
REMOTE=$(apd git-remote) && APD_ORCHESTRATOR_COMMIT=1 git push -u "$REMOTE" <branch>
Codex does not yet ship a Git tool hook; run the push from a terminal
outside Codex, or have the user run it.
Option 2 — push and open a PR
REMOTE=$(apd git-remote) && APD_ORCHESTRATOR_COMMIT=1 git push -u "$REMOTE" <branch>
gh pr create --title "<feature>" --body "$(cat <<'EOF'
## Summary
<one-paragraph summary of the change>
## APD Pipeline
- Runtime: Codex
- Spec: approved by user
- Builder: native Codex subagent (`<APD role>`)
- Reviewer: native Codex subagent (`<APD role>`)
- Adversarial: <total>/<accepted>/<dismissed> or "skipped"
- Verifier: all tests pass
- Duration: <time>
## Test plan
- [ ] <verification steps the reviewer should run>
EOF
)"
Option 3 — keep local
Print the branch name and current status. Stop. Let the user handle it.
Option 4 — discard
Require typed confirmation: ask the user to type discard before any
destructive action.
git checkout <base-branch>
git branch -D <branch>
Red flags — STOP
| Thought | Reality |
|---|
| "User probably wants me to push" | Never assume. Ask. |
| "I'll push and create the PR in one go" | User might want to review locally first. |
| "Skip verification, we just ran tests" | Verify again. Something might have changed. |
| "Force push to fix the branch" | Never force push. APD blocks it anyway. |
| "Push to origin" | The remote may not be origin (e.g. esir). Run apd git-remote — never assume. |
Rules
- Never push without user approval
- Resolve the push remote with
apd git-remote — never hardcode origin. If it exits non-zero (ambiguous), ask the user or pin apd git-remote --set-remote <name>
- Never force-push (the destructive-git guard blocks it)
- Always verify tests before presenting options
- PR body MUST include the APD pipeline summary — proves the work was reviewed
Examples
Example 1 — Clean pipeline, user picks Push.
Input: apd:apd_pipeline_state() shows next_step: "commit" after a successful commit. apd:apd_verify_step() returns green.
Output:
Pipeline complete. What would you like to do?
1. Push to remote (current branch)
2. Push and create a Pull Request
3. Keep local (I'll handle it)
4. Discard this work
> 1
$ apd git-remote
esir
$ APD_ORCHESTRATOR_COMMIT=1 git push -u esir feature/order-refund
→ pushed feature/order-refund → esir
The remote is esir, not origin — apd git-remote resolved it. If it exits
non-zero (multiple distinct remotes, none named origin, no upstream/config), it
lists the candidates: ask the user which, or pin it with
apd git-remote --set-remote <name>. Never fall back to a hardcoded origin.
Example 2 — Verifier red blocks the finish menu.
Input: Commit landed, but rerunning apd:apd_verify_step() from clean shows two failing integration tests (OrderRefundSpec.refundFailsTwice, WebhookSpec.signatureMismatch).
Output: Do NOT present the four options. Hand off to apd-debug:
Verifier red after commit:
- test/integration/OrderRefundSpec.refundFailsTwice
- test/integration/WebhookSpec.signatureMismatch
Switching to apd-debug — Phase 1: trace data flow on the two failures.
Example 3 — User picks PR, body carries the pipeline summary.
Input: User picks option 2 after a clean pipeline (6 R-criteria, 11m 32s, adversarial 5/3/2).
Output: PR opened with this body:
## Summary
Add idempotent POST /orders/:id/refund with audit log.
## APD Pipeline
- Runtime: Codex
- Spec: approved by user
- Builder: native Codex subagent (`backend-builder`)
- Reviewer: native Codex subagent (`code-reviewer`)
- Adversarial: 5/3/2 (total/accepted/dismissed)
- Verifier: all tests pass
- Duration: 11m 32s
## Test plan
- [ ] POST /refund twice with same Idempotency-Key → second is a no-op
- [ ] webhook fires exactly once on the first call
Return the PR URL to the user; do not auto-start a new pipeline.
Exit criteria
You're done when:
apd:apd_verify_step() was re-run and is green
- The pipeline report has been shown to the user
- The user has explicitly picked one of the four options (typed, not implied)
- The chosen option has been executed end-to-end (push completed, PR URL returned, branch deleted, etc.)
- For Discard: the user typed
discard literally before any branch was removed
Hand-off
- This is a terminal skill — when it completes, the cycle is closed
- If verification fails at Step 1 → switch to
apd-debug (do NOT present finish options on red tests)
- After option 1/2 success → return push/PR URL to the user; do not auto-start a new pipeline