Documentation

Shared agent note#

Each agent has one persistent Note, beside Chat and Dashboard (when enabled). It belongs to the agent rather than a conversation thread. It is separate from SOUL.md and Codex's private memory, and it is visible and editable by the user. Changing or starting a message thread does not replace it.

Use the note for a shared plan, reference details, or next steps. Paragraphs, three heading levels, bullet and numbered lists, and interactive to-dos are supported. Type # , ## , ### , - , 1. , or [] to start a block. Type / to search the block menu; use arrows and Enter, or tap a choice. The + Block button in the ••• editing menu below the note opens the same menu without typing. Escape closes it. Select text to reveal the floating bold, italic, and link toolbar; Alt+F10 moves keyboard focus into it. Undo and Redo are also available in the editing menu and through keyboard shortcuts. They work during an editing session, including after successful autosaves. Remote adoption, explicit reload, merge, and restore start a fresh undo history; Undo cannot remove an agent update from a previous editing session. Use revision history to restore older saved content.

Agent instructions sit above the note beside save status and History. They are optional, collapsed by default, and saved separately. The character count appears only near the 8,000-character limit. They tell the agent how to maintain the note; they never replace the note or permit purchases, messages, deployments, or other external actions. Only the user can edit these instructions. Agents must read both the current note and instructions before making a targeted, user-authorized edit. Existing approval boundaries still apply.

Saving, conflicts, and recovery#

Changes save after a short pause. The page reports Saving, Saved, or an error. While offline, drafts remain in browser storage on the current device. Reconnect to resume; if the server note changed, autosave pauses for reconciliation. A reopened note offers to recover an unsaved draft. Do not clear browser storage until drafts have been saved or downloaded. If browser storage is unavailable, keep the page open until saving succeeds.

An unsaved-draft recovery prompt keeps the saved note read-only until the user chooses to recover or discard the draft.

The page polls for changes every five seconds. It never replaces the editor while it has focus or has unsaved changes. Saves do not reset selection or undo. Concurrent changes to different blocks can be merged explicitly. Overlapping edits and reordering are not guessed: download the draft, reload the saved note, and reapply the intended changes. Reload/discard actions explicitly discard the local draft. Older poll responses cannot roll back a newer save.

History shows who changed the note, with revision previews and pagination. A restore creates a new revision and preserves current maintenance instructions. Save or resolve local edits before restoring. The server retains all revisions and retry records; storage grows with the note's edit history. No-op saves do not create revisions. Back up the Roost data directory to preserve notes and history.

Content and storage contract#

The browser and server share a validated structured format in apps/web/src/features/notes/schema.ts. There are at most 500 blocks, 500 inline spans per block, 20,000 characters per span, and 200,000 serialized characters per note. Maintenance instructions allow 8,000 characters. Each block has a UUID id, a type (paragraph, heading, bullet, ordered, or todo), and inline content. Spans contain text and optional bold, italic, and URL fields. Headings use levels 1–3; to-dos have a checked flag. New and split blocks receive fresh IDs; edits to an existing block retain its ID. Duplicate IDs are rejected.

Only HTTP, HTTPS, and mailto links are accepted. Renderers escape text and never inject note HTML. Pasted HTML is reduced to supported rich text; scripts, embedded content, event attributes, unsafe URLs, and copied IDs are removed. Lists are flat: indentation is disabled and pasted nested lists are flattened. Code, blockquotes, images, tables, strike, and underline are not offered as editable note formats. Line breaks, links, heading levels, and task completion survive save/reload.

Schema 14 integrates agent_notes, note_revisions, note_requests, and note_reads with Threads and Jobs. The atomic upgrade checks table shapes to support main schema 10, historical Notes-only schema 11, Threads schemas 11–13, and combined databases without replacing saved data. Jobs retain their separate feature-keyed migrations and active-report refusal preflight. Content, instruction, and restore writes use BEGIN IMMEDIATE, validate the agent, check maintenance availability, and compare the current revision. The entire transaction succeeds or rolls back. Each successful change advances a shared monotonic revision, so concurrent instruction changes also invalidate agent reads. Requests have stable UUIDs; an identical retry returns its original result, while reusing a UUID for another payload is rejected. Request IDs are scoped to the owner agent.

APIs and agent tools#

The Start functions in apps/web/src/features/notes/functions.ts provide current reads, content and instruction saves, paginated history, revision inspection, and restore. The application authentication and same-origin gates protect them; available and store-level maintenance checks follow other Roost features. Roost has one authenticated application owner. Agent tool ownership is narrower: the caller's server-owned agent ID is used, with no owner ID accepted in tool arguments.

  • roost_read_note: current content, instructions, revision, and a one-hour read token scoped to this agent and run.
  • roost_patch_note: up to 100 targeted edits with the current revision, read token, and a stable UUID request ID. Every edit includes the exact before block; replacements retain its ID. Insertions use before: null and an explicit afterId anchor (null means the beginning). Deletions use after: null.
  • roost_note_history: up to 100 revision metadata records, newest first; pass before with the oldest returned revision for the next page.
  • roost_read_note_revision: inspect an owner-scoped historical snapshot before proposing restore. Historical instructions are not current authorization.
  • roost_restore_note: user-requested content restore with current revision, read token, request ID, and target revision. Instructions remain unchanged.

Read tokens prove the current note and instructions were returned in this run; they do not grant external permissions. Reflection and mutation-disabled runs cannot write notes. A stale write returns NOTE_CONFLICT without mutation. The agent must read again, retain unrelated blocks, and construct a fresh targeted edit only if its intended change remains valid. It must not replace the whole note to resolve a conflict. Tool version 15 refreshes existing persistent threads to include these tools.

Editor choice and developer checks#

Tiptap 3.31.3 was selected over Lexical after reviewing both maintained projects. Both cores are MIT licensed (Tiptap license, Lexical license). Tiptap's pinned React package declares React 19 support. Its documented immediatelyRender: false setup defers the editor until hydration; Roost renders a safe text preview first. Its existing heading/list input rules, task-list support, history, and UniqueID extension cover this feature with less custom editor machinery.

Lexical's React integration is a credible alternative with modular plugins and an accessibility focus. It would also require application-owned slash menus, toolbars, stable persisted identities, and a persistence adapter. The choice here favors Tiptap's existing block and input-rule extensions, not a claim that one framework guarantees accessibility. Roost owns labels, focus handling, live save status, touch targets, menu keyboard navigation, and safe link entry. Browser review covers these application details.

apps/web/tests/notes.test.ts and apps/web/tests/notes-editor.test.ts cover persistence, owner/run boundaries, stale writes, read-before-edit, exact targeted edits, instruction independence, retries, revision inspection, pagination/restore, content bounds, unsafe URLs, escaped server rendering, editor round trips, and three-way recovery. The production authentication check exercises every note server function without a session and with a foreign origin. Run pnpm check for the repository's complete validation.