Witbitz docs HomeTrustAll docs

Run an agent turn

An async Space does not keep an agent process alive. A member posts a turn; the render opens the sealed room state, runs the agent, writes the reply, and goes cold again.

That is the core runtime loop.


The turn flow

One request-scoped render
Member sends turn with room key and message
->
Render checks admission, opens the ledger, runs tools, re-seals, and drops the key
  1. A member sends { op:'turn', room, mk, message }.
  2. The transport checks commit(mk) against the Space record.
  3. If the Space is gated, identity is verified against the sealed admission policy.
  4. The render opens the sealed ledger.
  5. The member entry is appended.
  6. The agent runs with the Space's persona and tools.
  7. The reply, widgets, files, or pending proposals are appended.
  8. The ledger is re-sealed and stored.
  9. The room key is dropped.

Read the deeper version in Async Spaces.

Minimal turn

const r = await client.turn(room, mk, {
  from: 'Ada',
  text: 'Summarize our plan and list the unresolved decisions.'
})

For an open Space, that is enough.

Signed member turns

A signed turn proves which admitted member wrote the entry. The client signs the entry core and sends the signature with the message. For an email-gated Space, the message also carries an ID token and the member signing public key.

Conceptually:

await client.turn(room, mk, {
  text: 'I approve the itinerary.',
}, {
  email: 'ada@example.com',
  googleIdToken,
  sign: { priv: memberPrivateKey, pub: memberPublicKey }
})

The render verifies the identity and stores only the verified attribution, not the raw ID token.

Tools during a turn

A Space's tools are declared in its sealed config. During a turn, the agent can call those tools. Tool outputs may become:

High-stakes calls are not run directly. They become proposals under Delegated authority.

Reads after a turn

Clients normally watch a Space with pollSealed. When the sealed ledger changes, the client opens it locally and renders the new entries.

const r = await client.pollSealed(room, mk, previousEtag, previousCount)

For gated Spaces, read operations also include the caller's identity so the server can refuse unauthorized reads before returning sealed content.

What plaintext exposure means

In the current production tier, the server-side render receives mk during turns. That is why the model can reason over the Space. The key is request-scoped and dropped afterward, and storage remains ciphertext at rest.

This is not the same as "the operator can never see plaintext in use." The attested server tier is the path to making that stronger property checkable for production traffic; it is built and verifiable, but not yet serving ordinary Spaces.

Read: Status, The double blind, The attested tier

Code map

Concern File
HTTP turn op agent/spaceHandler.mjs
Runtime service agent/spaceService.mjs
Decrypt-once render agent/asyncTurn.mjs
Agent tool loop agent/brain.mjs, agent/brainTools.mjs
Delegated authority agent/delegatedAuthority.mjs
Client turn wrapper spaces/public/spaceClient.js

Machine-readable source: agent-turns.md · every doc in one fetch: llms-full.txt (HTML) · ← create-space · tools-widgets