Skip to content

Architecture

Design rule

HeyAira coordinates work but does not own every artifact involved in it. Each part has one source of truth.

GitHub / Git
code, branches, commits, pull requests, CI
        ^                         ^
        | push, open PR           | GitHub App: check PR head, CI results
        |                         |
HeyAira Bridge (Mac)  <------>  HeyAira server  <------>  MCP clients
worktrees, sandboxed   offers,   memory, tasks,   MCP     ChatGPT, Claude,
Codex / Claude Code    leases,   task versions,           Codex, Claude Code
agent sessions         events    workflows, receipts
                                         |
                                         v
                                 iOS app (push notifications)

Git and GitHub

Git owns source files, documentation, history, branches, tags and pull requests. HeyAira stores references to them (repository URL, branch, commit SHA, pull request number). It does not copy source code into PostgreSQL. The one exception is agent instructions: sending a task reads the role, skill and soul files its catalog agents name from a pinned commit (each file at most 60,000 bytes, at most 60 KiB per agent) and stores their text in the task's workflow contract (task_workflows.contract) and in each execution plan (bridge_executions.plan). Uncommitted local changes are not a handoff.

The server reads GitHub through the HeyAira GitHub App on a bound repository: allowlisted documents pinned to a commit (Git document access), the pull request an agent's work was published to, and GitHub Actions results (github_ci_status, and the CI webhook that records results in a task's history). GitHub credentials are never accepted as, or passed through as, a HeyAira token.

Durable state (server and PostgreSQL)

PostgreSQL owns:

  • accounts, projects, memberships and roles;
  • project-to-repository bindings and allowlisted document sources;
  • OAuth clients, grants and project tokens (secrets stored only as hashes);
  • memory entries with explicit same-project supersession links and preserved originals, and separately versioned formal decisions;
  • tasks with optimistic versions, and immutable task-version snapshots;
  • the account catalog: versioned agents, roles and skills;
  • task workflows, executions, leases and their ordered event history;
  • work-session receipts and idempotency records;
  • Bridge identities, node-project bindings and phone registrations.

It holds no conversation transcripts, source code or provider credentials. The only repository text it keeps is the copied agent instruction files described above.

Projects

Project is the tenant and security boundary. Every memory entry, task, receipt, workflow and repository binding belongs to one project. A subject belongs to projects through explicit memberships (owner, admin, contributor, viewer). Repository bindings are many-to-many.

The account owns reusable agent definitions: agents, roles and skills (catalog provisioning). An agent names a provider, a model, a reasoning level, a role and skills; its instructions are references to pinned Git documents, resolved and frozen when a task is sent.

MCP interface

The server exposes its tools over MCP Streamable HTTP (tool catalogue). It:

  • authenticates every request and derives the project from the credential, never from model input;
  • enforces project boundaries on every lookup and relation;
  • requires write_context (resource, instance, project) on every write, so a client writes only to the project it verified with server_identity;
  • updates tasks atomically against an expected version;
  • does not log secrets or memory bodies.

Each project has its own address, https://mcp.heyaira.eu/p/<project-slug>/mcp, and a grant is bound to the address it was issued for (ADR-0003). The shared https://mcp.heyaira.eu/mcp is deprecated but still issues new grants, bound to /mcp; the Bridge and the iOS app use it. New clients use /p/<slug>/mcp.

Public clients authorize with OAuth 2.1 Authorization Code and PKCE, protected-resource metadata, resource indicators and project scopes (endpoint reference). A project-scoped Bearer token remains for internal and CLI compatibility.

The startup contract is server_identity followed by continuity_context: one bounded, read-only projection of recent memory, open tasks and recent receipts (continuity protocol, ADR-0002).

Agent execution

Bridge workflow dispatch and execution callbacks were removed in S5 (owner decisions a9f0e60e and 6cab5c63). Coordinators run tasks with scripts/heyaira-run.sh and record results with task_update. Historical workflow data remains readable; no migration or data deletion is part of this change.

