Skip to main content
OrchestKit v7.75.0 — 107 skills, 37 agents, 185 hooks · Claude Code 2.1.118+
OrchestKit
Skills

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.

Reference medium

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 error

Load 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_phases

Load 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 monitor

Key difference from CronCreate:

  • /loop can invoke skills: /loop 20m /ork:verify (CronCreate can't)
  • Both use the same underlying scheduler (50-task limit, 3-day expiry)
  • Skills use CronCreate for agent-initiated scheduling
  • Skills suggest /loop in "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

RuleImpactKey Pattern
rules/probe-before-use.mdHIGHAlways ToolSearch before MCP calls
rules/handoff-after-phase.mdHIGHWrite handoff JSON after every major phase
rules/checkpoint-on-gate.mdMEDIUMUpdate state.json at every user gate

References

Load on demand with Read("$\{CLAUDE_SKILL_DIR\}/references/<file>"):

FileContent
mcp-detection.mdToolSearch probe pattern + capability map
handoff-schema.mdJSON schema for .claude/chain/*.json
checkpoint-resume.mdstate.json schema + resume protocol
worktree-agent-pattern.mdisolation: "worktree" usage guide
cron-monitoring.mdCronCreate patterns for post-task health
experiment-journal.mdAppend-only TSV log for try/measure/keep-or-discard cycles
progressive-output.mdProgressive output with run_in_background
sendmessage-resume.mdSendMessage auto-resume (CC 2.1.77)
tier-fallbacks.mdT1/T2/T3 graceful degradation
  • ork:implement — Full-power feature implementation (primary consumer)
  • ork:fix-issue — Issue debugging and resolution pipeline
  • ork:verify — Post-implementation verification
  • ork: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 3

Correct

# 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 gone

Correct

# 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 continues

Which 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 runtimeNotify?
< 2 minNo — user is still at the terminal.
2–5 minOptional — only if the skill has parallel agents or external I/O that makes timing unpredictable.
> 5 minYes. 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 it

Correct

# 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_report

The title names the skill; the body summarizes the outcome in one line. Users filter their notification center by title, so keep it stable: "ork:&lt;skill&gt; complete" or "ork:&lt;skill&gt; 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.

  • 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 PreCompact hook 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.json at a time. Starting a new skill overwrites.
  • Stale state: If state.updated is 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 CronDelete condition — don't leave crons running forever
  • Use descriptive prompts so the cron agent knows what to check
  • Prefer gh CLI over curl for 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 status
  • verify / cover — log optimization attempts with metric deltas
  • implement — log iterative optimization attempts (performance, bundle size, prompts)
  • fix-issue — log attempted fixes with pass/fail

File Location

.claude/experiments/{skill}-{topic-slug}.tsv

Examples:

  • .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 activation

Column Reference

ColumnTypeDescription
timestampISO-8601When the experiment was logged
scorefloatComposite score (brainstorm) or metric value (optimization). 0.00 for crashes
statusenumkeep, discard, or crash
reasonstringWhy discarded: overkill, infeasible, duplicate, regression, complexity, untestable. - for keeps
commitstringGit short SHA if code was committed, - otherwise
descriptionstringShort 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 run

Trajectory 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 strategy

When 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:

ConditionRequirement
No custom modelAgent inherits parent model (no model= parameter)
No worktree isolationNo isolation: "worktree" parameter
Short promptPrompt body < 500 words (only the divergent part)
Same tool schemaAgent 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-tokenized

Cost: ~1.1× instead of ~3× for 3 parallel agents.

When NOT to Fork

ScenarioWhyUse Instead
Agent needs worktree isolationFile edits conflict between forksAgent(isolation="worktree")
Agent needs custom modele.g., Haiku for cheap analysisAgent(model="haiku")
Agent reads prior phase handoffHandoff file not in cache prefixStandard Agent() with file content in prompt
Coordinator mode activeCoordinator disables forksStandard Agent()
Agent needs permission_mode: "bubble"Prompts appear in parent terminalOnly if acceptable UX

Fork-Eligible Skills

SkillAgentsFork-ReadyNotes
explore4 parallelAll read-only, no worktree
brainstorm3-5 parallelDivergent ideation, no state
verify6-7 parallel⚠ partialDomain filter runs in parent; fork after filtering
review-pr6-7 parallel⚠ partialContext injection in parent; fork the review agents
implement3 parallelWorktree isolation required
fix-issue1-5 parallelWorktree 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

FieldTypeDescription
phasestringPhase identifier (kebab-case)
phase_numbernumberNumeric phase index
skillstringParent skill name
timestampstringISO-8601 timestamp
statusstringcompleted or failed
outputsobjectPhase-specific results
next_phasenumberNext 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 5

Cleanup

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

TierServersWho Has It
T1: CoreNone (CC built-in tools only)Every CC user
T2: Enhancedmemory, context7, sequential-thinkingMost CC users (free npm MCPs)
T3: Powertavily, agent-browserPower 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.json so 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 approachCostFailure mode
Spawn a subagent via Agent() from inside the hook30–60s + ~150K tokensHook timeouts, context budget blown
Shell out to npx -y &lt;mcp-server&gt; and parse stdout2–5s + brittle parsernpm 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:

  1. Resolve the MCP server (must be enabled in .mcp.json)
  2. Dispatch the tool call with input (templated against the hook's input)
  3. 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

SituationUse instead
MCP server is disabled: true in .mcp.jsonSkip the hook (it'll fail at dispatch)
You need to gate on the MCP responseSubagent — mcp_tool doesn't support conditional logic in-place
The hook needs MCP output for >1 downstream MCP callSubagent — 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

PathColdWarmCost (tokens)
Subagent spawn30–60s30–60s~150K
Shell npx -y2–5s0.3–1s~0
type: "mcp_tool"0.1–0.3s0.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.

  • chain-patterns/references/monitor-patterns.md — Monitor tool for streaming process output
  • src/skills/mcp-patterns/references/mcp-version-matrix.md — Tier classification for .mcp.json entries
  • src/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

SituationUse
Background build/test/long scriptMonitor — stream progress live
Finished task, need its final outputTaskOutput(task_id) — one-shot read (no block=true needed)
Gate entry on matching stdout lineMonitor + 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..." lies

Applies 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 visible

Applies 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 tokens

Anti-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.

  • 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 &lt;version&gt; runs validation across the plugin manifest hierarchy:

CheckSource of truthFailure mode
Marketplace version matches.claude-plugin/marketplace.json versionTag rejected
Plugin .claude-plugin/plugin.json matchesper-plugin manifestTag rejected
package.json version matchesrepo rootTag rejected
version.txt matches (if present)repo rootTag rejected
No uncommitted changes in plugins/working treeTag rejected
Plugin can be loadedclaude plugin validate (CC ≥ 2.1.77)Tag rejected

If all pass, an annotated git tag v&lt;version&gt; 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

SkillSection to update
src/skills/release-management/SKILL.mdAdd claude plugin tag to the validation checklist
src/skills/release-checklist/SKILL.mdPre-release verification step
src/skills/release-sync/SKILL.mdDetect 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-stage

Without 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.1

Three 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"
  • .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 ownership
  • src/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 familyURL patternDetection regex
github.com (public)https://github.com/\{owner\}/\{repo\}/pull/\{n\}^https://github\.com/
GitHub Enterprisehttps://\{host\}/\{owner\}/\{repo\}/pull/\{n\} (host suffix .github.&lt;corp&gt;)\.github\.[a-z]+/
GitLab.comhttps://gitlab.com/\{owner\}/\{repo\}/-/merge_requests/\{n\}^https://gitlab\.com/
Self-hosted GitLabhttps://gitlab.\{corp\}/\{group\}/\{repo\}/-/merge_requests/\{n\}^https://gitlab\.
Bitbucket Cloudhttps://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:

  1. Parse the URL with the host-detector helper (src/hooks/src/lib/pr-host-parser.ts).
  2. Branch on host_family for 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)
  3. Fall back to github.com defaults 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'tDo
Hardcode github.com in skill copyParameterize via the host-detector helper
Assume gh CLI is available for non-GitHubFall back to REST or document the dependency
Crash on unrecognized URLDefault 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 parsePrUrl from src/hooks/src/lib/pr-host-parser.ts
  • Replace github.com regex with parser call
  • Branch on family for any CLI/REST calls
  • Document prUrlTemplate in the skill's configuration section
  • Add fixture tests for at least 3 host families
  • Update SKILL.md with explicit support table
  • 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/prUrlTemplate documentation

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 verification

Cache-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.

DelayCacheUse When
60–270sWarmActive work — build running, CI check pending, process just started
Never 300sWorst of bothCache miss without amortizing the wait
300–3600sColdGenuinely idle — nothing to check for minutes
1200–1800sCold (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

AspectScheduleWakeupCronCreate
LifetimeSession-scopedPersistent
CleanupAuto (omit call)Manual CronDelete
PacingDynamic per-iterationFixed cron schedule
CacheAware (270s/1200s)Unaware
Best forIn-session pollingCross-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

TierMCP ServersInstallWho Has It
T1: CoreNoneBuilt into CCEvery CC user
T2: Enhancedmemory, context7, sequential-thinkingnpm install (free)Most CC users
T3: Powertavily, agent-browserAPI keys requiredPower users

Fallback Matrix

MCP ToolT2/T3 BehaviorT1 Fallback
mcp__memory__search_nodesSearch past decisionsSkip — rely on codebase Grep
mcp__memory__create_entitiesSave patternsSkip — patterns not persisted
mcp__context7__query-docsLive library docsWebFetch docs URL directly
mcp__sequential-thinking__*Structured reasoningUse inline evaluation rubric
mcp__tavily__tavily_searchDeep web searchWebSearch (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 functional

Rules

  1. Never assume MCP exists — always check capabilities.json
  2. Never error on missing MCP — skip gracefully with fallback
  3. T1 must produce useful output — reduced quality is OK, failure is not
  4. Log which tier is active — include in handoff files (mcps_used field)

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

ScenarioUse Worktree?Why
3 agents implementing different modulesYESEach edits different files, may overlap
3 agents investigating a bug (read-only)NOOnly reading, no conflicts possible
2 agents: one backend, one frontendYESBoth may edit package.json, config files
1 agent running testsNOSingle agent, no conflict risk
Agent doing code reviewNORead-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

  1. CC creates a git worktree (separate directory, own branch)
  2. Agent works in the worktree — edits don't affect main working directory
  3. On completion, agent's changes are on a separate branch
  4. Parent skill merges the branches back

Hooks That Fire

  • WorktreeCreateworktree-lifecycle-logger (logs creation)
  • WorktreeRemoveworktree-lifecycle-logger (logs cleanup)
  • SubagentStartunified-dispatcher (logs agent spawn)
  • SubagentStopunified-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
Edit on GitHub

Last updated on

On this page

Chain PatternsOverviewPattern 1: MCP Detection (ToolSearch Probe)Pattern 2: Handoff FilesPattern 3: Checkpoint-ResumePattern 4: Worktree-Isolated AgentsPattern 5: CronCreate MonitoringPattern 6: Progressive Output (CC 2.1.76)Pattern 7: SendMessage Agent Resume (CC 2.1.77)Pattern 8: /loop Skill Chaining (CC 2.1.71)RulesReferencesRelated SkillsRules (4)Checkpoint on Gate — MEDIUMCheckpoint on GateIncorrectCorrectWhyHandoff After Phase — HIGHHandoff After PhaseIncorrectCorrectWhich Phases Need HandoffsProbe Before Use — HIGHProbe Before UseIncorrectCorrectWhen to ProbePushNotification on Long-Skill Completion — MEDIUMPushNotification on Long-Skill CompletionWhen to applyIncorrectCorrectGraceful fallbackBody content rulesWhyRelatedReferences (13)Checkpoint ResumeCheckpoint-Resume ProtocolState SchemaResume FlowUpdate ProtocolWhen to CheckpointEdge CasesSession Context Restoration (CC 2.1.108+)Scheduled Task Recovery (CC 2.1.110+)Cron MonitoringCronCreate Monitoring PatternsCI Status MonitorRegression MonitorHealth CheckBest PracticesExperiment JournalExperiment Journal PatternWhen to UseFile LocationTSV FormatColumn ReferenceReading the JournalBefore Phase 1 (Memory + Context)Trajectory DetectionWriting to the JournalAfter Each ExperimentAfter Brainstorm Phase 4After Iterative Optimization LoopGit PolicyFork PatternFork Pattern — Cache-Sharing Parallel SubagentsWhen CC Forks AutomaticallyFork-Friendly Prompt TemplateWhat Forks InheritCache MechanicsWhen NOT to ForkFork-Eligible SkillsContext Stager BehaviorAnalyticsFallback StrategyHandoff SchemaHandoff File SchemaLocationSchemaRequired FieldsNaming ConventionCleanupSize LimitsMcp DetectionMCP Detection via ToolSearchProbe PatternUsage in Skill Phases3-Tier ModelImportant NotesMcp Tool HooksHooks Invoking MCP Tools — type: "mcp_tool"Why This Replaces Old PatternsThe New TypePattern 1 — Inject Memory Context Before EditPattern 2 — Read Annotation Queue After ReadPattern 3 — Sequential Thinking on Long TasksWhen NOT to UsePerformance EnvelopeTier CompatibilityRelatedMonitor PatternsMonitor Tool PatternsWhen to use MonitorPattern 1 — Streaming test executionPattern 2 — Streaming agent progressPattern 3 — Until-condition gatePattern 4 — Partial-result salvageAnti-patternsPolling TaskOutput in a loopTaskOutput(block=true) — deprecatedMonitor for one-shot commandsGraceful fallbackRelatedPlugin Tagclaude plugin tag — Plugin Release TaggingWhat It DoesOrchestKit Adoptionrelease-please integrationSkill referencesWhat Drift Looks LikeFailure Modes Pre-2.1.118Local WorkflowRelatedPr From Platform--from-pr Multi-Host SupportSupported HostsSkill AdoptionConfiguration: prUrlTemplateAnti-PatternsReference ImplementationMigration ChecklistRelatedScheduleWakeup — Dynamic Loop PacingScheduleWakeup — Dynamic Loop PacingWhen to UseCache-Aware Delay SelectionPatternsCI Status Polling (after PR creation)Post-Deploy Health CheckPost-Fix VerificationTerminationvs CronCreateAnti-PatternsTier FallbacksT1/T2/T3 Graceful DegradationTier DefinitionsFallback MatrixImplementation PatternRulesWorktree Agent PatternWorktree-Isolated AgentsWhen to UsePatternHow It WorksHooks That FireLimitations