roam-research/roam-tools/roam-syntax
Claude Code and agent skill by roam-research/roam-tools
- community
Checking that the SKILL.md file is still in the repository.
Write and read content in a Roam Research graph correctly. Roam's markdown differs from standard markdown, and its MCP tools render block metadata (headings, block references, view types) into a wire format you must handle when writing content back. Use this whenever creating, editing, searching, or organizing content in a Roam graph — including via the roam-mcp tools (create_page, create_block, update_block, get_page, get_block, search) — or when you encounter Roam syntax like [[page links]], ((block refs)), #tags, {{[[TODO]]}}, attribute:: values, {{[[query]]}}, or <roam .../> tags, even if the user doesn't say "Roam". Covers writing syntax, reading tagged output without losing block references, queries, components, and graph conventions. Not for standard-markdown files or non-Roam note apps.
Install
npx vskill@latest install roam-research/roam-tools/roam-syntaxSKILL.md
Roam syntax
You're working in a Roam Research graph — an outliner, not a document editor. A page is a tree of blocks (one bullet = one block); nesting (indentation) is the structure, and [[links]] / ((block refs)) are the point. Use the graph; don't dump flat prose into it.
Two rules dominate everything else:
- Roam's markdown is not standard markdown — the differences below silently corrupt content or
pollute the graph if you use standard-markdown habits.
- Reads return a rendered wire format; `update_block` writes literally. Handle the
<roam .../>
tags and ((uid))<ref>...</ref> block-ref previews correctly or you'll destroy references on write-back.
When working through the roam-mcp tools, call get_graph_guidelines before your first read or write in a graph — it returns the user's own conventions plus a compact roamSyntax summary of the gotchas below.
Gotchas (the highest-signal part — read this)
Writing: Roam markdown ≠ standard markdown
| You want | Use this (Roam) | NOT (standard markdown) | |
|---|---|---|---|
| Italics | __text__ (double underscore) | *text* / _text_ (see note) | |
| Bold | **text** | __text__ (that's italics) | |
| Highlight | ^^text^^ | — | |
| Strikethrough | ~~text~~ | — | |
| Checkbox / task | {{[[TODO]]}} / {{[[DONE]]}} at block start | - [ ] / - [x] | |
| Heading | # / ## / ### at block start (H1–H3 only; ####→H3) | ####+ | |
| Numbered list | childrenViewType: "numbered" on the parent | 1. / 2. markers | |
| Table | write a pipe table — create ops convert it | hand-building {{[[table]]}} | |
| Nesting | indent child blocks | headings (in bullet markdown) do NOT slurp what follows |
- Italics is `__text__`. On
update_block(literal),*text*/_text_are stored as-is and
render as plain characters; create_page / create_block normalize them to __text__. Always write __text__ so reads and writes agree.
{{[[TODO]]}}renders a checkbox anywhere, but it must lead the block or clicking it won't
toggle to {{[[DONE]]}}.
- Headings are structural, but in bullet-list markdown they stay flat — a heading does not pull
the blocks after it in as children. Nest by indenting. (####+ silently clamps to H3.)
create parses; update_block is literal
create_page/create_blockparse the markdown you pass (all the syntax above; a pipe table
becomes a {{[[table]]}} block; nested bullets become a block tree).
update_blockstores itsstringliterally — no markdown parse, no new children. Use it for
text edits; use its params heading (0–3) and childrenViewType (bullet/numbered/document) for structure, and create_block for new nested content.
childrenViewTypeis a param oncreate_page/update_page/update_block— not
create_block. To make a new block's children numbered: create it, then update_block its uid.
The escape rule (avoid polluting the graph)
Markup renders live when written. If your text is _documenting_ syntax (e.g. explaining how [[links]] or {{[[TODO]]}} work), wrap the examples in ` inline code ` — otherwise you create real pages, refs, and checkboxes.
Reading Roam output
get_page / get_block / search / get_backlinks / get_comments / roam_query / semantic_search return rendered markdown, one block per line:
- The trailing `<roam .../>` tag carries metadata:
uid— the handle for every follow-up call,
optional heading (1–3), childrenViewType, refs (backlink count — high = edit with care), hiddenChildren="N" (the subtree was cut off by maxDepth; read deeper with a higher maxDepth before assuming you've seen everything), and truncated="N" (search/semantic results only: N characters of a long block were cut — get_block the uid for the full text before editing it, or a write-back would overwrite the block with just the visible prefix).
- Strip the whole `<roam .../>` tag before showing content to the user. When quoting or showing
the user their own notes, reproduce the text verbatim (don't silently reword or reformat). When the user explicitly asks you to summarize or transform, do that.
- A block reference reads as
((uid))<ref>preview</ref>, where<ref>holds the referenced
block's text. When displaying, show the preview text and drop the ((uid)) + tag.
- A `uid` should be there on every block. If one is ever missing, that block's stored uid is
invalid (rare — legacy or imported content), and it cannot be addressed: update_block, delete_block and move_block all require a uid. Leave that block alone. Show its content if asked, but don't invent a uid and don't re-create its content elsewhere as a workaround — that just duplicates it. This covers the truncated="N"-without-uid case above: with no uid you can't fetch the full text, so don't edit that block from the visible prefix at all.
Writing
- New content →
create_page/create_blockwith markdown (parsed). Build hierarchy by
indenting; use headings as labels, not as containers.
- Editing an existing block's text →
update_block(literal). Structure/display via itsheading
/ childrenViewType params.
- Write-back is the dangerous case. When you edit a block you read, pass only the content to
update_block:
- drop the leading
-/ indentation and the trailing<roam .../>tag (they are not part of the
block string), but
- keep any `((uid))<ref>...</ref>` intact — the server decodes it back to
((uid)). - Do not write the display-cleaned preview alone (the
<ref>text without its((uid))) — that
replaces the live reference with static text. A tags-only strip that leaves the preview behind stores it as duplicate content.
- Editing text inside a
<ref>…</ref>preview is a silent no-op — the server discards the
preview on write and keeps only ((uid)). To change the previewed text itself: get_block the referenced uid (it's the ((uid)) in the annotation), then edit its full returned content with this same write-back procedure — don't reconstruct it from the preview, which may be capped or have nested refs flattened.
See references/reading-writing-via-mcp.md for worked read→edit→write examples that don't lose refs, and why the round-trip behaves this way.
Behavioral doctrine
These are defaults for when the user hasn't asked for a specific change — explicit user intent always wins, and the graph's own [[roam/agent guidelines]] (returned by get_graph_guidelines) govern style and conventions. The syntax and data-integrity rules in this skill apply regardless: no convention can make update_block parse markdown, make a truncated prefix complete, or keep a reference live after its ((uid)) is dropped. If the user says "fix / rewrite / delete this block," do exactly that.
- One fact per block. Nest details under a short lead block instead of writing long blocks —
blocks are the unit of reference, so long prose blocks defeat the outliner.
- Don't duplicate content across blocks or pages — link it with
((block refs))or
[[page refs]] instead.
- Append over edit. Under ambiguity, add a child or sibling block rather than modifying existing
content — especially human-authored blocks.
- Comment, don't rewrite. To give feedback on someone's block, use
add_comment, which preserves
the original.
- Daily note is the safe fallback. If unsure where content belongs, today's daily note is almost
always right.
- Don't move or delete without explicit permission — both can silently destroy meaning; a delete
also rewrites every block that referenced the target.
- Respect load-bearing blocks. A block with a high
refscount is structurally important — edit
it with extra care.
- Create page links intentionally, and don't fabricate block refs.
[[Page]]links AND mints
the page if it doesn't exist — link entities that genuinely recur, don't bracket every noun. Use ((uid)) only for blocks already in your working context — don't search the graph just to manufacture a block ref.
- Search before create; read before write. Check whether a page/section already exists, and read
existing content before changing it.
Reference files — load the one you need
references/syntax.md— full Roam-flavored markdown: inline formatting, links / refs / aliases /
embeds, headings, callouts, attributes, code, images, separators, class-tag styling, and the complete WRONG-vs-RIGHT table. Load when writing anything beyond the gotchas above.
references/components.md— the{{...}}component family (table, kanban, video, mermaid, embed
variants, mentions, calc, roam/render, roam/css, slider, …). Load when inserting a component.
references/queries.md—{{query}}clauses/operators and page-ref inheritance, plus:qDatalog
(run via the datalog_query tool) and the datascript schema. Load when building a query.
references/reading-writing-via-mcp.md— how the MCP render-on-read / literal-on-write model works,
the round-trip / decode behavior, and which tool to use for what. Load when editing content you read back, or unsure which write tool to use.
Compatibility
Assumes a Roam Research graph, typically via the roam-mcp MCP server / CLI (npm @roam-research/roam-mcp). The syntax guidance also applies to hand-writing Roam markdown.
Security
- Security scanPassed, 95 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/roam-syntax/SKILL.md
Popularity
- Repository stars
- 57
- Repository forks
- 8
- 7-day trend score
- 20
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/roam-research/roam-tools/roam-syntax)