fix(handoff): quote heredoc to prevent git output execution

Git status output contains ## which was being interpreted as bash.
Split render() into quoted heredocs + echo statements.
This commit is contained in:
dan 2026-01-23 10:17:25 -08:00
parent 9efc9aaa9f
commit f2d7fd7451
4 changed files with 206 additions and 1 deletions

View file

@ -277,7 +277,7 @@
{"id":"skills-sx8u","title":"Build 'spec new' command","description":"CLI command to create new spec from template.\n\n## Usage\n```bash\nspec new \"feature name\"\nspec new \"feature name\" --template=minimal\n```\n\n## Behavior\n- Generate unique ID\n- Create file in .specs/active/\n- Pre-fill template sections\n- Open in editor (optional)\n\n## Implementation\n- Shell script or small tool\n- Template interpolation\n- ID generation (timestamp? random?)","status":"closed","priority":2,"issue_type":"task","owner":"dan@delpad","created_at":"2026-01-18T08:13:57.937067038-08:00","created_by":"dan","updated_at":"2026-01-18T08:25:53.383301191-08:00","closed_at":"2026-01-18T08:25:53.383301191-08:00","close_reason":"Simplified: structure in bead issues, not separate files","dependencies":[{"issue_id":"skills-sx8u","depends_on_id":"skills-oh8m","type":"blocks","created_at":"2026-01-18T08:14:32.51120206-08:00","created_by":"dan"},{"issue_id":"skills-sx8u","depends_on_id":"skills-ya44","type":"blocks","created_at":"2026-01-18T08:14:44.593664507-08:00","created_by":"dan"},{"issue_id":"skills-sx8u","depends_on_id":"skills-rqi3","type":"blocks","created_at":"2026-01-18T08:14:44.688938513-08:00","created_by":"dan"}]}
{"id":"skills-t9ub","title":"Clean up dead code and unused imports","description":"Quick cleanup pass:\n\n- skills-5ax: Remove unused strformat, strutils imports in db.nim\n- skills-kvdl: Remove unused globalChannel in heartbeat.nim\n- skills-ib9u: Remove unused times import in heartbeat.nim\n- skills-fdu: Verify BusJsonlPath, BlobsDir, WorkersDir usage, delete if unused\n- skills-ghlb: Remove unused 'by' parameter from approve()\n\nParent: skills-g2wa","status":"closed","priority":3,"issue_type":"task","created_at":"2026-01-10T20:18:50.017642793-08:00","created_by":"dan","updated_at":"2026-01-10T20:41:09.681717088-08:00","closed_at":"2026-01-10T20:41:09.681717088-08:00","close_reason":"Dead code cleanup complete"}
{"id":"skills-tdfm","title":"Add error handling to writeContext for file write failures","description":"[ERROR] MED context.nim:11 - writeFile can fail (permissions, disk full) with no handling. Wrap in try/except with context: 'Failed to write context to {path}: {error}'","status":"closed","priority":2,"issue_type":"bug","created_at":"2026-01-10T20:10:03.523837508-08:00","created_by":"dan","updated_at":"2026-01-10T20:37:04.75187149-08:00","closed_at":"2026-01-10T20:37:04.75187149-08:00","close_reason":"Implemented consistent error handling strategy"}
{"id":"skills-telx","title":"Add handoff skill (portable)","description":"Create a portable handoff skill that generates structured Markdown summaries for session transitions. Include SKILL.md, README.md, and scripts/handoff.sh with git context (status, branch, commits, diff stat).","status":"open","priority":2,"issue_type":"task","owner":"dan@delpad","created_at":"2026-01-20T22:26:09.526265946-08:00","created_by":"dan","updated_at":"2026-01-20T22:26:09.526265946-08:00"}
{"id":"skills-telx","title":"Add handoff skill (portable)","description":"Create a portable handoff skill that generates structured Markdown summaries for session transitions. Include SKILL.md, README.md, and scripts/handoff.sh with git context (status, branch, commits, diff stat).","status":"closed","priority":2,"issue_type":"task","owner":"dan@delpad","created_at":"2026-01-20T22:26:09.526265946-08:00","created_by":"dan","updated_at":"2026-01-23T10:17:21.131207714-08:00","closed_at":"2026-01-23T10:17:21.131207714-08:00","close_reason":"Skill complete: SKILL.md, README.md, handoff.sh script. Fixed heredoc quoting bug."}
{"id":"skills-thk","title":"Design: Hybrid hook + gate architecture","description":"Design enforcement that uses hooks where available, orchestrator gates elsewhere.\n\n## Hook-Capable Agents (Claude, Gemini)\n- Stop hook checks beads for review status\n- Mechanical enforcement - agent can't bypass\n\n## Non-Hook Agents (OpenCode, Codex) \n- Orchestrator pattern enforces gate\n- Orchestrator checks beads before declaring done\n- Worker can't bypass because doesn't control session\n\n## Shared Components\n- beads: persistent state (issues, review status)\n- jwz: transient state (session messages, async handoffs)\n- review-gate CLI: checks state, returns exit code\n\n## Deliverable\nArchitecture doc showing:\n1. Hook configuration for Claude/Gemini\n2. Orchestrator flow for OpenCode/Codex\n3. State schema in beads\n4. review-gate CLI design","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-09T19:01:24.270855877-08:00","created_by":"dan","updated_at":"2026-01-09T19:33:36.705975116-08:00","closed_at":"2026-01-09T19:33:36.705975116-08:00","close_reason":"Consolidated into skills-8sj"}
{"id":"skills-tta","title":"Design: Circuit breaker patterns","description":"Design circuit breakers to prevent agent infinite loops.\n\n## Patterns to Implement\n\n### Semantic Drift Detection\n- Embed last N agent thoughts\n- If \u003e95% similar, inject \"try different approach\"\n- Use cheap embedding model\n\n### Three-Strike Tool Rule \n- Track tool call signatures (tool + args + error)\n- 3 identical failures → force strategy shift\n- Implement in PostToolUse hook\n\n### Budget-Based Interrupts\n- Allocate token budget per sub-task\n- Pause if \u003e50% budget used with \u003c30% progress\n- Request plan refinement\n\n### Time-Based Breaker\n- Timeout per task type\n- Escalate to review if exceeded\n\n## Implementation Options\n- Hook-based (Claude/Gemini)\n- Wrapper-based (all agents)\n- Orchestrator-enforced (all agents)\n\n## Deliverable\n- Circuit breaker design doc\n- Prototype implementation for one pattern","status":"closed","priority":2,"issue_type":"task","created_at":"2026-01-09T19:01:44.536499408-08:00","created_by":"dan","updated_at":"2026-01-09T19:59:37.700476328-08:00","closed_at":"2026-01-09T19:59:37.700476328-08:00","close_reason":"Covered in architecture design doc (docs/design/cross-agent-enforcement-architecture.md)"}
{"id":"skills-ty7","title":"Define trace levels (audit vs debug)","description":"Two trace levels to manage noise vs utility:\n\n1. Audit trace (minimal, safe, always on):\n - skill id/ref, start/end\n - high-level checkpoints\n - artifact hashes/paths\n - exit status\n\n2. Debug trace (opt-in, verbose):\n - tool calls with args\n - stdout/stderr snippets\n - expanded inputs\n - timing details\n\nConsider OpenTelemetry span model as reference.\nGPT proposed this; Gemini focused on rotation/caps instead.","status":"closed","priority":3,"issue_type":"task","created_at":"2025-12-23T19:49:48.514684945-05:00","updated_at":"2025-12-29T13:55:35.838961236-05:00","closed_at":"2025-12-29T13:55:35.838961236-05:00","close_reason":"Parked with ADR-001: skills-molecules integration deferred. Current simpler approach (skills as standalone) works well. Revisit when complex orchestration needed."}

