refactor(opencode): assume opencode runs in the worktree, drop bare-repo plumbing
The workflow previously created a worktree itself (Phase 3) and worked around opencode's lack of per-subagent CWD by capturing absolute paths and threading them through every dispatch (the "Subagent Dispatch Convention"). That ceremony exists only because the orchestrator's CWD differed from where subagents were rooted. Now the workflow assumes the user has already created the worktree and launched opencode inside it. Subagents inherit that as their project root, so all the absolute-path plumbing goes away. Phase 3 is removed, phases renumber to 1-9, and the Subagent Dispatch Convention section is dropped. Phase 1 is a sanity check (non-bare worktree, TODO.md present, HEAD not detached, current branch != base branch) that resolves the base branch from an optional second argument or by trying main then master. @pm now uses live filesystem mode against ./TODO.md throughout (the git-ref read mode stays available for ad-hoc use). Phase 8's diff uses git diff "$BASE_BRANCH"...HEAD without git -C wrapping.
This commit is contained in:
parent
8fcf7e5d34
commit
e2e35acdae
1 changed files with 55 additions and 75 deletions
|
|
@ -1,75 +1,54 @@
|
|||
---
|
||||
description: "Fire-and-forget multi-agent workflow: plan, test, implement, commit"
|
||||
description: "Multi-agent workflow for the current worktree: plan, test, implement, commit"
|
||||
agent: build
|
||||
---
|
||||
|
||||
You are executing the autonomous multi-agent workflow. Run all phases without waiting for user input. The user has walked away.
|
||||
You are executing the multi-agent workflow inside the worktree this opencode session was started from. Run all phases without waiting for user input. The user has walked away.
|
||||
|
||||
**Prerequisites (the user handles before launching opencode):**
|
||||
- A git worktree is checked out for the issue's feature branch
|
||||
- `opencode` was launched from the root of that worktree
|
||||
- `TODO.md` is committed to the repo and present at `./TODO.md`
|
||||
|
||||
**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`."
|
||||
If `$ARGUMENTS` is empty, stop immediately: "Usage: `/workflow <ISSUE-ID> [base-branch]` (e.g. `/workflow ABC-1`). The ID must exist in `./TODO.md`. Base branch defaults to `main` (then `master`)."
|
||||
|
||||
Parse `$ARGUMENTS`: the first whitespace-separated token is the issue ID, an optional second token overrides the base branch.
|
||||
|
||||
---
|
||||
|
||||
## Phase 1: Repo Setup
|
||||
## Phase 1: Sanity Check
|
||||
|
||||
Verify you are in a bare git repo and that the issue tracker exists.
|
||||
|
||||
1. Verify the current repository is bare: `git rev-parse --is-bare-repository 2>/dev/null` must output `true`. If not, stop: "Workflow requires a bare git repository (set up with `git clone --bare` or the `.bare/` + `.git` file pattern)."
|
||||
2. Capture the bare repo root for later worktree creation: `BARE_REPO_ROOT="$(pwd)"`.
|
||||
3. 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 to `main`
|
||||
|
||||
Store as `DEFAULT_BRANCH`.
|
||||
4. 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."
|
||||
5. Proceed to Phase 2.
|
||||
1. Verify CWD is a non-bare git worktree: `git rev-parse --is-bare-repository 2>/dev/null` must output `false`. If not, stop: "Workflow must be run from a non-bare worktree (the directory opencode was launched in)."
|
||||
2. Verify `./TODO.md` exists. If not, stop: "TODO.md not found in the current worktree. Commit a TODO.md to the repo first."
|
||||
3. Verify HEAD is not detached: `git symbolic-ref --short HEAD` must succeed. If it fails, stop: "Cannot run on a detached HEAD. Check out a feature branch first."
|
||||
4. Capture the current branch: `BRANCH_NAME="$(git symbolic-ref --short HEAD)"`.
|
||||
5. Resolve the base branch (`BASE_BRANCH`):
|
||||
- If `$ARGUMENTS` provided a second token, use it.
|
||||
- Else if `git rev-parse --verify --quiet main` succeeds, use `main`.
|
||||
- Else if `git rev-parse --verify --quiet master` succeeds, use `master`.
|
||||
- Else stop: "Could not determine base branch (no `main` or `master`). Pass it as the second argument: `/workflow <ISSUE-ID> <base-branch>`."
|
||||
6. Verify the current branch is not the base branch: if `BRANCH_NAME == BASE_BRANCH`, stop: "Cannot run workflow on the base branch (`$BASE_BRANCH`). Switch to a feature branch first."
|
||||
|
||||
---
|
||||
|
||||
## 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`:
|
||||
Dispatch `@pm` to read `./TODO.md` (live filesystem mode) and fetch the issue matching the parsed ID:
|
||||
- Issue title, description, acceptance criteria
|
||||
- Labels and priority
|
||||
- Any existing branch name
|
||||
- Existing status
|
||||
|
||||
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 `-`.
|
||||
If the issue's status is `Backlog` or `Todo`, ask `@pm` to set it to `In Progress` (this edit will be staged in Phase 9 alongside other TODO.md updates).
|
||||
|
||||
---
|
||||
|
||||
## Phase 3: Repo Setup (continued)
|
||||
## Phase 3: Plan
|
||||
|
||||
From `$BARE_REPO_ROOT`:
|
||||
|
||||
1. If an `origin` remote is configured, run `git fetch origin` (best-effort; ignore failure if there is no remote).
|
||||
2. Compute worktree directory: replace all `/` with `-` in the branch name (e.g. `feat/abc-1-foo` becomes `feat-abc-1-foo`)
|
||||
3. Check if worktree directory already exists. If yes, enter it and verify `git status --porcelain` is empty. If dirty, stop: "Worktree exists but has uncommitted changes. Clean it up first."
|
||||
4. If worktree does not exist: `git worktree add <dir-name> -b <branch-name> "$DEFAULT_BRANCH"`
|
||||
5. Change working directory to the new worktree and capture its absolute path: `WORKTREE_PATH="$(pwd)"`. From here on, `$WORKTREE_PATH/TODO.md` is 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:**
|
||||
|
||||
1. Open with the header `Worktree: <absolute path>` using the captured `$WORKTREE_PATH`.
|
||||
2. 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."
|
||||
3. 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.
|
||||
Analyze the codebase. Create a detailed implementation plan addressing the issue's requirements and acceptance criteria.
|
||||
|
||||
The plan should include:
|
||||
- Problem summary (from issue context)
|
||||
|
|
@ -89,9 +68,9 @@ The plan should include:
|
|||
|
||||
---
|
||||
|
||||
## Phase 5: Review Plan
|
||||
## Phase 4: 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).
|
||||
Dispatch `@check` and `@simplify` in parallel to review the plan.
|
||||
|
||||
Reviewers should evaluate testability:
|
||||
- `@check`: Is the design testable? Are the right behaviors identified? (Review Framework §8)
|
||||
|
|
@ -105,14 +84,14 @@ Reviewers should evaluate testability:
|
|||
**Review loop (max 3 cycles):**
|
||||
1. Send plan to both reviewers
|
||||
2. Merge findings
|
||||
3. If verdict is ACCEPTABLE from both (or JUSTIFIED COMPLEXITY from `@simplify`): proceed to Phase 6
|
||||
3. If verdict is ACCEPTABLE from both (or JUSTIFIED COMPLEXITY from `@simplify`): proceed to Phase 5
|
||||
4. If BLOCK or NEEDS WORK: revise the plan addressing findings, then re-review
|
||||
5. **Convergence detection:** if reviewers return the same findings as the previous cycle, stop the loop early
|
||||
6. 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
|
||||
## Phase 5: Split into Tasks
|
||||
|
||||
Break the approved plan into discrete tasks for `@make`. Each task needs:
|
||||
|
||||
|
|
@ -126,18 +105,18 @@ Break the approved plan into discrete tasks for `@make`. Each task needs:
|
|||
|
||||
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).
|
||||
Include **Test Design** from Phase 3 when available, attached to the relevant task(s).
|
||||
|
||||
**Task size:** ~10-30 minutes each, single coherent change, clear boundaries.
|
||||
|
||||
---
|
||||
|
||||
## Phase 7: Write Tests
|
||||
## Phase 6: Write Tests
|
||||
|
||||
For each task from Phase 6, dispatch `@test` with (per the **Subagent Dispatch Convention** — `Worktree: $WORKTREE_PATH`, absolute paths):
|
||||
For each task from Phase 5, dispatch `@test` with:
|
||||
- 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)
|
||||
- The test file path to create (following colocated pattern)
|
||||
|
||||
`@test` writes failing tests and verifies RED with structured failure codes.
|
||||
|
||||
|
|
@ -150,14 +129,17 @@ After `@test` completes, validate only NEW changes:
|
|||
```bash
|
||||
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/**`.
|
||||
All new files must match the project's test patterns:
|
||||
- Python: `**/test_*.py`, `**/*_test.py`, `**/conftest.py` (new only), `**/test_data/**`, `**/test_fixtures/**`
|
||||
- Rust: `tests/**/*.rs`, `**/tests/**/*.rs`, `**/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: false` | Proceed to Phase 7 |
|
||||
| `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. |
|
||||
|
|
@ -168,11 +150,11 @@ If any non-matching file appears: discard `@test` output, report violation.
|
|||
|
||||
---
|
||||
|
||||
## Phase 8: Implement
|
||||
## Phase 7: 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/`)
|
||||
Execute each task by dispatching `@make` with:
|
||||
- The task spec (from Phase 5)
|
||||
- Relevant code context (actual snippets)
|
||||
- **Pre-written failing tests and handoff from `@test` (if TESTS_READY)**
|
||||
|
||||
`@make` runs in TDD mode when tests are provided:
|
||||
|
|
@ -198,26 +180,26 @@ After all tasks complete, verify overall integration:
|
|||
|
||||
---
|
||||
|
||||
## Phase 9: Final Review
|
||||
## Phase 8: 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).
|
||||
Dispatch `@check` and `@simplify` in parallel to review the full implementation (all changes across all files).
|
||||
|
||||
Provide reviewers with:
|
||||
- The original plan
|
||||
- The full diff (`git -C "$WORKTREE_PATH" diff "$DEFAULT_BRANCH"...HEAD`)
|
||||
- The full diff (`git diff "$BASE_BRANCH"...HEAD`)
|
||||
- Any decisions or deviations from the plan
|
||||
|
||||
**Review loop (max 3 cycles):**
|
||||
1. Send implementation to both reviewers
|
||||
2. Merge findings (same precedence rules as Phase 5)
|
||||
3. If ACCEPTABLE: proceed to Phase 10
|
||||
2. Merge findings (same precedence rules as Phase 4)
|
||||
3. If ACCEPTABLE: proceed to Phase 9
|
||||
4. If issues found: fix them directly (no need to re-dispatch `@make` for small fixes), then re-review
|
||||
5. **Convergence detection:** same findings twice = stop loop early
|
||||
6. If unresolved after 3 cycles: document blockers, proceed to commit anyway
|
||||
|
||||
---
|
||||
|
||||
## Phase 10: Commit and Wrap Up
|
||||
## Phase 9: 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.
|
||||
|
||||
|
|
@ -227,8 +209,8 @@ The workflow is forge-agnostic. It commits locally and stops. **Do not push, and
|
|||
- 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.md` so it edits the worktree's writable copy. Ask it to:
|
||||
- Set **Branch** to the worktree branch name
|
||||
- Dispatch `@pm` against `./TODO.md` (live filesystem mode). Ask it to:
|
||||
- Set **Branch** to `$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 `@pm` to check them off
|
||||
|
|
@ -246,17 +228,15 @@ The workflow is forge-agnostic. It commits locally and stops. **Do not push, and
|
|||
- 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 `.gitignore` if not already.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Failure Handling
|
||||
|
||||
At any phase, if an unrecoverable error occurs:
|
||||
1. 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.
|
||||
1. Write `.opencode/workflow-summary.md` with what was completed and what failed. Do **not** stage or commit this file.
|
||||
2. If any code was written, commit it with message `wip: incomplete workflow run for <issue-id>`. Stage code only — exclude `.opencode/workflow-summary.md`.
|
||||
3. Leave the branch and worktree intact for the user to inspect — do not push, do not delete
|
||||
4. If a worktree exists, dispatch `@pm` (with header `Worktree: $WORKTREE_PATH` and the absolute path `$WORKTREE_PATH/TODO.md`) to add a comment on the issue summarising what failed
|
||||
5. Stop execution
|
||||
3. Leave the branch and worktree intact for the user to inspect — do not push, do not delete.
|
||||
4. Dispatch `@pm` against `./TODO.md` to add a comment on the issue summarising what failed.
|
||||
5. Stop execution.
|
||||
|
||||
**Never hang on interactive prompts.** If any command appears to require input, treat it as a failure and follow the above procedure.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue