The Helix spec
The vault format and protocol surface, published so that Helix-the-host is an implementation rather than a definition. Anyone may build a compatible vault server or a tool that reads a Helix export. Spec text is licensed CC BY 4.0; the reference vault server is AGPL-3.0.
Version helix-export/v1 · protocol v0.7 · August 2026. Breaking changes bump the version, and exports stay importable across versions.
1. Vault schema
A vault holds facts in six fixed categories, plus two media collections: subjects (people and pets) and a single owner voice profile.
categories: identity | work | projects | preferences |
relationships | communication-style
category = {
base: [ { id, text } ], // written by the owner
learned: [ { id, fact, source, date } ] // proposed by an app, approved by the owner
}Entry ids are content-addressed — a short FNV-1a hash of category, list and text. They require no storage, and they change when an entry changes, which is the mechanism behind supersession: a stale id simply stops resolving rather than silently pointing at different content.
subject = {
id, name, species,
thumb, // small data URI, app-visible
photos: [ { id, mime, b64, thumb } ] // never leaves the vault
}
voice = {
takes: [ { id, style, isPhrase, mime, b64, recordedAt } ],
phrase: { text, issuedAt }, // live verification script
verifiedAt, // set when a phrase take exists
providerVoiceId // cached compilation, rebuilt on change
}2. Labels and the private flag
Categories are a coarse grant — “work” hands over everything about work at once. Labels let an owner give an app one slice of a category and nothing else; private marks entries that leave through no app door at all.
marks = {
labels: { <entryId>: ["helix", "v0-7"] }, // lowercase, dashed, ≤32 chars, ≤6 per entry
private: [ <entryId> ]
}Stored against the same content-hash ids as the entries themselves, which is what lets marks survive an export/import: the same text in the same category yields the same id in any vault.
Two rules govern them, and both are normative:
- Labels only narrow. A label-restricted grant sees the intersection of its categories and its labels. A
helix-tagged entry sitting in a category the app wasn't granted stays invisible — otherwise a label becomes a privilege-escalation path through the consent screen. Entries with no labels are invisible to a restricted grant. - Private beats everything. No scope, label or grant reveals a private entry through an app door, and an import can only ever add private flags, never clear them.
Apps cannot apply labels — only propose them, through the same review queue as facts. Labels decide what otherapps can see, so that decision stays with the owner. The restriction itself rides in the grant, not in the scope strings, and is shown on the owner's connections page.
3. Export format
GET /account/export (session) or GET /owner/export (device token) returns the entire vault as one document. This is the interchange format — any tool can consume it.
{
"format": "helix-export/v1",
"exported_at": "2026-08-04T12:00:00Z",
"user": { "id", "name", "email", "created_at" },
"vault": { <category>: { base, learned } },
"subjects": [ subject ],
"voice": { "verified_at", "takes" },
"marks": { "labels": { <entryId>: [label] }, "private": [ <entryId> ] },
"pending": [ proposal ],
"audit": [ { "at", "client", "action", "detail", "seq", "hash", "prev" } ],
"connected_apps": [ { "app", "scopes" } ]
}Secrets are deliberately excluded: no passphrase hash, no OAuth tokens, no device-token hashes. An export is your data, not your credentials.
Import
POST /account/import (session, file upload) or POST /owner/import (device token, JSON body) loads the same document back. Owner-authenticated only — apps propose, owners load documents.
- Merge, never replace.Importing into an empty vault reproduces the original; importing into a populated one adds only what's missing. A file the owner picked never destroys what they already have.
- Idempotent. Facts dedupe on text, photos on bytes, subjects on name + species. Importing the same file twice changes nothing, so recovery never depends on remembering whether you already tried.
- Three things don't travel, and each refusal is reported rather than silently dropped: the audit log (it records what this server did — adopting a foreign one would let a document dictate history), voice verification (a live reading of a server-minted phrase, so it is re-earned rather than copied; the takes themselves import fine), and app grants (issued per vault).
The response reports counts per section plus any notes: { facts, subjects, photos, takes, marks, notes[] }. The import itself is written to the audit log.
4. Protocol surfaces
Three doors, one consent model, one audit log.
MCP — assistants and agents
Streamable HTTP at https://vault.helix.ai/mcp, OAuth 2.1 with dynamic client registration and PKCE. Tools are registered per session from the granted scopes, so the tool list is itself scope-shaped.
| Tool | Scope | Contract |
|---|---|---|
get_context | any category | Markdown of granted categories, each entry tagged [#id], plus section freshness, the labels in use, and pending count. Optional label narrows further. |
propose_learning | propose | Queues a fact for owner review. Optional replaces supersedes an entry on approval; optional labels tag it. |
propose_labels | propose | Queues labels for an entry that already exists. Same queue, same approval — apps never tag directly. |
list_subjects | likeness | Names and species only. |
generate_image | likeness | Subjects by name → expiring link. refine_image_id edits a previous result. |
generate_speech | likeness:voice | Text → expiring audio link, in the owner's verified voice. |
REST — apps
Same tokens and scopes. GET /api/subjects, GET /api/subjects/:id, POST /api/subjects and photo sub-routes, POST /api/generate. Detailed in REST — apps.
Owner door — the vault's own clients
Authenticated with the vault passphrase rather than an app scope, so approval powers can never be obtained through a consent screen. Covers facts, subjects, voice, review, audit, connections and export. Device tokens are stored hashed and are revocable like any app.
5. Scopes
Per-category grants (identity, work, projects, preferences, relationships, communication-style) plus propose, likeness, likeness:write and likeness:voice. Clients SHOULD send the scope parameter on /authorize: the consent screen pre-selects exactly what was requested and tucks the rest away. See Scopes & consent.
6. Governance invariants
These are normative — an implementation that breaks one isn't Helix.
- Apps MUST NOT write facts directly. Proposals enter a queue the owner approves or rejects. The same applies to labels, which decide what other apps can see.
- Labels MUST only narrow. No label may reveal a category the grant does not carry, and private entries MUST NOT cross any app door.
- Source media MUST NOT cross the app door. Apps receive names, thumbnails and finished generations only.
- Every read, proposal, write and generation MUST be recorded in an audit log visible to the owner.
- Audit entries MUST be hash-chained.
hash = SHA-256(seq + at + client + action + detail + prev), concatenated as strings in that order, hex-encoded;previs the previous entry's hash, empty for the first. A verifier MUST report an unverifiable entry as broken, and an entry written before the chain existed as unchecked — those are different claims. - Revocation MUST take effect immediately, including mid-session.
- Generation MUST name its downstream provider on the consent screen and in the audit entry.
- The owner MUST be able to export everything and delete everything without assistance.
7. Not yet specified
Stated plainly rather than left ambiguous: server-to-server federation, and end-to-end encryption (today: encrypted at rest, operator-readable — see the security note).