Context Vault
HPKE-encrypted shared memory for your team's agents. The platform stores only ciphertext.
A context vault is a versioned, encrypted bundle of text (runbooks, design docs, patterns, escalations) that agents can read at session start. Vaults are first-class resources: shared with teams, attached by workflows, and proposed back to by agents.
The crypto is real, not a slogan. Server staff cannot read context. A compromised platform server cannot read context. Decryption happens only on devices that have been granted a key share.
The crypto, concretely
Library: @hpke/core plus @hpke/dhkem-x25519.
Suite (frozen in packages/context-engine/src/crypto/hpke-grants.js):
{
kem: 'DHKEM_X25519_HKDF_SHA256',
kdf: 'HKDF_SHA256',
aead: 'AES_256_GCM',
}Grant version constant: viewport.context_key_grant/hpke-draft-01.
The vault is a signed event log. Each event is JSON-canonicalized and Ed25519-signed by an actor identity. Schemas live in packages/context-engine/schemas/:
context_event_v1(one event in the log)context_profile_v1(vault profile and settings)context_bundle_manifest_v1(manifest of bundled entries)context_erase_receipt_v1(proof of erasure)context_key_grant_v1(recipient grants)context_key_grant_hpke_draft_01(HPKE-wrapped grants)
What the platform sees
The platform stores signed encrypted events as opaque blobs and a small set of indexing metadata: event id, repo id, schema version, event type, actor name, key epoch, visibility, payload digest. None of those bytes are the body. The runtime endpoints that accept and return these blobs do not decrypt anything.
Control-plane-blind, by code
The runtime endpoints that ingest vault events read only the indexing columns. The body column is opaque ciphertext. There is no code path on the server that decrypts it.
Key grants
Each vault has a per-recipient symmetric key wrapped to the recipient's HPKE public key. Recipients are devices, not just users; adding a device requires an existing grantee to approve the new device, which appends a new grant event to the log.
Grants are events inside the log, not a separate table. The current authoritative set is computed by replaying the log on the trusted edge.
How an agent uses a vault
- Your repo's
.viewport/config.yamlreferences vaults undercontext.providers[]with provider typeviewport-vault. - At session start, the daemon checks via the context engine whether this device has a key share for the vault.
- If yes: it decrypts the relevant entries and offers them to the agent through a tool surface.
- If no: the session sees only public metadata. The agent may emit a context candidate asking a grantee to approve.
Candidate review: the trust gate
Agents can propose new entries based on what they observed during a session. Proposals are untrusted until a human reviewer approves them through the inbox. On approve:
- The platform records the decision with an HMAC signature so the trusted edge can verify the decision came from the control plane.
- The decision does not carry the body. Only a digest and routing metadata.
- The daemon receives the decision, re-decrypts the candidate it cached locally, signs a real encrypted event, and pushes it to the platform.
The body bytes never visit the platform in plaintext form, even during candidate approval.
CLI surface
The vpd context family manages identities and vaults:
vpd context init # initialize a per-repo context store
vpd context user-init # create a user identity (passphrase or macOS keychain)
vpd context join # join an existing vault on this device
vpd context status # show grants, devices, latest epoch
vpd context add # add an entry locally
vpd context propose # submit a candidate
vpd context resolve # approve / reject a candidate locally (for owner-auto-approve workflows)
vpd context sync-push # push signed encrypted events to the platform
vpd context sync-pull # pull signed encrypted events from the platform
vpd context identity-export
vpd context identity-import
vpd context device-request
vpd context device-approve
vpd context device-accept
vpd context grantSee CLI reference for the full flag set.
Local-edge storage
The daemon's local-edge store is SQLite via better-sqlite3. At-rest encryption uses either the OS key store (macOS Keychain on Darwin) or a passphrase-derived key. Default is --key-store file; pass --key-store macos-keychain for OS-backed.
What the docs do not promise
- Field-level encryption inside a vault entry. Entries are encrypted as wholes.
- Forward secrecy across grant revocations beyond key-epoch rotation. Revocation stops new grants; previously sealed material remains decryptable by past recipients.
Related
- Quickstart for how to attach a vault from a repo config
- Inbox for where context candidates surface
- Spec for the
viewport-config-v1field that attaches a vault - Self-host for running the relay on your own infra