Permission to push a branch — not access to GitHub. A local daemon decides each agent effect against sentences you wrote, in your tools’ own seams, and writes the receipt.
$ cermet rules allow 'github.push where owner = "you" and name = "your-repo"' # your agent, later — ordinary git, no wrapper: $ git push origin main remote: cermet: carried main@9f8734c to you/your-repo (request req_d374a1b8…) # and in a repo no sentence admits: $ git push origin main remote: cermet: no standing authority for main on you/new-project remote: cermet: to allow: cermet rules allow 'github.push where owner = "you" and name in {"your-repo", "new-project"}'
The whole first session, scripted: install, connect, the agent's first deny, the one sentence that widens it, the receipt. Type each hinted command yourself, or just press Enter through it, or ▶ play. A replica: the words are what the shipped binary prints; nothing you type leaves this page.
That was a replica. The real one is a two-minute install: quickstart.
Cermet authorizes effects, not traffic. Your agent asks for a typed provider effect — refund this charge, push this branch, deploy this project — and a daemon on your machine decides it against sentences you wrote. Credential gateways inspect the traffic that carries an effect; Cermet represents the effect itself as the authorization object.
Not "this agent may use the Stripe credential." Not "this agent may POST to api.stripe.com." But "this agent may refund this charge, up to $50." (amount is Stripe's own integer minor unit: 5000 = $50.00)
allow stripe.refund where charge = "ch_X"
and amount <= 5000. A request that doesn’t parse into a known verb with
typed fields does not exist — deny by default; absence is never permission.git push stays plain git push; your own
vercel CLI runs your deploys; Cermet stands only in the credential-bearing
hop. The commands your agent was trained on are the commands it runs.secrets manager — who may possess a credential? credential broker — who may use one without possessing it? agent firewall — which authenticated requests may leave? cermet — which external effects may occur?
Each step down delegates less. The layers above are real and increasingly free; the decision that was missing is the last one.
Every request follows the same model — typed policy, integrity-bound fields, a single-use grant, a recorded result. What varies is the enforcement mechanism, chosen to fit each operation instead of forcing everything through one proxy:
run stripe.refund {charge, amount} → allow → broker POSTs /v1/refunds (pinned API version) → receipt
git push
reaches its mirror, the update hook asks your sentences, and on allow a credentialed
runner carries mirror → upstream. No wrapper, no token in the repo, one receipt in the
push output.git push → hook: allow github.push where owner = "you" … → carried remote: cermet: carried feat/x@9f8734c to you/repo (request req_d374…)
run vercel.deploy {project, team, target} → relay handle → vercel deploy --api 127.0.0.1:7133 --token cermet_relay_…
each hop: check shape → stamp credential → forward outside the shape → refused, burned
The credential never leaves the daemon in any of the three. What varies is only where the work lives: the broker's own frozen request, git's own plumbing, or the native CLI under per-hop supervision.
A Vercel token doesn't authorize a deploy — it authorizes the entire API.
The same credential that ships your site can natively run vercel env pull
(download your production secrets to disk), delete projects, and deploy anything else
the account reaches. Inside the deploy envelope, those requests have nowhere to exist:
the credential only materializes inside hops that match what an honest deploy actually
needs — nine request shapes, one bound create pinned to a project, team, and target,
follow-up reads chained to the deployment it created, ten minutes.
The chain is the provider's; the subtraction is ours. That is the ontology doing work: describe the effect, transcribe its legitimate traffic, and everything else the token could do stops existing.
Nothing about this is provider-specific. The same model narrows any API where a bearer token authorizes everything — including the services inside your own firm. Descriptors are declarations over HTTP: describe your internal services' effects, and an agent navigates your microservices under sentences instead of service tokens.
Policies bind typed fields of the requested operation — for a push: repository and branch; for a refund: charge and amount; for a deploy: project and target. Every bound must match or the operation is denied.
allow github.push where owner = "you" and name = "your-repo" ▲ ▲ │ │ git push → { owner: you, name: your-repo, branch: main, new_oid: 9f8734c… } every name matched → ALLOW — carried, receipt req_d374…
allow stripe.refund where charge = "ch_3TyX…" and amount <= 5000 ▲ ▲ id pins, like git's names …plus the bound only money gets ┌─────────────────────┴─────────────────────────────────┐ { charge: ch_3TyX…, amount: 480 } { charge: ch_3TyX…, amount: 9000 } 480 ≤ 5000 → ALLOW 9000 ⊀ 5000 → no sentence admits it → DENY the deny is kept losslessly — amount and all — and suggests the sentence that would widen it
allow vercel.deploy where project = "cermet-site" and target = "preview" ▲ ▲ { project: cermet-site, target: preview } ← frozen before the grant exists then, per hop: POST /v13/deployments { name: cermet-site … } ← must equal the frozen pin
The full index is a page: the WHERE index —
every field a sentence can bind, per verb, generated from the same descriptors the daemon
enforces. Live equivalent on your own box: cermet catalog --all. The rules of thumb:
identity fields (ids, names, refs) take = and in {…}; integer
side-effect fields (money) additionally take <=, >=, and
in; free text can only be pinned byte-for-byte, which is rarely useful —
bounds need typed fields; and the enumerate verbs (vercel.list_projects,
stripe.search_customers) are typically granted bare — you may enumerate, or
you may not. Syntax exists only for bounds
a delegating human would say out loud.
Cermet does not grant "access to GitHub." It grants github.push for a
particular repository. That authority is written as sentences in one reviewable file —
the grammar is deterministic; no model interprets the decision:
allow github.fetch where owner = "you" and name = "your-repo" allow github.push where owner = "you" and name = "your-repo" allow stripe.refund where amount <= 5000 allow vercel.deploy where project = "your-site" and target = "preview"
Production deploys, payouts, deletes — anything you didn't write a
sentence for — deny, and the denial tells you exactly what rule would widen it.
Your call, not the model's. The whole corpus is one file in your repo:
an example CERMET.md — edit, cermet doc apply,
done; a rebuilt box recovers its authority from git.
The audit log is not a text stream to grep later. Requests arrive already parsed by the grammar — provider, verb, typed fields — so every decision lands as a typed, hash-chained row in a SQLite database on your disk: what the agent asked, verbatim; the exact sentence that admitted it, stored word for word; the policy version it was decided under; the reason the agent gave; what executed; how it ended.
ALLOW stripe.refund amount=480 — allowed by: allow stripe.refund where amount <= 5000 DENY stripe.refund amount=9000 — no sentence admits it; the ask is kept, not blanked
Every row is written at the decision point and chained to the last;
cermet audit-verify checks the chain from genesis. The log records what
the broker admitted and executed, under the documented daemon and host trust model.
Reading this as an agent? The machine version of this site is at cermet.dev/agents.md (markdown) or cermet.dev/agents.html (HTML, same content) — guarantees, the authority language by real example, and the practitioner's view. Index at /llms.txt.
Linux amd64 and macOS arm64 — artifacts and checksums live on the GitHub release; the package configures and starts the daemon on install:
curl -fsSLO https://github.com/suarezc/cermet/releases/download/v0.1.0/cermet_0.1.0_amd64.deb curl -fsSL https://github.com/suarezc/cermet/releases/download/v0.1.0/SHA256SUMS | sha256sum -c --ignore-missing sudo dpkg -i cermet_0.1.0_amd64.deb
Bare binaries (linux, darwin) on the same release · then the quickstart: prove the plumbing, connect a provider, write your first sentence.
The tool is free. Your credentials never leave your machine — that boundary is the
product, and it is absolute. This build contains no telemetry and no Cermet service. Its
one network contact besides the providers you connect: a disableable daily update check
against GitHub Releases, carrying no installation identifier
(cermet update --daily off).
v0.1.0. Pure Rust, MIT — source at github.com/suarezc/cermet. Linux and macOS daemons. GitHub, Stripe, and Vercel today. This page ships through Cermet itself — the agent that wrote it never saw a token.