From f2d7fd74516b77cfe71269bdf0da7c3ea39e573c Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 23 Jan 2026 10:17:25 -0800 Subject: [PATCH] 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. --- .beads/issues.jsonl | 2 +- skills/handoff/README.md | 23 +++++ skills/handoff/SKILL.md | 45 ++++++++++ skills/handoff/scripts/handoff.sh | 137 ++++++++++++++++++++++++++++++ 4 files changed, 206 insertions(+), 1 deletion(-) create mode 100644 skills/handoff/README.md create mode 100644 skills/handoff/SKILL.md create mode 100755 skills/handoff/scripts/handoff.sh diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index 4ae431b..7856894 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -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."} diff --git a/skills/handoff/README.md b/skills/handoff/README.md new file mode 100644 index 0000000..578a756 --- /dev/null +++ b/skills/handoff/README.md @@ -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+ diff --git a/skills/handoff/SKILL.md b/skills/handoff/SKILL.md new file mode 100644 index 0000000..2aa4b41 --- /dev/null +++ b/skills/handoff/SKILL.md @@ -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 diff --git a/skills/handoff/scripts/handoff.sh b/skills/handoff/scripts/handoff.sh new file mode 100755 index 0000000..59daec2 --- /dev/null +++ b/skills/handoff/scripts/handoff.sh @@ -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