MCP Tools — Company Brain (Knowledge)

Company Brain is your workspace's living knowledge system. These MCP tools let you search, read, and write every entity in the Brain — meetings, notes, tasks, decisions, topics, people, org units, glossary terms, playbooks, and versioned documents — all scoped to your tenant. They also expose a profile surface for reading and updating the authenticated user's own account fields.

For connection and authentication details, see MCP Overview.


Scopes#

ScopeWhat it grants
brain:readAll list / get / search operations
brain:writeCreate, update, delete, and propose operations
brain:approveApprove / reject AI review items; edit relationship overlays (sensitive — grant explicitly)
profile:readRead the authenticated user's profile
profile:writeUpdate the authenticated user's profile

Profile#

profile_get#

Return the authenticated user's name, email, and the linked client's public company fields.

  • Auth: profile:read

Tool call example:

{ "name": "profile_get", "arguments": {} }

Response:

{
  "user": { "id": 42, "name": "Ada Lovelace", "email": "ada@example.com" },
  "client": {
    "id": 7,
    "company": "Example Co",
    "phone": "+1 555-0100",
    "website": "https://example.com",
    "address": "123 Main St",
    "emailPrefix": "example"
  }
}

profile_update#

Update the authenticated user's name / email and / or the linked client's company fields. All fields are optional; only provided fields are written. Email must be unique across all users.

  • Auth: profile:write
Input fieldTypeDescription
namestring (optional)Display name
emailstring (optional)Must be a valid email and unique
companystring|null (optional)Company name
phonestring|null (optional)Phone number
websitestring|null (optional)Website URL
addressstring|null (optional)Address
emailPrefixstring|null (optional)Lowercase alphanumeric slug used for email routing

Tool call example:

{
  "name": "profile_update",
  "arguments": { "name": "Ada Lovelace", "company": "Example Co" }
}

Response:

{ "success": true }

Errors:

ConditionResponse
Email already taken{ "error": "Email already in use" }
Missing profile:write scopeisError: true — permission denied message

Search & Dashboard#

Hybrid lexical + semantic search across the entire workspace: notes, meetings, CRM companies / contacts / deals, tasks, relationships, and pages. Returns ranked hits with snippets and absolute citation URLs.

  • Auth: brain:read
Input fieldTypeDescription
querystring (1–500 chars)Search query
typesstring[] (optional)Filter to entity types: meeting, note, task, relationship, company, contact, deal, post
limitinteger 1–50 (optional)Max results (default 10)

Tool call example:

{
  "name": "brain_search",
  "arguments": { "query": "Q3 OKR kickoff", "types": ["meeting", "note"], "limit": 5 }
}

Response:

{
  "hits": [
    {
      "type": "meeting",
      "id": 101,
      "title": "Q3 OKR Kickoff",
      "snippet": "…discussed revenue targets for Q3…",
      "score": 0.94,
      "url": "https://simplerdevelopment.com/portal/brain/communications/101"
    }
  ]
}

brain_dashboard_summary#

Return the command-center snapshot: meetings needing review, overdue / blocked / upcoming tasks, stale prospects, priority relationships, recent meetings, and entity counts (including decisionsCount and topicsCount).

  • Auth: brain:read
  • No input fields.

Tool call example:

{ "name": "brain_dashboard_summary", "arguments": {} }

Response:

{
  "counts": {
    "pendingMeetings": 3,
    "openTasks": 12,
    "decisionsCount": 47,
    "topicsCount": 28
  },
  "needsReviewMeetings": [...],
  "overdueTasksCount": 2
}

Meetings#

brain_list_meetings#

List meetings, optionally filtered by status. Returns full rows including transcripts (MCP callers receive transcripts by default).

  • Auth: brain:read
Input fieldTypeDescription
statusdraft|processing|needs_review|approved (optional)Filter by status
limitinteger 1–200 (optional)Max results

brain_get_meeting#

Get a meeting with participants, transcript, AI summary, and the linked CRM record (if any).

  • Auth: brain:read
Input fieldTypeDescription
meetingIdintegerMeeting ID

Errors: Meeting not found.


brain_create_meeting#

Create a meeting from pasted transcript text. Optionally link to a CRM company or deal at creation time.

  • Auth: brain:write
Input fieldTypeDescription
transcriptstring (1–200 000 chars)Raw meeting notes or transcript
titlestring (optional)Meeting title
meetingDatestring (optional)ISO timestamp
participants{name, email?}[] (optional)Participant list
companyIdinteger (optional)Link to CRM company (mutually exclusive with dealId)
dealIdinteger (optional)Link to CRM deal (mutually exclusive with companyId)

Tool call example:

{
  "name": "brain_create_meeting",
  "arguments": {
    "transcript": "Ada: Let's review the pipeline...",
    "title": "Pipeline Review",
    "meetingDate": "2026-06-04T14:00:00Z",
    "companyId": 55
  }
}

Response (slim — transcript is never echoed back):

{
  "id": 201,
  "title": "Pipeline Review",
  "status": "processing",
  "source": "paste",
  "sourceRef": null,
  "createdAt": "2026-06-04T14:01:00.000Z"
}

Errors: Company Brain is not enabled for this workspace. | Error if companyId and dealId are both supplied.


Set or clear a meeting's CRM link (company or deal). Pass null to clear.

  • Auth: brain:write
Input fieldTypeDescription
meetingIdintegerMeeting ID
companyIdinteger|null (optional)CRM company to link
dealIdinteger|null (optional)CRM deal to link

Tasks#

brain_list_tasks#

List Brain tasks with optional filters.

  • Auth: brain:read
Input fieldTypeDescription
statusopen|in_progress|blocked|done (optional)
ownerIdinteger (optional)Filter by assignee
meetingIdinteger (optional)Tasks originating from a meeting
needsReviewboolean (optional)
limitinteger 1–200 (optional)

brain_get_task#

Fetch a single Brain task by id.

  • Auth: brain:read
Input fieldTypeDescription
taskIdintegerTask ID

brain_create_task#

Create a Brain task directly (bypasses the review queue).

  • Auth: brain:write
Input fieldTypeDescription
titlestring (1–500 chars)Task title
descriptionstring (optional)
prioritylow|medium|high|urgent (optional)
dueDatestring (optional)ISO date
ownerIdinteger (optional)Assignee; must be visible to this tenant

brain_propose_task#

Stage a suggested task in the AI review queue for a human to approve, edit, or reject. Prefer this over brain_create_task when acting on AI analysis.

  • Auth: brain:write
Input fieldTypeDescription
titlestring (1–500 chars)
descriptionstring (optional)
prioritylow|medium|high|urgent (optional)
dueDatestring (optional)ISO date
complianceFlagboolean (optional)
sourceMeetingIdinteger (optional)Attach to a meeting's review queue

brain_update_task#

Patch task fields (title, description, status, priority, due date, owner, blocked reason).

  • Auth: brain:write
