pm-gate · diff

git:20260729.4a3a4d0 to git:20260729.8dd5ad0

1 added, 0 removed. Audit A to A.

---
name: pm-gate
description: "Explicit gate approval for great-pm. Under gate-policy: explicit (great-pm's default), agents NEVER auto-close gates — only this command does. Subcommands: approve <id> | reject <id> <reason> | list | show <id>."
---
## Codex host binding
- Treat references to Claude slash workflows as the equivalently named Codex skill.
- Before delegating to any specialist, read the `great-pm-runtime` skill and the selected packaged role file.
- Treat "invoke", "assign", "delegate", "spawn", and source Agent-tool instructions as a required Codex `spawn_agent` call with that role and a bounded assignment.
+ - Set `task_name` to the exact canonical role name from the selected role file; never shorten, paraphrase, or invent specialist names.
- Store every returned agent identifier. Never call a wait tool until a spawn has returned an identifier, and wait only on identifiers returned by successful spawns.
- If `spawn_agent` is unavailable or a spawn fails, report BLOCKED; do not impersonate the specialist or wait on an empty agent set.
- Resolve bundled paths from the installed GreatPM plugin root.
- Ignore Claude-only model aliases, colors, turn limits, and tool allowlists.
- Preserve GreatPM human gates, governance, state, and reporting contracts.
You are the great-pm `$pm-gate` command. Under `gate-policy: explicit`
(great-pm's default), you are the **only** path that closes a great-pm
gate. Agents file gates as open Beads tasks and STOP — they wait for the
human to run `$pm-gate approve <id>`.
This enforces governance: human decides, agent never auto-advances.
A pipeline-enforcement gate command (
update); great-pm's default is more conservative — `explicit`, not `auto`.
## Setup
```bash
source .great-pm/env.sh 2>/dev/null || export PATH="/opt/homebrew/bin:$HOME/.local/bin:/usr/local/bin:$PATH"
ACTION="${1:-list}"
GATE_ID="${2:-}"
REASON="${3:-}"
# Read gate-policy for informational output. Behavior of $pm-gate does
# not depend on the policy — $pm-gate is the explicit-path tool.
GATE_POLICY=$(grep "^gate-policy:" .great-pm/PROJECT.md 2>/dev/null | awk '{print $2}' || echo "explicit")
```
---
## Action: `approve <id>` — close a gate, unblock the next stage
```bash
if [ -z "$GATE_ID" ]; then
echo "Usage: $pm-gate approve <id>"
echo ""
echo "Open great-pm gates:"
bd list --label gate --status open 2>/dev/null | head -10
exit 1
fi
# Verify the issue exists and is a gate
GATE_INFO=$(bd show "$GATE_ID" 2>/dev/null)
if [ -z "$GATE_INFO" ]; then
echo "Error: gate '$GATE_ID' not found."
echo "Run '$pm-gate list' to see open gates."
exit 1
fi
# Sanity check: title must contain 'gate:'
TITLE=$(echo "$GATE_INFO" | grep -i "^title:" | head -1)
if ! echo "$TITLE" | grep -qi "gate:"; then
echo "Error: '$GATE_ID' is not a gate (title: $TITLE)."
echo "Use 'bd close $GATE_ID' for regular tasks."
exit 1
fi
# Close the gate
bd close "$GATE_ID" --reason="Approved via $pm-gate approve by human" 2>/dev/null || {
echo "Error: failed to close gate $GATE_ID. Check 'bd show $GATE_ID' for status."
exit 1
}
# Log the approval
mkdir -p .great-pm/verdicts
TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)
LINE="$TS | pm-gate | APPROVED | id=$GATE_ID"
echo "$LINE" >> .great-pm/verdicts$pm-gate.log
echo "$LINE" >> ".great-pm/verdicts/$(date +%Y-%m-%d).log"
echo "✓ Gate $GATE_ID approved and closed."
echo ""
# Show what's newly unblocked
NEXT=$(bd close "$GATE_ID" --suggest-next 2>/dev/null | tail -10)
if [ -n "$NEXT" ]; then
echo "Newly unblocked:"
echo "$NEXT"
fi
```
Then tell the user which great-pm action should run next (derived from
the gate name):
- `gate:strategy` approved → next: `$pm-metrics <slug>` (force metrics
question to the front), then `$pm-spec <slug>` (Define stage)
- `gate:spec` approved → next: **hand-off to engineering** (engineering's
`/start` consumes the PRD and runs the build). great-pm resumes when
the build returns.
- `gate:launch` approved → next: launch happens; then `$pm-measure
<slug>` produces the read-out + next-cycle questions
---
## Action: `reject <id> <reason>` — block a gate, hold the pipeline
```bash
if [ -z "$GATE_ID" ] || [ -z "$REASON" ]; then
echo "Usage: $pm-gate reject <id> \"<reason>\""
exit 1
fi
bd update "$GATE_ID" --status=blocked --notes="Rejected by human: $REASON" 2>/dev/null || {
echo "Error: failed to reject gate $GATE_ID."
exit 1
}
mkdir -p .great-pm/verdicts
TS=$(date -u +%Y-%m-%dT%H:%M:%SZ)
LINE="$TS | pm-gate | REJECTED | id=$GATE_ID | reason=$REASON"
echo "$LINE" >> .great-pm/verdicts$pm-gate.log
echo "$LINE" >> ".great-pm/verdicts/$(date +%Y-%m-%d).log"
echo "✗ Gate $GATE_ID rejected: $REASON"
echo "Pipeline halted. Route to the relevant specialist to address the reason,"
echo "then promote a revised draft via $pm-promote, then run $pm-gate approve."
```
---
## Action: `list` (default) — show open gates
```bash
echo "Gate policy: $GATE_POLICY"
echo ""
echo "Open great-pm gates (run $pm-gate approve <id> to advance):"
echo ""
bd list --label gate --status open 2>/dev/null || {
echo "No bd available — falling back to .great-pm/tasks.md"
grep -i "gate:" .great-pm/tasks.md 2>/dev/null | head -10
}
```
---
## Action: `show <id>` — show one gate's full state
```bash
if [ -z "$GATE_ID" ]; then
echo "Usage: $pm-gate show <id>"
exit 1
fi
bd show "$GATE_ID" 2>/dev/null
echo ""
echo "Linked draft (if any):"
DRAFT_REF=$(bd show "$GATE_ID" 2>/dev/null | grep -E "drafts/" | head -1)
if [ -n "$DRAFT_REF" ]; then
DRAFT_PATH=$(echo "$DRAFT_REF" | grep -oE "\.great-pm/drafts/[^ ]+\.md")
[ -f "$DRAFT_PATH" ] && echo " $DRAFT_PATH (exists ✓)" || echo " $DRAFT_PATH (MISSING)"
fi
echo ""
echo "Linked REVIEW (pm-reviewer verdict):"
SLUG=$(echo "$DRAFT_PATH" | sed 's|.*/||; s|\.md$||')
ls .great-pm/reviews/REVIEW-*"$SLUG"*.md 2>/dev/null || echo " (none yet)"
```
---
## Notes
- **`$pm-gate` works regardless of `gate-policy:` value.** Under `auto`,
agents may also close gates as part of their own flow. Under `explicit`
(great-pm's default), `$pm-gate` is the **only** way to close a gate —
agents are forbidden from doing so.
- **Always reversible.** A gate closed by mistake can be reopened with
`bd reopen <id>`.
- **Use `$pm-inbox`** to see all open gates with full context. `$pm-gate
list` is the minimal view.
- **The 3 great-pm gates:** `gate:strategy`, `gate:spec`, `gate:launch`.
Each represents a human-decision checkpoint in the 6-stage loop.
## Reporting
- **DONE (approve)**: `DONE: $pm-gate approve <id> — gate closed. Next action: <auto-detected from gate type>.`
- **DONE (reject)**: `DONE: $pm-gate reject <id> — gate blocked with reason. Pipeline halted.`
- **DONE (list)**: `DONE: $pm-gate list — <N> open gates.`
- **BLOCKED**: gate ID not found / not a gate / Beads unavailable. tried + failed_because + need.