Chain Patterns
Chain patterns for CC 2.1.71 pipelines — MCP detection, handoff files, checkpoint-resume, worktree agents, CronCreate monitoring. Use when building multi-phase pipeline skills. Loaded via skills: field by pipeline skills (fix-issue, implement, brainstorm, verify). Not user-invocable.
Auto-activated — this skill loads automatically when Claude detects matching context.
Chain Patterns
Overview
Foundation patterns for CC 2.1.71 pipeline skills. This skill is loaded via the skills: frontmatter field — it provides patterns that parent skills follow.
Pattern 1: MCP Detection (ToolSearch Probe)
Run BEFORE any MCP tool call. Probes are parallel and instant.
# FIRST thing in any pipeline skill — all in ONE message:
ToolSearch(query="select:mcp__memory__search_nodes")
ToolSearch(query="select:mcp__context7__resolve-library-id")
ToolSearch(query="select:mcp__sequential-thinking__sequentialthinking")
# Store results for all phases:
Write(".claude/chain/capabilities.json", JSON.stringify({
"memory": true_or_false,
"context7": true_or_false,
"sequential": true_or_false,
"timestamp": "ISO-8601"
}))Usage in phases:
# BEFORE any mcp__memory__ call:
if capabilities.memory:
mcp__memory__search_nodes(query="...")
# else: skip gracefully, no errorLoad details: Read("$\{CLAUDE_SKILL_DIR\}/references/mcp-detection.md")
Pattern 2: Handoff Files
Write structured JSON after every major phase. Survives context compaction and rate limits.
Write(".claude/chain/NN-phase-name.json", JSON.stringify({
"phase": "rca",
"skill": "fix-issue",
"timestamp": "ISO-8601",
"status": "completed",
"outputs": { ... }, # phase-specific results
"mcps_used": ["memory"],
"next_phase": 5
}))Location: .claude/chain/ — numbered files for ordering, descriptive names for clarity.
Load schema: Read("$\{CLAUDE_SKILL_DIR\}/references/handoff-schema.md")
Pattern 3: Checkpoint-Resume
Read state at skill start. If found, skip completed phases.
# FIRST instruction after MCP probe:
Read(".claude/chain/state.json")
# If exists and matches current skill:
# → Read last handoff file
# → Skip to current_phase
# → Tell user: "Resuming from Phase N"
# If not exists:
Write(".claude/chain/state.json", JSON.stringify({
"skill": "fix-issue",
"started": "ISO-8601",
"current_phase": 1,
"completed_phases": [],
"capabilities": { ... }
}))
# After each major phase:
# Update state.json with new current_phase and append to completed_phasesLoad protocol: Read("$\{CLAUDE_SKILL_DIR\}/references/checkpoint-resume.md")
Pattern 4: Worktree-Isolated Agents
Use isolation: "worktree" when spawning agents that WRITE files in parallel.
# Agents editing different files in parallel:
Agent(
subagent_type="backend-system-architect",
prompt="Implement backend for: {feature}...",
isolation="worktree", # own copy of repo
run_in_background=true
)When to use worktree: Agents with Write/Edit tools running in parallel. When NOT to use: Read-only agents (brainstorm, assessment, review).
Load details: Read("$\{CLAUDE_SKILL_DIR\}/references/worktree-agent-pattern.md")
Pattern 5: CronCreate Monitoring
Schedule post-completion health checks that survive session end.
# Guard: Skip cron in headless/CI (CLAUDE_CODE_DISABLE_CRON)
# if env CLAUDE_CODE_DISABLE_CRON is set, run a single check instead
CronCreate(
schedule="*/5 * * * *",
prompt="Check CI status for PR #{number}:
Run: gh pr checks {number} --repo {repo}
All pass → CronDelete this job, report success.
Any fail → alert with failure details."
)Load patterns: Read("$\{CLAUDE_SKILL_DIR\}/references/cron-monitoring.md")
Pattern 6: Progressive Output (CC 2.1.76)
Launch agents with run_in_background=true and output results as each returns — don't wait for all agents to finish. Gives ~60% faster perceived feedback.
# Launch all agents in ONE message with run_in_background=true
Agent(subagent_type="backend-system-architect",
prompt="...", run_in_background=true, name="backend")
Agent(subagent_type="frontend-ui-developer",
prompt="...", run_in_background=true, name="frontend")
Agent(subagent_type="test-generator",
prompt="...", run_in_background=true, name="tests")
# As each agent completes, output its findings immediately.
# CC delivers background agent results as notifications —
# present each result to the user as it arrives.
# If any agent scores below threshold, flag it before others finish.Key rules:
- Launch ALL independent agents in a single message (parallel)
- Output each result incrementally — don't batch
- Flag critical findings immediately (don't wait for stragglers)
- Background bash tasks are killed at 5GB output (CC 2.1.77) — pipe verbose output to files
Pattern 7: SendMessage Agent Resume (CC 2.1.77)
Continue a previously spawned agent using SendMessage. CC 2.1.77 auto-resumes stopped agents — no error handling needed.
# Spawn agent
Agent(subagent_type="backend-system-architect",
prompt="Design the API schema", name="api-designer")
# Later, continue the same agent with new context
SendMessage(to="api-designer", content="Now implement the schema you designed")
# CC 2.1.77: SendMessage auto-resumes stopped agents.
# No need to check agent state or handle "agent stopped" errors.
# NEVER use Agent(resume=...) — removed in 2.1.77.Pattern 8: /loop Skill Chaining (CC 2.1.71)
/loop runs a prompt or skill on a recurring interval — session-scoped, dies on exit, 3-day auto-expiry. Unlike CronCreate (agent-initiated), /loop is user-invoked and can chain other skills.
# User types these — skills suggest them in "Next Steps"
/loop 5m gh pr checks 42 # Watch CI after push
/loop 20m /ork:verify authentication # Periodic quality gate
/loop 10m npm test -- --coverage # Coverage drift watch
/loop 1h check deployment health at /api/health # Post-deploy monitorKey difference from CronCreate:
/loopcan invoke skills:/loop 20m /ork:verify(CronCreate can't)- Both use the same underlying scheduler (50-task limit, 3-day expiry)
- Skills use
CronCreatefor agent-initiated scheduling - Skills suggest
/loopin "Next Steps" for user-initiated monitoring
When to suggest /loop in Next Steps:
- After creating a PR →
/loop 5m gh pr checks \{pr_number\} - After running tests →
/loop 10m npm test - After deployment →
/loop 1h check health at \{endpoint\} - After verification →
/loop 30m /ork:verify \{scope\}
Rules
| Rule | Impact | Key Pattern |
|---|---|---|
rules/probe-before-use.md | HIGH | Always ToolSearch before MCP calls |
rules/handoff-after-phase.md | HIGH | Write handoff JSON after every major phase |
rules/checkpoint-on-gate.md | MEDIUM | Update state.json at every user gate |
References
Load on demand with Read("$\{CLAUDE_SKILL_DIR\}/references/<file>"):
| File | Content |
|---|---|
mcp-detection.md | ToolSearch probe pattern + capability map |
handoff-schema.md | JSON schema for .claude/chain/*.json |
checkpoint-resume.md | state.json schema + resume protocol |
worktree-agent-pattern.md | isolation: "worktree" usage guide |
cron-monitoring.md | CronCreate patterns for post-task health |
experiment-journal.md | Append-only TSV log for try/measure/keep-or-discard cycles |
progressive-output.md | Progressive output with run_in_background |
sendmessage-resume.md | SendMessage auto-resume (CC 2.1.77) |
tier-fallbacks.md | T1/T2/T3 graceful degradation |
Related Skills
ork:implement— Full-power feature implementation (primary consumer)ork:fix-issue— Issue debugging and resolution pipelineork:verify— Post-implementation verificationork:brainstorm— Design exploration pipeline
Rules (4)
Checkpoint on Gate — MEDIUM
Checkpoint on Gate
Update state.json before every user gate (AskUserQuestion). User may close the session during a gate.
Incorrect
# BAD: State not saved before asking user
AskUserQuestion(questions=[{
"question": "Approve this fix?", ...
}])
# If user closes session: state.json still shows Phase 3Correct
# GOOD: Save state BEFORE the gate
Write(".claude/chain/state.json", {
...existing,
"current_phase": 5,
"completed_phases": [1, 2, 3, 4],
"last_handoff": "04-rca.json",
"updated": now()
})
# THEN ask user
AskUserQuestion(questions=[{
"question": "Approve this fix?", ...
}])Why
Users may:
- Close the terminal during a gate prompt
- Walk away and session times out
- Switch to a different task
In all cases, the completed work is preserved in state.json + handoff files.
Handoff After Phase — HIGH
Handoff After Phase
Write a handoff JSON file after every major phase completes.
Incorrect
# BAD: All phase results only in memory — lost on compaction
phase_4_results = run_rca_agents()
# ... continue to Phase 5 using in-memory results
# If rate-limited here: all RCA work is goneCorrect
# GOOD: Persist results to disk after each phase
phase_4_results = run_rca_agents()
Write(".claude/chain/04-rca.json", JSON.stringify({
"phase": "rca",
"phase_number": 4,
"skill": "fix-issue",
"timestamp": now(),
"status": "completed",
"outputs": phase_4_results,
"next_phase": 5
}))
# If rate-limited: next session reads 04-rca.json and continuesWhich Phases Need Handoffs
- After any phase that takes > 30 seconds
- After any phase that spawns parallel agents
- Before any AskUserQuestion gate
- After the final phase (completion record)
Probe Before Use — HIGH
Probe Before Use
Always run ToolSearch probes before calling any MCP tool.
Incorrect
# BAD: Assumes memory MCP exists — crashes if not installed
mcp__memory__search_nodes(query="past auth fixes")Correct
# GOOD: Probe first, use conditionally
ToolSearch(query="select:mcp__memory__search_nodes")
# → if found: call it
# → if not found: skip or use Grep fallback
caps = Read(".claude/chain/capabilities.json")
if caps.memory:
mcp__memory__search_nodes(query="past auth fixes")
else:
Grep(pattern="auth.*fix", glob="**/*.md")When to Probe
- Once at skill start (not before every call)
- Store results in
.claude/chain/capabilities.json - All subsequent phases read the capability map
PushNotification on Long-Skill Completion — MEDIUM
PushNotification on Long-Skill Completion
When a skill's typical runtime exceeds 5 minutes, fire a PushNotification at completion. Long runs mean the user has almost certainly context-switched; without the notification, a green run can sit unreviewed for hours.
When to apply
| Skill runtime | Notify? |
|---|---|
| < 2 min | No — user is still at the terminal. |
| 2–5 min | Optional — only if the skill has parallel agents or external I/O that makes timing unpredictable. |
| > 5 min | Yes. Fire a notification at the final synthesis / report step. |
Apply to: ork:implement, ork:audit-full, ork:cover, ork:demo-producer, ork:verify (runs on large changes), ork:brainstorm (deep 7-phase mode).
Incorrect
# BAD: skill ends silently after a 30-minute run
return final_report # user is still reading Slack; never sees itCorrect
# GOOD: fire at the final step, with an outcome-summarizing body
PushNotification(
title="ork:implement complete",
body=f"{FEATURE}: {tests_passing}/{tests_total} tests · ready for /ork:verify"
)
return final_reportThe title names the skill; the body summarizes the outcome in one line. Users filter their notification center by title, so keep it stable: "ork:<skill> complete" or "ork:<skill> needs input".
Graceful fallback
PushNotification requires Remote Control with "Push when Claude decides" enabled. Users without it see no error — the call is a silent no-op. No try/except needed. Do not branch on capability detection; the tool handles the absence itself.
# GOOD: unconditional call; tool is a no-op when RC is disabled
PushNotification(title="...", body="...")
# WRONG: defensive capability check adds complexity for no gain
if has_remote_control(): # this API does not exist
PushNotification(...)Body content rules
- Include an actionable outcome, not just "done". Bad:
"finished". Good:"47 files changed · all tests green · PR #1492 opened". - ≤ 100 characters — notification UIs truncate aggressively.
- No emojis — they render inconsistently across devices.
- State the next step when the skill expects one. Example:
"ready for /ork:verify"or"3 conflicts need review".
Why
Users running /ork:implement on a medium-sized feature commonly walk away for 20–30 min. A silent completion means either (a) they check back prematurely and see nothing interesting, or (b) they forget entirely. Neither is the point of running the skill.
Remote Control is opt-in — users who have enabled it have explicitly signaled they want these notifications. Skipping the call for "safety" wastes that signal.
Related
chain-patterns/references/monitor-patterns.md— streaming progress during a long run (complements completion notification).ork:implement,ork:audit-full,ork:cover,ork:demo-producer— skills that apply this rule.
References (13)
Checkpoint Resume
Checkpoint-Resume Protocol
Enables pipeline skills to survive rate limits, context compaction, and session crashes by persisting progress to disk.
State Schema
{
"skill": "fix-issue",
"args": "456",
"started": "2026-03-07T16:30:00Z",
"current_phase": 5,
"completed_phases": [1, 2, 3, 4],
"capabilities": {
"memory": true,
"context7": true,
"sequential": false
},
"last_handoff": "04-rca.json",
"updated": "2026-03-07T16:45:00Z"
}Resume Flow
# FIRST instructions in any pipeline skill:
# 1. Check for existing state
Read(".claude/chain/state.json")
# 2a. If state exists AND matches current skill:
if state.skill == current_skill:
# Read last handoff for context
Read(f".claude/chain/{state.last_handoff}")
# Skip completed phases
# Start from state.current_phase
# Tell user: "Resuming from Phase {N} — {phase_name}"
# "Previous session completed: {completed_phases}"
# 2b. If state exists but DIFFERENT skill:
# Ask user: "Found state from /ork:{state.skill}. Start fresh?"
# If yes: overwrite state.json
# If no: let user switch to that skill
# 2c. If no state exists:
# Fresh start — write initial state
Write(".claude/chain/state.json", { skill, current_phase: 1, ... })Update Protocol
# After completing each major phase:
Read(".claude/chain/state.json") # read current
# Update with new phase info:
Write(".claude/chain/state.json", {
...existing,
"current_phase": next_phase,
"completed_phases": [...existing.completed_phases, current_phase],
"last_handoff": f"{phase_number:02d}-{phase_name}.json",
"updated": now()
})When to Checkpoint
- After every numbered phase completes
- Before every AskUserQuestion gate
- Before spawning long-running parallel agents
- The
PreCompacthook auto-saves if context is about to compact
Edge Cases
- Rate limit mid-phase: Phase is NOT marked complete. On resume, the phase restarts from scratch.
- Multiple skills: Only one skill's state lives in
state.jsonat a time. Starting a new skill overwrites. - Stale state: If
state.updatedis older than 24 hours, warn user and offer fresh start.
Session Context Restoration (CC 2.1.108+)
When resuming a long chain after an idle period, CC 2.1.108 provides automatic session recap via /recap. This complements checkpoint-resume:
/recap: Restores conversational context (what was discussed, decided, attempted)state.json: Restores pipeline progress (which phases completed, what data was produced)
Both should be consulted on resume. The PostCompact hook already re-injects branch and task state — /recap adds the conversational layer on top.
Session recap is enabled by default since CC 2.1.110 (even with telemetry disabled). Opt out via /config or CLAUDE_CODE_ENABLE_AWAY_SUMMARY=0.
Scheduled Task Recovery (CC 2.1.110+)
--resume and --continue now resurrect unexpired scheduled tasks (created via CronCreate or ScheduleWakeup), not just session history. This means:
/loop-based chains that were interrupted by rate limits or session timeouts will auto-resume their scheduled ticks- Cron-scheduled agents will be restored alongside the session
- No need to manually re-create scheduled work after resuming
Cron Monitoring
CronCreate Monitoring Patterns
Schedule post-completion health checks that survive session end. Unlike /loop (user command), CronCreate is a tool the agent calls programmatically.
CI Status Monitor
# After creating a PR:
CronCreate(
schedule="*/5 * * * *", # every 5 minutes
prompt="Check CI status for PR #{pr_number} on {owner}/{repo}.
Run: gh pr checks {pr_number} --repo {owner}/{repo}
If all checks pass: CronDelete this job and report 'CI passed for PR #{pr_number}'.
If any check fails: report the failure details immediately."
)Regression Monitor
# After deploying a fix:
CronCreate(
schedule="0 */6 * * *", # every 6 hours
prompt="Regression check for fix deployed in PR #{pr_number}:
1. Run: npm test
2. If all pass and this is the 4th consecutive pass: CronDelete this job
3. If any fail: alert with test names and error messages"
)Health Check
# After deploying a feature:
CronCreate(
schedule="0 8 * * *", # daily at 8am
prompt="Health check for {feature} deployed {date}:
1. Run: gh api repos/{owner}/{repo}/actions/runs --jq '.[0].conclusion'
2. If healthy for 7 days: CronDelete this job
3. If errors: alert immediately"
)Best Practices
- Always include a
CronDeletecondition — don't leave crons running forever - Use descriptive prompts so the cron agent knows what to check
- Prefer
ghCLI overcurlfor GitHub checks (auth handled) - Schedule frequency: CI checks every 5min, health checks every 6h, regression daily
Experiment Journal
Experiment Journal Pattern
Append-only TSV log for tracking try/measure/keep-or-discard cycles across sessions. Inspired by autoresearch's results.tsv.
When to Use
Any skill that produces scored/rated output and may run multiple times on similar topics:
brainstorm— log evaluated ideas with composite scores and keep/discard statusverify/cover— log optimization attempts with metric deltasimplement— log iterative optimization attempts (performance, bundle size, prompts)fix-issue— log attempted fixes with pass/fail
File Location
.claude/experiments/{skill}-{topic-slug}.tsvExamples:
.claude/experiments/brainstorm-caching-strategy.tsv.claude/experiments/optimize-bundle-size.tsv.claude/experiments/fix-issue-1234.tsv
TSV Format
Tab-separated, 6 columns. Header row required.
timestamp score status reason commit description
2026-04-06T08:00 7.55 keep - a1b2c3d Session-only with signed cookies
2026-04-06T08:01 3.15 discard complexity - Custom token protocol
2026-04-06T08:05 0.00 crash untestable - Blockchain auth (can't assess)
2026-04-06T09:00 0.982 keep - c3d4e5f Increase LR to 0.04
2026-04-06T09:05 1.005 discard regression c3d4e5f Switch to GeLU activationColumn Reference
| Column | Type | Description |
|---|---|---|
timestamp | ISO-8601 | When the experiment was logged |
score | float | Composite score (brainstorm) or metric value (optimization). 0.00 for crashes |
status | enum | keep, discard, or crash |
reason | string | Why discarded: overkill, infeasible, duplicate, regression, complexity, untestable. - for keeps |
commit | string | Git short SHA if code was committed, - otherwise |
description | string | Short text describing what was tried. No tabs (breaks TSV) |
Reading the Journal
Before Phase 1 (Memory + Context)
journal_path = f".claude/experiments/{skill}-{topic_slug}.tsv"
try:
journal = Read(journal_path)
# Parse and surface to user
keeps = [row for row in journal if row.status == "keep"]
discards = [row for row in journal if row.status == "discard"]
print(f"Prior session: {len(keeps)} kept, {len(discards)} discarded")
# Pre-filter: skip ideas similar to discard entries
# Highlight: surface keep entries as starting points
except:
pass # No prior journal — first runTrajectory Detection
Count experiments in rolling windows to detect progress state:
recent = last_10_experiments()
keep_rate = count(status == "keep") / len(recent)
if keep_rate > 0.3:
trajectory = "improving" # Still finding wins
elif keep_rate > 0.1:
trajectory = "plateauing" # Diminishing returns
else:
trajectory = "stuck" # Consider switching strategyWhen trajectory == "stuck":
- Brainstorm: try more radical ideas, revisit discarded approaches with modifications
- Optimize: increase change magnitude, try orthogonal dimensions
- Fix-issue: escalate to user, try different root cause hypothesis
Writing to the Journal
After Each Experiment
# Append one line (never overwrite)
line = f"{timestamp}\t{score}\t{status}\t{reason}\t{commit}\t{description}\n"
# Use Bash to append:
Bash(command=f'echo "{line}" >> {journal_path}')After Brainstorm Phase 4
# Log all evaluated ideas
for idea in evaluated_ideas:
status = "keep" if idea in top_approaches else "discard"
reason = "-" if status == "keep" else idea.discard_reason
append_to_journal(idea.score, status, reason, "-", idea.description)After Iterative Optimization Loop
# Log each iteration
if metric_improved:
append_to_journal(new_metric, "keep", "-", commit_sha, change_description)
else:
append_to_journal(new_metric, "discard", "regression", "-", change_description)Git Policy
Do NOT commit experiment journals. Add to .gitignore:
.claude/experiments/Journals are local working memory, not source code. They survive across sessions via the filesystem but don't pollute git history. If a journal contains important decisions, persist them to the memory graph instead.
Fork Pattern
Fork Pattern — Cache-Sharing Parallel Subagents
CC 2.1.89 automatically forks subagents that meet certain criteria, sharing the parent's cached API prefix. This eliminates cold-start re-tokenization and reduces API cost by 30-50% for multi-agent skills.
When CC Forks Automatically
CC routes Agent() calls to fork (cache-sharing) mode when ALL conditions are met:
| Condition | Requirement |
|---|---|
| No custom model | Agent inherits parent model (no model= parameter) |
| No worktree isolation | No isolation: "worktree" parameter |
| Short prompt | Prompt body < 500 words (only the divergent part) |
| Same tool schema | Agent uses same tools as parent (no exact-tools override) |
If ANY condition fails, CC falls back to standard cold-start Agent().
Fork-Friendly Prompt Template
Agent(
subagent_type="backend-system-architect",
name="backend-explorer", # Named for @mention routing
prompt="""Scope: {specific_task}
Context: {brief_shared_context}
Deliverable: {expected_output_format}
RESULT: End with a one-line summary.""",
run_in_background=True,
max_turns=25
)Rules:
- Start with
Scope:header (signals fork-friendly intent) - Keep prompt under 500 words — parent context is inherited
- Do NOT repeat system instructions (fork inherits them)
- Do NOT set
model=(breaks cache prefix sharing) - Do NOT set
isolation: "worktree"(breaks fork mode) - End with
RESULT:summary line for structured collection
What Forks Inherit
Forked subagents automatically receive:
- Parent's full system prompt and CLAUDE.md rules
- All prior conversation context (cached)
- Tool definitions (same schema, same cache prefix)
- MCP server connections
- Session environment variables
They do NOT inherit:
- Parent's in-progress edits (no shared filesystem writes)
- Other forks' outputs (forks are isolated from each other)
Cache Mechanics
Parent conversation:
System prompt + CLAUDE.md + tool schemas + N turns of context
───────────────────────────────────────────────────────────
│ CACHED PREFIX (~90%) │
───────────────────────────────────────────────────────────
▼
Fork A: [cached prefix] + "Scope: analyze backend..." (~10% new)
Fork B: [cached prefix] + "Scope: analyze frontend..." (~10% new)
Fork C: [cached prefix] + "Scope: check test coverage..." (~10% new)
▲
Only this part is re-tokenizedCost: ~1.1× instead of ~3× for 3 parallel agents.
When NOT to Fork
| Scenario | Why | Use Instead |
|---|---|---|
| Agent needs worktree isolation | File edits conflict between forks | Agent(isolation="worktree") |
| Agent needs custom model | e.g., Haiku for cheap analysis | Agent(model="haiku") |
| Agent reads prior phase handoff | Handoff file not in cache prefix | Standard Agent() with file content in prompt |
| Coordinator mode active | Coordinator disables forks | Standard Agent() |
Agent needs permission_mode: "bubble" | Prompts appear in parent terminal | Only if acceptable UX |
Fork-Eligible Skills
| Skill | Agents | Fork-Ready | Notes |
|---|---|---|---|
| explore | 4 parallel | ✓ | All read-only, no worktree |
| brainstorm | 3-5 parallel | ✓ | Divergent ideation, no state |
| verify | 6-7 parallel | ⚠ partial | Domain filter runs in parent; fork after filtering |
| review-pr | 6-7 parallel | ⚠ partial | Context injection in parent; fork the review agents |
| implement | 3 parallel | ✗ | Worktree isolation required |
| fix-issue | 1-5 parallel | ✗ | Worktree isolation for RCA agents |
Context Stager Behavior
The subagent-context-stager SubagentStart hook detects forks via input.is_fork:
- Fork = true: Skip heavy context injection (CLAUDE.md rules, decisions, task list) — fork inherits parent context
- Fork = false: Full context staging (standard Agent cold-start path)
This prevents double-injection that wastes tokens and can confuse the model.
Analytics
Fork metrics are logged to subagent-quality.jsonl:
{
"agent": "backend-system-architect",
"is_fork": true,
"cache_creation_tokens": 150000,
"cache_read_tokens": 148500,
"cache_hit_pct": 99.0,
"duration_ms": 12500
}Compare cache_hit_pct between fork and non-fork agents to measure savings.
Fallback Strategy
If fork fails (CC version < 2.1.89, coordinator mode, etc.), the skill should gracefully degrade:
# Fork-friendly prompt (CC auto-detects):
Agent(subagent_type="Explore", prompt="Scope: ...", run_in_background=True)
# ↑ If CC can fork: forked (cheap)
# ↑ If CC can't fork: standard cold-start (works, just more expensive)No code change needed for fallback — CC handles routing automatically. The prompt pattern works in both modes.
Handoff Schema
Handoff File Schema
Handoff files pass structured data between phases of a pipeline skill. They persist to disk, surviving context compaction and rate limits.
Location
.claude/chain/
capabilities.json # MCP probe results (written once at start)
state.json # Checkpoint state (updated after each phase)
NN-phase-name.json # Phase handoff (one per completed phase)Schema
{
"phase": "rca",
"phase_number": 4,
"skill": "fix-issue",
"timestamp": "2026-03-07T16:30:00Z",
"status": "completed",
"outputs": {
// Phase-specific structured data
},
"mcps_used": ["memory", "context7"],
"next_phase": 5,
"next_phase_name": "fix-design"
}Required Fields
| Field | Type | Description |
|---|---|---|
phase | string | Phase identifier (kebab-case) |
phase_number | number | Numeric phase index |
skill | string | Parent skill name |
timestamp | string | ISO-8601 timestamp |
status | string | completed or failed |
outputs | object | Phase-specific results |
next_phase | number | Next phase index |
Naming Convention
NN-phase-name.json
Examples:
03-hypotheses.json # fix-issue Phase 3
04-rca.json # fix-issue Phase 4
02-ideas.json # brainstorm Phase 2
05-implementation.json # implement Phase 5Cleanup
Handoff files are NOT automatically cleaned up. They persist until:
- User manually deletes
.claude/chain/ - A new skill run overwrites them (same phase numbers)
- The skill's final phase cleans up on success
Size Limits
Keep handoff files under 50KB. For large outputs (full file contents, long diffs), summarize in the handoff and reference the source files by path.
Mcp Detection
MCP Detection via ToolSearch
Probe MCP server availability before using any MCP tool. This prevents hard crashes when a user doesn't have a specific MCP server configured.
Probe Pattern
# Run ALL probes in ONE message (parallel, ~50ms each):
ToolSearch(query="select:mcp__memory__search_nodes")
ToolSearch(query="select:mcp__context7__resolve-library-id")
ToolSearch(query="select:mcp__sequential-thinking__sequentialthinking")
# Write capability map (read by all subsequent phases):
Write(".claude/chain/capabilities.json", JSON.stringify({
"memory": true, // or false if ToolSearch returned no results
"context7": true,
"sequential": false, // not installed
"timestamp": "2026-03-07T16:30:00Z"
}))Usage in Skill Phases
# Read capabilities (already written at skill start):
caps = Read(".claude/chain/capabilities.json")
# BEFORE any MCP call, check capability:
if caps.memory:
mcp__memory__search_nodes(query="past fixes for auth errors")
else:
# T1 fallback: skip memory search, rely on codebase grep
Grep(pattern="auth.*error", glob="**/*.ts")
if caps.context7:
mcp__context7__query-docs(libraryId="...", query="...")
else:
# T1 fallback: WebFetch docs directly
WebFetch("https://docs.example.com/api")
if caps.sequential:
mcp__sequential-thinking__sequentialthinking(thought="...", ...)
else:
# T1 fallback: use inline evaluation rubric
# (the skill's own SKILL.md scoring instructions)3-Tier Model
| Tier | Servers | Who Has It |
|---|---|---|
| T1: Core | None (CC built-in tools only) | Every CC user |
| T2: Enhanced | memory, context7, sequential-thinking | Most CC users (free npm MCPs) |
| T3: Power | tavily, agent-browser | Power users (API keys required) |
Rule: T1 MUST always work. T2/T3 enhance but never required.
Important Notes
- ToolSearch is fast (~50ms) — probe overhead is negligible
- Probe ONCE at skill start, not before every MCP call
- Store in
.claude/chain/capabilities.jsonso all phases can read it - If a probe fails (tool not found), treat as
false— never error
Mcp Tool Hooks
Hooks Invoking MCP Tools — type: "mcp_tool"
CC 2.1.118 added a new hook dispatch type that lets a registered hook invoke an MCP tool directly, without spawning a subagent. Unlocks fast access to MCP context (memory, agentation, sequential-thinking) from inside hook handlers.
Closes: part of #1501 (M122-4). Reference for adoption.
Why This Replaces Old Patterns
Before 2.1.118, a hook that needed MCP context had two options, both bad:
| Old approach | Cost | Failure mode |
|---|---|---|
Spawn a subagent via Agent() from inside the hook | 30–60s + ~150K tokens | Hook timeouts, context budget blown |
Shell out to npx -y <mcp-server> and parse stdout | 2–5s + brittle parser | npm cache misses, MCP version drift, ad-hoc auth |
Both forced hooks into either expensive (subagent) or fragile (shell) territory for what should be a simple tool call.
The New Type
In hooks.json, register a hook that invokes an MCP tool:
{
"PreToolUse": [
{
"matcher": "Write",
"type": "mcp_tool",
"tool": "mcp__memory__search_nodes",
"input": {
"query": "${input.tool_input.file_path}"
},
"outputMapping": "additionalContext"
}
]
}type: "mcp_tool" tells CC to:
- Resolve the MCP server (must be enabled in
.mcp.json) - Dispatch the tool call with
input(templated against the hook's input) - Return the MCP response back to the hook context (via
outputMapping)
No subprocess spawn, no shell parsing — same dispatch path the model uses when invoking the tool itself.
Pattern 1 — Inject Memory Context Before Edit
{
"PreToolUse": [
{
"matcher": "Write|Edit",
"type": "mcp_tool",
"tool": "mcp__memory__search_nodes",
"input": { "query": "${input.tool_input.file_path}" },
"outputMapping": "additionalContext"
}
]
}Use case: surface prior decisions about the file being edited.
Pattern 2 — Read Annotation Queue After Read
{
"PostToolUse": [
{
"matcher": "Read",
"type": "mcp_tool",
"tool": "mcp__agentation__agentation_get_pending",
"input": { "filePath": "${input.tool_input.file_path}" },
"outputMapping": "systemMessage"
}
]
}Use case: alert the model when annotations exist for the file just read.
Pattern 3 — Sequential Thinking on Long Tasks
{
"TaskCreated": [
{
"matcher": ".*",
"type": "mcp_tool",
"tool": "mcp__sequential-thinking__sequentialthinking",
"input": { "thought": "Decompose: ${input.task_description}", "thoughtNumber": 1, "totalThoughts": 5, "nextThoughtNeeded": true },
"outputMapping": "additionalContext",
"condition": "task_description.length > 200"
}
]
}Use case: kick off a structured plan for any task description over 200 chars.
When NOT to Use
| Situation | Use instead |
|---|---|
MCP server is disabled: true in .mcp.json | Skip the hook (it'll fail at dispatch) |
| You need to gate on the MCP response | Subagent — mcp_tool doesn't support conditional logic in-place |
| The hook needs MCP output for >1 downstream MCP call | Subagent — chained MCP calls are expensive in this dispatch type |
MCP server is HIGH-tier (@21st-dev/magic, agentation pre-1.0) | Pin first (see src/skills/mcp-patterns/references/mcp-version-matrix.md) |
Performance Envelope
| Path | Cold | Warm | Cost (tokens) |
|---|---|---|---|
| Subagent spawn | 30–60s | 30–60s | ~150K |
Shell npx -y | 2–5s | 0.3–1s | ~0 |
type: "mcp_tool" | 0.1–0.3s | 0.05–0.1s | ~0 (within MCP server limits) |
The new type is functionally a free dispatch — same overhead as the model invoking the tool itself.
Tier Compatibility
The new type is enforced at hook registration time (CC ≥ 2.1.118). For older CC versions, hook registration is rejected with unsupported hook type: "mcp_tool". OrchestKit floors at 2.1.118 as of 7.70.0 — see src/hooks/src/lib/cc-version-matrix.ts.
Related
chain-patterns/references/monitor-patterns.md— Monitor tool for streaming process outputsrc/skills/mcp-patterns/references/mcp-version-matrix.md— Tier classification for.mcp.jsonentriessrc/skills/doctor/references/mcp-pinning-check.md— Doctor warn on HIGH-tier@latest
Monitor Patterns
Monitor Tool Patterns
Monitor (CC 2.1.98) streams each stdout line from a backgrounded process as a notification. Use it anywhere a workflow would otherwise poll output files or block on completion — tests, builds, long agents, agent-browser sessions.
When to use Monitor
| Situation | Use |
|---|---|
| Background build/test/long script | Monitor — stream progress live |
| Finished task, need its final output | TaskOutput(task_id) — one-shot read (no block=true needed) |
| Gate entry on matching stdout line | Monitor + until-condition loop |
| Very short command (<5s) | Bash(command="...") foreground — not worth the overhead |
Monitor is NOT a replacement for TaskOutput on finished tasks. They answer different questions: "what is this process doing right now?" vs "what did that task produce?".
Pattern 1 — Streaming test execution
# Start the test suite in the background
Bash(command="npm test -- --coverage 2>&1", run_in_background=true)
# Stream each line as it's produced
Monitor(pid=test_task_id)
# → user sees "PASS src/auth.test.ts", "FAIL src/db.test.ts", etc.
# → no polling, no intermediate "running tests..." liesApplies to: ork:cover, ork:verify, any skill that runs a test suite longer than ~10 seconds.
Pattern 2 — Streaming agent progress
# Spawn a background agent
Agent(subagent_type="test-generator", run_in_background=true,
prompt="Generate integration tests for the auth module")
# Watch its task-notification stream for partial progress (CC 2.1.98)
Monitor(pid=agent_task_id)
# → partial results arrive; if the agent crashes, salvageable output is visibleApplies to: ork:implement, ork:cover, any skill that spawns long-running background agents.
Pattern 3 — Until-condition gate
# Start a dev server
Bash(command="npm run dev 2>&1", run_in_background=true)
# Wait for "ready" message, then continue — don't block for fixed duration
Monitor(pid=dev_server_id)
# (gate satisfied once "ready" line is matched)Applies to: ork:expect (agent-browser readiness), preview servers, long initialization.
Pattern 4 — Partial-result salvage
Background agents can return [PARTIAL RESULT] when killed by context limit or timeout. With Monitor in place, the parent has already seen the partial stream — no need to re-spawn:
# After Agent completes (partial or whole):
if "[PARTIAL RESULT]" in agent_result.output:
# Stream already seen via Monitor — commit what's usable, flag incomplete
commit_partial_files(agent_result.worktree)
TaskUpdate(taskId=agent_task_id, status="completed",
description=f"Partial: salvaged {len(partial_files)} files")
# Do NOT re-spawn; wasted tokensAnti-patterns
Polling TaskOutput in a loop
# BAD — polls every N seconds, burns tokens on unchanged output
while True:
out = TaskOutput(task_id)
if "PASS" in out or "FAIL" in out: break
time.sleep(5)The sleep is blocked by OrchestKit's sleep-guard hook, and the pattern wastes cache on identical reads. Use Monitor instead.
TaskOutput(block=true) — deprecated
CC 2.1.98 deprecated the block=true variant. Any skill that still documents it is stale; convert to Monitor. Current OrchestKit skills contain zero block=true call sites (verified 2026-04-24).
Monitor for one-shot commands
# BAD — overhead for a command that finishes in 200ms
Bash(command="git rev-parse HEAD", run_in_background=true)
Monitor(pid=head_id)Foreground Bash is simpler and faster for short commands.
Graceful fallback
Monitor requires CC ≥ 2.1.98. The version matrix in src/hooks/src/lib/cc-version-matrix.ts gates it. Skills that reference Monitor should not silently fail on older clients — either (a) the MIN_CC_VERSION guard (currently 2.1.117) makes fallback moot, or (b) document the TaskOutput(task_id) final-read path as the fallback in the skill itself.
Related
chain-patterns/rules/push-notification-on-completion.md— notify at completion (complements streaming during run).chain-patterns/references/checkpoint-resume.md— state.json discipline for long streaming runs.ork:implement,ork:cover,ork:verify,ork:expect— skills that apply these patterns.
Plugin Tag
claude plugin tag — Plugin Release Tagging
CC 2.1.118 added the claude plugin tag CLI command for tagging plugin releases with version validation. OrchestKit's release flow adopts this in M122 to catch manifest-vs-tag drift before users see it.
Closes: part of #1505 (M122-7). Reference for the release flow.
What It Does
claude plugin tag <version> runs validation across the plugin manifest hierarchy:
| Check | Source of truth | Failure mode |
|---|---|---|
| Marketplace version matches | .claude-plugin/marketplace.json version | Tag rejected |
Plugin .claude-plugin/plugin.json matches | per-plugin manifest | Tag rejected |
package.json version matches | repo root | Tag rejected |
version.txt matches (if present) | repo root | Tag rejected |
| No uncommitted changes in plugins/ | working tree | Tag rejected |
| Plugin can be loaded | claude plugin validate (CC ≥ 2.1.77) | Tag rejected |
If all pass, an annotated git tag v<version> is created locally; pushing it triggers downstream release automation (GitHub Release, NotebookLM sync, etc.).
OrchestKit Adoption
release-please integration
.github/workflows/release-please.yml runs claude plugin tag after release-please opens its release PR — it validates the staged version bump before the PR is approved, catching drift early.
- name: Validate plugin tag
if: ${{ steps.release.outputs.release_created == 'true' }}
run: |
claude plugin tag "${{ steps.release.outputs.version }}" --dry-run--dry-run runs the validation without creating the tag (the actual tag is created by release-please's own GitHub Release step).
Skill references
| Skill | Section to update |
|---|---|
src/skills/release-management/SKILL.md | Add claude plugin tag to the validation checklist |
src/skills/release-checklist/SKILL.md | Pre-release verification step |
src/skills/release-sync/SKILL.md | Detect tag-based sync triggers |
What Drift Looks Like
Real-world example caught by claude plugin tag in OrchestKit's history:
$ claude plugin tag 7.70.0
✗ Marketplace version mismatch
expected: 7.70.0
found: 7.69.0 (in .claude-plugin/marketplace.json)
fix: release-please extra-files entry missing $.plugins[0].version
✗ Plugin manifest version mismatch
expected: 7.70.0
found: 7.69.0 (in plugins/ork/.claude-plugin/plugin.json)
fix: stale plugins/ — run `npm run build` and re-stageWithout this check, users would have installed ork@7.70.0 from the marketplace and gotten a 7.69.0 manifest — confusing and hard to diagnose.
Failure Modes Pre-2.1.118
OrchestKit's release flow before adoption:
release-please bumps 5 files → CI builds plugins/ →
drift in any of the 5 = user sees mismatched version → file bug → ship 7.69.1Three OrchestKit releases (v7.65.1, v7.66.0, v7.67.0) had to be patch-released because of manifest drift. Adopting claude plugin tag in CI eliminates this class of bug at the source.
Local Workflow
When making manual changes to plugin manifests:
# Bump versions across all 5 sites manually (or via release-please)
$EDITOR package.json manifests/ork.json .claude-plugin/marketplace.json \
plugins/ork/.claude-plugin/plugin.json version.txt
# Validate before committing
claude plugin tag $(cat version.txt) --dry-run
# If green: commit and push (CI runs the same check non-dry)
git add . && git commit -m "chore: release X.Y.Z"Related
.github/workflows/release-please.yml— release automation.release-please-config.json— extra-files configuration (5 file paths kept in sync)src/skills/release-management/SKILL.md— release flow ownershipsrc/skills/release-checklist/SKILL.md— pre-release validation
Pr From Platform
--from-pr Multi-Host Support
CC 2.1.119 extends --from-pr to accept GitLab MR, Bitbucket PR, and GitHub Enterprise URLs in addition to github.com. OrchestKit's PR-related skills (review-pr, create-pr, fix-issue) adopt this in M122.
Closes: part of #1502 (M122-5). Reference for skill authors.
Supported Hosts
| Host family | URL pattern | Detection regex |
|---|---|---|
| github.com (public) | https://github.com/\{owner\}/\{repo\}/pull/\{n\} | ^https://github\.com/ |
| GitHub Enterprise | https://\{host\}/\{owner\}/\{repo\}/pull/\{n\} (host suffix .github.<corp>) | \.github\.[a-z]+/ |
| GitLab.com | https://gitlab.com/\{owner\}/\{repo\}/-/merge_requests/\{n\} | ^https://gitlab\.com/ |
| Self-hosted GitLab | https://gitlab.\{corp\}/\{group\}/\{repo\}/-/merge_requests/\{n\} | ^https://gitlab\. |
| Bitbucket Cloud | https://bitbucket.org/\{owner\}/\{repo\}/pull-requests/\{n\} | ^https://bitbucket\.org/ |
Skill Adoption
Skills that previously assumed github.com:
src/skills/review-pr/SKILL.md— review existing PR (any host)src/skills/create-pr/SKILL.md— push branch + open PR (host-aware)src/skills/fix-issue/SKILL.md— branch from issue/MR (host-aware)
Each skill should:
- Parse the URL with the host-detector helper (
src/hooks/src/lib/pr-host-parser.ts). - Branch on
host_familyfor host-specific behaviors:- GitHub:
gh pr view/edit/checks(existing path) - GitLab:
glab mr view/edit(or REST/projects/:id/merge_requests/:iid) - Bitbucket:
bb pr(or REST/repositories/:ws/:repo/pullrequests/:id)
- GitHub:
- Fall back to
github.comdefaults when host is unrecognized — never crash.
Configuration: prUrlTemplate
CC 2.1.119 added a prUrlTemplate setting (in ~/.claude/settings.json or project-level) for custom code-review URL formatting:
{
"prUrlTemplate": "https://gitlab.acme.com/{owner}/{repo}/-/merge_requests/{n}"
}When set, skills should consult this template before constructing PR/MR URLs. Document it in src/skills/configure/references/.
Anti-Patterns
| Don't | Do |
|---|---|
Hardcode github.com in skill copy | Parameterize via the host-detector helper |
Assume gh CLI is available for non-GitHub | Fall back to REST or document the dependency |
| Crash on unrecognized URL | Default to github.com parsing + warn |
| Mix branch detection (push-side) with PR detection (review-side) | Keep them in separate parsers |
Reference Implementation
src/hooks/src/lib/pr-host-parser.ts exports:
export interface PrHostInfo {
host: string;
family: 'github' | 'github-enterprise' | 'gitlab' | 'gitlab-self' | 'bitbucket' | 'unknown';
owner: string;
repo: string;
pr_id: number;
}
export function parsePrUrl(url: string): PrHostInfo | null;Tests in src/hooks/src/__tests__/pr-host-parser.test.ts cover all 5 host families with real-world URL fixtures.
Migration Checklist
When converting a skill from github.com-only to multi-host:
- Import
parsePrUrlfromsrc/hooks/src/lib/pr-host-parser.ts - Replace
github.comregex with parser call - Branch on
familyfor any CLI/REST calls - Document
prUrlTemplatein the skill's configuration section - Add fixture tests for at least 3 host families
- Update SKILL.md with explicit support table
Related
src/skills/review-pr/SKILL.md— PR review skill (multi-host adopted)src/skills/create-pr/SKILL.md— PR creation skill (multi-host adopted)src/skills/fix-issue/SKILL.md— issue-to-branch skill (multi-host adopted)src/skills/configure/references/—prUrlTemplatedocumentation
ScheduleWakeup — Dynamic Loop Pacing
ScheduleWakeup — Dynamic Loop Pacing
When to Use
┌─ Need it after session ends?
│
YES ──┤──→ CronCreate (persistent)
│ Weekly drift, daily regression, health checks
NO ───┤
│──→ ScheduleWakeup (session-scoped)
CI polling, build watching, deploy verificationCache-Aware Delay Selection
The prompt cache has a 5-minute TTL. Sleeping past 300s means the next wake-up reads full context uncached — slower and more expensive.
| Delay | Cache | Use When |
|---|---|---|
| 60–270s | Warm | Active work — build running, CI check pending, process just started |
| Never 300s | Worst of both | Cache miss without amortizing the wait |
| 300–3600s | Cold | Genuinely idle — nothing to check for minutes |
| 1200–1800s | Cold (amortized) | Idle ticks with no specific signal to watch |
Patterns
CI Status Polling (after PR creation)
ScheduleWakeup(
delaySeconds: 270, # CI takes ~4min, stay in cache
prompt: "Check PR #123 CI status: gh pr checks 123. If all pass → done. If still pending → schedule again.",
reason: "CI pipeline running, checking in 4.5min"
)Post-Deploy Health Check
# First check: soon after deploy
ScheduleWakeup(
delaySeconds: 120,
prompt: "Verify deployment health: curl -s https://app.example.com/health | check status. If healthy for 2 consecutive checks → done.",
reason: "deploy just completed, quick health check"
)
# Subsequent checks: longer intervals
ScheduleWakeup(
delaySeconds: 1200, # 20min, amortize cache miss
prompt: "...",
reason: "deploy stable, monitoring at 20min intervals"
)Post-Fix Verification
ScheduleWakeup(
delaySeconds: 270,
prompt: "Re-run failing test to verify fix holds: npm test -- --testPathPattern=auth. If pass → done. If fail → investigate.",
reason: "verifying fix stability after 4.5min"
)Termination
To stop the loop, omit the ScheduleWakeup call in the next iteration. No explicit cleanup needed (unlike CronDelete).
# In the wakeup handler:
result = check_status()
if result == "all_pass":
# Don't call ScheduleWakeup → loop ends
return "CI passed, done."
else:
# Continue polling
ScheduleWakeup(delaySeconds: 270, ...)vs CronCreate
| Aspect | ScheduleWakeup | CronCreate |
|---|---|---|
| Lifetime | Session-scoped | Persistent |
| Cleanup | Auto (omit call) | Manual CronDelete |
| Pacing | Dynamic per-iteration | Fixed cron schedule |
| Cache | Aware (270s/1200s) | Unaware |
| Best for | In-session polling | Cross-session monitoring |
Anti-Patterns
- 300s delay: Exactly at cache boundary — pays cache miss without useful wait
- Fixed intervals for variable tasks: If build takes 2-8min, don't use fixed 5min — check elapsed and adapt
- ScheduleWakeup for persistent monitors: Use CronCreate for things that should survive session end
Tier Fallbacks
T1/T2/T3 Graceful Degradation
Every skill MUST work at T1 (zero MCP servers). T2 and T3 enhance but are never required.
Tier Definitions
| Tier | MCP Servers | Install | Who Has It |
|---|---|---|---|
| T1: Core | None | Built into CC | Every CC user |
| T2: Enhanced | memory, context7, sequential-thinking | npm install (free) | Most CC users |
| T3: Power | tavily, agent-browser | API keys required | Power users |
Fallback Matrix
| MCP Tool | T2/T3 Behavior | T1 Fallback |
|---|---|---|
mcp__memory__search_nodes | Search past decisions | Skip — rely on codebase Grep |
mcp__memory__create_entities | Save patterns | Skip — patterns not persisted |
mcp__context7__query-docs | Live library docs | WebFetch docs URL directly |
mcp__sequential-thinking__* | Structured reasoning | Use inline evaluation rubric |
mcp__tavily__tavily_search | Deep web search | WebSearch (CC built-in) |
Implementation Pattern
# Read capabilities (written by MCP probe at skill start)
caps = JSON.parse(Read(".claude/chain/capabilities.json"))
# Pattern: check before every MCP call
if caps.memory:
results = mcp__memory__search_nodes(query="auth error patterns")
# Use results to enrich analysis
else:
# T1 path: search codebase directly
Grep(pattern="auth.*error", glob="**/*.ts")
# Slightly less context, but still functionalRules
- Never assume MCP exists — always check
capabilities.json - Never error on missing MCP — skip gracefully with fallback
- T1 must produce useful output — reduced quality is OK, failure is not
- Log which tier is active — include in handoff files (
mcps_usedfield)
Worktree Agent Pattern
Worktree-Isolated Agents
Use isolation: "worktree" when spawning agents that write files in parallel. Each agent gets its own copy of the repo — no merge conflicts.
When to Use
| Scenario | Use Worktree? | Why |
|---|---|---|
| 3 agents implementing different modules | YES | Each edits different files, may overlap |
| 3 agents investigating a bug (read-only) | NO | Only reading, no conflicts possible |
| 2 agents: one backend, one frontend | YES | Both may edit package.json, config files |
| 1 agent running tests | NO | Single agent, no conflict risk |
| Agent doing code review | NO | Read-only analysis |
Pattern
# Launch parallel agents with worktree isolation:
Agent(
subagent_type="backend-system-architect",
description="Implement backend auth",
prompt="Implement auth API endpoints...",
isolation="worktree", # ← gets own repo copy
run_in_background=true # ← non-blocking
)
Agent(
subagent_type="frontend-ui-developer",
description="Implement frontend auth",
prompt="Implement auth UI components...",
isolation="worktree",
run_in_background=true
)How It Works
- CC creates a git worktree (separate directory, own branch)
- Agent works in the worktree — edits don't affect main working directory
- On completion, agent's changes are on a separate branch
- Parent skill merges the branches back
Hooks That Fire
WorktreeCreate→worktree-lifecycle-logger(logs creation)WorktreeRemove→worktree-lifecycle-logger(logs cleanup)SubagentStart→unified-dispatcher(logs agent spawn)SubagentStop→unified-dispatcher(logs completion)
Limitations
- Worktree agents are slightly slower to start (~2-3s overhead)
- Each worktree is a full copy — uses disk space
- Merge conflicts possible if agents edit same files (rare with proper task splitting)
- Don't use for read-only agents — unnecessary overhead
Business Case
Business case analysis with ROI, NPV, IRR, payback period, and TCO calculations for investment decisions. Use when building financial justification, cost-benefit analysis, build-vs-buy comparisons, or sensitivity analysis.
Checkpoint Resume
Rate-limit-resilient pipeline with checkpoint/resume for long multi-phase sessions. Saves progress to .claude/pipeline-state.json after each phase. Use when starting a complex multi-phase task that risks hitting rate limits, when resuming an interrupted session, or when orchestrating work spanning commits, GitHub issues, and large file changes.
Last updated on