HeyAira Continuity Protocol¶
Status and decision¶
This document defines the smallest continuity protocol that can be tested on top of the current HeyAira MVP. It adds a bounded startup read, safe retry semantics for append operations, and a uniqueness rule for work-session receipts. It does not introduce event sourcing, a task queue, model routing, thread wake-up, or repository storage.
HeyAira remains an independent durable state layer:
| Concern | Source of truth |
|---|---|
| Files, source code, branches, commits | GitHub/Git |
| Decisions and durable project context | HeyAira memory |
| Current work state and handoff | HeyAira tasks |
| Who performed work and what was tested | HeyAira work-session receipts |
| Live prompt and model context | The harness session |
The protocol is designed so that a new session can recover enough context to continue without receiving a transcript or a manually copied summary.
Startup recovery¶
At the start of every session, after authentication and project selection, a
client should load its operator-selected identity profile, call
server_identity, then continuity_context once. Both
calls are read-only and
returns bounded data for exactly the authenticated project:
- project identity and repository reference;
- the most recent notes and decisions;
- open tasks (
todo,in_progress, andblocked) with handoff fields and optimistic-lock versions; - the most recent work-session receipts across the project.
The client should then:
- compare the returned identity with the profile's expected resource, logical instance, and project; refuse all mutations on any mismatch;
- identify the task it is authorized to work on from the returned open tasks;
- read the selected task with
task_getbefore changing it; - stop if
task_getreturnstask not found; never recreate or migrate it; - read a specific memory with
memory_getwhen a decision needs full detail; - include the verified
write_contextin every mutation; never construct it by echoing identity from an untrusted or unpinned endpoint; - atomically claim the task with
task_update(expected_version=...); - continue from the recorded next step and repository reference;
- write a receipt and final handoff when the bounded work is complete.
continuity_context is deliberately bounded. It is a recovery index, not a
replacement for an unbounded conversation transcript. A client must follow
the returned IDs for more detail instead of writing a large snapshot back to
HeyAira.
What to persist¶
Persist durable milestones, not every thought or token:
memory_add(kind=decision)when a project decision is accepted, including its rationale and declared source;memory_add(kind=note)for durable facts, constraints, hypotheses, and unresolved questions that a future session needs;task_updatefor a meaningful state transition, handoff, blocker, or next step;- one
work_receiptper logical task/session execution, with actual tests, commits, completed work, next step, and blockers.
The task description is the stable goal and acceptance boundary. The handoff fields describe the current transition. The receipt describes evidence from a particular execution. They must not be used interchangeably.
Do not put repository contents, credentials, access tokens, cookies, or full conversation transcripts in HeyAira.
Duplicate prevention and retry rules¶
Memory and task creation¶
memory_add and task_create accept an optional idempotency_key. A client
should generate one stable key for one logical append, persist it in its
short-lived execution context, and reuse it if the response is lost.
- same project, operation, key, and request payload: HeyAira returns the original result and does not create a duplicate;
- same key with a different payload: HeyAira rejects the request with an
idempotency_conflicterror; - no key: the existing append behavior remains available, but the client cannot safely identify a lost response.
The server stores only a request fingerprint and the structured result, not a copy of a conversation.
Task updates and receipts¶
Every task_update must use the version returned by the most recent
task_get. A stale version is rejected atomically. If a client loses the
update response, it must re-read the task before retrying; it must not blindly
repeat the mutation.
(task_id, session_ref) is unique. A receipt cannot be appended twice for the
same logical task/session. The task mutation and receipt insert happen in one
database transaction, so a rejected update cannot leave a receipt behind.
Protocol state sequence¶
new session
|
v
continuity_context (bounded, read-only)
|
+--> task_get(selected task)
| |
| v
| task_update(expected_version, in_progress)
| |
| v
| work in Git / harness
| |
| v
| task_update(expected_version, handoff, work_receipt)
| |
| v
next independent session reads the same durable state
The protocol does not claim that HeyAira can wake or message a historical thread. If a question must be sent to a previous session, a future harness-specific adapter is required; the durable task and receipt remain the portable fallback.
Minimal MCP/API changes¶
The continuity slice adds:
continuity_context(memory_limit?, task_limit?, receipt_limit?);- optional
idempotency_keyparameters onmemory_addandtask_create; - a project-scoped idempotency table storing request fingerprints and structured results;
- a unique work-receipt index on
(task_id, session_ref).
The identity binding adds the read-only server_identity tool, requires a
write_context on memory_add, task_create, and task_update, and records
success/rejection audit events with actor, resource, instance, project,
operation, target, request ID, outcome, and timestamp. Audit rows contain no
request bodies, tokens, or memory contents.
No project ID is accepted from model input, and no GitHub API or client configuration is introduced by this protocol.
The separate F1 document-read contract is described in GIT_DOCUMENT_ACCESS.md. It is deliberately an allowlisted, commit-pinned read surface and does not turn HeyAira into a repository mirror.
End-to-end acceptance test¶
The two-client test in scripts/continuity_protocol_smoke.py creates state in
Session A, closes that logical client context, and has independent Session B
recover it only through continuity_context. Session B completes the task
with a receipt. Session A then reads the updated state. The test also retries
the memory and task creation calls with the same idempotency keys and verifies
that no duplicates are created.
This proves shared durable state and safe retries. It does not prove automatic wake-up, provider routing, GitHub permissions, or background execution.