A spec-driven, tool-agnostic methodology that starts before the SPEC: from a vague idea + reference material, the assistant proposes the shape of the system, you decide, and only then is it specified, built, and moved forward with evidence alone. This doc covers the instantiation in Claude Code and Codex with the uscha-kit.
Convention in this doc: in the kit already implemented · new added in this version · proposal design agreed, not yet in code · evaluated — deferred design on the record, decided against for now (dated in ISSUES-DEFERRED.md). No smoke: whatever doesn't exist is flagged.
The whole territory in one diagram: the flow line, its inner loop (converge without chasing zero), the frontier of the outer loop, and the CONSTITUTION no station may violate. Map first; then the doc walks it station by station.
The evidence engine at the center, the flow's phases on the left, the six verification layers on the right, the principles in the strip, and the agent's pieces that hold it up at the bottom.
The full cycle is a single line, runnable by a person, an agent, or the CI. The tool executes; the methodology governs; the evidence decides; the human approves.
Two things the flow guarantees: lowering the cost of entry (you don't have to design the system to be able to start — Discovery proposes that) and raising the certainty of the output (an honest state, with evidence and blockers, tells you how ready it truly is). In Claude Code all of this lives in nine callable skills (kit 1.65.0) and a measurement engine in Python.
The classic mistake is asking you to write entities, endpoints, and error cases from the start. But a new system begins earlier: all you know is what you want to achieve. That's why there are two fronts; you pick by starting point — and they emit different packages: /uscha-discovery writes the full spec package (CONTEXT, DOMAIN-MODEL/CONSTITUTION, SPEC, docs/adr, ACCEPTANCE, RISKS/HANDOFF); /uscha-adr-refine emits docs/adr/*.md + ACCEPTANCE.md (plus optional CONSTITUTION entries).
/uscha-discovery — "I don't know the how"Greenfield. You bring idea + constraints + reference material. The assistant proposes the domain, the API surface, and architecture options; you react and decide. The key inversion: you don't author the structure, you approve it. One question at a time, each with its recommended answer.
/uscha-adr-refine — "I know the what, precision is missing"A feature inside an existing system. The shape is already known; the adversarial interview paints the edges: dirty cases, errors, idempotency, inviolable constraints, out-of-scope. It emits no artifacts until it converges.
Both skills have allowed-tools: Read, Write, Glob, Grep (discovery adds WebFetch to read manuals/PDFs/URLs). Neither touches code: they generate clarity, not implementation.
Grill, don't agree. A discovery where you agreed with everything failed — an agreeable interviewer just inherits your blind spots and hands them back formatted as a plan. The value is in the questions — contradictions, fuzzy terms, missing failure modes, unspoken constraints — not in validating. The expensive failure it prevents: a confident build of the wrong shape.
The front ends up writing the package directly into the repo as decisions crystallize — it doesn't hoard everything for the end. The build reads it from the files, not from the chat.
| File | What it contains |
|---|---|
| CONTEXT.md | Domain glossary. Created with the first resolved term; sharpens fuzzy language ("is 'account' a Customer or a User?"). |
| DOMAIN-MODEL.md | The proposed core entities and their relationships — the "shape" you proposed and the human approved. |
| SPEC.md | Objective/value, risk, scope/out-of-scope, behavior, inputs/outputs/errors, acceptance, test plan, operation, rollback. |
| docs/adr/*.md | One per durable decision. Includes Implementation Plan + Verification (checkboxes) → it's an executable spec. |
| ACCEPTANCE.md | Definition of Done as - [ ] + success metrics. It's the file the readiness KPI measures downstream. |
| RISKS.md | Residual risks, assumptions, points that need human approval. |
| HANDOFF.md | What to read before coding + hard "do not" rules + required evidence. |
Why it matters even if it's all Claude Code: context resets (a new session, a /clear, or a compaction don't have the chat), sub-agents read files, a teammate or the CI builds from the repo, and the audit trail stays durable. The truth lives in versioned files.
If it describes observable behavior, it goes in SPEC. If it justifies a choice between alternatives, it goes in ADR. Almost every non-trivial change needs a SPEC; only some need a formal ADR.
Behavior, rules, inputs/outputs/errors, acceptance criteria, tests, operation. It's the build-and-verify contract.
A technical decision, the alternatives discarded, and the consequences. Architectural memory, not a task list.
Only if the decision meets all three: hard to reverse, surprising without context, and the result of a real trade-off. Otherwise it's noise that buries the important ones.
# docs/adr/ADR-NNN-<slug>.md ## Status: Accepted # proposed/accepted/deprecated/superseded ## Context / Forces ## Alternatives: A) … B) … C) … ## Decision ## Reasons ## Consequences (+ / -) ## Implementation Plan # affected paths · patterns · tests ## Verification - [ ] <criterion checkable by an agent>
The Implementation Plan is what makes the ADR executable: Claude Code reads it and implements it without asking again. During the build, the code links back: // ADR: <slug> — see docs/adr/ADR-NNN-<slug>.md, which makes it safe to supersede (you find everything the ADR governs).
The ADR chooses between alternatives. The CONSTITUTION forbids: it records the invariants that no ADR or SPEC may violate, whatever trade-off wins. It's the project's hierarchy of truth.
SPEC says what must happen. ADR says why this shape was chosen. CONSTITUTION says what is never acceptable. An ADR may choose Postgres vs Redis to cache a session token; an ADR cannot choose "store the certificate in plaintext" — the CONSTITUTION vetoes that before any alternatives are discussed.
## CONSTITUTION.md — project invariants # Security (non-negotiable) - Secrets never in logs or in the repo # CWE-532 / CWE-798 - All external input validated # CWE-20 - Parameterized SQL only, never concat # CWE-89 # Domain (example — fill per project) - Mandatory idempotency on critical operations - Business invariants that must never break - Never two effects for the same requestId # Operation - No destructive migration without explicit rollback - No merge without a human gate
It's a layer of its own: templates/CONSTITUTION.md, versioned, with invariants mapped to CWE. /uscha-discovery and /uscha-adr-refine write/extend it (an ADR cannot contradict it: it escalates, it isn't approved); /uscha-devloop reads it in Phase 0 and consults it before touching governed areas. A breach must be logged by the agent via flag-blocker --kind constitution; once logged it caps readiness ≤65 and blocks convergence until a human clears it with --resolve. The engine does not read CONSTITUTION.md itself — detection is the agent/human's duty; enforcement-after-logging is the engine's.
It's not a loose add-on: it's where the SOTA landed. Spec Kit has /speckit.constitution; the OSS dpolivaev/Uscha (same name as yours) defines its rules in CONSTITUTION.md with human-approval gates. Formalizing it aligns you with the field's convergence.
Opening question: what can this break, and how much does it cost if it breaks? Risk scales the apparatus — profile A doesn't drag along the whole machinery. The profiles are a process heuristic you apply by hand: no profile concept exists in code or config, and no profile selects gates automatically.
| Profile | Example | Documents | Minimum gates |
|---|---|---|---|
| A · Low | minor UI, non-critical config | SPEC mini | build + relevant test |
| B · Normal | local feature, bugfix | SPEC + acceptance | tests + static + review |
| C · Critical | payments, billing, security | formal SPEC + ADR | unit+integration+security+rollback |
| D · Multi-system | public API, events | SPEC + contracts + ADR | contract tests + versioning |
| E · Large legacy | refactor, migration | incremental SPEC + baseline | characterization + no regression |
/uscha-devloop phase by phase.The uscha-devloop is a multi-repo, spec-driven orchestrator. It takes the ADR set + ACCEPTANCE.md as input, builds, and runs a severity-gated review loop that converges instead of looping forever, with the tests as a guardrail between steps. It stops at the merge gate. Three non-negotiable principles govern it: converge, don't chase zero; tests are a guardrail, not the finale; generating tests is not running tests.
qa_ledger.py init --config uscha.config.json. The config lists each repo and its type (maven/flutter/python/node/go/rust/dotnet/cpp/gradle/swift). In multi-repo, the other repos are mounted with --add-dir./uscha-adr-refine first. The acceptance criteria become the contract tests of phase 1.snapshot --phase pre + check-coverage. If coverage ≥ threshold, the existing suite is the guardrail. If below (or no report): you write characterization/contract tests at the edge (public API, endpoints) — and let the human review them before trusting them.qa_tools_order (default: code-review → judgment-day → improve). One pass of all of them = one cycle. After each tool: apply only fixes ≥ severity gate (the rest to ISSUES-DEFERRED.md), run the tests, log with log-step, ingest the static gate with ingest-gate. The agent runs the fact gates inline (simplicity-check / gate-check / golden-diff — exit 0/1) and persists each verdict with log-gate; a failing fact gate blocks convergence. waste-check (reuse-first, 1.26.0) runs over the diff to catch Type-1/2 clones against the repo — advisory unless --gate. End-of-cycle advisory checks: converged and oscillation.--repo integration. It's the second layer of the QA architecture: per-repo green doesn't mean the seams are green./improve test writes the fine-grained coverage you deferred. Full suite green + coverage ≥ threshold before moving on.summary + readiness; /uscha-sysdoc is optional reporting, on request — not a mandatory pipeline phase. Retrospective pulled from the ledger.The crack the method closes: if the same agent that makes the change writes the ledger, it can put exit_code: 0 without running anything. The guarantee only holds if the evidence is produced by execution — the qa_ledger.py parses real artifacts (JaCoCo XML, Surefire XML, the linters' reports), it doesn't transcribe what the agent says.
# the ledger does NOT trust the agent: it parses files
coverage ← target/site/jacoco/jacoco.xml (LINE counter)
tests ← target/surefire-reports/TEST-*.xml
static ← checkstyle-result.xml · pmd.xml · spotbugsXml.xml
LOC ← its own count (prod vs test), pure stdlib
Absent = no evidence, never "OK". A linter report that exists but is empty credits the fix; an absent report is not treated as clean (it means the gate didn't run). A tool that didn't run is never invented as green — a lint-capable repo whose static gate never ran scores UNMEASURED (0.0) on that dimension, never a perfect 1.0.
qa_ledger.py — command reference.Pure stdlib, Python 3.8+, no dependencies. It owns everything that must be exact and reproducible. The judgments (did it converge? is it oscillating? do we escalate?) are made by the skill reading this data; the script only exposes deterministic advisory helpers.
Exact current parser surface: 56 subcommands; the list below mirrors build_parser(), including dashboard, waste-check, and spec-change-request.
| Subcommand | What it does |
|---|---|
| doctor | Installation diagnosis (flutter-doctor spirit): python/git, the 9 skills next to the engine, INV-GOLDEN-01 hook registered, project config/ACCEPTANCE/ledger and per-type toolchains. Exit 1 only on errors (1.22.0). |
| init | Creates the ledger from uscha.config.json (repos, thresholds, commands). |
| snapshot | Measures coverage / tests / LOC of a repo (--phase pre|post). |
| check-coverage | Exit 0 if ≥ threshold, 1 if below. It's the phase 1 gate. |
| log-step | Records a pass of a QA tool: reported / gated-reported / fixed / deferred / suppressed / tests-passed / files-changed / fingerprint. |
| ingest-gate | Parses Checkstyle/PMD/SpotBugs/FindSecBugs, normalizes severities, and computes the real fixed by diffing finding-IDs against the previous pass. |
| converged | Advisory. Exit 0 = converged (latest agent step of every tool in qa_tools_order clean + every linter clean + every persisted fact gate clean). A red measured snapshot vetoes a narrated green — padding the window doesn't help. |
| oscillation | Advisory. Detects that a tool's findings fingerprint repeats with period 2 (pass N == pass N-2). |
| log-gate | Persists a fact-gate verdict: --kind golden-diff|gate-check|pit-check|simplicity|regression --verdict pass|fail|not-run. A failing gate blocks convergence and caps readiness ≤65; a not-run is recorded but is never green. |
| corpus-run | Runs a REAL-INPUT corpus (JSONL: input / expected per line, fed to the command on stdin) and persists gate:corpus with the hit percentage. Field truth for greenfield, where every test payload was invented by the agent that wrote the code. ADVISORY while no threshold is declared (--threshold, else repos[R].corpus_threshold, else defaults.corpus_threshold); with one, a run under it caps readiness ≤65 and blocks convergence. A missing, empty or malformed corpus is exit 2 naming the line, never a scored 0 %. --ac closes a criterion MEASURED on a green run (ADR-046, 2.2.0). |
| smoke-ingest | Ingests the smoke run as the FACT it is: a report the PROJECT's tool writes ({"checks": [{"name", "ok", "status", "latency_ms", "evidence"}]}), persisted as gate:smoke. Phase 7 stops being prose — "the jar served /admin" believed on an agent's word is the failure this removes (a field team shipped an empty list reported as verified). A failed check caps readiness ≤65 and blocks convergence; a missing, malformed or EMPTY report is exit 2 naming the offending check or field, never a scored run. A FACT kind: --verdict advisory is refused, because ok is binary. A check named AC-nn ... closes that criterion MEASURED on a passing report, and a failed one VETOES it (ADR-047, 2.2.0). |
| flag-blocker | Logs a blocker (--kind constitution for CONSTITUTION breaches): caps readiness ≤65 and blocks convergence until a human clears it with --resolve. |
| escalate | Records a human-escalation event with a reason. |
| resolve-escalation | Resolves a recorded escalation — lifts the ≤75 readiness cap. |
| summary | Retrospective metrics (--json is consumed by /uscha-sysdoc). Includes first-time yield (FTY, 1.27.0): % of repos that cleared QA on the first cycle, no rework or escalation — an informational Lean metric, never gates. |
| readiness | The project-state KPI: score 0–100 with weights and hard caps. Single-verdict (anti-ceremony, 1.25.0): the default is ONE screen — verdict + a collapsed --- gates: line; --verbose expands the dimensions and by-repo detail. |
| rebuild | The rebuild test: SPEC completeness. --mode baseline signs the system; --mode compare scores the regeneration (COVERS/PARTIAL/DIVERGE). |
| regression-check | Find Bugs Once (1.16.0): findings closed with no new test line = NARRATED — advises; --strict gates; persisted via log-gate --kind regression. |
| waste-check | Reuse-first (1.26.0): deterministic Type-1/2 clone detection of the diff against the repository — the duplication simplicity-check can't see (it scores the diff in isolation). Each flag names the file:line to reuse. Advisory unless --gate or defaults.waste.gate. Roots: Lean muda (Poppendieck) + GitClear's +81% duplication finding. |
| phase | Workflow state DERIVED from the ledger (plan/build/qa/escalated/pr-ready), never self-declared. --require pr-ready gates the PR and vetoes spike/* branches (1.18.0–1.19.0). |
| rubric-ingest | Ingests rubric grader JSON. |
| production-finding | Records production feedback. |
| spec-doubt | Records SPEC doubts. |
| spec-change-request | Records SPEC/ADR change requests. |
| fastpath-eval | Measured fast-path verdict (ADR-003): ALLOW/DENY from the real diff against the merge-base; --intent records it, without it the call is a dry-run. Fail-closed (1.57.0). |
| spec-drift | Advisory spec-vs-code drift from git commit dates (ADR-005). Never gates; exit 0 always (1.58.0). |
| golden-coverage | Records the MEASURED source files a golden's harness exercises, by running it under coverage.py (ADR-006). Feeds the opt-in golden-touched veto (1.60.0). |
| cleanroom | Runs a caller-supplied command against a CLEAN worktree of one commit; opt-in pr-ready gate (ADR-008, 1.63.0). |
| curation-check | The INV-CURATION-01 gate: candidates, verdicts, append-only behavior ledger (ADR-009/010, 1.64.0). |
| roundtrip | Advisory: which promoted candidates are traceable in code via uscha-spec ids (1.65.0). |
| facts | Derives SYSTEM-FACTS.json from the artifacts and checks published claims against it (ADR-012, 1.68.0). |
| discover | Emits discovery/CANDIDATE-DELTA.json: typed observations with content-addressed OBS ids, measured/static/narrated (ADR-013, 1.69.0). |
| curate | Records ONE human verdict per observation as an append-only ledger object; no batch path (ADR-013, 1.69.0). |
| promote | Moves preserve-verdict observations into the canonical package with derived_from lineage; refuses over uncurated OBS (ADR-013, 1.69.0). |
| fidelity | The fidelity vector: 5 measured dimensions plus an advisory quarantine that can never gate (ADR-014, 1.69.0). |
| ir-extract | Extracts the canonical package into a typed graph (ir/IR.json); what cannot be typed deterministically is UNTYPED, counted, never guessed (ADR-015, 1.72.0). |
| ir-render | Regenerates the human view (ir/IR.md) from the graph; round-trip content-stable for the structured parts (ADR-015, 1.72.0). |
| compile-validate | Validates a COMPILATION.json (the LLM-compiler output contract) against a reference IR: unknown manifest ids, unit hash mismatches, a stale ir_hash and a broken seal each gate; degeneracy stats are advisory and never block (ADR-016, 1.73.0). |
| compile-ingest | Records a validated compilation into the ledger: by-construction unexplained_code plus each unresolved_intent as an append-only, content-addressed UINT object mirrored into ISSUES-DEFERRED.md — the compiler's output generates the backlog for the representation (ADR-016, 1.73.0). |
| bootstrap-oracle | Runs a WITHHELD oracle suite against a compiled implementation and exits 0 iff every case matches its expected exit — the maker≠checker wall made executable; a measured behavioural fact about whether an independent compilation is the same system (ADR-017, 1.74.0). |
| bootstrap-variance | Structural metrics (LOC, AST nodes, functions, imports) and pairwise divergence proving independent compilations of the same canonical package genuinely differ; advisory evidence, never a gate (ADR-017, 1.74.0). |
| bench | The Diamond Bench: a per-archetype verdict table (PASS / PARTIAL / FAIL / PENDING) over a set of bounded systems, aggregating compile-validate + bootstrap-oracle + bootstrap-variance and writing DIAMOND-BENCH.md; oracle-discrimination is a gate, model identities are anonymized in the headline; deterministic, no LLM (ADR-018, 1.75.0). With --fidelity, appends the per-compiler fidelity descriptor — the M1 static extractor over each compiled source, trace coverage, oracle pass-rate, curation UNMEASURED where no human verdict exists and judged/total where one does; advisory, never changes a verdict (ADR-022, 1.79.0; ADR-023, 1.80.0). Since 1.85.0 (ADR-028) entries may be JavaScript: the oracle runner is routed by extension (node for .js), structural metrics for JS are honestly 2-dimensional (no stdlib JS AST), and the static surface is the module's own exports as listed by Node; a JS entry without node on PATH reads PENDING/UNMEASURED, never a fake pass. Since 1.85.0 (ADR-029) entries may be multi-unit: the oracle runs the entry unit (cli.*) with the compilation dir as cwd, the fidelity surface and curation cover every unit, and the first such entry carries the bench's first IR with edges (a seam ADR in the canonical package). |
| bench-curate | ONE human verdict (preserve|fix|undefined) for ONE observation of ONE bench compilation, appended to BENCH-CURATION.json; the curable set is the same M1 static-extractor observations static_surface publishes, re-extracted at verdict time (a fixture edit invalidates the old id and reports STALE); batch input, an unknown obs or a malformed store refuse with exit 2 (ADR-023, INV-CURATION-01, 1.80.0). --dir is the compilation subdir (e.g. c-opus); --compilation is an alias for the same --dir, to avoid confusion with bench's own --dir, which is the bench root (1.82.0). |
| bench-r2 | Intra-model variance (ADR-027): for every bench entry with an r2/ second blind run of the same model on the same canonical package, the structural distance between run 1 and run 2 via the SAME _struct_distance the bench uses between compilers, plus behavioural stability against the oracle; a per-entry SIGNAL/NOISY/NOISE class from intra/inter (the noise floor under every variance claim the program makes); advisory, never changes a bench verdict; writes DIAMOND-BENCH-R2.md (ADR-027, 1.84.0). |
| bench-roundtrip | Round-trip recoverability (ADR-030): for every bench compilation, how much of the human-pinned IR the mechanical reverse organs already in the engine can anchor — static footing (an id literally referenced in a source unit or a static observation) and behaviour footing (a withheld-oracle case tagged with the AC id passes; UNMEASURED where no case carries that tag). The compiler's trace_manifest footing is reported APART as claimed and never counts as recovered — it is what the compiler CLAIMED (and the blind prompt handed it the ids), so counting it would be tautological: the first run of this instrument read 1.000 on every entry for exactly that reason. It regenerates no IR from code and infers no spec (ADR-013): a MEASURED coverage over the human-authored IR, never an IR′. The honest number today: mean recoverability 0.815 across 12 entries, with the behaviour dimension MEASURED in all 12 — it read 0.828 while three compilers were judged and 0.815 once a fourth, from a second vendor, joined (ADR-042), because an entry's recoverability is the mean over its compilations. ledger-lite's edges_recovered_mean moved 1.00 → 0.75 the same way: that field is a mean COUNT of edges recovered per compilation, not a ratio — only one arm anchors all three edges, so the value is 3/N and N went from 3 to 4. It read 0.062 with behaviour UNMEASURED everywhere until the 12 bench oracles were curated with a per-case ac tag list (ADR-030 amended, 1.90.0) — a named absence, not a zero, and what moved the number was the tagging: payloads and expectations are untouched. Advisory, never changes a verdict; writes DIAMOND-ROUNDTRIP.md (ADR-030, 1.85.0/1.90.0). |
| lang-compare | The controlled-language arm: compares a free-prose canonical package against an EARS+STE rewrite of it, judged by one shared withheld oracle (behaviour held fixed), and computes a behaviour-first verdict — REDUCED / IMPROVED / MIXED / NO EFFECT / WORSE — over inter-compiler variance, mean oracle pass-rate and unresolved_intent; reduced variance with a behavioural regression reads MIXED, never REDUCED, and a null result is first-class; IMPROVED (ADR-026, 1.83.0): behaviour improved while variance did not fall — the mirror of MIXED; two compilers converging on the same bug read as low variance; deterministic, no LLM (ADR-019, 1.76.0). Replicated deconfounded across 5 archetypes: REDUCED in 1, IMPROVED in 1, NO EFFECT in 2, WORSE in 1 -- the guard's positive did not generalize to the simple systems on its own, the transformer read WORSE (an oracle-green lost), and a second decision-dense archetype (scheduler) landed IMPROVED, strengthening the dense/simple split (ADR-024/ADR-025/ADR-026, 1.81.0-1.83.0). |
| top | Read-only projection of the ledger for uscha top (board, feed, verdicts, drift, rerun; ADR-031..037, 1.86.0-1.91.0). |
| check-terminado | INV-T1 (ADR-038, 1.92.0): is TERMINADO sealed to the code state on disk? Recomputes the same seal top --json publishes -- clean tree, no source-relevant change since the last snapshot's commit (a non-source difference seals with a note; ADR-039, 1.93.0), every ingested report still hashing to its recorded sha256. Exit 0 sealed, 1 broken, 2 unmeasured. Reads only. |
| execution-policy | Prints execution routing. |
| dashboard | Emits Mirador data contract. |
| simplicity-check | Scores diff minimality. |
| pit-check | Scores test effectiveness. |
| gate-check | Detects weakened gates or secrets. |
| spec-check | Validates SPEC/ACCEPTANCE; lifecycle dimension (ADR-040): compares the end-of-support dates cited in the ADRs' lifecycle: blocks against the SPEC's go_live. Advisory: never gates. |
| golden-diff | Byte-compares received/approved. |
| operability | Measures the repo’s operability as FACTS in the tree (ADR-048, 2.2.0): a workflow step running the configured test command, a workflow that publishes a release asset, a RUNBOOK.md naming start/config/rollback/smoke, and a declared seed_command whose script exists. Exit 0 always; persists gate:operability — advisory on risk profiles A/B, a BLOCKER on C/D/E via defaults.operability.gate. |
# a typical pass of the loop QL=./.claude/skills/uscha-devloop/qa_ledger.py python3 $QL init --config uscha.config.json python3 $QL snapshot --repo backend-api --phase pre python3 $QL check-coverage --repo backend-api # exit 0/1 # ...build + one QA tool... python3 $QL log-step --repo backend-api --tool code-review --iteration 1 \ --reported 12 --gated-reported 4 --fixed 9 --deferred 2 --suppressed 1 \ --tests-passed true --files-changed 7 --fingerprint a,b,c python3 $QL ingest-gate --repo backend-api --iteration 1 python3 $QL converged --repo backend-api --tools-per-cycle 3
The static gate (your java-qa-gate: Checkstyle/PMD/SpotBugs/FindSecBugs) is not counted by hand. You run the gate so it writes its XML, and ingest-gate parses them, normalizes to a common severity scale, separates FindSecBugs from SpotBugs, and computes the real fixed by diffing IDs.
| Linter | Native severity → common scale |
|---|---|
| Checkstyle | error → HIGH · warning → MEDIUM · info → INFO |
| PMD | priority 1 → BLOCKER · 2 → CRITICAL · 3 → HIGH · 4 → MEDIUM · 5 → LOW |
| SpotBugs | priority 1 → HIGH · 2 → MEDIUM · 3 → LOW |
| FindSecBugs | SECURITY-category findings → floor HIGH (separated under the tool findsecbugs) |
Full scale, lowest to highest: INFO · LOW · MEDIUM · HIGH · CRITICAL · BLOCKER. The default severity gate blocks at BLOCKER / CRITICAL / HIGH; everything below goes to ISSUES-DEFERRED.md, never into the loop. Finding-ID granularity is configurable (file or line) for the fixed diffing and oscillation.
The local java-qa-gate is self-sufficient (stdlib + linters, zero server). If the team already runs SonarQube, the plugin sonarqube@claude-plugins-official exposes the same role (issues, coverage, quality-gate) as MCP tools — same gate, different ingest. Normalize its severity to this same common scale.
It measures the state of the result, never the effort. A weighted 0–100 score with hard caps that override the average. It reports (always exit 0) — it is not a pass/fail gate; rebuild is the one that exits 1 unless COVERS. Cycles/regressions are churn (process health) and are reported separately — they never raise readiness. Show it after any task, not just complete runs.
[x] with no test = narrated_only, does not close)resolve-escalation)Single-verdict (anti-ceremony, 1.25.0): by default readiness is ONE screen — the verdict + a collapsed --- gates: line; the dimension breakdown you see above, plus acceptance, churn, and by-repo detail, live behind --verbose. A meta-invariant in the CONSTITUTION governs that future gates stay quiet-by-default and collapse into readiness. The blockers that cap it always speak (conditional: "speak only when it matters"). No formula, no number: that would be the numerology the method avoids.
The ledger proves correctness (this build passed). The rebuild test proves completeness (the SPEC is sufficient to regenerate the system). Two different questions. It's the completeness benchmark being standardized in the SOTA.
The mechanic: on a clean tree, a fresh session points only at the package (SPEC/ADR/ACCEPTANCE — not the chat) and regenerates. If it rebuilds and passes acceptance + tests → the SPEC covers. If it diverges → the SPEC has gaps: almost always implicit decisions (error codes, cache strategy, library choice) that lived in your head and never made it into the SPEC.
# rebuild test — real subcommand (kit 1.4.0+) # 1) ORIGINAL tree: capture the signature $ python3 $QL rebuild --mode baseline --config uscha.config.json → REBUILD-BASELINE.json # 2) CLEAN tree / fresh session: regenerate ONLY production from # SPEC/ADR/ACCEPTANCE, PRESERVING the tests, and run the suite # 3) score the regenerated tree against the baseline $ python3 $QL rebuild --mode compare --baseline REBUILD-BASELINE.json REBUILD: 72.2/100 — PARTIAL ! 1 test(s) fail on regenerated code — behavior the SPEC left implicit ! coverage 45.0% vs baseline 80.0% (tolerance 5)
Implemented and tested (kit 1.4.0+). Weights: tests 60 · acceptance 20 · coverage 15 · surface 5. Verdicts: COVERS ≥90 · PARTIAL ≥70 · DIVERGE <70 (exit 0 only if COVERS; --json is consumed by /uscha-sysdoc). The dominant signal is the preserved suite: a test that passed and now fails on the regenerated code = behavior the SPEC left implicit. When to run it: profile C+ and E, or on a periodic cadence (process rule — the kit ships no CI workflow) — it's the QA of the Discovery output.
Don't clean everything; don't make anything worse. Legacy debt is frozen, new debt is blocked. And the loop has a ceiling: exceeding it isn't going on alone, it's escalating.
max_iterations: 5 · tools_per_cycle: 3Escalating is not failing: it's that a human decision showed up. The process detected that it should not go on alone. Never auto-merge, never silently exceed the cap, never fix below the gate to make the number look better.
Maeda's Laws of Simplicity are design philosophy, not a dev cycle. Mapping the 10 laws to gates is tempting — and that's the trap: building 13 checks to "make things simple" violates Law 1 (Reduce). The framework refutes itself. Of the whole combo, only one piece has teeth — and that piece is really two things under one coat. Separate them, or you rebuild the same mix, smaller:
| What | Deterministic? | Already have it? |
|---|---|---|
| Numeric budgets: +lines (400 default), net growth, files changed, nesting depth, largest hunk | YES — measurable, enforced | NO — the only new thing |
| "Was this abstraction necessary? Is it speculative?" | NO — checker's judgment | YES — it's simplify + maker≠checker |
SIMPLICITY invariant in the CONSTITUTION: a complexity budget with hard caps.qa_ledger.py simplicity-check subcommand that scores — deterministic, zero opinion — and, since 2.1.0, is advisory by default (exit 0): it stops the loop only where the project declares its own budgets and defaults.simplicity.gate. A heavy dimension >1.5× budget floors the verdict to OVERBUILT — cheap dimensions can't average it away.simplify (official skill, post-diff) + the separate checker.# the invariant as an objective gate, not as philosophy $ python3 .claude/skills/uscha-devloop/qa_ledger.py simplicity-check --diff HEAD # budgets: +lines (400 default) · net growth · files changed · nesting depth · largest hunk # abstraction count/density: advisory, deliberately unweighted SIMPLICITY: PASS · +47 lines / budget 400 · nesting 2 · largest hunk 31L
Law 10 is worth more than the other nine combined. It goes as a north star atop the CONSTITUTION, not as a checklist:
"Simplicity is about subtracting the obvious and adding the meaningful."
A sensor is an automatic check that returns actionable feedback to the agent so it can self-correct — before human review. It's your "evidence captured, not narrated" under another name. They're ordered by when they run and by what evaluates them:
| Timing | Nature | Examples |
|---|---|---|
| During the session (fast) | computational | type-check, linters, layer rules, tests, secret-scan |
| Pipeline (confirmation) | computational | the same, on clean infra |
| Scheduled reviews (drift) | inferential (LLM) | modularity, security, dependency freshness |
Three findings that add teeth to your kit:
100% coverage with 13 live mutants: code that runs but that no test asserts on. Coverage measures execution, not verification. It plugs a hole in your rebuild test: if the preserved tests don't assert, the rebuild passes into the void. Java tool: PIT. Expensive → scheduled tier, not the inner loop.
The agent refactored complexity only when the message told it how and when. A bare pass/fail doesn't change behavior. Add the documented escape hatch: suppress with justification, not a binary wall. Your simplicity-check flags already go this way.
Deterministic metrics win at the file level (length, complexity, args); for the cross-cutting stuff (coupling), raw metrics are noisy — the LLM review that reads the code beats them. Design rule: file caps are a gate; the "is this over-architected?" judgment goes to the inferential checker, not to a regex. (This is exactly why new_abstractions gives false positives with records/DTOs in Java.)
A pile of sensors can create an illusion of quality by covering the semantic stuff that static analysis can't see. More sensors ≠ more quality. And running an inferential review twice yields different issues: a single pass isn't enough.
Your kit measures everything — but nothing checked that the change didn't WEAKEN the measurement. A maker running as an optimizer takes the cheapest path to "green", and editing the gate is often the cheapest. Three guards close the most direct exploit of an automatic gate: modifying the gate.
A diff that removes tests (including whole-file deletions), disables tests, or lowers/deletes thresholds (matched cross-hunk) is a BLOCKER — qa_ledger.py gate-check, deterministic, exit 1. Lint suppressions, rewritten asserts, and a measured executed-test-count drop (--repo) are soft REVIEW signals, gated with --strict. The apparatus that measures correctness is not modified by the change it measures.
Sharpens maker ≠ checker: for high-blast-radius changes the checker should have different blind spots — a different agent family, or at least a different profile. This is process discipline, not enforced by code. Data point: 93.4% of defects were caught by exactly 1 of 4 tools. The loop that produced the change is not its only approver.
A cheap heuristic BEFORE the pit-check: prioritize test-file hunks and flag mass rewrites of existing asserts — the safety net edited to accept what's broken. Mutation testing remains the authority on whether a test would detect the defect.
Osmani (Agentic Code Review) enumerates these red flags for human reviewers; the automatic detector and the principle "the apparatus is immutable by the change it measures" are a synthesis of the kit, not his recommendation. The 93.4% data point (1 of 4 tools) is from the article.
In the Uscha the agent authors almost everything (discovery, ADRs, spec, code, tests). The golden suite is the ONLY piece the agent cannot author — and that is its reason to exist. If the agent writes the test that judges it, it encodes the same blind spot that already lost logic once.
The golden is captured by running the ORIGINAL code with real inputs, mechanically, by a script. The .approved files are field truth: a HUMAN approves them, never the agent. qa_ledger.py golden-diff byte-compares .received vs .approved — a fact, not a judgment. Exit 0 CLEAN · 1 DIVERGE · 2 NOT-RUN (zero fixtures = NOT-RUN, never CLEAN). Any non-match = DIVERGE, cuts the chain.
No module enters migration/modernization without a golden captured and committed BEFORE touching it. The migration spec is written against that golden.
Freeze the clock, seeds, map ordering, GUIDs, and above all the target locale (decimal separator, date format — high risk across machines with a different locale). The snapshot comes out byte-for-byte identical when the behavior is identical.
Directly applicable to any migration of a legacy system with critical paths (byte-equivalence), where the silent loss of logic is the real risk. Already in the kit: brownfield front uscha-reverse-discovery (map + facts), uscha-characterize skill (capture), golden-diff gate, hook block-approved-writes.py (blocks the agent from touching an .approved), and .gitattributes.
A kit full of gates can turn into a diamond: beautiful and impractical. The principle that avoids it — your Böckeler rule (computational vs inferential) applied to the methodology itself:
Gates that read FACTS block; those that GUESS over prose advise.
| Gate | Reads | |
|---|---|---|
| golden-diff | byte-comparison vs .approved; declared volatiles in golden.scrub.json mask with VISIBLE masking, human-approved (1.15.0) | BLOCKS |
| pit-check | PIT XML (mutation testing) — scheduled tier; a failing report is persisted via log-gate | BLOCKS |
| gate-check | diff structure: deleted/disabled tests, lowered thresholds, added secrets (PEM/AKIA/tokens/key containers — 1.12.0) | BLOCKS |
| rebuild | baseline vs regeneration; exit 1 unless COVERS | BLOCKS |
| phase --require pr-ready | workflow state DERIVED from the ledger (converged + green tests + 0 BLOCKER/CRITICAL), never self-declared; a spike/* branch never passes (1.18.0–1.19.0) | BLOCKS |
| readiness | reports (0–100 KPI, always exit 0) with hard caps | REPORTS |
| simplicity · budgets | +lines / net growth / files / nesting / largest hunk — test trees stay OUT of the budget (1.11.0): writing tests never penalizes | BLOCKS |
| spec-check · structural | missing out-of-scope · absent/empty acceptance criteria · zero traceable AC-n IDs or duplicates | BLOCKS |
| regression-check | findings closed with no new test line = NARRATED (Find Bugs Once, 1.16.0) — --strict gates it | ADVISES |
| waste-check | Type-1/2 clones of the diff vs the repository (reuse-first, 1.26.0) — the duplication simplicity-check can't see; flags name the file:line to reuse — gates ONLY with --gate or defaults.waste.gate | ADVISES |
| rubric-ingest | rubric grade: versioned qualitative criteria with mandatory evidence (1.23.0) — gates ONLY when the human declares it (defaults.rubric.gate) | ADVISES |
| spec-check · prose · abstractions | heuristic over prose / "new types" (--strict gates them) | ADVISES |
A natural-language heuristic that blocks throws false positives → the dev turns it off → dead gate (the erosion gate-check fights). That's why spec-check's prose heuristics are advisory and abstractions were dropped from the score — only its two structural facts block. No CI workflow ships in the kit: in /uscha-devloop the agent runs the fact gates inline (exit 0/1), persists each verdict with log-gate, converges, and stops at the merge gate → the human reviews → ship.
Crossing Hunt & Thomas (20th Anniversary, 497 pp) against the method yielded a set of validations, tensions and ten actionable improvements, all shipped (kits 1.10.0 → 1.19.0, each with a fresh review and a green smoke suite). The per-item record lives in those releases' changelogs (uscha-kit/CHANGELOG-1.10.0.md … 1.19.0.md); the original analysis document was retired in the docs cleanup.
| Tip / Topic | What landed in the engine | Kit |
|---|---|---|
| Tip 87 · Sudoku anecdote | Traceable acceptance: AC-n closes on a MEASURED green testcase, not a checkbox — the dominant readiness dimension | 1.10.0 |
| Topic 51 | Tests outside the simplicity budget: writing tests never penalizes the gate | 1.11.0 |
| Topic 43 | Secret-scan in gate-check: added PEM/AKIA/tokens/key containers block as facts | 1.12.0 |
| Topic 34 | Atomic ledger: sha256 checksum + hardened load — external mutation or corrupt JSON blocks with a recovery message | 1.13.0 |
| Topics 37 · 5 | Plateau/stop-signal (advisory): findings not dropping for 3 cycles → "go back to the ADR"; everything converged → "PR candidate" | 1.14.0 |
| Topic 41 | Golden scrub: declared volatiles (timestamps/ids) mask with visible, human-approved masking | 1.15.0 |
| Tips 94 · 31 | Regression-capture: closing findings with no new test = NARRATED; resolving a blocker requires an escape-analysis | 1.16.0 |
| Tip 8 | Threshold provenance: every cap states whether it is a requirement (config) or kit-default opinion | 1.17.0 |
| Topic 29 | Derived FSM: phase computes state from the ledger — the PR is gated on --require pr-ready | 1.18.0 |
| Tip 21 | Formal spikes: a spike/* branch never passes the PR gate; the legitimate output is an ADR with lessons | 1.19.0 |
On the two big tensions the kit departed from the book's letter to defend its own principle: the caps keep biting (their existence is a definition, the number is an opinion — and now it says so), and the FSM is derived rather than declared — a declared FSM would be narrated state. Measured beats narrated, applied even to the book.
"Loop engineering" blew up in one week of June 2026 (Steinberger, Cherny, Osmani): "don't prompt agents; design loops that prompt them". When the front brought it down to spec-driven, it converged on these same principles. Uscha didn't fall behind: it reached the same shape independently.
| Trending autonomous-loop principle | Uscha | Where it lives in the kit |
|---|---|---|
| Done-criteria that rejects open loops | ✓ | ACCEPTANCE.md (acceptance that can fail) |
| Iteration budget / hard ceiling | ✓ | max_iterations: 5 · change budget |
| Maker ≠ checker: the writer doesn't self-grade | ✓ | captured evidence (ledger parses artifacts) |
| State externalized to disk | ✓ | QA-LEDGER.json + package in the repo |
| Done only with checker-pass + human sign-off | ✓ | phase 6: stops at the merge (human gate) |
| Oscillation / stuck detection | ✓ | oscillation (period-2 fingerprint) |
| Self-scheduled outer loop (timer / routine) | ✗ | deliberately not — you trigger it |
We didn't just reach it: we arrived at the same shape independently, and on verification integrity (maker ≠ checker) we articulated it as sharply as anyone. The only difference is that a person triggers the loop, not a cron — and that's the decision, not the gap.
The loop-engineering playbook (Osmani / AlphaSignal, Jun 2026) puts a 4-condition test before automating anything: fail one and the loop costs more than prompting by hand. Uscha already defines "when NOT to use it"; this is the entry filter for the outer loop.
Good: CI triage, dep bumps, lint-and-fix, flaky-test repro, issue→PR on well-tested code.
Bad (human in the chair): architecture, auth, payments, production deploys, fuzzy product.
High-blast-radius domains —regulated, financial, critical retail, safety-critical— fall on the "bad to autonomize" side. The playbook itself says: don't put the loop in charge of deciding on auth/payments/architecture. That's exactly the gated-by-design approach: the article confirms it from the other side.
Uscha is human-triggered today: you fire it. The playbook contributes the heartbeat — what turns "one run" into a loop. The synthesis: Uscha is the ideal payload of that heartbeat, because it already brings the gate, the state, the skills, and the maker ≠ checker. Only the trigger is missing.
# outer loop = schedule + /goal, wrapping /uscha-devloop > /loop 0 3 * * * # cadence: every night /goal readiness ≥ 80 AND tests green in touched modules AND 0 CRITICAL findings # checked by a separate model /guard 4-condition-test # repetitive task + automatic verification > run /uscha-devloop over <machine-checkable scope> gate = qa_ledger.py ingest-gate + fact gates (readiness = KPI) # ALREADY exists state = QA-LEDGER.json + package in repo # ALREADY exists stop = /goal met (fresh checker) or change budget exhausted on-done = open draft PR · escalate what touches the CONSTITUTION human = merge / deploy ALWAYS with approval # human gate
/loop — re-runs on a cadence, whether or not it looks at the state./goal — keeps going until a condition is true, verified by a separate model (maker ≠ checker in the stop condition).Your security today is build-time (static gate + CONSTITUTION with CWE). When the loop runs on its own, operational risks appear that the playbook documents. They enter as an operational layer of the CONSTITUTION: invariants the outer loop cannot violate.
| Unattended-loop risk | Operational invariant (CONSTITUTION) |
|---|---|
| Generated code merging without review | The gate includes SAST + secret-scan + dependency-audit; without that, no PR. |
| Skills as an injection vector — a third-party skill can leak credentials | Vet every skill's origin before installing; source allow-list. |
| Secrets in logs (verbose on long runs) | Non-verbose logging in production loops; sanitize what gets logged. |
| Permission scope creep (a "just one write permission" nobody re-audited) | Re-audit permissions every 30 days; the loop starts read-only by default. |
| A session that bloats on long loops and hangs — evidence lost, loop dead with no warning | Rotate the session before the size threshold; a hook that warns + transcript rescue (author's setup — not shipped in the kit). Session hygiene is part of the security tax. |
Silent failure: the agent emits the "done" token too early and the loop exits with the work half-done. The fix is the one you already have: an objective gate (test/build/linter that returns pass or fail), not an "opinionated" verifier. The gates plus the human gate close the loop — the engine doesn't close it by itself.
The playbook and Uscha don't compete: they're different layers. The article is the outer loop (the heartbeat that triggers machine-checkable maintenance). Uscha is the rigorous inner loop + Discovery for critical systems. The convergence on principles (maker ≠ checker = Anthropic's evaluator-optimizer, Dec 2024) confirms you reached the durable stuff, not the hype.
Cost per accepted change — not tokens or tasks attempted. If the accepted-change rate falls below 50%, the loop is handing you back the review work it came to take off your plate: that's where it loses. Uscha is the ideal payload of the heartbeat precisely because its gate raises that rate.
Twelve bounded archetypes, a withheld oracle (M4), four blind compilers from two vendors — Haiku, Sonnet, Opus and OpenAI Codex gpt-5.5 (measured September 2026). The question: how much of the system survives the round trip?
221 verdicts: 213 preserve, 8 fix, none unjudged. The cross-vendor arm is a falsification test the replaceability claim survived, not a survey: four blind compilers, two vendors, gpt-5.5 via Codex included.
More: uscha.dev/diamond · the full paper at docs/paper/uscha-paper.html.
The release is no longer a hand-run checklist: tools/release.py runs eight invariants and refuses, naming which one failed. Dogfooding freshness is decided by git ANCESTRY, never by a clock.
Every published claim (version, subcommands, skills, Diamond archetypes) is a derived FACT, checked against the engine. Born because the homepage said "9/12" for nine releases after the number moved — and no gate saw it.
Risk presets had never actually taken effect: init copied the kit's reference config, and that copy outranked the profile under the "explicit wins" rule. Now init generates a minimal config.
A gate needs an adopted budget. With none declared, the score informs but does not block.
origin: agent (ADR-044, who decided each item), corpus-run (ADR-046, field truth with real inputs), smoke-ingest (ADR-047, the suite's own run as measured evidence), operability (ADR-048, a measured dimension), and the version marker on every installed skill (ADR-045, doctor reports whether it is outdated).
Throwaway code to learn. No SPEC; yes to a note of what was learned. Whatever survives gets specified later.
A demo that won't go to production. Marked as such, isolated, with a death date.
Production incident: you fix first. But the minimum evidence (what changed, how to roll it back) and the retroactive SPEC/ADR are mandatory within 24h — a process rule the team commits to, not a shipped feature. Without an escape valve, people cargo-cult the throwaways or abandon the method under pressure.
The generic layer that runs the methodology: Claude Code + Python + git/gh + the skills. The stack-specific part (JDK/Maven, the database, the linters) is the project's adapter and lives in each repo's CLAUDE.md — not in the workbench.
| Component | What for | Minimum |
|---|---|---|
| Claude Code | the agent / orchestrator | Pro / Max / Team / Enterprise / Console account |
| Python 3.8+ | runs qa_ledger.py (pure stdlib) | python3 on PATH |
| git | versioning | 2.x with user.name/email |
| gh | create repo / open PR | optional, recommended |
| kit skills | uscha-discovery, uscha-adr-refine, uscha-devloop, uscha-sysdoc, uscha-reverse-discovery, uscha-characterize, uscha-rubric, uscha-mirador, uscha-status | in ~/.claude/skills/ |
| QA skills | code-review, judgment-day, improve | your global skills (uscha-devloop orchestrates them, doesn't bundle them) |
| engram (plugin) | persistent memory across sessions | marketplace Gentleman-Programming/engram |
| sonarqube (plugin) | hosted static gate (alternative to java-qa-gate) | marketplace claude-plugins-official |
| gentle-ai (CLI) | skill-registry hook (refreshes the skills index) — optional author toolchain, not required by the kit | scoop, bucket gentleman |
# Claude Code (native installer — no Node required, self-updating) curl -fsSL https://claude.ai/install.sh | bash # macOS/Linux/WSL irm https://claude.ai/install.ps1 | iex # Windows PowerShell claude # OAuth login # Kit skills (global) cp -r uscha-kit/.claude/skills/* ~/.claude/skills/ # Optional — author's toolchain, not required by the kit (Gentleman's own bucket) scoop bucket add gentleman https://github.com/Gentleman-Programming/scoop-bucket scoop install gentle-ai claude --version && claude doctor # verify
On Windows, WSL2 is the recommended path (you install and run claude inside WSL). For headless/server: export ANTHROPIC_API_KEY=...
The kit installs on seven agents. What each one provides is not equal — and honesty means saying where it isn't.
| Agent | What it provides |
|---|---|
| Claude Code | skills, sub-agents, hooks — including the INV-GOLDEN-01 write hook (blocks the agent from authoring a .approved), --add-dir multi-repo. |
| Codex | .codex-plugin + skills + AGENTS.md as the context file. No native hooks: the golden guard (INV-GOLDEN-01) is not enforced there — that is an honesty line, not a minor detail. |
| pi · cursor · copilot · gemini · cline | the five skill-root targets: skills only (Agent Skills standard), no plugin, no hooks. |
The repo's stable protocol: commands, no-go zones, DoD, how to record evidence. The permanent stuff lives here; the per-change stuff in SPEC/ADR.
uscha-discovery, uscha-adr-refine, uscha-devloop, uscha-sysdoc, uscha-reverse-discovery, uscha-characterize, uscha-rubric, uscha-mirador, uscha-status in .claude/skills/. Callable, versionable, shareable with the team.
They parallelize the QA tools (review, security, improvements) without dirtying the main context.
They run gates on their own: post-edit tests, pre-commit lint. Evidence is captured by execution, not narrated.
You mount several repos in one session for integration/contract QA (multi-repo).
You follow and drive the session from your phone while the loop runs. Add plan mode, settings.local.json for permissions, and ccusage to monitor usage.
The truth survives the session close: engram stores LLM-oriented facts and decisions per project; MEMORY.md is the file-based auto-memory. It's the "the truth lives in files" rule extended across sessions, not just within the repo.
engram is OPTIONAL: uscha does not require it. The kit declares no dependencies at all (only Node ≥18 for the npm router and Python 3.8+ stdlib for the engine) and never names engram in a single line of what it publishes. They solve different problems: the project's truth lives in QA-LEDGER.json, versioned alongside the repo and shared by the team; engram holds the agent's memory, which is personal to each machine. Without engram the method works exactly the same — what you lose is agent context across sessions, not evidence.
Long /uscha-devloop runs bloat the transcript until the app hangs — seen live: 77 MB = lost session. A hook warns by size, a traffic-light map lists the at-risk sessions, and a rescue pulls the .jsonl into readable Markdown (author's setup — not shipped in the kit). Rule: rotate the session before the threshold.
Verified on Codex: installation, AGENTS.md, the portable prompts (templates/rubric-grader-prompt.md, templates/esceptico-prompt.md), the cross-vendor compilation arm (ADR-042: gpt-5.5 via codex-cli, --write-mode return, 0 shell commands), and — 2026-09-20, Codex desktop app, GPT-5.6 (ADR-049) — a full /uscha-devloop run end to end on a greenfield pilot repo: CONVERGED, the criterion closed MEASURED, stopped clean at the merge gate. Two limits remain: no native hooks on Codex, so the golden write guard (INV-GOLDEN-01) is not enforced there; and no live statusline, mitigated (kit 2.4.0) by printing the compact status readout in the visible reply on surfaces that have none.
Permanent rules that Claude Code reads every session. The per-change stuff lives in SPEC/ADR/ACCEPTANCE, not here. (If you use other agents, copy this file as AGENTS.md.)
/uscha-discovery or /uscha-adr-refine).// ADR: <slug>.Before modifying any tracked .md (CLAUDE.md, plan/delta docs, docs/adr), ask for the repo's current version first. Those files carry real progress (checkboxes, notes); never regenerate them from scratch.
A backend service (Java, Spring Boot, React, SQL), from idea to PR, all in Claude Code:
claude code · single session $ claude > /uscha-discovery 1×1 grill, proposes entities/endpoints, you decide 3 things ✓ CONTEXT.md · DOMAIN-MODEL.md · SPEC-001 · ADR-001/2/3 ✓ ACCEPTANCE.md · RISKS.md · HANDOFF.md > /uscha-devloop plan → coverage gate → build → QA loop (sub-agents) → integration CONVERGED · PR opened. I stop at the merge. > !python3 .claude/skills/uscha-devloop/qa_ledger.py readiness --acceptance ACCEPTANCE.md READINESS: 88/100 — RELEASE CANDIDATE > /uscha-sysdoc # two-view deck from the ledger # (you) review the PR and merge — the human gate is not automated
The tool executes. The methodology governs. The evidence decides. The human approves.
A minimal feature — applyDiscount(amount, percent) — walked end to end. 6 of the 10 steps are a failure or a refinement (marked ⚠): the methodology is not that everything goes right the first time — it's that every deviation has a gate that catches it.
/uscha-discovery "applyDiscount(amount, percent)" → 1×1 grilling (rounding? % bounds?). Out comes SPEC-001 + ACCEPTANCE + ADR-001.spec-check --spec SPEC-001.md → vague criterion; you rewrite it testable: "amount=100, %=20 → 80.00 (2 decimals)"./uscha-adr-refine "rounding: HALF_UP or HALF_EVEN?" → ADR-002, with the alternative recorded./uscha-devloop → plan → coverage → build → QA loop. Compiles, happy path green.pit-check → a mutant survives in the rounding: the test runs but doesn't assert the cent. You add assertEquals("80.00", …). Coverage was lying.gate-check --from-git → the agent lowered the coverage threshold in pom.xml to pass. Revert it, fix the test for real.rebuild --mode compare → the %=120 case was left implicit. You amend the SPEC (">100 or <0 → error"), regenerate, go back to Ready. You don't patch the code.simplicity-check --from-git → OVERBUILT: the diff blew its growth budget — the agent added a DiscountStrategyFactory for 3 lines (the abstraction count itself is only advisory). Trim it.readiness --acceptance ACCEPTANCE.md → 88/100 RELEASE CANDIDATE. You read the diff, approve the merge (never auto). /uscha-sysdoc builds the deck. Ship.If instead of creating applyDiscount you were porting it from the legacy, step 1 is different: /uscha-reverse-discovery maps the old system (facts) and /uscha-characterize captures the golden of the OLD code with real inputs. Then golden-diff byte-compares the new one vs .approved — any mismatch = DIVERGE. The agent never authors the .approved.
The skills are "shareable with the team" — but the behavior does NOT live in a single file. It's 7 layers + an external CLI + a path gotcha. Copying just settings.json isn't enough. Scope note: this taxonomy and the bootstrap script are the author's setup in Claude Code Desktop — not shipped in the kit; the kit itself only needs Python 3.8+, git, gh optional, the kit skills installed per agent, and per-repo config + permissions. Installing the kit on another agent needs none of this: npx --yes @andresmassello/uscha@latest install --target codex.
| Layer | What it is | How it's reproduced |
|---|---|---|
| Config | settings.json · CLAUDE.md · output-style · theme | copy (+ fix paths) |
| Plugins | engram · sonarqube | install from marketplace |
| Skills | ~/.claude/skills/ (uscha-discovery, uscha-devloop, QA...) | copy the whole folder |
| Agents + Commands | the sdd-* | copy verbatim |
| Hooks | gates + session hygiene (.ps1) | copy (they use $env:USERPROFILE, portable) |
| External CLI | gentle-ai (skill-registry hook) | scoop, Gentleman's bucket |
| MCP servers | computer-use, chrome, preview... | free with Claude Code Desktop |
settings.json carries the literal username (C:\Users\...). On another account it all breaks. The bootstrap tokenizes the path on export and replaces it with the local user on import.
It's not in scoop's main bucket. Add Gentleman's own bucket first, otherwise install fails with "couldn't find manifest".
# bootstrap: one command per side # on YOUR machine — build the bundle (no secrets, no memory): bootstrap-claude-setup.ps1 -Mode export -Bundle D:\claude-bundle # on the NEW machine (bundle already copied there): bootstrap-claude-setup.ps1 -Mode import -Bundle D:\claude-bundle # manual: gentle-ai (own bucket) + the 2 plugins via /plugin scoop bucket add gentleman https://github.com/Gentleman-Programming/scoop-bucket scoop install gentle-ai
Memory is NOT shared. engram + MEMORY.md are personal to each machine and build themselves as you work. Behavior is replicated; memory is earned.
To check on the fly when a term shows up in the slides. Not linear reading: jump here when you need it (End takes you to the end).
| SPEC | What must happen. A change's verifiable requirements. |
| ADR | Architecture Decision Record. Why this shape and not another; a decision with its alternatives. |
| CONSTITUTION | Invariants that no ADR or SPEC may violate. What is never acceptable. |
| ACCEPTANCE | A change's verifiable "done" criteria. |
| CONTEXT · DOMAIN-MODEL · RISKS · HANDOFF | Document package that /uscha-discovery produces: context, domain model, risks, handoff. |
| ISSUES-DEFERRED.md | Findings below the severity gate; they don't block, they're deferred. |
| LEARNINGS.md | Corrections compiled into principles (learnings loop). |
| /uscha-discovery | Idea→shape mode (greenfield): 1×1 grill, proposes entities/endpoints. |
| /uscha-reverse-discovery | Brownfield front: extracts FACTS from the old system (map + golden), doesn't propose shape. The human infers the SPEC. |
| /uscha-characterize | Captures the golden of the ORIGINAL code with real inputs; stops at human approval. The agent doesn't author the .approved. |
| /uscha-adr-refine | Mode for polishing architectural decisions. |
| /uscha-devloop | The orchestrator: plan → coverage gate → build → QA loop → integration. |
| /uscha-sysdoc | Generates the two-view deck from the ledger. |
| Human gate | The human approves the merge/release; never automatic. |
| qa_ledger.py | Measurement engine (stdlib): readiness, rebuild, simplicity-check, waste-check, pit-check, gate-check, spec-check, golden-diff, log-gate, flag-blocker, resolve-escalation. |
| golden-diff / .approved | Golden-testing gate: byte-compares .received vs .approved (field truth, human-approved). The agent doesn't author it. |
| facts vs prose | Guiding principle: gates that read facts block; those that guess over prose (spec-check's prose heuristics, abstractions) advise. spec-check's two structural checks are facts and block. |
| static gate (java-qa-gate) | Checkstyle / PMD / SpotBugs / FindSecBugs over the code. |
| ingest-gate | Parses the static gate's XML and normalizes it to a common severity scale. |
| severity gate | Threshold that blocks convergence: BLOCKER / CRITICAL / HIGH. |
| Readiness (KPI) | Score derived from state (tests / acceptance / coverage), with hard caps. Reports (always exit 0); not a pass/fail gate. |
| rebuild test | Is the SPEC enough to regenerate the system? Bands COVERS / PARTIAL / DIVERGE; exit 1 unless COVERS. |
| change budget | Max iterations / files / deps. Exceed it → escalation. |
| SIMPLICITY (Reduce) | Invariant: the diff's complexity budget. Bands SIMPLE / ACCEPTABLE / OVERBUILT. |
| maker ≠ checker | The one who makes doesn't graduate; a checker in fresh context validates (evaluator-optimizer). |
| captured evidence | Execution produces it (reports), not narration. Absent = no evidence. |
| inner loop | The rigorous per-change cycle (Uscha). |
| outer loop | The heartbeat that triggers machine-checkable maintenance. |
| heartbeat | The outer loop's trigger (Automations · /loop · /goal). |
| Ralph Wiggum loop | Silent failure: the agent emits the "done" token too early. |
| engram | Persistent LLM-oriented memory, per project, across sessions. |
| MEMORY.md | File-based auto-memory; a distilled index of facts. |
| session hygiene | Rotate the session before the transcript bloats and hangs it. |
| CWE | Common Weakness Enumeration: standard catalog of security weaknesses. |
| YAGNI | "You Aren't Gonna Need It": don't build what wasn't asked for. |
| progressive disclosure | Show the minimum first; defer the detail until it's needed. |
As a matter of principle: the ideas in this document didn't come from nowhere. The concept/idea I developed was later enriched with the following documentary contributions:
| Person / source | Contribution to this methodology |
|---|---|
| Birgitta Böckeler · martinfowler.com | "Maintainability sensors for coding agents" — the sensor framework (timing × nature), coverage vs mutation testing, computational vs inferential. |
| Addy Osmani | "The New SDLC", "Agentic Code Review", "Loop Engineering" — anti gate-gaming (red flags), uncorrelated checker (93.4% = 1 of 4 tools), reading test diffs more strictly, isolation via git worktree, fan-out ≤ review bandwidth. |
| Martin Fowler | Technical Debt Quadrant (inadvertent vs deliberate debt); his site is the home of much of these ideas. |
| Vlad Khononov | Learning Domain-Driven Design — the modularity framework that grounds the modularity review. |
| Dave Thomas & Andy Hunt | The Pragmatic Programmer (20th Anniversary Ed.) — convergence verified against the full book: "Don’t Assume It — Prove It" (measured beats narrated), Design by Contract (CONSTITUTION), blackboards (the ledger), Crash Early (fail-closed design); "Find Bugs Once" and tracer bullets feed the 2.0 backlog (uscha-kit/CHANGELOG-1.10.0.md … 1.19.0.md). |
| Andrej Karpathy | "Simplicity First" — KISS operationalized (minimum code, surgical changes, goal-driven). |
| John Maeda | The Laws of Simplicity — Law 1 (Reduce), the north star of the SIMPLICITY invariant. |
| Geoffrey Huntley | The "Ralph Wiggum loop": the silent failure of the premature "done" token. |
| Anthropic | Evaluator-optimizer (maker ≠ checker, Dec 2024); Claude Code; the simplify skill. |
| Gentleman Programming | Environment tooling: engram (persistent memory) and gentle-ai. |
Honest credit: the mutation testing technique is popularized by Stryker (JS) / PIT (Java); "Simplicity First" was operationalized publicly in Forrest Chang's repo (Jan 2026), Karpathy didn't endorse it. Under-attributing impoverishes; over-attributing lies.