Ramifica is a collaborative nested-list outliner. Users capture thoughts as items inside lists; items nest arbitrarily deep via a parentId chain, and sibling order is held by a fractional-index string (lexicographic sort, not numeric). Lists can be private, shared with specific people, or owned by a workspace. Item text supports free-form #hashtags and @[Display Name](userId) mentions as literal characters. When you act on Ramifica you are editing a live document the user (and possibly their collaborators) sees in real time — be conservative with writes, and prefer reading before mutating.
8 MCP tools — read tools first, then write. Signatures match src/app/api/[transport]/route.ts.
Read all lists the user owns or has accepted as a collaborator — call this first to discover IDs.
No parameters
Returns
Array<{ id: string; name: string; itemCount: number; createdAt: number; updatedAt: number; isShared: boolean }>
Example
get_lists() // → [{ "id": "jd7abc", "name": "Inbox", "itemCount": 5, "isShared": false, ... }]Read every item inside one list, with depth computed from the parentId chain.
| Parameter | Type | Required | Description |
|---|---|---|---|
| listId | string | Yes | Convex ID of the list — get this from get_lists. |
Returns
Array<{ id: string; content: string; parentId: string | null; depth: number; order: string; isChecked: boolean; checkedAt: number | null }> — order is a fractional-index STRING (sort lexicographically); isChecked defaults to false when never checked; checkedAt is a ms timestamp or null.
Example
get_items({ "listId": "jd7abc" })Bulk-insert up to 50 items into a list. Supports nesting via depth or parentIndex.
| Parameter | Type | Required | Description |
|---|---|---|---|
| items | Array<{ content: string; depth?: number; parentIndex?: number }> | Yes | Items to add (max 50). depth gives nesting level; parentIndex points to an earlier item in this same array. |
| listName | string | No | Target list name. Omit to use Inbox (auto-created if absent). |
Returns
{ added: number; listId: string }
Example
add_items({ "listName": "Project Plan", "items": [{ "content": "Phase 1", "depth": 0 }, { "content": "Research", "depth": 1 }] })Create a new named list owned by the user.
| Parameter | Type | Required | Description |
|---|---|---|---|
| name | string | Yes | Name for the new list (min 1 character). |
Returns
{ listId: string }
Example
create_list({ "name": "Reading Queue" })Edit one item's content and/or check it off.
| Parameter | Type | Required | Description |
|---|---|---|---|
| itemId | string | Yes | Convex ID of the item to update. |
| content | string | No | New text content (optional). |
| checked | boolean | No | Set true to mark complete, false to uncheck. At least one of content/checked must be provided. |
Returns
string (itemId)
Example
update_item({ "itemId": "abc123", "checked": true })Rename one list. Owner-only — collaborators receive ACCESS_DENIED.
| Parameter | Type | Required | Description |
|---|---|---|---|
| listId | string | Yes | Convex ID of the list. |
| name | string | Yes | New list name (non-empty). |
Returns
string (listId)
Example
rename_list({ "listId": "jd7abc", "name": "Q3 Planning" })Toggle one item's checkbox — the canonical 'mark done' / 'uncheck' surface (mirrors the UI's toggleCheck behavior).
| Parameter | Type | Required | Description |
|---|---|---|---|
| itemId | string | Yes | Convex ID of the item to toggle. |
| checked | boolean | Yes | true marks complete (stamps checkedAt = now); false unchecks (clears checkedAt). |
Returns
{ updated: string; checked: boolean }
Example
set_checked({ "itemId": "abc123", "checked": true })Reparent an item and its entire subtree within the same list. Use to reorganise structure without re-adding content.
| Parameter | Type | Required | Description |
|---|---|---|---|
| itemId | string | Yes | Convex ID of the item to move — get from get_items. |
| parent_id | string | null | No | New parent item ID. Pass null or omit to move the item to root level of the same list. |
| after_item_id | string | No | Insert after this sibling ID. Omit to append as last sibling under the new parent. |
Returns
{ moved: string }
Example
move_item({ "itemId": "item123", "parent_id": "item456", "after_item_id": "item789" })Items relate through a parentId chain: an item's parent is another item in the same list, and depth is the number of links to a top-level item. Sibling order is held in order, a fractional-index STRING such as 'a0', 'a1', 'a0V' — always sort lexicographically, never parse it as a number, and never compute new keys client-side.
Use move_item for same-list reparenting; cross-list/cycle moves rejected. Two list fields shape what users see: tutorialAt marks the auto-generated 'Getting Started' list — agents should treat it as low-priority and generally skip it when summarising; archivedAt is a soft-delete timestamp — archived lists do not appear in default list collections, so you will only see them if the user explicitly asks.
Items carry two checkbox fields: isChecked (boolean, defaults to false) and checkedAt (ms timestamp or null when never checked). Use set_checked to toggle; on transition to checked the server stamps checkedAt = Date.now(); on uncheck it clears checkedAt. Filter on these to answer 'what's left / what's done / what did I finish this week' queries. Inside content, #hashtags are free-form topic markers (literal characters, no schema). Mentions appear as @[Display Name](userId) — treat the userId as opaque and surface only the display name to the user; never echo the raw userId back in chat.
Copy any of these into your agent to try Ramifica.
Summarise my Inbox
read
Use get_lists to find my Inbox, then get_items on it, then give me a short bulleted summary grouped by theme. Flag anything that looks overdue or stale.
What's left to do, skip what's already checked
read
Call get_lists, pick the list I name (or default to 'Inbox'), then get_items. Filter to items where isChecked is false, group by depth, and give me a short bulleted summary of what's still open. If everything is checked, say so.
Add three sub-items under a parent
write
In my 'Project Plan' list, find the item whose content matches '[parent item]'. Then use add_items with listName 'Project Plan' to insert three children under it — use parentIndex to nest them in a single call.
Reorganise — move an item under a new parent
write
In my 'Project Plan' list, call get_items, find the item whose content matches '[child item]', then move_item to reparent it under the item matching '[parent item]'. Call get_items again and confirm the new parentId chain.
Find overdue items, then summarise to Inbox
mixed
Walk every list with get_lists + get_items, find items whose content suggests a due date in the past, then add_items to my Inbox with a single summary item linking out to them by name.
Ramifica supports two auth methods. OAuth 2.1 (PKCE) is the primary path for OAuth-capable clients — no token management required. Manual Bearer tokens are the fallback for clients that don't support OAuth.
OAuth-capable clients (Claude web app, Cursor) connect automatically via the standard OAuth 2.1 authorization-code + PKCE flow. The client discovers Ramifica's authorization server at /.well-known/oauth-authorization-server, redirects the user to the consent screen at /authorize, and exchanges the code for a token automatically. No manual token creation needed.
Clients that accept a static Authorization header in their config (Claude Desktop, Cline, and others) use a manually-minted token. Create or revoke tokens from the MCP Tokens panel on your /home settings page. The token string passes only through your agent's local config — Ramifica never logs it server-side.
Authorization: Bearer <token>Each token gets 20 requests per minute, counted independently per token (source: src/lib/mcpRateLimit.ts). On a RATE_LIMITED error, back off and retry after the indicated interval — bulk writes (add_items in particular) are cheaper as one call of 50 items than 50 calls of one item each.
Apple Notes to Ramifica
Push selected Apple Notes content into any Ramifica list using Apple Shortcuts and the MCP API.
More documentation resources — Documentation home.