Viewport daemon, relay, and hosted runtime are available in alpha. Surfaces may change.
VIEWPORT
Security explained

Team Context encryption

How repo-attached context is encrypted, synced, selected, and delivered to an agent session.

A Viewport-hosted context vault is an encrypted event log. Entries, grants, candidates, and profile changes are written as signed events. The platform stores those events, indexes safe metadata, and returns them to authorized clients. The platform does not decrypt context entry bodies.

GitHub-backed context providers are different. They use GitHub as the plaintext system of record and Viewport as the provider registry, local retrieval protocol, and update proposal path. GitHub repo permissions govern who can read the markdown. Viewport stores repo metadata and does not copy markdown bodies into the platform database.

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.

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)

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 a repo uses a vault

The repo config points at a context provider. When an agent session starts in that repo, the daemon refreshes that provider through the trusted edge before resolving a bundle: pull encrypted events, materialize pending grants, process revokes, then select the bounded local result set.

Rendering diagram...

The important part is the shape of the request: repo, profile, query, and maxItems. A large vault is not pasted into every run. The daemon asks the engine for a bundle that is relevant to this repo and this invocation.

Automatic refresh is attached to the trusted-edge paths that actually use a repo provider: session start, user prompt submission, vpd context search, vpd context get, context candidate preview, and relay context resolve. If refresh fails, the edge falls back to its local cache. A local-only debug resolve of a specific vault does not pull first.

What the platform stores

The platform stores signed encrypted events plus metadata needed to route and audit them:

Field typeExample
Routing metadataworkspace id, context resource id, repo id
Event metadataevent id, event type, actor, key epoch, visibility, created time
Integrity metadatapayload digest, signature
Encrypted bodyciphertext, IV, authentication tag

The vault descriptor is also server-visible metadata: name, description, stable id, "use this when" guidance, and "propose an update when" guidance. Those fields exist so agents and humans can route context before decrypting it. Treat them like titles and labels, not like encrypted memory bodies.

The API rejects context events that contain plaintext-looking fields such as body, content, markdown, message, prompt, summary, text, or title outside the encrypted envelope.

Server-safe events

The platform is allowed to store routing metadata and ciphertext. It is not allowed to store context plaintext. That is enforced at ingestion, not left as a UI convention.

Keys and grants

Each vault has content keys for encrypted entries. Access is granted by wrapping the relevant key material to a user epoch or team epoch. A device becomes decrypt-ready only after it has enrolled into the user's epoch locally. An org admin role alone is not a decryption grant.

Rendering diagram...

This is why there are two checks:

  • The platform checks membership and ACLs before allowing sync, review, or metadata access.
  • The trusted edge checks key grants before decrypting content.

When a team epoch is published, the publishing trusted edge also wraps that team epoch to the active user epochs of current team members. Existing members can then materialize the team epoch on their own trusted edges during the next sync. Members removed later do not receive future team epoch grants.

Hosted web and remote daemons

The hosted web app does not decrypt a context vault by itself. When it needs plaintext for a candidate review or a context lookup, it asks a trusted edge to do that work at runtime.

For a local laptop daemon, that trusted edge can be the local daemon. For a VPS daemon, the browser cannot use 127.0.0.1 because that points at the browser's own machine, not the VPS. In relay mode, the browser sends a scoped command over the encrypted runtime command channel instead:

Rendering diagram...

The relay routes encrypted frames. It should not see the context body. The browser can render plaintext, so the JavaScript delivered to the browser is part of the trusted viewing path while the page is open.

The hosted web app no longer talks directly to 127.0.0.1 for context plaintext. A viewer unlocks a trusted edge with vpd unlock <id>, and the browser receives a short-lived capability for one command path. The capability is bound to the runtime target that activated the unlock.

If the viewer has enabled auto-unlock for an online trusted machine, the platform can create that short-lived unlock session automatically. This is still a trusted-edge decrypt path: the daemon has the keys, the command runs over the relay channel, and the platform stores only unlock metadata such as install id and expiry.

Adding a new trusted device

Pairing and decrypt enrollment are separate.

StepWhat it provesWhat the platform stores
Pair daemonThe daemon may connect to the relay for this user/workspaceInstall and runtime target metadata
Device enrollment requestThe new device controls its enrollment signing keySigned public request, no private key material
Device enrollment approvalAn existing trusted edge wrapped user epoch material to that deviceCiphertext grant and AAD
Device enrollment acceptThe new device decrypted the grant and materialized the user epoch locallySigned materialization receipt

The materialization receipt is signed by the user epoch signing key that was inside the encrypted grant. The platform verifies the receipt with the public user epoch before marking the device decrypt-ready.

Recovery key backup

A recovery key is optional. It is for the worst case where every enrolled trusted device is gone. If you have two enrolled devices, losing one device does not require recovery; use the remaining device to approve a replacement or rotate after revocation.

When recovery is enabled, the daemon encrypts the active user epoch private material locally with a user-held recovery key and uploads only the encrypted backup envelope:

Rendering diagram...

The recovery key is not escrowed by Viewport. If you skip recovery and later lose every enrolled device, encrypted context and encrypted plan grants for that user may be unrecoverable. If the recovery key is stolen, rotate it from a trusted device and treat the old key as compromised.

Why a giant vault does not get loaded whole

Context is selected into a bundle. A bundle is a manifest plus selected items. Selection can use:

  • the repo identity
  • the configured provider/resource
  • profile settings
  • query text
  • max item limits
  • profile pins for stable, expected context

That means a large vault should behave more like a searchable library than a giant prompt prefix. The agent gets a bounded subset, and the manifest records what was selected.

Current limits

  • Revocation is soft. A device that already pulled and decrypted content cannot be forced to forget it.
  • The platform can enforce ACLs and stop future sync, but it cannot claw plaintext back from a trusted edge.
  • Encrypted content is only as good as the local key store and device security. Use OS-backed storage where available.
  • Context selection quality depends on profiles, queries, and review hygiene. The system prevents unreviewed pollution, but humans still need to curate important vaults.
  • A new trusted device must be enrolled before it can decrypt. Pairing by itself is connection authorization, not decrypt authorization.
  • Recovery key backups are optional. They protect against total device loss, but they add a secret the user must store safely.

Revoke and rotate

Revocation has two jobs: stop future authorization and rotate future cryptographic access.

Rendering diagram...

The platform tracks this as state, not as a hidden admin override. A remaining recipient moves back to "grant emitted" after a key rotation and becomes "materialized" again only after that recipient's trusted edge imports the rotated grant.

On this page