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 exactbeforeblock; replacements retain its ID. Insertions usebefore: nulland an explicitafterIdanchor (nullmeans the beginning). Deletions useafter: null.roost_note_history: up to 100 revision metadata records, newest first; passbeforewith 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.