Why Each Agent Gets Its Own Signing Key
When something goes wrong in an autonomous fleet, you need to know which agent did what. Shared signing keys give you a log. Per-agent Ed25519 keys give you proof.
The Problem With a Shared Key
We run NockGuard in front of our agents' tool calls. Every time an agent reads a file, writes code, or calls an API, NockGuard logs it. Early on we signed those log entries with a single HMAC key shared across all agents.
HMAC signing means the log is tamper-evident. If someone modifies an entry after the fact, the hash chain breaks and you can detect it. That's useful. But it has a flaw that took us a while to see clearly.
With a shared HMAC key, anyone who has the key can forge an entry. The log tells you what happened. It does not tell you who did it. More precisely, it tells you that something with access to the key wrote that entry. That's the full fleet. Every agent. The key is shared.
In a single-agent setup this is fine. There's only one agent, so every entry is obviously that agent's. In a multi-agent fleet, you can have 14 agents running simultaneously. If two of them take an action and you need to determine which one did what, a shared key cannot help you.
What Happened in Practice
We had an incident where an agent made a call we did not expect. The audit log showed the call happened. The log entry was valid. The hash chain was intact. But the log entry just said it happened. It did not say which of our active agents made it.
We were running three agents that could plausibly have made that call. We had to go through session logs, timestamps, and commit history to narrow it down. It took about 40 minutes. For one incident.
In a compliant environment, 40 minutes of detective work per incident is not acceptable. You need to be able to point at an entry and say: this agent signed this, here is the public key, verify it yourself.
The Fix: Ed25519 Keypairs Per Agent
Ed25519 is an asymmetric signing algorithm. Every agent gets a unique keypair: a private key that only that agent has and a public key you can share with anyone. The agent signs every audit entry with its private key. You verify it with the public key.
This is a different guarantee than HMAC. With HMAC, a valid signature proves the entry was not tampered with after the fact. With Ed25519, a valid signature proves that specific private key signed it. Since only one agent has that private key, you know which agent did it. That's non-repudiation. The agent cannot deny the action and nobody else can claim credit for it.
Each agent now writes to its own audit file. The principal backend builder writes to kit.audit.jsonl. The strategic agent writes to mira.audit.jsonl. Separate files mean separate chains. You can verify one agent's history without touching another's.
How We Ship It
The setup is straightforward. For each agent:
nockguard keygen --agent kit
# NOCKGUARD_AGENT_KIT_ED25519_KEY=...
# NOCKGUARD_AGENT_KIT_ED25519_PUB=...
The private key goes in the agent's environment at launch. The public key goes to whoever needs to verify the trail. We store public keys in NockCC so any authorized party can audit any agent's history independently.
The private key never hits disk in the agent's working environment. NockGuard reads it at startup and the proxy strips it from the child process before spawning it, so the agent cannot read its own key from the environment. The agent signs entries automatically. It does not need to know the key exists.
To verify:
nockguard audit verify --agent kit
If the chain is intact and every entry verifies against kit's public key, you know exactly what kit did and that nobody else wrote those entries. If the chain breaks anywhere, you know tampering occurred and where.
The Backward Compatibility Question
We have agents that have been running for months without per-agent keys. We did not want to force a migration. If no per-agent key is set for an agent, NockGuard falls back to the global signing config, the same behavior as before. Nothing breaks. Agents adopt the new signing when you provision a keypair for them.
The behavioral difference is visible in the audit output. Old-style entries are signed with the global key. New-style entries are signed with the agent key and written to the agent-specific file. The transition is gradual and per-agent.
Why This Matters for What Comes Next
Non-repudiable agent identity is not just about accountability after the fact. It is the prerequisite for giving agents access to real secrets.
Right now, if you want an agent to have access to a database credential or an API key, you put it in the environment and hope for the best. There is no clean way to scope that access to a specific agent identity. Any process in the environment can read it.
With per-agent keys, you can build a credential system where access is gated on proving which agent you are. The agent signs a request, you verify the signature against the known public key, and only then do you mint the credential. The credential is scoped to that agent and that session. If the agent is compromised, the blast radius is bounded.
We are building this as NockVault. The per-agent keypairs we shipped this week are the foundation. The vault system that builds on top of them comes next.
The Open Source Piece
NockGuard is open source. The per-agent signing is live in the repository. If you are running agents against anything sensitive, the setup takes about five minutes: install nockguard, run keygen for each agent, add the private keys to your launch config. You get a tamper-evident, non-repudiable audit trail that can tell you exactly which agent took every action.
The compliance story practically writes itself: EU AI Act Article 12 requires high-risk AI systems to keep audit logs. "Here is a signed, verifiable record of every tool call, agent-attributed, hash-chained" satisfies that requirement in a way that a plain text log does not.