The 15-second recovery supervisor runs only unattended-move alerts, interactive task CI follow-up, and expired-execution settlement (the latter for one more release). Bridge workflow alerts, queued corrections/retries, publication rechecks and workflow CI polling have been retired (decisions a9f0e60e, 6cab5c63; S4). GitHub webhooks still store repository runs and wake interactive task CI watches; they no longer route runs or closed pull requests into workflows. Existing data and schema are preserved.

Agent work now runs outside the server: the coordinator session starts one Codex worker with scripts/heyaira-run.sh (isolated worktree, repository check, pull request, one Astra review) and records the outcome with task_update. A coordinator who sets a task's status takes it over from any historical workflow, which is retired with its history kept. task_ci_follow watches the pull request's CI for interactive tasks.

Historical: until S5, a project owner or admin configured a task with task_execution_configure and sent one task version to one Mac with workflow_send; the Bridge ran a worker and an independent verifier under a lease, reported through task_result, published the pull request, and the server checked it on GitHub. Those tools and routes are gone; the stored rows stay readable through workflow_get.

The historical contract (events, verification states, leases, capacity per Mac, session resume, server checks on GitHub) is in task-version execution. Workflow states and attribution maps each phase to its responsible actor.

Standalone executions and the inline-profile workflow_dispatch tool were removed in stage 6; records they created stay readable (task workflow).

HeyAira Bridge (Mac)

The Bridge is a Rust CLI with a native macOS status-bar app, in its own repository (h8v6/heyaira-bridge). It keeps the Mac's identity and HeyAira credentials in the Keychain, sends heartbeats (presence, provider account slots, parallel-task capacity), and never opens an inbound listener.

When the owner enables background work, it claims offers for the repositories its local policy maps, runs Codex CLI or Claude Code with the Mac's own provider accounts (credentials never leave the Mac), publishes accepted work to GitHub, and streams agent sessions to its Work Center window, where they can be watched live. Agent shells cannot reach loopback TCP; an optional per-repository test PostgreSQL is reached over a Unix socket.

A Bridge identity serves a project only through an explicit node-project binding, and every feed and lookup enforces that binding (Bridge project scope, identity, enrollment, transport protocol).

Notifications

Task events (such as blocked, checks failed, accepted but not published, or not picked up) and Server Beat incidents are delivered to the owner's inbox and, through APNs, to the HeyAira iOS app (notification reference).

Operations

  • Server Beat observes the services and opens, escalates and recovers incidents; an external watchdog checks that the beat itself is alive, and an SES e-mail fallback reaches the owner when a push is not confirmed (Server Beat and watchdog, runbook).
  • Backups are encrypted PostgreSQL dumps in Cloudflare R2 with freshness checks. Retention produces a plan for review and deletes nothing on its own (backup runbook).
  • Deployment is a rootless container service behind the public edge for mcp.heyaira.eu; PostgreSQL is never mapped to a public port (deployment).

Ownership matrix

Information Source of truth
Source code, files, branches, history Git repository
Pull requests and CI runs GitHub (HeyAira records references and results)
Decisions and rationale HeyAira memory
Task definition, status and handoff HeyAira tasks and task versions
What an agent did, and how it was verified HeyAira workflow history and receipts
Agent, role and skill definitions HeyAira account catalog, instructions pinned in Git
Provider accounts and credentials The owner's Mac
GitHub publishing credentials The owner's Mac (Bridge)
Live conversation context The client or agent session
Project membership and roles HeyAira PostgreSQL

Continuing work in a new session

  1. Authenticate to the project and call server_identity.
  2. Call continuity_context for recent decisions, open tasks and receipts.
  3. Read the task with task_get: repository, branch, commits, handoff.
  4. Check out that state with Git and do a bounded change.
  5. Commit, then update the task with its expected version and a work receipt naming the commit and the tests that ran.