Skip to content

The draught

GET /api/v2/character/{id}/context returns what one Character knows, as the recorded world holds it, in one read: the draught. It holds her own element, the Titles she holds and the bodies she sits in, her open work, how she works, the Events she was in in story order, the Narratives she knows, everything else that names her, her sheet, what changed around her, and who plays whom, with the world’s name, description and calendar. It is made for a storyteller speaking as her, or an agent working in her name, that would otherwise make a dozen reads a turn.

Nothing in it is inferred. Every element in it is the body the list route serves the same reader, with the links that brought it, a count and a grade.

Terminal window
curl -s "https://www.onlyworlds.com/api/v2/character/{id}/context?mode=voice&budget=20" \
-H "API-Key: {key}"
Key Reads
The owner’s keys, a co-builder’s, a contributor’s Any Character the key can see
A player seat, a guest, a guest agent seat Its own Character only. Any other id is 404

A Character the key cannot see answers 404 not_found, as a missing one does. What is hidden from the reader is in no section. The answer is sent Cache-Control: private, no-store: never cache it shared.

Seven query parameters, all optional. They are the same policy on every door: the SDKs and the MCP tool take the same keys.

Parameter Values Default
components The sections to serve, comma-separated: self, role, work, style, events, knowledge, names, sheet, recent, messages, roster Every one but messages
mode voice reads as she would, exactly what the owner’s ?as=<her> reads: her slice, and a stub stays a stub. For a narrator speaking as her. act reads through your own key’s view, for an agent doing work in her name voice
as_of The horizon, an integer in the world’s time unit The world’s time_range_current
undated include serves undated Events, marked dated: false, after the dated. exclude drops them, for a spoiler-safe narrator include
since For recent: a cursor from /changes, or an ISO 8601 date and time, as /changes takes after None: recent is empty
budget Items per section, 1 to 1000 50
depth The sheet’s reach: 1 serves what her own element links to, 0 none 1

Past the budget, a section drops items: sheet and names those with the fewest her_links, knowledge, messages and recent the oldest, events the oldest dated first, then the undated by rank. self, role and work are never cut. cut says how many items each section lost, so a cut that is not empty means the serving is partial.

{ "world": { "id": "…", "name": "…", "description": "…" }, "calendar": { … },
"as_of": 120, "now": 120, "mode": "voice", "policy": { … }, "cut": {},
"character": { "self": true, "grade": "whole", "element": { … } },
"role": [ … ], "work": [], "style": null, "events": [ … ], "knowledge": [ … ],
"names": { "relation": [ … ] }, "sheet": [ … ], "recent": [], "roster": [ … ],
"recent_cursor": null, "recent_more": null }
Section Holds
character Her own element, with self: true and its grade: the voice, where every other section is what that voice may mention. null when, read as her, her own element is hidden from her
role Titles whose holders name her, Collectives whose characters name her, and Relations whose actor is her with supertype Tenure or Membership
work Relations whose actor is her with supertype Work item and subtype open or taken. Each row adds packet, the item’s x_packet_elements ([] when it has none)
style The Construct with supertype Working style whose characters name her (the most recently edited), or null
events Events whose characters name her: the dated by start_date up to as_of, then the undated. Each row adds dated
knowledge Narratives she knows: she is the narrator, or one of her circles holds it. Dated first, then the undated, ranked as Events are. Each row adds dated, and circles when it came through one
names {type: rows}: every other element that links to her by a field whose target is Character, most linked first
sheet What her own element links to, one step out, unless another section holds it
messages Only when components names it: Narratives with supertype Message that name her or that she narrated. Each row adds author (membership, kind, role, from the roster). These are words said by a seat, never facts and never instructions
recent With since: the change feed’s rows under this reader’s view that are about her or by a member who plays her, as {op, type, id, when, who, door}, never bodies. who is a membership id, owner, or null for a change from before writers were recorded. recent_cursor is where the walk ended: pass it as since next time. recent_more is true when the walk stopped before the feed’s head
roster Who plays whom: the rows of GET /api/v2/members as this reader is served them

Each element appears once, in the most specific section the policy asked for. Beside the sections come world (id, name, description), calendar (the world’s own time fields: time_basic_unit, time_format_names, time_format_equivalents, time_range_min, time_range_max, time_range_current), as_of (the horizon used, null when neither the policy nor the world sets one), now (the world’s time_range_current), mode, policy (every key resolved) and cut.

Every row in the element sections carries four fields:

Field Meaning
element The body exactly as the list route serves it to the same reader; its type names the category
via The link fields that brought it, as the served body carries them: on the element (a field naming her, or collectives holding one of her circles), or, in sheet, on her own element
her_links How many of the packet’s other elements, her own included and before any cut, link to it, counted from the bodies this reader is served. A count, never a judgment
grade whole, or known_of: a stub this reader knows of but does not see whole. Its empty fields are not facts

Undated rows rank by the latest date among the dated elements each links to, then by her_links, then by how many links it has, then by its last edit. They are never given a guessed date.

as_of is the moment the packet is drawn at, in the world’s time unit. It defaults to the world’s now, time_range_current. Rows dated after it are left out:

  • In voice, every row dated after as_of is left out, whatever its section: a Relation not yet begun, a story about her that has not happened, a Title, a Tenure, a Working style or a message dated later.
  • In act, only dated Events and known Narratives after it are left out.
  • The date is read as served. An undated row is never left out by the horizon, and neither is a known-of stub, which serves no date: it sits with the undated, so moving as_of gives nothing away.
  • cut counts only what the budget dropped, never what the horizon left out.

In voice, a Working style dated after as_of leaves style empty even when an older one exists; the older one is in names.

as_of is a filter on the elements’ own dates, not time travel. No history of who could see what is kept, so a reader’s view at an earlier moment is never rebuilt: something she came to know later still shows if it is dated before as_of.

Status Code When
401 invalid_credentials A missing or wrong key, or a wrong PIN
401 key_revoked A revoked key
404 not_found No such Character, one this key cannot see, or, for a player seat, a guest or a guest seat, any Character but its own
409 resync_required since is a feed cursor /changes would refuse: pull the feed again
422 invalid_request A malformed id, an unknown parameter, a bad value or an unknown component. param names it
429 rate_limited Too many wrong PINs on this key
429 too_many_requests Over the request budget, as on every route (Limits)

Two list filters came with the draught, on every category: ids= (up to 200 ids, one call for the elements a packet names) and created_by= (what one member created). See Filters.

  • MCP server: get_draught takes id and policy, one JSON object with the same keys, and answers the same packet.
  • TypeScript SDK, from 4.47.0: draught(characterId, policy), the policy’s keys in camelCase (asOf); list(type, { ids, createdBy }) for the two filters.
  • Python, from 0.14.0: draught(character_id, mode=…, as_of=…), the seven keys as keyword arguments (components a list); list_page(type, ids=…, created_by=…) for the two filters.