Input fieldTypeDescription
taskIdintegerTask ID
titlestring (optional)
descriptionstring|null (optional)
statusopen|in_progress|blocked|done (optional)
prioritylow|medium|high|urgent (optional)
dueDatestring|null (optional)ISO date
ownerIdinteger|null (optional)
blockedReasonstring|null (optional)

AI Review Queue#

brain_list_review_items#

List items in the AI proposal queue.

  • Auth: brain:read
Input fieldTypeDescription
statuspending|approved|rejected|edited (optional)Defaults to pending
sourceIdinteger (optional)Filter to a specific meeting

brain_get_review_item#

Get a single AI proposal by id, including the full proposed payload.

  • Auth: brain:read
Input fieldTypeDescription
itemIdintegerReview item ID

brain_approve_review_item#

Approve a pending AI proposal. For task proposals this materializes a brain task row. Optionally patch the payload before approving. Audited.

  • Auth: brain:approve
Input fieldTypeDescription
itemIdintegerReview item ID
editedPayloadobject (optional)Overrides for the proposed payload

brain_reject_review_item#

Reject a pending AI proposal. Audited.

  • Auth: brain:approve
Input fieldTypeDescription
itemIdintegerReview item ID
reasonstring (max 500, optional)Rejection reason

brain_review_items_suggest_reviewer#

Score active Brain people for who should review an AI proposal based on expertise, org-unit context, past approval history, and current workload. Persists the top candidate (score ≥ 3) on the review item. Audited.

  • Auth: brain:write
Input fieldTypeDescription
reviewItemIdintegerReview item ID

Response:

{
  "reviewItemId": 88,
  "suggestedPersonId": 14,
  "score": 4,
  "reason": "Matched 2 expertise tags; low workload"
}

brain_review_items_list_for_reviewer#

List review items where suggested_reviewer_person_id matches the given brain_people.id. Capped at 50 rows.

  • Auth: brain:read
Input fieldTypeDescription
personIdintegerBrain person ID
statuspending|approved|rejected|edited (optional)Defaults to pending

Relationships#

brain_list_relationships#

List relationship overlays with optional filters.

  • Auth: brain:read
Input fieldTypeDescription
typestring (optional)Relationship type label
ownerIdinteger (optional)Owner user ID
prioritylow|medium|high|critical (optional)
statusactive|paused|archived (optional)
staleOnlyboolean (optional)Only relationships past their nextReviewAt

brain_get_relationship#

Get a relationship overlay by id with linked CRM record, contacts, recent meetings, and open tasks.

  • Auth: brain:read
Input fieldTypeDescription
overlayIdintegerOverlay ID

brain_create_relationship#

Start tracking a CRM company or deal as a Brain relationship. Idempotent.

  • Auth: brain:write
Input fieldTypeDescription
companyIdinteger (optional)Exactly one of companyId or dealId required
dealIdinteger (optional)
relationshipTypestring (optional)
prioritylow|medium|high|critical (optional)
summarystring (optional)
currentPrioritiesstring (optional)
openLoopsstring (optional)
nextReviewAtstring (optional)ISO timestamp
staleAfterDaysinteger (optional)Days before considered stale

brain_update_relationship#

Edit a Brain relationship overlay. Audited.

  • Auth: brain:approve
Input fieldTypeDescription
overlayIdintegerOverlay ID
prioritylow|medium|high|critical (optional)
statusactive|paused|archived (optional)
summarystring|null (optional)
currentPrioritiesstring|null (optional)
openLoopsstring|null (optional)
nextReviewAtstring|null (optional)ISO timestamp
staleAfterDaysinteger|null (optional)

Knowledge Notes#

brain_list_notes#

List / search knowledge notes. Slim by default (400-char body preview + length). Use sourceUrl / sourceUrlStartsWith to deduplicate before crawling. Paginated via { items, total, limit, offset }.

  • Auth: brain:read
Input fieldTypeDescription
searchstring (optional)ILIKE on title and body
tagstring (optional)Match a single tag
sourceUrlstring (optional)Exact URL match for dedup
sourceUrlStartsWithstring (optional)Prefix URL match — e.g. entire docs site
relationshipOverlayIdinteger (optional)
companyIdinteger (optional)
dealIdinteger (optional)
contactIdinteger (optional)
meetingIdinteger (optional)
pinnedOnlyboolean (optional)
trashedboolean (optional)When true, return only soft-deleted notes
limitinteger 1–200 (optional)Default 50
offsetinteger (optional)

brain_get_note#

Fetch a single note with its full body.

  • Auth: brain:read
Input fieldTypeDescription
noteIdintegerNote ID

brain_create_note#

Save a knowledge note. Primary write surface for AI-driven web ingestion — pass source: "crawl" and sourceUrl when ingesting from the web. Body is markdown, capped at 50 KB.

  • Auth: brain:write
Input fieldTypeDescription
titlestring (1–255 chars)
bodystring (max 50 000 chars, optional)Markdown
tagsstring[] (optional)
sourceUrlstring URL (optional)Provenance URL
sourcemanual|ai_review|document_import|crawl (optional)
confidentialityLevelstandard|restricted|confidential (optional)
pinnedboolean (optional)
relationshipOverlayIdinteger (optional)
companyIdinteger (optional)
dealIdinteger (optional)
contactIdinteger (optional)
meetingIdinteger (optional)

brain_upsert_note_by_url#

Idempotent crawl primitive: update an existing note for sourceUrl if found, otherwise create it. Returns { note, created: boolean }. Prefer this over brain_create_note when ingesting web pages.

  • Auth: brain:write
Input fieldTypeDescription
sourceUrlstring URLKey for the upsert
titlestring (1–255 chars)
bodystring (max 50 000 chars)
tagsstring[] (optional)
confidentialityLevelstandard|restricted|confidential (optional)
relationshipOverlayIdinteger (optional)
companyIdinteger (optional)
dealIdinteger (optional)

brain_update_note#

Patch fields on an existing note. Pass null for nullable fields to clear them.

  • Auth: brain:write
Input fieldTypeDescription
noteIdintegerNote ID
titlestring (1–255, optional)
bodystring (max 50 000, optional)
tagsstring[] (optional)
sourceUrlstring|null (optional)
confidentialityLevelstandard|restricted|confidential (optional)
pinnedboolean (optional)
relationshipOverlayIdinteger|null (optional)
companyIdinteger|null (optional)
dealIdinteger|null (optional)
contactIdinteger|null (optional)
meetingIdinteger|null (optional)

brain_delete_note#

Two-stage delete. Default (force: false) soft-deletes — note moves to trash and can be restored. If the note is already trashed, this hard-deletes it. Pass force: true to hard-delete immediately. Audited.

  • Auth: brain:write
Input fieldTypeDescription
noteIdintegerNote ID
forceboolean (optional)Skip soft-delete stage

Response:

{ "id": 55, "deleted": "soft" }

brain_restore_note#

Restore a soft-deleted note back to the active list.

  • Auth: brain:write
