Architecture from first principles — the lens, and its executable checks

SkillDev tools

Evaluate an architecture against foundational principles of state, change, and time — five grounded principles PLUS a fixed set of named, executable review checks (C1–C7) run as a Workflow fan-out over a diff: ecosystem duplicates, consumer ergonomics, graduation sweep, one-hop depends-on, fresh-eyes, state-and-time, project conventions. Theory and execution in one skill; per-repo specifics live in .agency/architecture-first-principles.md. Use when designing/reviewing state models, from /be-review (runs FIRST on framework/structure diffs), or on any architecture/electricity review ask.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Architecture from first principles — the lens, and its executable checks skill

What this skill tells your AI

The instructions your AI receives, as published by juspay/kolu in .agents/skills/architecture-first-principles/SKILL.md and read by ahel’s review.

Two halves, one skill: the five principles (the state-and-time lens — what hickey's simplicity and lowy's boundaries don't own), and the checks (C1–C7) — named, verbatim hunter prompts that RUN the principles and their sibling lenses over a diff. The checks exist because prose advice does not survive contact: in one real week, five architecture smells shipped past a four-lens review and were each caught by the human — every miss a question nobody asked. The questions are now executable.

The five principles

Each: the principle · the diagnostic question · the make-it-unspellable fix. (Sources, compressed: Backus '78; Hickey "Value of Values"; Moseley & Marks "Out of the Tar Pit"; Bernhardt "Functional Core, Imperative Shell"; Lamport '78; Shapiro et al. CRDTs '11; Minsky "make illegal states unrepresentable"; King "Parse, Don't Validate"; Saltzer/Reed/Clark "End-to-End Arguments" '84.)

  • P1 — Values, not places. State is a succession of immutable values; change is a new value, never an in-place edit of a shared cell one party writes and another reads back as truth. Ask: is "the current state" a mutable place, or a value derived from history? Fix: delete the shared mutable place.
  • P2 — Pure core, effects at the edge. Logic is a function of its inputs; I/O, clock, randomness, network live at the boundary, passed in as values. Ask: can the core run with no I/O, no now(), no globals? Fix: move the effect to the edge; pass it in.
  • P3 — One authority, ordered, on its own clock. Every fact has one writer; concurrent merges must survive reorder + duplication (idempotent, commutative, associative); a consumer stamps time with its OWN clock. Ask: who is the sole writer? whose clock? does any correctness claim assume two clocks agree? Fix: one writer, the consumer's clock, or a lawful merge.
  • P4 — Illegal states unrepresentable. Shape the data so a wrong value cannot be constructed; parse once at the boundary; errors are values, not nullable holes. Ask: can a contradictory value exist at all? is null doing two jobs? Fix: discriminated union; the bad state becomes a type error.
  • P5 — Guarantees at the knowing endpoint. A guarantee belongs where enough is known to make it complete; lower layers may optimize but cannot guarantee. Ask: can this layer actually see enough to promise this? Fix: relocate the guarantee; keep the lower check as a removable optimization.

The canonical composite (P1+P2+P3+P4, not a sixth principle): a pure fold (state, event) → state over an ordered immutable log — the log is the truth, the fold is pure, the state is a value, the types forbid bad transitions, the consumer stamps its own clock. (Reducer / Elm / Redux / CQRS lineage.) Techniques this subsumes, so the set stays minimal: functional-core, FRP, free monads/effects (P2); optics (P1); errors-as-values (P4); CRDTs/CALM/logical clocks (P3); event-sourcing (the composite).

Relationship to the other lenses: hickey = static separation ("is it braided?"), lowy = static boundaries ("does it encapsulate change?"), this = dynamic state & time. Orthogonal; run all; one defect often shows on several axes — that is triangulation, not redundancy.

The checks — how a review actually runs

Project overlay

Read .agency/architecture-first-principles.md if it exists (the code-police .agency/ pattern). It parameterizes: C1's ecosystem hints, C3's layer ladder, C7's conventions coverage map, plus any project-added checks. Only C1/C3/C7 take overlay parameters; the rest are fully generic. Missing overlay → run generic and SAY so.

Mechanics (identical every run)

  1. Resolve the diff (git diff origin/<base>...HEAD) in a clean checkout.
  2. ONE Workflow: each check is a parallel agent() hunter, flat schema { findings: [{ title, file, line, class, severity(real|minor), detail, fix }] }. Substitute $ROOT/$BASE/$NEW_FILES + overlay parameters into the prompts verbatim — never paraphrase them.
  3. Verify pass: every real finding gets an adversarial refuter (CONFIRMED|WEAKENED|REFUTED, evidence-required). REFUTED drops; WEAKENED keeps only what survived.
  4. Report confirmed findings ranked with per-finding fixes; disposition each (fix now or record where) — "acceptable for scope" is not a disposition.

Scope rule — one hop down (non-negotiable): for every new module, list its non-framework imports and run the checks on those files too; most real misses live one hop below the diff.

C1 · ecosystem-duplicate — "does something already ship this?"

HUNT hand-rolled ecosystem duplicates in $ROOT (diff vs $BASE, plus one hop: the non-framework imports of $NEW_FILES). For EVERY mechanism the diff adds or stands on: does the project's dependency set, its ecosystem's standard libraries (overlay hints), the language/runtime built-ins, or an existing in-repo framework export already ship it? Check the manifest AND the lockfile — a transitive dep already present costs zero to adopt. Name the exact library API, cite the hand-roll file:line, judge adopt-vs-keep honestly. ONLY real duplicates — no "could theoretically use X".

C2 · consumer-ergonomics — "read every new export from the consumer's chair"

For EVERY new exported symbol, grep its real call sites and read them as the CONSUMER. Hunt: (a) double-derefs / awkward call shapes (nested accessors as API); (b) options required or documented but NEVER READ (dead knobs); (c) exports with zero production callers; (d) paired obligations the API could fuse; (e) policy callbacks that cannot reach the mechanism they need (forcing forward-reference hacks); (f) near-constant boilerplate at every call site; (g) names that lie at the call site. Evidence: the call-site code, quoted.

C3 · graduation-sweep — the boundary question, BOTH directions

Containment: did volatility leak INTO a module where it doesn't belong? Graduation: does the diff CREATE app-local machinery HIDING a hard volatility (transport, connection lifetime, reconnection, multiplicity racing intent, persistence, context loss) that wants its own receptacle — NAMED, with the volatility and the home, EVEN AT POPULATION ONE (a recorded opportunity, never a blocker; prove-then-extract gates the act, not the naming)? Judge LAYER PLACEMENT against the overlay's ladder — lowest honest layer. State DEFENSIBLE placements explicitly; no moves for tidiness.

C4 · depends-on — "audit what the new code stands on"

Trace every non-framework import of $NEW_FILES into the PRE-EXISTING code it leans on; audit THOSE files for: detached lifetimes with discarded disposers; module-global mutable state / caches whose lifetime mismatches the new consumer; hand-rolled duplicates (C1's bar); sentinel/null-overload hacks; fail-fast throws whose reachability the diff CHANGED (a boot throw now triggered by persisted state); proxies/singletons with surprising semantics as a foundation. Report: the pre-existing hack + the NEW call site leaning on it.

C5 · fresh-eyes-consumer — "read only the public surface, know nothing"

You know NOTHING of this change's implementation or history. Read ONLY the public surface: touched packages' READMEs, exported symbols/types, any design doc the PR cites. As a competent newcomer: (a) every export you cannot explain from the README alone (undocumented or stale docs); (b) every name or call shape that confuses you; (c) every doc claim the exports contradict. Your confusions ARE the findings — no deference.

C6 · state-and-time — the five principles, executed

Run P1–P5's diagnostic questions (above) over the diff's state-bearing code: mutable place read back as truth? core reaching for now()/globals? sole writer per fact + whose clock + do merges survive reorder? constructible contradictions / two-job nulls? guarantees at a layer that can't see enough? SPECIAL CASE that hides from per-field audits — the FLAT FACTS-PRODUCT: any product of primitive fields feeding a decision function (a resolver, a renderer) where some field's VALIDITY has a precondition on another field ("this health claim is only groundable when that state is connected") left as arm-order/convention. Each field reads honest alone; the lie lives in the joint distribution. Demand the precondition be encoded as DISCRIMINATION (the dependent fact exists only on the arm that grounds it). Cite the violated principle per finding.

C7 · project-conventions — walk the overlay's coverage map

For each coverage-map row marked judgment-enforced, check the diff against that convention explicitly; report violations with file:line. Overlay absent → skip and say so.

Adding a check

A human catches a smell the checks missed → a GENERAL lesson lands here as a new named check or sharpened prompt line (and upstreams); a PROJECT lesson lands in the repo's .agency/architecture-first-principles.md. Never as advisory prose in another skill. A check earns its slot with: the seed miss, the question, the evidence bar.

Signals

GitHub stars
78
Forks
12
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
architecture-first-principles
Source
github.com/juspay/kolu