refactor(opencode): migrate @pm and workflow to per-issue TODO/ folder

The single TODO.md schema is replaced by a Linear-style folder layout
matching the user's existing setup at /home/harald/git/bglga/TODO:

  TODO/
  ├── README.md          # category-grouped index (top-level only)
  ├── GAL-1.md
  ├── GAL-2.md
  └── …

Each issue file has YAML frontmatter (id, title, status, parent,
labels) and a body with optional sections (Sub-issues, Acceptance
criteria, Integration test hints, Comments). The status set shrinks
to Todo / In Progress / Done; Branch / PR / Priority / Assignee
fields are gone. Comments are date-only.

@pm gains directory-walking semantics (still scoped to TODO/), bash
allowlist additions for git ls-tree and ls, and a propagation rule:
status flips to/from Done update the dependent index — README.md for
top-level issues, or the parent file's Sub-issues line for sub-issues.

The workflow's Phase 1 sanity check now verifies TODO/, TODO/README.md,
and TODO/<ID>.md all exist. Phase 2 reads the issue file and flips Todo
to In Progress with index propagation. Phase 9 stages everything under
TODO/ as a separate atomic chore(todo) commit, sets the status to Done
(or leaves In Progress for incomplete runs), and adds a date + branch +
commit comment. Failure handler routes through the same directory.
This commit is contained in:
Harald Hoyer 2026-05-07 09:58:23 +02:00
parent 91ba5bd272
commit 5a5cf269dc
2 changed files with 152 additions and 92 deletions

View file

@ -8,11 +8,11 @@ You are executing the multi-agent workflow inside the worktree this opencode ses
**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`
- A `TODO/` directory is committed to the repo containing per-issue files (`TODO/<ID>.md`) plus `TODO/README.md`
**Task reference:** $ARGUMENTS
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`)."
If `$ARGUMENTS` is empty, stop immediately: "Usage: `/workflow <ISSUE-ID> [base-branch]` (e.g. `/workflow ABC-1`). The ID must exist as `./TODO/<ID>.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.
@ -21,7 +21,10 @@ Parse `$ARGUMENTS`: the first whitespace-separated token is the issue ID, an opt
## Phase 1: Sanity Check
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."
2. Verify the TODO tracker exists:
- `./TODO/` directory must exist. If not, stop: "TODO/ directory not found in the current worktree. Commit a TODO/ folder with one file per issue plus a README.md index."
- `./TODO/README.md` must exist. If not, stop: "TODO/README.md not found. Add the category index file before running the workflow."
- `./TODO/<ARGUMENTS-first-token>.md` must exist. If not, stop: "Issue file `./TODO/<ID>.md` not found for ID parsed from `$ARGUMENTS`."
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`):
@ -35,14 +38,15 @@ Parse `$ARGUMENTS`: the first whitespace-separated token is the issue ID, an opt
## Phase 2: Issue Context
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
Dispatch `@pm` against `./TODO/` (live filesystem mode; pass the absolute `TODO/` directory path) and fetch the issue at `./TODO/<ID>.md`:
- Title, description, acceptance criteria (if section present)
- Labels and parent
- Sub-issues list (if the issue is a parent)
- Existing status
If the issue does not exist or `@pm` fails, stop with error.
If the issue file does not exist or `@pm` fails, stop with error.
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).
If the issue's status is `Todo`, ask `@pm` to set it to `In Progress` and propagate the change to the dependent index (`README.md` for top-level issues, the parent's `## Sub-issues` line for sub-issues). The status edit will be staged alongside other TODO updates in Phase 9.
---
@ -372,17 +376,17 @@ Provide reviewers with:
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`).
- Stage code changes only. **Do not stage anything under `TODO/`** (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 issue ID in the body (e.g. `Refs: GAL-39`).
- If changes are large/varied, use multiple atomic commits (one per logical unit)
### TODO Update
- 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
- Commit the TODO.md change as a separate atomic commit: `chore(todo): update <issue-id> status and progress`
- Dispatch `@pm` against the absolute `./TODO/` path (live filesystem mode). Ask it to:
- Set the issue file's frontmatter `status` to `Done` (or leave at `In Progress` if the run is incomplete and the user must verify before marking Done).
- Add a comment of the form: `- YYYY-MM-DD — Branch \`$BRANCH_NAME\`, commit <SHA><one-line summary>` (date from the shell, never fabricated).
- Propagate any status flip to the dependent index: `TODO/README.md` for top-level issues (`parent: null`), or the parent file's `## Sub-issues` line for sub-issues.
- If acceptance-criteria checkboxes were addressed by the implementation, ask `@pm` to check them off (flip `- [ ]` to `- [x]` under `## Acceptance criteria`).
- Commit the TODO/ changes as a separate atomic commit: `chore(todo): update <issue-id> status and progress`. Stage the issue file plus any propagated index file (README.md or parent file).
### Local Summary
- Write `.opencode/workflow-summary.md` in the worktree with:
@ -404,7 +408,7 @@ At any phase, if an unrecoverable error occurs:
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. Dispatch `@pm` against `./TODO.md` to add a comment on the issue summarising what failed.
4. Dispatch `@pm` against `./TODO/` (live filesystem mode) to add a comment on the issue file (`./TODO/<ID>.md`) 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.