Input fieldTypeDescription
noteIdintegerNote ID

brain_bulk_update_notes#

Apply a bulk operation to up to 500 notes at once. Cross-tenant IDs are silently skipped.

  • Auth: brain:write
Input fieldTypeDescription
idsinteger[] (1–500)Note IDs
opdiscriminated unionOperation: soft_delete, restore, hard_delete, add_tags, remove_tags, or replace_tag_prefix

Op shapes:

{ "kind": "add_tags", "tags": ["competitor", "q3"] }
{ "kind": "replace_tag_prefix", "from": "old-prefix", "to": "new-prefix" }

Response:

{ "updated": 48, "skipped": 2 }

brain_classify_notes#

Run the LLM classifier to assign BRAIN-1 taxonomy facets (source / slate-area / audience / content-type / recency / competitor / status). Default dryRun: true — returns counts and a 5-row sample without writing anything. Set dryRun: false to get the full per-note output to feed into brain_apply_classifications.

  • Auth: brain:write
Input fieldTypeDescription
noteIdsinteger[] (max 500, optional)Explicit note list; provide this OR all
allboolean (optional)Classify all notes for the tenant
limitinteger 1–500 (optional)Cap when using all
concurrencyinteger 1–8 (optional)LLM concurrency
dryRunboolean (default true)true = counts + sample only

brain_apply_classifications#

Persist classifier output from brain_classify_notes: writes the note status enum and attaches matching reserved taxonomy topics. Rows below minConfidence (default 0.7) are routed to the AI review queue unless routeBelowMinToReview: false. Idempotent.

  • Auth: brain:write
Input fieldTypeDescription
classificationsclassification[] (1–500)Output from brain_classify_notes with dryRun: false
minConfidencefloat 0–1 (optional)Default 0.7
routeBelowMinToReviewboolean (optional)Default true

Response:

{
  "notesUpdated": 45,
  "topicsAttached": 120,
  "attachmentsExisted": 3,
  "routedToReview": 2,
  "skippedTotal": 1,
  "skipped": [{ "noteId": 99, "reason": "below_min_confidence" }]
}

brain_list_note_history#

Audit log for a single note: created, updated, soft_deleted, restored, hard_deleted, etc.

  • Auth: brain:read
Input fieldTypeDescription
noteIdintegerNote ID
limitinteger 1–200 (optional)Default 50
includeDiffboolean (optional)When true, include the full metadata blob

Saved Searches#

brain_list_saved_searches#

List sidebar-pinned filter sets.

  • Auth: brain:read
Input fieldTypeDescription
scopemine|shared|all (optional)Default all
includeFiltersboolean (optional)Inline the filters JSON

Fetch a saved search by id, including the full filters JSON.

  • Auth: brain:read
Input fieldTypeDescription
idintegerSaved search ID

Pin a knowledge filter set to the sidebar.

  • Auth: brain:write
Input fieldTypeDescription
namestring (1–150 chars)Display name
filtersobject{ search?, tagPrefix?, tags?, pinnedOnly?, trashed?, sort?, order? }
iconstring (max 50, optional)Icon identifier
sortOrdernumber (optional)
scopepersonal|shared (optional)Default personal

Patch fields on a saved search. Pass scope to move between personal and shared.

  • Auth: brain:write
Input fieldTypeDescription
idintegerSaved search ID
namestring (optional)
filtersobject (optional)Same shape as create
iconstring (optional)
sortOrdernumber (optional)
scopepersonal|shared (optional)

Remove a saved-search pin from the sidebar.

  • Auth: brain:write
Input fieldTypeDescription
idintegerSaved search ID

Note Templates#

brain_list_note_templates#

List reusable note templates. Slim by default (no body). Pass includeBody: true to inline bodies.

  • Auth: brain:read
Input fieldTypeDescription
triggermanual|daily|meeting|slash (optional)
enabledboolean (optional)
includeBodyboolean (optional)

brain_get_note_template#

Fetch a template by id, including the full markdown body.

  • Auth: brain:read
Input fieldTypeDescription
idintegerTemplate ID

brain_create_note_template#

Define a reusable note template. Body is markdown and supports {{variables}}. Returns an error if a template with this name already exists for the tenant.

  • Auth: brain:write
Input fieldTypeDescription
namestring (1–150 chars)Must be unique per tenant
bodystringMarkdown body
triggermanual|daily|meeting|slash (optional)
variablesstring[] (optional)Named variable slots in the template
defaultTagsstring[] (optional)Auto-applied to notes created from this template
enabledboolean (optional)

brain_update_note_template#

Patch any field on a template.

  • Auth: brain:write
Input fieldTypeDescription
idintegerTemplate ID
namestring (optional)
bodystring (optional)
triggermanual|daily|meeting|slash (optional)
variablesstring[]|null (optional)
defaultTagsstring[]|null (optional)
enabledboolean (optional)

brain_delete_note_template#

Permanently delete a template. Existing notes created from it are unaffected.

  • Auth: brain:write
Input fieldTypeDescription
idintegerTemplate ID

brain_create_note_from_template#

Apply a template (resolving {{today}}, {{userName}}, etc.) and create a new note.

  • Auth: brain:write
Input fieldTypeDescription
templateIdintegerTemplate ID
titleOverridestring (max 255, optional)Override the default title

Response (slim):

{ "id": 301, "title": "Daily Standup 2026-06-04", "bodyLength": 420, "tags": ["standup"], "updatedAt": "..." }

CRM (via Brain)#

brain_list_companies#

List CRM companies. Use brain_search for semantic matching; use this for structured field filters.

  • Auth: brain:read
Input fieldTypeDescription
searchstring (optional)ILIKE on name and domain
industrystring (optional)
limitinteger 1–200 (optional)

brain_get_company#

Get a CRM company with its linked contacts and open deals.

  • Auth: brain:read
Input fieldTypeDescription
companyIdintegerCompany ID

brain_list_contacts#

List CRM contacts with optional filters.

  • Auth: brain:read
Input fieldTypeDescription
searchstring (optional)ILIKE on first name, last name, email
companyIdinteger (optional)
statusstring (optional)
limitinteger 1–200 (optional)

brain_get_contact#

Get a CRM contact with their linked company and open deals.

  • Auth: brain:read
Input fieldTypeDescription
contactIdintegerContact ID

brain_list_deals#

List CRM deals with optional filters.

  • Auth: brain:read
Input fieldTypeDescription
statusopen|won|lost (optional)
prioritylow|medium|high (optional)
stageIdinteger (optional)
companyIdinteger (optional)
limitinteger 1–200 (optional)

brain_get_deal#

Get a CRM deal with its linked company, primary contact, and stage info.

  • Auth: brain:read
Input fieldTypeDescription
dealIdintegerDeal ID

brain_list_posts#

List website posts / pages owned by this tenant. Slim response (no body JSON). Use brain_get_post for the full block content.

  • Auth: brain:read
