MCP Tools
The MCP server has 321 built-in tools across route-backed and locally handled paths; default connections receive the complete granted set, while a launcher opting in with --defer-tools starts with core tools plus discover_tools.
The MCP server's complete catalog contains 321 built-in tools.
Most tools call the same API routes as the CLI and web app. Locally handled paths stay
inside the catalog: batch dispatches member tools in process, and dry-run branches
can validate and preview a write without sending the mutation.
Default auto mode and explicit never mode initially advertise the complete granted catalog — up to 321 built-in tools.
Auto preserves that complete catalog because MCP exposes no compatible client capability
the server can use to prove that a host refreshes its tool list.
dots mcp --defer-tools is the opt-in a refresh-capable host sets. The catalog partitions into 16 core tools and 305 deferred built-in tools;
the initial list contains the granted members of the core class plus discover_tools,
while granted deferred members stay withheld until discovery activates them.
A tool is registered only when the connecting credential holds the permission atom it requires, so an agent only ever sees the tools its access allows: a read-only connection drops the write catalog while the read-classed tools stay registered, and a scoped token narrows it further. Scope and read-only filtering narrow either injection mode before the host sees its list. The sections below are grouped by that required atom.
Tool results come back as the same envelope described in Row Envelope Format. Routes used by route-backed tools are listed in the REST API Overview.
Tools Requiring access.agents.manage (3)
create_agent
Create an agent principal — a non-human identity that holds authority, carries credentials, and appears in the directory beside the humans. It starts with ZERO authority: it reaches nothing until a grant or a role assignment gives it something. grants seeds per-Dotabase authority at creation; the policy fields (denied_tools, denied_vault_tools, web_) are written as ONE ATOMIC policy, so sending any of the three sets all three — an omitted deny list is stored EMPTY, not left alone.
Parameters:
name(required) — Display name for the new agent principal.grants— Initial per- grants. Omit for a zero-authority agent — the default, and the only shape that needs no grants.manage of its own.denied_tools— Provider tool names the agent may not call (e.g. Bash, WebSearch).denied_vault_tools— Dotted vault tool names the agent is not offered (e.g. vault.create_row).web_access— Whether the agent may reach the web. Defaults to true when any policy field is set.dailySpendCapUsd— Daily spend ceiling in USD; null means no cap. Omit to leave the column default.
get_agent_profile
One agent principal's stored profile: its tool policy and its daily spend cap. Kind-scoped — a human principal's id is refused rather than answered with an empty profile, so a miss here means the id names a human or nothing at all.
Parameters:
principal(required) — The AGENT principal UUID. A human principal is refused: the profile is kind-scoped, not merely tenant-scoped.
set_agent_profile
Update an agent's tool policy and daily spend cap. The policy is ATOMIC: sending any of denied_tools / denied_vault_tools / web_access replaces the whole stored policy, so an omitted deny list is stored EMPTY rather than preserved — read get_agent_profile first and send the full intended policy. dailySpendCapUsd is independent; null clears the cap. Kind-scoped — a human principal is refused. At least one field is required.
Parameters:
principal(required) — The AGENT principal whose profile to update, by UUID or its exact name in list_principals.denied_tools— Provider tool names the agent may not call.denied_vault_tools— Dotted vault tool names the agent is not offered.web_access— Whether the agent may reach the web.dailySpendCapUsd— Daily spend ceiling in USD; null clears the cap.
Tools Requiring access.approvals.decide (2)
decide_approval
Approve or deny a parked action. An approve REPLAYS the original action under the requester's authority, so it lands the write the requester was refused; a deny closes the request without running it. This connection cannot decide an approval its OWN principal requested — that refusal is a hard bar, not a warning — and a row already decided by someone else is refused rather than re-decided, which is what arbitrates two agents reaching for the same entry.
Parameters:
approval(required) — The approval's UUID, as list_approvals returned it.decision(required) —approvereplays the parked action under the requester's authority;denycloses the request without running it.
list_approvals
The approval queue: actions parked awaiting a human decision, with the permission each needed and its current status. Overdue pending entries expire as this reads, so the answer is the live queue rather than a stale one. decide_approval settles an entry — but never one this connection's own principal requested.
Parameters:
status— Narrow to one queue status. Omit for the whole queue.limit— Max entries to return. Omit for the route's own default.
Tools Requiring access.audit.read (1)
list_audit_events
The workspace's append-only authorization ledger, newest first and keyset-paged: who did what to which target, when, with display names resolved. Narrow by actor, event, target, or an instant window; page by passing the previous answer's nextCursor back as cursor. This is the record of what authority was exercised — read it before asserting that something did or did not happen.
Parameters:
actor— Narrow to one actor principal's entries.event— Narrow to one event name, e.g.role.created.target— Narrow to one target id.since— Only entries at or after this ISO-8601 instant.until— Only entries before this ISO-8601 instant.limit— Max entries per page. Omit for the route's own default.cursor— The opaque keyset cursor a previous page returned asnextCursor.
Tools Requiring access.grants.manage (6)
add_grant
Grant a role or a principal a permission set on ONE Dotabase — the narrower layer on top of role baselines, so a subject's effective reach becomes its roles UNION its grants. Only Dotabase-scoped atoms are accepted; a workspace-scoped atom belongs on a role. requireApproval parks the named atoms behind an approval request rather than letting the subject exercise them directly.
Parameters:
subjectKind(required) — Whethersubjectnames a role or a principal.subject(required) — The role or principal the grant is held by, by UUID or exact name.dotabase(required) — The Dotabase the grant applies to, by UUID or slug.permissions(required) — The Dotabase-scoped permission atoms the grant carries. A workspace-scoped atom is refused — grants are per-Dotabase only.requireApproval— Atoms among the grant's own that need an approved request to exercise.
grant_entitlement
Provision a capability key for the ACTIVE company — the open key space that gates features, distinct from the RBAC permission atoms. The key is taken as given and charset-validated server-side; a malformed key is refused rather than stored.
Parameters:
capability(required) — The capability key to provision for the active company. An OPEN key , distinct from the permission catalog; the charset is validated server-side.
list_grants
Every per-Dotabase grant in the workspace: which role or principal holds which permissions on which Dotabase, and whether the grant needs approval. Workspace-wide authority comes from roles; this is the narrower layer on top, so a principal's effective reach is its role baselines UNION its grants here.
remove_grant
Revoke a per-Dotabase grant. The subject keeps whatever its roles confer and loses only what this grant added, immediately and without a restore.
Parameters:
grant(required) — The grant's UUID, as list_grants returned it.
revoke_entitlement
Revoke a capability key from the active company, withdrawing whatever feature it gated. Revoking a key the company does not hold is the route's own no-op, not an error.
Parameters:
capability(required) — The capability key to revoke from the active company.
update_grant
Replace a grant's permissions, its approval-required set, or both. Each is a WHOLE-SET replace, not an addition — send list_grants' current set plus the change. At least one of the two is required.
Parameters:
grant(required) — The grant's UUID, as list_grants returned it.permissions— The grant's WHOLE permission set, replacing what it held. Omit to leave it unchanged.requireApproval— The grant's WHOLE approval-required set, replacing what it held.
Tools Requiring access.members.manage (8)
add_role_assignment
Assign a role to a principal — the act that actually confers authority, since a role holds none until it is assigned. requireApproval parks the named atoms behind an approval request instead of letting this principal exercise them directly, and must be a subset of the role's own permissions.
Parameters:
principal(required) — The principal to assign the role to, by UUID or its exact name in list_principals.role(required) — The role to assign, by UUID or its exact name in list_roles.requireApproval— Atoms among the role's own that this principal may exercise only through an approved request. Must be a subset of the role's permissions.
create_invite
Invite a human to this workspace: creates an invited principal carrying the roles you name and mints a single-use accept token. The RAW TOKEN comes back EXACTLY ONCE, in this answer and nowhere else — it is stored only as a hash and no later read returns it. Hand it to the invitee (it is the accept link's credential) and do not paste it anywhere it will be retained.
Parameters:
email(required) — The invitee's email address.roles(required) — The roles the invitee lands with, each by UUID or exact role name. At least one; an unassignable role is refused server-side.
issue_credential
Issue a personal access token for a principal. The RAW TOKEN comes back EXACTLY ONCE, in this answer and nowhere else — the workspace stores only a hash and a display prefix, list_credentials never returns it, and it cannot be recovered if lost. scopes narrows the credential BELOW the principal's own authority; omitted, it carries the principal's full reach. Treat the answer as a secret: do not echo it into a file, a row, or a message that will be retained.
Parameters:
principal(required) — The principal the credential authenticates as, by UUID or its exact name in list_principals.name(required) — A label for the credential, shown in list_credentials.scopes— Narrow the credential to these permission atoms. Omit for the principal's own full authority.expiresAt— ISO-8601 expiry instant; null or omitted issues a credential that does not expire.
remove_principal
Hard-remove a principal — the human member or agent, its role assignments, its grants, and its credentials, permanently. There is no restore; suspend through update_principal is the reversible alternative. Removing the last active human Owner is refused server-side, so a workspace can never be locked out.
Parameters:
principal(required) — The principal to remove, by UUID or its exact name in list_principals.
remove_role_assignment
Remove a role assignment, withdrawing everything that role conferred on this principal. Removing the last active human Owner's Owner role is refused server-side. The role itself is untouched — delete_role is what removes it everywhere.
Parameters:
principal(required) — The principal to unassign the role from, by UUID or its exact name in list_principals.role(required) — The role to remove, by UUID or its exact name in list_roles.
revoke_credential
Revoke a credential so it authenticates nothing further. Immediate and permanent — a revoked credential is never reactivated, and issuing a replacement is the way back. Revoking one already revoked is the route's own idempotent answer, not an error.
Parameters:
credential(required) — The credential's UUID, as list_credentials returned it.
revoke_invite
Revoke a pending invite by hard-deleting the invited principal behind it, so its token can never be accepted. An invite already accepted is no longer an invite — remove_principal is what removes that member.
Parameters:
invite(required) — The invited principal's UUID, as create_invite returned it inprincipalId.
update_principal
Rename a principal, suspend it, or reactivate it. Suspending keeps the principal and every role assigned to it and refuses every request it makes, so it is the reversible half of remove_principal. At least one of name / status is required. The atom is the TARGET's kind — access.agents.manage for an agent, access.members.manage for a human — so a directory read first tells you which gate applies.
Parameters:
principal(required) — The principal to update, by UUID or its exact name in list_principals.name— New display name. Omit to leave it unchanged.status— New status.suspendedkeeps the principal and its roles but refuses every request it makes. Omit to leave it unchanged.
Tools Requiring access.principals.read (3)
list_credentials
The credentials issued in this workspace — id, name, owning principal, display prefix, and lifecycle state. Neither the hash nor the raw token is returned by the route at all, so this cannot be used to recover a token; it answers which credentials exist and which are still live.
Parameters:
principal— Narrow to one principal's credentials — its UUID or its exact directory name. Omit for every credential in the workspace. No hash and no raw token is ever returned — only the display prefix.
list_principals
The workspace directory: every human member and agent principal, with its status, the roles assigned to it, and the system roles among them. The starting point for any authority question — a principal's id here is what list_credentials, list_grants, and get_agent_profile are keyed by.
Parameters:
kind— Narrow the directory to one principal kind. Omit for both.
list_roles
The workspace's roles, system and custom alike, each with its permission atoms. A system role is flagged immutable and carries its baseline from the catalog rather than a stored list, so compare a custom role's atoms against permission_catalog's baselines to see what it actually adds.
Tools Requiring access.roles.manage (3)
create_role
Create a custom role carrying the permission atoms you name. Spell the atoms as permission_catalog spells them; an unknown atom is refused rather than dropped, and an owner-reserved atom cannot be granted through a custom role at all. The role holds authority only once assigned — add_role_assignment is what binds it to a principal.
Parameters:
name(required) — Display name for the new custom role.description— Optional description. Omit to leave it unset.permissions(required) — The permission atoms the role carries, spelled as permission_catalog spells them. An unknown atom is refused rather than ignored.
delete_role
Delete a custom role. Every principal holding it loses the authority it carried, immediately and without a restore. A system role cannot be deleted. Read list_principals first if you need to know who is about to lose what.
Parameters:
role(required) — The custom role to delete, by UUID or its exact name in list_roles.
update_role
Rename a custom role, re-describe it, or replace its permission set. permissions is a WHOLE-SET replace, not an addition: send list_roles' current set plus the new atom to add one, or the set minus an atom to remove it. A system role is immutable and refuses every field. At least one field is required.
Parameters:
role(required) — The custom role to update, by UUID or its exact name in list_roles.name— New display name. Omit to leave it unchanged.description— New description; null clears it. Omit to leave it unchanged.permissions— The role's WHOLE permission set, replacing what it held. Omit to leave the permissions unchanged; send the current set plus the addition to add one.
Tools Requiring automations.manage (11)
archive_automation
Archive an automation — it stops firing and leaves the active roster while its configuration and run history survive. Use delete_automation to remove it outright. Pass dryRun: true to preview.
Parameters:
automation(required) — The automation's UUID.dryRun— Resolve the target and report what would be removed without sending the write.
create_automation
Create a scheduled automation. Pass EXACTLY ONE of schedule (a cron expression) or runOnceAt (an ISO instant), and exactly one of prompt (plain text) or promptDoc (a raw TipTap document). Every fire starts a conversation and runs an agent unattended, so a cron schedule is a standing commitment to recurring agent work — set one only when the task genuinely recurs. The next run time is computed server-side; the run-state slots are server-managed and are not arguments.
Parameters:
title(required) — The automation title.prompt— The prompt each fire sends, as plain text. Mutually exclusive withpromptDoc; required on create unlesspromptDocis given.promptDoc— The prompt as a raw TipTap document, for the mention-chip and multi-node shapes plain text cannot express. Mutually exclusive withprompt.schedule— A cron expression. Exactly one ofscheduleorrunOnceAtis required.runOnceAt— An ISO instant to fire once. Exactly one ofscheduleorrunOnceAtis required.timezone(required) — The IANA timezone the schedule is evaluated in.cwd(required) — The working directory the fired conversation runs in.providerName(required) — The chat provider that will run the fire.automationType— The automation lane (default chat-automation).modelId— Pin the model each fire uses.mode— The mode each fired turn runs in.notifyOnSuccess— Notify on a successful fire (default false).notifyOnFailure— Notify on a failed fire (default true).templateSlug— Seed from a bundled template.
delete_automation
Permanently delete an automation and cascade the provenance edges to the conversations it produced. The conversations themselves survive; nothing restores the automation. Archive it instead if you only want it to stop firing. Pass dryRun: true to preview.
Parameters:
automation(required) — The automation's UUID.dryRun— Resolve the target and report what would be removed without sending the write.
get_automation
Read one automation's full configuration by its UUID.
Parameters:
automation(required) — The automation's UUID.
get_automation_runs
Read one automation's run history — what fired, when, and which conversation each fire produced.
Parameters:
automation(required) — The automation's UUID.
list_automation_templates
List the bundled automation templates a create can seed from, so you propose a real template slug rather than inventing one.
list_automations
List this workspace's automations — the scheduled prompts that fire conversations on their own. Each carries its schedule, its next run, and the state of its last one.
pause_automation
Pause an automation: it keeps its configuration but stops being scheduled, and its next run time is cleared. Reverse it with resume_automation.
Parameters:
automation(required) — The automation's UUID.
resume_automation
Resume a paused automation and recompute its next run time from its schedule.
Parameters:
automation(required) — The automation's UUID.
run_automation
Fire an automation NOW, outside its schedule. This starts a conversation and runs an agent unattended — the same work the schedule would do, brought forward. It returns the fire outcome and the conversation it produced; a skipped fire (a missed window, an overlapping run) says so rather than failing.
Parameters:
automation(required) — The automation's UUID.
update_automation
Edit an automation. At least one argument is required, and only what you pass changes. schedule and runOnceAt stay mutually exclusive: send null to clear one while sending the other, and clearing both is refused because it would leave the automation triggerless. The next run time is recomputed server-side.
Parameters:
automation(required) — The automation's UUID.title— The new title.prompt— The prompt each fire sends, as plain text. Mutually exclusive withpromptDoc; required on create unlesspromptDocis given.promptDoc— The prompt as a raw TipTap document, for the mention-chip and multi-node shapes plain text cannot express. Mutually exclusive withprompt.schedule— A new cron expression; null clears it (sendrunOnceAtto keep a trigger).runOnceAt— A new one-shot instant; null clears it (sendscheduleto keep a trigger).timezone— The new IANA timezone.cwd— The new working directory.providerName— The new chat provider.automationType— The new automation lane.modelId— The new pinned model; null clears the pin.mode— The new mode.notifyOnSuccess— Whether a successful fire notifies.notifyOnFailure— Whether a failed fire notifies.
Tools Requiring chat.executors.use (4)
list_machines
List the machines this account has registered for remote chat execution, newest first. Read two fields exactly as they come: present is derived by the SERVER from the machine's own last report against one staleness window, so never recompute it from lastSeenAt; and availability: null means the machine has never reported what it can run — which is a different fact from [], a machine that reported it can spawn nothing. A revoked machine keeps its row and is never present. The route answers the whole registry in one read, so there is no paging.
mint_machine_registration_token
Mint the one-time token a headless box exchanges for its own device-scoped executor credential, registering the named machine as pending in the same call. The RAW token comes back exactly once and only its hash is stored, so hand it straight to the box and do not persist it anywhere else; it expires in 15 minutes, and a second mint for the same machine invalidates the first. Use this rather than asking for a personal credential: it is scoped to one machine and revoking that machine revokes it.
Parameters:
name(required) — Display name for the machine this token registers. Names need not be unique.
rename_machine
Rename one registered machine. The label only — the id is the identity, and the machine's credential, presence, and reported availability are untouched. Machine names are deliberately not unique.
Parameters:
machine(required) — The machine's UUID.name(required) — The machine's new display name. The id is the identity; nothing else moves.
revoke_machine
Revoke a registered machine and its device-scoped executor credential together. The machine's next lease, frame, or heartbeat is refused at the broker, and any turn parked against it stops being executable. Revocation is a STATE, so re-revoking succeeds and changes nothing further; there is no un-revoke — registering the box again mints a NEW credential. Pass dryRun: true to preview.
Parameters:
machine(required) — The machine's UUID.dryRun— Resolve the target and report what would be removed without sending the write.
Tools Requiring chat.use (16)
acknowledge_chat_conversation_wake
Acknowledge a conversation's due wake, clearing wokeAt. A snooze whose moment has passed reports wokeAt until this lands or the conversation is opened. Idempotent, and it leaves the conversation's recency untouched.
Parameters:
conversationId(required) — Conversation row UUID.
create_conversation
Start a new chat conversation. It is created EMPTY — nothing runs until send_conversation_message dispatches the first turn. cwd is the working directory the conversation's agent will run in on whichever host executes the turn. The title fills itself in after the first turn unless you set one.
Parameters:
providerName(required) — The chat provider that will run turns.cwd(required) — The working directory the conversation's agent runs in.title— An opening title; omitted, the auto-titler fills it after the first turn.workspaceId— The registered workspace UUID backing the working directory.modeValue— The conversation mode.mode— Deprecated alias for modeValue; pass at most one of the two.seed_context— The guided-creation seed context persisted on the conversation.
fork_conversation
Branch a conversation at one message. Pass EXACTLY ONE of messageIndex (fork including that message) or beforeMessageIndex (fork excluding it). The fork is sliced from the stored transcript server-side and the source conversation is left untouched.
Parameters:
conversation(required) — The source conversation's UUID.messageIndex— Fork INCLUDING the message at this index. Exactly one index argument is required.beforeMessageIndex— Fork EXCLUDING the message at this index. Exactly one index argument is required.
invoke_superpower
Resolve an invokable Superpower (by its row UUID, from list_superpowers) to its system-prompt fragment — the text you prepend to operate as that directs.
Parameters:
id(required) — The Superpower row UUID to resolve to its system-prompt fragment.
list_chat_sidebar_conversations
List Chat sidebar conversations with the server-assigned shelf (settled/snoozed/pinned/inbox), projected agent status, and your per-user unread flag. Reads the working set by default, or the settled archive with settled: true.
Parameters:
settled— Read the settled archive (newest-settled first) instead of the working set. Default false.limit— Page size; max 50 for the working set, 25 for the archive.offset— Zero-based page offset.
list_superpowers
List the Superpowers invokable on a surface (default chat) — the active, surface-enabled building blocks, prompts, system prompts, prompt chains, skills, agents, scripts, and playbooks you can invoke. Returns each one's rowId, human-id, title, type, and Dotabase.
Parameters:
surface— The invocation surface (default chat).
mark_chat_conversation_unread
Mark a conversation unread again for yourself, rewinding your own visit receipt behind its newest activity. Affects only your own unread flag. Idempotent, and a no-op on a conversation that has no activity yet.
Parameters:
conversationId(required) — Conversation row UUID.
run_script
Run a stored Script row synchronously with invocation inputs. Accepts only stored row coordinates, inputs, and an optional idempotency key; transient source is never accepted.
Parameters:
dotabaseId(required) — Dotabase UUID containing the stored Script row.humanId(required) — Stored Script row human-id.inputs(required) — Invocation inputs for the stored Script.idempotencyKey— Optional replay key.
send_conversation_message
Dispatch one turn against an existing conversation and return the appended messages. This RUNS the conversation's configured provider — it is the tool that makes another agent act, so send it deliberately and read the result before sending another. Every retrieval source is off for the turn; the conversation's stored provider and mode are read server-side.
Parameters:
conversation(required) — The conversation's UUID.message(required) — The prompt to send as this turn.cwd(required) — The working directory this turn runs in.model— Override the model for this turn.mode— The mode recorded on the sent turn (defaultdefault).workspaceId— The registered workspace UUID backing this turn's working directory.workspaceMode— How the executor enters the workspace for this turn.reasoningEffort— The reasoning effort for this turn.toolPosture— The tool posture for this turn.
settle_chat_conversation
Settle a conversation, moving it to the archive and clearing any pin in the same write. Idempotent.
Parameters:
conversationId(required) — Conversation row UUID.
snooze_chat_conversation
Snooze a conversation until a given moment. A timed wake only — there is no woken state, and a snooze whose moment has passed simply reads as not snoozed.
Parameters:
conversationId(required) — Conversation row UUID.snoozedUntil(required) — ISO-8601 instant with an offset to snooze until (for example 2026-09-01T09:00:00Z).
stop_conversation
Abort the conversation's in-flight turn and clear anything queued behind it. Safe to call when nothing is running — it reports what it stopped.
Parameters:
conversation(required) — The conversation's UUID.
transcribe
Transcribe an actor-owned staged media file. Expected provider or media degradations return a tool error with the exact reason.
Parameters:
path(required) — Actor-owned staged storage path.mime(required) — Media MIME type.name— Optional display filename.
unsettle_chat_conversation
Return a settled conversation to the working set. Does not restore a pin the settle cleared. Idempotent.
Parameters:
conversationId(required) — Conversation row UUID.
unsnooze_chat_conversation
Clear a conversation's snooze, returning it to the inbox. Idempotent.
Parameters:
conversationId(required) — Conversation row UUID.
visit_chat_conversation
Stamp your visit to a conversation — the per-user unread receipt. Affects only your own unread flag.
Parameters:
conversationId(required) — Conversation row UUID.
Tools Requiring dotabase.delete (1)
delete_dotabase
Delete a Dotabase and everything filed in it — every row, page, saved view, and binding. No action restores it and no export is taken first, so read what it holds before calling. Deleting a Dotabase a second time is answered as a miss rather than a second success. Use delete_row when the intent is to remove rows and keep the store.
Parameters:
dotabase(required) — The Dotabase to delete, by UUID or slug.
Tools Requiring dotabase.read (104)
add_muted_notification_source
Mute one source for this principal: notifications from that entity stop reaching this inbox and are excluded from the unread count and every inbox read. Nothing already delivered is removed, and the source itself is untouched — this is a per-principal filter, never a change to the thing making the noise. Idempotent on the pair: muting an already-muted source reports no change rather than failing.
Parameters:
source_entity_type(required) — The muted source's entity type, exactly as list_notifications reports it (e.g.dotabase_row,automation).source_entity_id(required) — The muted source's UUID.
add_registered_workspace
Register a local directory on this account's workspace registry. Idempotent on the path: adding one that is already registered returns that entry with its name preserved rather than creating a second, and either way the entry becomes the newest-selected one. Registering does not create the directory or check that it exists — the path is stored for the spawn host to resolve. The registry key is (machine, path): pass machineId when the directory lives on a registered machine, and the same path on two machines stays two entries rather than colliding.
Parameters:
path(required) — Absolute path of the directory to register on this account's registry.name— Display name for the entry. Omit to use the path's last segment.machineId— The registered machine this path lives on, from list_machines. The registry key is (machine, path), so the same path on two machines is two entries; omit it for a workspace that names no machine.
archive_notification
Archive one notification. It leaves the unread and all views and stays readable under filter: 'archived', so this is the reversible way to clear something from the inbox — but there is no un-archive action, so the archived is where it lives from now on.
Parameters:
notification(required) — The notification's UUID (list_notifications).
cast_reaction
Cast an up or down vote on one row of a published page as this connection's own anonymous visitor. Casting the same kind again TOGGLES it off and casting the other switches it, so the answer's mine is the authority on where the vote ended up — null means the repeat cleared it. The visitor identity is minted on the first vote and kept for the life of this connection, which is what lets retract_reaction find it again.
Parameters:
slug(required) — The publication slug the row is served under.row(required) — The row's public handle (human id), e.g. IDEA-7.kind(required) — The reaction to cast.
clear_account_avatar
Clear the CALLER'S OWN account avatar. Self-scoped by construction — the principal is the one behind this connection's credential, never a named one — so this cannot touch anybody else's account, and only a human account has an avatar to clear. Setting one is CLI-only (it sends bytes from the operator's own disk): dots account avatar set --file <path>. Pass dryRun: true to preview.
Parameters:
dryRun— Resolve the target and report what would be removed without sending the write.
clear_read_notifications
Archive EVERY read notification in one call — an unbounded set scoped to this principal in the active company. Unread rows are untouched, so mark_all_notifications_read followed by this one empties the whole inbox. Archived rows stay readable under filter: 'archived' and there is no un-archive action. Answers the count actually archived, which is 0 when nothing was read.
coding_agent_backfill_status
How far the coding-agent import has got: each consented source's state and its imported / total / skipped / failed counts, the rolled-up aggregate, and the live dead-letter count of sessions still awaiting a retry. The polled read — call it again rather than assuming a running backfill finished.
coding_agent_consent_evidence
The consent/read ORDERING evidence for consented sources: when each consent was decided and when its backfill reader first ran. A source whose reader has not run leaves its read timestamp ABSENT rather than manufacturing one, so a check that consent preceded every read fails closed on it instead of claiming completion.
connections_gateway_status
Report whether the connector gateway is configured, where its key comes from, and which providers are available to connect right now. Read this before offering a connection flow, so you name providers this instance can actually reach.
count_rows
Count the rows matching a filter, without fetching any of them. The cheap answer to 'how many' — the count is a genuine filtered count over the whole Dotabase, not the size of a page, so it stays exact however large the result is. filters takes the same AST as list_rows; omit it to count the Dotabase.
Parameters:
dotabase(required) — The Dotabase UUID or slug to count rows in.filters— Filter AST, the same shape list_rows takes: condition/group nodes — {type:'condition',property_id,operator,value?} | {type:'group',conjunction:'and'|'or',children:[...]}. Omitted counts every row.archived— Lifecycle scope (default live).
create_row_comment
Comment on a row as this connection's own principal. The author comes from the credential, so no email verification or browser session is involved — this is the only comment path a credentialed caller has, because the public one reads a cookie identity an API key never carries. The spam heuristic can land the comment withheld: the answer reports status (visible or withheld_spam), so read it rather than assuming the comment is live. A row outside this company, or one in a different Dotabase, is not found.
Parameters:
dotabase(required) — The Dotabase holding the row, by UUID or slug.row(required) — The row's public handle (human id), e.g. IDEA-7.body(required) — The comment text (up to 10,000 characters).
current_actor
Who this connection is: the resolved principal, the active company, and the authority the credential carries. Read it before assuming which workspace a write will land in — the active-company selector, not the tool call, decides that. orient answers this plus what the vault holds, in one call.
describe_dotabase
One Dotabase in full: its identity, its human-id prefix, and every property it declares with that property's type and option roster. The read to make BEFORE writing a row — a property key or option id that this answer does not carry is one the write will be refused for.
Parameters:
dotabase(required) — The Dotabase UUID or slug to describe.
detect_coding_agents
What coding-agent session folders (Claude Code, Codex, Cursor) THIS SERVER can see on its own filesystem, folded together with the recorded consent decisions: each folder's key, agent kind, profile path, session count, and whether it is consented. A hosted deployment cannot see the operator's machine, so it reports nothing there — read list_coding_agent_consent for the decisions themselves. Total and safe: a detector fault degrades to an empty result, never an error.
dismiss_notification
Dismiss one notification. It leaves EVERY inbox view — unread, all, and archived alike — and no tool or filter brings it back, so use archive_notification when the row should stay readable. What the notification was ABOUT is untouched: the row, conversation, or automation behind it is not affected.
Parameters:
notification(required) — The notification's UUID (list_notifications).
dotabase_activity
One Dotabase's activity feed, newest first: what changed across its rows and when. Narrow to a single event kind. Use row_activity when the question is about one row rather than the Dotabase.
Parameters:
dotabase(required) — The Dotabase UUID or slug whose feed to read.kind— Narrow to one event kind. The route takes no kind filter, so this narrows the WINDOW this call returned — widenlimitif a match may sit further back.limit— How many events, newest first. Omit for the route's own default.offset— How many events to skip before the window.
export_conversation
Return one conversation's raw stored transcript exactly as persisted — the whole body, unrendered. Use get_conversation instead when you want the readable row rather than the raw record.
Parameters:
conversation(required) — The conversation's human id, e.g. CONVO-8.
find_similar_roadmap_requests
Preview the already-published roadmap items a nascent request would duplicate, and create nothing. It searches ONLY the rows the publication's published views serve, so anything hidden — including every Under Review submission — is absent by construction. Each match carries its public { up, down } tally, or null when reactions are off or unconfigured on that publication: null means the tally is unknown, never that the row has no votes. Use it before submit_roadmap_request to vote on an existing item instead.
Parameters:
slug(required) — The publication slug of the roadmap to search.text(required) — The nascent request's text to match against (up to 4,000 characters).
get_connection
Read one authorized-account connection by its UUID. There is no by-id route, so this reads the workspace's connections and picks the one named — an id this workspace does not carry is a clean not-found.
Parameters:
connection(required) — The connection's UUID.
get_conversation
Read one conversation row in full by its human id, e.g. CONVO-8.
Parameters:
conversation(required) — The conversation's human id, e.g. CONVO-8.
get_dotabase_manual
One Dotabase's Operating Manual: the operator-authored purpose and judgment that frame how its rows should be read and acted on. This is the same guidance that rides tool answers as the DBOM side-channel, addressed directly — read it before writing into an unfamiliar Dotabase.
Parameters:
dotabase(required) — The Dotabase UUID or slug whose Manual to read.
get_entity
Read one row (a ) by its Dotabase + human-id — the canonical follow-up to a search hit: get_entity(result.dotabaseId, result.humanId). Returns the row's title, body, properties, tags, and domains, plus the Dotabase's operating manual (DBOM) in structuredContent. For a LONG body, call get_outline first and pass sections here to read only the sections you need. Reading SEVERAL rows? Make it ONE batch call with a get_entity member per row — the reads use a bounded worker pool and each Dotabase's manual is carried once, where sequential get_entity calls repeat it per call.
Parameters:
dotabase(required) — The Dotabase UUID (a search result's dotabaseId) or its slug.id(required) — The row human-id, e.g. TASK-12.sections— Return only these body sections by ordinal ref from get_outline (e.g. ['2','4.1']); each ref returns its whole subtree. Omit for the full row.level— How much of the row to return:scan= identity only (human_id, title, icon);summaryadds the bounded classification fields and the closed-value-space properties;fulladds every remaining field plus the Markdown body. Defaultfull. The level actually used rides structuredContent.level. Ignored whensectionsis set (that is already a body projection).
get_human_md
Read the active HUMAN.md — the persona/context document the platform grounds agent turns in. Returns the resolved active document(s) so you can operate as the user expects.
get_notification_prefs
The resolved notification preferences for this principal. Unset values answer with their defaults rather than as absent, so this is the effective configuration and not a stored fragment. Read it before set_notification_prefs, which merges over what is stored.
get_onboarding_state
This actor's setup completion status and the key-free answers draft behind it. Says what onboarding has and has not been through, which is often why a workspace looks emptier than expected. Record a step with record_onboarding_state.
get_outline
Read a row or page body's H1-H3 outline — ordinal refs, headings, and per-section word counts — WITHOUT loading the body. The token-saving first read for any long document: outline first, then expand only the sections you need (pass sections here, or to get_entity for a row). Target a row via dotabase + row, or a standalone page via page.
Parameters:
dotabase— The Dotabase UUID or slug (pair withrow).row— The row human-id, e.g. TASK-12 (pair withdotabase).page— A standalone page UUID or slug (instead of dotabase + row).sections— Expand these ordinal refs (whole subtrees) instead of returning the outline — the page-target form of get_entity'ssections.
get_playbook
Get one Power-Up Playbook's sections, members, counts, and persisted retrieval scope by row UUID.
Parameters:
id(required) — Playbook row UUID.
get_project
Read one project in full by its human id, e.g. PROJ-12.
Parameters:
project(required) — The project's human id, e.g. PROJ-12.
get_row_import_status
One row-import execution's progress and outcome. Addressed by its execution id, so it stays readable after the client that started the import disconnected — reconnect and read rather than importing the file again.
Parameters:
dotabase(required) — The Dotabase UUID or slug the import was aimed at.execution(required) — The import execution's id.
get_row_template
Get one page template by its per-Dotabase slug — the section scaffold and its fill instructions, returned as Markdown. Use only a real slug shown by list_row_templates; unaddressed templates cannot be read by this tool. A slug that matches nothing is a successful empty answer (null), not an error.
Parameters:
dotabase(required) — The Dotabase UUID or slug the template lives in.slug(required) — The template's per-Dotabase slug, e.g.bug-report.
get_rows_many
Read MANY rows by UUID, human-id, or exact title in ONE request, instead of a get_entity per row. Identity matches win over titles; found rows keep request order, and misses or duplicate-title ambiguities are reported, so a partial hit is still a useful answer. Bodies are omitted by default (that is what makes the batch affordable); includeBody turns them on under the server-side response byte budget, with overflow returned as truncated ids for re-request.
Parameters:
dotabase(required) — The Dotabase UUID or slug the rows live in.ids(required) — Row UUIDs, human-ids, or exact titles, at most 500 per call. UUID and human-id matches win over titles; misses and duplicate-title ambiguities are reported separately.includeBody— Include each row's body. Body-bearing responses are byte-budgeted server-side; resolved rows that did not fit come back undertruncatedfor re-request.
get_script_capabilities
Read whether stored-Script execution is entitled and the executor's languages, network, filesystem, and integration capabilities.
get_settings
One settings category for THIS PRINCIPAL in the active company, resolved — an unset value answers with its default rather than as absent, so this is the effective configuration. Settings are per-user, so this is not what anyone else sees. Read it before set_settings, which merges over what is stored.
Parameters:
category(required) — Which settings category to read. Absent values answer with their defaults.
get_sync_binding
Read one sync binding: its source, its target Dotabase, its mode and cadence, and its current status with the last error if it has one. The binding alone — for the background enrichment drain behind it, read sync_binding_enrichment.
Parameters:
binding(required) — The sync binding's UUID.
get_task
Read one task in full by its human id, e.g. TASK-42.
Parameters:
task(required) — The task's human id, e.g. TASK-42.
get_view
Get one saved view by its UUID — its name, type, flags, and persisted query state.
Parameters:
view(required) — The saved-view UUID.
home_activity
Read what has been happening in this workspace, newest first — row activity events, each naming its actor and the Dotabase and row it touched. The read for 'what changed recently' and for picking up a thread someone else was pulling. Keyset-paged: pass the nextCursor a page returns to read the next one, and a null cursor means you have reached the end of the feed — not that the page was empty.
Parameters:
limit— How many activity items to return in one page (1-50).cursor— Resume after a previous page — pass thenextCursorthat page returned.
home_growth
Read the per-week new-knowledge series: rolling 7-day buckets anchored at now, zero-filled so a quiet week is an explicit zero rather than a gap, oldest first. Each bucket names the instant its window opened. The final bucket counts the trailing 7 days, so it equals the growthThisWeek home_stats reports — use this when the question is the TREND rather than the current number.
home_jump_back_in
Read the continuity strip — the most recently touched live rows plus the pinned ones, each with its Dotabase slug, human-id, DIIICE category, and when it was last updated. The read for resuming work: it hands you the exact human-ids to pass to get_entity, so you do not have to search for where the user left off.
home_needs_you
Read the actionable queue counts: rows with no edges at all (the graph-orphan set — knowledge that is stored but connected to nothing), rows untouched, unaccessed and uncited past the staleness threshold, and rows never verified. These are counts, not rows: follow an interesting one into list_rows or search to see which rows it covers.
home_stats
Read this workspace's knowledge rollup: how many live rows it stores, how many of those are linked into the graph, how many Dotabases hold them, how many arrived in the last 7 days, and the live-row count in each of the six DIIICE categories. The orienting first read when you do not yet know what this vault contains — the SIZE and shape of it, where list_dotabases gives the map. connectedTotal is never above knowledgeTotal: both come from the same row-lifecycle counters, and the difference is exactly the orphan count needs_you reports.
list_coding_agent_consent
The recorded per-folder coding-agent consent decisions for this workspace, ordered by folder key. Only DECIDED folders appear — an absent folder means no decision was ever recorded, which is never consent, and both absent and dismissed count as unconsented. This is the read a host whose folders the server cannot see uses to recover its own consent memory. The route answers the whole set, so the window is applied to what it returned.
Parameters:
limit— Page size over the returned decisions, 1-500. Omit for every decision.offset— How many decisions to skip before the page. Omit to start at the first.
list_connections
The authorized account connections in this workspace: which provider, which account, and what state each is in. get_connection reads one by id; connections_gateway_status says whether the connector gateway is configured at all. An id here is what revoke_connection takes.
list_conversations
List this workspace's chat conversations, newest page first. Read one in full with get_conversation, or pull its raw stored transcript with export_conversation.
Parameters:
archived— Lifecycle scope (default live).limit— Max rows to return (≤200, default 50 once either paging argument is set).offset— How many rows to skip before the window.
list_derivation_bindings
The standing derivation bindings in this workspace — each one a source Dotabase whose rows are extracted into a target Dotabase as they arrive. Explains rows appearing in a Dotabase nothing wrote to directly. The addressing read: an id here is what toggle_derivation_binding and delete_derivation_binding take.
list_dotabase_behaviors
The behaviors registered on one Dotabase — the automatic actions its rows trigger on create, update, or schedule. Explains why a row gained fields nothing in your call set. Read this before set_dotabase_behaviors, which replaces the whole binding set.
Parameters:
dotabase(required) — The Dotabase UUID or slug whose behaviors to list.
list_dotabase_templates
List the Dotabase TYPES this workspace can add — the built-in templates plus any this company registered — each with its category, target Space, human-id prefix, whether this company already has an instance, and which Dotabase that instance is. This is the read that answers whether a type already exists before provisioning one. The route answers the whole registry with no paging parameter, so the window is applied to what it returned.
Parameters:
limit— Page size over the returned registry, 1-500. Omit for every template.offset— How many templates to skip before the page. Omit to start at the first.
list_dotabases
List the Dotabases you can read — each with its name, slug, human-id, and purpose (from its operating manual). The map of where knowledge lives; then list_rows or search within one.
Parameters:
space_id— Restrict to one Space.is_foundational— Restrict to foundational Dotabases only.
list_entitlements
The capabilities provisioned to this company — the open key space that gates features, distinct from the RBAC permission atoms. A capability absent here is not held, however the caller's role is configured.
list_files
List the file objects stored for this workspace under a key prefix, key-ordered and paged. This is the only read that answers which keys exist, so reach for it before discarding an upload or minting a fresh URL: each key it returns is the exact value those take. A prefix outside this company lists nothing rather than erroring, and an instance whose storage is unconfigured says so.
Parameters:
prefix— Stored-key prefix to list under, e.g.<companyId>/chat— no trailing separator; it carries the stored-key grammar, which refuses an empty segment. Omit for this company's whole object namespace. A prefix outside the company lists nothing.limit— Page size, 1-1000. Omit for the route's default of 100.offset— How many keys to skip before the page. Omit to start at the first.
list_installed_listings
List what this workspace has installed from the marketplace: each listing's slug and type, the version installed, the newest published version, whether an update is available, and which kind of registration it landed as. This is the read that answers whether a capability is already here before reaching for one, and the slugs it returns are what uninstall_listing takes.
Parameters:
limit— Page size over the returned registry, 1-500. Omit for every installation.offset— How many installations to skip before the page. Omit to start at the first.
list_installed_plugins
The plugins installed in this workspace, newest first: name, version, status, and the slots each contributes. Explains capability a bare Dotabase would not have. A name here is what enable_plugin, disable_plugin, and uninstall_plugin take. Installing and upgrading are CLI-only — both post a built plugin directory's bytes from the operator's own machine.
list_muted_notification_sources
The sources this principal has muted — the filter every inbox read and the unread count are already applying, which is why an expected notification can be missing without anything being wrong. A ref here is what remove_muted_notification_source takes.
list_notifications
This principal's notification inbox, muted sources filtered out and expired entries hidden. Cursor-paged: pass the previous answer's cursor to continue. An id here is what mark_notification_read, mark_notification_unread, dismiss_notification, and archive_notification take.
Parameters:
filter— Which slice of the inbox to read. Omit for the route's own default,unread.limit— Page size, 1-50. Omit for the route's default.cursor— The opaque cursor a previous page returned. Omit for the first page.
list_pages
The standalone pages in this workspace's sidebar, with their Space and their place in the tree. The addressing read for the page family: an id here is what get_outline, the body composes, and the page writes take.
list_projects
List this workspace's projects, newest page first. Filter by workflow status and page with limit/offset. Projects are the platform-internal Projects Dotabase, so a project reads and writes like any row — this tool is the shortcut that already knows which Dotabase and which status vocabulary.
Parameters:
status— Narrow to these workflow statuses (values OR together).archived— Lifecycle scope (default live).limit— Max rows to return (≤200, default 50 once either paging argument is set).offset— How many rows to skip before the window.
list_providers
Render the local-agent provider availability snapshot the App Shell's provider gate reads: per provider, whether it is available, its transport (binary, gateway, or api), whether its binary was detected, and its auth status. Read this before offering a provider or model choice, so you name ones this instance can actually reach. An instance whose composition wired no availability probe answers an EMPTY snapshot — that is an unwired probe, not a machine with no providers.
list_publications
What this workspace has published to the web, newest first: each publication's slug, the views whitelisted into it, and its status. The slug here is what every anonymous public read is addressed by, and the id is what unpublish_publication takes. The addressing read for the publish plane — check it before create_publication so an existing publication is amended rather than duplicated under a second slug.
list_registered_workspaces
List the local directories this account has registered as workspaces, newest-selected first — the head is the default working directory a new conversation starts in. These are per-USER registrations, not tenants: each is a folder on the operator's machine, and the registry is what the Chat composer's directory control reads. The route answers the whole registry in one read, so there is no paging.
list_row_templates
List a Dotabase's page templates — each entry shows its title, source kind, and either its usable slug or an explicit unaddressed marker. Provide the Dotabase by UUID or slug. Only a real slug can be used with get_row_template; read an addressed template before writing a row so the body matches the section contract.
Parameters:
dotabase(required) — The Dotabase UUID or slug to list page templates from.
list_rows
List rows from one Dotabase with filters, sorts, full-text search, and pagination (the query DSL). Returns the matched rows + total, plus the Dotabase's operating manual (DBOM) in structuredContent.
Parameters:
dotabase(required) — The Dotabase UUID or slug to read rows from.filters— Filter AST: condition/group nodes — {type:'condition',property_id,operator,value?} | {type:'group',conjunction:'and'|'or',children:[...]}.sortsgrouptext— Full-text search over the rows.archived— Lifecycle scope (default live).verifiedpaginationmetadata_identity— Filter machine-stamped metadata identities by path and exact value. This is separate from declared-property filters and ANDs with every other query field.level— How much of each row to return:scan= identity only (human_id, title, icon);summaryadds the bounded classification fields and the closed-value-space properties;fulladds every remaining field. Defaultsummary— survey atscan/summary, then read a chosen row in full with get_entity. The level actually used rides structuredContent.level.
list_spaces
The Spaces in this workspace — the top-level sidebar groupings that Dotabases and standalone pages are filed under. A Space id here is what move_dotabase, create_page, and list_dotabases' space_id filter take.
list_sync_bindings
Every sync binding in this workspace — each a configured flow from a local folder or an external resource into a Dotabase, with its target, mode, cadence, and status. The addressing read: an id here is what get_sync_binding, sync_binding_enrichment, the pre-import target update, the run, and the pause / resume pair take.
list_tag_categories
List the workspace tag categories and their display settings.
list_tasks
List this workspace's tasks, filtered by workflow status and paged with limit/offset. Read one project's tasks as a tree with task_tree instead when you want the shape of the work rather than a flat page.
Parameters:
status— Narrow to these workflow statuses (values OR together).archived— Lifecycle scope (default live).limit— Max rows to return (≤200, default 50 once either paging argument is set).offset— How many rows to skip before the window.
list_view_widgets
List a dashboard view's widgets by the view UUID — each widget's id, type, title, and layout.
Parameters:
view(required) — The dashboard-view UUID whose widgets to list.
list_views
List a Dotabase's saved views — each view's id, name, and whether it is the default. Provide the Dotabase by UUID or slug. A saved view is a stored query (filter + sorts + grouping) over a Dotabase's rows.
Parameters:
dotabase(required) — The Dotabase UUID or slug to list saved views from.
mark_all_notifications_read
Mark EVERY visible unread notification read in one call — an unbounded set scoped to this principal in the active company, matching what list_notifications shows under filter: 'unread' (muted sources and expired rows are already excluded, so those are untouched). Answers the count actually marked, which is 0 when nothing was unread. Individually recoverable with mark_notification_unread, but only one row at a time.
mark_notification_read
Mark one notification read. It leaves the unread badge and the default unread inbox view but stays readable under filter: 'all', and mark_notification_unread puts it back. A row already read is re-stamped rather than refused, so a repeat is safe; an id this principal does not own is a typed miss — the inbox is per-principal, never workspace-wide.
Parameters:
notification(required) — The notification's UUID (list_notifications).
mark_notification_unread
Return one notification to unread, undoing mark_notification_read. It reappears in the default inbox view and the unread badge. Reversible in both directions and safe to repeat; nothing about the notification's content changes.
Parameters:
notification(required) — The notification's UUID (list_notifications).
memory_recall
Recall what this vault already knows about a topic, ranked across all three rule-bearing stores at once — the Memory Bank (MEM-N), Lessons (LESSON-N), and Guardrails (GUARD-N). The right first call before non-trivial work on a surface, and after two failed attempts at the same obstacle: the answer is a fused citation list, each row identified by the prefix that names its store. A store this workspace does not carry is reported as absent and skipped rather than failing the recall. type narrows to the alone, Lessons and Guardrails declaring no memory type.
Parameters:
query(required) — What to recall (hybrid keyword + semantic).type— Narrow to these memory types (values OR together). Any value narrows the corpus to the Memory Bank — Lessons and Guardrails declare no memory type.limit— Max fused results (≤100, default 20).level— How much of each recalled row to return:scan= identity only (human_id, title);summaryadds the bounded classification properties;fulladds the memory's own text. Defaultsummary— recall atsummary, then read a chosen row in full with get_entity. The level actually used rides structuredContent.level.
orient
Answer where you are, in one call — run this first in a workspace you do not know. It composes the grounding reads rather than repeating them: the endpoint this connection targets, who the credential is (principal, kind, role, tier), which company is active plus every company the credential can reach, the foundational Dotabase slugs to write memories and artifacts into, the knowledge rollup, the actionable queue counts, the rows to resume from, the unread notification count, the pending approval queue, how fresh the code graph is, and the instance's serving readiness. Only the identity read is required: a source this credential is not authorized for — the readiness report needs jobs.manage, the approval queue needs access.approvals.decide — is OMITTED from the result and named in unavailable with its status, so a narrow credential still gets everything else and a successful answer. Use the individual tools to go deeper into anything this surfaces.
permission_catalog
The workspace's permission vocabulary: every permission atom, which are Dotabase-scoped versus workspace-scoped, which are owner-reserved, and the baseline atom set each system role carries. Read this before reasoning about who can do what — a role's authority is its baseline plus its grants, and guessing an atom name that does not exist reads as a denial rather than an error.
provider_models
Read one provider's curated model catalog and its configured default — the list the composer's Model picker offers, each entry saying whether selecting it preserves tool capability and which reasoning-effort levels it accepts. An instance with no model-list handle wired, or a provider whose key is unset, answers a typed unavailability naming the provider; an upstream catalog fault is a bad gateway. Neither echoes a key.
Parameters:
provider(required) — Provider name: claude-code, codex, cursor, openrouter, hermes, or openclaw. A name outside that set is refused at the request boundary.
public_manifest
One publication as the WEB sees it: which views are whitelisted into it, and the engagement it carries. The addressing read for the published plane — a view id here is what public_rows takes. Use this to check what a published page actually exposes before assuming a vault row is or is not visible.
Parameters:
slug(required) — The publication's slug, aslist_publicationsreturned it.
public_row
One published row by its human-id, projected through its publication's whitelist. The published counterpart of get_entity: same row, only the fields publication exposes.
Parameters:
slug(required) — The publication's slug.row(required) — The row's human-id, as published.
public_row_neighbors
The published rows around one published row, walked across this company's publications and projected through each one's OWN whitelist. The published counterpart of graph_row_neighborhood — it answers what a reader can follow from a page, which is a narrower graph than the vault's.
Parameters:
slug(required) — The publication's slug.row(required) — The row's human-id, as published.hops— How many hops out to walk (1-3). Omit for the route's default. Each node is projected through its OWN publication's whitelist.
public_rows
One whitelisted view's published rows, paged. This is the PUBLISHED projection, not the vault row: only whitelisted fields survive, so a property present in list_rows can be absent here — and that absence is the answer to what a reader can see.
Parameters:
slug(required) — The publication's slug.view(required) — The whitelisted view's id, as the manifest returned it.page— Zero-based page index. Omit for the first page.
public_search
Search the published subset — this publication alone, or every publication this company has published. What a site visitor's search would return, which is why it answers differently from search over the same words: only published, whitelist-projected rows are in scope.
Parameters:
slug(required) — The publication's slug.query(required) — The search text, 1-200 characters.scope— Search this publication alone, or every publication this company has published. Omit for the route's default.limit— Max hits, 1-50 (default 20).
reaction_tally
Read the public { up, down } vote tally on one row of a published page — the same counts a visitor sees. Anonymous: the publication resolves the company, and an unknown slug, a row no published view serves, or a publication with reactions switched off all answer the same not-found rather than disclosing which. A deployment that configures no engagement secrets answers unavailable instead.
Parameters:
slug(required) — The publication slug the row is served under.row(required) — The row's public handle (human id), e.g. IDEA-7.
record_onboarding_state
Record one setup step's answers for this actor. The slice MERGES into the stored draft, so send only the step you just completed — the rest is left as it was, and re-sending the same slice converges rather than duplicating. This is a per-actor record within the company: nothing another member sees changes. Sending completedAt is what flips the run complete, which the answer reports. The store owns its envelope fields (version, writtenAt, source) and the server injects the scope, so an unknown key is refused with nothing written rather than silently dropped.
Parameters:
deployMode— How this instance is deployed, as the setup run answered it.licenseValidated— Whether the run validated a license key.workspace— The workspace step's answers: provisioning, Space ref, insights view.agents— Per coding agent: which were detected and which were offered an install.pluginInstall— The plugin-install step: whether it was offered, by which method, and completed.concierge— The concierge step: agent-driven, tracks skipped, artifacts accepted.repoIngest— The repo-ingest step: not ingested, or the path plus its graph-metrics outcome.completedAt— ISO timestamp marking the whole run complete. Sending it is what flipscomplete.
remove_muted_notification_source
Unmute one source, so its notifications reach this inbox again. The mute record is dropped permanently — add_muted_notification_source restores it, but nothing suppressed while the mute stood is recovered. Removing a source that was not muted reports no change rather than failing.
Parameters:
source_entity_type(required) — The muted source's entity type, exactly as list_muted_notification_sources reports it.source_entity_id(required) — The muted source's UUID.
remove_registered_workspace
Remove one entry from this account's workspace registry. The directory on disk is untouched — only the registration goes, and re-adding its path registers it again. An id this account's registry does not hold is a clean not-found. Pass dryRun: true to preview.
Parameters:
workspace(required) — The registry entry's UUID.dryRun— Resolve the target and report what would be removed without sending the write.
rename_registered_workspace
Rename one registry entry. The registered path is unchanged, so this only affects how the entry is labelled.
Parameters:
workspace(required) — The registry entry's UUID.name(required) — The entry's new display name. The path is unchanged.
report_row_comment
Report a comment for moderation as this connection's own principal. Deduped by the REPORTING PRINCIPAL, so reporting the same comment twice answers deduped: true and records nothing new — a repeat is safe, not a second strike. Scoped to the exact row: a comment attached to a different row is not found. Read the queue these land in with list_reported_comments, and act on one with remove_row_comment.
Parameters:
dotabase(required) — The Dotabase holding the row, by UUID or slug.row(required) — The row's public handle (human id) the comment sits on.commentId(required) — The comment's UUID.reason— Optional short note stored on the report (up to 500 characters).
rescan_providers
Re-probe the local-agent binaries and re-wire any newly detected adapters, answering the freshly probed snapshot in the same shape list_providers returns. Reach for this after a provider CLI has been installed or authenticated and list_providers still reports it missing. An instance with no re-scan hook wired answers a typed unavailability.
resolve_invite
Read what an invite token is FOR: the workspace's display name and the role the invitee would land with. Pre-authentication and read-only — it accepts nothing and changes nothing, and a token matching no pending invite is a clean miss that never says which half was wrong.
Parameters:
token(required) — The raw invite token (adots_invite_string). It rides the request body, never the URL.
resolve_ref
Resolve a bare row human-id — ART-3436, TASK-12, MEM-88 — to the row it names, WITHOUT knowing which Dotabase it lives in. Reach for this whenever an id turns up in a conversation, a document, or another row's body and you would otherwise have to guess or hunt for its Dotabase. The lookup is company-wide and filtered to what this credential may read, so an id you cannot reach comes back as a clean miss rather than someone else's row. Use get_entity instead once you already know the Dotabase, and search when you have words rather than an id.
Parameters:
ref(required) — A row human-id, e.g. ART-3436 or TASK-12. No Dotabase is needed: the resolver searches the whole company and returns only rows this credential may read.level— How much of the resolved row to return:scan= identity only (human_id, title, icon) — the cheapest answer when all you wanted was the address;summaryadds the bounded classification fields and closed-value-space properties;fulladds every remaining field plus the Markdown body. Defaultfull. The level actually used rides structuredContent.level.
resolve_row
Turn a row's TITLE into its human-id, inside a Dotabase you name. The counterpart to resolve_ref: reach for that one when you hold an id, and this one when you hold the words a row is called. An exact title wins, else a unique prefix, else the single row whose title contains what you gave; anything else comes back as a list of candidates, never a guess. Use search when you have a topic rather than a title.
Parameters:
dotabase(required) — The Dotabase UUID or slug the row lives in.title(required) — A title, or enough of one to identify the row: an exact match wins, else a unique prefix, else the sole row whose title contains it. Anything else comes back as an ambiguous list rather than a guess.
retract_reaction
Remove this connection's own vote from one row of a published page. Idempotent: retracting with nothing cast leaves the tally unchanged and answers mine: null either way. It removes only this connection's vote — the row's other votes are untouched — and it can only find a vote cast through this same connection.
Parameters:
slug(required) — The publication slug the row is served under.row(required) — The row's public handle (human id), e.g. IDEA-7.
row_activity
List ONE row's activity events, newest first: creation, status and tag changes, edge writes, title and embedding changes. The event log beside row_versions' content snapshots — this says what happened to the row, that says what the row said. total counts the row's complete history regardless of the requested page.
Parameters:
dotabase(required) — The Dotabase UUID or slug the row lives in.row(required) — The row's human-id — the feed is narrowed to this row.limit— How many of this row's events to return, newest first.offset— Row events to skip, newest first.
row_versions
List a row's version-history snapshots, newest first — what the row looked like at each save, who changed it, and when. Reach for it to see how a row got to its current state, or to recover wording an edit replaced. total counts every snapshot regardless of the page you asked for.
Parameters:
dotabase(required) — The Dotabase UUID or slug the row lives in.row(required) — The row's human-id.limit— Snapshots per page (default 50, max 1000).offset— Snapshots to skip, newest first.
scaffold_dotabase_schema
The canonical system-property scaffold a new Dotabase's schema starts from — title, edges, embedding, each carrying its config.system_field — served from the one server-side authority. Read this BEFORE create_dotabase and send what it returns as the head of initial_properties; pass your own definitions as properties and they are appended after it, with a key that collides with a system key refused. This is a read: nothing is created and no schema is touched.
Parameters:
properties— Your own property definitions, appended AFTER the system scaffold. A key that collides with a system key is refused — system properties are never hand-rolled or overridden.
search
Search the Dots vault across every readable Dotabase — notes, tasks, memories, conversations, code symbols, docs. Hybrid keyword + semantic, access-filtered. Returns matched rows (human-id + Dotabase + title + snippet) so you can follow a hit into get_entity / list_rows; scope to a Dotabase via filters.dotabaseIds, or to a 's curated member rows via playbook. For an organization-specific or unfamiliar proprietary term, scope this search to the Glossary Dotabase to resolve its definition before relying on your own guess. If the Glossary returns nothing, run this search again UNSCOPED across the whole vault — the term is often captured in another Dotabase with no Glossary row written for it yet, and a single distinctive word can match where the full phrase does not. Report what that sweep finds to the user. Only when both come back empty, use create_row when that tool is available; otherwise tell the user the term needs a definition.
Parameters:
query(required) — Natural-language or keyword query.scope— An entity-type scope, e.g. a Dotabase template kind.playbook— Narrow to a Power-Up Playbook's curated member rows: a PLAYBOOK-N human id or its row UUID (e.g. from list_superpowers). Its access-filtered scope resolves on themcpsurface and rides filters.rowIds (ANDed with filters.dotabaseIds when both are set).filters— Narrow by Dotabase, DIIICE type, domain, tag, source, recency, lifecycle, verification.sort— Result ordering (default relevance).limit— Max results (≤50, default 20).cursor— Keyset pagination cursor from a prior page.level— How much of each result line to return:scan= id, type, and title only;summaryandfulladd the match snippet. Defaultsummary. The level actually used rides structuredContent.level.
search_dotabase_rows
Search ONE Dotabase's rows, with the matching mode in your hands: keyword, semantic against the stored vectors, or hybrid. Cursor-paged and verification-scopable. Use search when the question spans the whole vault; use this when you already know the Dotabase and want to control how matching works.
Parameters:
dotabase(required) — The Dotabase UUID or slug to search inside.query(required) — The search text.mode— How to match:keywordis lexical,semanticreaches the stored vectors,hybridfuses both. Omit for the route's keyword default. Usesearchinstead to sweep every Dotabase at once.verified— Narrow to one verification state. Omit for both.sort— The route's sort token.limit— Max hits (default 50).cursor— The cursor a previous page returned.
select_registered_workspace
Make one registry entry the default working directory. There is no set-default route: selecting touches the entry's last-selected timestamp, and the registry is ordered newest-selected first, so the selected entry becomes the head of list_registered_workspaces.
Parameters:
workspace(required) — The registry entry's UUID.
set_notification_prefs
Set this principal's notification mute preferences — the per-category mute axes and the browser-notification toggle. A MERGE: a field you omit keeps its stored value, so read get_notification_prefs first and send only what changes. At least one field is required. Muting a category stops NEW notifications in it from reaching this inbox; nothing already delivered is removed.
Parameters:
muteChat— Mute the chat category.muteAutomations— Mute the automations category.muteSystem— Mute the system category.browserNotificationsEnabled— Whether the browser surfaces OS-level notifications.
set_settings
Write one settings category for THIS PRINCIPAL in the active company. Settings are per-user: nothing here changes what another member sees, and the same call in a different active company writes a different row. A one-level deep MERGE — a field you omit keeps its stored value, and the nested appearance a11y object merges the same way — so read get_settings first and send only what changes. The fields are category-specific and validated against that category's own schema before any request, so a field from the wrong category is refused rather than sent. The integrations composioApiKey is write-only: it is never echoed back, and the answer reports only whether a key is set.
Parameters:
category(required) — Which settings category to write.settings(required) — The fields to merge, validated against the named category's own schema. appearance: colorMode ('light'|'dark'|'system'), accentColor (a DIIICE category), a11y ({ reducedMotion, highContrast, focusRingStyle, skipLink }). profile: displayName. integrations: composioApiKey (write-only; null clears). personalization: default_human_md_row_id (uuid or null), human_md_injection_enabled. marketplace: accountToken, accountHandle, marketplaceApiUrl (each nullable). Read get_settings first — omitted fields keep their stored values.
sign_file
Re-sign a stored object's URL. Stored URLs expire, so a path read off a row's file property or a listing needs re-signing before it can be fetched. Company-scoped: the key must sit under this company's own prefix, so this is never an existence oracle for anyone else's objects.
Parameters:
path(required) — The full stored object key, exactly aslist_filesreturned it (<companyId>/<key>). The signed URL it answers with is short-lived.
sync_binding_enrichment
Report how far one binding's deferred enrichment has drained: how many of its imported rows still await an embedding or a classification. Answers applicable: false when the binding's rows are not a single-target markdown set, in which case the counts carry no meaning. Read this when an import has landed but semantic search or typing still looks incomplete.
Parameters:
binding(required) — The sync binding's UUID.
task_tree
Read one project's tasks as a single level: each task's human id, title, raw status, and the ids it is blocked by. The cheapest way to see what a project holds and what is unblocked right now.
Parameters:
project(required) — The project's human id, e.g. PROJ-12.
unread_notification_count
The unread badge count for this principal, with muted sources excluded — the cheap poll when all you need is whether anything is waiting, rather than what.
usage_summary
Read what this workspace has spent: totals, a per-bucket series, per-provider attribution, the costliest conversations and automations, and cost-cap spend by source. Per-provider attribution is APPROXIMATE and says so through byProviderApproximate — a conversation's whole usage is attributed to its current provider, because the stored aggregate carries none per turn. An imported transcript with no priced usage contributes zero cost rather than a fabricated figure, and a workspace with no Automations Dotabase reports conversations only rather than failing. Report the approximation when you report the numbers.
Parameters:
bucket— Granularity of the per-bucket series. Omit to take the route's own default.from— Start of the window, inclusive — an ISO-8601 date or instant, resolved to its UTC calendar day.to— End of the window, inclusive — an ISO-8601 date or instant, resolved to its UTC calendar day.
workspace_plan
Read the active company's billing plan tier (free, pro, or enterprise) — the tier the Settings plan display shows. Low-sensitivity workspace metadata: the billing customer binding is not on this read.
Tools Requiring dotabase.rows.create (20)
bulk_create_rows
Create many rows () in one Dotabase from an array of row-create bodies — the fast path for writing back a batch of enrichment knowledge. Accepts up to 5,000 rows and sends them in bounded 500-row requests. A per-row failure does not strand the batch; returns compact identity receipts + the per-row errors (index, code, message). Pass dryRun: true first on a large manifest to validate every row against the real write path and insert nothing. Honor the Dotabase's DBOM schema + judgment before writing.
Parameters:
dotabase(required) — The Dotabase UUID or slug to create the rows in.rows(required) — An array of row-create bodies ({ title?, body?, properties?, tags? }). Up to 5000, sent 500 per request.dryRun— Validate every row against the real create-time write path and insert NOTHING, so a large manifest is proven never to partial-write before any row is created. The ONLY bulk write with a server dry-run contract.
cancel_row_import
Cancel a running Dotabase CSV import. An import that has not started yet is killed outright and its staged file is discarded; one already in flight is asked to stop at its next checkpoint, so rows it has ALREADY written stay written — a cancel is not an undo. An execution that had already finished, failed, or been cancelled is left exactly as it was and its own status is the answer. Starting an import is CLI-only (it reads a file off the operator's machine); reading one is get_row_import_status, which is where the execution id comes from.
Parameters:
dotabase(required) — The Dotabase UUID or slug the import was aimed at.execution(required) — The import execution's id, exactly asget_row_import_statusreports it.
create_derivation_binding
Bind a standing derivation rule: from now on, every new or changed row of the source Dotabase is run through the extractor and lands in the target. A backfill over the EXISTING source rows runs at bind time by default so the target is not empty until the next live row; a backfill that fails leaves the binding in place and reports the failure beside it. Registering the same source, extractor, and target again updates that rule rather than creating a second one.
Parameters:
source(required) — Source Dotabase, by UUID, human id, or slug.target(required) — Target Dotabase the derived rows land in, by UUID, human id, or slug.extractor(required) — The extractor to run on every new or changed source row.enabled— Whether the rule fires. Defaults on.backfill— Run one pass over the EXISTING source rows at bind time so the target is not empty until the next live row. Defaults on. A backfill failure leaves the binding in place and rides back as a note.config— Extractor configuration — a flat bag of string / number / boolean values.
create_page
Create a standalone page inside a Space. A page is a long-form document that lives in the sidebar rather than in a Dotabase — use create_row for a Dotabase row. The slug is derived from the name server-side; parent nests the new page under an existing one. Write its body afterwards with append_page_body.
Parameters:
name(required) — Title of the new page. Its slug is derived from this server-side.space(required) — The Space the page belongs to, by UUID or slug.parent— Parent page (UUID or slug) to nest the new page under. Omit for a top-level page.icon— Icon token for the page.iconColor— Icon color token for the page.
create_project
Create a project. status is validated against the closed workflow roster before any request; omitted, it lands on the roster's own default (planning). Tenant and creator are injected server-side. Use properties for any slot this tool has no dedicated argument for.
Parameters:
title— The project title.body— The project's detail, authored as Markdown.status— The workflow status. Defaults toplanning, mirroring the Projects roster's own default option.properties— Any further property values as typed row envelopes, for slots this family declares no dedicated argument for. The dedicated arguments win on a key collision.idempotency_key— Retry key for this create. Calling again with the same key returns the row the first call created instead of a duplicate; reusing it with changed content is refused as a conflict.
create_row
Create a new row (a DOT) in a Dotabase. Provide the Dotabase by UUID or slug, plus any of title, body, typed property envelopes, and tags. Returns the created row + the Dotabase's operating manual (DBOM) in structuredContent. Honor the DBOM's schema + judgment before writing.
Parameters:
dotabase(required) — The Dotabase UUID or slug to create the row in.title— The row title.body— The row body. Agents should author Markdown; TipTap JSON remains accepted for backward compatibility with editor-authored rows.properties— Typed property envelopes keyed by property key: { <key>: { type, value } }.tags— Bare tag labels.idempotency_key— Retry key for this create. Calling again with the same key returns the row the first call created instead of a duplicate; reusing it with changed content is refused as a conflict.
create_superpower
Author a new Superpower of one kind — a Prompt, Building Block, System Prompt, Prompt Chain, Playbook, Skill, Script, or Agent. The kind decides which store the row lands in, so no Dotabase is named: the tool resolves that store and provisions it from its template when this workspace has none yet. The row is created as a draft; pass status in properties to override. Pass an idempotencyKey when a retry must not produce a second row. Returns the created row and its human-id, which is what update_superpower and invoke_superpower take.
Parameters:
kind(required) — Which kind of Superpower to author. Fixes the store the row is created in.title— The Superpower's title.properties— Typed row envelopes.statusdefaults to the create status; pass it here to override.idempotency_key— Optional replay key: a repeat with the same key answers the first row.
create_task
Create a task. status, priority, and due are validated before any request; assignee, project, parent, and blockedBy take human ids and are resolved to row pointers, so a reference that does not exist is refused rather than stored as a dangling id. Tenant and creator are injected server-side.
Parameters:
title— The task title.body— The task's detail, authored as Markdown.status— The workflow status.priority— The priority, p0 (most urgent) to p3.due— Due date asYYYY-MM-DDor a full ISO-8601 instant.assignee— An Agents row human id to assign, e.g. AGENT-3. Resolved to a row pointer.project— The parent project's human id, e.g. PROJ-12.parent— The parent task's human id, e.g. TASK-42.blockedBy— Task human ids this task is blocked by, e.g. ['TASK-7','TASK-9'].properties— Any further property values as typed row envelopes, for slots this family declares no dedicated argument for. The dedicated arguments win on a key collision.idempotency_key— Retry key for this create. Calling again with the same key returns the row the first call created instead of a duplicate; reusing it with changed content is refused as a conflict.
delete_derivation_binding
Delete a standing derivation binding. The rule stops firing permanently and its configuration is gone; rows already derived through it stay exactly where they are. Use toggle_derivation_binding when the rule should pause rather than be discarded. Deleting it twice is answered as a miss, not a second success.
Parameters:
binding(required) — The binding's UUID, from list_derivation_bindings.
duplicate_page
Duplicate a page, body and all, beside the original.
Parameters:
page(required) — The page to duplicate, by UUID or slug.
duplicate_row
Copy a row into a new row of the same Dotabase. The copy is live and carries its own freshly-minted human-id; the original is untouched. Reach for it to start from an existing row rather than authoring one from scratch — a filled-in template, a recurring checklist, a variant of a spec.
Parameters:
dotabase(required) — The Dotabase UUID or slug the row lives in.id(required) — The human-id of the row to copy.
instantiate_row_template
Create a new live row from a page template — a fresh human id, the template's body and property values, and every create behavior fires. The template is unchanged. Returns the new row's navigation identity; read the full row with get_entity. Address the template by its per-Dotabase slug or its UUID.
Parameters:
dotabase(required) — The Dotabase UUID or slug the template lives in.template(required) — The template's per-Dotabase slug or UUID.
memory_save
Save one durable memory to this vault's Memory Bank — a decision, an observation, a failure, a stated preference — so a later session recovers it. Give it a title that states the claim in one line and a body that carries the detail and the evidence. It SEARCHES the Bank first and refuses a near-duplicate, naming the MEM-N ids it found and writing nothing: reinforce or update one of those instead, or pass force: true when the new memory really is distinct. Lifecycle, review schedule, and confidence are seeded server-side — send only the claim, its detail, its type, and its scope.
Parameters:
title(required) — The memory's claim — the line it is cited by.body— The memory's detail, authored as Markdown.type(required) — The memory type. Validated before any request; an unlisted value is refused.scope— The memory's visibility scope.force— Save even when the Memory Bank already holds a near-duplicate. Default false: a near-duplicate is refused with the MEM-N ids it found and nothing is written.idempotency_key— Retry key for this create. Calling again with the same key returns the row the first call created instead of a duplicate; reusing it with changed content is refused as a conflict.
move_rows
Move rows to a different Dotabase. Each moved row is REISSUED a human-id in its new home, so references to the old one stop resolving, and its property values are remapped onto the destination's schema — a value whose key the destination does not declare is not carried over. Call it with dryRun: true first: the route answers with the per-row preview naming exactly which keys map and which are dropped, and persists nothing.
Parameters:
dotabase(required) — The Dotabase UUID or slug the rows are moving out of.ids(required) — Row human-ids or UUIDs to move, at most 100 per call. A longer list is refused here rather than sent.to(required) — The destination Dotabase UUID or slug.dryRun— Ask the route for the per-row remap preview — the destination, the property keys that map, and the keys that do not — persisting nothing.
record_stage_artifact
Record one pipeline stage's completion: create the Artifacts row for it and draw its provenance edges — the authoring Conversation that produced it, and the initiative anchor it belongs to. Reach for this instead of create_row whenever the row IS a stage completion: both types are system-only, so a plain row create cannot draw them and the record would land unlinked. Anchoring to a Projects row also derives a project:N tag and fills the project relation, and an optional task links the work item — but only when that task already belongs to the anchor Project, so a task from another project is refused rather than cross-linked. Stage completions are immutable records: a re-run writes a SECOND row, it does not update the first. An edge that fails to draw is reported per step with the row still created.
Parameters:
stage(required) — The pipeline stage this artifact completes.artifactType— Optional explicit artifact type. Omit for the stage's canonical type; a type belonging to another stage is refused.title(required) — The artifact row's title.body(required) — The artifact body, as Markdown.origin(required) — The surface that produced it. Required — a guessed origin is a fabricated fact.anchorRowId(required) — UUID of the initiative anchor row the artifact attaches to. A Projects row additionally derives a project tag and relation.sourceConversationRowId— Optional authoring Conversation row UUID. Omitted means NO provenance edge is drawn rather than a guessed one.task— Optional Tasks row (TASK-N or UUID). Admitted only when its own project relation points at the anchor Project.tags— Optional extra tags. A tag contradicting a derived project:/task: tag is refused.
run_derivation
Run one cross-Dotabase derivation now: read every row of the source Dotabase, run the named extractor, and create the derived rows in the target. Synchronous and one-pass — it answers a report of what was scanned, derived, skipped, failed, and whether the pass was truncated. The extractor's declared source kind must match the source Dotabase's slug or the run is refused. Use create_derivation_binding when the rows should keep arriving rather than be derived once.
Parameters:
source(required) — Source Dotabase to read rows from, by UUID, human id, or slug.target(required) — Target Dotabase the derived rows land in, by UUID, human id, or slug.extractor(required) — The extractor to run. Its declared source kind must match the source Dotabase's slug, or the run is refused.config— Extractor configuration — a flat bag of string / number / boolean values.
save_row_as_template
Save an existing row as a new page template: its body, icon, layout key, and the property values the Dotabase schema still declares are copied into a fresh template under the title you give. The source row is never touched, and the new template has no slug — address it by the UUID this returns until one is seeded.
Parameters:
dotabase(required) — The Dotabase UUID or slug the source row lives in.row(required) — The source row to copy — its canonical human id (e.g.BUG-12) or UUID.title(required) — Title for the new page template.
submit_roadmap_request
File a feature request into a Roadmap Dotabase as this connection's own principal. The row lands in the hidden Under Review lane every published roadmap view filters out, so it is INVISIBLE on the public page until an operator moves it — do not expect it back from find_similar_roadmap_requests. Tenant and creator are injected server-side; the answer carries the landed row's human id so you can read, link, or flip it. Run find_similar_roadmap_requests first: this tool does no dedup of its own.
Parameters:
dotabase(required) — The Roadmap Dotabase to file into, by UUID or slug.title(required) — The request title (up to 256 characters).body— Optional request detail (up to 10,000 characters).
toggle_derivation_binding
Enable or disable a standing derivation binding without deleting it. A disabled binding stops firing and keeps its configuration and its last-run stamp, so re-enabling resumes the same rule — nothing already derived is removed either way. Setting it to the state it is already in is answered by the route as it stands, not as a second change.
Parameters:
binding(required) — The binding's UUID, from list_derivation_bindings.enabled(required) — Whether the rule fires from now on.
upsert_row
Create a row, or update the one already carrying this EXACT title. The upsert key is the title, matched case-insensitively but exactly — a prefix or substring never counts — so re-running the same call updates the row it made the first time instead of minting a second. Two rows already sharing the title is an error naming both, never a third row. Use create_row when you want a new row regardless, and update_row when you hold the human-id. Returns the row + the Dotabase's operating manual (DBOM).
Parameters:
dotabase(required) — The Dotabase UUID or slug to upsert the row in.title(required) — The row title. It is BOTH the match key and, on a create, the new row's title. Matching is case-insensitive but EXACT — a prefix or substring never counts.body— The row body, replacing the stored body when an existing row matched. Agents should author Markdown.properties— Typed property envelopes keyed by property key: { <key>: { type, value } }.tags— Bare tag labels.idempotency_key— Retry key for the CREATE arm only: when no row matches the title, calling again with the same key returns the row the first call created instead of a duplicate. An update match ignores it (the title match already makes the update idempotent).
Tools Requiring dotabase.rows.delete (11)
consolidate_rows
Ask for duplicate rows to be folded into one primary row you name. This REQUESTS the merge — the route publishes the consolidation onto the event bus and answers accepted; the fold itself is performed afterwards by the Dotabase's bound consolidation behavior, so a successful call is not a completed merge. Read the primary back to see the result. The duplicates lose their separate existence: their content is merged into the primary and their own human-ids stop naming live rows, so references to them stop resolving. Every duplicate human-id is resolved to a real row before anything is published, and one that matches nothing fails the whole call.
Parameters:
dotabase(required) — The Dotabase UUID or slug every row involved lives in.id(required) — The human-id of the PRIMARY row — the one that survives.duplicates(required) — Human-ids of the duplicate rows to fold into the primary. Each is resolved to its UUID before the request, so a name that matches nothing fails before anything is published. The route caps the set; a longer list is refused there.
delete_conversation
Archive a conversation, or hard-delete it with purge: true. Archiving is reversible from the app; a purge is not, and takes the transcript with it. Pass dryRun: true first to see exactly which row would go.
Parameters:
conversation(required) — The conversation's human id, e.g. CONVO-8.purge— Hard-delete instead of archiving. Default false: the conversation is archived.dryRun— Resolve the target and report what would be removed without sending the write.
delete_page
Delete a page, its body, and EVERY page nested under it — the delete cascades down the sidebar subtree, and no action reverses it. Read get_outline first if you are unsure what the page holds.
Parameters:
page(required) — The page to delete, by UUID or slug.
delete_project
Permanently delete a project. This removes the row itself, not its status — nothing restores it, and tasks that referenced it keep a dangling relation. Pass dryRun: true first to see exactly which row would go.
Parameters:
project(required) — The project's human id, e.g. PROJ-12.dryRun— Resolve the target and report what would be removed without sending the write.
delete_row
Soft-delete (archive) a row by its Dotabase + human-id. The row becomes archived, not destroyed; it can be restored. Reports the archived count (0 when the row was already gone or archived).
Parameters:
dotabase(required) — The Dotabase UUID or slug the row lives in.id(required) — The row human-id, e.g. TASK-12, to archive (soft-delete).
delete_row_template
Delete a page template by its per-Dotabase slug or UUID. Rows already created from it are copies and survive; no action restores the template. A template this company does not carry is a typed not-found, so a repeat delete reports the miss rather than succeeding silently.
Parameters:
dotabase(required) — The Dotabase UUID or slug the template lives in.template(required) — The template's per-Dotabase slug or UUID.
delete_superpower
Permanently delete a Superpower row by human-id. Destructive.
Parameters:
id(required) — Superpower row human-id, such as SKILL-3.
delete_task
Permanently delete a task. The row goes and nothing restores it; tasks blocked by it keep a dangling dependency. Pass dryRun: true first to see exactly which row would go.
Parameters:
task(required) — The task's human id, e.g. TASK-42.dryRun— Resolve the target and report what would be removed without sending the write.
discard_file
Remove a stored file object that was never committed to a row, page, or property — the cleanup for an abandoned upload. The bytes go and nothing restores them. Removal is idempotent, so an already-absent key succeeds the same way and nothing here reveals whether an object stood behind it. Pass dryRun: true to preview.
Parameters:
path(required) — The full stored object key to remove, exactly as a listing returned it (<companyId>/<key>).dryRun— Resolve the target and report what would be removed without sending the write.
purge_row
Hard-delete (purge) a row by its Dotabase + human-id. The row is permanently removed and cannot be restored. Reports the purged count (0 when the row was already gone).
Parameters:
dotabase(required) — The Dotabase UUID or slug the row lives in.id(required) — The row human-id, e.g. TASK-12, to hard-delete permanently.
uninstall_listing
Remove an installed listing's registration from this workspace. What the install created — the rows, templates, and Spaces — stays where it landed; what goes is the registration binding them to the listing, and installing it again is the only way back. Installing itself is CLI-only. Pass dryRun: true to preview.
Parameters:
slug(required) — The installed listing's slug, exactly aslist_installed_listingsreturns it inlistingSlug.dryRun— Resolve the target and report what would be removed without sending the write.
Tools Requiring dotabase.rows.update (28)
add_playbook_members_bulk
Add snapshot rows or one live reference to a Playbook section. Pass dryRun: true to validate and preview with zero writes.
Parameters:
id(required) — Playbook row UUID.members(required)dryRun— Validate the request and report the planned write without sending a write request.
append_page_body
Append Markdown to the end of a page's body. Safe by construction: the existing document is read, the new blocks are added to it, and the write carries the page's compare-and-set token, so a page someone edited in between is REFUSED (ROW_UPDATE_CONFLICT) rather than overwritten — re-run to compose against the current page. Every existing node is preserved, including content Markdown cannot represent.
Parameters:
page(required) — The page whose body to append to, by UUID or slug.markdown(required) — Markdown appended as new blocks at the end of the body.
bulk_update_rows
Apply ONE change set to MANY rows in a single request — the fast path for a property backfill, a re-tag, or a status sweep. Address the rows by UUID (a list_rows row's id, a search hit's entityId), and pass the shared edit in changes; every listed row receives exactly that edit, so a per-row edit still belongs in update_row. The reply is DELIBERATELY COMPACT — counts plus per-row success/conflict receipts and any request-wide failure, never row bodies. A receipt's persisted flag distinguishes a refused write from an update that committed before later effects were skipped. Re-read a row with get_entity when you need its full post-update state. Honor the Dotabase's operating manual (read it from any list_rows / get_entity call) before writing.
Parameters:
rowIds(required) — The row UUIDs to update — theidon a list_rows row or theentityIdon a search hit, NOT the human-id. Up to 1000, sent 100 per request.changes(required) — ONE change set applied to EVERY row in rowIds; unset fields are left alone.expectedUpdatedAtById— Optional optimistic-concurrency guard: each rowId mapped to theupdated_atyou read it at. Every rowId must appear; a row that moved since is refused rather than overwritten.
complete_project
Mark a project completed — the one-argument form of setting its status to completed. Use update_project to move it to any other state.
Parameters:
project(required) — The project's human id, e.g. PROJ-12.
complete_task
Mark a task completed — the one-argument form of setting its status to completed. Use flip_task when you want to record the commit and a log line in the same write.
Parameters:
task(required) — The task's human id, e.g. TASK-42.
derive_conversation_usage
Backfill the token and cost aggregate onto conversations that predate the current derivation, so usage_summary can price them. Re-running only sweeps what is still stale; a conversation whose transcript carries no priced usage is a counted skip rather than a fabricated figure.
Parameters:
limit— Cap how many stale conversations this sweep backfills.
flip_task
Advance a task atomically: set its status, stamp a commit SHA, and append one line to its body log in ONE transaction. Pass at least one of the three. The status is validated server-side against the LIVE Tasks roster, so it cannot drift from what the board actually offers.
Parameters:
task(required) — The task's human id, e.g. TASK-42.status— The status to set. Validated server-side against the live Tasks roster.sha— A commit SHA to stamp on the task.log— One line appended to the task's body log.
list_reported_comments
One Dotabase's reported-comment queue, most-reported first, with the report reasons attached. The moderation read: what readers have flagged and why. Act on one with remove_row_comment.
Parameters:
dotabase(required) — The Dotabase UUID or slug whose report queue to read.
list_row_comments
The comments on one Dotabase's rows with their FULL fields — author, status, body — rather than the PII-stripped public projection. Narrow to one row or one moderation status. A comment id here is what remove_row_comment takes.
Parameters:
dotabase(required) — The Dotabase UUID or slug whose comments to read.row— Narrow to one row's human-id.status— Narrow to one moderation status. Omit for every status.
move_page
Move a page in the sidebar — into another Space, under another parent, or to another position among its siblings. Pass parent: null to make a nested page top-level.
Parameters:
page(required) — The page to move, by UUID or slug.space— Destination Space, by UUID or slug.parent— New parent page (UUID or slug); null makes the page top-level.position— New 0-based position among its siblings.
pin_row
Pin or unpin a row so it surfaces first in its Dotabase. The flag is SET, not toggled — pinned: true on an already-pinned row succeeds and changes nothing — so it is safe to call without reading the row first.
Parameters:
dotabase(required) — The Dotabase UUID or slug the row lives in.id(required) — The row's human-id.pinned(required) — true pins the row, false clears the pin. The flag is SET, never toggled.
reinforce_row
Record a spaced-repetition review of a memory and advance its schedule — the third move beside memory_save and memory_recall, and the only one that changes what a recall will surface next. Reach for it after recalling a memory and finding it still true: the review updates the row's FSRS stability and difficulty and moves its next review date out, and a memory whose schedule never advances decays out of the ranked recall. grade says how well it held up (1 Again … 4 Easy); omitted, it takes the source's default. Omit dotabase for the Memory Bank, or name any other FSRS-carrying Dotabase — one without that schema is refused, not silently skipped. The answer carries the new FSRS state and whether the memory's status band moved with it.
Parameters:
id(required) — The row's human-id — a MEM-N for the Memory Bank.dotabase— The Dotabase UUID, slug, or human-id the row lives in. Omit for the Memory Bank, which is what a memory review means. Any other Dotabase must carry the FSRS schema or the route refuses the call.grade— The FSRS review grade: 1 Again (it did not come back), 2 Hard, 3 Good, 4 Easy. Omit to take the source's default —explicitgrades Easy,user_referencegrades Good.source— Where the review came from:explicitis a deliberate review (the default),user_referenceis the weaker signal a mention carries. It selects the default grade and is recorded with the review.
remove_row_comment
Hide one comment from a published row's public list — the moderation action behind list_reported_comments. The comment is flipped to hidden rather than deleted, so it stays in the moderation reads while no visitor sees it; there is no un-hide. Scoped to the exact row: a comment attached to a different row is not found, which is also how a wrong row id fails rather than removing something else. Removing an already-hidden comment succeeds and leaves it hidden.
Parameters:
dotabase(required) — The Dotabase holding the row, by UUID or slug.row(required) — The row's public handle (human id) the comment sits on.commentId(required) — The comment's UUID.
replace_page_section
Replace one page-body section — its heading through its whole subtree — with new Markdown. Address the section by the ordinal ref get_outline returns; refs are positional, so read the outline first and use it immediately. Everything outside that section is preserved untouched, and the write carries the page's compare-and-set token, so a page edited in between is REFUSED rather than overwritten.
Parameters:
page(required) — The page whose section to replace, by UUID or slug.ref(required) — Ordinal ref of the section to replace, from get_outline (e.g. '2' or '4.1'). Refs are positional against the outline you read.markdown(required) — Markdown replacing the whole section, including its new heading.
restore_row
Bring an archived row back to live. The exact inverse of delete_row, which archives rather than deletes; a row that was already live comes back as a no-op success. Use purge_row's hard delete only when the row must not be recoverable at all.
Parameters:
dotabase(required) — The Dotabase UUID or slug the row lives in.id(required) — The archived row's human-id.
set_code_area_signature
Stamp one Code Area row's rule-derived membership signature — the lowercase 64-hex digest the post-push reconciler computes over the files that area's rules currently match. Setting it to the same digest converges rather than erroring, so a re-run is safe. The property is writer-authority protected: this is the only path that writes it, and update_row cannot. A human-id that is not a kind: area Code Area row is refused rather than stamped.
Parameters:
area(required) — The Code Area row's human id, such as AREA-4.membershipSignature(required) — The lowercase 64-hex SHA-256 digest of the area's rule-derived membership.
set_row_template_property
Set one property value on a page template — the default a row instantiated from it starts with. Send the RAW value; the server wraps it in the typed envelope its schema declares for the key and validates it there. A key the Dotabase schema does not declare, or a value its type rejects, is refused with the reason.
Parameters:
dotabase(required) — The Dotabase UUID or slug the template lives in.template(required) — The template's per-Dotabase slug or UUID.propertyKey(required) — The property key as declared on the Dotabase schema. An undeclared key is refused.value— The RAW property value. The server wraps it in the typed envelope the schema declares for this key and validates it there, so never send a { type, value } envelope.
unverify_row
Withdraw a row's human-verified mark, clearing both the verifier and the timestamp. The exact inverse of verify_row, and it removes only the mark — the row's content, tags, and edges are untouched. Unverifying a row that carried no mark succeeds and clears nothing.
Parameters:
dotabase(required) — The Dotabase UUID or slug the row lives in.id(required) — The row's human-id.
update_page
Rename a page or change its slug, icon, or icon color. Body edits do NOT go here: use append_page_body or replace_page_section, which preserve the rest of the document.
Parameters:
page(required) — The page to update, by UUID or slug.title— New page title.slug— New page slug (the addressable handle).icon— New icon token; null clears it.iconColor— New icon color token; null clears it.
update_playbook_members
Apply one member operation to a Playbook: add, edit its note, move, or remove. Remove is destructive.
Parameters:
id(required) — Playbook row UUID.operation(required)
update_playbook_retrieval_scope
Set a Playbook's graph-expansion retrieval scope: expand, depth, and optional edge-type allowlist. Pass at least one field.
Parameters:
id(required) — Playbook row UUID.expand— Whether graph expansion is enabled.depth— Expansion depth, 1 or 2.edge_types— Optional edge-type allowlist.
update_playbook_sections
Apply one section operation to a Playbook: add, rename, delete, or reorder. Delete is destructive when it drops members.
Parameters:
id(required) — Playbook row UUID.operation(required)
update_project
Update a project's title, body, status, or any other property. Title and body are written through the row fields route and the properties through the row update route, so sending both is two writes against the same row. Only the arguments you pass are touched.
Parameters:
project(required) — The project's human id, e.g. PROJ-12.title— The new title.body— The replacement detail, authored as Markdown.status— The new workflow status.properties— Any further property values as typed row envelopes, for slots this family declares no dedicated argument for. The dedicated arguments win on a key collision.
update_row
Update an existing row's title, body, and/or typed property envelopes by its Dotabase + human-id. Only the fields you pass are changed. For a surgical body edit that never rewrites the whole document, pass bodyAppend (append one line) or bodyReplaceSection (replace one heading-named section, its new content in body) — these reroute to the atomic body endpoints and are used on their own; bodyAppend carries a generated operation UUID for transport-replay safety. Returns the updated row + the Dotabase's operating manual (DBOM).
Parameters:
dotabase(required) — The Dotabase UUID or slug the row lives in.id(required) — The row human-id, e.g. TASK-12.title— New title.body— New body. Agents should author Markdown; TipTap JSON remains accepted for backward compatibility with editor-authored rows.properties— Typed property envelopes to set: { <key>: { type, value } }.metadata— Machine-bookkeeping bag merged per-top-level-key into the row's metadata: enrichment summaries { enrichment: { summary, summary_model, summary_at } }, etc.force— Overwrite even if the stored body has non-markdown nodes that would be lost.bodyAppend— Append this line as a new paragraph to the row's body (atomic; never rewrites the existing body). The tool attaches one operation UUID, making a transport replay a no-op while a later identical tool call remains distinct. Reroutes to the append endpoint instead of a full-body replace; provide EITHER bodyAppend OR bodyReplaceSection, not both, and not alongside title/properties/metadata/force.bodyReplaceSection— Replace the body section under this exact heading; the new section content (INCLUDING its heading) is passed asbody. Reroutes to the section-replace endpoint; provide EITHER bodyAppend OR bodyReplaceSection, not both, and not alongside title/properties/metadata/force.expected_updated_at— Apply this edit only if the row is still at this revision — theupdated_atfrom the read this edit is based on. A row changed by someone else since then is refused with ROW_UPDATE_CONFLICT instead of overwritten. Ignored on the bodyAppend / bodyReplaceSection paths, which are atomic server-side.
update_row_template
Edit a page template's own fields — title, body scaffold, icon, icon colour, layout key. Only the fields you pass change, null clears a nullable one, and at least one is required. Rows already created from the template are copies and are not rewritten.
Parameters:
dotabase(required) — The Dotabase UUID or slug the template lives in.template(required) — The template's per-Dotabase slug or UUID.title— New template title.body— New body scaffold as Markdown; null clears it.icon— New icon token; null clears it.icon_color— New icon colour token; null clears it.layout_key— New layout registry key (lowercase letters, digits, underscore, dot; first character a letter); null clears it.
update_superpower
Update a Superpower row by human-id, changing its title, typed properties, or both. Pass at least one field.
Parameters:
id(required) — Superpower row human-id, such as SKILL-3.title— New title.properties— Property updates as typed row envelopes.
update_task
Update a task's title, body, or any of its scheduling and relation properties. Only the arguments you pass are touched; relation arguments re-resolve their targets, so passing blockedBy REPLACES the existing dependency set rather than adding to it.
Parameters:
task(required) — The task's human id, e.g. TASK-42.title— The new title.body— The replacement detail, authored as Markdown.status— The new workflow status.priority— The new priority.due— Due date asYYYY-MM-DDor a full ISO-8601 instant.assignee— An Agents row human id to assign, e.g. AGENT-3. Resolved to a row pointer.project— The parent project's human id, e.g. PROJ-12.parent— The parent task's human id, e.g. TASK-42.blockedBy— Task human ids this task is blocked by, e.g. ['TASK-7','TASK-9'].properties— Any further property values as typed row envelopes, for slots this family declares no dedicated argument for. The dedicated arguments win on a key collision.
verify_row
Mark a row human-verified — the stamp that says a person stood behind its content. The row records WHO verified it and WHEN, both taken from your own credential and never from an argument. Verifying an already-verified row succeeds and re-stamps the timestamp to now, so the mark always says when it was last affirmed rather than when it was first made. unverify_row is the exact inverse.
Parameters:
dotabase(required) — The Dotabase UUID or slug the row lives in.id(required) — The row's human-id.
Tools Requiring dotabase.schema.manage (8)
add_schema_property
Add one or more property declarations to a Dotabase's schema. Purely additive: every existing property rides through untouched, and a key that is already declared is refused rather than overwritten — use replace_dotabase_schema when the intent really is to change an existing declaration. The current schema is read and replaced under a compare-and-set token, so a schema edited in between is REFUSED (SCHEMA_UPDATE_CONFLICT) rather than clobbered.
Parameters:
dotabase(required) — The Dotabase to add properties to, by UUID or slug.properties(required) — The property definitions to APPEND. Purely additive: a key already declared is refused, so an append never overwrites an existing property.
apply_option_roster
Edit a select / multi_select / status property's option roster: add, rename (display name), recolor, delete, and reorder options in ONE ordered batch. The ops are merged against the CURRENT roster under a row lock, so concurrent non-conflicting edits all survive and you never need to read-modify-write the roster yourself. Read the current option ids with list_dotabases or a row's DBOM before a rename, recolor, delete, or reorder — each of those targets an existing id, a reorder must name EVERY id, and a miss is refused (OPTION_ROSTER_CONFLICT). Deleting an option rewrites no row: rows that selected it keep the raw id with no label behind it, so delete only ids nothing has selected.
Parameters:
dotabase(required) — The Dotabase whose option roster to edit, by UUID or slug.property(required) — Key of the option-bearing property to edit (a select, multi_select, or status property).ops(required) — Ordered delta ops applied against the CURRENT roster under a row lock, so concurrent non-conflicting edits all survive. Each op reads the list its predecessors produced, so one call can add, rename, recolor, delete, and reorder together.
instantiate_dotabase_template
Provision a Dotabase from a registered template into the Space that template targets — the target is resolved server-side from the template, so there is no Space argument. SINGLE-INSTANCE IDEMPOTENT: calling it again on an already-provisioned single-instance template returns the existing Dotabase with created: false rather than a second copy. A non-built-in template requires an admin actor.
Parameters:
template(required) — The template id, exactly aslist_dotabase_templatesreturns it (a dotted lowercase id, e.g.forge.skill).name— Display name for the new Dotabase, overriding the template's own. The human-id prefix is not overridable on a single-instance built-in.
remove_schema_property
Remove one property from a Dotabase's schema. The declaration goes and every row's stored value under that key stops being declared, so it stops surfacing anywhere — re-declaring the same key brings the values back. The current schema is read and replaced under a compare-and-set token, so a schema someone else edited in between is REFUSED (SCHEMA_UPDATE_CONFLICT) rather than overwritten. Every other property rides through unchanged.
Parameters:
dotabase(required) — The Dotabase to remove a property from, by UUID or slug.property(required) — Key of the property to remove.
rename_schema_property
Rename a property's KEY, rewriting every stored reference in ONE server-side transaction: each row's value, every saved-view filter and sort, every dashboard-widget query, and the page-property config. This is the only safe way to change a key — a whole-schema replace that renames one strands every stored value under the old key. The display name is not touched. A collision with a declared key, an unknown key, a system field, a template-protected property, and a key a formula references are each refused with their own code.
Parameters:
dotabase(required) — The Dotabase holding the property, by UUID or slug.property(required) — The property's CURRENT key.new_key(required) — The new key. Letters, digits, and underscores only; a key already declared is refused.
reorder_schema_properties
Reorder a Dotabase's property array — the schema's column order. Pass EVERY declared key in the order you want; a list that omits, repeats, or invents a key is refused rather than silently dropping properties. Nothing is added, removed, or retyped, and the replace carries a compare-and-set token so a concurrent schema edit is refused rather than overwritten.
Parameters:
dotabase(required) — The Dotabase whose property order to change, by UUID or slug.keys(required) — EVERY declared property key in its new order. The array IS the schema's column order, so a list that omits, repeats, or invents a key is refused rather than dropping properties.
replace_dotabase_schema
Replace a Dotabase's WHOLE property array in one write — the tool for a multi-property edit that add_schema_property, remove_schema_property, rename_schema_property, retype_schema_property, and reorder_schema_properties would take several calls to make. Read the current array with describe_dotabase, edit it, and send it back: anything you leave out is DROPPED and anything whose type you change is RETYPED, so both are refused unless you pass force, with the affected keys named. Omit properties entirely to re-send the current array unchanged, which is how agent_write_guidance is set alone. The replace carries a compare-and-set token from the same read, so a schema someone else edited in between is REFUSED (SCHEMA_UPDATE_CONFLICT) rather than overwritten.
Parameters:
dotabase(required) — The Dotabase whose schema to replace, by UUID or slug.properties— The WHOLE property array this Dotabase will declare. Read the current one with describe_dotabase and send it back edited — anything you leave out is dropped. Omit it to re-send the current array unchanged, which is how you set guidance alone.agent_write_guidance— Workspace-authored redirect text carried on a REQUIRED_PROPERTIES_MISSING refusal — name the workflow that collects this Dotabase's required properties. Omit to keep the stored text; empty string clears it.force— Admit a replace that DROPS or RETYPES a declared property. Without it such a replace is refused with the affected keys named, so a partial array can never silently delete declarations.
retype_schema_property
Flip a property between the value-compatible select and status types under ONE transaction. Only that pair is reachable: they share the stored option-id representation, so no row value is migrated and none is lost. It is still a declaration change with reach — a status→select flip drops the workflow grouping (category) every option carries, and a status property whose options declare a status-only key is refused outright rather than flipped lossily. Every other type change is refused; rebuild through replace_dotabase_schema instead, which loses the stored values.
Parameters:
dotabase(required) — The Dotabase holding the property, by UUID or slug.property(required) — Key of the property to retype.target_type(required) — The type to flip to. Only the value-compatible select ⇄ status pair is reachable — every other type change is refused.
Tools Requiring dotabase.settings.manage (5)
approve_dotabase_manual_proposal
Accept the Manual proposal a staleness pass drafted for a Dotabase: its proposed judgment is promoted into the live judgment as a new version. Takes nothing but the Dotabase — the text is the one already drafted, so read it through get_dotabase_manual before accepting. A Dotabase with no Manual is not found; one with no pending proposal is refused as unprocessable rather than silently doing nothing, so a second approve of the same draft says so.
Parameters:
dotabase(required) — The Dotabase UUID or slug whose pending Manual proposal to accept.
move_dotabase
Move a Dotabase into a Space at an exact sidebar position. This is placement only: the Dotabase's rows, their human ids, and its schema are untouched, unlike move_rows, which rehomes rows and reissues their ids. Omit position to land it last. Re-running the same call converges on the same placement.
Parameters:
dotabase(required) — The Dotabase to move, by UUID or slug.space(required) — Destination Space, by UUID or slug.position— 0-based slot among the destination Space's sidebar items. Omit to land last.
set_dotabase_behaviors
Replace a Dotabase's WHOLE behavior binding set — the automatic actions its rows trigger on create, update, or schedule. Read the current set with list_dotabase_behaviors, edit it, and send it back: anything you leave out is UNBOUND, which is why the tool takes the full set rather than a patch. Each behavior validates its own config on apply; a toggle-only binding sends config: {}.
Parameters:
dotabase(required) — The Dotabase whose bindings to replace, by UUID or slug.bindings(required) — The WHOLE binding set this Dotabase will carry. Read the current one with list_dotabase_behaviors and send it back edited — anything you leave out is unbound. Toggle-only callers sendconfig: {}.
update_dotabase
Change a Dotabase's settings: its name, description, icon, and the DIIICE and embedding toggles, plus which markdown-import normalizer it uses. Only the fields you pass are touched. This is settings only — the schema is edited with the schema tools, and sidebar placement with move_dotabase. Turning embedding on makes this Dotabase's rows eligible for the embedding backfill; it does not embed them synchronously.
Parameters:
dotabase(required) — The Dotabase to update, by UUID or slug.name— New display name.description— New description; null clears it.icon— New icon token; null clears it.icon_color— New icon color token; null clears it.diiice_enabled— Turn DIIICE classification on or off.embedding_enabled— Turn embedding on or off. Flipping it on makes this Dotabase's rows eligible for the embedding backfill job.import_normalizer_key— New markdown-import normalizer key; null clears it back to the resolver default.import_normalizer_config— Declarative config for the named import normalizer.
update_dotabase_manual
Edit a Dotabase's Manual — the purpose framing it and the judgment telling an agent how to read and act on its rows. Pass at least one of the two; the one you omit is left as it was. Every accepted edit bumps the Manual version, keeps the prior text as a version row, restamps the schema hash, and CLEARS any pending staleness-drafted proposal — so editing discards a proposal you have not read. Read get_dotabase_manual first, and approve_dotabase_manual_proposal instead when the pending draft is what you want.
Parameters:
dotabase(required) — The Dotabase UUID or slug whose Manual to edit.judgment_md— New judgment markdown — how an agent should read and act on this Dotabase's rows.purpose— New one-line purpose framing the Dotabase.
Tools Requiring dotabase.views.manage (13)
create_view
Create a saved view on a Dotabase: a name plus the persisted query state ({ filter, sorts, group?, groupSort? }). Optionally set an icon, description, and view type (e.g. dashboard). Returns the created view.
Parameters:
dotabase(required) — The Dotabase UUID or slug to create the view on.name(required) — The view name.icon— Optional icon token.description— Optional description.viewType— Optional view type, e.g. table | dashboard.seed_starter_widgets— For a dashboard view: seed the schema-derived starter widgets on create. Default off.state
create_view_widget
Add a widget to a dashboard view by the view UUID: a widget_type (bar | line | donut | stat | gauge | heatmap | distribution | table), an aggregate query, and a grid layout, plus optional title, icon, display, and appearance. Gauge requires display.target as a finite number. Returns the created widget.
Parameters:
view(required) — The dashboard-view UUID to add the widget to.widget_type(required) — The widget type.title— Optional widget title.icon— Optional icon token.query(required) — The widget's aggregate query.display— Per-type display config. Required for gauge: { target: finite number }; optional for other types.appearance— Optional appearance overrides.layout(required) — Grid placement { x, y, w, h } (clamped server-side into the per-type span rules).
delete_view
Delete a saved view by its UUID. Permanent — the view and its config are removed.
Parameters:
view(required) — The saved-view UUID to delete.
delete_view_widget
Remove a widget from a dashboard view by the view + widget UUIDs.
Parameters:
view(required) — The dashboard-view UUID the widget lives on.widget(required) — The widget UUID to remove.
duplicate_view
Duplicate a saved view by its UUID, optionally naming the copy. Returns the new view.
Parameters:
view(required) — The saved-view UUID to duplicate.newName— Optional name for the duplicate.
reorder_view
Reorder a saved view within its Dotabase by its UUID and a new zero-based position.
Parameters:
view(required) — The saved-view UUID to move.newPosition(required) — New zero-based position within the Dotabase.
set_default_view
Set a Dotabase's default saved view (the view opened by default). Identify the Dotabase and the view UUID.
Parameters:
dotabase(required) — The Dotabase UUID or slug the view belongs to.view(required) — The saved-view UUID to mark default.
set_view_column_widths
Set a saved view's Table column-width overrides — a { propertyKey: pixels } map. Identify the view by its UUID.
Parameters:
view(required) — The saved-view UUID.columnWidths(required) — Table column-width overrides: { propertyKey: pixels }.
set_view_display_config
Set a saved view's Layout-panel display config — card size/layout, property-chip + entity-icon toggles, conditional color, gallery cover, and board lane tint. An additive partial; unset keys derive their defaults. Identify the view by its UUID.
Parameters:
view(required) — The saved-view UUID.displaySettings(required) — The Layout-panel display config — an additive partial; unset keys derive their defaults.
set_view_flag
Set a saved-view boolean flag by its UUID: is_pinned | is_private | is_protected | autosave_for_me, to true or false.
Parameters:
view(required) — The saved-view UUID to flag.flag(required) — The boolean flag to set.value(required) — The flag value.
set_view_property_config
Set a saved view's per-view property config — the ordered { key, hidden? } list controlling which properties show and in what order. Identify the view by its UUID.
Parameters:
view(required) — The saved-view UUID.propertySettings(required) — Ordered per-view property config: { key, hidden? } entries.
update_view
Update a saved view by its UUID — any of name, icon, description, view type, and persisted query state. Only the fields you pass change.
Parameters:
view(required) — The saved-view UUID to update.name— New view name.icon— New icon token.description— New description.viewType— New view type.state
update_view_widget
Update a widget's config and/or layout by the view + widget UUIDs. Only the fields you pass change; the widget type is preserved, and a replacement gauge display requires a finite display.target.
Parameters:
view(required) — The dashboard-view UUID the widget lives on.widget(required) — The widget UUID to update.title— New title (null clears it).icon— New icon token (null clears it).query— New aggregate query.display— Replacement per-type display config; a gauge display requires { target: finite number }.appearance— New appearance overrides.layout— Partial grid placement to move/resize the widget.
Tools Requiring graph.edges.create (4)
bulk_create_edge_pairs
Create exactly the edges you list — one element per edge, each with its own sourceId, targetId, and edgeType (plus optional targetDotabase, reasoning, and metadata). Use this instead of bulk_create_edges whenever the edges are sparse or mix verbs: bulk_create_edges writes the whole cartesian product of sourceIds x targetIds under ONE verb, which a heterogeneous campaign cannot express. Re-running is safe — an existing pair is left untouched and counted as skipped; returns the created + skipped counts.
Parameters:
dotabase(required) — The Dotabase UUID or slug the source rows live in.pairs(required) — The exact edges to create — one element per edge ({ sourceId, targetId, edgeType, targetDotabase?, reasoning?, metadata? }), at most 500.
bulk_create_edges
Create many edges in one request from row UUIDs: every edge in the cartesian product of sourceIds x targetIds gets edgeType (and the optional reasoning). With targetDotabase the targets resolve in that Dotabase (the cross-Dotabase form). The fast path for writing back a batch of enrichment edges; returns the created + failed counts and every created edge id.
Parameters:
dotabase(required) — The Dotabase UUID or slug the source rows live in.edgeType(required) — Edge type label applied to every created edge.sourceIds(required) — Source row UUIDs (the edge tails).targetIds(required) — Target row UUIDs (the edge heads).targetDotabase— Resolve the target UUIDs in this Dotabase (UUID or slug) — the cross-Dotabase form.reasoning— Optional rationale persisted on every created edge.
create_edge
Create one knowledge-graph edge between two rows by their human-ids (semantic enrichment): implements / documents / references and the like. The source resolves in dotabase; with targetDotabase the target resolves in that Dotabase (the cross-Dotabase form). Both Dotabases must belong to your company; the edge keeps each endpoint's edge_count in sync. Returns the created edge id.
Parameters:
dotabase(required) — The Dotabase UUID or slug the source row lives in.source(required) — Source row human-id (the edge's tail), e.g. SYM-12.target(required) — Target row human-id (the edge's head), e.g. ART-3.edgeType(required) — Edge type label, e.g. implements | documents | references.targetDotabase— Resolve the target human-id in this Dotabase (UUID or slug) — the cross-Dotabase form.reasoning— Optional free-text rationale persisted on the edge.ifAbsent— Treat an already-drawn pair as success instead of a conflict: the edge is created if missing, and an existing one is left untouched and reported as already present. Makes a re-draw safe to retry. Omitted, a duplicate pair fails.
graduate_edge
Graduate a lesson into a guardrail by resolving both canonical Dotabases and rows server-side.
Parameters:
lesson(required)guardrail(required)
Tools Requiring graph.edges.delete_any (1)
delete_edge
Permanently delete one knowledge-graph edge by UUID.
Parameters:
edgeId(required)
Tools Requiring graph.edges.update (1)
update_edge
Patch one edge's mutable reasoning, confidence, weight, or metadata fields.
Parameters:
edgeId(required)reasoningconfidenceweightmetadata
Tools Requiring graph.read (25)
callees_of
List the code symbols the given symbol CALLS (outgoing calls edges) — what it depends on.
Parameters:
symbol(required) — A SYM-N human-id or a friendly <path>#<qualifiedName> reference.limit— Maximum symbols returned (max 500).
callers_of
List the code symbols that CALL the given symbol (incoming calls edges) — who depends on it. symbol is a SYM-N human-id or a <path>#<qualifiedName>.
Parameters:
symbol(required) — A SYM-N human-id or a friendly <path>#<qualifiedName> reference.limit— Maximum symbols returned (max 500).
context
The 1-hop categorized neighborhood of a symbol: every incident edge (calls / inherits / defines / …) with its direction, category, confidence, and the neighbor node.
Parameters:
symbol(required) — A SYM-N human-id or a friendly <path>#<qualifiedName> reference.limit— Neighbors per page (default 500, max 500).cursor— Resume after a previous page — thenextCursorthat page returned.
detect_changes
Report the ingested repositories' state — name, root path, remote URL, last-ingested commit SHA, and when each was last updated. To refresh the graph after code changes, run dots repo ingest <path> in a shell (this tool does NOT trigger a re-ingest).
diff
What changed between two commits and what depends on it: the commit range (base-exclusive, head-inclusive), the changed files, the live and retired symbols those files define, and the dependent blast radius. Attribution is FILE-grain — precision states what that costs, each symbol's attribution says how it was attributed, and graphSkew is non-null when the graph was not built from head.
Parameters:
base(required) — The base commit SHA, EXCLUSIVE of the range — a full 40-char SHA or a ≥4-char hex abbreviation.head(required) — The head commit SHA, inclusive — same ref forms asbase.repository— Narrow SHA resolution to one repository — the Git Commitsrepositoryvalue (org/repoor a checkout basename). Resolves an abbreviation matching several repositories.hops— Dependent-walk depth over the changed set (default 2, max 5).
edge_census
Count active edges incident to a Dotabase, optionally grouped or filtered by type.
Parameters:
dotabase(required)typegroupBy
edge_types
List the active edge vocabulary, optionally filtered by category or endpoint kind.
Parameters:
categorysourceKindtargetKind
enrich_candidates
The code↔doc pairs an enrichment pass would judge: both endpoints, the embedding similarity, the pagerank tier, and whether an accepted-verb edge (implements / documents / references) already joins them. READ-ONLY — it judges nothing; write your verdicts back with create_edge or bulk_create_edge_pairs. Page by passing the previous meta.nextCursor, and stop when meta.hasMore is false; feed the pairKeys you judged back as excludedPairKeys so the next page refills instead of shrinking. A page never splits one doc anchor's shortlist, so it can come back shorter than limit (or longer, when limit is below that shortlist's size) — a short page is NOT the end of the sweep; only hasMore:false is. That means the scanned anchor window is exhausted, not that the final page is empty or every pair has been judged. Doc BODIES are not on the wire: read one with get_entity when the titles and signatures are not enough to judge. judged counts an existing code→doc edge even if it was later pruned, and does NOT count an edge drawn doc→code.
Parameters:
repositoryExternalId— Bound the code endpoints to one repository's active subgraph — its canonicalrepo:source key. Absent scans every repository in the company.repositoryPathPrefix— Narrow candidates to one repo-relative file or directory prefix. Requires repositoryExternalId.sourcePlatform— The repository's source platform. Defaults togit.excludedPairKeys— The pairKeys you already judged, dropped BEFORE the page cap so the page refills rather than shrinks (max 50).cursor— Resume the doc-anchor scan with the opaquemeta.nextCursorfrom the previous page.limit— Candidates per page (max 50).
get_edge
Read one edge by UUID with its endpoint identity, reasoning, confidence, and metadata.
Parameters:
edgeId(required)
git_commit_coverage
Exact Git Commit ledger coverage for a named set of commit SHAs: how many were requested, how many are ledgered as active rows, and how many are missing. Use it to check a bounded set you already hold — a range you are about to attribute, or the SHAs a diff named — rather than to enumerate history. SHAs must be full 40-char lowercase and distinct; ask about a larger set in several calls.
Parameters:
shas(required) — The commit SHAs to check, 1-1000 per call, each a full 40-char lowercase SHA and no repeats. A larger set is asked in several calls.
git_commit_watermark
What is already in the Git Commit ledger for ONE repository: its newest ingested commit SHAs, newest first and server-capped, plus its total ingested count. This is the read a delta client makes BEFORE parsing any history — walk the SHAs for the first one a checkout resolves and read only what came after it. A repository with nothing ingested answers an empty list and a count of zero, never an error.
Parameters:
repository(required) — The stored repository identity —owner/repofor a checkout with a GitHub origin, else the checkout's directory name. The same value Git Commits rows carry anddiffnarrows by.
graph_cluster_keys
List the cluster keys available for one Dotabase and their coverage.
Parameters:
dotabase(required)
graph_cluster_members
Read the bounded member subgraph for one Dotabase cluster.
Parameters:
dotabase(required)key(required)value(required)
graph_clusters
Read the cluster rollup for one Dotabase and cluster key.
Parameters:
dotabase(required)key(required)
graph_dotabase
Read one cursor page of a Dotabase's interactive row graph.
Parameters:
dotabase(required)cursor
graph_neighborhoods
Resolve a batch of CODE-symbol names at once and hydrate each one's immediate callers and callees, with a per-symbol status so an unresolved name is reported rather than silently dropped. The batch shape of callers_of plus callees_of — reach for it when a whole set of symbols is in hand. This is the code graph; graph_row_neighborhood walks the ROW graph instead.
Parameters:
symbols(required) — Code-symbol names to read neighborhoods for (1-500). This is the CODE-symbol walk — graph_row_neighborhood is the row-graph one.
graph_region
Read graph nodes and edges inside a layout bounding box.
Parameters:
minx(required)miny(required)maxx(required)maxy(required)zoomdotabaselimit
graph_row_neighborhood
Read all edges incident to a selected set of row UUIDs plus their cross-Dotabase neighbors.
Parameters:
dotabase(required)rowIds(required)
graph_stats
Read the workspace graph's cached node, edge, and density statistics.
graph_universe
Compose a bounded cross-Dotabase subgraph from hubs, recent activity, or an entity seed.
Parameters:
seedhopslimitkindsdiiiceedgeCategorieslens
impact
Transitive impact: every symbol that (in)directly depends on the given symbol, up to hops away — what could break if you change it.
Parameters:
symbol(required) — A SYM-N human-id or a friendly <path>#<qualifiedName> reference.hops— Transitive dependency hops (default 2, max 5).
list_edges
List one row's incoming and outgoing edges with filters, pagination, and disclosure level.
Parameters:
dotabase(required)row(required)edgeTypedirectionlimitoffsetlevel
repo_verb_campaign_export
One verb campaign's ledger export: its dispositions, the support behind them, and how they materialized. The read-backable record of what a campaign decided — the CLI writes the same payload to a file, and this returns it. Importing a recovery bundle is CLI-only: its payload is a file on the operator's own machine.
Parameters:
campaign(required) — The verb campaign's UUID.
trace
Shortest path between two graph nodes. Reaches across kinds: function → file → commit → conversation → plan, so you can trace a symbol back to the conversation or plan that authored it.
Parameters:
from(required) — Start node: a SYM-N / <path>#<name> / FILE-N / COMMIT-N / ART-N / a repo path.to(required) — Target node: same ref forms asfrom.hops— How many hops the path may span (default: the company hop limit, 6; max 12).limit— Node budget before the walk gives up (default 2500, max 10000).
why
Why a code symbol exists: the provenance walk from the symbol out to the file defining it and on to the commits, conversations, plans, and rows that produced or reference it. Each hop names both endpoints by human-id. narrative always reads; a symbol that reaches nothing comes back with a typed noProvenance reason and a remedy, never an empty result.
Parameters:
symbol(required) — A SYM-N human-id or a friendly <path>#<qualifiedName> reference.limit— Producing commits the walk carries forward, newest first (default 5, max 50).
Tools Requiring jobs.manage (5)
cancel_job_execution
Cancel one durable job execution. An execution that has not started yet dies immediately with an operator-cancel result; one already running is asked to stop and winds down at its next cancellation check, so work it already committed stays committed. Cancelling an execution that already finished is answered by the route with that execution's settled status and changes nothing. Pass dryRun: true to preview.
Parameters:
execution(required) — The durable job execution's UUID.dryRun— Resolve the target and report what would be removed without sending the write.
get_job_execution
One durable job execution's status, its trigger detail, and its outcome. The polled read — a running execution answers again with a later state rather than blocking, so call it again instead of assuming it finished.
Parameters:
execution(required) — The durable job execution's id.
list_job_executions
This workspace's durable job executions. The default window is the ACTIVE ones (queued, running, retrying) oldest first; naming a status instead answers filtered history newest first. Narrow by job name or by an instant. Use get_job_execution once you have an id, retry_job to replay one, and cancel_job_execution to stop one.
Parameters:
status— Narrow to one durable status, or theactive/allaliases. Omit for the route's own default, which is the active window oldest first.job— Narrow to one job name.since— Only executions at or after this ISO-8601 instant.limit— Max executions to return, 1-200. Omit for the route's default.offset— How many executions to skip before the window.
retry_job
Re-run a durable background job the way one of its executions was originally run. There is no retry route: the execution is read, and the job it names is re-enqueued with the repository scope, dry-run posture, and batch cap that execution recorded — so retrying a dry run stays a dry run and a scoped backfill stays scoped. An execution the scheduler triggered carries no such detail and replays bare. Returns the NEW execution's receipt; poll it like any other.
Parameters:
execution(required) — The durable job execution id to replay. The execution names both the job to re-enqueue and what that run was aimed at, so the repository scope, dry-run posture, and batch cap are replayed from its recorded trigger.
run_job
Enqueue a registered background job by name and return its durable execution receipt. The job runs in the BACKGROUND and outlives this call — the receipt's execution id is the handle, and get_job_execution is how you watch it reach a terminal status. Nothing here blocks or waits: a backfill can run far longer than one tool call. An unregistered job name is a clean not-found, and a job already at its concurrency limit is refused rather than queued behind itself.
Parameters:
job(required) — The registered job's name — a lowercase token likerepo.provenance.sweeporfsrs-nightly-decay. An unregistered name is a clean not-found.repository_external_id— Narrow a repo-scoped job to one repository's stored external id. A job that reads no repository scope ignores it.dry_run— Resolve and report without persisting, for jobs that declare a read-only dry-run path. Jobs that do not support dry-run refuse the request; they never run normally.batch_limit— Per-run row cap for the jobs that support one, 1-10000.
Tools Requiring workspace.dotabases.create (1)
create_dotabase
Create a Dotabase — a typed store with its own schema, its own human-id prefix, and its own views. slug and human_id_prefix are immutable after this call and every row keeps the id it is issued, so choose both before creating rather than renaming later. Call scaffold_dotabase_schema first and send what it returns as the head of initial_properties: the system properties it carries are server-authoritative and are never hand-rolled. Views, behavior bindings, and the Operating Manual can all be seeded here or set afterwards. Tenant and creator are injected server-side.
Parameters:
name(required) — Display name, e.g. Lessons.slug(required) — Company-scoped url slug, lowercase kebab-case, e.g. lessons. Immutable after create.human_id_prefix(required) — Prefix every row's public handle carries, e.g. LESSON — rows become LESSON-1, LESSON-2. Immutable after create, and each row keeps its id for life.description— What this Dotabase holds.icon— Icon token (a picker icon name or an emoji).icon_color— Icon color token, e.g. a DIIICE category likecontext.space_id— Destination Space UUID (list_spaces). Omit to land in the default Space.diiice_enabled— Whether rows are DIIICE-classified. Defaults on.embedding_enabled— Whether rows are embedded for semantic search. Defaults on.manual_row_creation_enabled— Whether a person may add rows by hand. Pass false for an import-only Dotabase.body_renderer_key— Registered body-renderer key. Omit for the default editor.import_normalizer_key— Registered markdown-import normalizer key. Omit for the resolver default.import_normalizer_config— Declarative config for the named import normalizer.initial_properties— The schema this Dotabase starts with. Call scaffold_dotabase_schema first and send what it returns plus your own properties — the system properties it carries are never hand-rolled.initial_views— Saved views seeded with the Dotabase. Each is the create_view body shape;filterscarries exactly one root group node.behavior_bindings— Behaviors bound at create. Read the catalog with list_dotabase_behaviors; set_dotabase_behaviors changes them afterwards.manual— The Operating Manual seed —purpose(one line) andjudgment_md(markdown). Omit and the starter skeleton is stamped.creation_plan_row_id— An Artifacts row UUID holding this Dotabase's Creation Plan. Verified in this company, and aproducesprovenance edge is drawn from it.
Tools Requiring workspace.provision (6)
create_sandbox
Provision a THROWAWAY sandbox workspace — a fresh, fully seeded company to prove Dotabase behaviour in without touching any real tenant. The deliberate agent-reachable exception to workspace provisioning: the route uses the workspace.sandboxes.manage gate and drops the login-linked-human predicate. The new company is stamped with sandbox provenance SERVER-SIDE — no argument sets it — and that stamp is what makes destroy_sandbox willing to remove it later. Returns the company's id, slug, and name; keep the id, it is the destroy handle. Pass idempotencyKey when a create may be retried; the same key and input return the original company, while input drift is refused.
Parameters:
workspaceName— Optional display name for the sandbox workspace. Omit for a generic name the server disambiguates.idempotencyKey— Optional replay key. Reusing it with the same input returns the original sandbox.
create_workspace
Provision a NEW company for the login identity behind this credential and make that identity its Owner. This does not rename or modify the active workspace: it creates a separately selectable company, seeds its foundational estate, and returns its id, slug, and resolved name. Owner-reserved on workspace.provision, and available only when the credential belongs to a login-linked human principal. Not idempotent — every successful call creates another company, so do not retry an uncertain outcome.
Parameters:
workspaceName(required) — Name for the new company. The server derives a unique slug and returns both.
destroy_sandbox
Destroy a sandbox company and every row it holds — the teardown half of create_sandbox, permanent and cascading. Hard-scoped server-side: the DELETE removes only a company carrying the server-side sandbox provenance stamp, so a real tenant is refused with a typed 403 whatever id is passed, and an unknown id is a clean 404. Pass dryRun: true to preview without sending the delete.
Parameters:
id(required) — The sandbox company's own id, as create_sandbox returned it.dryRun— Resolve the target and report what would be removed without sending the write.
provision_workspace_template
Provision a registered workspace template's estate into this workspace: its Space, Dotabases, seeded rows, pages, and edges. Idempotent by design — a member that already exists is reported exists and left untouched, so a replay repairs a partial run rather than duplicating it. Member keys named in excludedMemberKeys are never re-created, which is how a store this workspace deliberately deleted stays deleted across replays. Partial failures land in the report's failures rather than throwing, so read the per-member outcomes rather than treating a success as a complete estate.
Parameters:
templateKey— Which registered workspace template's estate to provision. Omit for the default.excludedMemberKeys— Member keys this workspace has deliberately deleted. They are reported skipped, never re-created.creationPlanRowIds— Creation Plan row UUIDs keyed by the member they produced, so a replay repairs provenance without duplicating.
seed_workspace_dotabases
Seed this workspace's foundational Dotabases, Spaces, and day-one Superpower stores — the one-time bootstrap that turns an empty company into a usable one. Idempotent: a re-run instantiates only what is missing and reconciles the additive seed members (options, views, properties) onto what already exists, touching no row you wrote. Owner-reserved — it is advertised only to a credential holding workspace.provision.
send_new_workspace_invite
Email an invitation to provision a NEW workspace of the recipient's own. It does not add anyone to this workspace and grants no access to it — reach for create_invite when the intent is a member here. The email IS the operation: there is no copyable token to fall back on, so a deployment with no invite email configured answers unavailable rather than reporting a send that never happened. Not idempotent — a repeat sends a second email.
Parameters:
email(required) — Recipient email address. They provision their OWN workspace — this adds nobody to yours.
Tools Requiring workspace.settings.manage (26)
add_connection
Record an authorized-account connection from a connected-account REFERENCE you already hold. This is the low-level upsert on (provider, account_ref): re-adding the same pair refreshes its scopes and credential reference and reactivates it rather than adding a second connection. The server proves the reference belongs to the active gateway entity before storing it. Reach for initiate_connection instead when nobody has consented yet — that flow never puts a credential in this conversation.
Parameters:
provider(required) — The connector provider id this account belongs to — a lowercase registry key. Read connections_gateway_status for the ids this deployment can reach.account_ref(required) — How the external account identifies itself (a workspace id, a handle, an email). One connection per (provider, account_ref) per workspace: re-adding the same pair refreshes it rather than adding a second.scopes— The grant tokens this account carries. Omit to leave the stored scopes as they are.credential— The connected-account REFERENCE. Never a raw token, secret, or authorization code — this argument enters the host model's context, and the gateway handshake (initiate_connection then complete_connection) is the path that never puts one there.
clear_provider_key
Clear one capability's stored provider key. This is the same write set_provider_key drives, sending null for that capability — the other capabilities' keys are untouched. A cleared key cannot be read back or recovered, and the capability it backed degrades until a key is set again. Pass dryRun: true to preview.
Parameters:
capability(required) — Which capability's stored key to clear.dryRun— Resolve the target and report what would be removed without sending the write.
clear_workspace_avatar
Clear the ACTIVE WORKSPACE's avatar — a tenant-wide identity change every member sees, gated on workspace.settings.manage. The stored image is left behind as an orphan; only the pointer goes, and uploading a new one is the reversal. Setting an avatar is CLI-only (it sends bytes from the operator's own disk): dots workspaces avatar set --file <path>. Pass dryRun: true to preview.
Parameters:
dryRun— Resolve the target and report what would be removed without sending the write.
complete_connection
Resolve a started connection to its connected-account reference and persist it, active. Idempotent on the same request id — calling it after a browser callback already completed re-upserts the same connection rather than adding a second. No token or authorization code is returned, stored, or logged: what persists is the gateway REFERENCE the proxy dereferences server-side.
Parameters:
provider(required) — The provider the connection was started for.connection_request_id(required) — The request id initiate_connection returned, resolved once the person has consented.
create_publication
Publish a Dotabase to the web. This makes the named views' rows readable by ANYONE on the internet with the link — no login, no membership, no invitation — and the published pages are crawlable. Only the property keys in visible_property_whitelist are served; every other property stays private, and the row body is served only if the reserved body key is in that list. Check what a view actually returns before publishing it: rows the view includes are rows the world can read. A slug already taken by this company is refused rather than replacing the existing publication. Reverse it with unpublish_publication — which stops future reads but does not recall what was already fetched, cached, or indexed.
Parameters:
dotabase(required) — The Dotabase to publish, by UUID or slug.slug(required) — The URL-safe public slug the published pages are served under.view_ids(required) — Saved-view UUIDs to publish. Only rows these views return are served, and the ids must be unique.visible_property_whitelist(required) — Property keys readers may see. Every key omitted here stays private; the reserved tokenbodyopts the row body in.engagement— Optional engagement toggles (comments, reactions). Omit to take the server's defaults.
create_sync_binding
Bind one resource under an authorized-account connection to a Dotabase, so its rows flow in. This is the CONNECTOR half of the bind. Binding a local folder or a local repository is deliberately absent here and stays CLI-only under the local-file-input axis: those arms name a directory on the operator's own machine and start the local companion process that watches it, neither of which an MCP host can supply or run. The binding is created idle — run_sync_binding starts the first import, or leave it to the cadence.
Parameters:
connection_id(required) — UUID of the authorized-account connection this binding pulls through. list_connections is the roster it comes from.source_resource(required) — The one resource under the connection this binding imports from.target_dotabase_id— UUID of the Dotabase to import into. Required unless schema_strategy is mirror_new, which creates one from the source's own shape.mode— How often the source is read: once, pulled on the cadence, or two-way. Omit for the server's default.schema_strategy— Whether to mirror the source's shape into a new Dotabase or map it onto the target's existing properties.field_mapping— Source field key → target property key, for a map_existing binding.cadence— How often the binding runs itself —manual(the server's default for a connector bind) or a schedule label.conflict_policy— Which side wins when a row changed on both. Omit for the server's default.
create_tag_category
Create a workspace tag category.
Parameters:
category(required)displayName(required)descriptioncolorautoDetectableaiSuggestablefacetDisplaysortOrder
delete_sync_binding
Delete a sync binding — the unbind. The rows it already imported stay in the target Dotabase; what goes is the ongoing relationship, and re-binding the source is the only way back. Pass dryRun: true to preview.
Parameters:
binding(required) — The sync binding's UUID.dryRun— Resolve the target and report what would be removed without sending the write.
delete_tag_category
Delete a workspace tag category.
Parameters:
category(required)
disable_plugin
Disable an installed plugin, unregistering the behavior slots it contributes so its rules stop running. The install itself is kept — its configuration and its row survive, and enable_plugin brings it back — so this is the reversible half of uninstall_plugin. Like the enable twin, this touches the TENANT registry and never this connection's own tool catalog, and disabling an already-disabled plugin re-runs its onDisable hook rather than doing nothing. A plugin that is not installed is not found.
Parameters:
name(required) — The installed plugin's package name, exactly aslist_installed_pluginsreports it.
dismiss_coding_agent_folders
Mark coding-agent folders prompted-not-consented — the "not now" memory that re-surfaces gently rather than auto-opening. This WITHDRAWS consent from a folder that had it: the decision is overwritten with dismissed and its recorded decision time replaced, so nothing reads that folder again until consent is recorded afresh and the earlier consent time cannot be recovered. Only folders this server detects are affected. Pass dryRun: true to preview.
Parameters:
folderKeys— Folder keys to dismiss, asdetect_coding_agentsreturns them. Omit to dismiss every folder this server currently detects.dryRun— Resolve the target and report what would be removed without sending the write.
enable_plugin
Enable an installed plugin, so the behavior slots it contributes are registered and its rules run on this workspace's Dotabases. This is the TENANT plugin registry, not this MCP connection's own toolset: enabling a plugin never adds a tool here, because the tools you can call come from the server's built-in catalog and the host's own runtime extensions, neither of which this registry feeds. Enabling an already-enabled plugin is not a no-op — it re-runs the plugin's own onEnable hook — so read list_installed_plugins first if the hook has side effects. A plugin that is not installed is not found.
Parameters:
name(required) — The installed plugin's package name, exactly aslist_installed_pluginsreports it.
grant_coding_agent_consent
Record consent for coding-agent session folders and enqueue the backfill for the ones this server can read, returning the initial backfill status. folderKeys names folders THIS SERVER detects; folders ATTESTS ones it cannot see, carrying the key plus its agent kind — supply at least one list. Consent is the gate on reading a folder's transcripts at all, so recording it is what allows that content into Conversations. Consenting a set also marks every OTHER folder this server currently detects as dismissed: the call's decision wins.
Parameters:
folderKeys— Folder keys THIS server detects, asdetect_coding_agentsreturns them (1-50). A key the server cannot detect records nothing — attest it throughfoldersinstead.folders— Folders ATTESTED by the caller — key plus kind — for folders living where this server cannot look (1-50). Supply at least one of the two lists.
initiate_connection
Start a gateway connection for a provider and return the consent URL a person opens, plus the request id complete_connection resolves. Persists NOTHING: until the person consents and the flow completes, this workspace has no connection. Opening the URL in a browser auto-completes the connection through the deployment's callback, so complete_connection is for the case where it did not. A provider this deployment cannot reach is refused before anything starts.
Parameters:
provider(required) — The provider to start a connection for. It must be available on this deployment — connections_gateway_status is the read that says which are.
merge_tag_categories
Merge one workspace tag category into another and remove the source.
Parameters:
source(required)target(required)
pause_sync_binding
Pause a sync binding so the cadence sweep stops picking it up. The binding, its target, and every row it already imported are untouched — only the automatic runs stop, and resume_sync_binding restores them. The route accepts an already-paused binding and re-stamps it, so the response reports a mutation rather than a no-op.
Parameters:
binding(required) — The sync binding's UUID.
provider_keys_status
Report this instance's provider-key custody and what it enables: who owns the keys (this instance's own secure store, or its host environment), which storage backend is available, whether each capability's key is absent, stored, or unreadable, and whether semantic search, AI fill, and Chat are active or degraded. Presence and state only — no field on this read carries a key value.
resume_sync_binding
Return a sync binding to active so its cadence and watchers pick it up again. The route accepts an already active binding, but still rewrites its recovery timestamps and clears failure/recovery state, so the response reports a mutation rather than a no-op.
Parameters:
binding(required) — The sync binding's UUID.
retry_coding_agent_backfill
Re-drain the coding-agent dead-letter queue: re-enqueue the sessions whose backfill failed, and return the refreshed status. Safe to repeat — a session that succeeds leaves the queue, and a job runner that cannot be reached is reported server-side rather than failing the call, so the status still returns.
revoke_connection
Revoke an authorized-account connection: the external account is dropped at the gateway and the connection is marked revoked. Every sync binding riding this connection stops authenticating and its runs fail until a new connection is made — rows already imported stay where they landed. Revoking an already-revoked connection is answered the same way and drops nothing further. Pass dryRun: true to preview.
Parameters:
connection(required) — The connection's UUID.dryRun— Resolve the target and report what would be removed without sending the write.
run_sync_binding
Run a sync binding now. The work happens in the BACKGROUND and outlives this call: a binding that has never run backfills the whole source, and a later run pulls from where the last one stopped. Nothing here blocks or reports rows — read get_sync_binding for the status (it reads backfilling while a first run is in flight) and sync_binding_enrichment for how far the follow-on enrichment has drained. A runtime without the sync jobs assembled says so rather than silently doing nothing.
Parameters:
binding(required) — The sync binding's UUID.
set_provider_key
Seal a raw provider key for one capability. The key travels in the request and is never read back: the answer is the same key-free status projection provider_keys_status serves. An instance whose keys belong to its host environment refuses the write rather than silently ignoring it. The key you pass here enters this conversation's context — when it must not, use dots providers keys set --capability <name> --key-file <path> instead.
Parameters:
capability(required) — Which capability's key to write: embeddings (voyage), ai (anthropic), or chat (openrouter).key(required) — The raw provider key. It is sealed server-side and never read back — but it does enter this conversation's context, so use the CLI'sdots providers keys set --key-file <path>instead whenever the value must not.
uninstall_plugin
Remove an installed plugin from this workspace for good. It runs the plugin's own onUninstall hook — which is told to purge its data — then deletes the install row and unregisters every slot it contributed; anything that hook discards is gone, and re-installing gives a fresh install rather than the old state back. Reach for disable_plugin instead when you want its rules to stop but the install kept. This is the TENANT registry, so nothing here changes which tools this connection can call. A failing onUninstall hook aborts before anything is deleted, and a plugin that is not installed is not found. Call with dryRun: true to see the target named and send nothing.
Parameters:
name(required) — The installed plugin's package name, exactly aslist_installed_pluginsreports it.dryRun— Report what the uninstall would target and send NOTHING. Nothing is read either — this answers from the name alone.
unpublish_publication
Take one publication offline: its pages stop serving and every anonymous read of them starts answering not-found. It does NOT undo the exposure — a copy someone already fetched, a cache, or a search index that crawled the page is untouched and beyond this workspace's reach. Nothing is deleted: the vault rows and the publication record both survive, so the same slug can be published again. Unpublishing an already-unpublished page succeeds and leaves it offline. The id is the publication UUID from list_publications, not the slug.
Parameters:
id(required) — The publication row's UUID (from list_publications).
update_sync_binding
Change a connector binding's destination before its first import. For a local or started binding, create a new binding so one provenance identity never spans multiple Dotabases.
Parameters:
binding(required) — The sync binding's UUID.target(required) — UUID of the Dotabase an unrun connector binding should import into.
update_tag_category
Update a workspace tag category without replacing omitted settings.
Parameters:
category(required)displayName(required)
Tools Requiring workspace.spaces.manage (4)
create_space
Create a Space — a top-level sidebar grouping that Dotabases and pages live in. It lands last in the sidebar; reposition it from the app or move members into it with move_dotabase. Tenant and creator are injected server-side.
Parameters:
name(required) — Display name for the new Space.icon_value— Icon token — a picker icon name (e.g. folder, IconPointFilled) or an emoji. Defaults to "folder", the icon the app's own New Space dialog starts on.icon_kind— Whether icon_value is a picker icon name or an emoji. Defaults to "icon".icon_color— Icon color token (e.g. a DIIICE category likecontext); null leaves it unset.
delete_space
Delete an EMPTY Space. A Space that still holds Dotabases is refused (SPACE_NOT_EMPTY) — move them out with move_dotabase first. A locked (DIIICE) Space and the System Space are refused outright, and no action restores a deleted one. Nothing inside a Space is deleted by this tool.
Parameters:
space(required) — The Space to delete, by UUID or slug.
sort_space_dotabases
Reorder one Space's Dotabases alphabetically (A–Z) in the sidebar. Pages in that Space keep their existing slots — only the Dotabase positions are rewritten. Returns the Space's Dotabases in their new order.
Parameters:
space(required) — The Space to sort, by UUID or slug.
update_space
Rename a Space, restyle its icon, or move it in the sidebar. Settings and placement of the Space ITSELF — nothing filed inside it moves, and its members keep their own order; use move_dotabase to rehome a Dotabase and sort_space_dotabases to reorder the contents. position is the Space's own 0-based sidebar slot, so omit it to rename in place. An explicit null on icon_color clears it. A call naming no field is refused before any request rather than sent as an empty PATCH.
Parameters:
space(required) — The Space to update, by UUID or slug.name— New display name.icon_value— New icon token — a picker icon name (e.g. folder) or an emoji.icon_kind— Whether icon_value is a picker icon name or an emoji.icon_color— New icon color token (e.g. a DIIICE category likecontext); null clears it.position— 0-based slot among the sidebar's Spaces. Omit to leave the Space where it is.
Ungated Tools (1)
batch
Run up to 50 tool calls in one request: an ordered list of { tool, arguments }. Reads run with at most 4 in flight and a 30-second timeout per read; writes run sequentially in array order, and a failed write halts the remaining writes (reporting the failing index) while reads still complete. Returns a result array aligned to the input order, with the Dotabase operating manuals its members would otherwise each repeat carried once in dboms (a member names its own through dbomRef).
Parameters:
operations(required) — An ordered list of up to 50 { tool, arguments } operations. Reads run with at most 4 in flight and a 30-second timeout per read; writes run in array order.
generator: apps/docs/pipeline/generate-reference.ts — regenerate with pnpm --filter @dots/docs docs:generate:reference; a hand edit to this page fails the docs drift gate.
MCP Tools · This page in the graph
- mentionstoDIIICE: Data
- mentionstoPublish A Dotabase To The Web
- mentionstoCreate A Dotabase
- mentionstoMemory Bank
- mentionstodots workspaces, dots account, and dots providers
- mentionstoApp Shell
- mentionstoBehavior
- mentionstoDIIICE
- mentionstoConversations
- mentionstoView
- mentionstoEdge
- mentionstoDOT
- mentionstoDIIICE
- mentionstoDIIICE: Instructions
- mentionstoHUMAN.md
- mentionstoDotabase
- mentionstoAccess
- mentionstoDots
- mentionstoSpace
- mentionstoPower-Up Playbook
- mentionstoSuperpower
- mentionstoDIIICE: Context
- mentionstoDOT
- mentionstodots mcp, dots repo, and dots graph
- referencestoRow Envelope Format
- referencestoREST API Overview
- mentionsfromRow Envelope Format
- referencesfromRepo Graph Overview
- referencesfromMCP Overview
- mentionsfromdots mcp, dots repo, and dots graph
- mentionsfromBuild And Publish A Plugin
- referencesfromBuild A Plugin
- referencesfromQuery The Code Graph
- referencesfromIssue Scoped Agent Credentials
- referencesfromQuickstart: Agents
- documented byfromMCP Batch Tool
- documented byfromMCP Built-In Vault Tool Catalog
- referencesfromConnect Your Agent
- referencesfromConnect An Agent Via MCP