Witbitz docs HomeTrustAll docs

The room as a store — your app's data, sealed with the conversation

A Space can hold your app's data, not only its conversation: rows in named collections, sealed like everything else, ordered by the server without reading them, and readable by the assistant. An app can keep all its state in its rooms, with no database of its own.

Part of the SDK · every call: the reference.


Declare and write

Declare the collections when you make the room, or later with configure. Give each field one line: what it is, and the rule for it. Those lines go into the assistant's tool descriptions on every turn and are read at the moment it fills the field, so a rule about a field belongs on the field; who the assistant is belongs in its instructions.

javascript
const space = await wb.createSpace({
  agent: { name: 'Planner', instructions: 'Keep my week honest.' },
  data: {
    tasks:    { description: 'things to do', fields: { title: 'short text', due: 'ISO date — only if I said one', done: '0 or 1' } },
    projects: { fields: { name: 'short text' } },
  },
})

await space.data.put('tasks', { title: 'Buy milk', due: '2026-09-22', done: 0 })
await space.data.put('tasks', { title: 'Buy oat milk', done: 1 }, { id: 't1' })   // with an id: replace that row
await space.data.delete('tasks', 't2')
space.data.rows('tasks')   // [{ id, title, due, done, _updated, _by, _v }, …]
space.data.get('tasks', 't1')
space.on('data', ({ ops, from, self }) => rerender())   // every write, yours or the assistant's

space.data.batch(ops) writes several rows as one entry. A write answers { ok: true, id, ops } and throws on a refusal.

The store is the room's history. Every write is one entry in the room — ▦ Dana saved tasks “Buy milk” — so every member sees it, two devices writing different rows never collide, and any device holding the key rebuilds the store by reading the room. There is no second copy to drift. A row is at most 16 KB.

What the assistant gets, in a room that declares collections:

Tool Runs What it does
data_query in the turn, at once SQL over one table, rows(collection, id, row JSON, updated, by) — SELECT … WHERE json_extract(row,'$.due') < ? — so it answers "what is due this week" without being handed everything. Read-only, enforced by the engine; at most 200 rows. A query that runs longer than a few seconds is stopped, and the assistant is told to narrow it.
data_put proposes Add or replace one row. It is written when a member approves, never during the turn.
data_delete proposes Delete one row by id, the same way.

dataWrites: false lets the assistant read the store without proposing writes (builder mode). id and every field name starting with _ are the room's own: a write that sets one is refused (reserved_field) — what they carry is in who did what.

Row schemas

Field descriptions guide the assistant; a schema is enforced. Give a collection schema — JSON Schema for one row — and the room checks every write against it, so a row that does not fit is never stored:

javascript
const space = await wb.createSpace({
  agent: { name: 'Ops' },
  data: {
    tasks: {
      description: 'things to do',
      schema: {
        type: 'object',
        properties: {
          title:    { type: 'string', minLength: 1, maxLength: 80, description: 'what to do' },
          due:      { type: 'string', format: 'date' },
          priority: { enum: ['low', 'normal', 'high'] },
          estimate: { type: 'number', minimum: 0, maximum: 40, description: 'hours' },
        },
        required: ['title'],
        additionalProperties: false,
      },
    },
  },
})

try { await space.data.put('tasks', { title: 'Call', priority: 'urgent' }) }
catch (e) { e.code === 'invalid_row' /* tasks: priority must be one of "low", "normal", "high" */ }

Conditional writes

Two devices editing the same row is the one case a room's history cannot settle by itself — the last write would win — so a write can be made conditional. Every row carries _v, the id of the entry that last wrote it; pass it back, and the write is refused if the row has changed since:

javascript
const t = space.data.get('tasks', 't1')
try {
  await space.data.put('tasks', { ...t, done: 1 }, { id: 't1', ifVersion: t._v })
} catch (e) {
  if (e.code === 'row_changed') { /* e.conflicts: [{ collection, id, version }] — read again, merge, retry */ }
  else throw e
}
await space.data.put('tasks', { title: 'first' }, { id: 't9', ifVersion: null })   // only if t9 does not exist yet
await space.data.delete('tasks', 't1', { ifVersion: t._v })

Collections only admins write

Declare a collection write: 'admins' and only the room's admins may write it — see admins. The limits on collections and fields: Reference.

Machine-readable source: sdk-store.md · Generated 2026-10-27T07:05:42Z · build f301388c · every doc in one fetch: llms-full.txt (HTML)