Input fieldTypeDescription
websiteIdinteger (optional)
publishedboolean (optional)
postTypestring (optional)
limitinteger 1–200 (optional)

brain_get_post#

Get a post including its full block JSON (posts.content). Validates tenancy via the website ownership.

  • Auth: brain:read
Input fieldTypeDescription
postIdintegerPost ID

Initiatives#

brain_initiatives_list#

List initiatives. Slim by default — returns { id, name, slug, status, priority, ownerId, targetDate, goalCount } per row. Heavy text fields are opt-in via include.

  • Auth: brain:read
Input fieldTypeDescription
statusplanned|active|paused|completed|cancelled (optional)
ownerIdinteger (optional)
prioritylow|medium|high|critical (optional)
hasOpenGoalsboolean (optional)
targetDateBeforestring (optional)ISO date
limitinteger 1–100 (optional)
offsetinteger (optional)
include["description"]|["lessonsLearned"] (optional)Opt into heavy text fields

brain_initiatives_get#

Get one initiative by id with optional goals and linked entities.

  • Auth: brain:read
Input fieldTypeDescription
idintegerInitiative ID
includeGoalsboolean (optional)Inline ordered goals
includeLinksboolean (optional)Inline linked entity rows + byType counts
includestring[] (optional)"description", "lessonsLearned"

List polymorphic entities linked to an initiative (tasks, notes, meetings, decisions, topics, CRM deals/companies).

  • Auth: brain:read
Input fieldTypeDescription
idintegerInitiative ID
entityTypetask|note|meeting|decision|topic|crm_deal|crm_company (optional)
limitinteger 1–100 (optional)
offsetinteger (optional)

brain_initiatives_create#

Create a multi-quarter initiative. Echo: { id, slug, status }.

  • Auth: brain:write
Input fieldTypeDescription
namestring (1–255 chars)
descriptionstring|null (optional)
statusplanned|active|paused|completed|cancelled (optional)
prioritylow|medium|high|critical (optional)
ownerIdinteger|null (optional)
sponsorIdinteger|null (optional)
startDatestring|null (optional)ISO date
targetDatestring|null (optional)ISO date
confidentialityLevelstandard|restricted|confidential (optional)

brain_initiatives_update#

Patch fields on an initiative. Status changes are rejected — use brain_initiatives_close or brain_initiatives_reopen instead.

  • Auth: brain:write
Input fieldTypeDescription
idintegerInitiative ID
patchobjectname, description, priority, ownerId, sponsorId, startDate, targetDate, confidentialityLevel

brain_initiatives_close#

Terminal status transition — outcome must be completed or cancelled. Requires at least one of reason / lessonsLearned. When lessonsLearned is provided, a pinned brain note is auto-created.

  • Auth: brain:write
Input fieldTypeDescription
idintegerInitiative ID
outcomecompleted|cancelled
reasonstring (max 2000, optional)
lessonsLearnedstring (max 50 000, optional)Auto-creates a linked pinned note

brain_initiatives_reopen#

Reopen a previously closed initiative — only from completed or cancelled. Sets status to active.

  • Auth: brain:write
Input fieldTypeDescription
idintegerInitiative ID

Attach a polymorphic entity to an initiative. Idempotent.

  • Auth: brain:write
Input fieldTypeDescription
initiativeIdinteger
entityTypeenumtask, note, meeting, decision, topic, crm_deal, crm_company, person, org_unit, glossary_term
entityIdinteger
notestring|null (optional)
pinnedboolean (optional)

Remove a polymorphic link from an initiative.

  • Auth: brain:write
Input fieldTypeDescription
initiativeIdinteger
entityTypeenumSame values as brain_initiatives_link
entityIdinteger

Goals#

brain_goals_list#

List goals. Slim by default; opt into "description" and "lastProgressNote" via include.

  • Auth: brain:read
Input fieldTypeDescription
initiativeIdinteger (optional)
statusopen|on_track|at_risk|off_track|achieved|missed (optional)
ownerIdinteger (optional)
limitinteger 1–100 (optional)
offsetinteger (optional)
includestring[] (optional)"description", "lastProgressNote"

brain_goals_get#

Get one goal by id with a slim parent-initiative reference.

  • Auth: brain:read
Input fieldTypeDescription
idintegerGoal ID
includestring[] (optional)"description", "lastProgressNote"

brain_goals_create#

Create a goal under an existing initiative.

  • Auth: brain:write
Input fieldTypeDescription
initiativeIdintegerParent initiative
titlestring (1–255 chars)
descriptionstring|null (optional)
ownerIdinteger|null (optional)
unitstring (max 30)|null (optional)Metric unit (e.g. "ARR $", "%")
targetMetricinteger|null (optional)
currentMetricinteger|null (optional)
targetDatestring|null (optional)ISO date
sortOrderinteger (optional)
statusopen|on_track|at_risk|off_track|achieved|missed (optional)

brain_goals_update#

Patch fields on a goal (including status).

  • Auth: brain:write
Input fieldTypeDescription
idintegerGoal ID
patchobjectSame fields as create minus initiativeId

brain_goals_checkin#

Drop a progress check-in: updates currentMetric, lastProgressNote, lastCheckedInAt. When status is omitted but currentMetric is provided, the auto-classifier picks the new status.

  • Auth: brain:write
Input fieldTypeDescription
idintegerGoal ID
currentMetricinteger (optional)
notestring (max 10 000)|null (optional)Progress note
statusopen|on_track|at_risk|off_track|achieved|missed (optional)

brain_goals_delete#

Hard-delete a goal.

  • Auth: brain:write
Input fieldTypeDescription
idintegerGoal ID

Decisions#

Decisions are immutable history — rationale and decision text cannot be edited in place. Use brain_decisions_supersede to create a successor and atomically link it.

brain_decisions_list#

List decisions with optional filters. Slim by default; opt into heavy text fields via include. Paginated via { items, total, limit, offset }.

  • Auth: brain:read
Input fieldTypeDescription
statusproposed|accepted|superseded|rejected (optional)
reversibilityone_way|two_way (optional)
decisionMakerIdinteger (optional)
dateFromstring (optional)ISO — decidedAt >= this
dateTostring (optional)ISO — decidedAt <= this
supersededOnlyboolean (optional)
topicIdinteger (optional)
limitinteger 1–100 (optional)
offsetinteger (optional)
includestring[] (optional)"context", "rationale", "decision", "alternatives"

brain_decisions_get#

Fetch a decision by id with its supersedes chain (ancestors + descendants). Heavy text fields are opt-in.

  • Auth: brain:read
Input fieldTypeDescription
idintegerDecision ID
includestring[] (optional)"context", "rationale", "decision", "alternatives"

brain_decisions_create#

Create a new accepted decision. Echo is slim — full prose lives in the input but is not echoed back. Audited.

  • Auth: brain:write