23
skills/handoff/README.md Normal file
View file

@ -0,0 +1,23 @@
# handoff
Generate a structured handoff summary for a new session or another agent.
## Usage
```bash
./scripts/handoff.sh --goal "Short goal description"
./scripts/handoff.sh --goal "Short goal description" --output /tmp/handoff.md
```
## Output
The script prints a Markdown summary including:
- Goal and next steps placeholders
- Repo location and branch
- Git status + diff summary
- Recent commits
## Requirements
- `git` installed
- Bash 4+

45
skills/handoff/SKILL.md Normal file
View file

@ -0,0 +1,45 @@
---
name: handoff
description: Create a structured handoff summary for continuing work in a new session. Use when you need to pause and resume later or transfer context to another agent.
---
# Handoff
Create a portable handoff summary that captures current state, context, and next steps for another agent or future session.
## When to Use
- "Create a handoff"
- "Summarize this for another agent"
- "I need to pause and resume later"
- "Write a context handoff"
## Process
1. Run the helper script to generate a structured summary.
2. Add or edit the **Goal**, **Open Questions**, and **Next Steps** sections.
3. Paste the output into the new session or share with another agent.
## Helper Scripts
### handoff.sh
**Usage**:
```bash
./scripts/handoff.sh --goal "Short goal description" --output /tmp/handoff.md
```
**Examples**:
```bash
./scripts/handoff.sh --goal "Implement worker RPC launcher"
./scripts/handoff.sh --goal "Audit web skills" --output /tmp/handoff.md
```
**Notes**:
- If `--output` is omitted, the handoff is printed to stdout.
- Requires a git repository for full context. If not in a git repo, only basic info is included.
## Requirements
- `git` in PATH
- Bash 4+ shell

