> For the complete documentation index, see [llms.txt](https://docs.thecolliery.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.thecolliery.org/tools/coalwash/reference/platform-cc.md).

# Claude Code adapter

> The validated platform. Facts below are what `class-b.mjs` / the conductor implement — verified 2026-07-09; ⚠️ CC internals are version-sensitive, re-verify on a discovery miss (a missing dir degrades safe: no entries, no harm).

## Class-B map (what discovery finds)

| Surface            | Where                                                                                                              | Load behavior                                                                                 |
| ------------------ | ------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------- |
| Global governance  | `~/.claude/CLAUDE.md` + its `@import` closure (depth cap 5)                                                        | always-loaded, every session                                                                  |
| Project governance | the `CLAUDE.md` up-tree walk (cwd → home, never above) + each file's imports                                       | always-loaded                                                                                 |
| Rules tree         | `[project]/.claude/rules/**/*.md`                                                                                  | on-demand (recall cost) unless pulled in via an `@import`                                     |
| Memory index       | `~/.claude/projects/[slug]/memory/MEMORY.md` — slug = the absolute project path, every non-alphanumeric char → `-` | always-loaded; platform cap class \~25KB / \~200 lines (the caliper's absolute-cap tripwires) |
| Memory files       | sibling `*.md` in the same dir                                                                                     | on recall only — count toward total-store, not the per-session cost                           |

The per-session saving = the **always-loaded** subset delta; the receipt splits it from total-store. Discovery is read-only, realpath-and-contained to the home + project trees; an unresolvable/escaping candidate is skipped + flagged.

## Wiring + state files (all local, user-readable)

* **Conductor:** `hooks/hooks.json` → SessionStart + Stop → `hooks/coalwash-conductor.js` (Phoenix-13: fail-silent, no network, no spawn; SessionStart ONLY measures + caches — it never asks, at any band; Stop is the sole ask/directive surface and stays silent when no band crossing is pending).
* **Caliper state (per-project, rides the memory dir):** `~/.claude/projects/<slug>/coalwash/state.json` — beside Claude Code's own per-project memory folder — holds session stamps (ring-capped), the last recorded verdict + the certain-fat hysteresis bit + the economic latch (task #4 re-axed both onto MEASURED fat, not BMI), the pending once-per-crossing edge (no time-based snooze), and a legacy lean-floor field (task #4, 2026-08-03: inert history only — no gauge reads it for the band any more; fat and muscle are measured from content at every gauge). Sitting inside the platform's project dir means the platform's own lifecycle carries it: it is auto-removed when the project is (free orphan-prune), and rides along if the platform relocates `projects/`. Every derived path is realpath-contained to `~/.claude` (fail-closed to `~/.claude/coal/coalwash/` on any escape — never a write outside the sandbox). Loss degrades to bootstrap behavior: the hysteresis bit and the economic latch reset un-armed, and the very next gauge re-measures fat and muscle from content — the band is live immediately, with no floor-stamp or "first full clean" dependency to wait on. Migrated from the pre-relocation `~/.claude/.coalwash-state.json` automatically: read-new/fallback-old on read, write-new/delete-old on the first write.
* **Transaction dir:** `[project]/.claude/coalwash/` — `.coalwash.lock` (atomic-create + stale-timeout 30min + defer-on-doubt), `journal.json` (the WAL; CoalHearth-visible location — CH-side recognition lands in a CoalHearth release), `snap-[timestamp]/` (last 3 kept). This stays at the workspace (project data, correctly not in `~/.claude`). Named assumption: the lock's exclusive-create is atomic on a LOCAL filesystem; on a network/cloud-synced mount that guarantee may not hold — every acquire therefore re-reads the lock and defers on a foreign token (fail-closed), but a store kept on such a mount is still best moved local.
* **Config:** global `~/.claude/.coalwash.json` overlaid by the per-project override (walk stops at home, physical-path compare) — except a handful of safety keys (`coalwashMode`, `updateMode`, `writeGuard`, `localOnly`, `scanEverything`, `estate.deleteCold`), which merge safer-value-wins: a project may only quieten them, never escalate past a deliberate or unreadable global; `estate.archiveDir` is a REACH key, not a consent key — read from the global config only, a project value is ignored. For `scanEverything` the escalated value is `true` (see more), so the clamp runs the OPPOSITE way to `localOnly`'s — the direction of escalation is what decides the polarity, never the key's name. **Per-project read order (namespace campaign #69+#39, 2026-08-08, extended UMB-133 2026-09-22 — `projectConfigCandidates`/`projectConfigResolution`/`discoverIgnoredConfigs` in `config-load.mjs`):** `<project>/.claude/coal/coalwash.json` (Claude Code, the only running-agent identity this room's own hook ever runs under) → `.agents/coal/coalwash.json` → `.gemini/coal/coalwash.json` (first found wins) → **DEPRECATED:** `<project>/.claude/.coalwash.json` (the nested legacy shape, CoalTipple's/CoalBoard's own convention) → **DEPRECATED:** `<project>/.coalwash.json` at the root (the pre-2026-08-08 shape) — both legacy shapes are still read, nested-before-root. A legacy hit is reported by `config-status`/`/coalwash:stats`, never by an unconditional per-session line (this room's own hermetic sandbox default IS the root legacy shape, so a SessionStart nag would fire on the ordinary case); a `.coalwash.json` planted under `.agents`/`.gemini` bare (a shape this walk carries no nested-legacy candidate for) is reported ambiently on SessionStart instead, since that shape is genuinely rare. A config that EXISTS where the walk reads but cannot be used (`malformed JSON` · `a directory` · `not a JSON object` · `unreadable`) is reported on SessionStart too, as `UNREADABLE: <path> exists but is not a readable config (<reason>); it was skipped — canonical = <canonical>`; `config-status` does not carry it. `scripts/configure.mjs` is the write side of this same walk (it exists, contrary to an earlier note here) and performs no migrate-and-delete: a write lands back wherever a config was already found, legacy included, never relocated to canonical for you.
* **Update stamp (global):** `~/.claude/coal/coalwash/update-check` (a timestamp; the hook only schedules — the online check is `/coalwash:update`, consent-gated). Migrated from the pre-relocation `~/.claude/.coalwash-update-check` the same read-new/write-new-delete-old way.

## Capacity + spawn

* **Capacity denominator:** the per-model adapter now exists (`caliper.mjs discoverCapacity()`, CWK-081+CWK-099) — THREE probes, in order, the first that answers wins. **(1) stats-cache**: `~/.claude/stats-cache.json` `modelUsage[<model>].contextWindow`, the smallest in-range window over every model the cache knows, used only when usable; on this box every model's field reads `0` (present, unpopulated), so it falls through. **A populated cache never falls through:** when it reports a window (any value above `0`) but none this probe can use — below the discovery floor once the reserve is taken off, or outside the supported range — (3) answers directly and (2) is not read, so a larger file can never override a smaller window the platform itself reported in a cache this adapter can read (an absent, corrupt, BOM-prefixed or array-shaped cache reads as nothing found, and (2) answers). **(2) the capacity file**: `~/.claude/coal/coalwash/capacity.json`, read-only — this plugin never writes it, a separate runner does. **Its writer must record the SMALLEST raw window of any model the machine runs, never the last receipt's:** it is one number for every session, and a hook cannot tell which model its session runs. This adapter cannot verify that the writer honoured it — the file is trusted to be the minimum, and a writer that records a larger window makes smaller-window sessions gauge against a wall they do not have. The file is ignored (falls through to (3), silently, no throw) on ANY of: absent or unreadable · corrupt JSON (a leading byte-order mark is stripped first, not doubt) · not an object, or an array · a `stateSchema` that is not the exact current number (a string `"1"` included) · `rawWindowTokens`/`capacityTokens` missing or non-numeric · `rawWindowTokens` out of the supported range · the derived usable window (`rawWindowTokens` minus the fixed auto-compact reserve) not matching the file's own `capacityTokens` exactly — the file's number is a CHECK against this module's own arithmetic, never trusted on its own, because the reserve has one home and a silent second copy outside the codebase is what this check exists to catch. A valid file reports `source: 'capacity-file'`. **(3) the CONSERVATIVE DEFAULT**, when (1) found a window it cannot use, or when neither probe found anything: `CAPACITY_STANDARD_WINDOW_TOKENS (200000) − CAPACITY_AUTOCOMPACT_RESERVE_TOKENS (33000) = 167000`, `source: 'conservative-default'`, `discovered: false` — the smallest supported window minus the auto-compact reserve, not a discovery. The day the cache field populates, or a capacity-file writer ships, the same probe chain returns a discovered window with no code change here — (1)'s own minimum over the in-range windows of every model the cache knows, or (2)'s single number, which is only as safe as its writer's minimum. `capacitySource` rides every capacity-carrying gauge/ask template, worded distinctly per source.
* **Outsider spawn:** use the `Explore` agent type (no Agent/Task tool → structurally leaf, no zombie grandchildren) from a neutral cwd (e.g. the OS temp dir) so the up-tree walk loads no project governance into the sub. Reconcile the sub by id on return; a flattened sub only the user's UI can clear — say so rather than pretend a reap.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.thecolliery.org/tools/coalwash/reference/platform-cc.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
