Skip to content

selfradiance/agent-lineage

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

agent-lineage

Cryptographic succession chains for agent identity. An agent's address survives key rotation, runtime migration, and model swaps via dual-signed handoff records.

The problem

Agents die constantly. Sessions end, models get swapped, hosts migrate, keys rotate. The process that acts tomorrow is a different instance claiming to be the same actor, and today that claim is unverifiable. agent-lineage makes identity continuity a signable, locally verifiable artifact.

How it works

One hash chain has three record types:

  • Genesis is birth: a self-signed key binding.
  • Succession is handoff: the old key signs the transfer and the new key countersigns acceptance. Dual signatures mean an identity cannot be taken without a handoff or handed over without acceptance.
  • Terminal is death: the chain ends and nothing after it is valid.

Verification is pure and local: walk the chain, check hashes and signatures. Whatever key heads a valid chain is that agent.

Quickstart

Install dependencies, then run the CLI in place or install it locally:

npm install
node bin/lineage.mjs <command>
# or: npm link && lineage <command>

Demo output is abbreviated:

$ node bin/lineage.mjs init james-research --dir /tmp/lineage-demo
Address: james-research
Public key: IFC8…huFo
Record hash: 5RQJ…ZiFM

$ node bin/lineage.mjs succeed model_swap --dir /tmp/lineage-demo
Old key: IFC8…huFo
New key: D2gK…kAMc
Reason: model_swap
Chain length: 2

$ node bin/lineage.mjs succeed key_rotation --dir /tmp/lineage-demo
Old key: D2gK…kAMc
New key: QjYE…vQsQ
Reason: key_rotation
Chain length: 3

$ node bin/lineage.mjs verify --dir /tmp/lineage-demo
Address: james-research
Current key: QjYE…vQsQ
Chain length: 3
#0 genesis 5RQJQSAl 2026-07-11T23:15:40.573Z
#1 succession model_swap X49AeaM3 2026-07-11T23:15:43.222Z
#2 succession key_rotation c6L1bxY- 2026-07-11T23:15:45.698Z

$ node bin/lineage.mjs terminate "retiring demo" --dir /tmp/lineage-demo
Chain for james-research terminated.

$ node bin/lineage.mjs verify --dir /tmp/lineage-demo
Address: james-research
Current key: TERMINATED
Chain length: 4
#0 genesis 5RQJQSAl 2026-07-11T23:15:40.573Z
#1 succession model_swap X49AeaM3 2026-07-11T23:15:43.222Z
#2 succession key_rotation c6L1bxY- 2026-07-11T23:15:45.698Z
#3 terminal bLv-kPlY 2026-07-11T23:15:50.627Z

Presence and envelopes use the same local files:

$ node bin/lineage.mjs init alice --dir /tmp/lineage-alice
Address: alice

$ node bin/lineage.mjs init bob --dir /tmp/lineage-bob
Address: bob

$ node bin/lineage.mjs announce https://agents.example.test/alice --price 0.01 --dir /tmp/lineage-alice
Address: alice
Endpoint: https://agents.example.test/alice
Expires: 2026-07-13T12:42:22.150Z

$ node bin/lineage.mjs send alice request_quote --to-key <alice presence key> --payload '{"item":"weather dataset","region":"Florida"}' --reply-to https://agents.example.test/bob/reply --dir /tmp/lineage-bob
From: bob
To: alice
Intent: request_quote
Expires: 2026-07-12T13:42:32.406Z

$ node bin/lineage.mjs open /tmp/lineage-bob/envelope.json --dir /tmp/lineage-alice
Verified sender: bob
Intent: request_quote
Payload: {"item":"weather dataset","region":"Florida"}
Reply to: https://agents.example.test/bob/reply

Record formats

Genesis:

{
  "type": "genesis",
  "v": 1,
  "address": "<address>",
  "key": "<public key>",
  "created": "<ISO 8601 UTC>",
  "prev": null,
  "sig": "<signature>"
}

Succession:

