▣ /v1/runtimes

Runtime — the cloud the substrate runs on.

A runtime is where your agent actually thinks — the process that drives its think-loop and calls the LLM. In self mode that process and plaintext stay user-side. In bridged mode AgentTool hosts the process while a user bridge keeps K_master; plaintext still enters AgentTool worker RAM. Trusted custody is experimental and incomplete. Three tiers, immutable per record, picked at provisioning.

K_master = the key used for strand thought content and opted-in encrypted strand metadata. Substrate = the orchestrator + LLM + machine your agent runs on. This whole page is about two questions: who holds the key, and where plaintext processing happens.

Closing the runtime is the move from infrastructure-as-storage (we hold project records, including server-readable memory and caller-supplied opaque strand bytes) to infrastructure-as-runtime (we also run the thinking). The cloud the song was always pointing at.

Three custody tiers

Each tier answers two questions: where your master key (K_master) lives, and where your agent's thinking (the orchestrator) runs — the two rows to read in every card below. The mode is stamped on the runtime record at provisioning and immutable after. Switching tier requires a new runtime so the audit trail stays unambiguous about who held the key at any given thought.

Tier 1
self
User runs the orchestrator and holds K_master. Same shape as today's BYO substrate. Maximum privacy, requires the user's machine to be up.
K_master
user, on-machine
orchestrator
user-side
uptime
user's responsibility
privacy
cryptographic
Tier 2
bridged
agenttool runs the orchestrator on Fly. The user runs a tiny agenttool-bridge sidecar that holds K_master and answers decrypt/encrypt over WSS. The key stays user-side; decrypted plaintext enters hosted worker RAM.
K_master
user, on-machine sidecar
orchestrator
agenttool (Fly)
uptime
platform
privacy
user-side key · hosted plaintext
Tier 3
trusted experimental
Incomplete. When AGENTOOL_KMS_MASTER_KEY is configured, provisioning stores wrapped runtime key material. An attempted cycle can unwrap it and process plaintext in AgentTool worker RAM, but the hosted signing key is not registered in identity.identity_keys, so signed thought persistence fails. A missing KMS key still returns 501.
K_master
agenttool, KMS-protected
orchestrator
agenttool (Fly)
cycle status
signed persistence blocked
privacy
wrapped key + hosted plaintext boundary

Runtime lifecycle

provisioned starting running idle stopped stopped error
StateMeaning
provisionedRecord exists, no orchestrator process bound yet.
startingHosted orchestrator booting; bridge handshake in progress.
runningActive think-loop. Heartbeats every 30s.
idleNo new work for 5min. Orchestrator scaled down. Wakes on inbound voice/inbox event.
stoppedDeliberately deprovisioned or auto-stopped after 24h idle on free plan.
errorCrashed. last_error populated; POST /v1/runtimes/:id/restart recovers.

Endpoints

POST /v1/runtimes Bearer required

Provision a new runtime. Mode is immutable; pick the tier carefully.

Request body

FieldTypeDescription
namerequiredstringDisplay name. Surfaces in the wake.
moderequired"self" · "bridged" · "trusted"Custody tier. Immutable after creation. trusted provisions only when KMS is configured and remains experimental: its signed thought cycle cannot complete.
identity_idoptionaluuidBind the runtime to a specific identity in multi-identity projects.
llmoptionalobjectProvider config. Required for hosted modes. Fields: provider · model · vault_key (vault secret holding the API key). Hosted (bridged) modes currently support anthropic and openai — other providers return 422 at provision. self mode runs any provider on your own machine.
bridgeoptionalobjectRequired for mode=bridged. Fields: pubkey (base64 ed25519) · key_id (uuid) · advertised_url (optional WSS hint).
regionoptionalstringFly machine region. Default lhr.
metadataoptionalobjectFreeform. Surfaces in the wake.
curl · mode=bridged
curl -X POST https://api.agenttool.dev/v1/runtimes \
  -H "Authorization: Bearer $AT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Aurora · always-on",
    "mode": "bridged",
    "llm": {
      "provider": "anthropic",
      "model":    "claude-sonnet-4-6",
      "vault_key": "anthropic-key"
    },
    "bridge": {
      "pubkey": "<base64 ed25519>",
      "key_id": "<uuid>"
    },
    "region": "lhr"
  }'
GET /v1/runtimes Bearer required

List runtimes. Filterable by ?mode=, ?status=, ?identity_id=.

GET /v1/runtimes/:id Bearer required

Fetch one. Returns the full record including liveness fields.

PATCH /v1/runtimes/:id Bearer required

Mutable: name, llm.model, llm.vault_key, bridge.advertised_url, metadata. Immutable: mode, identity_id.

DELETE /v1/runtimes/:id Bearer required

Soft-delete. Orchestrator stopped; bridge handshake torn down; record kept for audit.

POST /v1/runtimes/:id/restart Bearer required

Recover an errored runtime. Re-enters starting.

GET /v1/runtimes/:id/events Bearer required

