emilia-protocol: authority checked before the protected tool runs
Authority control plane for autonomous work. EMILIA Gate enforces finite customer-owned mandates at protected executor boundaries; the open protocol keeps evidence verifiable.
At a glance
- What is it?
- EMILIA Protocol is an authority control plane for autonomous work. EMILIA Gate checks a customer-owned mandate at the executor boundary, the resulting receipts are meant to be verifiable under your own keys, and the repository is unusually explicit about which of its own claims are self-attested.
- Who is it for?
- emilia-protocol earns attention if your agent can move money or reach a credentialed provider, because it attacks the exact failure where an approval is reused after the approved thing changed. Two things to verify before you trust it.
- Can I use it commercially?
- Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 5, 2026, and from our analysis. They are not legal advice.
Editorial analysis
An $82,000 approval stops counting when the amount changes
The scenario the project opens with is a payment rather than an abstraction. An agent prepares an $82,000 supplier payment and a person approves it, and then the amount or the bank destination changes. The requirement that follows is narrow and testable: the earlier approval must not release the changed payment. That is the gap EMILIA Gate targets, checking authority before a protected tool runs rather than after it has already called the provider. The protocol layer underneath is meant to make the resulting evidence checkable under the verifier's own trusted keys and rules, and the design keeps your existing identity provider, agent framework and business systems in place. Nothing here asks you to replace your IdP. It also keeps two claims apart on purpose. The stated division of labour is that the protocol proves and the Gate prevents, and that split only holds on paths the deployment completely mediates. The repository publishes its machine-readable evidence, provenance, assumptions and exclusions at public/.well-known/emilia-context.json for reviewers who want the current version rather than a staged document.
The payment example binds approval to amount, currency, vendor and destination
The local example is the shortest path to understanding what a mandate contains. With Node.js 20.19 or newer and npm installed:
git clone https://github.com/emiliaprotocol/emilia-protocol.git
cd emilia-protocol
npm ci
FAST=1 node examples/mcp/payment-server.mjsThe listed behaviours are the interesting part. The example refuses a call that has no approval, binds the approval to the amount, currency, vendor and destination, admits the matching call once, and then refuses changed payment details, replayed calls and forged evidence. Admitting exactly once is what makes the demo a demo rather than a permission: a mandate that could be spent repeatedly would be a different product with a different risk profile, and the replay refusal is the check that proves it. Forged evidence is refused because the verification runs against keys the caller does not control. The same boundaries are available in three integration shapes: an MCP or HTTP Gate Starter for a single covered action, a wrapper for an existing Hugging Face smolagents tool, and a GitHub Merge Gate action that binds a check to a proposed merge, where the check must be required and the alternate merge paths closed.
Generated keys and a mock tool: what the demo refuses to prove
The payment example is labelled a local demonstration, and the label is load-bearing. It runs on generated signing keys, keeps consumption state in memory and calls a mock payment tool. It performs no real human ceremony and moves no money. That list is short enough to check against your own threat model, which is unusual for a project whose homepage leads with a dollar amount. Three production requirements follow from it: enrolled credentials, durable shared state, and Gate sitting on every path to the protected provider credential. The last one is the one teams tend to skip. An in-memory ledger cannot stop a second process that holds the same provider key, so a deployment with two paths to the credential needs Gate on both, and the project says outright that Gate cannot constrain a bypass path. One more sentence in the same section is worth keeping: a valid approval does not establish that the bank details are legitimate. The approval binds the fields you named; it does not vouch for them.
When a provider result is unknown, the lifecycle keeps it unknown
Most agent guards resolve ambiguity by retrying. This one refuses to. If a provider's result is unknown, the production lifecycle preserves that uncertainty for reconciliation instead of blindly retrying, and that choice propagates into the conformance vocabulary the project uses. AEB-1 Consequence Admission Conformance tests the composed CAID/AEC path at the last control point before a consequential action, and its checklist names the steps that make a no-blind-retry promise checkable: native verification, relying-party acceptance, exact-action binding, required CAID matching, required AEC evidence satisfaction, local authorization, atomic reservation, `INVOKING` custody, separate provider-outcome and observed-effect truth, no-blind-retry behaviour, and authenticated reconciliation. The interesting term is `INVOKING` custody, which is the window where the system knows it has committed to an action but does not yet know what the provider did. Under AEB-07, posted on 2026-09-25 as an individual Internet-Draft and not adopted by any working group, CAID is used only when independently encoded actions must be joined, and AEC only when local policy requires several evidence legs.
35 claims over 264 hashed evidence files, all of it self-attested
The numbers in this repository are unusually specific, and they are claims about the repository rather than measurements of a deployed system. The current state given is 35 security claims resolved over 264 hashed evidence files, 20 Tamarin lemmas across two composed Dolev-Yao models split into 17 all-traces obligations and 3 exists-trace reachability witnesses, and 8 deliberately weakened variants that produce concrete attack traces when load-bearing checks are removed. The live same-team conformance corpus holds 21 suites and 340 current vectors, while an externally authored Rust verifier is pinned to a frozen 16-suite, 164-vector bundle plus a 359-case hostility campaign, and the broader suite contains more than 10,700 automated tests across over 650 files. Each claim names its enforcement path, positive and negative vectors, language coverage, formal scope or explicit gap, assumptions, exclusions and an evidence hash. The weakened variants are the part a reviewer should care about most, since a check that never fails when removed has not been tested.
A passing AEB-1 report is evidence, not an audit
Two commands let you run parts of that yourself, and each carries a disclaimer that is part of the design:
npx @emilia-protocol/verify aeb-conformance --referenceThe pack is format-neutral and self-run, and a passing report is explicitly self-attested conformance evidence rather than an audit, a certification, a production-deployment claim, or permission to execute an action. The composition corpus is the one to read carefully before citing it:
npm run conformance:composition:consequence-admissionIt is a standalone lifecycle model with its own in-memory store and admission logic. It does not execute the shipped `@emilia-protocol/verify` or `@emilia-protocol/gate` code, so it is not evidence for those packages, which have their own test suites, and it is not evidence that the named native protocols, which include AuthZEN/COAZ-MCP, AP2 and the OAuth Transaction Token, conform to AEB-07. A 26-case synthetic corpus modelling the direct-native lifecycle is a design exercise. A repository that says so before you run it is easier to review than one that does not.
The runtime image deletes npm and pins libcrypto3 around an Alpine CVE
The Dockerfile is where the security posture stops being abstract. It builds in three stages from a digest-pinned `node:24-alpine` image, installs with `npm ci` from a copied lockfile, and then in the runner stage carries a comment explaining that the pinned base predates Alpine's CVE-2026-14456 fix, so the libraries are pinned explicitly to `libcrypto3=3.5.9-r0` and `libssl3=3.5.9-r0` to stop a rebuilt image from silently keeping the older 3.5.7-r0. The same stage strips package managers out of the runtime: npm, npx, corepack, yarn and yarnpkg are removed along with their directories, the image drops to a system `nextjs` user at uid 1001, and only the Next.js standalone output, static assets, public files and content pages are copied across. Port 3000 is exposed and the entrypoint is `node server.js`. Note the version spread inside the repository: package.json asks for Node 20.19.0 or newer while the image runs Node 24.
Base mainnet is the compose default, and the root release is six months behind
Two configuration facts decide what happens when you follow the quick path. docker-compose.yml starts only the Next.js app container, on port 3000 with restart unless-stopped, because EP requires a Supabase-compatible HTTP API hosted or self-hosted; .env.example adds that a raw Postgres container alone is not sufficient. `CRON_SECRET` has no safe default and must be set, while `EP_WALLET_PRIVATE_KEY` is optional and `BASE_RPC_URL` falls back to `https://mainnet.base.org`, so an unedited compose file points anchoring traffic at Base mainnet rather than a test network, where `BASE_NETWORK` also accepts sepolia and signing mode can be env, kms or hsm, with external modes requiring a registered custody provider. The release history is the other loose end. The root package is private at version 1.0.0 and v1.0.0 shipped on 2026-03-27, the last push was on 2026-10-02, and the newest tag is the package-scoped smolagents-v0.1.1 from 2026-09-06, so six months of commits sit outside any root release.
Editorial conclusion
emilia-protocol earns attention if your agent can move money or reach a credentialed provider, because it attacks the exact failure where an approval is reused after the approved thing changed. Two things to verify before you trust it. First, read what the demo does not do: generated signing keys, in-memory consumption and a mock tool, and a valid approval never establishes that bank details are legitimate. Second, read what the numbers mean, since a passing AEB-1 report is self-attested evidence rather than an audit, and the composition corpus never executes the shipped packages. Start at AI_CONTEXT.md, then run npx @emilia-protocol/verify aeb-conformance --reference and npm run proof:gate:reference on your own checkout before putting Gate on a path to a real provider credential.
Frequently asked questions
What does EMILIA Gate actually check before a protected tool runs?
It checks authority against a finite customer-owned mandate, and in the payment example the approval is bound to the amount, currency, vendor and destination, so a changed payment is refused.
Does the emilia-protocol payment example move real money?
No. It is a local demonstration with generated signing keys, in-memory consumption and a mock payment tool, so it performs no real human ceremony and moves no money.
What does a passing AEB-1 conformance report prove in emilia-protocol?
It is self-attested conformance evidence, not an audit, a certification, a production-deployment claim, or permission to execute an action. The pack runs with npx @emilia-protocol/verify aeb-conformance --reference.
Has the AEB-07 specification in emilia-protocol been adopted by a working group?
No. AEB-07 was posted on 2026-09-25 as an individual Internet-Draft and is not adopted by any working group, and CAID is used only when independently encoded actions must be joined while AEC needs several evidence legs.
Which Node.js version does emilia-protocol require?
The engines field asks for Node 20.19.0 or newer, the README says Node.js 20.19 or newer with npm installed, and the Dockerfile builds and runs on a digest-pinned node:24-alpine image.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/emiliaprotocol-emilia-protocol)