Documentary record · claude-library (clib) · April – July 2026

The Evidence Chronicle

Every load-bearing claim in clib's history — who asserted it, who challenged it, how it was tested, and what survived. Each piece of evidence is attributed to one of six source classes, because the record shows the classes have very different track records. Purpose: this is a field guide for teams adopting Anthropic tooling — one real project's paper trail of what model-driven development gets right, where it silently drifts, and how to catch it. The transferable cautions are at the end.

9validated
5debunked
1misleading
2unresolved
2fact-check verdicts overturned

One claim, one verdict. An exhibit that involves more than one claim states each claim and stamps each separately — a verdict never has two resolutions. Findings that emerge alongside a verdict (a bonus discovery, a real defect behind a wrong attribution) are recorded as evidence, not stamped.

Evidence classes — in order of demonstrated reliability
EMPIRICAL
Observed behavior of the actual machine or product. Live filesystem reads, headless claude -p probes, error output proving execution, scratch-DB migration runs, the interpreter's own AST. Never overturned in this record. Highest authority.
BILL
Assertions and challenges made by the user — the only party with continuous memory. Every Claude session in this record started amnesiac; Bill is the sole thread connecting them, navigating rather than adjudicating. His challenges read as course corrections from the one participant who was present for all of it — which is why they kept surfacing contradictions no single session could see. When he ran something, the result is chipped EMPIRICAL.
ANTHROPIC
Official online documentation, changelog, and issue tracker. Authoritative but incomplete — twice contradicted by observed machine behavior in this record (Exhibits C, D).
REPO
Artifacts persisted in the repository — the config reference doc, CLAUDE.md, docs/v2requirements.md, and the code itself. Honest attribution: these were also written by Claude, across many sessions, with Bill as editor and integrator. Each of the repo's 24 commits is a discrete Claude-driven session, and the log is direct documentary evidence of the drift — messages like fix4, overhaul again, well well well well well, and diffs that visibly flip decisions back and forth are the seam lines between sessions that shared no memory. REPO is not an independent witness; it's model output that survived long enough to be treated as consensus.
MODEL · APR
Claude's responses in prior sessions (the ~April founding session; the June 28 incident session). Confident, sometimes tested, sometimes not — the chips note which session. Distinct from Bill's side of those same conversations.
REVIEW · JUL 12
Today's audit outputs — the architect, six bounded workers, and the docs-check agent. Also model-generated, and held to the same standard: two of its verdicts were overturned by EMPIRICAL evidence within the same day (that's the point of separating it).
Reading order — by blast radius, not chronology

Exhibit letters are stable citation anchors assigned at admission; presentation order is severity. The keystone comes first, minor claims last.

