This morning, ModelFacts didn't exist. By lunch it had a spec, a schema, a validator, a generator, and a website. By the end of the day it had siblings with specs of their own. The family is now five labels and a hub. This post is about the labels, and a little about how a day like that is possible now.
It started with AppFacts, our nutrition label for software. Package manifests are complete but noisy: full dependency trees, dev tooling, pinned versions, written for package managers rather than for a person getting their bearings. README tech-stack sections are the opposite problem, readable prose that goes stale the week after you write it. AppFacts sits between the two. One small file, YAML a machine can parse on top, a rendered label a human can read in a minute below.
Then we noticed the same problem repeating at every layer of the AI stack, always at the same moment: right when you have to decide whether to trust something.
Model cards run thousands of words and can't be validated or compared. "Trained on the internet" is not a fact. An MCP server you install today can read your disk and call home, and nothing anywhere requires it to say so. An agent acting on your behalf has some set of things it will do without asking, and good luck finding that list written down.
The family
So AppFacts got siblings. One label per layer, each answering the one question you actually have at adoption time. The family door is xfacts.dev.
AppFacts labels the body. What is this app built from?
ModelFacts labels the brain. What went into this model, what
can it do out of the box, and how hot are its built-in filters?
ToolFacts labels the toolbelt. What does this instrument touch
when invoked?
AgentFacts labels the hands. What may this actor do, and on
what leash?
SkillFacts labels the playbook. What will this teach my agent
to do?
Every label follows the same two rules. First, objective facts only. "This model is very creative" belongs in marketing copy. "128k context window, trained on 15 trillion tokens, knowledge cutoff December 2023" belongs on a label. Second, when a developer withholds a fact, the file says undisclosed, because the absence of a fact is itself a fact worth labeling. A comparison table where half of one column reads "undisclosed" tells you something no marketing page will.
The most interesting reader of these labels isn't a person. It's your agent's harness.
A label a human reads is documentation. A label software acts on is infrastructure. ToolFacts is designed so a harness can read a toolset's side-effect facts and set approval policy mechanically: wave through the read-only tools, gate the writes, always ask before anything destructive. That's the trajectory for the whole family. Each label starts as a disclosure and ends as an input to policy.
What we didn't label
A suite like this dies by sprawl, so there's an admission rule. A label earns a domain only if someone adopts a thing and needs to trust it at that moment, the essential facts are objective and mostly machine-derivable, and no existing format already answers the question. DataFacts fails the third test, since dataset labels have been tried and the ground is well covered. PromptFacts fails the second, because prompts are mostly judgment. Saying no is the same muscle as always.
Where the labels come from matters too. Hard facts never come from prose. The generators pull them from structured sources that already exist: package metadata, model config, and for tools, what a server lists when you ask. The handshake is the inventory. A human still has to classify reach and side effects. That classification is the label.
About that one day
I wrote recently that if someone tells you their AI feature took a weekend, they built a demo. That still holds. July 31 bought specs, schemas, working tooling, and a plan. The months were never going to be a public directory of other people's tools.
The day itself is the point of the fire essay made concrete. The loop between having an idea and holding a working artifact used to run in months. And the reason four labels came fast is the other essay: the what was settled before any building started. Every label is the same decision, applied to a new layer. Once that's aligned, the hows get cheap.
Since then
I built the rest of the shop. A couple dozen tools, most of them public on the open-source shelf. They wear the labels.
AppFacts sits in the repo next to the README: ForgeTrail, Smell Check, FilePress, ollanet, LocalSlip, LocalHelm, and the rest of the shelf. ToolFacts sits on the MCP servers we actually run: ForgeTrail, ollanet, DictaWhisper. SkillFacts sits on the skills we publish, one file per package, not one file per product. TemperPass has four. DocuPuncture has three.
The portable viewer is live on each label site. A /v URL carries a compressed card in the hash. Nothing is stored on our server. You can pass
the link. LocalHelm can put those cards on a Sites board and show which repo is missing a label, or still showing yesterday's name.
Names moved. ForgeTrail used to be ForgeKit. Smell Check used to be aiBreze. LocalSlip used to be LocalBerth. A label that still says the old name is drift. The sites should say the names we ship.
What is not next: a directory of every public agent, and a sixth layer because someone asked. The admission rule still holds. The next load-bearing piece
is Panel, a derived view that notices when a tool surface changes. Native TOOL_FACTS.md stays the file you write until that lands.
Everything is open. The specs and schemas are CC0, the tooling is MIT, and the repos live on our GitHub. Adopt a label, or argue with a field. Do not send a new layer unless it clears the three tests.
If it's worth adopting, it's worth labeling.
Want your AI stack
this legible?
We help businesses find where AI fits, prove the value with a quick win, and make sure the team can own it going forward. Honest answers about what's slowing you down.
Tell Us Where It Hurts