TL;DR: Yesterday the GRID drew itself — a periodic
table of FAF skills at mcpaas.live/grid.
Today the GRID became a verb. Point it at any npm package or GitHub repo
and the same renderer reads the structure. ?npm=react, ?gh=facebook/react, ?npm=lodash. Same renderer.
Swappable adapters. A debugging surface for package.json, drawn
honestly — empty cells stay empty.
Try it
https://mcpaas.live/grid?npm=react https://mcpaas.live/grid?gh=facebook/react https://mcpaas.live/grid.txt?npm=react Three views, one URL primitive. HTML for the browser, plain text for the terminal/PR/email/IETF thread, GitHub repo for things outside npm. No install. No auth. No JS in the page itself — pure CSS Grid. Just paste a URL.
Yesterday: the grid drew itself
May 3 was an internal-architecture day. We’d been writing a 2-line FAF stamp into every markdown file across the FAF ecosystem — one stamp per skill, one per repo doc. A small comment block, invisible to humans, parseable by any AI.
When we ran a script over those stamps, something showed up that we hadn’t
designed. Plotted by (family, layer), the stamps formed a periodic
table. 4 families emerged from the data — FAF, TAF, WJTTC,
xAI — none of them enumerated anywhere. 9 layers. 58 stamped
nodes. 25 honest empty cells.
The empty cells weren’t aesthetic gaps. They were questions the
architecture was asking. Mendeleev’s periodic table didn’t just predict
gallium — it caught data inconsistencies. Same here. The GRID surfaced
its own stamp bug within an hour of going live (a misclassified family=FAF on a faf-taf-git CONTRIBUTING.md that
should have been family=TAF). We fixed it in v1.4.1. The grid drew
itself, then the grid found its own bug.
Yesterday was the architecture. Today is the product.
Today: the noun became a verb
The renderer was already general. The data sources just needed to be swappable. v1.5.0 ships three:
| URL | Source | What it shows |
|---|---|---|
/grid | FAF skills (baked) | The original periodic table — 58 stamps, 4 families, 9 layers, 25 empty cells |
/grid?npm=<pkg> | registry.npmjs.org | package.json across 6 blocks — identity, distribution, scripts, deps, engines, signals |
/grid?gh=<owner>/<repo> | GitHub API | package.json + project.faf + repo metadata, fetched in parallel |
Same renderer. Different adapters. Each source produces the same GridSource shape (blocks of slots); the renderer doesn’t know or
care where the data came from. Add a new source — add an adapter. Add a
new view — add a transform. Architecture clicks into place.
React, our story
React was the demo. Most-famous package on npm. We pointed the GRID at it and let the truth-printing rule do its job:
https://mcpaas.live/grid?npm=react At the time of writing, react@19.2.5 renders 11 of 33 slots filled, 22 empty, 1 warn. Those numbers are real, not curated.
What’s filled: name, version, description, license, main, exports, repository, homepage, bugs, keywords, sideEffects.
What’s empty: author (no individual attribution), contributors (none declared), funding (no sponsorship link), module (no ESM-specific entry), types (no TypeScript types declared at the package level), bin (no CLI), files (no whitelist), test/build/lint/typecheck/start/prepublish scripts (none declared), engines.node (no Node version pin), engines.npm/yarn (no pin), packageManager (no Corepack pin), publishConfig.
What’s warn: the missing engines.node pin.
A package this widely consumed not declaring its supported Node range is a
signal worth noticing.
This is react. The biggest package on npm. None of those facts are secret — they’re all in the published package.json. They’ve just never been rendered as a debugging surface before. npmjs.com renders package.json as marketing (downloads, popularity, install CTA). bundlephobia renders one slice (size). depcheck renders dependency health. None of them treat package.json as a spec to be drawn.
The GRID does. Empty cells stay empty. Sparse blocks stay sparse. We don’t pad. We don’t soften. We don’t grade on a curve. We print what we see.
The format draws itself
There’s a quieter doctrine landing alongside this ship. The text view at /grid.txt is itself a parseable format with its own grammar —
header, table, empty-cells list, footer. Anyone can write a parser for it
and reconstruct the underlying data.
That makes application/vnd.faf-grid a formal IANA
media-type candidate — sister to the already-registered application/vnd.faf+yaml. Same author. Same registry.
Two levels of recursion. The format is the moat.
Every ?source= we add inherits this media type. The renderer is
one implementation of the spec. The format is the moat.
What’s next: ?view=tsa
v1.5.0 only ships one view: ?view=structure (the default identity
transform). The architecture is now in place to add more.
v1.6.0 will add ?view=tsa — a behavioral view
that reads source files and classifies declared dependencies as CORE, ACTIVE,
DORMANT, or LEGACY based on actual import counts. The TSA engine
(“the TSA of package.json”, removed from faf-cli in the v6.0 cleanup)
ports almost verbatim — pure regex logic, easy to run in a Cloudflare Worker.
Its real home was always a URL surface, not a CLI command.
After TSA: ?pypi=requests, ?crate=tokio, and a ?view=score for FAF score breakdowns. Each adapter is ~150 lines.
Each view is ~80 lines. The renderer doesn’t change.
The Numbers
- v1.5.0 — mcpaas-cf, deployed 2026-05-04
- 63/63 — post-deploy WJTTC tests passed first try
- 864 KiB / 200 KiB gzip — bundle size (+26 raw, +6 gzip vs v1.4.1)
- 2 ms — Worker startup time
- 33 slots / 6 blocks — per npm package
- FAF skills grid — byte-identical to v1.4.1, verified
- 1 hour — KV cache TTL for npm + GitHub fetches
- 5000 req/hr — GitHub API ceiling with server-side PAT
Source
Full release notes on GitHub →
- Repo: Wolfe-Jam/faf-mcpaas
- Architecture:
src/grid/sources/npm.ts,src/grid/sources/github.ts,src/grid/views/structure.ts - Memory: cli-vs-url-migration-pattern, vnd-faf-grid-recursive-self-authoring, faf-truth-printing-applied-to-grid
