A per-branch artifact written by every run causes merge conflicts when multiple workflow branches are merged together. The summary is now documented as an intentionally untracked local file: not staged in the main commit, not committed in its own commit, and not staged in the failure-path WIP commit. Recommends the user add `.opencode/` to `.gitignore`.
13 KiB
| description | agent |
|---|---|
| Fire-and-forget multi-agent workflow: plan, test, implement, commit | build |
You are executing the autonomous multi-agent workflow. Run all phases without waiting for user input. The user has walked away.
Task reference: $ARGUMENTS
If $ARGUMENTS is empty, stop immediately: "Usage: /workflow <ISSUE-ID> (e.g. /workflow ABC-1). The ID must exist in ./TODO.md."
Phase 1: Repo Setup
Verify you are in a bare git repo and that the issue tracker exists.
-
Verify the current repository is bare:
git rev-parse --is-bare-repository 2>/dev/nullmust outputtrue. If not, stop: "Workflow requires a bare git repository (set up withgit clone --bareor the.bare/+.gitfile pattern)." -
Capture the bare repo root for later worktree creation:
BARE_REPO_ROOT="$(pwd)". -
Determine the default branch (source of TODO.md and base for new worktrees). Resolve in order: a.
git symbolic-ref --short HEAD— the bare repo's HEAD b.git config init.defaultBranch— the configured default c. fall back tomainStore as
DEFAULT_BRANCH. -
Verify TODO.md exists on the default branch:
git show "$DEFAULT_BRANCH:TODO.md" > /dev/null 2>&1. If not, stop: "TODO.md not found on$DEFAULT_BRANCH. Commit a TODO.md there first — the workflow expects it to be a tracked file." -
Proceed to Phase 2.
Phase 2: Issue Context
Dispatch @pm in read-only git-ref mode: tell it the bare repo path is $BARE_REPO_ROOT and to read TODO.md via git show "$DEFAULT_BRANCH:TODO.md". Ask for the issue matching $ARGUMENTS:
- Issue title, description, acceptance criteria
- Labels and priority
- Any existing branch name
If the issue does not exist or @pm fails, stop with error.
Derive a branch name: <issue-id-lowercase>-<slugified-title> (e.g. abc-1-add-retry-logic). Validate: only [A-Za-z0-9._/-], no leading -.
Phase 3: Repo Setup (continued)
From $BARE_REPO_ROOT:
- If an
originremote is configured, rungit fetch origin(best-effort; ignore failure if there is no remote). - Compute worktree directory: replace all
/with-in the branch name (e.g.feat/abc-1-foobecomesfeat-abc-1-foo) - Check if worktree directory already exists. If yes, enter it and verify
git status --porcelainis empty. If dirty, stop: "Worktree exists but has uncommitted changes. Clean it up first." - If worktree does not exist:
git worktree add <dir-name> -b <branch-name> "$DEFAULT_BRANCH" - Change working directory to the new worktree and capture its absolute path:
WORKTREE_PATH="$(pwd)". From here on,$WORKTREE_PATH/TODO.mdis the live, writable copy that Phase 10 will update.
Subagent Dispatch Convention
Subagents do not inherit the orchestrator's cd. When opencode dispatches @check, @simplify, @test, @make, or @pm, each starts with a fresh shell in an unspecified working directory and may resolve relative paths against the bare repo root rather than the worktree. This produces silent "file not found" failures for paths like src/main.rs.
Every dispatch prompt in Phases 5, 7, 8, 9, and 10 must:
- Open with the header
Worktree: <absolute path>using the captured$WORKTREE_PATH. - State explicitly: "All file paths in this prompt are relative to that worktree. Read files via their absolute path (
<worktree>/<rel>); do not rely on the current working directory." - Pass any file reference (in code context, diff snippets, file lists) as an absolute path under
$WORKTREE_PATH/.
@pm invocations that update TODO.md must receive $WORKTREE_PATH/TODO.md as the live path. @pm invocations that only read from a git ref (Phase 2) instead receive $BARE_REPO_ROOT and the ref name.
Phase 4: Plan
Analyze the codebase in the worktree context. Create a detailed implementation plan addressing the issue's requirements and acceptance criteria.
The plan should include:
-
Problem summary (from issue context)
-
Proposed approach with rationale
-
Files to modify (with brief description of changes)
-
New files to create
-
Risks and open questions
-
Test Design (conditional — include for non-trivial tasks):
- Key behaviors to verify (what tests should assert)
- Edge cases and error conditions worth testing
- What explicitly should NOT be tested (prevents bloat)
- Testability concerns (heavy external deps, GPU-only paths, etc.)
Include Test Design for: Public API changes, bug fixes with behavioral impact, new features with business logic, multi-module changes. Skip Test Design for: Config-only changes, decorator swaps, import reorganization, documentation. When skipped,
@testderives test cases directly from acceptance criteria.
Phase 5: Review Plan
Dispatch @check and @simplify in parallel to review the plan. Each dispatch prompt must follow the Subagent Dispatch Convention (header Worktree: $WORKTREE_PATH, absolute paths only).
Reviewers should evaluate testability:
@check: Is the design testable? Are the right behaviors identified? (Review Framework §8)@simplify: Is the test scope appropriate? Over-testing proposed?
Merge rules:
@checksafety/correctness findings are hard constraints- If
@simplifyrecommends removing something@checkflags as needed,@checkwins - Note conflicts explicitly
Review loop (max 3 cycles):
- Send plan to both reviewers
- Merge findings
- If verdict is ACCEPTABLE from both (or JUSTIFIED COMPLEXITY from
@simplify): proceed to Phase 6 - If BLOCK or NEEDS WORK: revise the plan addressing findings, then re-review
- Convergence detection: if reviewers return the same findings as the previous cycle, stop the loop early
- If still unresolved after 3 cycles: note unresolved blockers and proceed anyway (they will be documented in the workflow summary and commit message)
Phase 6: Split into Tasks
Break the approved plan into discrete tasks for @make. Each task needs:
| Required | Description |
|---|---|
| Task | Clear description of what to implement |
| Acceptance Criteria | Specific, testable criteria (checkbox format) |
| Code Context | Actual code snippets from the codebase, not just file paths |
| Files to Modify | Explicit list, mark new files with "(create)" |
| Test File | Path for test file (colocated pattern), e.g., <module>/tests/test_<feature>.py (create) |
Include Integration Contracts when a task adds/changes function signatures, APIs, config keys, or has dependencies on other tasks.
Include Test Design from Phase 4 when available, attached to the relevant task(s).
Task size: ~10-30 minutes each, single coherent change, clear boundaries.
Phase 7: Write Tests
For each task from Phase 6, dispatch @test with (per the Subagent Dispatch Convention — Worktree: $WORKTREE_PATH, absolute paths):
- The task spec (acceptance criteria, code context, files to modify)
- The Test Design section from the plan (if provided)
- The test file path to create as an absolute path under
$WORKTREE_PATH/(following colocated pattern)
@test writes failing tests and verifies RED with structured failure codes.
Post-step file gate (MANDATORY):
Before dispatching @test, snapshot the current changed files:
git diff --name-only > /tmp/pre_test_baseline.txt
After @test completes, validate only NEW changes:
git diff --name-only | comm -23 - /tmp/pre_test_baseline.txt > /tmp/test_new_files.txt
All new files must match: **/test_*.py, **/*_test.py, **/conftest.py (new only), **/test_data/**, **/test_fixtures/**.
If any non-matching file appears: discard @test output, report violation.
Decision table — handling @test results:
| Condition | Action |
|---|---|
TESTS_READY + escalate_to_check: false |
Proceed to Phase 8 |
TESTS_READY + escalate_to_check: true |
Route tests to @check for light review. @check diagnoses, caller routes fixes to @test. Then proceed. |
NOT_TESTABLE |
Route to @check for sign-off on justification. If approved, task goes to @make without tests. |
BLOCKED |
Investigate. May need to revise task spec or plan. |
| Test passes immediately | Investigate — behavior may already exist. Task spec may be wrong. |
Parallelism: Independent tasks can have tests written in parallel.
Constraint: @test must not modify existing conftest.py files (prevents collision during parallel execution).
Phase 8: Implement
Execute each task by dispatching @make with (per the Subagent Dispatch Convention — Worktree: $WORKTREE_PATH, absolute paths):
- The task spec (from Phase 6)
- Relevant code context (actual snippets, with absolute file paths under
$WORKTREE_PATH/) - Pre-written failing tests and handoff from
@test(if TESTS_READY)
@make runs in TDD mode when tests are provided:
- Entry validation: run tests, verify RED, check failure codes match handoff
- Implement minimal code to make tests pass (GREEN)
- Regression check on broader area
- Refactor while keeping green
- Report RED→GREEN evidence
Escalation: If @make flags test quality concerns during entry validation:
@makereports the issue to caller- Caller routes to
@checkfor diagnosis @checkreports findings- Caller routes to
@testfor fixes - Fixed tests return to
@make
For NOT_TESTABLE tasks, @make runs in standard mode.
After all tasks complete, verify overall integration:
- Run the project's test suite if available
- Run linting/type checking if configured
- Fix any integration issues between tasks
Phase 9: Final Review
Dispatch @check and @simplify in parallel to review the full implementation (all changes across all files). Each dispatch prompt must follow the Subagent Dispatch Convention (header Worktree: $WORKTREE_PATH, absolute paths only).
Provide reviewers with:
- The original plan
- The full diff (
git -C "$WORKTREE_PATH" diff "$DEFAULT_BRANCH"...HEAD) - Any decisions or deviations from the plan
Review loop (max 3 cycles):
- Send implementation to both reviewers
- Merge findings (same precedence rules as Phase 5)
- If ACCEPTABLE: proceed to Phase 10
- If issues found: fix them directly (no need to re-dispatch
@makefor small fixes), then re-review - Convergence detection: same findings twice = stop loop early
- If unresolved after 3 cycles: document blockers, proceed to commit anyway
Phase 10: Commit and Wrap Up
The workflow is forge-agnostic. It commits locally and stops. Do not push, and do not open a pull/merge request — the user chooses their forge and review workflow manually.
Commit Code Changes
- Stage code changes only. Do not stage
TODO.md(committed separately below) and do not stage.opencode/workflow-summary.md(intentionally never committed — see Local Summary). - Write a conventional commit message summarizing the implementation. Reference the TODO.md issue ID in the body (e.g.
Refs: ABC-1). - If changes are large/varied, use multiple atomic commits (one per logical unit)
TODO Update
- Dispatch
@pm(per the Subagent Dispatch Convention) and pass the live path$WORKTREE_PATH/TODO.mdso it edits the worktree's writable copy. Ask it to:- Set Branch to the worktree branch name
- Set Status to
In Review - Add a comment with the branch name, latest commit SHA, and a one-line summary
- If acceptance-criteria checkboxes were addressed by the implementation, ask
@pmto check them off - Commit the TODO.md change as a separate atomic commit:
chore(todo): update <issue-id> status and progress
Local Summary
- Write
.opencode/workflow-summary.mdin the worktree with:- Run timestamp
- Issue reference and title
- Branch name and final commit SHA(s)
- Summary of implementation
- TDD evidence (RED→GREEN per task, NOT_TESTABLE justifications)
- Review outcomes (plan review + final review verdicts)
- Unresolved items (if any)
- Files changed
- Do not commit this file. It is a per-run, per-branch artifact; committing it would create merge conflicts whenever multiple workflow branches are merged. Leave it untracked. Recommend the user add
.opencode/to.gitignoreif not already.
Failure Handling
At any phase, if an unrecoverable error occurs:
- Write
.opencode/workflow-summary.md(in the worktree, if one exists) with what was completed and what failed. Do not stage or commit this file. - If any code was written, commit it with message
wip: incomplete workflow run for <issue-id>. Stage code only — exclude.opencode/workflow-summary.md. - Leave the branch and worktree intact for the user to inspect — do not push, do not delete
- If a worktree exists, dispatch
@pm(with headerWorktree: $WORKTREE_PATHand the absolute path$WORKTREE_PATH/TODO.md) to add a comment on the issue summarising what failed - Stop execution
Never hang on interactive prompts. If any command appears to require input, treat it as a failure and follow the above procedure.