How enforcement works
A promise you can’t verify is just marketing. The
values we hold are only worth anything because a machine keeps them
for us — automatically, in the open — so the people who depend on what you build
never have to take anyone’s word for it, including ours. The engine is a
TypeScript CLI (enforcement/cli.ts) that runs in CI on every pull request and
weekly against the whole catalog, checking three independent layers — something
can hide from one, but not all three.
-
Check one
We read the label
We read each tool's own list of ingredients and flag anything owned by a gatekeeper we exclude.
In plain terms What it openly declares.
-
Check two
We trace the whole chain
We follow the full supply chain — what your tool depends on, and what those depend on — and show the exact path to anything excluded.
In plain terms What it quietly pulls in.
-
Check three
We check what it reaches
We scan the code for hidden connections — imports, addresses, and settings — that phone home to an excluded provider.
In plain terms What it actually talks to.
Fail any one check, and it isn't listed.
No warnings. No exceptions. No override.
The checker runs offline and returns the same answer every time — and it's open source, so anyone can read the rules and run it themselves.
Layer 1 — direct dependencies
Section titled “Layer 1 — direct dependencies”Layer 1 reads a project’s manifests — package.json, Cargo.toml,
pyproject.toml/requirements.txt, go.mod, mix.exs, pubspec.yaml,
Gemfile, and Gradle build files — and flags any directly declared
dependency owned by an excluded organization. For the catalog itself, it also
reads every entry’s frontmatter and confirms the tool it describes isn’t an
excluded package.
Example: adding
openaitopackage.jsonfails Layer 1 with"openai" → openai (npm_package: openai).
Layer 2 — the transitive tree
Section titled “Layer 2 — the transitive tree”The dangerous case is the dependency you didn’t choose: a library you trust that quietly pulls in an excluded client three levels down. Layer 2 walks the full lockfile graph — across 13 formats (npm, pnpm, yarn classic & Berry, Cargo, uv, Poetry, pip-compile, Go modules, Bundler, Hex, pub, Gradle) — and reports the entire chain to the excluded package.
Example:
a@1.0.0 → openai@4.0.0 → openaishows exactly how the excluded package got in.
Layer 3 — provider strings in source
Section titled “Layer 3 — provider strings in source”Ownership isn’t the whole story: a permissively-licensed, independently-owned library can still ship code that calls an excluded provider. Layer 3 scans source for three kinds of signal:
-
Imports —
import OpenAI from "openai",from facebook_business …,use async_openai::— the strongest signal, hardest to explain away. -
Endpoints —
api.openai.com,api.x.ai,graph.facebook.com. -
Config keys —
OPENAI_API_KEY,XAI_API_KEY,META_APP_ID.
Endpoints and config keys can appear in negative contexts (“we deliberately do
not call api.openai.com”), so Layer 3 reports each match with file:line
for human review and weights imports highest. The signal definitions live in
enforcement/excluded-provider-signals.yaml.
Locking down configurable tools: recipes
Section titled “Locking down configurable tools: recipes”A tool that is itself configurable to reach an excluded provider may be admitted only under a provider-lockdown recipe — and the recipe must prove the excluded providers are forbidden, not merely available. This is enforcement of the exclusion, not an exemption from it. Layer 3 validates each recipe against a contract:
- it must target a catalog entry marked
provider_agnostic: true(i.e. the tool has a configurable provider picker); - every excluded LLM provider (OpenAI, xAI) must appear in the recipe’s
must_not_be_one_oflist — otherwise the recipe does not actually forbid them and is rejected; - no “permitted” provider may itself be an excluded organization;
- verification steps must block the excluded providers’ endpoints.
A recipe that forgets to forbid OpenAI fails the build. See the Shakespeare lockdown recipe for a passing example.
What runs, and when
Section titled “What runs, and when”| Trigger | What runs |
|---|---|
| Every pull request | Layer 1 (catalog) + recipe validation + astro check + dead-link check |
| Weekly cron (Mondays) | All three layers + license-watcher + maintenance-checker, opening PRs with any drift |
| Locally, any time | npm run enforce or enforcement/cli.ts all --tree . |
The engine has a test suite of its own (40+ tests covering every parser and the recipe contract), because the thing that enforces accountability has to be accountable too.