feat(implement-issue): make child agent dispatch agent-agnostic
- Add formal arg syntax: --agent, --base, --force - Add process-tree detection scripts (Linux / macOS) to auto-detect parent agent - Add dispatch table supporting pi, opencode, goose, codex, claude + unknown fallback - Write child prompt to temp file instead of inline escaping - Name tmux windows for discoverability - Add new pre-flight checks: tmux session, agent detection, binary on PATH
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: implement-issue
|
name: implement-issue
|
||||||
|
description: Dispatch a child agent in an isolated git worktree to implement a `ready-for-agent` issue end-to-end.
|
||||||
disable-model-invocation: true
|
disable-model-invocation: true
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -9,6 +10,17 @@ Dispatch a child agent in an isolated git worktree to implement a `ready-for-age
|
|||||||
|
|
||||||
The issue tracker conventions live in [`docs/agents/issue-tracker.md`](../../../docs/agents/issue-tracker.md) and the triage label vocabulary in [`docs/agents/triage-labels.md`](../../../docs/agents/triage-labels.md). Both should have been provided to you already.
|
The issue tracker conventions live in [`docs/agents/issue-tracker.md`](../../../docs/agents/issue-tracker.md) and the triage label vocabulary in [`docs/agents/triage-labels.md`](../../../docs/agents/triage-labels.md). Both should have been provided to you already.
|
||||||
|
|
||||||
|
## Invocation
|
||||||
|
|
||||||
|
```
|
||||||
|
/skill:implement-issue <N> [--agent <name>] [--base <branch>] [--force]
|
||||||
|
```
|
||||||
|
|
||||||
|
- `<N>` — required, the issue number
|
||||||
|
- `--agent <name>` — optional, one of `pi`, `opencode`, `goose`, `codex`, `claude`. If omitted, auto-detected from the process tree.
|
||||||
|
- `--base <branch>` — optional, target base branch (default: repo default branch).
|
||||||
|
- `--force` — optional, allow overwriting an existing worktree.
|
||||||
|
|
||||||
## Process
|
## Process
|
||||||
|
|
||||||
### 1. Pre-flight checks
|
### 1. Pre-flight checks
|
||||||
@@ -79,6 +91,37 @@ ls -d ../<repo-name>-issue-<N>
|
|||||||
|
|
||||||
If it exists, report and stop. Let the user override with `--force`.
|
If it exists, report and stop. Let the user override with `--force`.
|
||||||
|
|
||||||
|
#### 1h. Running inside a tmux session
|
||||||
|
|
||||||
|
Confirm `$TMUX` is set. If not, report "This skill requires a tmux session. Start tmux and rerun." and stop.
|
||||||
|
|
||||||
|
#### 1i. Detect the agent binary
|
||||||
|
|
||||||
|
If `--agent <name>` was provided in the invocation args, use that name directly. Otherwise, run the platform-appropriate detection script:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash ./detect-agent-linux.sh
|
||||||
|
# or on macOS:
|
||||||
|
bash ./detect-agent-macos.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
The script outputs the agent name on success (exit 0), or nothing on failure (exit 1).
|
||||||
|
|
||||||
|
If detection fails (no `--agent` flag and script returns nothing), report:
|
||||||
|
|
||||||
|
> Could not detect which agent is running. Rerun with `--agent <name>`.
|
||||||
|
> Supported agents: pi, opencode, goose, codex, claude.
|
||||||
|
|
||||||
|
Stop.
|
||||||
|
|
||||||
|
If detection succeeds, confirm the binary is on PATH:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
command -v <agent>
|
||||||
|
```
|
||||||
|
|
||||||
|
If the binary is not found, report "Agent binary '<agent>' not found on PATH." and stop.
|
||||||
|
|
||||||
### 2. Setup
|
### 2. Setup
|
||||||
|
|
||||||
#### 2a. Fetch latest base
|
#### 2a. Fetch latest base
|
||||||
@@ -99,7 +142,7 @@ tea issues edit <N> --add-labels "in-progress" --remove-labels "ready-for-agent"
|
|||||||
git worktree add -b <branch-name> ../<repo-name>-issue-<N> <base>
|
git worktree add -b <branch-name> ../<repo-name>-issue-<N> <base>
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Compose the child prompt
|
### 3. Compose and write the child prompt
|
||||||
|
|
||||||
Assemble a single prompt that the child agent will receive. Include:
|
Assemble a single prompt that the child agent will receive. Include:
|
||||||
|
|
||||||
@@ -120,15 +163,46 @@ Assemble a single prompt that the child agent will receive. Include:
|
|||||||
10. Print `DONE — issue #<N>`
|
10. Print `DONE — issue #<N>`
|
||||||
- **Failure instruction**: "If any step fails, report where you stopped and what remains for manual recovery. Print the exact commands needed."
|
- **Failure instruction**: "If any step fails, report where you stopped and what remains for manual recovery. Print the exact commands needed."
|
||||||
|
|
||||||
### 4. Launch the child
|
Write the full prompt to a temp file:
|
||||||
|
|
||||||
Open a new tmux window in the worktree directory and run `pi` with the composed prompt:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
tmux new-window -c <absolute-worktree-path> "pi --prompt '<escaped-prompt>'"
|
cat > /tmp/issue-<N>-prompt.md <<'PROMPT_EOF'
|
||||||
|
<full-composed-prompt>
|
||||||
|
PROMPT_EOF
|
||||||
```
|
```
|
||||||
|
|
||||||
The pane stays open after the child completes so the user can review the output.
|
### 4. Launch the child
|
||||||
|
|
||||||
|
Look up the full shell command from the dispatch table below, using the agent name detected in step 1i.
|
||||||
|
|
||||||
|
| Agent | Shell command |
|
||||||
|
|-------|--------------|
|
||||||
|
| `pi` | `pi -p @/tmp/issue-<N>-prompt.md` |
|
||||||
|
| `opencode` | `opencode run -f /tmp/issue-<N>-prompt.md` |
|
||||||
|
| `goose` | `goose run -i /tmp/issue-<N>-prompt.md` |
|
||||||
|
| `codex` | `cat /tmp/issue-<N>-prompt.md \| codex exec` |
|
||||||
|
| `claude` | `cat /tmp/issue-<N>-prompt.md \| claude -p` |
|
||||||
|
| *unknown* | `cat /tmp/issue-<N>-prompt.md \| <binary>` |
|
||||||
|
|
||||||
|
Substitute the actual temp file path and issue number, then launch in a new tmux window:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tmux new-window -n "issue-<N>-<repo>" -c <absolute-worktree-path> "<shell-command>"
|
||||||
|
```
|
||||||
|
|
||||||
|
For example, with pi:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tmux new-window -n "issue-42-myrepo" -c ../myrepo-issue-42 "pi -p @/tmp/issue-42-prompt.md"
|
||||||
|
```
|
||||||
|
|
||||||
|
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-<N>-prompt.md
|
||||||
|
```
|
||||||
|
|
||||||
### 5. Print summary
|
### 5. Print summary
|
||||||
|
|
||||||
@@ -137,7 +211,8 @@ After launching, print:
|
|||||||
- Worktree path
|
- Worktree path
|
||||||
- Branch name
|
- Branch name
|
||||||
- Base branch
|
- Base branch
|
||||||
- Tmux window (so the user can find it)
|
- Agent used
|
||||||
|
- Tmux window name (so the user can find it)
|
||||||
- Cleanup command: `git worktree remove <worktree-path> && git worktree prune`
|
- Cleanup command: `git worktree remove <worktree-path> && git worktree prune`
|
||||||
|
|
||||||
The parent's turn ends here. The user can dispatch another issue immediately.
|
The parent's turn ends here. The user can dispatch another issue immediately.
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Walk the process tree upward from $PPID to find a known agent binary.
|
||||||
|
# Outputs the agent name on stdout if found, exits 0.
|
||||||
|
# Outputs nothing and exits 1 if no known agent is found.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Dispatch table: binary names we recognize.
|
||||||
|
KNOWN_AGENTS="pi opencode goose codex claude"
|
||||||
|
|
||||||
|
pid=$PPID
|
||||||
|
|
||||||
|
while [ "$pid" -gt 1 ]; do
|
||||||
|
# Read command name and parent PID from /proc.
|
||||||
|
comm=$(cat /proc/$pid/comm 2>/dev/null) || { pid=1; continue; }
|
||||||
|
ppid=$(awk '{print $4}' /proc/$pid/stat 2>/dev/null) || ppid=1
|
||||||
|
|
||||||
|
# Direct match against known binaries.
|
||||||
|
for agent in $KNOWN_AGENTS; do
|
||||||
|
if [ "$comm" = "$agent" ]; then
|
||||||
|
echo "$agent"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# If the process is node or bun, inspect cmdline for agent script paths.
|
||||||
|
case "$comm" in
|
||||||
|
node|bun)
|
||||||
|
cmdline=$(tr '\0' ' ' < /proc/$pid/cmdline 2>/dev/null) || cmdline=""
|
||||||
|
for agent in $KNOWN_AGENTS; do
|
||||||
|
case "$cmdline" in
|
||||||
|
*"$agent"*)
|
||||||
|
echo "$agent"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
pid=$ppid
|
||||||
|
done
|
||||||
|
|
||||||
|
exit 1
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Walk the process tree upward from $PPID to find a known agent binary.
|
||||||
|
# Outputs the agent name on stdout if found, exits 0.
|
||||||
|
# Outputs nothing and exits 1 if no known agent is found.
|
||||||
|
#
|
||||||
|
# macOS version — uses ps(1) since /proc is not available.
|
||||||
|
# Requires bash 3.2+ (macOS ships bash 3.2).
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
KNOWN_AGENTS="pi opencode goose codex claude"
|
||||||
|
|
||||||
|
pid=$PPID
|
||||||
|
|
||||||
|
while [ "$pid" -gt 1 ]; do
|
||||||
|
# Get parent PID and command name.
|
||||||
|
ppid=$(ps -o ppid= -p "$pid" 2>/dev/null | tr -d ' ') || ppid=1
|
||||||
|
comm=$(ps -o comm= -p "$pid" 2>/dev/null) || { pid=$ppid; continue; }
|
||||||
|
# Strip leading path, keep only the basename.
|
||||||
|
comm=$(basename "$comm" 2>/dev/null || echo "$comm")
|
||||||
|
|
||||||
|
# Direct match against known binaries.
|
||||||
|
for agent in $KNOWN_AGENTS; do
|
||||||
|
if [ "$comm" = "$agent" ]; then
|
||||||
|
echo "$agent"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# If the process is node or bun, inspect full command line for agent names.
|
||||||
|
case "$comm" in
|
||||||
|
node|bun)
|
||||||
|
args=$(ps -o args= -p "$pid" 2>/dev/null) || args=""
|
||||||
|
for agent in $KNOWN_AGENTS; do
|
||||||
|
case "$args" in
|
||||||
|
*"$agent"*)
|
||||||
|
echo "$agent"
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
pid=$ppid
|
||||||
|
done
|
||||||
|
|
||||||
|
exit 1
|
||||||
Reference in New Issue
Block a user