| name | p2p-chronicle-log |
| description | P2P append-only action log for distributed agent audit trails. Peer-to-peer replication, content-addressed entries, causal ordering, and tamper-evident chain without central coordinator. Sources: mafintosh/chronicle (MIT). |
/p2p-chronicle-log
When to Use
- Distribute the yamtam audit log across multiple agent nodes without a central server
- Causal ordering: agent B sees agent A's action before acting on it
- Tamper-evident: Merkle-backed log where any edit breaks all downstream hashes
- Offline-first: agents append locally, sync when peers reconnect
Do NOT use for
- Strong consistency required (use [[etcd-distributed-config]] with Raft)
- Simple local audit logging (use [[append-only-hypercore]])
Append-only log (hypercore-based P2P)
import Hypercore from 'hypercore'
import Hyperswarm from 'hyperswarm'
import crypto from 'hypercore-crypto'
const core = new Hypercore('./data/agent-audit-log', {
valueEncoding: 'json',
})
await core.ready()
console.log('[chronicle] key:', core.key.toString('hex'))
console.log('[chronicle] length:', core.length)
async function logAction(agentId: string, action: string, meta: object) {
await core.append({
agentId,
action,
meta,
ts: Date.now(),
seq: core.length,
})
}
for (let i = 0; i < core.length; i++) {
const entry = await core.get(i)
console.log('[chronicle]', entry)
}
P2P replication via Hyperswarm
import Hyperswarm from 'hyperswarm'
const swarm = new Hyperswarm()
const discovery = swarm.join(core.discoveryKey, { server: true, client: true })
await discovery.flushed()
swarm.on('connection', (socket, info) => {
console.log('[chronicle] peer connected:', info.publicKey.toString('hex').slice(0, 8))
const replicationStream = core.replicate(info.client)
socket.pipe(replicationStream).pipe(socket)
replicationStream.on('error', (err) => {
console.error('[chronicle] replication error:', err.message)
})
})
core.on('peer-add', () => console.(, core..))
Causal ordering (multi-writer with Autobase)
import Autobase from 'autobase'
const base = new Autobase({
inputs: [localCore, ...remoteCores],
output: outputCore,
apply: async (nodes, view, base) => {
for (const node of nodes) {
await view.append(node.value)
}
},
})
await base.ready()
await base.append({ agentId: 'agent-1', action: 'task.start', ts: Date.now() })
Verify entry integrity (Merkle proof)
const proof = await core.proof(i, { block: { index: i, nodes: 0 }, upgrade: false })
const valid = await core.verify(proof)
console.log('[chronicle] entry integrity:', valid ? 'OK' : 'TAMPERED')
Anti-Fake-Pass Checklist
❌ Multiple processes opening same Hypercore path → lock conflict, data corruption
❌ No error handler on replication stream → network errors crash the process
❌ Reading core.length before core.ready() → always 0; await ready() first
❌ Appending objects without valueEncoding: 'json' → stored as raw Buffer, not parseable
❌ Autobase without deterministic apply function → non-idempotent merges cause divergence
❌ discoveryKey shared publicly → any peer can replicate the log; use authentication layer