coding CLAUDE.md

A set of project instructions for coding work, covering documentation, TypeScript, APIs, local services, rebuilding, and browser-based checks.

In plain words
What is it for?
Guiding development startup, strict TypeScript checks, API-preserving fixes, PlantUML and Mermaid files, rebuilds, and visual checks of local web pages.
Why use it?
It keeps changes consistent with the repository’s rules and specifies how to verify local web interfaces and generated documentation.

Instructions file

Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

agentmods
npx agentmods add instructions/fwornle/coding/claude-md
Clone the repo
git clone --depth 1 https://github.com/fwornle/coding
Per session 10,167 This file is loaded in full into every session.
When invoked 10,167 The same file — it is already loaded in full.
Security scan A 1 finding. Scan, not verified.
Origin 95% copy Near-identical to another mod in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5 $0.10167 $0.10167
Opus 5 $0.05084 $0.05084
Sonnet 5 $0.02033 $0.02033
Haiku 4.5 $0.01017 $0.01017

Measured yesterday against content hash 418a60ae4e92, method: parsed. Prices are Anthropic first-party input rates as of 2026-08-30, from the pricing page.

Security

Grade A, and why

coding CLAUDE.md scanned grade A with 1 finding against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured yesterday.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Makes network callslowCapability

Not a fault in itself. Listed so you know the mod talks to something, and to what.

- **km-core wiring — hand-made symlink, NOT a package.json dependency**: `@fwornle/km-core` is the `lib/km-core` git submodule, linked in by hand as `node_modules/@fwornle/km-core -> ../../lib/km-core`. It appears in **n
Origin

This is a copy

95% identical to coding copilot-instructions.md — 41 lines differ, which has more behind it and is treated as the original. This page carries a canonical link to it rather than competing with it.

CLAUDE.md · 147 lines

How it starts

The opening of the file, as written. The whole thing — 147 lines — stays where its author put it; the contents beside it link to each section on GitHub.

CLAUDE.md - Coding Project Guidelines