Input fieldTypeDescription
titlestring (1–255 chars)
decisionstringThe decision text (required)
rationalestringWhy this decision was made (required)
contextstring|null (optional)Background
alternativesConsideredstring|null (optional)
reversibilityone_way|two_way (optional)
decidedAtstring (optional)ISO timestamp; defaults to now
decisionMakerIdinteger|null (optional)
anchorsobject (optional){ meetingId?, noteId?, companyId?, dealId? }
confidentialityLevelstandard|restricted|confidential (optional)

brain_decisions_update#

Patch mutable fields on a decision (title, context, decisionMakerId, anchors, confidentialityLevel, alternativesConsidered). Attempts to mutate decision, rationale, or reversibility return { error: "use_supersede" }. Audited.

  • Auth: brain:write

brain_decisions_supersede#

Atomically create a successor decision and link it back to the old one (old.status → "superseded"). Use when you need to change rationale, decision text, or reversibility. Audited.

  • Auth: brain:write
Input fieldTypeDescription
oldIdintegerDecision to supersede
titlestring
decisionstringNew decision text
rationalestring
Plus all optional fields from brain_decisions_create

Response:

{
  "previous": { "id": 10, "status": "superseded" },
  "current": { "id": 11, "status": "accepted", "decidedAt": "2026-06-04T..." }
}

brain_decisions_reject#

Soft-reject a decision by transitioning status to rejected. Idempotent. Audited.

  • Auth: brain:write
Input fieldTypeDescription
idintegerDecision ID
reasonstring (max 500, optional)

Topics#

brain_topics_list#

Flat list of every topic in path order. Pass tagPrefix to scope to a subtree; includeEntityCounts to add per-row count.

  • Auth: brain:read
Input fieldTypeDescription
tagPrefixstring (optional)Path prefix filter
includeEntityCountsboolean (optional)

brain_topics_tree#

Nested topic taxonomy tree with per-node childCount and entityCount. Descriptions are opt-in.

  • Auth: brain:read
Input fieldTypeDescription
includeDescriptionsboolean (optional)

brain_topics_get#

Fetch a topic by id with its breadcrumb (root → immediate parent).

  • Auth: brain:read
Input fieldTypeDescription
idintegerTopic ID
includeDescriptionboolean (optional)

brain_topics_entities#

List entities attached to a topic (notes, meetings, tasks, decisions, relationship overlays, initiatives, people). Paginated; limit capped at 100.

  • Auth: brain:read
Input fieldTypeDescription
idintegerTopic ID
entityTypenote|meeting|task|decision|relationship_overlay|initiative|person (optional)
limitinteger 1–100 (optional)
offsetinteger (optional)

brain_topics_create#

Create a topic. Slug and path auto-derive from name; collisions get a -2, -3 suffix. Audited.

  • Auth: brain:write
Input fieldTypeDescription
namestring (1–150 chars)
parentIdinteger|null (optional)
descriptionstring|null (optional)
colorstring (optional)
iconstring (optional)
sortOrderinteger (optional)
derivedFromTagstring (optional)Tag slug this topic was derived from

brain_topics_update#

Patch a topic. Rename does NOT change slug (stable URLs). Use brain_topics_move to reparent. Audited.

  • Auth: brain:write
Input fieldTypeDescription
idintegerTopic ID
patchobjectname, description, color, icon, sortOrder

brain_topics_move#

Move a topic under a new parent, recomputing the materialized path for the entire subtree atomically. Pass newParentId: null to promote to root. Audited.

  • Auth: brain:write
Input fieldTypeDescription
idintegerTopic ID
newParentIdinteger|nullTarget parent; null = root

brain_topics_merge#

Fold sourceId into targetId: reattach entity links (skipping duplicates), reparent source's children under target, then delete source. Refuses to merge into a descendant. Audited.

  • Auth: brain:write
Input fieldTypeDescription
sourceIdinteger
targetIdinteger

brain_topics_delete#

Delete a topic. Refuses if it has children. Refuses if entities are attached unless force: true.

  • Auth: brain:write
Input fieldTypeDescription
idintegerTopic ID
forceboolean (optional)Drop attached entity join rows before deleting

brain_topics_attach#

Bulk-attach one or more topics to a single entity. Idempotent; cross-tenant topic IDs are silently dropped.

  • Auth: brain:write
Input fieldTypeDescription
targetEntityTypenote|meeting|task|decision|relationship_overlay|initiative|person
targetEntityIdinteger
topicIdsinteger[] (1–50)

brain_topics_detach#

Bulk-detach one or more topics from a single entity. Missing rows are a no-op.

  • Auth: brain:write
Input fieldTypeDescription
targetEntityTypesame enum as attach
targetEntityIdinteger
topicIdsinteger[] (1–50)

brain_topics_import_from_tags#

Walk every brain_notes.tags string, split hierarchical a/b/c tags into a topic tree, find-or-create each segment, and attach notes to the leaf topic. dryRun: true returns the report without writing. Idempotent.

  • Auth: brain:write
Input fieldTypeDescription
tagPrefixstring (optional)Scope to one branch
dryRunboolean (optional)Default false

People#

brain_people_list#

List internal people (employees / advisors / contractors). Slim by default; opt into "notes" and "profileUrls" via include.

  • Auth: brain:read
Input fieldTypeDescription
statusactive|inactive|departed (optional)
orgUnitIdinteger (optional)
expertiseTagIdinteger (optional)
managerIdinteger (optional)
searchstring (optional)
limitinteger 1–100 (optional)
offsetinteger (optional)
include["notes"]|["profileUrls"] (optional)

brain_people_get#

Fetch a person with manager, direct reports, org-unit memberships, and expertise tags.

  • Auth: brain:read
Input fieldTypeDescription
idintegerPerson ID
includestring[] (optional)"notes", "profileUrls"

brain_who_knows#

Resolve a free-text query to expertise tags, then rank people by matched-tag count, level bonus, and primary-org-unit bonus. Use this for "who should I talk to about X" queries.

  • Auth: brain:read
Input fieldTypeDescription
querystring (1–200 chars)
limitinteger 1–25 (optional)

Tool call example:

{ "name": "brain_who_knows", "arguments": { "query": "Postgres query optimization", "limit": 5 } }

brain_people_create#

Add an internal person. Echo: { id, status }.

  • Auth: brain:write
Input fieldTypeDescription
fullNamestring (1–200 chars)
emailstring|null (optional)
userIdinteger|null (optional)Link to a portal user account
managerIdinteger|null (optional)
titlestring|null (optional)Job title
startDatestring|null (optional)ISO date
endDatestring|null (optional)ISO date
statusactive|inactive|departed (optional)
notesstring|null (optional)Free-form notes
profileUrls{label, url}[] (optional)LinkedIn etc.

brain_people_update#

Patch fields on a person. Manager change is cycle-guarded — assigning a descendant returns { error: "manager_cycle" }.

  • Auth: brain:write
Input fieldTypeDescription
idintegerPerson ID
patchobjectSame fields as create minus userId

brain_people_delete#

