Skip to content

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, and blocked) with handoff fields and optimistic-lock versions;
  • the most recent work-session receipts across the project.

The client should then:

  1. compare the returned identity with the profile's expected resource, logical instance, and project; refuse all mutations on any mismatch;
  2. identify the task it is authorized to work on from the returned open tasks;
  3. read the selected task with task_get before changing it;
  4. stop if task_get returns task not found; never recreate or migrate it;
  5. read a specific memory with memory_get when a decision needs full detail;
  6. include the verified write_context in every mutation; never construct it by echoing identity from an untrusted or unpinned endpoint;
  7. atomically claim the task with task_update(expected_version=...);
  8. continue from the recorded next step and repository reference;
  9. 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_update for a meaningful state transition, handoff, blocker, or next step;
  • one work_receipt per 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_conflict error;
  • 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:

  1. continuity_context(memory_limit?, task_limit?, receipt_limit?);
  2. optional idempotency_key parameters on memory_add and task_create;
  3. a project-scoped idempotency table storing request fingerprints and structured results;
  4. 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.