diff --git a/common/engineering/implement-issue/SKILL.md b/common/engineering/implement-issue/SKILL.md index 587f7f9..c5304a4 100644 --- a/common/engineering/implement-issue/SKILL.md +++ b/common/engineering/implement-issue/SKILL.md @@ -13,11 +13,10 @@ The issue tracker conventions live in [`docs/agents/issue-tracker.md`](../../../ ## Invocation ``` -/skill:implement-issue [--agent ] [--base ] [--force] +/skill:implement-issue [--base ] [--force] ``` - `` — required, the issue number -- `--agent ` — **DEPRECATED**: this argument is ignored. The agent CLI is read from `docs/agents/agent-cli.md`, which is set up by `/setup-skills` Section E. Rerun `/setup-skills` to change the agent. - `--base ` — optional, target base branch (default: repo default branch). - `--force` — optional, allow overwriting an existing worktree. @@ -119,7 +118,7 @@ Stop. #### 2a. Label the issue `in-progress` -Apply the `in-progress` triage label. +Change the issue triage labels to `in-progress` #### 2b. Create the worktree @@ -131,7 +130,7 @@ git worktree add -b ../-issue- Assemble a single prompt that the child agent will receive. Include: -- **Issue body** — the full markdown body from `tea issue -o json` +- **Issue body** — the full markdown body of the issue. - **Comments** — all comments, if any - **Standing instruction**: "Implement using TDD: write a failing test first, make it pass, refactor. Explore the codebase before writing code. Respect ADRs and the project domain glossary. Set up the project (install dependencies, build) before starting. The issue body may contain Implementation Decisions and Testing Decisions sections — treat these as constraints." - **Context**: "Base branch: ``. Target your PR at ``. Branch name: ``." @@ -143,9 +142,10 @@ Assemble a single prompt that the child agent will receive. Include: 5. Commit with conventional commits (`feat:` for enhancement, `fix:` for bug) referencing `(#)` 6. Push the branch: `git push origin ` 7. Create a PR with: link to the issue, one-sentence summary, short key-changes list - 8. Comment on the issue with the PR link: `tea comment "PR opened: "` - 9. Change the issue label to `needs-review`: `tea issues edit --add-labels "needs-review" --remove-labels "in-progress"` - 10. Print `DONE — issue #` + 8. Comment on the issue with the PR link: `"PR opened: "` + 9. Change the issue triage label to `needs-review` + 10. remove the prompt file from `/tmp` (the child may have already read it) + 11. Print `DONE — issue #` - **Failure instruction**: "If any step fails, report where you stopped and what remains for manual recovery. Print the exact commands needed." Write the full prompt to a temp file: @@ -170,46 +170,49 @@ If available, use `mise x --allow-env='*' --` as the runner prefix. Otherwise, f #### 4b. Compose the agent command -Substitute `@{prompt}` in the configured `args` with the absolute path to the temp prompt file: +Substitute `{prompt}` in the configured `args` with the absolute path to the temp prompt file. The prompt file path is `/tmp/issue--prompt.md`: -- If `args` is non-empty: the agent command is ` ` -- If `args` is empty (stdin-piping agents): the agent command is `cat | ` +```bash +prompt_file="/tmp/issue--prompt.md" +substituted_args="${args//\{prompt\}/$prompt_file}" +``` + +- If `args` was non-empty: the agent command is ` $substituted_args` +- If `args` was empty (stdin-piping agents): the agent command is `cat $prompt_file | ` #### 4c. Compose the full tmux command +Use `$substituted_args` from step 4b: + ```bash -tmux new-window -n "issue--" -c " " +tmux new-window -n "issue--" -c " $substituted_args" ``` **With mise:** ```bash -tmux new-window -n "issue--" -c /path/to/worktree "mise x --allow-env='*' -- " +tmux new-window -n "issue--" -c /path/to/worktree "mise x --allow-env='*' -- $binary $substituted_args" ``` **Without mise (fallback):** ```bash -tmux new-window -n "issue--" -c /path/to/worktree "$SHELL -c ' '" +tmux new-window -n "issue--" -c /path/to/worktree "$SHELL -c '$binary $substituted_args'" ``` -For stdin-piping agents (empty args), wrap the pipe command: +For stdin-piping agents (empty args), use the pipe form: **With mise:** ```bash -tmux new-window -n "issue--" -c /path/to/worktree "mise x --allow-env='*' -- sh -c 'cat | '" +tmux new-window -n "issue--" -c /path/to/worktree "mise x --allow-env='*' -- sh -c 'cat $prompt_file | $binary'" ``` **Without mise:** ```bash -tmux new-window -n "issue--" -c /path/to/worktree "$SHELL -c 'cat | '" +tmux new-window -n "issue--" -c /path/to/worktree "$SHELL -c 'cat $prompt_file | $binary'" ``` The window stays open after the child completes so the user can review the output. -After tmux launches, clean up the temp file: - -```bash -rm /tmp/issue--prompt.md -``` +Do not remove the prompt file immediately — the child agent may not have read it yet. The file will be read from `/tmp` and cleaned up by the OS or the child after use. ### 5. Print summary diff --git a/common/engineering/implement-issue/agent-cli.test.md b/common/engineering/implement-issue/agent-cli.test.md deleted file mode 100644 index d257709..0000000 --- a/common/engineering/implement-issue/agent-cli.test.md +++ /dev/null @@ -1,161 +0,0 @@ -# Agent CLI Tests for implement-issue - -These tests verify the tmux command composition logic in `implement-issue`. They intercept the generated shell command string rather than the tmux invocation itself. - -The seam being tested: given a `docs/agents/agent-cli.md` config and a `mise` availability state, `implement-issue` must compose the correct tmux launch command. - -## Test fixtures - -### Fixture: pi agent config (stdin-piped via @{prompt}) - -```yaml -# docs/agents/agent-cli.md -selected: pi -binary: pi -args: "-p @{prompt}" -``` - -### Fixture: opencode agent config - -```yaml -# docs/agents/agent-cli.md -selected: opencode -binary: opencode -args: "run -f @{prompt}" -``` - -### Fixture: codex agent config (empty args = stdin pipe) - -```yaml -# docs/agents/agent-cli.md -selected: codex -binary: codex -args: "" -``` - -### Fixture: missing binary config - -```yaml -# docs/agents/agent-cli.md -selected: missing-agent -binary: totally-not-on-path -args: "" -``` - -## Test cases - -### Test: composes correct tmux command for pi with mise available - -**Given:** -- `docs/agents/agent-cli.md` contains the pi fixture -- `command -v mise` succeeds - -**When:** `implement-issue` composes the tmux launch command - -**Then:** the generated command string is: - -``` -tmux new-window -n "issue-42-ws-sjb-skills" -c /home/sjb/Projects/personal/ws-sjb-skills/ws-sjb-skills-issue-42 "mise x --allow-env='*' -- pi -p /tmp/issue-42-prompt.md" -``` - -**Notes:** -- `@{prompt}` is substituted with the actual temp file path -- Window name includes issue number and repo slug -- Worktree path is absolute -- `mise x --allow-env='*'` is prepended when mise is available - ---- - -### Test: composes correct tmux command for pi without mise (fallback to $SHELL -c) - -**Given:** -- `docs/agents/agent-cli.md` contains the pi fixture -- `command -v mise` fails (no mise on PATH) - -**When:** `implement-issue` composes the tmux launch command - -**Then:** the generated command string is: - -``` -tmux new-window -n "issue-42-ws-sjb-skills" -c /home/sjb/Projects/personal/ws-sjb-skills/ws-sjb-skills-issue-42 "$SHELL -c 'pi -p /tmp/issue-42-prompt.md'" -``` - -**Notes:** -- Falls back to `$SHELL -c` when mise is absent -- The agent command is wrapped inside `$SHELL -c '...'` - ---- - -### Test: composes correct tmux command for codex (stdin piping, no @{prompt}) - -**Given:** -- `docs/agents/agent-cli.md` contains the codex fixture (args: "") -- `command -v mise` succeeds - -**When:** `implement-issue` composes the tmux launch command - -**Then:** the generated command string is: - -``` -tmux new-window -n "issue-42-ws-sjb-skills" -c /home/sjb/Projects/personal/ws-sjb-skills/ws-sjb-skills-issue-42 "mise x --allow-env='*' -- sh -c 'cat /tmp/issue-42-prompt.md | codex'" -``` - -**Notes:** -- When args is empty, prompt is piped via `cat | ` -- The pipe syntax is always `cat | ` for stdin-based agents - ---- - -### Test: fails fast with clear message when binary not on PATH - -**Given:** -- `docs/agents/agent-cli.md` contains the missing binary fixture -- `command -v totally-not-on-path` fails - -**When:** `implement-issue` validates the binary at invocation time - -**Then:** it fails immediately with: - -``` -Agent 'totally-not-on-path' not found on PATH — rerun /setup-skills to reconfigure. -``` - -**Notes:** -- Validation happens before any tmux launch -- Error message directs user to re-run setup-skills - ---- - -### Test: reads selected agent from docs/agents/agent-cli.md - -**Given:** -- `docs/agents/agent-cli.md` exists and contains valid YAML with `selected`, `binary`, and `args` fields - -**When:** `implement-issue` reads the config at invocation time - -**Then:** it parses the three fields correctly and uses them for dispatch - -**Notes:** -- Does not use hardcoded dispatch table -- Does not run detection scripts -- Reads directly from the repo-side config file - ---- - -### Test: @{prompt} placeholder substitution - -**Given:** -- `docs/agents/agent-cli.md` contains opencode fixture (args: "run -f @{prompt}") -- `command -v mise` succeeds - -**When:** `implement-issue` composes the tmux launch command with prompt file at `/tmp/issue-99-prompt.md` - -**Then:** the generated command contains: - -``` -opencode run -f /tmp/issue-99-prompt.md -``` - -**Notes:** -- `@{prompt}` in args is replaced with the absolute path to the temp prompt file -- Works regardless of where `@{prompt}` appears in the args string \ No newline at end of file diff --git a/common/engineering/setup-skills/agents-seed.md b/common/engineering/setup-skills/agents-seed.md index 2be75fe..000dd2e 100644 --- a/common/engineering/setup-skills/agents-seed.md +++ b/common/engineering/setup-skills/agents-seed.md @@ -9,7 +9,7 @@ agents: - name: pi binary: pi args: "@{prompt}" - description: "My primary agent harness. Accepts prompt file via @{prompt}." + description: "My primary agent harness. Accepts prompt file via {prompt}." - name: opencode binary: opencode @@ -26,7 +26,7 @@ agents: - name: codex binary: codex args: "@{prompt}" - description: "OpenAI Codex. Accepts prompt file via @{prompt}." + description: "OpenAI Codex. Accepts prompt file via {prompt}." - name: claude binary: claude @@ -41,6 +41,6 @@ agents: |-------|-------------| | `name` | Display name used in menus and `--agent` flag | | `binary` | Command name expected on PATH | -| `args` | Static arguments appended after the binary. May include `@{prompt}` which is substituted at invocation time with the absolute path to the prompt file. Empty string means stdin piping (prompt is piped via `cat`). | +| `args` | Static arguments appended after the binary. May include `{prompt}` which is substituted at invocation time with the absolute path to the prompt file. Empty string means stdin piping (prompt is piped via `cat`). | | `description` | Short human-readable description for the setup menu | | `note` | Optional additional context | diff --git a/common/engineering/setup-skills/triage-labels.md b/common/engineering/setup-skills/triage-labels.md index 4e4a1f5..79daba8 100644 --- a/common/engineering/setup-skills/triage-labels.md +++ b/common/engineering/setup-skills/triage-labels.md @@ -1,6 +1,6 @@ # Triage Labels -The skills speak in terms of five canonical triage roles. This file maps those roles to the actual label strings used in this repo's issue tracker. +The skills speak in terms of seven canonical triage roles. This file maps those roles to the actual label strings used in this repo's issue tracker. | Label in skills | Label in our tracker | Meaning | | -------------------------- | -------------------- | ---------------------------------------- | @@ -12,6 +12,6 @@ The skills speak in terms of five canonical triage roles. This file maps those r | `in-progress` | `in-progress` | Being actively worked on by a human or agents | | `wontfix` | `wontfix` | Will not be actioned | -When a skill mentions a role (e.g. "apply the AFK-ready triage label"), use the corresponding label string from this table. +When a skill mentions a role (e.g. "apply the AFK-ready triage label"), use the corresponding label string from this table. Only one triage label should be active. Edit the right-hand column to match whatever vocabulary you actually use. diff --git a/docs/agents/agent-cli.md b/docs/agents/agent-cli.md index 1446fc8..01ccb11 100644 --- a/docs/agents/agent-cli.md +++ b/docs/agents/agent-cli.md @@ -1,6 +1,6 @@ # Agent CLI Configuration -The CLI agent used by `/implement-issue` for spawning child agents in isolated git worktrees. +The CLI agent used for spawning child agents in isolated git worktrees. ## Configuration @@ -16,7 +16,7 @@ args: "@{prompt}" |-------|-------------| | `selected` | Display name of the selected agent | | `binary` | Command name expected on PATH | -| `args` | Static arguments. `@{prompt}` is substituted with the prompt file path at invocation time. Empty means stdin piping via `cat`. | +| `args` | Static arguments. `{prompt}` is substituted with the prompt file path at invocation time. Empty means stdin piping via `cat`. | ## Changing the agent diff --git a/docs/agents/triage-labels.md b/docs/agents/triage-labels.md index 9b56521..ab9669a 100644 --- a/docs/agents/triage-labels.md +++ b/docs/agents/triage-labels.md @@ -1,6 +1,6 @@ # Triage Labels -The skills speak in terms of five canonical triage roles. This file maps those roles to the actual label strings used in this repo's issue tracker. +The skills speak in terms of seven canonical triage roles. This file maps those roles to the actual label strings used in this repo's issue tracker. | Label in skills | Label in our tracker | Meaning | | -------------------------- | -------------------- | ---------------------------------------- | @@ -12,4 +12,4 @@ The skills speak in terms of five canonical triage roles. This file maps those r | `in-progress` | `in-progress` | Being actively worked on by a human or agents | | `wontfix` | `wontfix` | Will not be actioned | -When a skill mentions a role (e.g. "apply the AFK-ready triage label"), use the corresponding label string from this table. +When a skill mentions a role (e.g. "apply the AFK-ready triage label"), use the corresponding label string from this table. Only one triage label should be active.