Mandatory Rules

  • Documentation skill: ALWAYS invoke documentation-style skill before creating/modifying PlantUML, Mermaid, or documentation artifacts
  • PlantUML: Use plantuml CLI command. NEVER java -jar plantuml.jar
  • TypeScript: Mandatory with strict type checking
  • API design: Never modify working APIs for TypeScript compliance; fix types instead
  • Visual UI verification — use gsd-browser: For any visual smoke / screenshot / click-through against localhost:3002 / 3032 / 8080 or any local web UI, use the gsd-browser CLI (gsd-browser navigate, screenshot, click, eval, select-frame, snapshot). It wraps Playwright with the correct chromium resolution and avoids the ERR_MODULE_NOT_FOUND failure mode of inline chromium.launch() scripts. The /playwright-cli skill is allowed as an entry point but does NOT excuse writing a hand-rolled node /tmp/foo.mjs Playwright script — that re-triggers the prefer-gsd-browser constraint. For structured E2E tests, place them under tests/e2e/<area>/<spec>.spec.ts and run via npx playwright test.
  • Constraint dodging is forbidden: When a constraint blocks a tool call, fix the underlying issue — DO NOT swap to a different API that pattern-matches around the regex (e.g., process.stderr.write to dodge no-console-log). Switching to a different raw-write API preserves the behaviour the rule prevents and is itself a violation. For legitimate exceptions, include OVERRIDE_CONSTRAINT: <id> in the prompt with rationale.
  • km-core scripts: Any CLI or service that imports resolveEntities from @fwornle/km-core MUST construct GraphKMStore with an ontologyDir option — otherwise default-class resolution throws opts.classes omitted but store has no ontology registry. Resolve via import.meta.resolve('@fwornle/km-core') + walk up to package root. Integration tests pass this explicitly, so absent CLI greps will mask the gap (Phase 41 lesson, commits 87bc2f567 / fd35c5350). When authoring a new CLI plan, include an acceptance grep for ontologyDir in the script.
  • km-core LLM proxy endpoint: The local rapid-llm-proxy serves POST /api/complete (NOT OpenAI /v1/chat/completions) on port 12435 (host) / host.docker.internal:12435 from inside the coding-services container. The container has LLM_CLI_PROXY_URL=http://host.docker.internal:12435 pre-set in docker/docker-compose.yml. DO NOT confuse with port 3033 — that's the Health API, not the LLM proxy (the Health API will silently return Cannot POST /api/complete HTML, masking the wrong-port bug — Phase 42.2 Plan 06 follow-up lesson; submodule commit 7df8773). Request body: { process, messages, complexity? }; response: { content, provider, model, tokens, latencyMs } — not OpenAI-wrapped, and provider is the ACCOUNT id (gh-copilot, claude-code-max). URL resolution precedence (matches @rapid/llm-proxy SDK convention): RAPID_LLM_PROXY_URLLLM_CLI_PROXY_URLLLM_PROXY_URLhttp://localhost:${LLM_CLI_PROXY_PORT ?? '12435'}; append /api/complete exactly once. See scripts/backfill-raw-observations.mjs:40,95 for the canonical host-side client and integrations/semantic-analysis/src/agents/llm-with-process.ts for the container-side wrapper. taskType does nothing — this file used to claim it "routes dedup calls to claude-haiku (cheaper)", but server.mjs and worker-pool.mjs contain zero references to it and always did; the field was silently ignored. To make a call cheap, give its bg-<process> a complexity: small route in llm-routing.yaml, or send complexity per request on a route declared from-caller.
  • km-core wiring — hand-made symlink, NOT a package.json dependency: @fwornle/km-core is the lib/km-core git submodule, linked in by hand as node_modules/@fwornle/km-core -> ../../lib/km-core. It appears in no package.json, so npm install neither creates nor restores it and nothing fails loudly at install time. If the link goes missing (the scope dir node_modules/@fwornle/ is typically left behind, empty), every ETM spawn dies instantly with ERR_MODULE_NOT_FOUND: Cannot find package '@fwornle/km-core' imported from .../src/live-logging/ObservationWriter.js. Symptom: statusline shows [LSL🔴] and the project's agent letter turns 🟡 while the Health API still reports green — this is the ETM, not a service, so health is the wrong place to look. Diagnose: curl -s localhost:3034/health/state (the project's lsl entry reads status: stopped, which getLSLHealthStatus() maps to down), then tail .logs/etm-<project>.log for the real error (the ETM is no longer launchd-managed — see the daemon list below — so launchctl tells you nothing about it; the coordinator re-spawns it within 30s, which turns this into a visible respawn loop in that log). Fix: ln -s ../../lib/km-core node_modules/@fwornle/km-core, then either wait 30s for the coordinator or launchctl kickstart -k gui/$(id -u)/com.coding.health-coordinator to force it. Beware the false all-clear: long-lived daemons that resolved the module before it vanished (e.g. obs-api) keep running and only fail on their next restart, so "obs-api is up" does not prove the link exists (2026-08-08).
  • km-core snapshot-restore patch (now upstream — nothing to re-apply): hydrate() in store/persistence.js prefers the JSON export over the LevelDB graph:state cache when the JSON has more nodes. Why: persistGraph only fires on clean close(); an obs-api crash during shutdown (we hit a libc++abi mutex lock failed on SIGTERM) leaves LevelDB frozen at the prior clean state — days behind the JSON exports written by the exporter's 5s-debounced scheduleExport. Without it, launchctl kickstart com.coding.obs-api resurrects the stale state (a 2026-06-05 snapshot came back over a 2026-06-11 backfill). This is no longer a local node_modules patch — but not for the reason this file used to give. It is committed in the submodule source, at lib/km-core/src/store/persistence.ts (marked "Phase 57-05 lesson: prefer JSON exports"), and it reaches dist/ only by being rebuilt. lib/km-core/.gitignore line 2 is dist/, so NOTHING under lib/km-core/dist/ is tracked by git — the earlier claim that the patch "is committed at lib/km-core/dist/store/persistence.js" was wrong. Two consequences: (1) since the patch lives in source, npm run build regenerates it and cannot wipe it, so disregard any older instruction to re-apply it manually after npm install; (2) a fresh clone or a wiped dist/ has no built km-core at all, and since node_modules/@fwornle/km-core is a symlink to lib/km-core (not an npm install), nothing restores it — you MUST run npm run build in lib/km-core before any consumer can import it. The same applies to every km-core change you make: it does not travel via git as dist/, so each machine has to build it.
  • km-core reads MUST NOT write — pass readOnly on any request-scoped open: GraphKMStore.close() persists by default, and persistGraph is a single db.put('graph:state', JSON.stringify(graph))the whole graph as ONE value under ONE key (the experiment LevelDB contains exactly 1 key). So a store opened purely to READ still rewrites the entire graph when it closes. Harmless for a CLI that opens once; fatal on a polled HTTP route doing open→read→close per request. Any handler that opens a km-core store to read MUST use openExperimentStore({ readOnly: true }) (which sets persistOnClose: false); the default stays true, so writers need no change. Why: /api/experiments/runs is polled every 30s by performance.tsx:173, and each poll appends a ~1 MB SST for a graph that exports to 8.3 MB. Left unchecked, .data/experiments/leveldb grows to thousands of files and multiple GB backing ~4,000 nodes — 550× amplification — at which point open() alone exceeds the container's 4 GiB cgroup limit and the kernel OOM-kills vkb-server on every poll; each SIGKILL is an unclean close, so compaction never catches up and the loop sustains itself. Diagnostic signature: WARN exited: vkb-server (terminated by SIGKILL; not expected) every ~30s with clean, fast startup logs (⇒ request-triggered, not startup). docker stats lies here — it reports a few hundred MB against the 4 GiB limit because the spike outruns its 1s sampling; read /sys/fs/cgroup/memory.events (oom_kill) and memory.peak instead. Cheapest positive test: one GET adds one ~1 MB .ldb file; an order-of-magnitude gap between du -sh of the LevelDB and its JSON export IS the bug. Recovery: stop vkb-server, launchctl bootout the writers (com.coding.auto-measure-foreground, com.coding.measurement-reconciler), move the leveldb dir aside, then open+close the store once — hydrate() rebuilds it from .data/experiments/exports/*.json.

Read the full file on GitHub · 147 lines

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. yesterday First seen · 147 lines · 10,167 tokens per session scan A 418a60ae4e92

Subscribe to this mod's changes

coding CLAUDE.md is an instructions file published in the GitHub repository fwornle/coding (2 stars, last pushed yesterday), licensed MIT. It adds 10,167 tokens to every session, about $0.0508 per session on Opus 5. A static security scan graded it A with 1 finding (makes network calls). It is 95% identical to coding copilot-instructions.md, differing in 41 lines, and is treated as a copy.