Delete a person. Cascades org-unit memberships and expertise junctions; direct reports chains are nulled out.

  • Auth: brain:write
Input fieldTypeDescription
idintegerPerson ID

brain_people_attach_expertise#

Attach an expertise tag to a person with an optional proficiency level (1–4). Idempotent — updates level if the row already exists.

  • Auth: brain:write
Input fieldTypeDescription
personIdinteger
expertiseTagIdinteger
levelinteger 1–4|null (optional)Proficiency level

brain_people_detach_expertise#

Remove an expertise tag from a person.

  • Auth: brain:write
Input fieldTypeDescription
personIdinteger
expertiseTagIdinteger

Expertise Tags#

brain_expertise_tags_list#

List per-tenant expertise tags. peopleCount is always populated. Slim by default.

  • Auth: brain:read
Input fieldTypeDescription
searchstring (optional)ILIKE on name and description
sourcemanual|ai_suggested (optional)
limitinteger 1–100 (optional)
offsetinteger (optional)
include["description"] (optional)

brain_expertise_tags_create#

Create a per-tenant expertise tag. Slug auto-derived; collisions suffixed -2, -3. Echo: { id, slug }.

  • Auth: brain:write
Input fieldTypeDescription
namestring (1–100 chars)
descriptionstring|null (optional)
sourcemanual|ai_suggested (optional)

brain_expertise_tags_update#

Patch name or description on an expertise tag. Slug stays stable.

  • Auth: brain:write
Input fieldTypeDescription
idintegerTag ID
patchobject{ name?, description? }

brain_expertise_tags_delete#

Delete an expertise tag. Refuses by default if any person still holds it — pass force: true to cascade-detach. Returns { error: "in_use", peopleAttached } on conflict.

  • Auth: brain:write
Input fieldTypeDescription
idintegerTag ID
forceboolean (optional)

brain_expertise_tags_merge#

Re-attach every person–expertise row from sourceTagId to targetTagId, then delete the source tag.

  • Auth: brain:write
Input fieldTypeDescription
sourceTagIdinteger
targetTagIdinteger

Org Units#

brain_org_units_list#

Flat list of org units ordered by path. memberCount always populated. Descriptions are opt-in.

  • Auth: brain:read
Input fieldTypeDescription
include["descriptions"] (optional)

brain_org_units_tree#

Nested org-unit tree with per-node childCount and memberCount.

  • Auth: brain:read
Input fieldTypeDescription
include["descriptions"] (optional)

brain_org_units_get#

Fetch an org unit with its ancestor chain and members.

  • Auth: brain:read
Input fieldTypeDescription
idintegerOrg unit ID

brain_org_units_create#

Create a hierarchical org unit. Slug auto-derived; path computed from parent. Echo: { id, slug, path }.

  • Auth: brain:write
Input fieldTypeDescription
namestring (1–150 chars)
parentIdinteger|null (optional)
descriptionstring|null (optional)
leadPersonIdinteger|null (optional)
colorstring (optional)
iconstring (optional)
sortOrderinteger (optional)

brain_org_units_update#

Patch fields on an org unit. Slug and path stay stable on rename. Use brain_org_units_move to reparent.

  • Auth: brain:write
Input fieldTypeDescription
idintegerOrg unit ID
patchobjectname, description, leadPersonId, color, icon, sortOrder

brain_org_units_move#

Re-parent an org unit, rewriting the path prefix for the unit and all descendants. Cycle-guarded.

  • Auth: brain:write
Input fieldTypeDescription
idintegerOrg unit ID
newParentIdinteger|nullnull = promote to root

brain_org_units_merge#

Re-parent source's children under target, re-attach source's members to target (dedup-safe), then delete source.

  • Auth: brain:write
Input fieldTypeDescription
sourceIdinteger
targetIdinteger

brain_org_units_delete#

Delete an org unit. Refuses by default if it has members or children — pass force: true to cascade. Returns { error: "in_use", memberCount, childCount } on conflict.

  • Auth: brain:write
Input fieldTypeDescription
idintegerOrg unit ID
forceboolean (optional)

brain_org_units_add_member#

Attach a person to an org unit. Idempotent — re-attaching updates primary and roleInUnit. Marking primary: true flips other memberships to primary: false.

  • Auth: brain:write
Input fieldTypeDescription
orgUnitIdinteger
personIdinteger
primaryboolean (optional)
roleInUnitstring|null (optional)Role label within this unit

brain_org_units_remove_member#

Detach a person from an org unit.

  • Auth: brain:write
Input fieldTypeDescription
orgUnitIdinteger
personIdinteger

brain_org_units_set_primary#

Mark an org unit as the primary membership for a person. Flips all other memberships to primary: false. Requires the membership to already exist.

  • Auth: brain:write
Input fieldTypeDescription
personIdinteger
orgUnitIdinteger

Glossary#

brain_glossary_list#

List tenant glossary terms (acronyms, codenames, jargon). Slim by default; opt into "definition" and "aliases" via include. Limit capped at 100.

  • Auth: brain:read
Input fieldTypeDescription
statusactive|deprecated (optional)
categorystring (optional)
searchstring (optional)Substring on term, aliases, and definition
ownerIdinteger (optional)
limitinteger 1–100 (optional)
offsetinteger (optional)
include["definition"]|["aliases"] (optional)

brain_glossary_get#

Fetch a single term with its "see also" related terms.

  • Auth: brain:read
Input fieldTypeDescription
idintegerTerm ID
includestring[] (optional)"definition", "aliases"

brain_glossary_lookup#

Scored lookup against active glossary terms — returns ranked matches (exact term → exact alias → prefix → substring → definition). Use before answering any question that may contain tenant-specific acronyms. Limit capped at 25.

  • Auth: brain:read
Input fieldTypeDescription
querystring (1–200 chars)
limitinteger 1–25 (optional)Default 10

Tool call example:

{ "name": "brain_glossary_lookup", "arguments": { "query": "OKR", "limit": 3 } }

brain_glossary_create#

Add a new glossary term. Slug auto-derived from term. Echo: { id, slug }.

  • Auth: brain:write
Input fieldTypeDescription
termstring (1–200 chars)
definitionstringFull definition
shortDefinitionstring (max 500, optional)One-liner
aliasesstring[] (optional)
statusactive|deprecated (optional)
categorystring (max 100, optional)
ownerIdinteger (optional)
relatedTermIdsinteger[] (optional)
sourcemanual|ai_suggested (optional)

brain_glossary_update#

Patch any field on a glossary term except slug. Echo: { id, updatedFields }.

  • Auth: brain:write
Input fieldTypeDescription
idintegerTerm ID
patchobjectterm, definition, shortDefinition, aliases, status, category, ownerId, relatedTermIds

brain_glossary_delete#

Hard-delete a term. Also prunes this ID from every other term's relatedTermIds list.

  • Auth: brain:write
Input fieldTypeDescription
idintegerTerm ID

Response:

{ "id": 22, "deleted": true, "prunedRelatedTermFromCount": 3 }

brain_glossary_bulk_import#

Insert or update up to 200 terms in one call. Upsert keyed on slug (auto-derived from term) per tenant. Echo: { created, updated, errors }.

  • Auth: brain:write
Input fieldTypeDescription
termsobject[] (1–200)Each: { term, definition, shortDefinition?, aliases?, category? }

Playbooks#

brain_playbooks_list#

List multi-step playbooks. Slim by default — returns { id, name, slug, status, category, triggerKind, ownerId, stepCount, activeRunCount }. Opt into "description", "triggerConfig", "defaultTopicIds" via include.

  • Auth: brain:read
Input fieldTypeDescription
statusdraft|active|archived or array (optional)
categorystring (optional)
triggerKindmanual|event|scheduled or array (optional)
ownerIdinteger (optional)
limitinteger 1–100 (optional)
offsetinteger (optional)
includestring[] (optional)

brain_playbooks_get#

Get one playbook with its ordered steps. Heavy fields (description, step config / condition blobs) are opt-in.

  • Auth: brain:read
Input fieldTypeDescription
idintegerPlaybook ID
includestring[] (optional)"description", "stepConfigs"

brain_playbooks_create#

Create a new playbook (always starts in draft). Use brain_playbooks_add_step to attach steps, then brain_playbooks_activate to make it runnable.

  • Auth: brain:write
Input fieldTypeDescription
namestring (1–200 chars)
descriptionstring|null (optional)
triggerKindmanual|event|scheduled (optional)
triggerConfigobject|null (optional){ event?, filters?, cron? }
categorystring|null (optional)
ownerIdinteger|null (optional)
defaultTopicIdsinteger[] (optional)Auto-attach to runs

brain_playbooks_update#

Patch fields on a playbook definition. Status changes are rejected — use brain_playbooks_activate or brain_playbooks_archive instead.

  • Auth: brain:write
Input fieldTypeDescription
idintegerPlaybook ID
patchobjectname, description, category, ownerId, triggerKind, triggerConfig, defaultTopicIds

brain_playbooks_activate#

Flip status from draft to active. Refuses if the playbook has zero steps or the step graph fails DAG validation (cycles, missing refs, no entry point). Returns { error: "dag_invalid", errors: string[] } on failure.

  • Auth: brain:write
Input fieldTypeDescription
idintegerPlaybook ID

brain_playbooks_archive#

Archive an active playbook (no new runs can be started).

  • Auth: brain:write
Input fieldTypeDescription
idintegerPlaybook ID

brain_playbooks_delete#

Permanently delete a playbook. Refuses if there are any active or paused runs.

  • Auth: brain:write
Input fieldTypeDescription
idintegerPlaybook ID

brain_playbooks_add_step#

Add a step to a playbook (only on draft playbooks).

  • Auth: brain:write
Input fieldTypeDescription
playbookIdinteger
keystringUnique step key within the playbook
namestringDisplay name
kindtask|note|meeting|decision|review_item|wait|branch
nextStepKeysstring[] (optional)Keys of following steps
configobject (optional)Step-kind-specific configuration
condition{ field, op, value? }|null (optional)Branch condition
descriptionstring (optional)
sortOrderinteger (optional)

brain_playbooks_update_step#

Patch fields on a step.

  • Auth: brain:write
Input fieldTypeDescription
stepIdintegerStep ID
patchobjectSame optional fields as add_step

brain_playbooks_remove_step#

Remove a step from a playbook.

  • Auth: brain:write
Input fieldTypeDescription
stepIdintegerStep ID

brain_playbooks_reorder_steps#

Reorder steps within a playbook by providing the full ordered list of step IDs.

  • Auth: brain:write
Input fieldTypeDescription
playbookIdinteger
stepIdsinteger[]Full ordered list of step IDs

Playbook Runs#

brain_playbook_runs_list#

List runs. Slim row default. Filter by status and/or playbookId. Limit capped at 100.

  • Auth: brain:read
Input fieldTypeDescription
statuspending|active|paused|completed|aborted|failed or array (optional)
playbookIdinteger (optional)
limitinteger 1–100 (optional)
offsetinteger (optional)

brain_playbook_runs_get#

Get one run with { run, playbook (slim), steps, links }. Heavy JSON columns are opt-in.

  • Auth: brain:read
Input fieldTypeDescription
idintegerRun ID
include["context"]|["triggerPayload"] (optional)

brain_playbook_runs_active_for_entity#

List active and paused runs anchored to a given entity via playbook links.

  • Auth: brain:read
Input fieldTypeDescription
entityTypeinitiative|person|crm_company|crm_deal|meeting|decision
entityIdinteger

brain_playbook_runs_start#

Start a playbook run.

  • Auth: brain:write
Input fieldTypeDescription
playbookIdintegerMust be active
labelstring (optional)Human-readable run label
contextobject (optional)Seed data for the run
triggerPayloadobject (optional)
linkedEntities{entityType, entityId}[] (optional)Anchor the run to entities

brain_playbook_runs_advance#

Advance a run to the next step (or complete it if no further steps). Triggers recursive spawn chaining when explicit step completion is used.

  • Auth: brain:write
Input fieldTypeDescription
runIdintegerRun ID

brain_playbook_run_steps_complete#

Mark a specific run step as completed, providing an optional result entity reference.

  • Auth: brain:write
Input fieldTypeDescription
runIdintegerRun ID
stepIdintegerStep ID
resultEntityTypestring (optional)Entity type of the result
resultEntityIdinteger (optional)Entity ID of the result

brain_playbook_run_steps_skip#

Skip a specific run step with a reason.

  • Auth: brain:write
Input fieldTypeDescription
runIdintegerRun ID
stepIdintegerStep ID
reasonstring (optional)

brain_playbook_runs_abort#

Abort a run.

  • Auth: brain:write
Input fieldTypeDescription
runIdintegerRun ID
reasonstring (optional)

Documents#

Documents are versioned SOPs, policies, and required-reads. The lifecycle is: create → edit draft → publish → (archive / unarchive). Acknowledgments are the compliance record.

brain_documents_list#

List versioned documents. Slim by default. Pass include: ["body"] to hydrate each row with the current published version's body (heavy). Limit capped at 100.

  • Auth: brain:read
Input fieldTypeDescription
statusdocument status enum (optional)
categorydocument category enum (optional)
ownerIdinteger (optional)
searchstring (max 500, optional)
limitinteger 1–100 (optional)
offsetinteger (optional)
include["body"] (optional)

brain_documents_get#

Fetch a single document with version list and links. includeBody: true attaches current published + draft version full rows; includeAllVersions: true attaches every version row.

  • Auth: brain:read
Input fieldTypeDescription
idintegerDocument ID
includeBodyboolean (optional)
includeAllVersionsboolean (optional)

brain_document_versions_list#

List a document's versions newest-first. Slim by default; opt into "body", "changeNotes", "summary" via include. Limit capped at 100.

  • Auth: brain:read
Input fieldTypeDescription
documentIdinteger
limitinteger 1–100 (optional)
offsetinteger (optional)
includestring[] (optional)"body", "changeNotes", "summary"

brain_document_versions_get#

Fetch one specific document version. Full markdown body ships by default. Optional "changeNotes" and "summary" via include.

  • Auth: brain:read
Input fieldTypeDescription
versionIdintegerVersion ID
includestring[] (optional)"changeNotes", "summary"

brain_documents_create#

Create a new document seeded with an empty v1 draft. Echo: { id, slug, status, version1Id }. Follow up with brain_document_versions_edit_draft, then brain_documents_publish.

  • Auth: brain:write
Input fieldTypeDescription
titlestring (1–255 chars)
categorydocument category enum (optional)
ownerIdinteger|null (optional)
confidentialityLevelstandard|restricted|confidential (optional)
defaultTopicIdsinteger[] (optional)Auto-link topics on creation
sourceNoteIdinteger|null (optional)Note this document was promoted from

brain_documents_update#

Patch document-level metadata (title, category, ownerId, confidentialityLevel, defaultTopicIds). Status changes return { error: "use_publish_or_archive" }.

  • Auth: brain:write
Input fieldTypeDescription
idintegerDocument ID
patchobjecttitle, category, ownerId, confidentialityLevel, defaultTopicIds

brain_document_versions_edit_draft#

Patch the document's draft body / summary / changeNotes. If no draft exists (last action was a publish), creates a new draft seeded from the latest version body. Refuses if the document is archived.

  • Auth: brain:write
Input fieldTypeDescription
documentIdinteger
patchobject{ body?, summary?, changeNotes? }

Response:

{ "documentId": 5, "versionId": 18, "versionNumber": 3, "isDraft": true }

brain_documents_publish#

Flip the current draft to a published version. Refuses if no draft exists or if the draft body is empty — returns { error: "empty_draft_body" } in that case.

  • Auth: brain:write
Input fieldTypeDescription
idintegerDocument ID

brain_documents_archive#

Soft-archive a document — sets status to archived. Document remains in the database.

  • Auth: brain:write
Input fieldTypeDescription
idintegerDocument ID
reasonstring (max 2000, optional)Archive reason

brain_documents_unarchive#

Reverse archive — restores status to published (if a published version exists) or draft otherwise.

  • Auth: brain:write
Input fieldTypeDescription
idintegerDocument ID

brain_documents_delete#

Hard-delete a document and (via FK cascade) every version, required-read, link, and acknowledgment. Refuses by default if any acknowledgments exist — returns { error: "document_has_acks", ackCount }. Pass force: true to cascade.

  • Auth: brain:write
Input fieldTypeDescription
idintegerDocument ID
forceboolean (optional)

brain_documents_promote_from_note#

Create a new document seeded from an existing brain note — the note's body becomes the v1 draft body. Echo: { documentId, slug, version1Id }.

  • Auth: brain:write
Input fieldTypeDescription
noteIdintegerSource note ID
titlestring (optional)Defaults to note title
categorydocument category enum (optional)

Attach a polymorphic entity (topic, initiative, decision, meeting, glossary_term, person) to a document. Idempotent.

  • Auth: brain:write
Input fieldTypeDescription
documentIdinteger
entityTypetopic|initiative|decision|meeting|glossary_term|person
entityIdinteger
notestring|null (optional)

Remove a polymorphic link from a document.

  • Auth: brain:write
Input fieldTypeDescription
documentIdinteger
entityTypesame enum as brain_documents_link
entityIdinteger

Document Required Reads & Compliance#

brain_document_required_reads_list_for_document#

Who is required to read this document? Returns rows with targetType, targetId, targetName, pinnedVersionId, dueAt, assignedAt. Limit capped at 100.

  • Auth: brain:read
Input fieldTypeDescription
documentIdinteger
targetTypeperson|org_unit (optional)
limitinteger 1–100 (optional)
offsetinteger (optional)

brain_document_required_reads_list_for_person#

What does this person have to read? Returns direct required-read assignments with acknowledgment status. status filter: open, acknowledged, all (default).

  • Auth: brain:read
Input fieldTypeDescription
personIdinteger
statusopen|acknowledged|all (optional)
limitinteger 1–100 (optional)
offsetinteger (optional)

brain_document_acknowledgments_list_for_document#

Audit trail of every (version, person, acknowledgedAt) recorded against a document.

  • Auth: brain:read
Input fieldTypeDescription
documentIdinteger
versionIdinteger (optional)
personIdinteger (optional)
limitinteger 1–100 (optional)
offsetinteger (optional)

brain_document_acknowledgments_list_for_person#

Every document a person has acknowledged, newest first.

  • Auth: brain:read
Input fieldTypeDescription
personIdinteger
limitinteger 1–100 (optional)
offsetinteger (optional)

brain_document_compliance_report#

The canonical "who has read this, who hasn't" view. Expands org-unit required-reads to active member person IDs, partitions the assigned universe into acknowledged / pending / overdue, and returns full ID arrays plus a summary count rollup.

  • Auth: brain:read
Input fieldTypeDescription
documentIdinteger

Response:

{
  "documentId": 5,
  "currentPublishedVersionId": 18,
  "acknowledged": [14, 22],
  "pending": [33],
  "overdue": [41],
  "counts": { "acknowledged": 2, "pending": 1, "overdue": 1, "total": 4 }
}

brain_document_required_reads_assign#

Make a person or org unit required to read a document. Idempotent on (documentId, targetType, targetId). When targetType: "org_unit" and expandOrgUnit: true, fans out to one row per active member (current snapshot). Echo: { assigned, alreadyAssigned, expandedTo? }.

  • Auth: brain:write
Input fieldTypeDescription
documentIdinteger
targetTypeperson|org_unit
targetIdinteger
pinnedVersionIdinteger|null (optional)Pin to a specific version
dueAtstring|null (optional)ISO timestamp
expandOrgUnitboolean (optional)Fan out to active org-unit members

brain_document_required_reads_remove#

Delete a required-read row. Refuses by default if any acknowledgments reference it — returns { error: "has_acks" }. Pass force: true to unlink (acks survive but lose their pointer).

  • Auth: brain:write
Input fieldTypeDescription
requiredReadIdintegerRequired-read row ID
forceboolean (optional)

brain_documents_acknowledge#

Record a (documentId, versionId, personId) acknowledgment. Idempotent. If requiredReadId is omitted, auto-links to a matching person-target required-read when one exists.

  • Auth: brain:write
Input fieldTypeDescription
documentIdinteger
versionIdinteger
personIdinteger
acknowledgmentNotestring (max 10 000)|null (optional)
requiredReadIdinteger|null (optional)

Response:

{
  "ackId": 77,
  "documentId": 5,
  "versionId": 18,
  "personId": 14,
  "acknowledgedAt": "2026-06-04T09:00:00.000Z"
}