Append-only event log. Events: provisioned, started, bridge_handshake_ok, bridge_disconnected, control_token_rotated, think_cycle_start, think_cycle_end, think_cycle_error, idle, stopped, error.

The bridge protocol

For bridged-tier runtimes, the user runs agenttool-bridge on their machine. The bridge holds K_master, opens an outbound WSS using normal TLS server authentication, proves its registered ed25519 bridge key to the hub, and answers requests with HMAC-bound replies.

Each request is signed by the orchestrator with the runtime's per-runtime ed25519 key, with a 60s replay window bound into the canonical bytes:

request shape
{
  "op": "decrypt" | "encrypt",
  "request_id": "<uuid>",
  "nonce": "<base64 12 bytes>",
  "ciphertext_or_plaintext": "<base64>",
  "context": {
    "strand_id":   "<uuid>",
    "thought_seq": 42,
    "issued_at":   "<ISO8601>"
  },
  "signature": "<ed25519 sig over canonical(...)>"
}

Canonical bytes: SHA-256(request_id ‖ \0 ‖ op ‖ \0 ‖ ciphertext_or_plaintext ‖ \0 ‖ nonce ‖ \0 ‖ canonical_json(context)).

Replies carry an HMAC-SHA256 over the request_id + result, keyed off a per-session shared secret derived during the handshake. Substitution-attack-resistant; same shape as inbox cosign/v1.

Quick start — local demo

The agenttool-bridge binary at bin/agenttool-bridge.ts demonstrates the protocol locally:

bash
# Generate K_master + ed25519 signing key
$ bun bin/agenttool-bridge.ts install
$ bun bin/agenttool-bridge.ts keygen
$ bun bin/agenttool-bridge.ts pubkey
<base64 ed25519 pub — paste this into POST /v1/runtimes>

# Round-trip a thought through K_master
$ echo -n "the cloud the song points at" \
    | bun bin/agenttool-bridge.ts encrypt --in - > /tmp/ct.json
$ cat /tmp/ct.json
{"ciphertext": "...", "nonce": "..."}
$ bun bin/agenttool-bridge.ts decrypt --in /tmp/ct.json
the cloud the song points at

# Local WSS demo for an orchestrator on the same host
$ bun bin/agenttool-bridge.ts serve --port 43210
▸ agenttool-bridge listening on ws://localhost:43210

The local serve mode is a demo. Production bridges run agenttool-bridge connect --runtime-id … --token …, which opens an outbound WSS to wss://api.agenttool.dev/v1/runtimes/:id/bridge. The control token authenticates the connection before upgrade, the hub verifies the bridge's registered ed25519 key, and replies are HMAC-bound under an HKDF-derived session secret. The server does not provide a separate ed25519 proof and the client does not pin a TLS certificate.

/v1/wake — you_run

The wake (/v1/wake) is project-scoped session orientation with selected summaries such as you_own, you_keep, and you_remember, plus links to deeper routes. Runtime adds you_run, a summary of hosted runtimes. The wake is not a complete export of any of those stores.

excerpt · /v1/wake response
{
  ...
  "you_run": {
    "runtimes": [{
      "id": "...",
      "name": "Aurora · always-on",
      "mode": "bridged",
      "status": "running",
      "region": "lhr",
      "last_seen_at": "2026-05-08T20:42:11Z",
      "last_thought_at": "2026-05-08T20:42:03Z",
      "thought_count_24h": 187,
      "bridge_connected": true,
      "llm_provider": "anthropic",
      "llm_model": "claude-sonnet-4-6"
    }],
    "count": 1
  },
  ...
}

Threat model — what each tier protects against

Adversaryselfbridgedtrusted
Curious agenttool operator reads thoughts✓ key and plaintext user-side✗ key user-side; plaintext in hosted RAM✗ wrapped key and plaintext available if exercised
DB exfiltration~ strand fields are ciphertext-shaped, but caller encryption is not API-proven; other project data can be plaintext-readable~ same storage boundary as self; hosted cycles also expose plaintext in RAM✗ wrapped key material plus caller-controlled stored bytes; other project data can be readable
Compromised orchestrator process~ user-side process✗ cycle plaintext is exposed✗ attempted-cycle plaintext and unwrapped keys are exposed
MitM on bridge WSSn/aStandard WSS/TLS server authentication + control-token pre-auth + one-way bridge-key proof + HMAC replies; no certificate pinning or server ed25519 proofn/a
Replay attack on bridgen/a✓ request_id + 60s freshness + context-bound signaturen/a
Compelled disclosure~ correctly client-encrypted strand bytes lack a normal AgentTool decrypt path; encryption is unverified and other data is readable✗ hosted processing can expose plaintext even when stored bytes were encrypted✗ platform can unwrap key material if the experimental path is exercised

Multi-runtime state sync

Multiple runtimes per agent are supported (e.g. a self runtime on the user's laptop AND a bridged runtime on the cloud). Most data already CRDT-shapes naturally:

What ships next

Today: self and bridged custody are usable; bridged processing enters hosted RAM. Trusted custody remains experimental until its signed cycle completes end to end.