Who says yes?
Agents can act. We never agreed on how they get permission — provably, from the right people, on the record. That's counter-sign.
Picture the moment. An autonomous agent, mid-task, resolves a step that reads: billing.wire — $42,000 → vendor. Everything before this point was reasoning and retrieval. This step moves money. And in almost every agent system shipping today, the honest answer to "what happens next?" is: it depends on whatever glue the builder happened to wire up that afternoon.
Maybe a message lands in a Slack channel with an Approve button. Maybe a webhook flips a boolean. Maybe — often — the agent just does it, because the demo needed to look autonomous. None of those approvals are verifiable after the fact. None of them survive an audit. And most of them can be manufactured by the very service that's asking the question.
We have spent the last two years standardising almost everything else about agents. MCP gave them a common way to reach tools. A2A gave them a common way to reach each other. But the oldest question in any system that can do something consequential — who authorized this, and can you prove it later? — is still improvised, per project, every time.
counter-sign is my attempt to give that question a real answer.
Proposing is not authorizing
The core move is almost boringly simple, and everything else follows from it: separate the act of proposing an action from the act of authorizing it.
An agent should be able to ask with full precision, and be completely unable to grant. A human (or a quorum of humans) should be the only party that can turn a proposal into authority — and that grant should be a cryptographic fact, not a UI event.
So counter-sign has two verbs.
First, the agent signs an Intent. This is a canonical-JSON envelope that pins down exactly what is being requested — the action, the amount, a risk tier, the number of approvals required, and a default to fall back to if nobody responds (usually reject). The agent signs it with its own ed25519 key over domain-separated bytes. Crucially, the Intent is a request. It carries no authority on its own. It is the agent saying, on the record, "here is precisely what I want to do."
Second, the required humans countersign it into authority. Each approver signs their own receipt with their own key. When two people approve, you get two independent signatures from two independently-held keys — and the moment those meet the quorum the Intent demanded, the action is authorized.
That's the whole shape: an agent signs its intent; a human countersigns it into authority.
Why the keys matter more than the buttons
The interesting engineering is in that second verb, and specifically in what happens when quorum > 1.
A naive "four-eyes" system lets one authority service vouch that N people clicked approve. But that just relocates the trust: whoever controls that service controls the approvals. If it's compromised, it can invent a quorum out of thin air, or approve on a user's behalf, and the receipt will look identical to an honest one.
counter-sign makes multi-party approval cryptographic separation of duty instead. For a quorum, every approver signs their own receipt with a key the service never holds. Each approver's key is bound in the agent-signed Intent, so an approver's key can't be quietly swapped. A party in possession of the authority key — the key that runs the flow — can neither forge the quorum nor stand in for an approver. The compromise of the coordinating server stops being game over.
Humans sign with passkeys / WebAuthn, which matters more than it sounds. It means there is no fresh secret to distribute, rotate, or leak: the approver uses the same platform authenticator they already trust to unlock their laptop or phone. The private key never leaves their device, and it never touches the server.
The artifact that survives the audit
Every decision — approve, veto, or a timeout falling back to the signed default — produces a receipt. Receipts are hash-chained into a tamper-evident, append-only log: change one entry and every entry after it stops verifying. And the whole thing verifies offline. Hand someone the receipts and the relevant public keys and they can confirm, months later and with no access to your systems, that this action was authorized, by these parties, under this quorum, at this point in the chain.
That is the deliverable that most "approval" systems never produce. A green checkmark in a dashboard is not evidence. A signed, chained, offline-verifiable receipt is.
Key bindings themselves come from an enrollment registry — an org-root-attested, append-only log that anchors each actor → key mapping, signed by an org-root key that is deliberately distinct from the runtime authority, with proof-of-possession required for every key (a raw-ed25519 self-signature, or a WebAuthn assertion for a passkey), plus revocation. It's the part that lets a verifier trust whose key they're looking at.
A protocol, not a product
counter-sign is an open protocol with a reference implementation, not a service you sign up for. That distinction is the point. If "who says yes" is going to be answerable across different agent frameworks and vendors, it has to be a spec that anyone can implement — and a spec is only real if independent implementations agree byte-for-byte.
So the repository ships conformance test vectors: a deterministic, language-neutral fixture set covering canonical-JSON known-answers, key derivation, signature vectors, signed Intents, keyed / vouched / timeout-default receipts, the accept and reject cases for resolution, and the receipt-log chain head. A second implementation in any language can check itself against them. Interop is provable, not assumed.
Everything runs locally. The library is on npm, and there's a single-org admin console you launch with one command — it holds no signing key of its own; your admin key signs each policy change client-side, in the browser, and the server only validates and stores.
npm i @countersignlabs/counter-sign # the protocol library npx @countersignlabs/console # a local admin console for your org
Code is Apache-2.0. The specification text is CC BY 4.0. Delivery adapters exist for the channels people actually approve from — Telegram, Discord, Slack, WhatsApp, email — so the human side can meet people where they are.
One rail of many that will be needed
counter-sign is deliberately narrow: agent-to-human authorization, and nothing else. But the shape it takes — cryptographic, human-named, mandate-scoped, non-repudiable — is the shape every emerging technology has eventually needed to reach regulated adoption. Aviation had flight plans and tail numbers. Payments had PCI-DSS and tokenization. Commercial drones needed Part 107. None of these made the underlying technology safer in the physics sense; they made it accountable, and only then did regulators sign off, insurers underwrite, and the market scale.
Autonomous agents are at the moment right before their accountability layer exists. I've been calling the general class of it Agent Accountability Rails (AAR): cryptographic, human-named, mandate-scoped accountability infrastructure for autonomous agents. counter-sign is one such rail — the authorization one. Others will follow: credential-issuance lifecycle, delegated-mandate transport across service boundaries, provider-side receipt verification. Each is a distinct spec; each is one component of the same category.
The point of naming the category is that no single vendor should own it. The next twelve months of enterprise AI adoption will be gated by whether these rails exist as neutral, open standards or as proprietary lock-in. That's a choice the industry gets to make once, and the wrong choice is very hard to reverse.
Where it is, honestly
This is v0.2.0, and I'd rather be precise than promotional about its state.
v0.2 deliberately broke the v0.1 wire format. The old integrity-only receipts predate per-approver keys and were forgeable by a compromised authority server, so a v0.2 verifier refuses them — loudly, never silently. If you have v0.1 archives, audit them with a v0.1 install. The passkey delivery and collection glue is marked experimental while I settle its shape; the raw-ed25519 approval path is the stable one to build on today. The keyed-quorum path has been through repeated adversarial review rounds and a browser + WebAuthn simulation harness exercising approve / veto / timeout / wrong-key end to end.
If you build anything that lets an agent take a consequential action, I'd value your eyes on the threat model — especially the compromised-authority-server case — before the wire format freezes. The spec is in /spec, the vectors in /vectors, and the whole thing is open at github.com/countersign-labs/counter-sign.
MCP gave agents tools. A2A gave agents colleagues. counter-sign gives agents a boss.