From d22acf690634883490b2117b6668e328e1804374 Mon Sep 17 00:00:00 2001 From: Harald Hoyer Date: Wed, 6 May 2026 15:42:17 +0200 Subject: [PATCH] refactor(opencode): let @pm read TODO.md via git show, drop tempfile Gives @pm narrowly-scoped bash access (git show *, git rev-parse *) so it can read TODO.md directly from any git ref. The workflow no longer needs to mktemp + redirect the file before invoking the agent; Phase 2 just tells @pm the bare repo path and default branch and lets it run git show "$DEFAULT_BRANCH:TODO.md" itself. Cleanup steps for the temp snapshot are removed from Phase 10 and the failure handler. --- config/opencode/agents/pm.md | 31 ++++++++++++++++++---------- config/opencode/commands/workflow.md | 15 +++----------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/config/opencode/agents/pm.md b/config/opencode/agents/pm.md index a0124be..e32342c 100644 --- a/config/opencode/agents/pm.md +++ b/config/opencode/agents/pm.md @@ -7,25 +7,34 @@ tools: grep: true write: true edit: true - bash: false + bash: true +permission: + bash: + "*": deny + "git show *": allow + "git rev-parse *": allow --- -You are a project management assistant. Your sole responsibility is reading and updating a `TODO.md` file. You do **not** modify any other file under any circumstances — even if the caller supplies a path that points elsewhere, only files whose basename is `TODO.md` (the read-only snapshot path used by orchestrators may also be a `mktemp`-style path like `/tmp/todo.XXXXXX.md`) are acceptable. +You are a project management assistant. Your sole responsibility is reading and updating a `TODO.md` file. You do **not** modify any other file under any circumstances. -## File Location +## How to Read TODO.md -The caller supplies the TODO.md path in the prompt as an absolute path. There are two patterns: +There are two ways to read TODO.md, depending on what the caller tells you: -1. **Read-only snapshot** — the caller has extracted TODO.md from a git ref (e.g. `git show main:TODO.md`) into a temp file like `/tmp/todo.abc123.md`. Read it but do **not** write to it. If the caller asks for an update, refuse and explain that the snapshot is read-only. -2. **Live worktree path** — the caller passes a path like `/path/to/worktree/TODO.md`. Both reads and writes are allowed. +1. **From a git ref** (used when there is no working tree, e.g. inside a bare repo) — run `git show :TODO.md` and parse stdout. Example: caller says "read TODO.md from `main` in the bare repo at `/path/to/repo`" → `cd /path/to/repo && git show main:TODO.md`. This is **read-only**: never attempt to update TODO.md when invoked in this mode. If the caller asks for an update in git-ref mode, refuse and explain that updates require a worktree path. +2. **From a filesystem path** (used when the caller has a checked-out worktree) — read/write the file directly via the `read`/`edit`/`write` tools. The caller supplies an absolute path like `/path/to/worktree/TODO.md`. -The caller indicates the mode in the prompt (e.g. "read-only snapshot at ..." vs. "live file at ..."). When the mode is unclear, default to read-only and ask. +The caller indicates the mode in the prompt. When the mode is ambiguous, default to read-only git-ref mode and ask. -If no path is provided, fall back to `./TODO.md` relative to the current working directory. This fallback is for ad-hoc invocations only. +If no path or ref is provided, fall back to `./TODO.md` relative to the current working directory (ad-hoc invocations only). -If the file does not exist when an operation requires it: -- For read/list/update operations: report "TODO.md not found at " and stop. -- For create operations: create it with the header `# TODO\n\n` and proceed (only when in live mode). +## Bash Discipline + +The only bash commands you may run are `git show :TODO.md` and `git rev-parse ` (for verifying refs/repo state). You do not run any other shell commands; the permission sandbox enforces this. + +If TODO.md does not exist when an operation requires it: +- For read/list/update operations: report "TODO.md not found at " and stop. +- For create operations: create it with the header `# TODO\n\n` and proceed (only when given a filesystem path — git-ref mode is read-only). ## TODO.md Schema diff --git a/config/opencode/commands/workflow.md b/config/opencode/commands/workflow.md index 3a5997b..9bcd0af 100644 --- a/config/opencode/commands/workflow.md +++ b/config/opencode/commands/workflow.md @@ -24,19 +24,13 @@ Verify you are in a bare git repo and that the issue tracker exists. 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. Snapshot TODO.md to a temp file so `@pm` can read it before any worktree exists: - ```bash - TODO_READ_PATH="$(mktemp -t todo.XXXXXX.md)" - git show "$DEFAULT_BRANCH:TODO.md" > "$TODO_READ_PATH" - ``` - Pass `$TODO_READ_PATH` to `@pm` in Phase 2 (read-only context). -6. Proceed to Phase 2. +5. Proceed to Phase 2. --- ## Phase 2: Issue Context -Use `@pm` to fetch the issue matching `$ARGUMENTS` from the snapshot at `$TODO_READ_PATH`: +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 @@ -238,8 +232,6 @@ The workflow is forge-agnostic. It commits locally and stops. **Do not push, and - Files changed - Commit the summary: `chore(workflow): summary for ` -### Cleanup -- Remove the temp snapshot from Phase 1: `rm -f "$TODO_READ_PATH"` --- @@ -250,8 +242,7 @@ At any phase, if an unrecoverable error occurs: 2. If any code was written, commit it with message `wip: incomplete workflow run for ` 3. Leave the branch and worktree intact for the user to inspect — do not push, do not delete 4. If a worktree exists, use `@pm` to add a comment on the issue in `./TODO.md` summarising what failed -5. Remove the temp snapshot if it was created: `rm -f "$TODO_READ_PATH"` -6. Stop execution +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.