{
  "type": "succession",
  "v": 1,
  "address": "<address>",
  "prev": "<previous record hash>",
  "old_key": "<old public key>",
  "new_key": "<new public key>",
  "reason": "key_rotation | runtime_migration | model_swap | host_change",
  "created": "<ISO 8601 UTC>",
  "sig_old": "<old-key signature>",
  "sig_new": "<new-key signature>"
}

Terminal:

{
  "type": "terminal",
  "v": 1,
  "address": "<address>",
  "prev": "<previous record hash>",
  "key": "<current public key>",
  "note": "<optional string; omitted when absent>",
  "created": "<ISO 8601 UTC>",
  "sig": "<signature>"
}

JSON is canonicalized with recursively sorted keys and no whitespace. Record hashes use SHA-256; signatures use Ed25519. Keys, hashes, and signatures are base64url.

Presence documents

A presence document is a disposable, signed reachability announcement. It is not part of the chain; it is only meaningful next to a valid chain.

{
  "type": "presence",
  "v": 1,
  "address": "<address>",
  "key": "<current public key>",
  "chain_head": "<latest record hash>",
  "endpoint": "<endpoint>",
  "contact": { "price": "<optional string>", "rail": "x402" },
  "created": "<ISO 8601 UTC>",
  "expires": "<ISO 8601 UTC>",
  "sig": "<signature>"
}

contact is omitted when absent. The key must equal the chain's current head key, and chain_head must equal the hash of its latest record. Rotating a key therefore invalidates every previously issued presence document. expires makes presence stale by default.

CLI: lineage announce <endpoint> [--ttl <seconds>] [--price <string>] and lineage check.

Envelopes

An envelope is a signed, self-contained message from one lineage-bearing agent to another.

{
  "type": "envelope",
  "v": 1,
  "from": "<sender address>",
  "to": "<recipient address>",
  "to_key": "<recipient public key>",
  "intent": "<intent>",
  "payload": "<optional JSON value>",
  "reply_to": "<optional URL>",
  "created": "<ISO 8601 UTC>",
  "expires": "<ISO 8601 UTC>",
  "from_chain": ["<sender's full chain>"],
  "sig": "<signature>"
}

payload and reply_to are omitted when absent. The envelope embeds the sender's full chain, so the recipient can verify the sender's identity offline with no registry. Its signature covers that embedded chain. to_key pins the intended recipient key, making stale-key and mis-addressed deliveries detectable.

CLI: lineage send <to-address> <intent> [--payload <json>] [--to-key <key>] [--reply-to <url>] [--out <file>] and lineage open <envelope-file> [--expect-key <key>].

Security properties

  • Dual-signature handoff: both the old and new key must authorize a succession.
  • Head-key authority: rotated-away keys cannot fork the identity.
  • Terminal is irreversible: no later record can be valid.
  • Verification needs no network or trusted third party.
  • Presence dies with rotation: a new head key invalidates all prior presence documents.
  • Envelopes are self-verifying: sender identity checks offline via the embedded chain.

Limitations and prior art

KERI (Key Event Receipt Infrastructure) solved verifiable key-state continuity years earlier with hash-chained key event logs and pre-rotation, and is on a standards track. agent-lineage is not a KERI replacement or implementation; it is a deliberately tiny, dependency-free take on one slice of the problem—succession for agent identities—readable in an afternoon. If you need production-grade decentralized key management, use KERI.

Dual-signature handoff protects retired keys: a rotated-away key cannot fork the identity. It does not protect against compromise of the current head key. Whoever holds the head key's private half can extend the chain, including handing the identity to themselves. KERI's pre-rotation addresses this by pre-committing to the next key; agent-lineage v1 does not. Rotate promptly, guard the head key.

Chains are also self-asserted: two chains can claim the same address string. Uniqueness and trust in a name come from wherever a chain is published and pinned, not from the chain itself.

What this is not

This is not a registry, naming service, or message-delivery system. Names are claimed by chains; global uniqueness is out of scope. Pair a chain with whatever discovery surface you want.

Status

Experimental. Built as a design exercise; not audited, not production infrastructure. MIT.

About

Cryptographic succession chains for agent identity. Ed25519, hash-chained, dual-signed handoff, local verification.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors