Skip to content

Instantly share code, notes, and snippets.

@MaskyS
Last active June 3, 2026 05:14
Show Gist options
  • Select an option

  • Save MaskyS/c60e58b7fb30afff35b10b91633b5783 to your computer and use it in GitHub Desktop.

Select an option

Save MaskyS/c60e58b7fb30afff35b10b91633b5783 to your computer and use it in GitHub Desktop.
Writing Roam — a syntax & conventions guide for LLMs (paste into any model). Distilled from Roam's in-app help graph.

Writing Roam

Roam is an outliner: use the graph — short blocks, nesting, and links — rather than dumping flat prose. Every example below is shown in code so it stays literal; type it without the backticks to make it live.

Roam primitives — blocks, refs & links, formatting, block references & embeds, callouts

Every example is shown in code so it stays literal — type it without the backticks to make it live.

Block model

  • A page is a tree of blocks (one bullet = one block); the block tree is the data model.
    • Roam also renders the tree through view types (document / bullet / numbered) and components ({{[[kanban]]}}, {{[[table]]}}, {{diagram}}, {{[[mermaid]]}}) — the tree is the substrate, not the only shape.
  • Escape rule — when documenting markup, wrap every example in inline code or a fenced block. Bare [[refs]], #tags, {{[[TODO]]}}, Name::, and [[>]] [[!TIP]] render LIVE and create stray pages, backlinks, checkboxes, and attributes.
  • Soft line break — Shift+Enter keeps text in the same block (no new bullet); this is how a pipe-separated tag-footer row sits under a block.

Refs and links

  • Page reference [[Page Name]]
    • Bidirectional link (type [[ to insert); creates the page if absent and collects backlinks in its Linked References.
    • Plain-text mentions of a page's name appear under its Unlinked References, where you can link them in one click.
    • Multi-word names are fine.
  • Block reference ((uid))
    • Points to one block; its text renders inline. [[ finds pages, (( finds blocks.
    • uids are usually 9 chars but can be any length (imported uids vary); preserve them, never invent duplicates (collisions fail import).
  • Tag #tag / #[[multi word]]
    • A page reference styled as a grey tag; conventionally placed at the start or end of a block.
  • Alias [label]([[Page]]) / [label](((uid))) / [label](https://url)
    • Custom display text over a page, block, or URL (default block-alias text is *).
    • Cmd/Ctrl+k turns selected text into an alias; hover an alias to preview the target.

Formatting

  • Bold **text**. Italics __text__ — double-underscore is ITALICS in Roam, not bold. Highlight ^^text^^. Strikethrough ~~text~~.
  • Headings # / ## / ### (H1–H3 only); a heading is still a block and can carry children and refs.
  • Inline code (single backticks); fenced code block with a language tag (javascript, css, clojure) held in one block (/code block).
  • Math $$KaTeX$$ — can compose inner $$...$$ from child blocks.
  • Blockquote — start a block with > (> then a space).
  • Image ![alt](https://url) or /upload. --- on its own block is a horizontal rule. Blocks can be left/center/right/justified.

Block references and embeds

  • ((uid)) references one block (text renders inline). An embed renders a live, editable COPY — distinct concepts; do not conflate.
  • Create a ref — right-click the bullet → Copy Block Ref, or Alt-drag a block, or type ((. Navigate with Ctrl-o (jump) / Ctrl-Shift-o (sidebar).
  • Context-menu "Replace With" modes
    • text — dead copy, link severed.
    • embed — live portal; edits propagate.
    • original — moves the canonical block here, leaving a ref behind.
    • alias — hyperlink.
    • text and alias — text + back-pointer; best for drafting.
    • Plus "Apply Children" as text or as references.
  • Embed variants
    • {{embed: ((uid))}} — the block plus its children.
    • {{embed-children: ((uid))}} — children only.
    • {{embed-path: ((uid))}} — with a clickable breadcrumb path.

Callouts

  • Styled blockquotes with a type icon and color.
  • Create with [[>]] [[!NOTE]] (canonical) or > [!NOTE]; /Callout inserts one; click the icon to change type.
  • Title = first line; body = next line via Shift+Enter (same block).
  • Foldable — append + (expanded) or - (collapsed) to the type, e.g. [[!TIP]]+; click the header to toggle. Works in heading blocks too.
  • 12 types: NOTE INFO SUMMARY TIP SUCCESS QUESTION WARNING FAILURE DANGER BUG EXAMPLE QUOTE.
    • Aliases: tldr/abstract, hint/important, check/done, help/faq, caution/attention, fail/missing, error, cite.
  • Custom type → "note" styling + .rm-callout--{type} class + --callout-color/--callout-bg vars (style via a {{[[roam/css]]}} block).

Roam components — the {{...}} family

Every example is shown in code so it stays literal — type it without the backticks to make it live.

Components

  • Invoke via /name or by typing {{[[name]]: arg}}.
  • Video {{[[video]]: url}} — YouTube / Vimeo / Loom (paste a URL and click play to auto-convert). /video.
  • Table {{[[table]]}}
    • Renders nested children as a grid: each first-level child is a row, and each deeper level within it is the next cell across (columns), so the first row reads as headers.
    • Cells can hold rich blocks ("complex cells") and columns are sortable.
    • Example (nesting depth = columns; first row reads as headers):
      {{[[table]]}}
          - Action
              - QWERTY
                  - Colemak
          - Select Block Up
              - k
                  - h
      
  • Kanban {{[[kanban]]}}
    • 1st-level children = columns (can be [[page]] refs); their children = cards; deeper nesting = card detail.
    • Cards are directly editable; Enter splits a card; drag-and-drop moves cards and rewrites the nesting; the board can be opened in the sidebar.
  • Mermaid {{[[mermaid]]}}
    • Diagram source in child blocks; the first child sets the type, and any diagram mermaid.js supports works (flowchart, sequenceDiagram, gantt, stateDiagram-v2, and so on).
    • Per-diagram theme: first line %%{init: {"theme":"forest"}}%%. Graph-wide theme: a {{[[roam/css]]}} block setting --mermaidjs-theme (reload required).
  • Diagram {{diagram: Title}} — a 2D canvas; every node IS a real block and appears in that block's references (not canvas-only); nodes can be images or {{[[video]]}}. Has a legacy version.
  • Mentions {{[[mentions]]: [[Page]]}} — inlines a page's linked + unlinked references (/mentions); {{children-mentions: [[Page]]}} inlines the children of those mentions.
  • Calc {{calc: 4 + 5}} — block-ref args scrape the FIRST number from the referenced block (3 from "My 3 apples"): {{calc: ((uid)) + ((uid))}}.
  • roam/render {{roam/render: ((codeUid))}} — renders a referenced code block as a component (some take extra arg refs). JS/JSX must be ES5 (no const/imports/exports); full component docs live in Roam's dev graph.
  • roam/css {{[[roam/css]]}} — a child fenced css block applies graph-wide styling. iframe {{iframe: https://url}} embeds a live webpage.
  • Hiccup — a block starting with :hiccup renders a Clojure/Hiccup vector as HTML, e.g. :hiccup [:iframe {:width "600" :height "400" :src "https://..."}]. (Real Roam feature, but NOT in the help-graph export — verify against Roam's dev docs before relying.)
  • More components
    • {{[[video-timestamp]]: ((videoUid)) HH:MM:SS}}/video timestamp or Cmd/Ctrl+Alt+t under a video; newer ones embed a ref to the video so they stay linked, older bare ones still work but do not auto-update.
    • {{character-count}} / {{word-count}} — slash-inserted; count the containing block, not the page; word-count also sorts in All Pages.
    • {{date}}/date calendar that inserts a date-page ref.
    • {{encrypt:CIPHERTEXT}} — a password-protected block; password unrecoverable and exports/backups are NOT encrypted; not graph-wide encryption.
    • {{[[streak]]: [[Goal]]}} — heatmap of how often a ref appears in daily notes; also takes query logic, e.g. {{[[streak]]: {or: [[DONE]] [[Solutions]]}}}.
    • {{[[slider]]}} (or / → Slider) — an inline rating control for polls; on Multiplayer graphs others can click to add their rating; used as an attribute value like certainty:: {{[[slider]]}} or in templates, and its state is captured/re-applied by templates.

Roam queries — {{query}} clauses and :q Datalog

Every example is shown in code so it stays literal — type it without the backticks to make it live.

Queries

  • Form {{query: {and: [[A]] {not: [[B]]}}}} (the {{[[query]]: ...}} form also renders; /query inserts).
  • Clauses
    • {and:} / {or:} match a block (or its parent) containing the refs; {not:} excludes; operands can mix [[page refs]] and ((block refs)).
    • {search: text} is a sub-clause nested inside {and:}/{or:}, never standalone; multiple can combine, e.g. {{query: {and: {search: June} {search: mobile}}}}.
    • {between: [[start]] [[end]]} works on Daily Notes pages ONLY; accepts [[today]] [[tomorrow]] [[yesterday]] [[last week]] [[next week]] [[last month]] [[next month]].
    • {created-by: [[User]]}, {edited-by: [[User]]}, {by: [[User]]}.
  • Queries also have UI controls for sorting and filtering, plus a "Nest under parent results" display option.

Datalog (advanced)

  • A :q block, written inline after :q (optionally with a quoted title) OR with a fenced clojure [:find ... :where ...] query.
    • A scalar find ((count ?b) .) shows inline; a relation renders as a table; a var whose name contains uid renders as a clickable block/page view.
  • Special symbols
    • current/* — page/block id, uid, title; main-window-* variants for sidebar queries that auto-refresh when the main window changes.
    • ms/* — millisecond bounds for :create/time/:edit/time; offsets like ms/+1M-start, absolute ms/=2025-01-01-start (note ms/+1W-end is not ms/+7D-end).
    • dnp/* — resolve to a daily-note page-title STRING, not a timestamp (e.g. dnp/today, dnp/=2025-01-01).
  • Inbuilt rules (custom rules NOT supported): (created-by) (edited-by) (by) (refs-page) (block-or-parent-refs-page) (created-between) (edited-between) (in-dnp-between) (refs-dnp-between) (in-or-refs-dnp-between) (in-dnp) (refs-dnp) (in-or-refs-dnp).
  • Works via the frontend window.roamAlphaAPI.data.q; the backend /api/graph/{name}/q does NOT support these additions.
  • Raw datascript schema (what :where clauses match): pages have :node/title; blocks have :block/string (text), :block/uid, :block/order (position under parent), :block/page, :block/children (immediate), :block/parents (all ancestors), :block/refs (outgoing refs), :block/heading (1–3), :block/text-align, :children/view-type (bullet/document/numbered); both carry :create/time / :edit/time (epoch ms) and :create/email / :edit/email (the attribution behind created-by/edited-by). Pull a tree: [:find (pull ?e [* {:block/children [*]}]) :where [?e :node/title "Page"]].

Roam attributes and class-tag styling

Every example is shown in code so it stays literal — type it without the backticks to make it live.

Attributes

  • Name:: value (double colon) creates a queryable attribute page; a single : or **bold:** does not. Values can be text, [[page]], #tag, embeds, or child blocks.
  • The help graph uses empty-value attributes as section labels (## Community Videos::, Articles::, Key Commands::) — a convention, not required syntax.
  • A page-level Type:: #TypeName attribute (multi-type allowed, e.g. Type:: #Project #Blog) shows a chip by the page title that opens a typed-fields sidebar panel.
  • The attribute-table macro {{=: ...}} is barely documented — verify before relying on it.

Class-tags (styling)

  • Any #.classname adds that CSS class to the block; Tailwind + Blueprint ship built in (#.bg-blue-500, #.text-xl, #.bp3-card).
  • #.rm-E — shows immediate children inline (first level only; re-tag to go deeper).
  • #.rm-g — hides the container and promotes children up one level (use [[.rm-g]] to keep it visible).
  • #.rm-hide — collapses the block to a thin bar until clicked open (for hiding metadata).
  • .rm-grid is NOT a documented class.

Conventions — daily notes, page shape, collaboration

Every example is shown in code so it stays literal — type it without the backticks to make it live.

Daily notes and dates

  • Date pages use Roam's English ordinal format, e.g. [[February 8th, 2021]], [[January 1st, 2021]]. [[today]] resolves dynamically; /date or {{date}} inserts a date.
  • Date pages are normal pages; blocks written on or referencing them are found via linked references and date queries. Daily Notes are Roam's default landing page and primary capture surface.

Good page shape

  • A few heading blocks (often [[refs]]) with content nested under; --- divides sections.
  • The help graph's "card" idiom (a help-graph convention, not a universal rule): ### Title by [[Author]] → a child media/link → a soft-break footer row of #[[topic]] tags.
  • Reuse with ((refs))/{{embed:}} when identity or edit-propagation matters; copy text when you want an independent copy.

Collaboration & multiplayer

"Multiplayer" is a concept cluster — sharing, roles, attribution, comments, reactions, versions — and most of those features never use the word.

  • Sharing & roles: a graph can be shared read-only, publicly editable, or with specific emails as readers/editors, by URL or email (three-dot menu → Share; a person needs a Roam account first). Your own MCP token also carries an access level (read-only / read-append / full) that caps what you can write.
  • Attribution: every block records who created and last edited it (queryable via the created-by / edited-by / {by:} rules). An agent writes as a distinct user — the "AI user", surfaced as aiUserDisplayName by get_graph_guidelines — so its writes are attributed and visible to collaborators like any other user's.
  • Shared-graph mechanics: edits and deletions are visible to every collaborator, and Roam's undo does not reliably reverse bulk or API-driven changes. A block can hold multiple drafts/versions (Ctrl/Cmd+,).
  • Comments are a separate thread on a block (add_comment / get_comments), distinct from child blocks. Reactions are emoji on a block. {{[[slider]]}} lets collaborators rate/vote.

More

For feature details, recent changes, and the API, Roam's documentation lives in two public graphs you can open and search like any other graph:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment