Roam Research
The Roam Research MCP server enables AI assistants to programmatically interact with Roam Research graphs through a standardized interface, providing comprehensive read and write operations:
Content retrieval: Fetch pages by title, search for specific text, dates, block references, or pages modified today
Content creation: Create new pages, blocks, hierarchical outlines, or import markdown
Content management: Add todos, update blocks (individually or in batch), store and recall memories
Advanced search: Search by tags, status (TODO/DONE), hierarchy, or execute custom Datomic/Datalog queries
Automation: Perform batch operations and efficiently handle nested content structures
This allows AI assistants to fully leverage Roam's database capabilities for both retrieving and manipulating graph content.
Supports loading configuration from .env files for managing environment variables like API tokens and graph names.
Enables parsing and conversion of markdown content, with support for importing nested markdown structures into Roam Research with proper hierarchy preservation.
Provides comprehensive access to Roam Research's API functionality, allowing AI assistants to interact with Roam Research graphs through tools for fetching, creating, and updating pages and blocks, importing markdown, searching content, and executing Datalog queries.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Roam Researchsearch for notes about project planning from last month"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.

Roam Research MCP + CLI
Introduction
I created this project to solve a personal problem: I wanted to manage my Roam Research graph directly from Claude Code (and other LLMs). As I built the Model Context Protocol (MCP) server to give AI agents access to my notes, I realized the underlying tools were powerful enough to stand on their own.
What started as an backend for AI agents evolved into a full-featured Standalone CLI. Now, you can use the same powerful API capabilities directly from your terminal—piping content into Roam, searching your graph, and managing tasks—without needing an LLM at all.
Whether you want to give Claude superpowers over your knowledge base or just want a robust CLI for your own scripts, this project has you covered.

Related MCP server: Roam Research MCP Server
How this differs from Roam's official MCP server
Roam Research ships its own MCP server and CLI (@roam-research/roam-mcp). It is a good tool, and this project is not trying to replace it. They talk to two different Roam APIs, which is the difference everything else follows from.
This project | Official | |
Talks to | Roam's backend REST API (graph token + graph name) | Roam Desktop's local HTTP API |
Needs Roam running | No — works headless | Yes, the desktop app must be open (it deep-links to launch it) |
Where it can run | Anywhere: laptop, server, container, CI | The machine running Roam Desktop |
Shared daemon | Yes — | Per-client stdio |
Multi-graph |
|
|
Web-only graphs | Works | Desktop only |
Reach for the official server when you want Roam's own supported path, or you need things only the running app can do: controlling the Desktop UI (open a page, read the current selection, drive the sidebar), semantic/embeddings search, link suggestions, file upload, comments, or invoking tools that Roam extensions register.
Reach for this one when Roam isn't running or isn't installed — a server, a container, a cron job, a CI step. Or when you want the extras this project has grown: a full standalone CLI with stdin piping, a shared HTTP daemon with optional bearer auth, smart page diffing that preserves block UIDs (and therefore your block references), batch operations with UID placeholders for building nested structures in one call, and agent memory tools.
One deliberate omission: there is no page-delete tool here. Roam has no undo that can reverse a bulk API deletion. The official server does offer delete_page; this project takes the more conservative line.
They interoperate
The two servers share conventions on purpose, so running both costs you nothing:
[[roam/agent guidelines]]— both read the same page for your conventions. Write them once; both honour them. See Agent guidelines.#.rm-hide/#.rm-private— both withhold tagged blocks from AI-facing content. Tag once, hidden from both. See Hiding content from the AI.
Standalone CLI: roam
The roam CLI lets you interact with your graph directly from the terminal. It supports standard input (stdin) piping for all content creation and retrieval commands, making it perfect for automation workflows.
Quick Examples
# Save a quick thought to your daily page
roam save "Idea: A CLI for Roam would be cool"
# Pipe content from a file to a new page
cat meeting_notes.md | roam save --title "Meeting: Project Alpha"
# Create a TODO item on today's daily page
echo "Buy milk" | roam save --todo
# Prepend to top of page (newest-first ordering)
roam save -p "Changelog" --order first "v2.18.0 release"
# Search your graph and pipe results to another tool
roam search "important" --json | jq .
# Search for pages by namespace prefix
roam search --namespace "Convention" # Finds all Convention/* pages
# Fetch a page by title
roam get "Roam Research"
# Fetch daily pages using any date format (auto-normalized)
roam get today # Today's daily page
roam get 2026-03-21 # ISO date → "March 21st, 2026"
roam get "03/21/2026" # US date → "March 21st, 2026"
roam get "March 21" # Named (assumes current year)
# Fetch a block with ancestors (parent chain to page root)
roam get abc123def -a # Block + children + ancestors
roam get abc123def -a -d 0 # Ancestors only, no children
# Fetch page by UID or Roam URL
roam get page abc123def
roam get page "https://roamresearch.com/#/app/my-graph/page/abc123def"
# Sort and group results
roam get --tag Project --sort created --group-by tag
# Find references (backlinks) to a page
roam refs "Project Alpha"
# Update a block (e.g., toggle TODO status)
roam update ((block-uid)) --todo
# Multi-graph: read from a specific graph
roam get "Page Title" -g work
# Multi-graph: write to a protected graph
roam save "Note" -g work --write-key "$ROAM_SYSTEM_WRITE_KEY"Available Commands: get, search, save, refs, update, batch, rename, status, server.
Run roam <command> --help for details on any command.
Installation
npm install -g roam-research-mcp
# The 'roam' command is now available globallyMCP Server Tools
The MCP server exposes these tools to AI assistants (like Claude), enabling them to read, write, and organize your Roam graph intelligently.
Multi-Graph Support: All tools accept optional
graphandwrite_keyparameters. Usegraphto target a specific graph from yourROAM_GRAPHSconfig, andwrite_keyfor write operations on protected graphs.
Tool Name | Description |
| Fetch page content by title. |
| Fetch a page's content plus all linked references with breadcrumb context and children. |
| Fetch a block by UID with optional children (depth) and/or ancestors (up to page root). |
| Create new pages, optionally with mixed text and table content. |
| Update a page using smart diff (preserves block UIDs). |
| List sub-pages under a namespace prefix (e.g. "Project/") with optional tag filter. |
| Full-text search across the graph or within specific pages. Supports namespace prefix search for page titles. |
| Find blocks that reference a page, tag, or block UID. |
| Find TODO or DONE items. |
| Find blocks containing specific tags (supports exclusion). |
| Find blocks/pages by creation or modification date. |
| List pages modified since midnight. |
| Add TODO items to today's daily page. |
| Create properly formatted Roam tables. |
| Create hierarchical outlines. |
| Execute multiple low-level actions (create, move, update, delete) in one batch. |
| Move a block to a new parent or position. |
| specialized tools for AI memory management within Roam. |
| Execute raw Datalog queries for advanced filtering. |
| Retrieve the Roam-flavored markdown reference. |
| Retrieve this graph's user-defined agent conventions. |
Structured results from write tools (v3.0.0+)
The ten write tools declare an outputSchema and return structuredContent — a validated object — alongside the usual text. A client can read page_uid, uid_map or success directly instead of hunting for JSON inside a string, which makes chaining calls more reliable:
// roam_process_batch_actions
{ "success": true, "uid_map": { "parent1": "Xk7mN2pQ9" },
"validation_passed": true, "actions_attempted": 4 }Three things worth knowing:
Nothing was taken away. The text channel is unchanged, so a client that ignores
structuredContentbehaves exactly as before.Read tools deliberately have neither. They already serialise their whole result into the text channel, so a schema would just double the payload.
These fields are additive-only. Some clients validate live responses against a cached tool list, so a field will be added or deprecated — never renamed or removed outside a major version.
Upgrading from 2.x: three write-result fields were renamed —
uid→page_uid(roam_create_page),created_uids→created_blocks(roam_create_outline,roam_import_markdown) andpreservedUids→preserved_uids(roam_update_page_markdown). This only affects code that reads those names; if you use the server through an AI assistant, nothing changes. See the changelog for why.
Agent guidelines (per-graph)
roam_get_guidelines reads a page inside the graph — [[roam/agent guidelines]] by default — holding your own conventions: how you tag, how you namespace pages, what an agent should never do. Roam's official MCP server reads the same page title, so one page serves both.
This is distinct from CUSTOM_INSTRUCTIONS_PATH, and the two compose:
|
| |
Lives in | a file on disk | a page in the graph |
Scope | server-wide, all graphs | per-graph |
To change it | edit the file, restart the server | edit the page |
Answers | how to write Roam markdown | how this user wants this graph handled |
Just create the page. With no configuration at all, roam_get_guidelines reads [[roam/agent guidelines]] — the same title Roam's own server reads, so writing it once makes both honour it. Creating a page with that exact namespaced title is the opt-in; nothing is read from the graph unless an agent explicitly calls the tool.
If the page doesn't exist, the tool returns exists: false rather than failing, so it is always safe to call.
It also returns the rules that aren't yours to set
Alongside your conventions, every roam_get_guidelines response carries a roamSyntax field: the short list of things that destroy content — roam_update_page_markdown deleting every block your markdown omits, truncated structure previews written back as if they were content, block references retyped as plain text — plus a caution that reads silently exclude #.rm-hide subtrees, and the handful of places Roam's markdown inverts standard markdown.
Two reasons it rides here rather than in the cheatsheet. It reaches every client, including one that never calls roam_markdown_cheatsheet; and it is returned even when a graph has no guidelines page, which is exactly the case where an agent has least context. The layering is deliberate: your conventions win on style, roamSyntax wins on data safety. No convention can make a truncated preview complete.
The full syntax reference — components, queries, embeds, tool selection — stays in roam_markdown_cheatsheet. roamSyntax is ~800 tokens and deliberately capped.
Each graph can point at a different page, or turn it off:
ROAM_GRAPHS='{
"personal": {"token": "...", "graph": "..."},
"work": {"token": "...", "graph": "...", "guidelinesPage": "work/agent rules"},
"private": {"token": "...", "graph": "...", "guidelinesPage": false}
}'
ROAM_GUIDELINES_PAGE='team/agent guidelines' # change the default for every graphResolution order is per-graph guidelinesPage → ROAM_GUIDELINES_PAGE → roam/agent guidelines. Above: personal uses the env override, work uses its own page, and private has guidelines off entirely. Only an explicit false disables it — an unset value never does.
Results are cached for 30 seconds — an edit to the page takes effect without a restart. A starter template lives at .roam/agent-guidelines.template.md.
Note that guidelines are read through the normal page path, so blocks tagged #.rm-hide / #.rm-private are withheld from them too — see below.
Hiding content from the AI
Blocks tagged #.rm-hide or #.rm-private — and everything nested under them — are omitted from the content these tools return. Both the hashtag (#.rm-hide, #[[.rm-hide]]) and link ([[.rm-hide]]) forms work. .rm-private is Roam's existing "hidden from other users" tag; .rm-hide hides from the AI specifically.
This follows the same convention as Roam's official MCP server, so a block tagged for one is hidden from the other.
Applied to: roam_fetch_page_by_title, roam_fetch_block, roam_fetch_page_full_view, roam_get_subpages, roam_search_by_text, roam_search_for_tag, roam_search_by_status, roam_search_block_refs, roam_search_hierarchy, roam_search_by_date.
Hidden blocks are also excluded from the page-rewrite diff, which is what stops them being deleted for being absent from markdown the agent could not have written. roam_update_page_markdown (and roam save --update) replaces a page with what you give it, deleting whatever your markdown omits — so its baseline is pruned by this same filter, on the rule that the baseline a diff deletes from must be the same page the caller was allowed to read. It reports preserved_hidden when it protected anything. Content is preserved; exact ordering relative to visible siblings may shift. This was a real data-loss bug before the fix — see the changelog.
This is a convenience filter, not a security guarantee. roam_datomic_query reads the database directly and deliberately does not apply it, so a capable agent can still surface hidden blocks through raw Datalog. Treat these tags as "keep it out of the AI's way," not "keep it secret."
Tag matching is case-insensitive, and only exact tags match — #.rm-hidden and #.rm-highlight are left alone. The set of hidden UIDs is cached for 30 seconds, so a block tagged just now may remain visible for up to that long.
Configuration
Environment Variables
Single Graph Mode
For a single Roam graph, set these in your environment or a .env file:
ROAM_API_TOKEN=your-api-token
ROAM_GRAPH_NAME=your-graph-nameMulti-Graph Mode (v2.0+)
Connect to multiple Roam graphs from a single server instance:
ROAM_GRAPHS='{
"personal": {"token": "token-1", "graph": "personal-db", "memoriesTag": "#[[Personal Memories]]"},
"work": {"token": "token-2", "graph": "work-db", "protected": true, "memoriesTag": "#[[Work Memories]]"},
"research": {"token": "token-3", "graph": "research-db"}
}'
ROAM_DEFAULT_GRAPH=personal
ROAM_SYSTEM_WRITE_KEY=your-secret-keyGraph Configuration Options:
Property | Required | Description |
| Yes | Roam API token for this graph |
| Yes | Graph name/database identifier |
| No | If |
| No | Tag for |
Two kinds of access control (and how they differ)
The server has two independent locks. They're easy to mix up because both are "keys" — here's the plain version (both are optional and off by default):
Bearer token — | Write key — | |
In a phrase | The key to the front door | The latch on a safe inside |
Controls | Who can reach the server at all | Whether a write to a |
Covers | Everything — reads and writes, all graphs | Only writes, and only to graphs marked |
Protects reading? | Yes | No |
When you need it | Only if the server is reachable beyond your own machine (e.g. | Whenever you want a guard against accidental edits to important graphs |
How it's sent | HTTP header: | A |
Think of a house: the bearer token locks the front door (keeps strangers out entirely), and the write key locks a safe inside (even someone already in the house needs it to change what's in the safe). On your own machine bound to 127.0.0.1, the front door faces a wall — you don't need the bearer token there. The write key is still handy locally as an "are you sure?" guard, because Roam has no undo.
So: to mark a graph as needing the write key, set protected: true on it and configure ROAM_SYSTEM_WRITE_KEY; callers then pass a matching write_key for any write to that graph.
⚠️
protecteddoes nothing on your default graph. Writes to whichever graphROAM_DEFAULT_GRAPHnames are always allowed, beforeprotectedis ever consulted — the flag guards the graphs you have to ask for by name, on the reasoning that reaching for a non-default graph is the deliberate act worth confirming. If you want a graph write-guarded, it must not be your default.
Optional:
ROAM_MEMORIES_TAG: Default tag forroam_remember/roam_recall(fallback when per-graphmemoriesTagnot set).HTTP_STREAM_PORT: Port for the HTTP Stream transport (defaults to 8088).--servermode only — stdio mode opens no socket, so this is ignored there.HTTP_STREAM_HOST: Host to bind the HTTP transport to (defaults to127.0.0.1, loopback-only).--servermode only. Set to0.0.0.0to expose on the LAN, and setHTTP_AUTH_TOKENwhen you do.HTTP_AUTH_TOKEN: Optional bearer token that locks the whole HTTP endpoint. Unset = open (fine for loopback). When set, every MCP request must sendAuthorization: Bearer <token>(GET /healthstays open). Use it whenever you bind beyond127.0.0.1. Different fromROAM_SYSTEM_WRITE_KEY— see Two kinds of access control.
Running the Server
1. Default Mode (stdio) Best for local integration (e.g., Claude Desktop, IDE extensions). The MCP client launches the process per session and talks to it over stdin/stdout. No port is opened — nothing about MCP over stdio needs one.
Before 3.1.0 this mode also opened an HTTP listener, and bound it to every interface. If you were using that endpoint, run a
--serverdaemon instead; see below.
npx roam-research-mcp2. Shared Server Mode (--server)
Best for a single long-lived, HTTP-only daemon that multiple MCP clients share — instead of each session spawning its own subprocess. This saves memory and gives clients a stable URL.
HTTP_STREAM_PORT=8088 npx roam-research-mcp --serverOr manage it through the roam CLI, which adds start/stop/status/logs:
roam server start # start the shared daemon in the background
roam server start -H 0.0.0.0 # expose on the LAN (no transport auth!)
roam server status # is it up? version, graphs, active sessions
roam server logs -f # follow the log
roam server stop # stop a CLI-started daemonroam server status works no matter how the daemon was launched (it probes /health), so it also reports a daemon started by a LaunchAgent/systemd unit. State (pidfile + log) lives in ~/.roam/ (override with ROAM_HOME).
The two modes are mutually exclusive, and each opens exactly one transport: stdio mode speaks stdio and binds nothing, --server speaks HTTP and reads no stdin. In --server mode the server:
runs HTTP-only (no stdio transport),
binds the exact
HTTP_STREAM_PORTonHTTP_STREAM_HOSTand exits non-zero if the port is taken (no silent drift — a shared daemon must keep a stable URL),exposes
GET /health→{"status":"ok", ...}for liveness checks.
Point MCP clients at it with an HTTP transport config:
{
"mcpServers": {
"roam-research-mcp": {
"type": "http",
"url": "http://127.0.0.1:8088/mcp"
}
}
}Env vars (tokens, graphs) live with the server process, not the client config.
Securing an exposed server (two layers):
If you bind beyond loopback (-H 0.0.0.0), add the perimeter lock:
HTTP_AUTH_TOKEN=$(openssl rand -hex 32) roam server start -H 0.0.0.0Clients then send the token as a header:
{
"mcpServers": {
"roam-research-mcp": {
"type": "http",
"url": "http://<host>:8088/mcp",
"headers": { "Authorization": "Bearer <token>" }
}
}
}Keep both — they do different jobs (see Two kinds of access control above): the bearer token controls who can connect, the write key only guards writes to protected graphs.
⚠️ The write key is not a substitute for the bearer token. On an exposed server without
HTTP_AUTH_TOKEN, anyone on the network can still read every graph (and write non-protected ones). For anything beyond loopback, setHTTP_AUTH_TOKEN.
Keeping it running (macOS LaunchAgent):
Create ~/Library/LaunchAgents/com.example.roam-mcp.plist with RunAtLoad + KeepAlive, your env vars under EnvironmentVariables, and --server as the last ProgramArguments entry. Keep StandardOutPath/StandardErrorPath on a local path (e.g. ~/Library/Logs/), then:
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.example.roam-mcp.plist
curl -s http://127.0.0.1:8088/health # verify3. Docker
docker run -p 8088:8088 --env-file .env roam-research-mcp --serverConfiguring in LLMs
Claude Desktop / Cline:
Add to your MCP settings file (e.g., ~/Library/Application Support/Claude/claude_desktop_config.json):
Pinning the version.
npx -y roam-research-mcpfetches the latest release every time your client starts the server, so a new major version arrives without warning. Pin the major to decide for yourself when to move:
argsYou get
["-y", "roam-research-mcp"]Latest, always — including the next major
["-y", "roam-research-mcp@3"]3.x only; majors need an edit here
["-y", "roam-research-mcp@3.0.0"]Exactly this build
Pinning the major is the sensible default: you still get fixes and new tools, but a breaking change becomes something you opt into. The examples below stay unpinned to match what most people paste in first.
Single Graph:
{
"mcpServers": {
"roam-research": {
"command": "npx",
"args": ["-y", "roam-research-mcp"],
"env": {
"ROAM_API_TOKEN": "your-token",
"ROAM_GRAPH_NAME": "your-graph"
}
}
}
}Multi-Graph:
{
"mcpServers": {
"roam-research": {
"command": "npx",
"args": ["-y", "roam-research-mcp"],
"env": {
"ROAM_GRAPHS": "{\"personal\":{\"token\":\"token-1\",\"graph\":\"personal-db\",\"memoriesTag\":\"#[[Memories]]\"},\"work\":{\"token\":\"token-2\",\"graph\":\"work-db\",\"protected\":true}}",
"ROAM_DEFAULT_GRAPH": "personal",
"ROAM_SYSTEM_WRITE_KEY": "your-secret-key"
}
}
}
}Query Block Parser (v2.11.0+)
A utility for parsing and executing Roam query blocks programmatically. Converts {{[[query]]: ...}} syntax into Datalog queries.
Supported Clauses
Clause | Syntax | Description |
Page ref |
| Blocks referencing a page |
Block ref |
| Blocks referencing a block |
|
| All conditions must match |
|
| Any condition matches |
|
| Exclude matches |
|
| Date range filter |
|
| Full-text search |
|
| Daily notes pages only |
|
| Created or edited by user |
|
| Created by user |
|
| Edited by user |
Relative Dates
The between clause supports relative dates: today, yesterday, last week, last month, this year, 7 days ago, 2 months ago, etc.
Usage
import { QueryExecutor } from 'roam-research-mcp/query';
const executor = new QueryExecutor(graph);
// Execute a query
const results = await executor.execute(
'{{[[query]]: "My Query" {and: [[Project]] {between: [[last month]] [[today]]}}}}'
);
// Parse without executing (for debugging)
const { name, query } = QueryParser.parseWithName(queryBlock);Utility Functions
import { isQueryBlock, extractQueryBlocks } from 'roam-research-mcp/query';
// Detect if text is a query block
isQueryBlock('{{[[query]]: [[tag]]}}'); // true
// Extract all query blocks from a string
extractQueryBlocks(pageContent); // ['{{[[query]]: ...}}', ...]Support
If this project helps you manage your knowledge base or build cool agents, consider buying me a coffee! It helps keep the updates coming.
License
MIT License - Created by Ian Shen.
Available Tools
25 toolsroam_add_todoA
Add a list of todo items as individual blocks to today's daily page in Roam. Each item becomes its own actionable block with todo status. NOTE on Roam-flavored markdown: For direct linking: use [[link]] syntax. For aliased linking, use alias syntax. Do not concatenate words in links/hashtags - correct: #[[multiple words]] #self-esteem (for typically hyphenated words).
IMPORTANT: call roam_get_guidelines for this graph once per session, and load the Roam Markdown Cheatsheet, before using this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| todos | Yes | List of todo items to add | |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. |
Output Schema
| Name | Required | Description |
|---|---|---|
| success | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark readOnly=false, and the description adds that each item becomes an 'actionable block with todo status', and provides markdown linking rules. This is useful behavioral context beyond what annotations convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The main purpose is stated in a single, direct sentence. The markdown note and IMPORTANT prerequisite are structured with labels and are relevant to correct use. It is slightly long, but each part earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has an output schema, so return values don't need to be explained. The description covers the action, the effect on blocks, markdown syntax details, and the required prerequisite call to roam_get_guidelines, making it complete for an agent to invoke correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already describes all three parameters with 100% coverage, so the baseline is 3. The description adds valuable markdown syntax guidance for the 'todos' parameter text, such as [[link]] and #[[multiple words]], which increases the score.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Add') and resource ('today's daily page'), and clearly states that each item becomes an 'individual block' with todo status. This distinguishes it from sibling tools like roam_create_outline or roam_import_markdown.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It clearly states when to use: adding todos to today's daily page. It also gives an explicit prerequisite: call roam_get_guidelines and load the Roam Markdown Cheatsheet before use. It doesn't explicitly mention alternatives or when not to use, so a 4 is appropriate.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
roam_create_outlineA
Add a structured outline to an existing page or block (by title text or uid), with customizable nesting levels. To create a new page with an outline, use the roam_create_page tool instead. The outline parameter defines new blocks to be created. To nest content under an existing block, provide its UID or exact text in block_text_uid, and ensure the outline array contains only the child blocks with levels relative to that parent. Including the parent block's text in the outline array will create a duplicate block. Best for:
Adding supplementary structured content to existing pages
Creating temporary or working outlines (meeting notes, brainstorms)
Organizing thoughts or research under a specific topic
Breaking down subtopics or components of a larger concept Best for simpler, contiguous hierarchical content. For complex nesting (e.g., tables) or granular control over block placement, consider
roam_process_batch_actionsinstead. API Usage Note: This tool performs verification queries after creation. For large outlines (10+ items) or when rate limits are a concern, consider usingroam_process_batch_actionsinstead to minimize API calls.
IMPORTANT: call roam_get_guidelines for this graph once per session, and load the Roam Markdown Cheatsheet, before using this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| order | No | Insertion position for the first level-1 block relative to existing page/block children. Accepts "first", "last", or a non-negative integer (0-indexed). Default: "last". | |
| outline | Yes | Array of outline items with block text and explicit nesting level. Must be a valid hierarchy: the first item must be level 1, and subsequent levels cannot increase by more than 1 at a time (e.g., a level 3 cannot follow a level 1). | |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. | |
| block_text_uid | No | The text content or UID of the block to nest the outline under (UID is preferred for accuracy). If blank, content is nested directly under the page (or the default daily page if page_title_uid is also blank). | |
| page_title_uid | No | Title or UID of the page (UID is preferred for accuracy). Leave blank to use the default daily page. |
Output Schema
| Name | Required | Description |
|---|---|---|
| success | Yes | |
| page_uid | Yes | |
| parent_uid | Yes | Block the outline was nested under |
| created_blocks | Yes | The created block tree. Objects, not UID strings. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes beyond the annotations (which are all false) by disclosing that the tool 'performs verification queries after creation' and warns about the risk of duplicate blocks if the parent block's text is included in the outline array. It also clarifies that the outline parameter defines new blocks, which is key behavioral context. However, it does not mention idempotency failure behavior or partial-failure details, so it is not fully exhaustive.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is longer than strictly necessary but well-structured with a clear opening sentence, bulleted 'Best for' list, and a separate API Usage Note. Each section adds value without redundancy, and the most essential information is front-loaded. It earns a 4 rather than 5 due to its length, though it remains focused.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (6 parameters, nested outline structure), the description is remarkably complete. It covers purpose, usage alternatives, API rate-limit implications, common use cases, and even a prerequisite instruction (call roam_get_guidelines). The existence of an output schema further reduces the need to describe return values, so there are no significant gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already provides 100% coverage of parameter descriptions, so the baseline is 3. The description adds meaningful semantic nuances beyond the schema, particularly for the `outline` parameter: it explains that levels are relative to the parent block, and warns against including the parent block's text. This extra guidance helps prevent common usage errors.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: 'Add a structured outline to an existing page or block (by title text or uid), with customizable nesting levels.' It distinguishes itself from the sibling tool `roam_create_page` by explicitly noting that tool should be used for creating new pages with outlines. The verb-resource pairing is specific and unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit guidance on when to use this tool vs alternatives: 'To create a new page with an outline, use the `roam_create_page` tool instead' and 'For complex nesting (e.g., tables) or granular control over block placement, consider `roam_process_batch_actions` instead.' It also includes a 'Best for' list and a clear exclusion criterion, making the decision process straightforward.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
roam_create_pageA
Create a new standalone page in Roam with optional content, including structured outlines and tables, using explicit nesting levels and headings (H1-H3). This is the preferred method for creating a new page with an outline in a single step. Best for:
Creating foundational concept pages that other pages will link to/from
Establishing new topic areas that need their own namespace
Setting up reference materials or documentation
Making permanent collections of information
Creating pages with mixed text and table content in one call. Efficiency Tip: This tool batches page and content creation efficiently. For adding content to existing pages, use
roam_process_batch_actionsinstead.
IMPORTANT: call roam_get_guidelines for this graph once per session, and load the Roam Markdown Cheatsheet, before using this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| title | Yes | Title of the new page | |
| content | No | Initial content for the page as an array of content items. Each item can be a text block or a table. Text blocks use {text, level, heading?}. Tables use {type: "table", headers, rows}. Items are processed in order. | |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. |
Output Schema
| Name | Required | Description |
|---|---|---|
| success | Yes | |
| page_uid | Yes | UID of the created page |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations indicate a write operation (readOnlyHint=false) and no idempotency/destructive hints. The description adds context beyond annotations by explaining the tool 'batches page and content creation efficiently' and requiring the user to consult guidelines beforehand. However, it does not disclose edge-case behaviors such as what happens if the page already exists, which would be useful for a creation tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured with a clear opening sentence, a 'Best for' list, an efficiency tip, and an important prerequisite note. It is slightly longer than necessary (the best-for list has some overlap), but every section earns its place and it is front-loaded with the core purpose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's moderate complexity (nested content arrays, table support, headings) and the detailed input schema, the description provides sufficient context: it explains the structure of content, highlights the ability to mix text and tables, and gives usage boundaries. It could mention conflict behavior for existing pages, but overall it is quite complete for a creation tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has 100% parameter description coverage, so the schema carries the burden. The description restates general capabilities (outlines, tables, headings) but does not add specific parameter-level semantics beyond what the schema already explains. Thus the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function: 'Create a new standalone page in Roam with optional content, including structured outlines and tables, using explicit nesting levels and headings (H1-H3).' It also distinguishes itself from siblings by noting it is 'the preferred method for creating a new page with an outline in a single step' and contrasts with roam_process_batch_actions for adding content to existing pages.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit when-to-use guidance through a 'Best for:' list covering foundational pages, new namespaces, reference materials, and permanent collections. It also gives an exclusion: 'For adding content to existing pages, use roam_process_batch_actions instead,' and includes a prerequisite instruction to call roam_get_guidelines and load the Markdown Cheatsheet before using.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
roam_create_tableA
Create a table in Roam with specified headers and rows. This tool abstracts the complex nested structure that Roam tables require, making it much easier to create properly formatted tables.
Why use this tool:
Roam tables require precise nested block structures that are error-prone to create manually
Automatically handles the {{[[table]]}} container and nested column structure
Validates row/column consistency before execution
Converts empty cells to spaces (required by Roam)
Example: A table with headers ["", "Column A", "Column B"] and rows [{label: "Row 1", cells: ["A1", "B1"]}] creates a 2x3 table.
IMPORTANT: call roam_get_guidelines for this graph once per session, and load the Roam Markdown Cheatsheet, before using this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| rows | Yes | Data rows for the table. Each row has a label (first column) and cells (remaining columns). | |
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| order | No | Optional: Position under the parent. Can be a number (0-based) or "first"/"last". Defaults to "last". | last |
| headers | Yes | Column headers for the table. The first header is typically empty (for the row label column). Example: ["", "Option A", "Option B"] | |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. | |
| parent_uid | Yes | The UID of the parent block or page where the table should be created. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present only when success is false. |
| success | Yes | |
| uid_map | No | Placeholder name → generated UID. Present only on success. |
| table_uid | No | |
| actions_attempted | No | |
| validation_passed | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations indicate a write operation (readOnlyHint: false) but provide limited safety info. The description adds valuable context: it automatically handles the {{[[table]]}} container, validates row/column consistency, and converts empty cells to spaces. It also mentions the session prerequisite, giving the agent important operational details beyond the structured annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is well-structured and front-loaded with the core action. The 'Why use this tool' bullets are concise and purposeful, the example is helpful, and the IMPORTANT note is relevant. No sentence is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity (6 params), the description provides purpose, rationale, an example, and a prerequisite. The output schema exists, so return-value details are not necessary. It lacks explicit edge-case handling but is complete enough for an agent to use effectively.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all parameters. The description's example adds a concrete illustration of how headers and rows map to a table, but it does not add significant new semantics beyond what the schema provides. Baseline of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Create a table in Roam with specified headers and rows,' which is a specific verb+resource statement that clearly distinguishes this tool from siblings like roam_create_outline or roam_create_page. It also explains the tool abstracts Roam's complex nested table structure, reinforcing its unique purpose.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The 'Why use this tool' section explicitly states when this tool is beneficial (avoiding error-prone manual creation, handling table containers, validating consistency). It also provides a clear prerequisite: call roam_get_guidelines and load the Markdown Cheatsheet before use. However, it does not explicitly name alternatives or state when not to use it, though the context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
roam_datomic_queryARead-onlyIdempotent
Execute a custom Datomic query on the Roam graph for advanced data retrieval beyond the available search tools. This provides direct access to Roam's query engine. Note: Roam graph is case-sensitive.
Optimal Use Cases for roam_datomic_query:
Advanced Filtering (including Regex): Use for scenarios requiring complex filtering, including regex matching on results post-query, which Datalog does not natively support for all data types. It can fetch broader results for client-side post-processing.
Highly Complex Boolean Logic: Ideal for intricate combinations of "AND", "OR", and "NOT" conditions across multiple terms or attributes.
Arbitrary Sorting Criteria: The go-to for highly customized sorting needs beyond default options.
Proximity Search: For advanced search capabilities involving proximity, which are difficult to implement efficiently with simpler tools.
List of some of Roam's data model Namespaces and Attributes: ancestor (descendants), attrs (lookup), block (children, heading, open, order, page, parents, props, refs, string, text-align, uid), children (view-type), create (email, time), descendant (ancestors), edit (email, seen-by, time), entity (attrs), log (id), node (title), page (uid, title), refs (text). Predicates (clojure.string/includes?, clojure.string/starts-with?, clojure.string/ends-with?, <, >, <=, >=, =, not=, !=). Aggregates (distinct, count, sum, max, min, avg, limit). Tips: Use :block/parents for all ancestor levels, :block/children for direct descendants only; combine clojure.string for complex matching, use distinct to deduplicate, leverage Pull patterns for hierarchies, handle case-sensitivity carefully, and chain ancestry rules for multi-level queries.
IMPORTANT: call roam_get_guidelines for this graph once per session before using this tool, reads included — conventions change how results are read, not just written.
| Name | Required | Description | Default |
|---|---|---|---|
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| query | Yes | The Datomic query to execute (in Datalog syntax). Example: `[:find ?block-string :where [?block :block/string ?block-string] (or [(clojure.string/includes? ?block-string "hypnosis")] [(clojure.string/includes? ?block-string "trance")] [(clojure.string/includes? ?block-string "suggestion")]) :limit 25]` | |
| inputs | No | Optional array of input parameters for the query | |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. | |
| regexFlags | No | Optional: Flags for the regex filter (e.g., "i" for case-insensitive, "g" for global). | |
| regexFilter | No | Optional: A regex pattern to filter the results client-side after the Datomic query. Applied to JSON.stringify(result) or specific fields if regexTargetField is provided. | |
| regexTargetField | No | Optional: An array of field paths (e.g., ["block_string", "page_title"]) within each Datomic result object to apply the regex filter to. If not provided, the regex is applied to the stringified full result. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description adds substantial behavioral context beyond annotations: it notes case-sensitivity, explains that regex filtering is applied client-side after the query, and warns that graph conventions affect results. Annotations already declare readOnly, idempotent, and non-destructive, and the description does not contradict them; it enriches the agent's understanding of side effects and result interpretation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is lengthy but well-structured with sections (Optimal Use Cases, data model, predicates, tips) and all content is relevant to using the tool effectively. It front-loads the purpose and uses bold headers for scannability, though a slight trim could make it more concise.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex Datomic query tool, the description covers most essential context: syntax, use cases, data model, predicates, and a required guideline call. However, it does not describe the return format beyond mentioning client-side filtering, and could benefit from noting potential errors or performance implications, so it isn't fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds significant value by providing an example Datalog query, listing predicates and aggregates, and explaining the data model namespaces. This goes beyond the schema's parameter descriptions and helps the agent construct correct queries, especially for the 'query' parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool executes custom Datomic queries on the Roam graph for advanced data retrieval, explicitly distinguishing it from search tools. It further lists specific advanced use cases (regex filtering, complex boolean logic, arbitrary sorting, proximity search), making the purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description has an 'Optimal Use Cases' section that clearly specifies when to use this tool (advanced filtering, complex boolean logic, etc.), and the opening sentence implies it should be used beyond the available search tools. It also mandates calling roam_get_guidelines before use, but doesn't explicitly name alternative tools for contrast or state when not to use it, so it falls short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
roam_fetch_blockARead-onlyIdempotent
Fetch a block by its UID with optional children (down to a specified depth) and/or ancestors (up to page root). Returns the block's UID, text, order, children array, and optionally an ancestors array with the chain to the page root.
IMPORTANT: call roam_get_guidelines for this graph once per session before using this tool, reads included — conventions change how results are read, not just written.
| Name | Required | Description | Default |
|---|---|---|---|
| depth | No | Optional: The number of levels deep to fetch children. Defaults to 4. Set to 0 to skip children. | |
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| block_uid | Yes | The UID of the block to fetch. | |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. | |
| include_ancestors | No | Optional: Include the ancestor chain from the block up to the page root. Each ancestor includes uid, string/title, and depth. Defaults to false. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already mark this as read-only and idempotent, and the description aligns with that by stating it 'fetches' and 'returns' data. It adds valuable behavioral context beyond the annotations: the graph's conventions can change read semantics, and the response includes a specific ancestors array shape when requested.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two short paragraphs with no filler. The first sentence states the core function and return values, and the second conveys an essential prerequisite in an 'IMPORTANT' callout. Every sentence earns its place and the structure is immediately scannable.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description compensates by naming the exact return fields. The mandatory prerequisite for roam_get_guidelines is highlighted, and all parameters are covered by the schema. For a read-only fetch tool with clear sibling context, this is fully adequate.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the parameter descriptions already document depth, graph, block_uid, write_key, and include_ancestors. The description adds minimal extra semantic value beyond restating those concepts in prose (e.g., 'children down to a specified depth' maps to depth), but it does not introduce information absent from the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description begins with a specific verb and resource: 'Fetch a block by its UID' with optional children and ancestors, which clearly distinguishes it from page-level fetch siblings like roam_fetch_page_by_title and roam_fetch_page_full_view. It also enumerates the return fields, reinforcing what the tool does.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly instructs the agent to call roam_get_guidelines once per session before using the tool, including for reads, and explains that conventions affect how results are read. It does not explicitly name alternative tools or provide exclusion criteria, but the prerequisite and context are clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
roam_fetch_page_by_titleARead-onlyIdempotent
Fetch page by title. Returns content in the specified format.
IMPORTANT: call roam_get_guidelines for this graph once per session before using this tool, reads included — conventions change how results are read, not just written.
| Name | Required | Description | Default |
|---|---|---|---|
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| title | Yes | Title of the page. For date pages, use ordinal date formats such as January 2nd, 2025 | |
| format | No | Format output as markdown, JSON, or structure. 'markdown' returns readable string; 'raw' returns full JSON with nested blocks; 'structure' returns a flattened list (uid, order, text, depth, parent_uid) for locating blocks to update. In 'structure', `text` is a PREVIEW cut at 80 characters — an entry marked `truncated: true` is a fragment, and writing it back would replace the block with its own opening. Use it to find the uid, then fetch that block with roam_fetch_block before editing its text. | raw |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and destructiveHint=false, so the safety profile is covered. The description adds behavioral context by warning that graph conventions affect how results are read, which is not captured by annotations or schema. This is useful and complements the structured metadata.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is extremely concise: two sentences achieve the core purpose and add a critical usage warning. There is no filler or redundant explanation. The important guideline is highlighted with 'IMPORTANT' and placed prominently, making it effective.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only fetch tool with rich schema descriptions and annotations, the description is sufficiently complete. It covers the core function, return format note, and the prerequisite guideline call. There is no output schema, but the format parameter description in the schema explains expected outputs. Minor gaps like behavior on missing pages are acceptable for this tool type.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has 100% coverage with detailed descriptions for all parameters, including the format enum and its behavior. The description adds no additional parameter-specific meaning beyond what the schema provides, so the baseline score of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb 'Fetch' and the resource 'page by title', making the tool's purpose unambiguous. It is specific enough to distinguish from sibling tools like roam_fetch_page_full_view or roam_fetch_block, which operate on different inputs or views.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly instructs the agent to call roam_get_guidelines before every session, even for reads, adding important prerequisite guidance. It does not mention specific alternative tools or exclusion criteria, but the context of use is clear from the verb and resource.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
roam_fetch_page_full_viewARead-onlyIdempotent
Fetch a complete page view that mirrors what Roam Research shows in its UI: the page's own content, plus all linked references (backlinks) grouped by source page, each with their ancestor breadcrumb context and children expanded to the specified depth. Use this when you need the full picture of a page — both what is written on it and everything else in the graph that references it.
IMPORTANT: call roam_get_guidelines for this graph once per session before using this tool, reads included — conventions change how results are read, not just written.
| Name | Required | Description | Default |
|---|---|---|---|
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| title | Yes | Title of the page to fetch. For date pages use ordinal format e.g. "January 2nd, 2025". | |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. | |
| children_depth | No | How many levels deep to expand children of each referring block. Defaults to 4. | |
| max_references | No | Maximum number of linked references to return. Prevents timeouts on heavily-referenced pages (e.g. TODO, common tags). Defaults to 200. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and destructiveHint. The description adds behavioral context: mirrors Roam UI, groups backlinks by source page, includes breadcrumbs, and mentions max_references to prevent timeouts. No contradictions with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences of purpose and usage, plus one important prerequisite note. Every sentence earns its place, front-loaded with the core purpose. No fluff or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a complex read tool with no output schema, the description well explains the response composition: page content, grouped backlinks, breadcrumbs, and child expansion depth. It also includes a session-level prerequisite. Minor gap: no explicit mention of pagination beyond max_references, but that is partially covered in schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so parameters are already fully documented. The description's references to 'children expanded to the specified depth' and 'max_references' merely restate what the schema provides without adding new semantic meaning.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description starts with 'Fetch a complete page view' which clearly identifies the verb, resource, and scope. It distinguishes itself from sibling tools by specifying it includes linked references grouped by source page with breadcrumb context, unlike a simple fetch_page_by_title.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit use case: 'Use this when you need the full picture of a page'. Also instructs to call roam_get_guidelines before use, which is a prerequisite. Does not explicitly name alternatives to exclude, but gives clear context for when to choose this tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
roam_find_pages_modified_todayARead-onlyIdempotent
Find pages that have been modified today (since midnight), with pagination and sorting options.
IMPORTANT: call roam_get_guidelines for this graph once per session before using this tool, reads included — conventions change how results are read, not just written.
| Name | Required | Description | Default |
|---|---|---|---|
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| limit | No | The maximum number of pages to retrieve (default: 50). Use -1 for no limit, but be aware that very large result sets can impact performance. | |
| offset | No | The number of pages to skip before returning matches. Useful for pagination. Defaults to 0. | |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. | |
| sort_order | No | Sort order for pages based on modification date. "desc" for most recent first, "asc" for oldest first. | desc |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (read-only, idempotent), the description adds a behavioral caveat: conventions change how results are read, and it requires calling roam_get_guidelines. This enriches the agent's understanding without contradicting annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two impactful sentences: the main action and an important prerequisite. The description is front-loaded with the core purpose and wastes no words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the read-only nature, schema coverage, and annotations, the description covers the core function, the required guideline call, and a behavioral caveat. It lacks explicit return format or timezone clarification for 'midnight', but these are minor gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so parameters (limit, offset, sort_order, graph, write_key) are already fully described in the schema. The description only mentions pagination and sorting generically without adding new parameter-specific meaning, keeping the baseline at 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the action ('Find') and the resource ('pages modified today'), with a precise time scope ('since midnight'). It is easily distinguished from sibling tools like roam_search_by_date or roam_fetch_page_by_title.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides explicit context for when to use the tool (for pages modified today) and a critical prerequisite (call roam_get_guidelines once per session). However, it does not mention alternatives or exclusions, so it falls short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
roam_get_guidelinesARead-onlyIdempotent
Retrieve this graph's user-defined agent conventions, read from the [[roam/agent guidelines]] page inside the graph (configurable per graph). These are the user's own rules — how they tag, how they name and namespace pages, what to never do, how they want your voice attributed.
Also returns roamSyntax: the rules whose violation destroys content — whole-page rewrites that delete, truncated previews written back as content, retyped block references, and the syntax that differs from standard markdown. These are returned on every call, including when the graph has no guidelines page, and they hold regardless of what the conventions say.
Call this ONCE per graph per session, before other tools, INCLUDING for reads: conventions change how results should be interpreted and presented, not just how content is written. Returns today's daily note title as orientation.
Distinct from roam_markdown_cheatsheet, which is the complete syntax reference — components, queries, embeds, tool selection. Call that when you need to look something up; this one you need before writing at all. Returns exists:false rather than failing when no page has been created.
| Name | Required | Description | Default |
|---|---|---|---|
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, openWorldHint=false, idempotentHint=true, destructiveHint=false. The description adds valuable context beyond these: it returns `roamSyntax` on every call, returns `exists:false` instead of failing when no page exists, returns today's daily note title, and explains that conventions affect interpretation/presentation, not just writing. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is longer than the absolute minimum but well-structured: purpose, special return value, usage instruction, sibling differentiation, and existence behavior are each in their own sentence/paragraph. Every sentence earns its place, though it could be tightened slightly without losing meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Even without an output schema, the description explains what is returned (user conventions, roamSyntax, daily note title, exists:false), why it must be called before other tools, and the behavior when no guidelines page exists. It fully covers the operational context a read tool with no output schema needs.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema provides 100% coverage for both parameters (`graph` and `write_key`) with descriptions. The description adds no new parameter-specific meaning beyond noting the guidelines page is 'configurable per graph', which is already implied by the schema. Baseline 3 is appropriate since the schema does the heavy lifting.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific verb and resource: 'Retrieve this graph's user-defined agent conventions', and names the source page `[[roam/agent guidelines]]`. It also distinguishes itself from the sibling `roam_markdown_cheatsheet` by stating what each is for, eliminating ambiguity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly instructs 'Call this ONCE per graph per session, before other tools, INCLUDING for reads' and contrasts with the alternative: 'Call that when you need to look something up; this one you need before writing at all.' This gives clear when-to-use and when-not-to-use guidance with a direct sibling reference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
roam_get_subpagesARead-onlyIdempotent
Fetch all sub-pages (namespace children) of a given page prefix. Matches by page title prefix — pages titled "Prefix/Something" are sub-pages of "Prefix" and appear in the Hierarchy section of that page. This is namespace/title-prefix matching, distinct from roam_search_hierarchy which traverses block parent/child relationships. Optionally filter to only sub-pages containing a specific tag (e.g. filter active projects with filter_tag="active"), and optionally include each sub-page's full block content.
IMPORTANT: call roam_get_guidelines for this graph once per session before using this tool, reads included — conventions change how results are read, not just written.
| Name | Required | Description | Default |
|---|---|---|---|
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| prefix | Yes | The namespace prefix to search under, e.g. "Project", "Zettel", "Framework". The trailing "/" is added automatically if omitted. | |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. | |
| filter_tag | No | Optional. Only return sub-pages that contain at least one block referencing this tag. Matches both #tag and [[tag]] usage. Example: "active" to find active projects. | |
| include_content | No | If true, include each sub-page's block content in the output. Defaults to false (list only). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With annotations already declaring read-only/idempotent, the description adds meaningful behavioral details: it explains that the trailing slash is added automatically, that filter_tag matches both #tag and [[tag]] usage, and that include_content controls whether full block content is returned. The IMPORTANT note about conventions affecting how results are read adds extra context beyond the annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three sentences plus a focused IMPORTANT note. It front-loads the core purpose, uses no filler, and each sentence adds a distinct piece of information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the tool's behavior, prerequisites, and optional parameters. Since there is no output schema, it would be helpful to state the exact return shape, but the description implies a list of sub-pages and mentions content inclusion for include_content. Overall it's sufficiently complete for a read-only list tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema covers all 5 parameters with detailed descriptions, so the baseline is 3. The description enhances the meaning of 'prefix' by explaining the namespace/title-prefix matching convention and the hierarchy section, which aids correct parameter use.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Fetch all sub-pages (namespace children) of a given page prefix,' which is a specific verb+resource. It further distinguishes itself from roam_search_hierarchy (block parent/child traversal) and clarifies the title-prefix matching rule.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly names an alternative tool: 'distinct from roam_search_hierarchy which traverses block parent/child relationships.' It also mandates a prerequisite: 'call roam_get_guidelines for this graph once per session before using this tool,' including for reads.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
roam_import_markdownA
Import nested markdown content into Roam under a specific block. Can locate the parent block by UID (preferred) or by exact string match within a specific page. If a parent_string is provided and the block does not exist, it will be created. Returns a nested structure of the created blocks.
API Usage Note: This tool fetches the full nested structure after import for verification. For large imports or when rate limits are a concern, consider using roam_process_batch_actions with pre-structured actions instead.
IMPORTANT: call roam_get_guidelines for this graph once per session, and load the Roam Markdown Cheatsheet, before using this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| order | No | Optional: Where to add the content under the parent ("first" or "last"). Defaults to "first". | first |
| content | Yes | Nested markdown content to import | |
| page_uid | No | Optional: UID of the page containing the parent block (preferred for accuracy). | |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. | |
| page_title | No | Optional: Title of the page containing the parent block (used if page_uid is not provided). | |
| parent_uid | No | Optional: UID of the parent block to add content under (preferred for accuracy). | |
| parent_string | No | Optional: Exact string content of an existing parent block to add content under (used if parent_uid is not provided; requires page_uid or page_title). If the block does not exist, it will be created. |
Output Schema
| Name | Required | Description |
|---|---|---|
| success | Yes | |
| page_uid | Yes | |
| parent_uid | Yes | |
| created_blocks | Yes | The created block tree. Objects, not UID strings. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations (write, non-destructive), the description discloses two important behaviors: it auto-creates a missing parent block when `parent_string` is used, and it fetches the full nested structure post-import for verification, adding rate-limit context. This is valuable extra transparency, though it does not detail all side effects (e.g., how existing content is affected).
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is appropriately sized and front-loaded with the main purpose. It uses a clear structure with an API usage note and an important prerequisite. While slightly longer due to the usage warnings, every sentence serves a purpose and there is no fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For an 8-parameter tool with a full output schema, the description covers the core behavior, parameter lookup logic, rate-limit implications, and required preconditions. It does not explicitly cover error cases or edge conditions, but the schema and output schema fill many gaps, making it reasonably complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3. The description adds meaning by explaining the preference order (parent_uid/page_uid over parent_string) and clarifying that `parent_string` will create a new block if it doesn't exist. This goes beyond the schema definitions and helps agents choose the right parameters.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Import nested markdown content into Roam under a specific block' with a specific verb, resource, and location. It distinguishes itself from siblings by detailing how the parent block is located (UID or exact string match) and refers to the alternative tool `roam_process_batch_actions` for large imports.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides explicit usage guidance: UID is preferred over string match, and it names an alternative for large imports or rate-limit concerns. It also instructs to call `roam_get_guidelines` and load the Markdown Cheatsheet before use, covering prerequisites and when-not-to-use scenarios.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
roam_markdown_cheatsheetARead-onlyIdempotent
Provides the comprehensive Roam syntax reference. Covers: formatting, links & references (page refs, block refs, embeds including embed-children and embed-path), tags, dates, tasks, callouts, attributes, queries (native {{query}} with its clause rules and page-ref inheritance, plus :q Datalog tables with built-in rules), tables, kanban, mermaid diagrams (with theme support), advanced components (dropdowns, tooltips, templates, document mode, word-count), CSS tags (#.rm-E, #.rm-hide, etc.), anti-patterns, tool selection guide, and API efficiency tips.
IMPORTANT: Always load this cheatsheet before creating or updating Roam content. It prevents common syntax errors and guides tool selection.
IMPORTANT: call roam_get_guidelines for this graph once per session before using this tool, reads included — conventions change how results are read, not just written.
| Name | Required | Description | Default |
|---|---|---|---|
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, covering safety. The description adds behavioral context by noting it 'prevents common syntax errors' and 'guides tool selection,' which goes beyond annotations. It doesn't describe the output format, but for a read-only reference the annotations carry the main safety burden.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but front-loaded with the main purpose and then organized into a categorized list. Each sentence adds value, and the IMPORTANT warnings are clearly highlighted. It is appropriately detailed for a comprehensive reference tool, though slightly verbose.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only reference tool with no output schema, the description is complete: it lists the full scope of content covered, provides usage prerequisites, and includes warnings about guidelines. It explains why to load it and mentions the companion function. No significant information is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, as both parameters (graph, write_key) have descriptions in the schema. The tool description itself does not mention parameters, but because the schema fully documents them, the baseline is 3. No additional parameter semantics are needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a clear verb+resource: 'Provides the comprehensive Roam syntax reference.' It enumerates a detailed list of covered topics (formatting, links, queries, diagrams, etc.), which distinguishes it from sibling tools like roam_create_table or roam_add_todo. The purpose is unmistakable and specific.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly instructs 'Always load this cheatsheet before creating or updating Roam content' and explains it prevents syntax errors and guides tool selection. It also names a prerequisite: 'call roam_get_guidelines for this graph once per session before using this tool.' This is clear when-to-use guidance with an alternative tool mentioned.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
roam_move_blockADestructiveIdempotent
Move a block to a new location (different parent or position). This is a convenience wrapper around roam_process_batch_actions for single block moves.
IMPORTANT: call roam_get_guidelines for this graph once per session before using this tool, reads included — conventions change how results are read, not just written.
| Name | Required | Description | Default |
|---|---|---|---|
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| order | No | Position under the new parent. Can be a number (0-based index) or "first"/"last". Defaults to "last". | last |
| block_uid | Yes | The UID of the block to move | |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. | |
| parent_uid | Yes | The UID of the new parent block or page |
Output Schema
| Name | Required | Description |
|---|---|---|
| order | Yes | |
| success | Yes | |
| block_uid | Yes | |
| new_parent_uid | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=false and destructiveHint=true, so the description does not need to restate these. It adds context about being a wrapper around batch actions and the importance of graph-specific guidelines. However, it does not disclose additional behavioral details such as whether the move is atomic, if child blocks are moved recursively, or the exact impact on references. With annotations covering the safety profile, a 3 is appropriate.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is three sentences, each earning its place. The first sentence states the action, the second frames it as a wrapper alternative, and the third provides a critical workflow prerequisite. It is front-loaded and free of fluff.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's moderate complexity (5 parameters, 2 required, output schema present), the description covers the essential context: what the tool does, how it relates to sibling tools, and the required pre-use step. The output schema handles return values, and annotations handle safety traits, so the description is complete for an agent to select and invoke correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has 100% description coverage for all five parameters, so the description does not need to explain each parameter. It does add a high-level semantic cue ('different parent or position') that maps to parent_uid and order, but this is already explicit in the schema. The description adds marginal value over the schema, matching the baseline of 3.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Move a block to a new location' which is a specific verb+resource action, and immediately clarifies the scope: 'different parent or position'. It also distinguishes itself from the sibling tool by explicitly calling itself a 'convenience wrapper around roam_process_batch_actions for single block moves', making its purpose unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly indicates when to use this tool—for single block moves—by positioning it as a wrapper around the batch action tool, implying batch actions would be used for multiple moves. It also includes an explicit prerequisite: 'call roam_get_guidelines for this graph once per session', with a brief rationale. This is direct usage guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
roam_process_batch_actionsADestructive
RATE LIMIT EFFICIENT: This is the most API-efficient tool for multiple block operations. Combine all create/update/delete operations into a single call whenever possible. For intensive page updates or revisions, prefer this tool over multiple sequential calls.
Executes a sequence of low-level block actions (create, update, move, delete) in a single, non-transactional batch. Actions are executed in the provided order.
UID Placeholders for Nested Blocks: Use {{uid:name}} syntax for parent-child references within the same batch. The server generates proper random UIDs and returns a uid_map showing placeholder→UID mappings. Example: { uid: "{{uid:parent1}}", string: "Parent" } then { location: { "parent-uid": "{{uid:parent1}}" }, string: "Child" }. Response includes { success: true, uid_map: { "parent1": "Xk7mN2pQ9" } }.
For actions on existing blocks, a valid block UID is required. Note: Roam-flavored markdown, including block embedding with ((UID)) syntax, is supported within the string property for create-block and update-block actions. For actions on existing blocks or within a specific page context, it is often necessary to first obtain valid page or block UIDs. Tools like roam_fetch_page_by_title or other search tools can be used to retrieve these UIDs before executing batch actions. For simpler, sequential outlines, roam_create_outline is often more suitable.
IMPORTANT: call roam_get_guidelines for this graph once per session, and load the Roam Markdown Cheatsheet, before using this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| actions | Yes | An array of action objects to execute in order. | |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. |
Output Schema
| Name | Required | Description |
|---|---|---|
| error | No | Present only when success is false. |
| success | Yes | |
| uid_map | No | Placeholder name → generated UID. Present only on success. |
| actions_attempted | No | |
| validation_passed | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes beyond the annotations by disclosing non-transactional execution, ordered actions, UID placeholder behavior with uid_map responses, and the requirement for valid block UIDs. It also notes that existing-block actions often need page/block UIDs first. The destructiveHint annotation is consistent with the write operations described; no contradiction.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is long but well-structured with bold section labels and examples. It contains some repetition (e.g., 'For actions on existing blocks' appears twice), but each sentence contributes either usage guidance, parameter enrichment, or prerequisite context. The front-loaded rate-limit note is practical.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's complexity and the presence of an output schema (indicated but not shown), the description covers the essentials: what the tool does, when to use it, prerequisites for UIDs, nested-block placeholder mechanics, response shape, and the guideline prerequisite. It could mention failure semantics more explicitly, but the non-transactional note covers the key risk.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3. The description adds meaningful semantics beyond the schema by explaining the {{uid:name}} placeholder syntax with a concrete example, describing the structure of the uid_map response, and noting that Roam-flavored markdown including block embeds is supported in the 'string' property.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a clear verb-resource pairing: 'Executes a sequence of low-level block actions (create, update, move, delete) in a single, non-transactional batch.' It also brands itself as 'the most API-efficient tool for multiple block operations,' which distinguishes it from siblings like roam_create_outline and roam_move_block.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicit usage guidance is provided: 'Combine all create/update/delete operations into a single call whenever possible' and 'For simpler, sequential outlines, roam_create_outline is often more suitable.' It also directs users to call roam_get_guidelines once per session and to use search tools like roam_fetch_page_by_title to obtain UIDs.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
roam_recallARead-onlyIdempotent
Retrieve all stored memories on page titled ROAM_MEMORIES_TAG, or tagged block content with the same name. Returns a combined, deduplicated list of memories. Optionally filter blocks with a specific tag and sort by creation date.
IMPORTANT: call roam_get_guidelines for this graph once per session before using this tool, reads included — conventions change how results are read, not just written.
| Name | Required | Description | Default |
|---|---|---|---|
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| sort_by | No | Sort order for memories based on creation date | newest |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. | |
| filter_tag | No | Include only memories with a specific filter tag. For single word tags use format "tag", for multi-word tags use format "tag word" (without brackets) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and idempotentHint, so the description only needs to add context. It adds that results are deduplicated and that 'conventions change how results are read, not just written,' which is a valuable behavioral caveat. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two paragraphs; the first is a single dense sentence covering core behavior, the second is a necessary warning. It is efficient with no redundant content, though the first sentence is long and complex.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the dual retrieval source, deduplication, optional filtering/sorting, and a per-session prerequisite. It also states the return type ('combined, deduplicated list'). For a simple read-only tool with good annotations, this is adequate, though it could clarify the exact format of the returned list.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, with all four parameters described. The description mentions filter_tag and sort_by but does not add new semantic detail beyond the schema, so the baseline score of 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the primary function: 'Retrieve all stored memories on page titled ROAM_MEMORIES_TAG, or tagged block content with the same name.' It specifies the resource (memories), the source (page or tags), and the output (deduplicated list). This distinguishes it from sibling search tools by focusing on memory recall.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly mandates calling roam_get_guidelines before using this tool, which is a clear prerequisite. However, it does not explicitly contrast with alternative tools like roam_search_for_tag, though the memory-specific scope implies the intended use case.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
roam_rememberA
Add a memory or piece of information to remember, stored on the daily page with ROAM_MEMORIES_TAG tag and optional categories (unless include_memories_tag is false). NOTE on Roam-flavored markdown: For direct linking: use [[link]] syntax. For aliased linking, use alias syntax. Do not concatenate words in links/hashtags - correct: #[[multiple words]] #self-esteem (for typically hyphenated words).
IMPORTANT: call roam_get_guidelines for this graph once per session, and load the Roam Markdown Cheatsheet, before using this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| memory | Yes | The memory detail or information to remember. Add tags in `categories`. | |
| heading | No | Optional heading text to nest the memory under (e.g., "Memories" or "## LLM Memories"). If the heading does not exist on the daily page, it will be created. Ignored if parent_uid is provided. | |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. | |
| categories | No | Optional categories to tag the memory with (will be converted to Roam tags). Do not duplicate tags added in `memory` parameter. | |
| parent_uid | No | Optional UID of a specific block to nest the memory under. Takes precedence over heading parameter. | |
| include_memories_tag | No | Whether to append the ROAM_MEMORIES_TAG tag to the memory block. |
Output Schema
| Name | Required | Description |
|---|---|---|
| success | Yes | |
| block_uid | No | UID of the stored memory block |
| parent_uid | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations are all false, providing no behavioral safety hints (e.g., readOnlyHint=false implies a write, but no further detail). The description compensates by disclosing that the tool writes to the daily page, applies a tag and optional categories, and includes a markdown syntax warning to avoid formatting errors. It does not mention permission requirements or rate limits, but for a write tool with no other annotation coverage, it adds substantial behavioral context.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description opens with a clear one-sentence purpose, followed by a detailed markdown note and a prerequisite warning. While the markdown note is verbose, it provides essential usage guidance. The structure is front-loaded and the additional paragraphs earn their place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description covers the core purpose, storage location, tag behavior, and prerequisite calls, making it sufficient for an agent to invoke the tool correctly. It does not mention heading or parent_uid options, but these are fully described in the schema. Given the high schema coverage and output schema, the description is adequately complete, though it could briefly note that headings/parent_uid can organize memories.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all parameters. The description adds value by explaining the storage behavior (daily page + tag), the optionality of categories, and a detailed markdown note relevant to formatting memory content and categories. However, the phrase '(unless include_memories_tag is false)' is ambiguous, potentially implying categories are also omitted when the tag is disabled, which conflicts with the schema's separate handling.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action ('Add a memory or piece of information to remember') and specifies the storage location (daily page with ROAM_MEMORIES_TAG tag). This distinguishes it from siblings like roam_add_todo (adds tasks) and roam_recall (retrieves memories).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides clear context for use (storing memories) but does not explicitly state when to use this tool versus alternatives. It includes a prerequisite instruction to call roam_get_guidelines and load the markdown cheatsheet, but lacks exclusionary guidance such as 'use roam_add_todo for tasks' or 'use roam_recall to fetch memories.'
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
roam_rename_pageADestructiveIdempotent
Rename a page by changing its title. Identifies the page by current title or UID.
IMPORTANT: call roam_get_guidelines for this graph once per session before using this tool, reads included — conventions change how results are read, not just written.
| Name | Required | Description | Default |
|---|---|---|---|
| uid | No | UID of the page to rename (use this OR old_title, not both) | |
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| new_title | Yes | New title for the page | |
| old_title | No | Current title of the page to rename (use this OR uid, not both) | |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. |
Output Schema
| Name | Required | Description |
|---|---|---|
| message | Yes | |
| success | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare this tool destructive and idempotent. The description adds useful context beyond annotations by requiring a call to roam_get_guidelines and noting that conventions affect reads as well as writes. This provides behavioral nuance not captured in the structured fields.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is brief (two sentences) and front-loaded with the core purpose. The second sentence conveys a critical prerequisite but is slightly convoluted with 'reads included.' Overall, it is compact and earns its place, though the phrasing could be clearer.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple rename tool with a complete input schema, output schema, and annotations covering safety, the description adds the essential prerequisite and identification method. It does not explain error conditions, but these are not critical for correct tool usage in most contexts.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has 100% description coverage for all parameters, including guidance on using old_title or uid. The description adds no additional parameter semantics beyond the phrase 'current title or UID,' which merely mirrors the schema. Baseline 3 is appropriate given high schema coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's function with a specific verb and resource: 'Rename a page by changing its title.' It also specifies the identification method ('by current title or UID'), distinguishing it from sibling tools like create_page or update_page_markdown.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit usage guidance by instructing the agent to call roam_get_guidelines before using this tool, including a rationale about conventions. However, it does not name alternative tools or state when not to use this tool, so it stops short of a full 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
roam_search_block_refsARead-onlyIdempotent
Search for block references within a page or across the entire graph. Can search for references to a specific block, a page title, or find all block references.
IMPORTANT: call roam_get_guidelines for this graph once per session before using this tool, reads included — conventions change how results are read, not just written.
| Name | Required | Description | Default |
|---|---|---|---|
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| title | No | Optional: Page title to find references to (uses :block/refs for [[page]] and #tag links) | |
| block_uid | No | Optional: UID of the block to find references to (searches for ((uid)) patterns in text) | |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. | |
| page_title_uid | No | Optional: Title or UID of the page to search in (UID is preferred for accuracy). If not provided, searches across all pages. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and destructiveHint, but the description adds meaningful context: results must be interpreted based on graph conventions (calling roam_get_guidelines even for reads). This goes beyond the structured annotations by warning that behavior depends on per-graph conventions.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two short paragraphs: a focused purpose statement followed by a critical warning. Every sentence is useful, no filler, and the most important usage instruction is front-loaded with 'IMPORTANT.'
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the full schema coverage, read-only annotations, and lack of an output schema, the description sufficiently explains the tool's capability and a key prerequisite. It could mention default behavior when no parameters are provided, but 'find all block references' is already implied, so it is nearly complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema covers all parameters with descriptions, providing a solid baseline. The description adds relationship semantics: block_uid targets a specific block, title targets page references, and page_title_uid scopes the search to a page or graph-wide. This helps agents understand how to combine parameters effectively.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states 'Search for block references within a page or across the entire graph' and lists specific modes (specific block, page title, all references). This makes the tool's purpose unambiguous and distinguishes it from sibling text-search tools like roam_search_by_text, even though no alternatives are named.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description conveys when to use the tool (searching for references) and gives an explicit directive to call roam_get_guidelines first due to convention-dependent behavior. It does not explicitly compare with alternative search tools for when not to use it, but the usage context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
roam_search_by_dateARead-onlyIdempotent
Search for blocks or pages based on creation or modification dates. Not for daily pages with ordinal date titles.
IMPORTANT: call roam_get_guidelines for this graph once per session before using this tool, reads included — conventions change how results are read, not just written.
| Name | Required | Description | Default |
|---|---|---|---|
| type | Yes | Whether to search by creation date, modification date, or both | |
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| scope | Yes | Whether to search blocks, pages | |
| end_date | No | Optional: End date in ISO format (YYYY-MM-DD) | |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. | |
| start_date | Yes | Start date in ISO format (YYYY-MM-DD) | |
| include_content | No | Whether to include the content of matching blocks/pages |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare read-only, idempotent, and non-destructive behavior. The description adds valuable context by requiring a call to roam_get_guidelines and warning that conventions change how results are read, going beyond what annotations and schema provide.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences long, front-loaded with the core action and followed by a critical exclusion and warning. Every sentence earns its place, and the formatting makes the important prerequisite prominent.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With 7 parameters, no output schema, and rich annotations, the description plus schema is almost sufficient. It provides a mandatory guidelines call and exclusion, but could benefit from a brief note on result format or edge cases like end_date inclusivity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema provides 100% coverage for all 7 parameters, so the baseline is 3. The description does not add any parameter-specific details, examples, or additional meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool searches blocks/pages by creation or modification dates, and includes an explicit exclusion for daily pages with ordinal date titles. It is specific and actionable, but does not explicitly name sibling alternatives to differentiate from.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly says 'Not for daily pages with ordinal date titles' (when-not) and instructs to call roam_get_guidelines once per session before using the tool (prerequisite). This provides clear usage context, even though it does not name an alternative tool.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
roam_search_by_statusARead-onlyIdempotent
Search for blocks with a specific status (TODO/DONE) across all pages or within a specific page.
IMPORTANT: call roam_get_guidelines for this graph once per session before using this tool, reads included — conventions change how results are read, not just written.
| Name | Required | Description | Default |
|---|---|---|---|
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| status | Yes | Status to search for (TODO or DONE) | |
| exclude | No | Optional: Comma-separated list of terms to filter results by exclusion (matches content or page title) | |
| include | No | Optional: Comma-separated list of terms to filter results by inclusion (matches content or page title) | |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. | |
| page_title_uid | No | Optional: Title or UID of the page to search in (UID is preferred for accuracy). If not provided, searches across all pages. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and idempotentHint=true. The description adds a meaningful behavioral nuance: graph conventions can change how results are read, not just written, and guidelines must be fetched once per session. This goes beyond the annotations and aids correct usage.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences: the first states the purpose, the second delivers a critical usage prerequisite. It is front-loaded, concise, and every word adds value. No redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's moderate complexity and full schema coverage, the description is complete for selection and invocation. It discloses the prerequisite call, the scope options, and the status filter. It does not describe return format, but search tools without output schema are often self-explanatory. Minor gap: no mention of exclude/include filters beyond the schema, but those are documented there.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema provides 100% coverage with detailed descriptions for all 6 parameters. The description does not add syntax or format details beyond the schema, so the baseline 3 is appropriate. The scope behavior (all pages vs specific page) is already captured in the page_title_uid parameter description.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it searches for blocks by status (TODO/DONE) across all pages or a specific page. The verb 'search' plus resource 'blocks' and filter 'status' makes the purpose specific and distinguishes it from sibling search tools like roam_search_by_text or roam_search_by_date.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides an explicit prerequisite: call roam_get_guidelines before using this tool, even for reads. It also mentions the optional scope (all pages vs a specific page). However, it does not explicitly contrast with alternative search tools or state when-not-to-use, so it falls short of a 5.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
roam_search_by_textARead-onlyIdempotent
Search for blocks containing specific text across all pages or within a specific page. Use scope: "page_titles" to search for pages by namespace prefix (e.g., "Convention/" finds all pages starting with that prefix). This tool supports pagination via the limit and offset parameters.
IMPORTANT: call roam_get_guidelines for this graph once per session before using this tool, reads included — conventions change how results are read, not just written.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes | The text to search for. When scope is "page_titles", this is the namespace prefix (trailing slash optional). | |
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| limit | No | Optional: The maximum number of results to return. Defaults to 50. Use -1 for no limit, but be aware that very large results sets can impact performance. | |
| scope | No | Search scope: "blocks" for block content (default), "page_titles" for page title namespace prefix matching. | blocks |
| offset | No | Optional: The number of results to skip before returning matches. Useful for pagination. Defaults to 0. | |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. | |
| case_sensitive | No | Optional: Whether the search should be case-sensitive. If false, it will search for the provided text, capitalized versions, and first word capitalized versions. Only used when scope is "blocks". | |
| page_title_uid | No | Optional: Title or UID of the page to search in (UID is preferred for accuracy). If not provided, searches across all pages. Only used when scope is "blocks". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the tool read-only, idempotent, and non-destructive, lowering the bar. The description adds a meaningful behavioral note: graph conventions affect how results are read, not just written, implying results can vary between graphs. It also mentions pagination support, though the schema already documents limit/offset.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact: two sentences covering core functionality and a one-sentence important note. It front-loads the primary purpose, explains the alternate scope, then delivers the essential prerequisite. Every sentence earns its place without fluff or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With 8 parameters but only 1 required, full schema coverage, and complete annotations, the description adds the crucial missing context: a session-level prerequisite to call roam_get_guidelines because conventions affect reads. The namespace prefix example clarifies a non-obvious mode. No output schema exists, but the return value for a block/page search tool is self-evident.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% for all 8 parameters, so the baseline is 3. The description's mentions of `scope: 'page_titles'`, the namespace prefix example, and pagination via `limit`/`offset` all reinforce but do not add substantive meaning beyond what the parameter descriptions already provide.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Search for blocks containing specific text across all pages or within a specific page,' a specific verb and resource. It clearly distinguishes the free-text blocks search from the namespace-prefix page_titles mode, and the availability of these two modes helps set it apart from sibling search tools like roam_search_for_tag or roam_search_by_status.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear usage context: it tells the agent to use scope 'page_titles' for namespace prefix searches and includes an 'IMPORTANT' instruction to call roam_get_guidelines once per session because conventions change how results are read. It lacks explicit exclusions or direct references to sibling alternatives, but the context is strong enough to guide appropriate selection.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
roam_search_for_tagARead-onlyIdempotent
Search for blocks containing a specific tag. Use primary_tag for the tag to find, and optionally page_title_uid to limit search to a specific page. Supports pagination via limit and offset. Use this tool to search for memories tagged with the ROAM_MEMORIES_TAG.
IMPORTANT: call roam_get_guidelines for this graph once per session before using this tool, reads included — conventions change how results are read, not just written.
| Name | Required | Description | Default |
|---|---|---|---|
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| limit | No | Optional: The maximum number of results to return. Defaults to 50. Use -1 for no limit, but be aware that very large results sets can impact performance. | |
| offset | No | Optional: The number of results to skip before returning matches. Useful for pagination. Defaults to 0. | |
| near_tag | No | Optional: Another tag to filter results by - will only return blocks where both tags appear | |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. | |
| primary_tag | Yes | The main tag to search for (without the [[ ]] brackets) | |
| case_sensitive | No | Optional: Whether the search should be case-sensitive. If false, it will search for the provided tag, capitalized versions, and first word capitalized versions. | |
| page_title_uid | No | Optional: Title or UID of the page to search in (UID is preferred for accuracy). Defaults to today's daily page if not provided. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true and idempotentHint=true. The description adds behavior beyond annotations by mentioning pagination via limit/offset and the important note that conventions change how results are read, requiring a one-time call to roam_get_guidelines. This enriches the agent's understanding of how to invoke and interpret results.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two short paragraphs, front-loaded with the primary purpose. The second paragraph is an important, non-obvious prerequisite that earns its place. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no output schema, the description doesn't detail the return structure, but the purpose implies a list of blocks. It covers the key parameters, pagination, page scoping, and a critical guideline call. This is sufficient for a read-only search tool with good annotation coverage.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all 8 parameters are documented. The description briefly references primary_tag, page_title_uid, limit, and offset, but doesn't add meaningful semantics beyond the schema—it mostly repeats the schema's parameter descriptions. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with 'Search for blocks containing a specific tag', which clearly states the verb (search) and resource (blocks with a tag). It also differentiates from sibling search tools by emphasizing tag-based search and gives a concrete use case ('search for memories tagged with the ROAM_MEMORIES_TAG').
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides clear context with 'Use this tool to search for memories tagged with the ROAM_MEMORIES_TAG' and instructs to call roam_get_guidelines first. It doesn't explicitly name alternatives or when-not cases, but the tag-focused purpose and required preliminary call give sufficient guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
roam_search_hierarchyARead-onlyIdempotent
Search for parent or child blocks in the block hierarchy. Can search up or down the hierarchy from a given block.
IMPORTANT: call roam_get_guidelines for this graph once per session before using this tool, reads included — conventions change how results are read, not just written.
| Name | Required | Description | Default |
|---|---|---|---|
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| child_uid | No | Optional: UID of the block to find parents of | |
| max_depth | No | Optional: How many levels deep to search (default: 1) | |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. | |
| parent_uid | No | Optional: UID of the block to find children of | |
| page_title_uid | No | Optional: Title or UID of the page to search in (UID is preferred for accuracy). |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, covering safety. The description adds valuable behavioral context: the ability to search both up and down, and the critical caveat that per-graph conventions affect how results are read. This goes beyond the annotations without contradicting them.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two short paragraphs: the first front-loads the core purpose, the second delivers an essential prerequisite note. No filler words, every sentence earns its place, and the structure is easy to scan.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's moderate complexity (6 optional params, no output schema), the description covers the essential behavioral scope and a critical prerequisite. It does not explain edge cases like providing both parent_uid and child_uid, or default behavior when neither is given, but the annotations and schema fill many gaps, making the description reasonably complete for a read-only search tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema provides 100% coverage with descriptions for all six parameters, so the baseline is 3. The description adds minimal extra meaning beyond the schema, mainly correlating 'from a given block' with parent/child UID parameters. It does not elaborate on parameter interactions (e.g., mutual exclusivity), but the schema already handles the basics.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action ('Search for parent or child blocks') on a specific resource ('block hierarchy'), and clarifies the directional capability ('up or down') from a given block. This clearly distinguishes it from sibling search tools like roam_search_by_text or roam_search_by_status, which operate on content or status rather than hierarchy.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description makes it obvious when to use this tool: when you need to traverse parent/child relationships in the block hierarchy. It also provides a mandatory prerequisite instruction to call roam_get_guidelines once per session, which is concrete usage guidance. However, it does not explicitly mention alternatives or when not to use this tool, so it falls short of the strongest 'when-not' clarity.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
roam_update_page_markdownADestructiveIdempotent
Update an existing page with new markdown content using smart diff. Preserves block UIDs where possible and generates minimal changes. This is ideal for:
Syncing external markdown files to Roam
AI-assisted content updates that preserve references
Batch content modifications without losing block references
⚠️ This REPLACES the page, it does not append. Any block your markdown does not account for is deleted. Pass the complete intended page, or use roam_process_batch_actions / roam_create_outline to change only part of one. Use dry_run: true to see the actions first.
How it works:
Fetches existing page blocks
Matches new content to existing blocks by text similarity
Generates minimal create/update/move/delete operations
Preserves UIDs for matched blocks (keeping references intact)
#.rm-hide / #.rm-private subtrees are excluded from the diff and left untouched — you cannot see them, so you cannot be asked to account for them. preserved_hidden reports how many, when any.
IMPORTANT: call roam_get_guidelines for this graph once per session, and load the Roam Markdown Cheatsheet, before using this tool.
| Name | Required | Description | Default |
|---|---|---|---|
| graph | No | Target graph key from ROAM_GRAPHS config. Defaults to ROAM_DEFAULT_GRAPH. Only needed in multi-graph mode. | |
| title | Yes | Title of the page to update | |
| dry_run | No | If true, returns the planned actions without executing them. Useful for previewing changes. | |
| markdown | Yes | New GFM markdown content for the page | |
| write_key | No | Write confirmation key. Required for write operations on non-default graphs when write_key is configured. |
Output Schema
| Name | Required | Description |
|---|---|---|
| stats | Yes | |
| actions | Yes | Roam batch actions applied (or planned, when dry_run) |
| success | Yes | |
| summary | Yes | |
| preserved_uids | Yes | Blocks whose UIDs survived the diff, so refs to them still resolve |
| preserved_hidden | No | Present only when non-zero: how many #.rm-hide / #.rm-private blocks were excluded from the diff and left on the page untouched |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the destructiveHint annotation, the description explicitly discloses that 'This REPLACES the page' and any unaccounted block is deleted. It explains the smart diff algorithm step-by-step, mentions hidden subtrees are excluded and left untouched, and that `preserved_hidden` reports the count. It also notes the requirement to call guidelines once per session, offering deep behavioral insight beyond the structured annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Despite being long, the description is well-structured with clear sections: summary, use cases, warning, how-it-works steps, hidden subtree note, and important prerequisite. Every sentence adds critical information, and the formatting (bullets, bold warning, numbered list) makes it scannable. It is appropriately detailed for a complex, destructive tool.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The description is exceptionally complete given the tool's complexity. It covers purpose, alternatives, destructive behavior, algorithm steps, hidden content handling, output hints, and required prior steps. Combined with rich schema and annotations, the agent has all necessary context to select and invoke the tool safely.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the baseline is 3. The description adds some context around `dry_run` usage and mentions `preserved_hidden` (an output field), but does not provide additional meaning for the parameters beyond what the schema already documents. It reinforces the purpose but does not elevate semantic understanding.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool 'Updates an existing page with new markdown content using smart diff' and lists specific use cases. It distinguishes itself from siblings by explicitly naming alternatives like `roam_process_batch_actions` and `roam_create_outline` for partial edits.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides explicit guidance on when to use the tool ('ideal for syncing...', 'AI-assisted content updates...') and when not to, warning that it replaces the whole page and directing to alternatives for partial changes. It also instructs to use `dry_run: true` and to call `roam_get_guidelines` first, covering prerequisites and exclusion conditions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
TDQS
Each tool has a distinct primary purpose, and descriptions include explicit disambiguation notes (e.g., get_subpages vs search_hierarchy). However, the large number of search/find tools (search_by_text, search_for_tag, search_by_status, search_by_date, find_pages_modified_today) can still cause confusion, so not a perfect 5.
All tools use snake_case and the `roam_` prefix, but action verbs are inconsistent: fetch, get, search, find, create, add. Search tools mix preposition patterns (search_by_text, search_for_tag, search_block_refs), and two tools are noun phrases (roam_markdown_cheatsheet, roam_datomic_query).
25 tools is at the high end of the 'feels heavy' range. The complexity of Roam's data model justifies many operations, but some search variants could be consolidated. The count is not extreme, but it is on the boundary.
The set covers page/block creation, retrieval, update, batch operations, rich search, memory, table creation, markdown import, and custom Datomic queries. Explicit page/block deletion tools are missing, though batch actions include delete. There is no general 'list all pages' tool, but search_by_text with page_titles scope partially fills this gap.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Personal wiki and memory layer for AI assistants. Persistent, structured memory across sessions.
Personal CRM for Claude. Contacts live as plain-text files in your own Google Drive.
Serve a folder of Markdown notes as an MCP server: hybrid search, reading, and sourced answers.
The Ramp MCP server enables users to securely connect Ramp with AI assistants like ChatGPT and Claude to query financial data and take actions using natural language. It transforms Ramp's developer API into a SQL interface that LLMs can query, allowing admins to analyze spend trends, identify cost savings, and run complex SQL analyses on comprehensive datasets (transactions, purchase orders, vendors, users), while all users can manage cards, view transactions, request reimbursements, and get expense policy answers.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceProvides a standardized interface for AI assistants to interact with Obsidian vaults through a local REST API, enabling reading, writing, searching, and managing notes.66MIT
- AlicenseNot gradedqualityDmaintenanceA server that enables AI assistants like Claude to interact with Roam Research graphs through a standardized interface, providing comprehensive tools for content creation, search, retrieval, and optional memory management.8MIT
- FlicenseAqualityDmaintenanceA Model Context Protocol server that enables Claude Desktop to read from and write to Roam Research graphs, allowing for retrieving page content, finding references, and adding blocks to existing or daily pages.41
- AlicenseAqualityNot gradedmaintenanceEnables AI assistants to interact with Roam Research graphs through comprehensive API access, supporting page/block operations, markdown import, search, memory storage, and complex batch actions for managing knowledge graphs.18119
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/2b3pro/roam-research-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server