<!-- swain-model-hint: sonnet, effort: low — default for task management; see per-section overrides below -- Execution Tracking <!-- session-check: SPEC-121 -- Before proceeding with any state-changing operation, check for an active session: If the JSON output has other than , inform the operator: "No active session — start one with ?" Proceed if they dismiss. Abstraction layer for agent execution tracking. Other skills (e.g., swain-design) express intent using abstract terms; this skill translates that intent into concrete CLI commands. Before first use: Read references/tk-cheatsheet.md for…

, content, re.MULTILINE)\n if m:\n header['title'] = m.group(1).strip()\n\n # Goal, Architecture, Tech Stack from **Key:** Value lines\n for key in ('Goal', 'Architecture', 'Tech Stack'):\n m = re.search(rf'^\\*\\*{key}:\\*\\*\\s*(.+)

<!-- swain-model-hint: sonnet, effort: low — default for task management; see per-section overrides below -- Execution Tracking <!-- session-check: SPEC-121 -- Before proceeding with any state-changing operation, check for an active session: If the JSON output has other than , inform the operator: "No active session — start one with ?" Proceed if they dismiss. Abstraction layer for agent execution tracking. Other skills (e.g., swain-design) express intent using abstract terms; this skill translates that intent into concrete CLI commands. Before first use: Read references/tk-cheatsheet.md for…

, content, re.MULTILINE)\n if m:\n header[key.lower().replace(' ', '_')] = m.group(1).strip()\n\n return header\n\n\ndef parse_tasks(content: str) -> list[dict]:\n \"\"\"Split content on ### Task N: boundaries, extract title and body.\"\"\"\n # Find all ### Task headings\n pattern = r'^### Task (\\d+):\\s*(.+)

<!-- swain-model-hint: sonnet, effort: low — default for task management; see per-section overrides below -- Execution Tracking <!-- session-check: SPEC-121 -- Before proceeding with any state-changing operation, check for an active session: If the JSON output has other than , inform the operator: "No active session — start one with ?" Proceed if they dismiss. Abstraction layer for agent execution tracking. Other skills (e.g., swain-design) express intent using abstract terms; this skill translates that intent into concrete CLI commands. Before first use: Read references/tk-cheatsheet.md for…

