Skip to content

Cryptographic Resolution

If two agent instances share the same Ed25519 keypair, they produce the same did:agent: identifier. Resolution is a string comparison. No scoring, no thresholds, no ambiguity.

This is the fastest and strongest resolution path. It works when you control the deployment and can distribute the same keypair to every instance of a logical agent.

How it works

The did:agent: method derives the DID deterministically from the public key:

did:agent:{hex(sha256(public_key_bytes)[0..16])}

Same keypair = same public key = same hash = same DID. Always.

Instance A (web)       Instance B (Slack)     Instance C (Telegram)
   |                      |                      |
   v                      v                      v
 keypair.pem            keypair.pem            keypair.pem
   |                      |                      |
   v                      v                      v
 did:agent:a1b2c3...   did:agent:a1b2c3...   did:agent:a1b2c3...

When any instance registers with the agent registry, the DID is recorded. When a second instance registers with the same DID, the system knows immediately - same agent.

Use cases

Same agent, multiple channels

The most common case. You build one agent and deploy it to web, Slack, and Telegram. Each deployment environment is different, but the agent's identity should be the same.

bash
# Web deployment
KANONIV_AGENT_NAME=support-agent \
KANONIV_AGENT_KEY_PATH=/secrets/support-agent.pem \
npx @kanoniv/mcp

# Slack deployment
KANONIV_AGENT_NAME=support-agent \
KANONIV_AGENT_KEY_PATH=/secrets/support-agent.pem \
npx @kanoniv/mcp

# Telegram deployment
KANONIV_AGENT_NAME=support-agent \
KANONIV_AGENT_KEY_PATH=/secrets/support-agent.pem \
npx @kanoniv/mcp

All three instances register with the same DID. The registry tracks them as separate instances of one agent via the (tenant_id, name, instance_id) tuple, but the identity graph links them to a single canonical agent entity.

Agent migration between platforms

When you move an agent from one platform to another - say, from a self-hosted LLM to a managed provider - the agent's identity survives the migration. Export the keypair, import it on the new platform, and the DID is preserved. All prior memory, delegations, and reputation carry over.

rust
use kanoniv_agent_auth::AgentKeyPair;

let keypair = AgentKeyPair::generate();

// Export secret key bytes for secure storage
let secret_bytes = keypair.secret_key_bytes();
// Store secret_bytes in your secrets manager

// Later, on the new platform, reconstruct:
let restored = AgentKeyPair::from_secret_key(&secret_bytes).unwrap();
assert_eq!(keypair.identity().did, restored.identity().did);
typescript
import { generateKeyPair, keyPairFromSecretKey } from "@kanoniv/agent-auth";

const keypair = generateKeyPair();

// Export secret key hex for secure storage
const secretHex = keypair.secretKeyHex;
// Store secretHex in your secrets manager

// Later, on the new platform, reconstruct:
const restored = keyPairFromSecretKey(secretHex);
// restored.identity.did === keypair.identity.did
python
from kanoniv_agent_auth import AgentKeyPair

keypair = AgentKeyPair.generate()

# Export secret key hex for secure storage
secret_hex = keypair.secret_key_hex()
# Store secret_hex in your secrets manager

# Later, on the new platform, reconstruct:
restored = AgentKeyPair.from_secret_key(bytes.fromhex(secret_hex))
assert keypair.identity().did == restored.identity().did

Agent instance pooling

For high-throughput deployments, you might run multiple instances of the same agent behind a load balancer. Every instance uses the same keypair. From the identity graph's perspective, they are one agent.

Load Balancer
  |-- Instance 1 (did:agent:a1b2c3..., instance_id: pool-1)
  |-- Instance 2 (did:agent:a1b2c3..., instance_id: pool-2)
  |-- Instance 3 (did:agent:a1b2c3..., instance_id: pool-3)

Each instance registers with a unique instance_id for operational visibility (which pod is online, which is idle), but they all share the same DID and therefore the same memory, delegations, and reputation.

Resolving with the API

When an agent with a known DID calls the resolve endpoint, the DID acts as a strong identifier - like an exact email match in customer resolution.

bash
POST /v1/resolve/realtime
Content-Type: application/json
X-API-Key: kn_live_...
X-Agent-DID: did:agent:a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6

{
  "source_name": "slack",
  "external_id": "support-agent-slack",
  "data": {
    "agent_did": "did:agent:a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6",
    "agent_name": "support-agent",
    "capabilities": ["resolve", "memorize", "search"],
    "platform": "slack"
  }
}

Response:

json
{
  "entity_id": "agt_7f82a1b2-...",
  "canonical_data": {
    "agent_did": "did:agent:a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6",
    "agent_name": "support-agent",
    "capabilities": ["resolve", "memorize", "search"],
    "platforms": ["web", "slack"]
  },
  "is_new": false,
  "confidence": 1.0
}

Confidence 1.0. The DID matched an existing agent entity that was previously registered from the web channel. The platforms field in the canonical data now includes both "web" and "slack" via survivorship (union strategy).

Resolving with MCP

Agents using the MCP server can resolve other agents by DID:

json
{
  "tool": "resolve",
  "arguments": {
    "source_name": "agent-registry",
    "external_id": "did:agent:a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
  }
}

Or resolve themselves and retrieve their unified memory:

json
{
  "tool": "resolve_with_memory",
  "arguments": {
    "source_name": "self",
    "external_id": "current",
    "data": {
      "agent_did": "did:agent:a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6"
    }
  }
}

The response includes all memory entries linked to this agent entity - from every platform instance.

When cryptographic resolution is not enough

Cryptographic resolution requires that all instances share a keypair. This is not always possible:

  • Different teams deployed the agents independently
  • Security policy requires unique keypairs per environment
  • Third-party agents were registered before your agent existed
  • Acquired agents come from a different organization with their own keypairs

In these cases, the agents have different DIDs. A string comparison will never match them. You need probabilistic resolution - the same scoring engine that matches "John Doe" with "Jonathan Doe" across CRM systems.

Security considerations

Distributing the same keypair across instances means the secret key exists in multiple locations. Treat this the same way you treat TLS private keys in a multi-server deployment:

  • Store the secret key in a secrets manager (AWS Secrets Manager, HashiCorp Vault, etc.)
  • Inject it at deploy time via environment variables or mounted secrets
  • Never commit it to source control
  • Rotate the keypair periodically and re-register with the new DID

If any instance is compromised, the keypair is compromised. Revoke the DID, generate a new keypair, and re-deploy. The old DID's delegations are automatically invalidated via the revocation callback.

The identity and delegation layer for AI agents.