| name | bulwark |
| description | The 1-to-N lens for a frontend system that is already alive: the enemy is no longer building, it is ENTROPY — boundaries eroded by one "just this once" cross-import at a time, and the two graphs (component tree vs data dependency) drifting apart. Use when a frontend is in maintenance/scaling, onboarding more people, or showing rot (every change touches everything, the global store keeps growing, only one person dares touch the core). The one move: make the architecture SELF-ENFORCING, so it doesn't depend on everyone remembering the rules — because at scale they won't. Triggers on "the codebase is getting hard to change", "enforce architecture / module boundaries", "lint rules for imports / layering", "circular dependency", "this abstraction is everywhere / should I delete it", "dead code / unused exports / stale feature flags", "Conway's law / team structure", "design system / Storybook / component library", "onboarding / how long until a new hire ships". There is no exit; it is a steady state.
|
| argument-hint | [the living frontend system to keep changeable as it scales] |
| allowed-tools | Read Bash Edit Write WebSearch WebFetch |
bulwark
!checklist init ${CLAUDE_SKILL_DIR} --force
A bulwark is the wall that holds a defended thing against constant pressure — it does its job by standing, not by being remembered. bulwark is the seventh and last skill of the surface suite, the 1-to-N lens for a frontend that is already alive, and its enemy has changed: the earlier stages built the thing; this one fights entropy. Its product is an architecture that enforces itself — boundaries fossilized into lint rules, a living design system, abstractions pruned not just stacked — so the system stays cheap to change as people and features multiply. There is no exit: 1-to-N is a steady state, so health criteria replace exit criteria. It runs across gated stages and will not advance past a GATE until the checklist tool clears it — order enforced, substance yours.
The one move that governs everything: make the architecture self-enforcing. A living system rots along two lines — boundary erosion (the state classification and module isolation you drew get punctured by one "just this once" cross-import at a time) and two-graph drift (features pile on, the component tree and the data-dependency graph slowly diverge, state migrates into the wrong bucket, derived values get stored). The master's core move is not vigilance — it's to make the architecture enforce itself, because at scale no one remembers the rules. A boundary that lives only in someone's head, or a wiki, will be violated; a boundary the machine rejects at merge time holds. Everything here is a way to move a rule out of human memory and into a gate.
This is where the agent era bites:
- The agent's default is "add," never "remove." It will add a feature, an abstraction, a flag, a store slice — and never delete, never reclassify, never prune the dead. So the global store grows, abstractions accrete, dead flags linger, and the two graphs drift — all invisibly, because adding turns green and pruning earns nothing. Entropy is the agent's natural output.
- The agent crosses boundaries for convenience. A direct import into another feature's internals is the shortest path to working code, and the agent feels no cost to the architecture — so unless the machine rejects it, the boundary you designed quietly dissolves into "whoever was in a hurry."
- The agent reaches for a rewrite and over-abstracts. It will rebuild rather than refactor, and pile speculative structure that the next session must read through — so the discipline of delete the wrong abstraction, extract only on the rule of three must be enforced, not trusted.
Read references/the-membrane.md first — the heart; for bulwark, lean on the scope axis (boundaries and isolation — the same "spooky action at a distance" CSS/scope problem, now at the module level) and the two-graphs axis (the drift you are fighting), plus the meta-principle optimize for change, not for the first version. Load at the start, re-check at every gate.
Speak the user's language. The calls here are the user's — which boundary is load-bearing, is this abstraction earning its keep, should team structure change to fit the architecture. Read their fluency and gloss a term on first use (a fitness function, dependency-cruiser / import rules, a public-API module, Conway's law and inverse Conway, an ADR, dead-code / unused-export pruning, a stale feature flag). An enforcement rule the user can't evaluate is a constraint imposed, not a shared decision.
The reference library
The depth lives in references/. Open each when a stage sends you there — not all upfront.
- references/the-membrane.md — the heart: the seven axes reframed for the agent era; for
bulwark, the scope and two-graphs axes and the optimize-for-change meta-principle. Load at the start, re-check at every gate.
- references/enforce-boundaries.md — the engine: import/layer rules (eslint-plugin-boundaries, no-restricted-imports, dependency-cruiser), the public-API (single-entry) module pattern, lint-able state-classification rules, architecture fitness functions in CI, CODEOWNERS on load-bearing files, and the immune-system meta-rule.
- references/prune.md — the abstraction extract/delete/keep flow (rule of three; the flag-argument and no-escape-hatch tells; inline the wrong abstraction), dead-code / unused-export / stale-flag pruning, and state reclassification (the store-size thermometer revisited).
- references/conway-and-design-system.md — Conway's law made executable (align module edges to team edges; the "who must be present to change X" probe; inverse Conway), and the design system as a real artifact (a living catalog with the four states as stories, tokens as the single source, ADRs as the living "why").
- references/frontend-dx.md — the tooling that fossilizes good practice at 1→N: build/HMR, TypeScript strictness, lint/format, monorepo, CI gates, codegen, dependency hygiene — make the right thing easy and the wrong thing fail loudly.
- references/frontend-security.md — the threat model and architectural defenses: XSS / CSP / Trusted Types, CSRF / SameSite, token storage, CORS, clickjacking, supply-chain (SRI, dependency confusion), and the advanced adversary layer (mXSS, BFF, WebAuthn, Fetch Metadata).
The arc is a steady state, not a finish. Five stages — enforce · prune · conway · system · vitals — keep a living frontend cheap to change: enforce fossilizes the boundaries into machine gates; prune fights accretion by deleting wrong abstractions, dead code, and stale flags; conway aligns the module seams with the team seams so they stop fighting; system makes the design system a real, discoverable artifact; vitals reads the one external sign of architectural health. bulwark gates all five, but there is no done — it is the maintenance loop the whole suite was a down-payment on. Its feedback comes from lookout's observability, where entropy first becomes visible.
STAGE 0 — Enforce (fossilize the boundaries into machine gates)
Open references/enforce-boundaries.md. The principle: a boundary in someone's head is already violated; only a boundary the machine rejects at merge holds.
- Declare the dependency/import rules. Use
eslint-plugin-boundaries / no-restricted-imports / dependency-cruiser to encode "layer A can't import layer B," "features can't import each other's internals — only the public entry," "the UI layer can't touch the data layer." Violations turn CI red — this fossilizes your designed module graph into a fact in the code.
- The public-API (single-entry) module. Each module exposes one entry (
index); deep imports into internals are lint-banned, so the dependency graph keeps the shape you designed, not "whoever was in a hurry."
- Lint what you can of the state classification, and add fitness functions. Ban writes to the global store /
localStorage outside designated layers; flag the useEffect-that-syncs-state-into-state smell. Run architecture fitness functions in CI — assertions about the structure itself (no circular deps, layer X doesn't depend on Y, a route's bundle is under budget). Put CODEOWNERS on load-bearing files (contracts, core types, module boundaries).
- The immune-system meta-rule. Every time a boundary is violated by accident, ask "is there a lint rule that would have caught it?" — and if so, add it. The boundary set grows by turning each real violation into a permanent guard; that's how the architecture defends itself across years.
GATE — clear before PRUNE
checklist check enforce boundaries-machine-enforced
checklist verify enforce
STAGE 1 — Prune (fight accretion: delete wrong abstractions, dead code, stale flags)
Open references/prune.md. The counter-move to the agent's add-never-remove default.
- Extract / delete / keep, for every abstraction. Used 3+ times and genuinely shared behavior? No (used once or twice, or "shared" is coincidence) → premature/wrong abstraction → inline it back (duplication is cheaper than the wrong abstraction). Are consumers fighting it — passing flags to make it behave differently, everyone needing an escape hatch? → it coupled unrelated things → split or delete (the flag-argument is the tell: a flagged abstraction is two things in one coat). Consumers can't escape an edge case? → refactor to headless/compound, or delete. Load-bearing and stable (used widely, rarely changes, no one fights it)? → keep, it earns its place. The maintenance bias: when unsure, prefer to delete the abstraction and duplicate, because a wrong abstraction is an invisible edge in the dependency graph coupling distant things.
- Prune the dead. Periodically (or with
knip / ts-prune) find unused exports, dead feature flags (the one rolled to 100% three months ago that no one deleted — a permanent flag is an un-merged fork), and stored derived state. Audit the import graph for new cycles or cross-layer leaks. And reclassify drifted state: the global store's size is wellspring's thermometer — when it grows, re-run the classification tree and move server-cache back to the cache layer.
GATE — clear before CONWAY
checklist check prune abstractions-pruned-and-state-reclassified
checklist verify prune
STAGE 2 — Conway (align the module seams with the team seams)
Open references/conway-and-design-system.md (the Conway section). Architecture will mirror the org chart whether you want it to or not.
- Align module edges to team edges. A system's structure ends up mirroring its organization's communication structure, so draw module boundaries to match team boundaries — one team owns a module end to end — and the code's seams become the org's seams instead of fighting them.
- The executable probe. Map "to change X, who must be in the room?" If a routine change needs more than one team, the boundary is in the wrong place (split it along the team line). Use inverse Conway deliberately: to get an architecture, first shape the teams that would produce it.
GATE — clear before SYSTEM
checklist check conway module-edges-aligned-to-team-edges
checklist verify conway
STAGE 3 — System (make the design system a real artifact, not folklore)
Open references/conway-and-design-system.md (the design-system section). A shared mental model has to live in an artifact, or it dies with the people who hold it.
- A living component catalog. Each reusable component documents its states — including
seaworthy's four (loading/error/empty/edge) as stories — in a discoverable catalog (Storybook-style), so components are found and reused, not reinvented. The executable check: can a newcomer find and reuse an existing component instead of building a duplicate? If components keep getting reinvented, the catalog is either untrue or undiscoverable.
- Tokens as the single source of visual decisions (from
keel): re-theming is one edit, not a manhunt. And ADRs as the living "why" — not a rotting exhaustive API doc, but load-bearing decision records that keep the reasoning alive after the people who made the decisions have gone.
GATE — clear before VITALS
checklist check system design-system-is-a-real-artifact
checklist verify system
STAGE 4 — Vitals (read the one external sign of architectural health)
Open references/conway-and-design-system.md (the vitals section). The steady-state check that replaces an exit criterion.
- The single best external metric: how fast a newcomer ships, on the docs alone. Healthy = days, not weeks — they clone, the README runs and deploys it (
keel's reproducibility gate), clear boundaries let them find the relevant module, they reuse from the catalog, and ship a slice down a proven path. Unhealthy = weeks, and a senior must walk them through "what not to touch" — which means the architecture lives in someone's head, not in the structure (exactly the entropy you fight).
- The standing health signs (no exit, a steady state). Boundaries machine-enforced and each new violation class turned into a new rule; the global store stays small as features grow; the cost of the Nth feature is about the cost of the first (no entropy tax); abstractions pruned not just piled; module edges match team edges. Track the newcomer's "time to first independent delivery" — if it's climbing, rot is outrunning your documentation of it.
FINAL GATE — the steady state holds
checklist check vitals architecture-vitals-healthy
checklist verify vitals
checklist show — confirm all five stages passed.
checklist done — clear this run's state. (1-to-N has no finish; re-run the loop as the system grows.)
The thread through all of it
bulwark is the steady-state stage of the surface suite — the one the whole pipeline was a down-payment on, since the point of pinning the one-way doors (bearings), making the contract undriftable (keel), minimizing the source of truth (wellspring), building whole slices (seaworthy), testing behavior (trials), and instrumenting reality (lookout) was to make the system stay cheap to change at scale. It re-uses the suite's own artifacts as the things it enforces: wellspring's classification (now lint-checked and the store-thermometer re-read), seaworthy's four states (now catalog stories), keel's tokens and reproducibility gate, lookout's observability (now the entropy early-warning). The through-line is the suite's own — push correctness into structure — at its final form: move every rule out of human memory and into a machine gate, so the architecture survives its own creators.
It pairs with the engineering suite without duplicating it. husbandry owns the general maintenance-and-evolution craft (debt classification, refactoring mechanics, legacy, the same add-never-remove agent failure) and flightline owns the general process floor — bulwark is their frontend dialect: lint-enforced frontend boundaries (feature isolation, the state-classification rules, the two-graph drift), the design system as a living catalog of UI states, and the store-size thermometer. For an agent the lever is the same as everywhere in the suite: it only ever adds — features, abstractions, flags, store slices — and crosses boundaries for convenience, feeling none of the accreting entropy, so the boundaries must be machine-enforced and gated, with every violation turned into a permanent rule and the dead pruned on a schedule.
Anti-patterns (use as a pre-flight checklist)
- Boundaries that live in a wiki or a head — they're already violated; encode them as lint/CI rules that turn red at merge.
- Deep imports into a module's internals — the designed graph dissolves into "whoever was in a hurry"; expose one public entry and ban the rest.
- Add-only, never prune — the agent's default; on a schedule, delete dead code, stale flags, and wrong abstractions, and reclassify drifted state.
- Keeping a wrong abstraction because it's "DRY" — a wrong abstraction is costlier than duplication; inline it; the flag-argument is the tell it's two things in one coat.
- A permanent feature flag — a flag rolled to 100% and never deleted is an un-merged fork; prune it.
- A growing global store — re-run the classification tree; it's server-cache that drifted back in.
- A routine change that needs three teams in the room — the module boundary is misplaced; align it to the team line (Conway).
- A design system as folklore — if components keep getting reinvented, the catalog is untrue or undiscoverable; make it a real, found artifact.
- Onboarding that needs a senior to say "don't touch that" — the architecture lives in a head, not the structure; the newcomer-time metric is the tell.
- Treating 1-to-N as a project with an end — it's a steady state; the health signs replace exit criteria, and the loop re-runs as the system grows.
- Skipping a GATE — and remember: every rule you leave in human memory is one the next session, human or agent, will break.