\n matches = list(re.finditer(pattern, content, re.MULTILINE))\n\n if not matches:\n return []\n\n tasks = []\n for i, match in enumerate(matches):\n task_num = int(match.group(1))\n title = match.group(2).strip()\n start = match.end()\n end = matches[i + 1].start() if i + 1 \u003c len(matches) else len(content)\n body = content[start:end].strip()\n\n # Extract file paths from **Files:** section\n files = []\n files_match = re.search(r'^\\*\\*Files:\\*\\*\\s*\\n((?:- .+\\n)+)', body, re.MULTILINE)\n if files_match:\n for line in files_match.group(1).strip().split('\\n'):\n line = line.strip().lstrip('- ')\n if line:\n files.append(line)\n\n tasks.append({\n 'number': task_num,\n 'title': title,\n 'body': body,\n 'files': files,\n })\n\n return tasks\n\n\ndef parse_plan(path: str) -> dict:\n \"\"\"Parse a superpowers plan file into structured data.\"\"\"\n with open(path) as f:\n content = f.read()\n\n header = parse_header(content)\n tasks = parse_tasks(content)\n\n if not tasks:\n print(f\"Error: no '### Task N:' headings found in {path}\", file=sys.stderr)\n sys.exit(1)\n\n return {'header': header, 'tasks': tasks, 'source': path}\n\n\ndef tk_create(args: list[str]) -> str:\n \"\"\"Run a tk create command and return the created ticket ID from stdout.\"\"\"\n cmd = ['tk'] + args\n result = subprocess.run(cmd, capture_output=True, text=True)\n if result.returncode != 0:\n print(f\"tk error: {result.stderr.strip()}\", file=sys.stderr)\n sys.exit(1)\n # tk create prints \"Created \u003cid>\" — extract the ID\n output = result.stdout.strip()\n m = re.search(r'Created\\s+(\\S+)', output)\n if m:\n return m.group(1)\n # Fallback: return the last word on the first line\n return output.split()[-1] if output else ''\n\n\ndef tk_dep(child_id: str, parent_id: str):\n \"\"\"Add a dependency: child depends on parent.\"\"\"\n subprocess.run(\n ['tk', 'dep', child_id, parent_id],\n capture_output=True, text=True,\n )\n\n\ndef register_in_tk(plan: dict, origin_ref: str, extra_tags=None):\n \"\"\"Create tk epic + child tasks from parsed plan.\"\"\"\n header = plan['header']\n tasks = plan['tasks']\n title = header.get('title', os.path.basename(plan['source']))\n\n # Create epic\n epic_args = [\n 'create', title,\n '-t', 'epic',\n '--external-ref', origin_ref,\n '-d', f\"Ingested from {plan['source']}. \"\n f\"Goal: {header.get('goal', 'N/A')}. \"\n f\"Architecture: {header.get('architecture', 'N/A')}.\",\n ]\n epic_id = tk_create(epic_args)\n print(f\"Created epic: {epic_id} — {title}\")\n\n # Create child tasks\n tags = [f'spec:{origin_ref}']\n if extra_tags:\n tags.extend(extra_tags)\n tag_str = ','.join(tags)\n\n task_ids = []\n for task in tasks:\n # Truncate body for description (keep reasonable)\n desc = task['body']\n if len(desc) > 4000:\n desc = desc[:3997] + '...'\n\n task_args = [\n 'create', f\"Task {task['number']}: {task['title']}\",\n '-t', 'task',\n '--parent', epic_id,\n '-p', '1',\n '-d', desc,\n '--tags', tag_str,\n ]\n task_id = tk_create(task_args)\n task_ids.append(task_id)\n print(f\" Created task: {task_id} — {task['title']}\")\n\n # Wire sequential dependencies\n for i in range(1, len(task_ids)):\n tk_dep(task_ids[i], task_ids[i - 1])\n print(f\" Dep: {task_ids[i]} depends on {task_ids[i - 1]}\")\n\n return {'epic_id': epic_id, 'task_ids': task_ids}\n\n\ndef main():\n parser = argparse.ArgumentParser(description='Ingest a superpowers plan file into tk')\n parser.add_argument('plan_file', help='Path to superpowers plan markdown file')\n parser.add_argument('origin_ref', help='Origin artifact ID (e.g., SPEC-003)')\n parser.add_argument('--dry-run', action='store_true',\n help='Parse only — output JSON without creating tk tasks')\n parser.add_argument('--tags', default='',\n help='Additional comma-separated tags for all tasks')\n args = parser.parse_args()\n\n if not os.path.isfile(args.plan_file):\n print(f\"Error: file not found: {args.plan_file}\", file=sys.stderr)\n sys.exit(1)\n\n plan = parse_plan(args.plan_file)\n\n if args.dry_run:\n json.dump(plan, sys.stdout, indent=2)\n print()\n return\n\n extra_tags = [t.strip() for t in args.tags.split(',') if t.strip()] if args.tags else None\n result = register_in_tk(plan, args.origin_ref, extra_tags)\n print(f\"\\nIngestion complete: {len(result['task_ids'])} tasks under epic {result['epic_id']}\")\n\n\nif __name__ == '__main__':\n main()\n","content_type":"text/x-python; charset=utf-8","language":"python","size":6272,"content_sha256":"60aa0225fb69f3f6388679a0b1a473564f0ec5a856c2230e235b0b954032ae87"},{"filename":"scripts/swain-worktree-overlap.sh","content":"#!/usr/bin/env bash\n# swain-worktree-overlap.sh — SPEC-195: Check for existing worktrees matching a spec/context\n#\n# Usage:\n# swain-worktree-overlap.sh SPEC-194 # check for worktrees matching SPEC-194\n# swain-worktree-overlap.sh \"fast greeting\" # check for worktrees matching text\n#\n# Output (JSON):\n# { \"found\": true, \"worktrees\": [{ \"path\": \"...\", \"branch\": \"...\" }] }\n# { \"found\": false, \"worktrees\": [] }\n\nset +e\n\nSEARCH_TERM=\"${1:-}\"\nif [[ -z \"$SEARCH_TERM\" ]]; then\n echo '{\"found\":false,\"worktrees\":[],\"error\":\"no search term provided\"}'\n exit 1\nfi\n\n# Normalize search term for case-insensitive matching\nSEARCH_LOWER=$(echo \"$SEARCH_TERM\" | tr '[:upper:]' '[:lower:]' | tr ' ' '-')\n\nMATCHES=()\n\n# Parse git worktree list --porcelain\nwhile IFS= read -r line; do\n case \"$line\" in\n \"worktree \"*)\n current_path=\"${line#worktree }\"\n current_branch=\"\"\n ;;\n \"branch \"*)\n current_branch=\"${line#branch refs/heads/}\"\n # Check if branch name contains the search term\n branch_lower=$(echo \"$current_branch\" | tr '[:upper:]' '[:lower:]')\n if echo \"$branch_lower\" | grep -q \"$SEARCH_LOWER\"; then\n MATCHES+=(\"{\\\"path\\\":\\\"$current_path\\\",\\\"branch\\\":\\\"$current_branch\\\"}\")\n fi\n ;;\n esac\ndone \u003c \u003c(git worktree list --porcelain 2>/dev/null)\n\n# Build JSON output\nif [[ ${#MATCHES[@]} -eq 0 ]]; then\n echo '{\"found\":false,\"worktrees\":[]}'\nelse\n echo -n '{\"found\":true,\"worktrees\":['\n for ((i=0; i\u003c${#MATCHES[@]}; i++)); do\n [[ $i -gt 0 ]] && echo -n \",\"\n echo -n \"${MATCHES[$i]}\"\n done\n echo ']}'\nfi\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":1578,"content_sha256":"30207fbcca6259a55e2f164f4f8b4b8e8479c8484d95e95990965dc2778052b1"},{"filename":"scripts/test-worktree-overlap.sh","content":"#!/usr/bin/env bash\n# test-worktree-overlap.sh — SPEC-195: Test worktree overlap detection\n#\n# Usage: bash test-worktree-overlap.sh [--verbose]\n\nset -euo pipefail\n\nVERBOSE=0\n[[ \"${1:-}\" == \"--verbose\" ]] && VERBOSE=1\n\nSCRIPT_DIR=\"$(cd \"$(dirname \"${BASH_SOURCE[0]}\")\" && pwd)\"\nOVERLAP_SCRIPT=\"$SCRIPT_DIR/swain-worktree-overlap.sh\"\n\nPASS=0\nFAIL=0\nTOTAL=0\n\nassert_eq() {\n local test_name=\"$1\" expected=\"$2\" actual=\"$3\"\n TOTAL=$((TOTAL + 1))\n if [[ \"$expected\" == \"$actual\" ]]; then\n PASS=$((PASS + 1))\n [[ $VERBOSE -eq 1 ]] && echo \" PASS: $test_name\"\n else\n FAIL=$((FAIL + 1))\n echo \" FAIL: $test_name (expected: '$expected', got: '$actual')\"\n fi\n}\n\necho \"=== SPEC-195: Worktree overlap detection tests ===\"\n\n# Test 1: Script exists\nTOTAL=$((TOTAL + 1))\nif [[ -x \"$OVERLAP_SCRIPT\" ]]; then\n PASS=$((PASS + 1))\n [[ $VERBOSE -eq 1 ]] && echo \" PASS: overlap script exists and is executable\"\nelse\n FAIL=$((FAIL + 1))\n echo \" FAIL: overlap script not found at $OVERLAP_SCRIPT\"\n echo \"Results: $PASS/$TOTAL passed, $FAIL failed\"\n exit 1\nfi\n\n# Test 2: No search term → error\necho \"Test 2: No search term returns error\"\nresult=$(bash \"$OVERLAP_SCRIPT\" 2>/dev/null || true)\nfound=$(echo \"$result\" | jq -r '.found' 2>/dev/null || echo \"\")\nassert_eq \"no search term returns found=false\" \"false\" \"$found\"\n\n# Test 3: Search for current worktree (should find this one)\necho \"Test 3: Search for current worktree branch\"\ncurrent_branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null)\nresult=$(bash \"$OVERLAP_SCRIPT\" \"$current_branch\" 2>/dev/null)\nfound=$(echo \"$result\" | jq -r '.found' 2>/dev/null)\nassert_eq \"current branch found\" \"true\" \"$found\"\n\n# Test 4: Search for nonexistent spec\necho \"Test 4: Search for nonexistent spec\"\nresult=$(bash \"$OVERLAP_SCRIPT\" \"SPEC-99999\" 2>/dev/null)\nfound=$(echo \"$result\" | jq -r '.found' 2>/dev/null)\nassert_eq \"nonexistent spec not found\" \"false\" \"$found\"\n\n# Test 5: Case-insensitive search\necho \"Test 5: Case-insensitive search\"\nresult_upper=$(bash \"$OVERLAP_SCRIPT\" \"$(echo \"$current_branch\" | tr '[:lower:]' '[:upper:]')\" 2>/dev/null)\nfound_upper=$(echo \"$result_upper\" | jq -r '.found' 2>/dev/null)\nassert_eq \"case-insensitive search works\" \"true\" \"$found_upper\"\n\n# Test 6: Performance (\u003c100ms)\necho \"Test 6: Performance (\u003c500ms)\"\nstart_ms=$(python3 -c \"import time; print(int(time.time()*1000))\")\nbash \"$OVERLAP_SCRIPT\" \"SPEC-195\" >/dev/null 2>&1\nend_ms=$(python3 -c \"import time; print(int(time.time()*1000))\")\nelapsed=$((end_ms - start_ms))\nTOTAL=$((TOTAL + 1))\nif [[ $elapsed -lt 500 ]]; then\n PASS=$((PASS + 1))\n [[ $VERBOSE -eq 1 ]] && echo \" PASS: performance (${elapsed}ms)\"\nelse\n FAIL=$((FAIL + 1))\n echo \" FAIL: performance (${elapsed}ms, expected \u003c100ms)\"\nfi\n\n# Test 7: JSON output is valid\necho \"Test 7: Valid JSON output\"\nresult=$(bash \"$OVERLAP_SCRIPT\" \"test\" 2>/dev/null)\nTOTAL=$((TOTAL + 1))\nif echo \"$result\" | jq . >/dev/null 2>&1; then\n PASS=$((PASS + 1))\n [[ $VERBOSE -eq 1 ]] && echo \" PASS: valid JSON output\"\nelse\n FAIL=$((FAIL + 1))\n echo \" FAIL: invalid JSON output: $result\"\nfi\n\necho \"\"\necho \"Results: $PASS/$TOTAL passed, $FAIL failed\"\n[[ $FAIL -eq 0 ]] && exit 0 || exit 1\n","content_type":"application/x-sh; charset=utf-8","language":"bash","size":3174,"content_sha256":"198f2ba1da59b011e7c166c8cc22da33d73b26096dc816f51efa49da44ca05c4"}],"content_json":{"type":"doc","content":[{"type":"paragraph","content":[{"text":"\u003c!-- swain-model-hint: sonnet, effort: low — default for task management; see per-section overrides below -->","type":"text"}]},{"type":"heading","attrs":{"level":1},"content":[{"text":"Execution Tracking","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003c!-- session-check: SPEC-121 --> Before proceeding with any state-changing operation, check for an active session:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"REPO_ROOT=\"$(git rev-parse --show-toplevel 2>/dev/null || pwd)\"\nbash \"$REPO_ROOT/.agents/bin/swain-session-check.sh\" 2>/dev/null","type":"text"}]},{"type":"paragraph","content":[{"text":"If the JSON output has ","type":"text"},{"text":"\"status\"","type":"text","marks":[{"type":"code_inline"}]},{"text":" other than ","type":"text"},{"text":"\"active\"","type":"text","marks":[{"type":"code_inline"}]},{"text":", inform the operator: \"No active session — start one with ","type":"text"},{"text":"/swain-init","type":"text","marks":[{"type":"code_inline"}]},{"text":"?\" Proceed if they dismiss.","type":"text"}]},{"type":"paragraph","content":[{"text":"Abstraction layer for agent execution tracking. Other skills (e.g., swain-design) express intent using abstract terms; this skill translates that intent into concrete CLI commands.","type":"text"}]},{"type":"paragraph","content":[{"text":"Before first use:","type":"text","marks":[{"type":"strong"}]},{"text":" Read ","type":"text"},{"text":"references/tk-cheatsheet.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/tk-cheatsheet.md","title":null}}]},{"text":" for complete command syntax, flags, ID formats, and anti-patterns.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Artifact handoff protocol","type":"text"}]},{"type":"paragraph","content":[{"text":"This skill receives handoffs from swain-design based on a four-tier tracking model:","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Tier","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Artifacts","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"This skill's role","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Implementation","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"SPEC","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Create a tracked implementation plan and task breakdown before any code is written","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Coordination","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"EPIC, VISION, JOURNEY","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Do not track directly — swain-design decomposes these into children first, then hands off the children","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Research","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"SPIKE","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Create a tracked plan when the research is complex enough to benefit from task breakdown","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Reference","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ADR, PERSONA, RUNBOOK","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"No tracking expected","type":"text"}]}]}]}]},{"type":"paragraph","content":[{"text":"If invoked directly on a coordination-tier artifact (EPIC, VISION, JOURNEY) without prior decomposition, defer to swain-design to create child SPECs first, then create plans for those children.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Term mapping","type":"text"}]},{"type":"paragraph","content":[{"text":"Other skills use these abstract terms. This skill maps them to the current backend (","type":"text"},{"text":"tk","type":"text","marks":[{"type":"code_inline"}]},{"text":"):","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Abstract term","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Meaning","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"tk command","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"implementation plan","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Top-level container grouping all tasks for a spec artifact","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"tk create \"Title\" -t epic --external-ref \u003cSPEC-ID>","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"task","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"An individual unit of work within a plan","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"tk create \"Title\" -t task --parent \u003cepic-id>","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"origin ref","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Immutable link from a plan to the spec that seeded it","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--external-ref \u003cID>","type":"text","marks":[{"type":"code_inline"}]},{"text":" flag on epic creation","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"spec tag","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Mutable tag linking a task to every spec it affects","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"--tags spec:\u003cID>","type":"text","marks":[{"type":"code_inline"}]},{"text":" on create","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"dependency","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Ordering constraint between tasks","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"tk dep \u003cchild> \u003cparent>","type":"text","marks":[{"type":"code_inline"}]},{"text":" (child depends on parent)","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"ready work","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Unblocked tasks available for pickup","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"tk ready","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"claim","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Atomically take ownership of a task","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"tk claim \u003cid>","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"complete","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Mark a task as done","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"tk add-note \u003cid> \"reason\"","type":"text","marks":[{"type":"code_inline"}]},{"text":" then ","type":"text"},{"text":"tk close \u003cid>","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"abandon","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Close a task that will not be completed","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"tk add-note \u003cid> \"Abandoned: \u003cwhy>\"","type":"text","marks":[{"type":"code_inline"}]},{"text":" then ","type":"text"},{"text":"tk close \u003cid>","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"escalate","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Abandon + invoke swain-design to update upstream artifacts","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Abandon, then invoke swain-design skill","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Configuration and bootstrap","type":"text"}]},{"type":"paragraph","content":[{"text":"Config stored in ","type":"text"},{"text":".agents/execution-tracking.vars.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" (created on first run). Read ","type":"text"},{"text":"references/configuration.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/configuration.md","title":null}}]},{"text":" for first-run setup questions, config keys, and the 6-step bootstrap workflow.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Statuses","type":"text"}]},{"type":"paragraph","content":[{"text":"tk accepts exactly three status values: ","type":"text"},{"text":"open","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"in_progress","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"closed","type":"text","marks":[{"type":"code_inline"}]},{"text":". Use the ","type":"text"},{"text":"status","type":"text","marks":[{"type":"code_inline"}]},{"text":" command to set arbitrary statuses, but the dependency graph (","type":"text"},{"text":"ready","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"blocked","type":"text","marks":[{"type":"code_inline"}]},{"text":") only evaluates these three.","type":"text"}]},{"type":"paragraph","content":[{"text":"To express abandonment, use ","type":"text"},{"text":"tk add-note \u003cid> \"Abandoned: ...\"","type":"text","marks":[{"type":"code_inline"}]},{"text":" then ","type":"text"},{"text":"tk close \u003cid>","type":"text","marks":[{"type":"code_inline"}]},{"text":" — see ","type":"text"},{"text":"Escalation","type":"text","marks":[{"type":"link","attrs":{"href":"#escalation","title":null}}]},{"text":".","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Ticket lifecycle (ADR-015)","type":"text"}]},{"type":"paragraph","content":[{"text":"Tickets are ","type":"text"},{"text":"ephemeral execution scaffolding","type":"text","marks":[{"type":"strong"}]},{"text":" — they exist to help agents track and resume work during SPEC implementation. Once the parent SPEC transitions to a terminal state (Complete, Abandoned), its tickets may be discarded. Tickets are not committed to trunk, not used as retro evidence, and should not block worktree cleanup. The session log (","type":"text"},{"text":".agents/session.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" JSONL) is the archival record of what happened; tickets are the live dashboard of what's in progress.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Operating rules","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Always include ","type":"text","marks":[{"type":"strong"}]},{"text":"--description","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" (or ","type":"text"},{"text":"-d","type":"text","marks":[{"type":"code_inline"}]},{"text":") when creating issues — a title alone loses the \"why\" behind a task. Future agents (or your future self) picking up this work need enough context to act without re-researching.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Create/update tasks at the start of work, after each major milestone, and before final response — this keeps the tracker useful as a live dashboard rather than a post-hoc record.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Keep task titles short and action-oriented — they appear in ","type":"text"},{"text":"tk ready","type":"text","marks":[{"type":"code_inline"}]},{"text":" output, tree views, and notifications where space is limited.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Store handoff notes using ","type":"text"},{"text":"tk add-note \u003cid> \"context\"","type":"text","marks":[{"type":"code_inline"}]},{"text":" rather than ephemeral chat context — chat history is lost between sessions, but task notes persist and are visible to any agent or observer.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Include references to related artifact IDs in tags (e.g., ","type":"text"},{"text":"spec:SPEC-003","type":"text","marks":[{"type":"code_inline"}]},{"text":") — this enables querying all work touching a given spec.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Prefix abandonment reasons with ","type":"text","marks":[{"type":"strong"}]},{"text":"Abandoned:","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" when closing incomplete tasks — this convention makes abandoned work findable so nothing silently disappears.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use ","type":"text","marks":[{"type":"strong"}]},{"text":"ticket-query","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" for structured output","type":"text","marks":[{"type":"strong"}]},{"text":" — when you need JSON for programmatic use, pipe through ","type":"text"},{"text":"ticket-query","type":"text","marks":[{"type":"code_inline"}]},{"text":" (available in the vendored ","type":"text"},{"text":"bin/","type":"text","marks":[{"type":"code_inline"}]},{"text":" directory) instead of parsing human-readable output. Example: ","type":"text"},{"text":"ticket-query '.status == \"open\"'","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"paragraph","content":[{"text":"\u003c!-- swain-model-hint: opus, effort: high — plan creation and code implementation require deep reasoning -->","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"TDD enforcement","type":"text"}]},{"type":"paragraph","content":[{"text":"Strict RED-GREEN-REFACTOR with anti-rationalization safeguards and completion verification. Read ","type":"text"},{"text":"references/tdd-enforcement.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/tdd-enforcement.md","title":null}}]},{"text":" for the anti-rationalization table, task ordering rules, and evidence requirements.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Spec lineage tagging","type":"text"}]},{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"--external-ref SPEC-NNN","type":"text","marks":[{"type":"code_inline"}]},{"text":" on plan epics (immutable origin) and ","type":"text"},{"text":"--tags spec:SPEC-NNN","type":"text","marks":[{"type":"code_inline"}]},{"text":" on child tasks (mutable). Query: ","type":"text"},{"text":"ticket-query '.tags and (.tags | contains(\"spec:SPEC-003\"))'","type":"text","marks":[{"type":"code_inline"}]},{"text":". Cross-plan links: ","type":"text"},{"text":"tk link \u003ctask-a> \u003ctask-b>","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Escalation","type":"text"}]},{"type":"paragraph","content":[{"text":"When work cannot proceed as designed, abandon tasks and escalate to swain-design. Read ","type":"text"},{"text":"references/escalation.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/escalation.md","title":null}}]},{"text":" for the triage table, abandonment commands, escalation workflow, and cross-spec handling.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"\"What's next?\" flow","type":"text"}]},{"type":"paragraph","content":[{"text":"Run ","type":"text"},{"text":"tk ready","type":"text","marks":[{"type":"code_inline"}]},{"text":" for unblocked tasks and ","type":"text"},{"text":"ticket-query '.status == \"in_progress\"'","type":"text","marks":[{"type":"code_inline"}]},{"text":" for in-flight work. If ","type":"text"},{"text":".tickets/","type":"text","marks":[{"type":"code_inline"}]},{"text":" is empty or missing, defer to ","type":"text"},{"text":"bash \"$(git rev-parse --show-toplevel 2>/dev/null || pwd)/.agents/bin/chart.sh\" ready","type":"text","marks":[{"type":"code_inline"}]},{"text":" for artifact-level guidance.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Context on claim","type":"text"}]},{"type":"paragraph","content":[{"text":"When claiming a task tagged with ","type":"text"},{"text":"spec:\u003cID>","type":"text","marks":[{"type":"code_inline"}]},{"text":", show the Vision ancestry breadcrumb to provide strategic context. Run ","type":"text"},{"text":"bash \"$(git rev-parse --show-toplevel 2>/dev/null || pwd)/.agents/bin/chart.sh\" scope \u003cSPEC-ID> 2>/dev/null | head -5","type":"text","marks":[{"type":"code_inline"}]},{"text":" to display the parent chain. This tells the agent/operator how the current task connects to project strategy.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Artifact/tk reconciliation","type":"text"}]},{"type":"paragraph","content":[{"text":"When specwatch detects mismatches (","type":"text"},{"text":"TK_SYNC","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"TK_ORPHAN","type":"text","marks":[{"type":"code_inline"}]},{"text":" in ","type":"text"},{"text":".agents/specwatch.log","type":"text","marks":[{"type":"code_inline"}]},{"text":"), read ","type":"text"},{"text":"references/reconciliation.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/reconciliation.md","title":null}}]},{"text":" for the mismatch types, resolution commands, and reconciliation workflow.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Drift resolution (SPEC-307)","type":"text"}]},{"type":"paragraph","content":[{"text":"On ticket create, edit, or close — if the ticket has a ","type":"text"},{"text":"spec:","type":"text","marks":[{"type":"code_inline"}]},{"text":" tag — run drift resolution against the tagged SPEC. Read both the ticket and the SPEC. If the ticket's scope drifts from the SPEC's acceptance criteria or problem statement, apply a fix: either re-align the child (edit the ticket) or update the parent (edit the SPEC).","type":"text"}]},{"type":"paragraph","content":[{"text":"Fix direction uses ","type":"text"},{"text":"signals and content judgment","type":"text","marks":[{"type":"strong"}]},{"text":": count prior drift decisions against the parent (more means parent is likely stale), plus assess which direction produces the better outcome. Apply the fix, then present the result for operator review: accept, modify, or revert. All outcomes are recorded as drift decisions via ","type":"text"},{"text":"swain-session-state.sh record-decision","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Session bookmark","type":"text"}]},{"type":"paragraph","content":[{"text":"After state-changing operations, update the bookmark: ","type":"text"},{"text":"bash \"$(git rev-parse --show-toplevel 2>/dev/null || pwd)/.agents/bin/swain-bookmark.sh\" \"\u003caction> \u003ctask-description>\"","type":"text","marks":[{"type":"code_inline"}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Superpowers skill chaining","type":"text"}]},{"type":"paragraph","content":[{"text":"When superpowers is installed, swain-do invokes these skills at specific points. Skipping them or inlining the work undermines the guarantees they provide — TDD catches regressions before they compound, and verification prevents false completion claims that waste downstream effort:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Before writing code for any task:","type":"text","marks":[{"type":"strong"}]},{"text":" Invoke the ","type":"text"},{"text":"test-driven-development","type":"text","marks":[{"type":"code_inline"}]},{"text":" skill. Write a failing test first (RED), then make it pass (GREEN), then refactor. This applies to every task, not just the first one.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"When dispatching parallel work:","type":"text","marks":[{"type":"strong"}]},{"text":" Invoke ","type":"text"},{"text":"subagent-driven-development","type":"text","marks":[{"type":"code_inline"}]},{"text":" (if subagents are available and tasks are independent) or ","type":"text"},{"text":"executing-plans","type":"text","marks":[{"type":"code_inline"}]},{"text":" (if serial). Read ","type":"text"},{"text":"references/execution-strategy.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/execution-strategy.md","title":null}}]},{"text":" for the decision tree.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Before claiming any task or plan is complete:","type":"text","marks":[{"type":"strong"}]},{"text":" Invoke ","type":"text"},{"text":"verification-before-completion","type":"text","marks":[{"type":"code_inline"}]},{"text":". Run the verification commands, read the output, and only then assert success. No completion claims without fresh evidence.","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Detection:","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":"ls .agents/skills/test-driven-development/SKILL.md .claude/skills/test-driven-development/SKILL.md 2>/dev/null","type":"text","marks":[{"type":"code_inline"}]},{"text":" — if at least one path exists, superpowers is available. Cache the result for the session.","type":"text"}]},{"type":"paragraph","content":[{"text":"When superpowers is NOT installed, swain-do uses its built-in TDD enforcement (see ","type":"text"},{"text":"references/tdd-enforcement.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/tdd-enforcement.md","title":null}}]},{"text":") and serial execution.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Plan ingestion (superpowers integration)","type":"text"}]},{"type":"paragraph","content":[{"text":"When a superpowers plan file exists, use the ingestion script (","type":"text"},{"text":"scripts/ingest-plan.py","type":"text","marks":[{"type":"code_inline"}]},{"text":") instead of manual task decomposition. Read ","type":"text"},{"text":"references/plan-ingestion.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/plan-ingestion.md","title":null}}]},{"text":" for usage, format requirements, and when NOT to use it.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Execution strategy","type":"text"}]},{"type":"paragraph","content":[{"text":"Selects serial vs. subagent-driven execution based on superpowers availability and task complexity. Read ","type":"text"},{"text":"references/execution-strategy.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/execution-strategy.md","title":null}}]},{"text":" for the decision tree, detection commands, and worktree-artifact mapping.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Pre-plan implementation detection","type":"text"}]},{"type":"paragraph","content":[{"text":"Before creating a plan for a SPEC, scan for evidence that it's already implemented. This avoids re-implementing work that exists on unmerged branches or was done in a prior session. Run these checks in parallel — they're independent signals that feed a single decision.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Signal scan","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Signal","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Check","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Why it matters","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Unmerged branches","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"git for-each-ref --format='%(refname:short) %(upstream:trackshort)' refs/heads/ | grep -i \"\u003cSPEC-ID>\"","type":"text","marks":[{"type":"code_inline"}]},{"text":" then verify not merged: ","type":"text"},{"text":"git merge-base --is-ancestor \u003cbranch> HEAD","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Worktree branches from prior sessions are the strongest signal — they contain commits that never reached trunk. Discovering this mid-plan-creation is disruptive; catching it here is cheap.","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Git history","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"git log --oneline --all | grep -i \"\u003cSPEC-ID>\"","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Commits referencing the spec ID indicate implementation happened somewhere in the repo's history.","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Deliverable files","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Read the spec to identify described outputs (scripts, modules, configs). Check whether they exist on HEAD via ","type":"text"},{"text":"ls","type":"text","marks":[{"type":"code_inline"}]},{"text":" or Glob.","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Files on disk without matching commits may indicate partial or uncommitted work.","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Tests pass","type":"text","marks":[{"type":"strong"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Re-run the spec's tests now and read the output. Prior results are not evidence — only fresh execution counts.","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"This is the critical gate. Agents are prone to rationalizing that \"tests passed before\" without re-running. The reason this matters: code changes between sessions can silently break previously-passing tests.","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Decision","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"2+ signals","type":"text","marks":[{"type":"strong"}]},{"text":" → take the retroactive-close path (below)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"1 signal","type":"text","marks":[{"type":"strong"}]},{"text":" → proceed with normal plan creation; note the signal in the first task's description","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"0 signals","type":"text","marks":[{"type":"strong"}]},{"text":" → proceed normally","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Retroactive-close path","type":"text"}]},{"type":"paragraph","content":[{"text":"When evidence confirms prior implementation, skip full task decomposition:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Create a single tracking task: ","type":"text"},{"text":"tk create \"Retroactive verification: \u003cSPEC-ID>\" -t task --external-ref \u003cSPEC-ID> -d \"Verify prior implementation before closing SPEC.\"","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Claim it: ","type":"text"},{"text":"tk claim \u003cid>","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Run ","type":"text"},{"text":"verification-before-completion","type":"text","marks":[{"type":"code_inline"}]},{"text":" (if superpowers installed) or re-run the spec's tests manually.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If verification passes: add a note with the evidence, close the task, then invoke swain-design to transition the spec to Complete.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If verification fails: fall back to normal plan creation — the prior implementation was incomplete.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Worktree isolation preamble","type":"text"}]},{"type":"paragraph","content":[{"text":"All mutating work tracked by swain-do happens in a worktree — regardless of whether it touches source code, artifacts, skill files, or data. This prevents half-finished changes from polluting trunk and avoids collisions between parallel agents. Before any operation that will produce file changes (plan creation, task claim, code writing, artifact editing, skill file changes, spec transitions, execution handoff), run this detection:","type":"text"}]},{"type":"paragraph","content":[{"text":"Read-only operations skip this preamble entirely","type":"text","marks":[{"type":"strong"}]},{"text":" — proceed in the current context. The explicit read-only allowlist:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"tk ready","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"tk show","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"tk status","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"tk list","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"ticket-query","type":"text","marks":[{"type":"code_inline"}]},{"text":" (structured queries)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Plan inspection (reading plan files without modifying them)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Status checks and task queries","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 0 — Commit any dirty files","type":"text"}]},{"type":"paragraph","content":[{"text":"This step ALWAYS runs","type":"text","marks":[{"type":"strong"}]},{"text":", regardless of whether you're in a worktree or on trunk. Uncommitted changes from earlier in the session (newly created artifacts, edited specs, etc.) must be on HEAD before proceeding — worktrees check out from HEAD, and even on trunk, dirty files risk being overwritten or lost.","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"REPO_ROOT=\"$(git rev-parse --show-toplevel 2>/dev/null || pwd)\"\nUNTRACKED=$(git -C \"$REPO_ROOT\" ls-files --others --exclude-standard 2>/dev/null)\nMODIFIED=$(git -C \"$REPO_ROOT\" diff --name-only 2>/dev/null)\nif [ -n \"$UNTRACKED\" ] || [ -n \"$MODIFIED\" ]; then\n [ -n \"$UNTRACKED\" ] && echo \"$UNTRACKED\" | xargs -d '\\n' git -C \"$REPO_ROOT\" add --\n [ -n \"$MODIFIED\" ] && echo \"$MODIFIED\" | xargs -d '\\n' git -C \"$REPO_ROOT\" add --\n git -C \"$REPO_ROOT\" commit -m \"chore: stage dirty tree before worktree creation\" || {\n echo \"ERROR: pre-commit step failed — aborting worktree creation\"\n exit 1\n }\nfi","type":"text"}]},{"type":"paragraph","content":[{"text":"If the commit fails (e.g., pre-commit hook rejection), surface the error and stop. Do not proceed to worktree detection or any other step.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 1 — Detect worktree context","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# SPEC-250: Check env var first (set by bin/swain), then git plumbing\nif [ -n \"${SWAIN_WORKTREE_PATH:-}\" ]; then\n IN_WORKTREE=yes\nelse\n GIT_COMMON=$(git rev-parse --git-common-dir 2>/dev/null)\n GIT_DIR=$(git rev-parse --git-dir 2>/dev/null)\n [ \"$GIT_COMMON\" != \"$GIT_DIR\" ] && IN_WORKTREE=yes || IN_WORKTREE=no\nfi","type":"text"}]},{"type":"paragraph","content":[{"text":"If ","type":"text","marks":[{"type":"strong"}]},{"text":"IN_WORKTREE=yes","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":":","type":"text","marks":[{"type":"strong"}]},{"text":" already isolated. Proceed to step 5 (worktree bookmark).","type":"text"}]},{"type":"paragraph","content":[{"text":"If ","type":"text","marks":[{"type":"strong"}]},{"text":"IN_WORKTREE=no","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" (main worktree) and the operation will produce file changes:","type":"text"}]},{"type":"ordered_list","attrs":{"order":2,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Check for existing worktrees","type":"text","marks":[{"type":"strong"}]},{"text":" matching the target spec/work:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"REPO_ROOT=\"$(git rev-parse --show-toplevel 2>/dev/null || pwd)\"\nbash \"$REPO_ROOT/.agents/bin/swain-worktree-overlap.sh\" \"\u003cSPEC-ID>\"","type":"text"}]},{"type":"paragraph","content":[{"text":"If the JSON output has ","type":"text"},{"text":"\"found\": true","type":"text","marks":[{"type":"code_inline"}]},{"text":", offer to reuse: \"Worktree for ","type":"text"},{"text":"\u003cSPEC-ID>","type":"text","marks":[{"type":"code_inline"}]},{"text":" already exists at ","type":"text"},{"text":"\u003cpath>","type":"text","marks":[{"type":"code_inline"}]},{"text":". Reuse it?\" If yes, inform the operator to restart the session with ","type":"text"},{"text":"swain --resume \u003cname>","type":"text","marks":[{"type":"code_inline"}]},{"text":". If no, inform the operator to start a new session with the purpose text.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Worktree creation is handled by bin/swain pre-launch","type":"text","marks":[{"type":"strong"}]},{"text":" (SPEC-245, EPIC-056). Most runtimes (Gemini CLI, Codex, Copilot, Crush) cannot change their working directory mid-session — only Claude Code can via ","type":"text"},{"text":"EnterWorktree","type":"text","marks":[{"type":"code_inline"}]},{"text":", and that is a runtime-specific crutch, not a universal pattern. The correct universal approach is pre-launch isolation via ","type":"text"},{"text":"bin/swain","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"paragraph","content":[{"text":"If ","type":"text"},{"text":"SWAIN_WORKTREE_PATH","type":"text","marks":[{"type":"code_inline"}]},{"text":" is set, the agent is already in a managed worktree. If ","type":"text"},{"text":"IN_WORKTREE=yes","type":"text","marks":[{"type":"code_inline"}]},{"text":" via git plumbing, the agent is in a worktree (possibly entered manually). In both cases, proceed with work.","type":"text"}]},{"type":"paragraph","content":[{"text":"If ","type":"text"},{"text":"IN_WORKTREE=no","type":"text","marks":[{"type":"code_inline"}]},{"text":" and the operation requires isolation, inform the operator: \"Not in a worktree. Start a new session with ","type":"text"},{"text":"swain \\\"\u003cpurpose>\\\"","type":"text","marks":[{"type":"code_inline"}]},{"text":" to get worktree isolation.\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"After entering (if worktree was just created by bin/swain), re-run tab naming to reflect the new branch:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"bash \"$REPO_ROOT/.agents/bin/swain-tab-name.sh\" --path \"$(pwd)\" --auto","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Record the worktree bookmark","type":"text","marks":[{"type":"strong"}]},{"text":" (SPEC-235). After entering a worktree, call swain-bookmark.sh to register it in session.json.","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"WT_PATH=\"$(pwd)\"\nWT_BRANCH=\"$(git branch --show-current 2>/dev/null || echo 'unknown')\"\nbash \"$REPO_ROOT/.agents/bin/swain-bookmark.sh\" worktree add \"$WT_PATH\" \"$WT_BRANCH\"","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Operator override:","type":"text","marks":[{"type":"strong"}]},{"text":" If the operator explicitly says \"work on trunk\" or \"don't isolate,\" respect the override and proceed on trunk. Log a warning: \"Proceeding on trunk at operator request — changes will land directly on the development branch.\"","type":"text"}]},{"type":"paragraph","content":[{"text":"Note (SPEC-195):","type":"text","marks":[{"type":"strong"}]},{"text":" swain-init does not create worktrees at startup — worktree creation is deferred to this preamble, which runs when swain-do dispatches actual work. This ensures worktree names reflect the work context and allows overlap detection.","type":"text"}]},{"type":"paragraph","content":[{"text":"When all tasks in the plan complete, or when the operator requests, run the plan completion handoff (see below) before exiting the worktree.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Plan completion and handoff","type":"text"}]},{"type":"paragraph","content":[{"text":"When all tasks under a plan epic are closed (or the operator declares the work done), execute this chain ","type":"text"},{"text":"before","type":"text","marks":[{"type":"strong"}]},{"text":" exiting the worktree. This ensures retros, SPEC transitions, and EPIC cascades fire consistently.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 1 — Detect plan completion","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"REPO_ROOT=\"$(git rev-parse --show-toplevel 2>/dev/null || pwd)\"\nexport PATH=\"$REPO_ROOT/.agents/bin:$PATH\"\n# Check if any tasks under the plan epic are still open\nOPEN_COUNT=$(ticket-query \".parent == \\\"\u003cepic-id>\\\" and .status != \\\"closed\\\"\" 2>/dev/null | wc -l | tr -d ' ')","type":"text"}]},{"type":"paragraph","content":[{"text":"If ","type":"text"},{"text":"OPEN_COUNT > 0","type":"text","marks":[{"type":"code_inline"}]},{"text":", the plan is not complete — continue working or ask the operator. If ","type":"text"},{"text":"OPEN_COUNT == 0","type":"text","marks":[{"type":"code_inline"}]},{"text":", proceed.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 2 — Run completion pipeline (SPEC-257)","type":"text"}]},{"type":"paragraph","content":[{"text":"After detecting plan completion, run the quality gate pipeline before transitioning the SPEC. This ensures BDD tests, smoke tests, and retro all fire automatically.","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"2a — Create completion state file","type":"text"}]},{"type":"paragraph","content":[{"text":"Identify the SPEC ID from the plan epic's ","type":"text"},{"text":"--external-ref","type":"text","marks":[{"type":"code_inline"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"REPO_ROOT=\"$(git rev-parse --show-toplevel 2>/dev/null || pwd)\"\nSPEC_ID=$(tk show \u003cepic-id> 2>/dev/null | grep -i 'external_ref' | awk '{print $NF}')\nif [ -z \"$SPEC_ID\" ]; then\n echo \"WARNING: No SPEC linked to plan epic — skipping completion pipeline.\"\nfi","type":"text"}]},{"type":"paragraph","content":[{"text":"If ","type":"text"},{"text":"SPEC_ID","type":"text","marks":[{"type":"code_inline"}]},{"text":" is empty, skip Step 2 entirely and proceed to Step 3. Log the warning.","type":"text"}]},{"type":"paragraph","content":[{"text":"Create the state file per DESIGN-018:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"mkdir -p \"$REPO_ROOT/.agents\"\njq -n --arg spec \"$SPEC_ID\" --arg branch \"$(git branch --show-current)\" \\\n '{spec_id: $spec, branch: $branch, pipeline_started: (now | todate), steps: {bdd_tests: {status: \"pending\", timestamp: null, detail: null}, smoke_test: {status: \"pending\", timestamp: null, detail: null}, retro: {status: \"pending\", timestamp: null, detail: null}}}' \\\n > \"$REPO_ROOT/.agents/completion-state.json.tmp\" \\\n && mv \"$REPO_ROOT/.agents/completion-state.json.tmp\" \"$REPO_ROOT/.agents/completion-state.json\"","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"2b — Run BDD tests","type":"text"}]},{"type":"paragraph","content":[{"text":"Check if ","type":"text"},{"text":"swain-test.sh","type":"text","marks":[{"type":"code_inline"}]},{"text":" is available:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"REPO_ROOT=\"$(git rev-parse --show-toplevel 2>/dev/null || pwd)\"\nSWAIN_TEST=\"$REPO_ROOT/.agents/bin/swain-test.sh\"","type":"text"}]},{"type":"paragraph","content":[{"text":"If ","type":"text","marks":[{"type":"strong"}]},{"text":"swain-test.sh","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" exists:","type":"text","marks":[{"type":"strong"}]},{"text":" Run it once, capture output and exit code:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"BDD_OUTPUT=$(bash \"$SWAIN_TEST\" --artifacts \"$SPEC_ID\" 2>&1)\nBDD_EXIT=$?","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If exit code is 0 → update state to ","type":"text"},{"text":"passed","type":"text","marks":[{"type":"code_inline"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"BDD_DETAIL=$(echo \"$BDD_OUTPUT\" | head -5 | tr '\\n' ' ')\njq --arg status \"passed\" --arg detail \"$BDD_DETAIL\" \\\n '.steps.bdd_tests.status = $status | .steps.bdd_tests.timestamp = (now | todate) | .steps.bdd_tests.detail = $detail' \\\n \"$REPO_ROOT/.agents/completion-state.json\" > \"$REPO_ROOT/.agents/completion-state.json.tmp\" \\\n && mv \"$REPO_ROOT/.agents/completion-state.json.tmp\" \"$REPO_ROOT/.agents/completion-state.json\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If exit code is non-zero → update state to ","type":"text"},{"text":"failed","type":"text","marks":[{"type":"code_inline"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"BDD_DETAIL=$(echo \"$BDD_OUTPUT\" | tail -10 | tr '\\n' ' ')\njq --arg status \"failed\" --arg detail \"$BDD_DETAIL\" \\\n '.steps.bdd_tests.status = $status | .steps.bdd_tests.timestamp = (now | todate) | .steps.bdd_tests.detail = $detail' \\\n \"$REPO_ROOT/.agents/completion-state.json\" > \"$REPO_ROOT/.agents/completion-state.json.tmp\" \\\n && mv \"$REPO_ROOT/.agents/completion-state.json.tmp\" \"$REPO_ROOT/.agents/completion-state.json\"","type":"text"}]},{"type":"paragraph","content":[{"text":"Stop the pipeline. Report the failure to the operator: \"BDD tests failed. Details: {detail}. Say ","type":"text"},{"text":"retry","type":"text","marks":[{"type":"strong"}]},{"text":" to re-run, or ","type":"text"},{"text":"skip BDD","type":"text","marks":[{"type":"strong"}]},{"text":" to continue without.\"","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"If ","type":"text","marks":[{"type":"strong"}]},{"text":"swain-test.sh","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" does not exist:","type":"text","marks":[{"type":"strong"}]},{"text":" Warn and mark skipped:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"jq --arg status \"skipped\" --arg detail \"swain-test.sh not available\" \\\n '.steps.bdd_tests.status = $status | .steps.bdd_tests.timestamp = (now | todate) | .steps.bdd_tests.detail = $detail' \\\n \"$REPO_ROOT/.agents/completion-state.json\" > \"$REPO_ROOT/.agents/completion-state.json.tmp\" \\\n && mv \"$REPO_ROOT/.agents/completion-state.json.tmp\" \"$REPO_ROOT/.agents/completion-state.json\"","type":"text"}]},{"type":"paragraph","content":[{"text":"Display: \"swain-test not available — skipping BDD gate.\"","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"2c — Run smoke tests","type":"text"}]},{"type":"paragraph","content":[{"text":"Only proceed if ","type":"text"},{"text":"bdd_tests","type":"text","marks":[{"type":"code_inline"}]},{"text":" is ","type":"text"},{"text":"passed","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"skipped","type":"text","marks":[{"type":"code_inline"}]},{"text":". If ","type":"text"},{"text":"bdd_tests","type":"text","marks":[{"type":"code_inline"}]},{"text":" is ","type":"text"},{"text":"failed","type":"text","marks":[{"type":"code_inline"}]},{"text":", the pipeline is paused — do not run smoke.","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"BDD_STATUS=$(jq -r '.steps.bdd_tests.status' \"$REPO_ROOT/.agents/completion-state.json\")","type":"text"}]},{"type":"paragraph","content":[{"text":"If ","type":"text"},{"text":"BDD_STATUS","type":"text","marks":[{"type":"code_inline"}]},{"text":" is ","type":"text"},{"text":"passed","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"skipped","type":"text","marks":[{"type":"code_inline"}]},{"text":":","type":"text"}]},{"type":"paragraph","content":[{"text":"If ","type":"text","marks":[{"type":"strong"}]},{"text":"swain-test.sh","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" exists:","type":"text","marks":[{"type":"strong"}]},{"text":" The smoke test output from ","type":"text"},{"text":"swain-test.sh","type":"text","marks":[{"type":"code_inline"}]},{"text":" includes a ","type":"text"},{"text":"## SMOKE","type":"text","marks":[{"type":"code_inline"}]},{"text":" section with manual verification steps. Extract and present these to the operator:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"SMOKE_SECTION=$(bash \"$SWAIN_TEST\" --artifacts \"$SPEC_ID\" 2>&1 | sed -n '/^## SMOKE/,/^## /p' | head -20)","type":"text"}]},{"type":"paragraph","content":[{"text":"Present the smoke instructions and ask for confirmation:","type":"text"}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"text":"Smoke test instructions: {smoke section content}","type":"text"}]},{"type":"paragraph","content":[{"text":"Did the smoke test pass? (yes / no / skip)","type":"text"}]}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"yes","type":"text","marks":[{"type":"strong"}]},{"text":" → update ","type":"text"},{"text":"smoke_test","type":"text","marks":[{"type":"code_inline"}]},{"text":" to ","type":"text"},{"text":"passed","type":"text","marks":[{"type":"code_inline"}]},{"text":" with detail \"operator confirmed\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"no","type":"text","marks":[{"type":"strong"}]},{"text":" → update ","type":"text"},{"text":"smoke_test","type":"text","marks":[{"type":"code_inline"}]},{"text":" to ","type":"text"},{"text":"failed","type":"text","marks":[{"type":"code_inline"}]},{"text":" with detail from operator. Stop pipeline: \"Smoke test failed. Say ","type":"text"},{"text":"retry","type":"text","marks":[{"type":"strong"}]},{"text":" to re-check, or ","type":"text"},{"text":"skip smoke","type":"text","marks":[{"type":"strong"}]},{"text":" to continue.\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"skip","type":"text","marks":[{"type":"strong"}]},{"text":" → update ","type":"text"},{"text":"smoke_test","type":"text","marks":[{"type":"code_inline"}]},{"text":" to ","type":"text"},{"text":"skipped","type":"text","marks":[{"type":"code_inline"}]},{"text":" with detail \"operator chose to skip\"","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Use the same jq update pattern from 2b to write state.","type":"text"}]},{"type":"paragraph","content":[{"text":"If ","type":"text","marks":[{"type":"strong"}]},{"text":"swain-test.sh","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":" does not exist:","type":"text","marks":[{"type":"strong"}]},{"text":" Mark skipped with detail \"swain-test.sh not available\", same as BDD fallback.","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"2d — Run retrospective","type":"text"}]},{"type":"paragraph","content":[{"text":"Only proceed if both ","type":"text"},{"text":"bdd_tests","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"smoke_test","type":"text","marks":[{"type":"code_inline"}]},{"text":" are ","type":"text"},{"text":"passed","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"skipped","type":"text","marks":[{"type":"code_inline"}]},{"text":". Retro ","type":"text"},{"text":"cannot be skipped","type":"text","marks":[{"type":"strong"}]},{"text":" — if the operator says \"skip retro\", refuse: \"Retro always runs. It captures learning even from imperfect work.\"","type":"text"}]},{"type":"paragraph","content":[{"text":"Invoke the swain-retro skill using the agent's Skill tool (this is a tool invocation, not a bash command):","type":"text"}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"text":"Use the ","type":"text"},{"text":"Skill","type":"text","marks":[{"type":"strong"}]},{"text":" tool: invoke ","type":"text"},{"text":"swain-retro","type":"text","marks":[{"type":"code_inline"}]},{"text":" with args: ","type":"text"},{"text":"\"SPEC completion — run retro for \u003cSPEC-ID> before phase transition.\"","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"paragraph","content":[{"text":"After swain-retro completes, update the state:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"jq --arg status \"passed\" --arg detail \"retro captured\" \\\n '.steps.retro.status = $status | .steps.retro.timestamp = (now | todate) | .steps.retro.detail = $detail' \\\n \"$REPO_ROOT/.agents/completion-state.json\" > \"$REPO_ROOT/.agents/completion-state.json.tmp\" \\\n && mv \"$REPO_ROOT/.agents/completion-state.json.tmp\" \"$REPO_ROOT/.agents/completion-state.json\"","type":"text"}]},{"type":"paragraph","content":[{"text":"If swain-retro fails (skill invocation error), update state to ","type":"text"},{"text":"failed","type":"text","marks":[{"type":"code_inline"}]},{"text":" and report. The operator can say ","type":"text"},{"text":"retry","type":"text","marks":[{"type":"strong"}]},{"text":" to re-run.","type":"text"}]},{"type":"heading","attrs":{"level":4},"content":[{"text":"2e — Skip and resume handling","type":"text"}]},{"type":"paragraph","content":[{"text":"Skip handling:","type":"text","marks":[{"type":"strong"}]},{"text":" At any point during the pipeline, the operator can say:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"skip BDD\" → set ","type":"text"},{"text":"bdd_tests","type":"text","marks":[{"type":"code_inline"}]},{"text":" to ","type":"text"},{"text":"skipped","type":"text","marks":[{"type":"code_inline"}]},{"text":" with detail \"operator requested skip\", continue to 2c","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"skip smoke\" → set ","type":"text"},{"text":"smoke_test","type":"text","marks":[{"type":"code_inline"}]},{"text":" to ","type":"text"},{"text":"skipped","type":"text","marks":[{"type":"code_inline"}]},{"text":" with detail \"operator requested skip\", continue to 2d","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"\"skip retro\" → ","type":"text"},{"text":"refuse","type":"text","marks":[{"type":"strong"}]},{"text":". Retro always runs. Say: \"Retro captures learning even from imperfect work — it cannot be skipped.\"","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Resume handling:","type":"text","marks":[{"type":"strong"}]},{"text":" If a step failed and the operator says \"retry\" or \"continue\":","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Read ","type":"text"},{"text":".agents/completion-state.json","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Find the first step with status ","type":"text"},{"text":"pending","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"failed","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Resume the pipeline from that step — do not re-run steps that already ","type":"text"},{"text":"passed","type":"text","marks":[{"type":"code_inline"}]},{"text":" or were ","type":"text"},{"text":"skipped","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"paragraph","content":[{"text":"Pipeline gate:","type":"text","marks":[{"type":"strong"}]},{"text":" After all three steps, verify completion:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"PENDING=$(jq -r '.steps | to_entries[] | select(.value.status == \"pending\" or .value.status == \"failed\") | .key' \"$REPO_ROOT/.agents/completion-state.json\")","type":"text"}]},{"type":"paragraph","content":[{"text":"If ","type":"text"},{"text":"PENDING","type":"text","marks":[{"type":"code_inline"}]},{"text":" is empty (all steps ","type":"text"},{"text":"passed","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"skipped","type":"text","marks":[{"type":"code_inline"}]},{"text":"), proceed to Step 3 (SPEC transition). If not, the pipeline is blocked — report which steps remain.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 3 — Invoke swain-design for SPEC transition","type":"text"}]},{"type":"paragraph","content":[{"text":"Pipeline gate (SPEC-257):","type":"text","marks":[{"type":"strong"}]},{"text":" Only proceed to SPEC transition if the completion pipeline passed. Check: ","type":"text"},{"text":"jq -r '.steps | to_entries[] | select(.value.status == \"pending\" or .value.status == \"failed\") | .key' \"$REPO_ROOT/.agents/completion-state.json\"","type":"text","marks":[{"type":"code_inline"}]},{"text":". If any steps are ","type":"text"},{"text":"pending","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"failed","type":"text","marks":[{"type":"code_inline"}]},{"text":", do not transition — return to Step 2 to resolve.","type":"text"}]},{"type":"paragraph","content":[{"text":"Identify the SPEC linked to the plan epic (via ","type":"text"},{"text":"--external-ref","type":"text","marks":[{"type":"code_inline"}]},{"text":"):","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"tk show \u003cepic-id> 2>/dev/null # external_ref field contains the SPEC ID","type":"text"}]},{"type":"paragraph","content":[{"text":"Invoke ","type":"text"},{"text":"swain-design","type":"text","marks":[{"type":"strong"}]},{"text":" to transition the SPEC forward. The target phase depends on the spec's current state and whether verification is complete:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If all acceptance criteria have evidence → transition to ","type":"text"},{"text":"Complete","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If acceptance criteria need manual verification → transition to ","type":"text"},{"text":"Needs Manual Test","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If implementation is done but untested → transition to ","type":"text"},{"text":"In Progress","type":"text","marks":[{"type":"code_inline"}]},{"text":" (if not already)","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"swain-design handles the downstream chain automatically:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Checks whether the parent EPIC should also transition (all child SPECs complete → EPIC Complete)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"If the EPIC reaches a terminal state → invokes ","type":"text"},{"text":"swain-retro","type":"text","marks":[{"type":"strong"}]},{"text":" for the EPIC-level retrospective (the SPEC-level retro already ran in Step 2d)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 4 — Offer merge and cleanup","type":"text"}]},{"type":"paragraph","content":[{"text":"After the SPEC transition completes, offer to merge and clean up:","type":"text"}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"text":"All tasks closed. SPEC-NNN transitioned to {phase}. Merge this branch into {base-branch} and clean up the worktree?","type":"text"}]}]},{"type":"paragraph","content":[{"text":"If the operator accepts:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Ensure all changes are committed","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Run ","type":"text"},{"text":"/swain-sync","type":"text","marks":[{"type":"code_inline"}]},{"text":" to merge and push (marks lockfile ","type":"text"},{"text":"ready_for_cleanup","type":"text","marks":[{"type":"code_inline"}]},{"text":")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Worktree cleanup is handled by bin/swain after the runtime exits (SPEC-245)","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"If the operator declines, the branch is preserved. bin/swain will show it in the menu next launch.","type":"text"}]},{"type":"paragraph","content":[{"text":"Note (ADR-015):","type":"text","marks":[{"type":"strong"}]},{"text":" ","type":"text"},{"text":".tickets/","type":"text","marks":[{"type":"code_inline"}]},{"text":" files in the worktree are ephemeral scaffolding and should not block cleanup. Tickets have no archival value after SPEC completion.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Skipping the chain","type":"text"}]},{"type":"paragraph","content":[{"text":"The operator can say \"just exit\" or \"skip the handoff\" to bypass Steps 2–4 and go directly to ","type":"text"},{"text":"ExitWorktree","type":"text","marks":[{"type":"code_inline"}]},{"text":". Log a note on the plan epic: ","type":"text"},{"text":"tk add-note \u003cepic-id> \"Exited without completion handoff\"","type":"text","marks":[{"type":"code_inline"}]},{"text":". The worktree remains for the next session.","type":"text"}]},{"type":"paragraph","content":[{"text":"Note:","type":"text","marks":[{"type":"strong"}]},{"text":" Skipping the chain means the completion pipeline did not run. If ","type":"text"},{"text":".agents/completion-state.json","type":"text","marks":[{"type":"code_inline"}]},{"text":" was already created (Step 2a ran), any ","type":"text"},{"text":"pending","type":"text","marks":[{"type":"code_inline"}]},{"text":" steps remain pending. swain-teardown will detect this and invoke the missing steps before sync.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Bookmark management (ADR-023)","type":"text"}]},{"type":"paragraph","content":[{"text":"Bookmarks track what the operator is working on. They persist across sessions so the next session can pick up where this one left off.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Set bookmark","type":"text"}]},{"type":"paragraph","content":[{"text":"When the operator says \"bookmark this\", \"remember where I am\", or after state-changing operations:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"REPO_ROOT=\"$(git rev-parse --show-toplevel 2>/dev/null || pwd)\"\nbash \"$REPO_ROOT/.agents/bin/swain-bookmark.sh\" \"\u003ccontext note>\"","type":"text"}]},{"type":"paragraph","content":[{"text":"Infer the note from conversation context or the operator's explicit text. Do not prompt for a note if the context is clear.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Worktree bookmarks","type":"text"}]},{"type":"paragraph","content":[{"text":"When entering a worktree (already handled in the worktree isolation preamble, Step 5), the worktree is registered:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"bash \"$REPO_ROOT/.agents/bin/swain-bookmark.sh\" worktree add \"$WT_PATH\" \"$WT_BRANCH\"","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Clear bookmark","type":"text"}]},{"type":"paragraph","content":[{"text":"When the operator says \"clear bookmark\" or \"fresh start\":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"bash \"$REPO_ROOT/.agents/bin/swain-bookmark.sh\" --clear","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Decision recording (ADR-023)","type":"text"}]},{"type":"paragraph","content":[{"text":"When the operator or agent makes a significant decision (approves a spec, chooses an approach, sets direction), record it:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"REPO_ROOT=\"$(git rev-parse --show-toplevel 2>/dev/null || pwd)\"\nbash \"$REPO_ROOT/.agents/bin/swain-session-state.sh\" record-decision --note \"Approved SPEC-119 implementation approach\"","type":"text"}]},{"type":"paragraph","content":[{"text":"Decisions are tracked against the session's decision budget. When the budget is reached, inform the operator and suggest running ","type":"text"},{"text":"/swain-teardown","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Progress log (ADR-023)","type":"text"}]},{"type":"paragraph","content":[{"text":"After completing tasks or reaching milestones, update the progress log:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"REPO_ROOT=\"$(git rev-parse --show-toplevel 2>/dev/null || pwd)\"\nbash \"$REPO_ROOT/.agents/bin/swain-progress-log.sh\" --digest \"$REPO_ROOT/.agents/session-log.jsonl\"","type":"text"}]},{"type":"paragraph","content":[{"text":"This updates each touched EPIC/Initiative's ","type":"text"},{"text":"progress.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"## Progress","type":"text","marks":[{"type":"code_inline"}]},{"text":" section.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Fallback","type":"text"}]},{"type":"paragraph","content":[{"text":"If ","type":"text"},{"text":"tk","type":"text","marks":[{"type":"code_inline"}]},{"text":" cannot be found or is unavailable:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Log the failure reason.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Fall back to a neutral text task ledger (JSONL or Markdown checklist) in the working directory.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use the same status model (","type":"text"},{"text":"open","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"in_progress","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"blocked","type":"text","marks":[{"type":"code_inline"}]},{"text":", ","type":"text"},{"text":"closed","type":"text","marks":[{"type":"code_inline"}]},{"text":") and keep updates externally visible.","type":"text"}]}]}]},{"type":"hr","attrs":{"markup":"---"}}]},"metadata":{"date":"2026-06-05","name":"swain-do","author":"@skillopedia","source":{"stars":2,"repo_name":"swain","origin_url":"https://github.com/cristoslc/swain/blob/HEAD/skills/swain-do/SKILL.md","repo_owner":"cristoslc","body_sha256":"a051a562dbe6f4de84e6276a53752950088c424508d0d78f97c945d6b591155e","cluster_key":"18021dec58e9f1610d1082f9a7aca758a099c31199a479ba881688d0250b0846","clean_bundle":{"format":"clean-skill-bundle-v1","source":"cristoslc/swain/skills/swain-do/SKILL.md","attachments":[{"id":"4c922c6d-d119-584b-8c41-88a378cd0ffb","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/4c922c6d-d119-584b-8c41-88a378cd0ffb/attachment","path":"bin/ticket-migrate-beads","size":2314,"sha256":"5589c5b6feec06241ea412d1889c3f69a466b302ef96b0c84962b744d7ac528b","contentType":"text/plain; charset=utf-8"},{"id":"ae5a1086-6de9-5562-98fa-840aa922f39c","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/ae5a1086-6de9-5562-98fa-840aa922f39c/attachment","path":"bin/ticket-query","size":2028,"sha256":"02af9a9f9880b6259dbe6628e6c0e2da57fcf0d9404dc1f97e1cb44b3b424b2f","contentType":"text/plain; charset=utf-8"},{"id":"d46c5539-ff8e-50d3-994f-f70188f6de34","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/d46c5539-ff8e-50d3-994f-f70188f6de34/attachment","path":"bin/tk","size":45053,"sha256":"f969985495ddb42a6209eeab54d0aeb1f4a4aeba1cc7b9ab8f89fbf35c88b648","contentType":"text/plain; charset=utf-8"},{"id":"3f2b6660-e226-51f0-aada-f3844db3a1f7","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/3f2b6660-e226-51f0-aada-f3844db3a1f7/attachment","path":"references/.gitkeep","size":0,"sha256":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","contentType":"text/plain; charset=utf-8"},{"id":"42257a3a-0ee2-5dee-9f77-7932146940d7","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/42257a3a-0ee2-5dee-9f77-7932146940d7/attachment.md","path":"references/configuration.md","size":1812,"sha256":"18d6531feddd0bb20227bb36abc541e88975819efa84e0ef6c8495063dc36bd6","contentType":"text/markdown; charset=utf-8"},{"id":"8987ed02-c18b-5147-8089-f6cc2b339e48","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/8987ed02-c18b-5147-8089-f6cc2b339e48/attachment.md","path":"references/escalation.md","size":2611,"sha256":"e917f5631f6ff3779406ebebbbc0cfd25b093140dfd807e09b5e1b4afdc6b646","contentType":"text/markdown; charset=utf-8"},{"id":"ad8fc316-f2d6-5954-9ff8-752c469cf4ba","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/ad8fc316-f2d6-5954-9ff8-752c469cf4ba/attachment.md","path":"references/execution-strategy.md","size":1550,"sha256":"fc1503b9390bd93bec22c862d8358b920179aff07476b0f45a44b0277f1721fd","contentType":"text/markdown; charset=utf-8"},{"id":"c532e688-6c2b-583c-bb2d-4e3877f12a0f","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/c532e688-6c2b-583c-bb2d-4e3877f12a0f/attachment.md","path":"references/plan-ingestion.md","size":1509,"sha256":"bd649b6bf975615f8fbffc28472e04d90b6e2ac3431607d06624a344cd7f1629","contentType":"text/markdown; charset=utf-8"},{"id":"7ffb66b9-ac3b-5f8c-9e0e-c18c2695d59c","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/7ffb66b9-ac3b-5f8c-9e0e-c18c2695d59c/attachment.md","path":"references/reconciliation.md","size":1642,"sha256":"2763a597dcfdcbcf5cdb111fe4168752e8f839e8abda81afad5e34ff4cb0e973","contentType":"text/markdown; charset=utf-8"},{"id":"f2407a8e-ab91-5b9f-8383-4ca23ef71971","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/f2407a8e-ab91-5b9f-8383-4ca23ef71971/attachment.md","path":"references/tdd-enforcement.md","size":5398,"sha256":"aed371590478a1b1db293def77f8d558d31e0615e76d2ec19bbe91c174b3617e","contentType":"text/markdown; charset=utf-8"},{"id":"be3d8fc1-718f-50af-abc6-1a2d79feefff","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/be3d8fc1-718f-50af-abc6-1a2d79feefff/attachment.md","path":"references/tk-cheatsheet.md","size":6154,"sha256":"4204d373360c43a8ad0144388f93b667b9bcbabf1f0cfb4b7206110f044db971","contentType":"text/markdown; charset=utf-8"},{"id":"e867a651-0e90-5bb4-a6d0-983d7d5eb118","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/e867a651-0e90-5bb4-a6d0-983d7d5eb118/attachment","path":"scripts/.gitkeep","size":0,"sha256":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","contentType":"text/plain; charset=utf-8"},{"id":"044508ea-167d-5024-8ff3-79a1f60b092e","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/044508ea-167d-5024-8ff3-79a1f60b092e/attachment.py","path":"scripts/ingest-plan.py","size":6272,"sha256":"60aa0225fb69f3f6388679a0b1a473564f0ec5a856c2230e235b0b954032ae87","contentType":"text/x-python; charset=utf-8"},{"id":"662f0602-c9bd-548c-a6ba-b62e0489db4c","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/662f0602-c9bd-548c-a6ba-b62e0489db4c/attachment.sh","path":"scripts/swain-worktree-overlap.sh","size":1578,"sha256":"30207fbcca6259a55e2f164f4f8b4b8e8479c8484d95e95990965dc2778052b1","contentType":"application/x-sh; charset=utf-8"},{"id":"0a5a78c9-d154-5cca-8918-07960eb75848","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/0a5a78c9-d154-5cca-8918-07960eb75848/attachment.sh","path":"scripts/test-worktree-overlap.sh","size":3174,"sha256":"198f2ba1da59b011e7c166c8cc22da33d73b26096dc816f51efa49da44ca05c4","contentType":"application/x-sh; charset=utf-8"}],"bundle_sha256":"4e0de4375988d6d4c6dc9dc8ec349c181eef4907b06fce7dbe5065aeb79fd414","attachment_count":15,"text_attachments":10,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":5,"excluded_attachments":[]},"cluster_size":1,"skill_md_path":"skills/swain-do/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"design-ux","category_label":"Design"},"exact_dupes_collapsed_into_this":0},"license":"UNLICENSED","version":"v1","category":"design-ux","metadata":{"author":"cristos","source":"swain","version":"4.0.0","short-description":"Task tracking, bookmarks, decisions, and progress"},"import_tag":"clean-skills-v1","description":"Task tracking and implementation execution for swain projects. Invoke whenever a SPEC needs an implementation plan, the user asks what to work on next, wants to check or update task status, claim or close tasks, manage dependencies, abandon work, bookmark context, or record a decision. Also invoked by swain-design after creating a SPEC that's ready for implementation. Tracks SPECs and SPIKEs — not EPICs, VISIONs, or JOURNEYs directly (those get decomposed into SPECs first). Triggers also on: 'bookmark', 'remember where I am', 'record decision'.","allowed-tools":"Bash, Read, Write, Edit, Grep, Glob"}},"renderedAt":1782987796824}

<!-- swain-model-hint: sonnet, effort: low — default for task management; see per-section overrides below -- Execution Tracking <!-- session-check: SPEC-121 -- Before proceeding with any state-changing operation, check for an active session: If the JSON output has other than , inform the operator: "No active session — start one with ?" Proceed if they dismiss. Abstraction layer for agent execution tracking. Other skills (e.g., swain-design) express intent using abstract terms; this skill translates that intent into concrete CLI commands. Before first use: Read references/tk-cheatsheet.md for…