@bigsteele/wiremap
v0.1.4
Published
Cable management for a codebase. Scores how far a repository is from one change, one place (tokens) and one question, one file (blocks), shows the blast radius of everything not yet wired, and ships the templates that wire it.
Readme
@bigsteele/wiremap
Cable management for a codebase.
Point it at a repository and it answers two questions with numbers:
- One change, one place? Is every value referenced by a name from one source of truth, or typed where it is used? A booking URL in nine files is nine edits when it changes.
- One question, one file? Is every file claimed by exactly one named capability, so that "if I change the email system, what am I touching" has an answer a person or a model can read instead of search for?
npx @bigsteele/wiremapWrites wiremap-<app>.md and wiremap-<app>.json into the repository, named for the app
so two scans never overwrite each other, and adds them to .git/info/exclude so they never
show up as untracked. That is a local exclude: it never edits a tracked .gitignore. Exit
code 0 when the gate passes, 2 when it does not, 1 when it refuses. (Read the code through
a pipeline and you get the pipeline's status, not the scan's.)
| Level | Name | Means | |---|---|---| | 0 | Tangled | values are typed where they are used; nothing says what the software is made of | | 1 | Labeled | tokens or a map exist, but nothing holds the codebase to them | | 2 | Tokened | one change to a value is one edit | | 3 | Blocked | one question about a capability is one file | | 4 | Wired | one change, one place; one question, one file; the map is what the model reads first |
The number it leads with
Not a percentage. Files touched today, against files touched once it is wired.
| What | Files today | Wired | Give it this name |
|---|---|---|---|
| bg-green-100 text-green-800 | 34 | 1 | the success token |
| url: https://system.example.com/…/consultation | 9 | 1 | CONSULTATION_URL |
| the number 10*1024*1024 | 4 | 1 | MAX_UPLOAD_BYTES |
That table is the report's first section, because it is the only part that makes the case on its own.
What it measures
Tokens. Custom properties, mapped into the utility layer, as four MEANINGS rather than four hues: success, warning, danger, info, each with an ink, an ink-on-its-own-surface and a tinted surface. Against them: every hardcoded palette class, arbitrary hex, bare white/black, raw value outside the palette file, colour set on a canvas or an SVG attribute, and colour in an inline style. Plus the three faults that hide: a token used that nothing defines (the class generates no rule and the element inherits at random), a token defined in one theme only, and a pair below WCAG AA.
The contrast check reads the pairs your code actually renders — an ink class and a
background class in the same class string — rather than assuming a convention. Codebases
commonly run two at once (text-success-foreground on bg-success-surface beside
bg-destructive text-destructive-foreground), and a checker that picks a side reports
failures against pairs that are never on screen. Each failure says how many files render
that pair and how many put anything on that colour at all.
Values. The same principle for everything that is not a colour: URLs, addresses, prices, route paths and the numbers that decide something, wherever they are typed in three or more files. One module owning the environment. Error codes that name their block.
Blocks. A manifest that claims every API route, shared module, lib file, component, hook, page, edge function and table exactly once, and a test that holds it to the filesystem on every surface with a floor so an empty listing cannot pass. Where there is no manifest, the scan drafts one from the import graph and says plainly that it is a draft.
Legibility. Whether the map is named as the agent's first read, whether it is generated rather than written, whether there is a dated counts snapshot, whether functions carry a design-doc header with a version stamp, and which capability has quietly become everyone's dependency.
It grades against your North Star, not the rubric's
A rubric will always find something. Before ordering anything, the scan looks for a North
Star: a NORTH-STAR.md from a Big Sean
run, a PRODUCT.md, or a north_star block in wiremap.config.json. Every finding is
then ranked by blast radius multiplied by how close it sits to the money path or the
critical few, and the multiplier prints beside each row so the ordering can be argued with.
Criteria that fall short but touch nothing the North Star names, and are not defects, go to a section called "Rubric items that do not serve your North Star" with the reason they wait. The scan never invents a mission: with no North Star it says UNKNOWN, orders by blast radius alone, and says what would settle it. A README that is still the generator's own counts as no North Star, because "simply visit the project and start prompting" is real prose about somebody else's product, and reading it as the mission would reorder every finding in the report around a scaffold.
Defects come before percentages
A token used but defined nowhere is not an unfinished migration; it is a bug that ships on every render. Those are listed first and hold the level down whatever the total says.
The how-to ships with it
Every step in the report names a template inside the package, and each template opens with what it is, what to rename, and the invariant it holds:
| | |
|---|---|
| templates/tokens/index.tokens.css | the token layer: two themes, four meanings, mapped into the utility layer |
| templates/tokens/design-tokens.test.ts | the ratchet, with its budget and its three blind spots closed |
| templates/tokens/tokenize-palette.mjs | the migration, matching whole idioms rather than single shades |
| templates/tokens/canvas-tokens.ts | the sanctioned resolver, with the dev probe that turns a silent canvas into a throw |
| templates/tokens/readable-ink.ts | computed ink for colour that is data rather than design |
| templates/values/env.ts, constants.ts | one module owns the environment; one home per repeated value |
| templates/blocks/blocks.json, blocks.test.ts | the manifest and the test that holds it to disk |
| templates/blocks/generate-blocks-doc.mjs, generate-codebase-snapshot.mjs | generated maps, because a written one drifts |
| templates/legibility/CLAUDE-three-maps.md, error-codes.md, function-header.ts | the section that makes the map the agent's first read |
Where the rubric came from
Every number in it was measured in a production codebase before it was written down. That
codebase went from 3,545 hardcoded palette classes across 267 files to zero, ratcheting
the budget down one migration at a time (3,533, 3,385, 3,218, 247, 0) and proving each new
number exact by first failing at one below it. Its map went from prose that claimed eleven
modules that existed nowhere to 21 blocks, 146 features, 913 names claimed exactly
once, asserted on every surface. CALIBRATION.md records the measurements and what this
scanner reads on those repositories today.
What it never does
No network, no database, no shell, no env files. It reads files in the folder you point it at. It never writes source text or a value into the report: findings are paths, counts and masked shapes. If any output string matches a credential shape, nothing is written and the exit code is 1, because that means a secret is committed and that is the thing to fix first.
Options
wiremap [dir] scan and write the report (default: here)
wiremap --stdout print it instead
wiremap --draft-blocks also write .planning/blocks.draft.json when there is no manifest
wiremap --profile <p> product | platform | library | marketing-site
wiremap --gate <score> the pass mark (default 30 and level 1 or above)
wiremap --json-only write only the JSONA repository may declare { "profile", "waive", "palette_files", "fixed_tokens",
"surfaces", "north_star" } in wiremap.config.json. A waiver needs a reason of at least a
sentence, the criteria that make the grade cannot be waived, and every declaration and
every refused waiver prints in the report.
After the report
Send it in at bigsteele.com/scan and get a written read of the three moves that cut your blast radius most, in order. Free, no call required, no pitch inside it. The live Scan Analysis call is $497, booked from the same page.
Big Steele · bigsteele.com