137
skills/handoff/scripts/handoff.sh Executable file
View file

@ -0,0 +1,137 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'USAGE'
Usage: handoff.sh --goal "short goal" [--output /path/to/handoff.md]
Options:
-g, --goal Short goal description (required)
-o, --output Write output to file (optional; defaults to stdout)
-h, --help Show this help
USAGE
}
GOAL=""
OUTPUT=""
while [[ $# -gt 0 ]]; do
case "$1" in
-g|--goal)
if [[ $# -lt 2 || "$2" == -* ]]; then
echo "Error: --goal requires a value" >&2
usage
exit 1
fi
GOAL="$2"
shift 2
;;
-o|--output)
if [[ $# -lt 2 || "$2" == -* ]]; then
echo "Error: --output requires a path" >&2
usage
exit 1
fi
OUTPUT="$2"
shift 2
;;
-h|--help)
usage
exit 0
;;
*)
echo "Error: unknown argument '$1'" >&2
usage
exit 1
;;
esac
done
if [[ -z "$GOAL" ]]; then
echo "Error: --goal is required" >&2
usage
exit 1
fi
if ! command -v git >/dev/null; then
echo "Error: git is required" >&2
exit 1
fi
repo_root=""
branch=""
status=""
diff_stat=""
recent_commits=""
if git rev-parse --show-toplevel >/dev/null 2>&1; then
repo_root=$(git rev-parse --show-toplevel)
branch=$(git branch --show-current || true)
status=$(git status --short --branch)
diff_stat=$(git diff --stat)
recent_commits=$(git log --oneline -5)
fi
timestamp=$(date -Iseconds)
render() {
cat <<'HEADER'
# Handoff Summary
HEADER
echo "**Goal:** $GOAL"
echo ""
echo "**Timestamp:** $timestamp"
cat <<'MIDDLE'
## Current State
- [ ] Summary of what is already done
- [ ] Notable decisions made
## Next Steps
- [ ] Step 1
- [ ] Step 2
## Open Questions
- [ ] Question 1
## Repository Context
MIDDLE
echo "**Repo Root:** ${repo_root:-"(not in git repo)"}"
echo "**Branch:** ${branch:-"(unknown)"}"
cat <<'GITHEADER'
### Git Status
```
GITHEADER
echo "${status:-"(no git status available)"}"
cat <<'DIFFHEADER'
```
### Diff Summary
```
DIFFHEADER
echo "${diff_stat:-"(no changes)"}"
cat <<'COMMITSHEADER'
```
### Recent Commits
```
COMMITSHEADER
echo "${recent_commits:-"(no commits found)"}"
echo '```'
}
if [[ -n "$OUTPUT" ]]; then
render > "$OUTPUT"
echo "Wrote handoff to $OUTPUT"
else
render
fi