Diagnostics Model
drwn doctor and drwn status share one diagnostics engine. Both are report-only: they never mutate the store, downstream tool config, or write records. This page covers what each command checks, how they overlap with the write pipeline's hard-fail contracts, and where to look when something looks wrong.
Doctor: Report-Only Across Five Detector Categories
drwn doctor runs every detector and renders a structured report:
drwn doctor
drwn doctor --json
The categories surfaced:
- Broken skill entries in downstream skill directories — drwn-owned entries whose content no longer exists
- Stale downstream skill entries — drwn-owned skill entries that no longer correspond to any active skill
- MCP drift in Claude
settings.json, Codexconfig.toml, or Cursormcp.json— the managed content has been modified outside drwn - Hook issues — a locked card declares hook policies but no hook consent has been recorded via
drwn card trust.drwn writewill not materialize hooks until consent is granted. - Project config issues — unknown servers in
project.servers, unknown skills inskills.include, unknown extensions, stale target overrides, unavailable card skills, and danglingdefaultsreferences
doctor reports issues. It never fixes them. The intent is that an operator (or an agent following a skill) reads doctor output, decides what to do, and then runs the right command (drwn write, drwn card update, drwn library defaults remove, and so on).
See reference/cli/doctor for the command surface and troubleshooting/reading-doctor for how to triage common output.
Hook issues
hookIssues fires when a locked card declares hook policies (in its card.lock entry) but no hook consent has been recorded for that card. drwn write will skip hook materialization for the card until consent is granted.
Resolve by reviewing and trusting the card's hooks:
drwn card trust @your-handle/backend --hooks
drwn write
Use --range to scope consent to a specific semver range. drwn card untrust @your-handle/backend revokes consent.
Status: As-Written vs As-Active, Plus Provenance
drwn status has three modes:
drwn status
drwn status --explain
drwn status --why <name>
- Default mode renders concise per-target and per-source counts plus the full diagnostics sections in JSON form.
--explainadds a human-readable explanation of the same sections.--why <name>answers a provenance question: which layer (card, project overlay, machine default, packaged registry) is making this skill, server, extension, or card active.
--why is the right command before a write when an operator is unsure why a given skill or server is appearing in the effective state. It is the inverse of doctor: doctor surfaces problems, --why explains decisions.
See reference/cli/status for flag details.
The Write-Time vs Doctor-Report Split
skills.include is the canonical example of how the two surfaces relate:
- At write time, an unresolved
skills.includename fails the run before any filesystem mutation.drwn writerefuses to leave the project half-applied. - At report time,
drwn doctorsurfaces the same condition as a project-config diagnostic and returns normally so the rest of the report still renders.
This split is deliberate. Materialization must be all-or-nothing for skills; diagnostics must always finish so the operator gets a complete picture.
The same pattern applies to other write-time invariants (corrupt card store, integrity mismatch, name collision): write and install raise typed errors; doctor and status surface them as diagnostics.
Managed-Field Drift Detection
The _drwn meta block written into Claude settings.json and Codex config.toml is how diagnostics know whether a user has hand-edited drwn-managed content.
The block contains:
{
"version": 1,
"managedKeys": ["mcpServers"],
"fieldHashes": { "mcpServers": "sha256-..." },
"lastWriteAt": "..."
}
On each write, drwn parses the current file, reads the prior _drwn block, recomputes the canonical hash of each managed key, and aborts the merge if any recorded hash diverges (unless --force is passed). doctor runs the same comparison and reports the divergence as MCP drift without aborting anything.
Canonical hashing sorts object keys recursively before sha256 so semantically equivalent edits — reordered keys, whitespace differences — do not register as drift. Only meaningful content changes trigger the report.
Cursor's standalone JSON format means drwn owns the whole file as managed-content. There is no meta block; doctor instead reports mcpDrift when the written content no longer matches the recorded hash.
Store and Write Record Diagnostics
Both doctor and status --explain include:
- store status: schema version, card count, source count, skill-bundle count, MCP-server count, legacy-layout detection
- write-record status: presence, corruption, managed-path count, last write timestamp, and the harness version that produced the last write
A missing write record is normal on a fresh project; a corrupt one is reported so the operator can decide whether to delete it and re-run drwn write.
Cross-References
- reference/cli/doctor for the command surface
- reference/cli/status for status modes
- troubleshooting/reading-doctor for triage
- Ownership and Write Records for the meta-block and ledger model