Agent reporting protocol
Agent Reporting Protocol¶
Mobius Civic AI — Heartbeat, Journal, and Attestation Contract¶
Cycle draft: C-284 Status: Protocol Spec v1 Author: kaizencycle CC0 Public Domain
0. Purpose¶
Mobius agents run in many places — Cursor Background Agents, Render workers, Vercel crons, local laptops, the ATLAS-PAW dashboard cron. They all need to report into the Substrate using the same protocol so that where an agent runs doesn't matter — how it reports does.
The Agent Reporting Protocol defines the three write paths every agent uses:
- Heartbeat — "I am present"
- Journal commit — "I observed, inferred, recommended"
- Attestation — "I witnessed this Seal / EPICON / claim"
All three go through the Terminal. The Terminal is the agent gateway. The Substrate receives its agents' work as an archive, not as a live write target.
1. Source of truth hierarchy¶
Before defining the endpoints, the protocol specifies which store holds which kind of truth:
| Store | Holds | TTL |
|---|---|---|
| Upstash KV (via Terminal) | live heartbeats, current GI, active tripwires, recent journal entries | 5 min – 2 h |
| Mobius-Substrate (git archive) | committed journals, constitutional docs, protocol specs, Seal records | forever |
| GitHub commit history | ZEUS verification commits, PR merges, agent identity proofs | forever, immutable |
Reads flow through the Terminal's /api/terminal/snapshot, which merges hot KV state with the cold Substrate archive. Writes go to the Terminal first; the Substrate receives copies via archive crons.
Doctrine: KV is authoritative for now. Substrate is authoritative for history. Terminal is authoritative for the composition of both.
2. Agent identity¶
Every agent authenticates with AGENT_SERVICE_TOKEN, a shared bearer token held by:
- The Terminal (validator)
- Each agent runtime (client)
Token rotation is a constitutional event (not yet specced). Until rotation is defined, the token is long-lived. This is an accepted risk for the early substrate; tightening is planned.
Every write carries an agent_id field identifying which of the eight named agents is reporting: ATLAS, ZEUS, EVE, JADE, AUREA, HERMES, ECHO, DAEDALUS. Unknown agent names are rejected.
3. Heartbeat¶
Endpoint¶
POST /api/agents/heartbeat
Authorization: Bearer {AGENT_SERVICE_TOKEN}
Content-Type: application/json
{
"agent": "ATLAS",
"source": "cursor-agent" | "paw-cron" | "render-worker" | "vercel-cron" | "local",
"timestamp": "2026-04-17T09:40:00Z",
"observed": {
"cycle": "C-284",
"gi": 0.74,
"mode": "yellow"
},
"note": "string (optional, <= 280 chars)"
}
Effect¶
- Writes
HEARTBEAT:{agent}to KV with 5-minute TTL - Records
last_heartbeattimestamp in the agent's KV record - Appears in
/api/terminal/snapshotagents lane within 12s
Semantics¶
A heartbeat is a claim of presence. It means the agent is running and able to observe something. It does not imply the agent produced reasoning this cycle — that's what journal commits are for.
A heartbeat that carries no observed state is acceptable (the agent is present but has nothing specific to report). A heartbeat that claims observed state the agent couldn't possibly know is a protocol violation.
Idempotency¶
Multiple heartbeats from the same agent within the TTL window simply reset the TTL. No duplicate tracking. An agent that heartbeats every 60 seconds is not penalized; an agent that heartbeats once every 10 minutes is.
NEVER¶
- Never have the Terminal fabricate a heartbeat on an agent's behalf. A heartbeat must come from the agent's own runtime. The Terminal may surface "no recent heartbeat" — that's a legitimate state — but must not write
HEARTBEAT:atlason ATLAS's behalf. Fabricated heartbeats corrupt MII calculations, hide outages, and break the sentinel architecture. This is a load-bearing rule.
4. Journal commit¶
Endpoint¶
POST /api/agents/journal/commit
Authorization: Bearer {AGENT_SERVICE_TOKEN}
Content-Type: application/json
{
"agent": "ATLAS",
"cycle": "C-284",
"scope": "observation" | "inference" | "recommendation",
"observation": "string",
"inference": "string",
"recommendation": "string",
"confidence": 0.87,
"derived_from": ["signal-snapshot:kv", "source:cron"],
"category": "observation" | "inference" | "civic-risk" | "market" | "infrastructure",
"severity": "nominal" | "elevated" | "critical",
"tags": ["ATLAS", "observation", "C-284"],
"content_signature": "sha256-hash-of-canonical-content (optional, server fills if absent)"
}
Effect¶
- Writes to KV hot lane:
LPUSH journal:{AGENT}:{CYCLE}(cap 200 per agent per cycle) - Fires
scheduleVaultDepositForJournalfor Vault v1/v2 accrual - Appears in
/api/agents/journalread endpoint immediately - Mirrors to
Mobius-Substrate/journals/{agent}/{ISO-timestamp}-journal.jsonvia nightly archive cron - If within a Seal's deposit window,
content_signatureis tracked for later inclusion indeposit_hashes
Idempotency¶
content_signature dedup. Two commits with identical signatures within a cycle are treated as one. This is how the Substrate prevents agents from padding reserve via repeated identical entries.
Agents MAY pre-compute the signature client-side; the server recomputes and validates. Mismatches are a protocol violation (client either lied about content or computed the hash wrong).
Required fields¶
agent— must be a known agentcycle— must match current cycle percycle.jsonor the prior cycle (for late commits within 60s of rollover)- At least one of
observation,inference,recommendationmust be non-empty confidencemust be in[0, 1]
Validated on write¶
- Agent exists and matches the bearer token holder (no impersonation)
- Cycle is current or previous
- Total content size under 4KB
- No HTML/script content in text fields
5. Attestation (Seal)¶
Endpoint¶
POST /api/vault/seal/attest
Authorization: Bearer {AGENT_SERVICE_TOKEN}
Content-Type: application/json
{
"seal_id": "seal-C-284-001",
"agent": "ATLAS" | "ZEUS" | "EVE" | "JADE" | "AUREA",
"verdict": "pass" | "flag" | "reject",
"rationale": "string (<= 2000 chars)",
"signature": "HMAC-SHA256(AGENT_SERVICE_TOKEN, seal_hash || verdict || rationale)",
"posture": "confident" | "cautionary" | "stressed" | "degraded"
}
(posture is AUREA only.)
Effect¶
- Server verifies HMAC signature against the current candidate's
seal_hash - Records attestation on
vault:seal:candidateKV record - If submission makes the candidate complete, the
/api/cron/vault-attestationcron will finalize on its next tick (no immediate effect on this request)
Who attests¶
Only the five voting Sentinels — ATLAS, ZEUS, EVE, JADE, AUREA — may attest Seals. HERMES, ECHO, and DAEDALUS cannot. This is enforced server-side.
Verdict semantics¶
pass— agent's tier-specific criteria metflag— criteria met with concerns; Seal may still mint but concerns are recordedreject— criteria not met; Seal cannot mint in attested state- Only ZEUS's
rejectholds absolute veto. Other agents' rejects move the Seal toquarantined, awaiting operator review.
See vault-v2-sealed-reserve.md §5 for per-Sentinel scope and §6 for quorum rules.
Idempotency¶
An agent posting the same attestation twice replaces the prior one. An agent posting a different attestation replaces the prior one but with a revised_from field recorded. Revisions within the 5-minute attestation window are permitted (useful for corrections); after window close, no changes.
6. Archive mirroring (Substrate write path)¶
KV holds hot state with 5-minute to 2-hour TTLs. To preserve long-term memory, the Terminal runs a nightly archive cron that writes:
- Journal commits from the last 24h →
Mobius-Substrate/journals/{agent}/YYYY-MM-DD.json(append) - Attested Seals →
Mobius-Substrate/ledger/seals/{seal_id}.json - Quarantined/rejected Seals →
Mobius-Substrate/ledger/seals/quarantined/{seal_id}.json - Cycle summary →
Mobius-Substrate/journals/cycles/{cycle}.json
The archive cron opens a PR against main in Mobius-Substrate rather than direct-committing. ZEUS verifies the PR diff matches the KV source before approving. Every archive write is a commit that carries a ZEUS verification footer.
This is the pattern that makes the cathedral remember. Each day, the substrate transcribes itself from hot KV into cold git. The agents don't write to Mobius-Substrate directly — they write to Terminal, and the archive transcribes. This is why "Substrate is the memory" works.
7. Read paths (for completeness)¶
All reads go through Terminal. Substrate is never a hot read target.
GET /api/terminal/snapshot— full 13-lane stateGET /api/terminal/snapshot-lite— minimal surface for clients with tight budgetsGET /api/agents/status— agent roster with heartbeat statusGET /api/agents/journal?cycle=C-284&agent=atlas— journal entriesGET /api/vault/status— Vault reserve + seals countGET /api/vault/seal— list attested SealsGET /api/vault/seal/{id}— single Seal with attestations
If an agent needs to know its own state (last heartbeat, last journal), it reads from /api/agents/status?agent={self}. It does NOT read Mobius-Substrate directly for hot state — it would be stale by up to 24h.
8. Stop conditions¶
An agent runtime must refuse to POST and log loudly if:
AGENT_SERVICE_TOKENis unset (no authentication possible)- The agent's own identity doesn't match the expected token holder
- A response returns 401 three times in a row (potential token revocation — escalate to operator)
- The
cyclefield would be older than previous cycle (clock drift) - The agent is about to commit a journal entry whose
content_signatureduplicates one it committed within the last 60 minutes (likely loop bug)
Stop conditions are meant to catch agents-gone-wrong. A stopped agent is better than a corrupting agent. DAEDALUS-µ watches for stopped agents and raises the agent-quiet tripwire when a Sentinel goes silent for more than 30 minutes.
9. Non-goals (explicitly)¶
- The protocol does not define agent reasoning. How ATLAS forms an observation, how ZEUS decides what to verify, how JADE recognizes precedent drift — those are each agent's internal logic, not this protocol's concern.
- The protocol does not define inter-agent communication. Agents do not talk to each other. They talk to the Terminal. The Terminal's state is their shared substrate, and that's how they coordinate.
- The protocol does not define MIC emission. MIC minting follows from Vault v2 Seal attestation + Fountain activation per the Vault v2 spec. Journal commits may trigger accrual, but they never mint MIC directly.
10. Summary (short)¶
- One token:
AGENT_SERVICE_TOKEN - Three write endpoints: heartbeat, journal/commit, seal/attest
- One gateway: the Terminal
- Two stores: KV (hot, Terminal-owned) and Substrate (cold, archive cron)
- One rule that cannot be broken: no fabricated heartbeats
The agents report. The gateway witnesses. The Substrate remembers.