F
Keystone. Deferred loading — the tool's central premise. Broke importing, deploying, injecting, maintaining, and catalog back-referencing at once.
A · B
Dead features. The import syntax that silently killed contexts (a facet of F's premise); the hook schemas no version ever accepted.
G · H
Platform limits and the workaround. The flat one-level namespace that still constrains everything; the undocumented symlink discovery the delivery mechanism rests on.
I · J
Silent failures. The June 28 out-of-contract incident; phantom-version catalogs.
C · D · E
Config-surface claims. Where the machine overturned the docs, and where a user test overturned the model.
K · L · M
Minor. A refuted review claim, a settled preference, residuals.
EXHIBIT FSkills-push / contexts-pull architecture (auto-discovery + progressive disclosure)KEYSTONE — LARGEST BLAST RADIUS

This is the central premise of the entire tool: deferring loads. Get it wrong and every downstream function breaks at once — importing (inert @import lines, Exhibit A is the syntax facet of this same premise), deploying and injecting (eager @import regions defeating the budget), maintaining (eject anchored to the wrong inventory), and back-referencing the catalog (CLAUDE.md region vs filesystem vs DB disagreeing about what's installed). Every other exhibit is a component failure; this one is the load-bearing wall.

Provoked
BILLCaught domain bleed in the drafted skills ("springbig.members is not only wrong depending on postgres vs redshift…") and asked how org knowledge could be reused without contaminating generic skills — the challenge that forced the layering.
Asserted
MODEL · APRDesign response: "skills are pushed (auto-discovered based on description matching), domain contexts are pulled (explicitly imported by the project that needs them)." The three-layer architecture rests on it.
Violated
REPO · cli/inject.pyBetween spec and implementation, inject gained a CLAUDE.md @import region for skills — force-loading bodies native discovery would lazy-load. Author: a later Claude implementation session contradicting an earlier Claude design session, with no shared context between them to catch it.
Tested
ANTHROPIC · skills docsProgressive disclosure confirmed. EMPIRICAL · headless probeLive run saw all ~75 user skills plus project probes surfaced by name+description only.
Verdict
VALIDATED — THE REPO WAS THE DEVIATION  The Jul 12 inject rework is a return to the founding spec, not a redesign.
EXHIBIT A@import <path> as CLAUDE.md import syntax
Asserted
MODEL · APR"CLAUDE.md supports @import to pull in shared instruction sets. That's your actual composability layer today." Example project files written as @import ~/.claude/domains/springbig/…. Never demonstrated working in the session.
Codified
REPO · config docREPO · imports_mgr.py:42Layer 2/3 architecture examples use @import; clib emits f"@import {path}" and its parser expects the same prefix. The consensus inherited the untested assertion.
Challenged
ANTHROPIC · memory docsREVIEW · JUL 12Official syntax is bare @path; an @import … line is inert text. Every context "imported" through the region silently never loaded.
Tested
REVIEW · transcript auditAll 52 pages of the founding session searched for a counter-example: @import asserted repeatedly, never once observed loading content. No working-era evidence exists. Ironic corollary: the harmful inject region used correct bare-@ and worked; the legitimate contexts region used @import and never did.
Verdict
DEBUNKED — MODEL ASSERTION, NEVER VALIDATED  Fixed Jul 12: writer emits bare @path, parser reads both forms, legacy regions self-heal. EMPIRICAL · JUL 12 post-fix, clib imports add wrote a valid @/Users/…/contexts/personal/defaults.md line — contexts loadable for the first time.
EXHIBIT BFlat SessionStart hook objects {command, timeout: 10000}
Asserted
REPO · provision.py:274REPO · match.py:57Two implementations, two different flat shapes (one with an invented marker key), neither aware of the other. Author: Claude, in later implementation sessions now lost to transcript retention — writing from memory instead of the founding session's own correct nested examples. Model-to-model drift across sessions that shared no context.
Counter-evidence
MODEL · APRThe founding session's own hook examples used the correct nested form. EMPIRICAL · in-sessionAnd the transcript captures nested hooks executing: SessionStart:startup hook error — Failed with non-blocking status code is proof of firing. The repo diverged from its own source material.
Challenged
REVIEW · surface workerANTHROPIC · hooks docsNested {matcher, hooks:[{type, command, timeout(seconds)}]} since hooks shipped (v1.0.38). Flat shapes silently ignored; timeout: 10000 also ms-vs-seconds confused.
Verdict
DEBUNKED — IMPLEMENTATION DRIFT, NEVER VALID IN ANY ERA  Fixed Jul 12: shared application/hooks.py helper — nested schema, seconds, mutual idempotency, in-place upgrade of legacy entries. 9 unit tests.
EXHIBIT GNested skill hierarchies are unsupported — the scan is one level deep
Asserted
BILL"I put the full configuration files in my claude root, but it doesn't seem to pick up any of the skills." EMPIRICAL · in-sessionNested two-level taxonomy demonstrably not discovered. ANTHROPIC · issues #18192/#39138Limitation documented on the tracker. 27 skills flattened to {category}-{name} live in that session; REPO clib inherited it as symlink_name.
Challenged
ANTHROPIC · changelog"Nested .claude/skills/ loading added ~v2.1.190+" — suggesting the limitation may have lifted and flattening might now be legacy cruft.
Tested
EMPIRICAL · headless probe · JUL 12Live claude -p run: flat skills/flat-probe/ ✓ discovered · nested skills/nested/depth-probe/ ✗ absent. (The symlink probe from the same run is Exhibit H — a separate finding.)
Verdict
VALIDATED — STILL TRUE TODAY  The scan is one level deep; flattening remains required. The changelog hint did not survive contact with the machine.
Implication
Validated does not mean acceptable. A one-level scan makes skills/ a flat namespace with zero hierarchy: no grouping by domain, vertical, or class; taxonomy demoted to name-mangling conventions (data-dba, lang-python); and common task names across domains can only coexist as atomic files that risk clobbering each other in the one shared namespace. This is a standing platform deficiency, not a solved problem — and it is a load-bearing part of clib's necessity case: the catalog's namespace/section/rules model is the hierarchy layer the platform lacks, with flattened symlink names as mere wire format. Recorded as a structural consequence, not stamped: it's an assessment, not a testable claim.
EXHIBIT HSymlinked skill directories are discovered natively
Initial design
MODELThe original deployment design copied assets into each repo — defeating the library's purpose, since isolated clones drift out of sync with the source of truth. The design's fossils survive in the codebase: deployer.py's copytree path, the deprecated deploy/auto commands, and profile use --apply.
Challenged
BILLSuggested symlinking instead — one source of truth in the store, links as the deployment. Adopted and tested together; REPO clib inject has been symlink-based since.
Docs status
ANTHROPICSilent on symlink discovery to this day — an undocumented-but-working mechanism, same class as Exhibit C (~/.mcp.json). The two behaviors this setup most depends on are the two the docs don't mention.
Tested
EMPIRICAL · headless probe · JUL 12Re-confirmed in isolation for the first time: skills/linked-probe → elsewhere ✓ discovered by name+description like any real directory.
Verdict
VALIDATED — BILL'S WORKAROUND, UNDOCUMENTED, MACHINE-CONFIRMED  The assumption inject's entire delivery mechanism rests on holds. Residual risk: undocumented behavior carries no compatibility promise — re-probe after major Claude Code updates (the probe is one claude -p invocation).
EXHIBIT I"Claude Code updates dropped my imported library" (June 28)
Claimed
BILL · JUN 28"You have a few updates, and it completely drops all of my imported library… we no longer have the agents." Read literally this sounds like an accusation of deletion — but the assets are git-backed and not meaningfully destroyable locally, and nobody claimed otherwise. The claim, properly read, is shorthand for: "after this process, the deployed catalog no longer matches the expected contract, so it's missing from your context."
Tested
EMPIRICAL · in-session diagnosisDirect inspection confirmed exactly that: every store/agent/<name>/ dir malformed into a flat copy of all 11 agents with no AGENT.mdprovision agents silently skipped all of them → 11 dangling symlinks → zero agents in context. Content intact throughout; contract broken. REVIEW · JUL 12The re-keying timing (May 5 / Jun 4) aligns with clib's own v7 migration — the drift was internal to the amnesiac-session pipeline, not a Claude Code update.
Verdict
VALIDATED — AS MEANT  The catalog really was out of contract and absent from context. The only refinement the evidence adds is causal: the format drift came from a clib-side session's own migration, not the product update the shorthand pointed at. Fourth confirmed silent failure; motivates clib doctor (P1).
EXHIBIT J"Phantom v6" catalogs exist and corrupt silently
Asserted
REPO · migrations.py:371The 5→6 docstring admits "an earlier experimental build stamped some catalogs at version=6 without ever defining a v6 migration."
Tested
REVIEW · QA workerEMPIRICAL · scratch-DB reproReproduced against a real DuckDB file: a v6-stamped DB with only v1 schema skips migrations 1→5, reports itself fully current at v8, then throws an opaque BinderException on first write. No warning at any point.
Verdict
VALIDATED — GUARD SHIPPED  SchemaIntegrityError sentinel checks now fail loudly at open, naming the missing features. Tested for phantom and honest-v1 paths.
EXHIBIT CGlobal ~/.mcp.json is honored by Claude Code
Asserted
MODEL · APR"The file at ~/.mcp.json makes servers available in all projects" — and generated one (context7, clickup, cloudflare, postman, codebranch) with env-var token references. REPO · surfaces.pyCodified as clib's mcp_global surface and a config-doc table row.
Challenged
ANTHROPIC · MCP docsREVIEW · docs-check"Never existed as a recognized file — user scope has always been ~/.claude.json via claude mcp add --scope user." The findings register stamped this NEVER TRUE and queued a P0 fix to re-point the surface.
Tested
EMPIRICAL · live machine~/.mcp.json holds exactly codebranch + telnyx; ~/.claude.json has an empty mcpServers; no project .mcp.json — yet codebranch connected in a live Claude Code session. Only possible source: the "nonexistent" file.
Verdict
VALIDATED — DOCS-BASED VERDICT OVERTURNED  The April model response was right; official docs are incomplete. clib's surface model vindicated; P0 item dropped.
EXHIBIT D~/.claude/settings.local.json as a user-level scope
Asserted
MODEL · APRListed as user-local overrides. BILLChallenged it mid-session ("you actually said that is where I manage my config and not to touch settings.json"). MODEL · APRConceded the earlier framing was wrong, then re-affirmed the file exists at lower priority. REPO · config docCodified in the file table and precedence list.
Challenged
ANTHROPIC · settings docsREVIEW · docs-check"Does NOT exist as a recognized file — only project-level .claude/settings.local.json." Register initially agreed: remove from the doc.
Tested
EMPIRICAL · live machineThe file exists, populated with keys Claude Code itself manages: disabledMcpjsonServers, enableAllProjectMcpServers, permissions.allow.
Verdict
VALIDATED (LIKELY) — DOCS-BASED VERDICT OVERTURNED  Harness-written keys are strong evidence of recognition. Doc stands as written.
EXHIBIT EThe settings.json env block — two claims, one test
Asserted
MODEL · APRRecommended "PATH": ".../proto/shims:${PATH}", claiming expansion works ("the ${PATH} version is self-maintaining").
Tested
BILLDeployed it for real, same conversation. EMPIRICAL · in-sessionResult: SessionStart:startup hook error — env: bash: No such file or directory / python3: command not found. PATH had been set to the literal string. The model corrected on the evidence: settings.json does NOT expand ${VAR}; .mcp.json does.
Consequence
REPO · v2 requirements R5The failure birthed clib env sync / env_mgr.py, on the theory that "the static block drifts by design, so tooling must re-sync it."
Refined
BILL · JUL 12Independent post-hoc root-cause determination: the recurring env breakage wasn't primarily config staleness — it's that the macOS Desktop app and certain IDE terminal subshells silently run bash and never source the zsh dotfile setup (ZDOTDIR, paths.d/*), so zsh-configured environment — and sometimes zsh syntax — was being run through bash. R5 was designed against a partially mischaracterized mechanism, and env sync has barely been used since. The correct diagnosis was scattered through the founding transcript the whole time (Dock launches get the bare system env; Claude Code hardcodes ~/.zshrc and ignores ZDOTDIR, issue #11635; the Bash tool uses bash) — but no session assembled it into the requirement. EMPIRICAL · this sessionCorroborated live today: a Bash-tool subshell failed with command not found: curl/head before absolute paths succeeded — same failure class, still occurring.
Claim E1
The settings.json env block is honored by Claude Code. The failure is the proof: a mis-set PATH could only break hook execution if the block were applied. Also closed today's last open schema question. VALIDATED
Claim E2
${VAR} expands inside that block. Refuted by Bill's own deployment minutes after the model asserted it — PATH was set to the literal string. (.mcp.json does expand ${VAR}; the two files parse differently.) DEBUNKED
EXHIBIT KThe profiles.py:54 "real bug" (Python-2 except binding)
Asserted
REVIEW · profiles workerClaimed except orjson.JSONDecodeError, OSError: binds OSError as a variable and catches only the first type — "verified empirically on 3.14.4."
Counter-claim
REVIEW · surface workerIndependently called the identical construct valid PEP 758 tuple syntax. Two model "verifications", mutually exclusive.
Tested
EMPIRICAL · live interpreterAST dump: Tuple(ValueError, OSError), handler name None. Runtime: both exception types caught. Python 3.14.4, this repo's interpreter.
Verdict
DEBUNKED — A MODEL'S "EMPIRICAL" CLAIM THAT WASN'T  Style/portability nit only. Review outputs get no exemption from the hierarchy.
EXHIBIT Lattribution: "false" as a string value
Asserted
MODEL · APRInferred boolean/custom-string semantics from search results.
Challenged
BILL"Nope, they will not expect a boolean, I'm going to try the string 'false'."
Tested
EMPIRICAL · in-sessionThe string form worked and persists in ~/.claude/settings.json today; the model conceded "your real-world testing is more reliable than my inference from search results."
Verdict
VALIDATED — USER TEST BEAT MODEL INFERENCE
EXHIBIT MResidual minor claims
"Setup" event
MODEL · APRREPO · config docUsed for per-session toolchain activation. ANTHROPIC · hooks docsSetup exists but fires on --init/--maintenance; SessionStart + matcher startup is correct per-session. MISLEADING — WRONG USAGE
Hook env vars
REPO · config doc$CLAUDE_FILE_PATH / $CLAUDE_TOOL_INPUT. ANTHROPIC · hooks docsHooks receive stdin JSON; no evidence these vars ever existed in any source class. DEBUNKED
XDG support
MODEL · APR"Partial support — ~/.claude can respect XDG_CONFIG_HOME." ANTHROPICNot in current docs. EMPIRICALNever observed; the symlink workaround is what actually runs, and runs fine. UNRESOLVED
mcpServers in settings.json
REPO · config docClaimed as an alternative to ~/.mcp.json. ANTHROPICDocs say no — but after Exhibit C, docs-say-no is not dispositive; no machine evidence either way. UNRESOLVED

What the progression shows, by source class

EMPIRICAL is undefeated. No observation of the machine was ever overturned in this record — not the in-session hook failures, not the live filesystem reads, not the headless probes, not the scratch-DB reproductions. Everything else was overturned at least once.

BILL is the continuity layer, and that — not omniscience — is why the challenges landed. The user was navigating an unfamiliar tool, not adjudicating it; but as the only participant present across every session, he was also the only place cross-session contradictions could surface. The domain-bleed catch created the contexts layer (Exhibit F); the symlink suggestion replaced a copy design that would have drifted (H); the attribution pushback beat model inference (L); the settings.local.json challenge exposed a model self-contradiction (D); "you'll excuse me if I'm skeptical" overturned two fact-check verdicts (C, D); and even the shorthand of Exhibit I was a correct reading of the observable symptom. In a system where every other author is amnesiac, the human's accumulated friction is the institutional memory.

ANTHROPIC docs are necessary but describe a subset of the product. They correctly killed @import and the flat hook schema — and were contradicted by the machine on ~/.mcp.json and user-level settings.local.json. Observed behavior is a superset of documentation.

REPO artifacts are consensus snapshots, not truth — and they're Claude's writing too. The config doc and clib's code (both model-authored, Bill-curated) faithfully preserved the good empirical lessons (flattening, env sync) alongside the untested model assertions (@import) — and added drift of their own (flat hooks, skill @imports) where a later Claude session, writing without the earlier session's context, contradicted the earlier Claude's correct work.

MODEL and REVIEW assertions are hypotheses until tested. April's model was right about ~/.mcp.json and wrong about ${VAR} expansion; July's reviewers were right about hooks and wrong about ~/.mcp.json. Same class, same failure mode, opposite directions — which is why the class, not the date, is what the chips track.

The uncomfortable census: of the six classes, four — MODEL, REVIEW, REPO, and even the config doc this audit began by fact-checking — are Claude's own output at different moments, checking and contradicting itself across sessions that share no memory. The only independent witnesses in the entire record are BILL, ANTHROPIC, and the machine itself. That is the structural argument for the evidence hierarchy: when four of your six sources are the same fallible author wearing different timestamps, you privilege the two that aren't — and the machine outranks everyone.

Cautions for teams adopting Anthropic tooling

What this record generalizes to. Each caution cites the exhibits that earned it.

1. Treat model-asserted configuration as a hypothesis, and test it the moment it's written. The most expensive errors here were schemas Claude stated confidently and nobody ran: an import keyword that was never real (A), a hook shape no version ever accepted (B). Both were cheap to verify at generation time — a one-line probe, a read of the file another tool actually consumes. The cost of not verifying was months of a silently dead feature. (Exhibits A, B, E2)

2. Don't trust the docs as a ceiling either — the product's observed behavior is a superset of its documentation. Two "the docs say this doesn't exist" verdicts died on contact with the live machine (C, D). Before ripping out something that works, or building on something documented, check what the machine actually does: read the real config files, run a headless probe, watch what loads. (Exhibits C, D, G, H)

3. Session amnesia is the root hazard of model-driven development. Every session starts with no memory of the last one. This repo's git log is the fossil record: 24 commits, each a discrete Claude session, with diffs that flip prior decisions and messages that chart the frustration. A later session contradicted an earlier session's correct design (F) and its correct hook examples (B) because nothing carried the context forward. Mitigations: persist decisions in repo docs the next session will read, review diffs specifically for silent reversals, and keep one human continuously in the loop — their accumulated friction is the only institutional memory the system has. (Exhibits B, F; the git log)

4. Expect failures to be silent, and build fail-loud checks into anything that writes config another system consumes. Claude Code ignores invalid config rather than rejecting it: bad hooks are skipped, inert import lines render as text, malformed stores provision zero assets without a word. Every breakage in this record announced nothing, which is why each one read as "the product broke." If your tool writes settings, hooks, or assets for another system, ship a doctor command that asserts the contract end-to-end. (Exhibits A, B, I, J)

5. Prefer the platform's native primitives over re-implementing them — but know where the primitives end. The single largest blast radius here (F) came from re-implementing loading that the platform had made native — auto-discovery and progressive disclosure. The founding design got this right; a later implementation session drifted into fighting the platform. At the same time, the primitives have real gaps teams will hit at scale: skills/ is a flat, one-level namespace with no hierarchy — no grouping by domain or vertical, taxonomy only by naming convention, and collision risk once multiple teams contribute skills. Plan a taxonomy layer (a catalog, a naming contract, or both) before your skill count grows past what one flat directory can carry. And favor symlinks over copies for anything deployed from a shared library — copies drift, and the platform discovers symlinked dirs even though the docs don't say so. (Exhibits F, G, H)

6. Read user reports as symptom descriptions, not literal mechanism claims. "It dropped my agents" meant "the deployed catalog no longer matches the contract, so it's absent from context" — accurate observation, compressed. Triage the observable symptom (what's missing from context, what file diverged from what schema) before litigating the attribution. (Exhibit I)