Grove documentation

Memory tools and API

Reference for Grove note and notebook tools, authentication, scoped search, revisions and API behavior.

The Node 24 Hono service exposes /v1 REST and stateless Streamable HTTP /mcp. Both call the same transactional memory service and Zod contracts. The published CLI is an API-only stdio bridge; it has no database credentials or local database.

The owner-only Files & storage API projects upload metadata, authorized locations and conservative storage counters without exposing source keys or widening the existing original-download readers.

Authentication

Private /v1 data endpoints and /mcp require Authorization: Bearer …:

  • Website: Clerk session JWT, fixed issuer/JWKS, RS256, expiry, session ID and exact authorized website origin. No cookies are accepted directly by the API.
  • Agent OAuth: Clerk Backend API verifies active access tokens, exact resource audience API_ORIGIN/mcp, user subject, OAuth client identity and token scopes. Clerk requires openid; its scopes establish identity, not memory permissions. Grove checks the database connection's memory:* capabilities and project grant on every call. An identity token alone grants no content access.
  • Headless: named random API keys, stored hashed, with the same grant enforcement.

An unapproved OAuth client gets no memory access. Keys never grant account-admin access. Connections may include personal memories, selected projects, or all current and future projects. Revocation is checked for each request. Revoked keys cannot be reactivated. OAuth reapproval requires a token issued after the new authorization cutoff. Client-supplied owner IDs are rejected.

Protected-resource discovery: /.well-known/oauth-protected-resource/mcp. Anonymous requests receive 401 and WWW-Authenticate. Provider outages return 503, not a fabricated connected state. Development and production OAuth verification are recorded in delivery evidence; this is not acceptance of either hosted-chat client. See hosted-chat setup.

An authenticated, unapproved OAuth client can initialize MCP and list tool schemas, but cannot read or write notes. Remote tool calls return connection_required with an exact connection link and authenticated client ID for owner approval. This is a Grove permission failure, not a 401 challenge that should restart OAuth. Tool listing and the connection's last-contact timestamp do not prove host tool use.

Owner GET /v1/connections includes a state fingerprint. The website sends it as expectedState on PATCH /v1/connections/:id; an atomic mismatch returns 409 connection_conflict without editing/reactivating the grant. Contact timestamps are excluded. Existing API callers may omit it for backward compatibility; it does not authorize anything and never replaces an owner session.

Public read-only sharing uses separate capability-checked /public/shares/* routes. Link management requires the owning website session; OAuth/API keys cannot publish content. See sharing for routes, permissions, live membership, pagination, independent public limits and revocation.

Directory domain verification

Set optional API-only OPENAI_APPS_CHALLENGE to the exact public token issued by OpenAI. GET /.well-known/openai-apps-challenge returns only that plain text, with no-store and nosniff; it returns 404 when unset. HEAD returns no body. There is no proof-upload endpoint, redirect, database lookup, authentication grant or access to notes. The token is a public ownership proof, not an access credential. Whitespace and values over 512 characters are rejected rather than silently changed.

All memory tools publish human-readable titles and explicit safety annotations for directory discovery. Names, arguments and per-call permissions remain unchanged.

Memory and notebook tools

Tools carry shared human-readable note-writing guidance and model-visible content/scope/capture/version/retry descriptions. Note bodies use CommonMark/GFM; a supplied content replaces the complete body even on a partial field update. Guidance does not normalize content, change validation or authorize an action. Existing schemas, bounds, defaults and grants remain unchanged.

ToolPurposeMain fields
rememberDurable save or versioned correctionoperationId, content, kind, projectId, source; correction: id, expectedVersion
recallBounded active contextquery, projectId, includePersonal, optional taskId
memoriesInspect IDs, versions, provenance and statusesquery, projectId, kind, status, cursor, limit
forgetExact-ID soft deletion; retained history is hiddenoperationId, items: [{id, expectedVersion}]
get_memoryExact current or historical noteid, optional revision
memory_historyLatest 100 revisionsid
update_memoryPartial edit; omitted fields preservedoperationId, id, expectedVersion, changed fields
move_memoriesAtomic batch filing (up to 50)operationId, items, destination projectId or null
archive_memory, restore_memoryArchive or restore an exact noteoperationId, id, expectedVersion; restore: optional revision, durable
notebooksPaginated directory/tree discoverystatus, query, parentId, cursor, limit
create_notebookRetry-safe notebook creationoperationId, name, optional parentId
update_notebookPartial rename/moveoperationId, id, expectedVersion, name and/or parentId
notebook_lifecycleOwner-only subtree preview/archive/restore/deleteid, action; changes also require operationId, expectedVersion, preview fingerprint

All 14 tools share schemas and execution between remote MCP and the packaged stdio bridge. POST /v1/tools/:tool accepts the same arguments and normal REST envelopes. Existing REST routes and the original four tools remain compatible. Ship the matching API before the upgraded bundled clients; an older server cannot execute new tools.

Use update_memory for corrections: omitted content, notebook, kind, provenance, task ID and lifetime stay unchanged. Legacy remember corrections still replace metadata, so callers must supply it. To convert a handoff, set kind: "fact" and taskId: null; set retentionDays: null too if it should become permanent. Optional capture: "automatic" obeys both server and packaged-host privacy controls.

Notebooks are folders, represented internally by project IDs. Follow notebooks cursors to discover the full granted tree; hidden parents remain hidden. Moving notes/notebooks checks both source and destination grants. Notebook creation requires all-project write access or an owner session. Notebook subtree lifecycle and archived notebook listing remain website-owner session only, including through the tool endpoint; OAuth and API keys cannot use these operations. Hierarchy never inherits permissions. parentId: null moves a notebook to the root.

Deletion is retained soft deletion, not physical erasure. Deleted notes/notebooks cannot be restored through these tools; use archive when later restoration is needed. Batch moves are all-or-nothing; forget retains its per-item outcome contract.

Kinds: preference, fact, decision, solution, handoff. Personal scope is projectId: null. Project IDs are account-owned UUIDs. A handoff requires a stable taskId; update its existing ID/version instead of creating duplicate handoffs. Content is trimmed, 1–6,000 characters. capture: "automatic" is rejected when automatic capture is paused; explicit user-requested saves use "explicit".

retentionDays is nullable and independent of kind: null keeps the note until removed; 1–365 selects a temporary lifetime. New handoffs default to 30 days and other kinds to permanent. Omission on correction preserves retention and expiry. Changing retention restarts it; restore renews it. Expired notes are hidden from recall and retained for a 60-day restoration window before soft deletion. Hidden source records and their revisions remain retained.

Use a new UUID operation ID per mutation and keep it across retries. Reusing an ID with different arguments returns 409. Replaying a deleted save returns 410 and does not resurrect content. A correction race yields one success and one conflict. Deletion reports deleted, not_found, or version_conflict per item.

remember returns the actual current memory and indexing: pending|ready|failed. Storage success does not claim the embedding has finished. Revisions and embedding jobs are committed with the save. MCP failures set isError: true.

Recall defaults: 8 items, 6,000 total content/metadata characters (approximately 1,500 tokens), no unrelated filler. Full-text and semantic ranks are fused; semantic distance is thresholded. Query-free recall selects a compact preference/fact/decision profile, with a specific handoff only when taskId is supplied. Archived and expired records never enter normal recall. Other projects are never searched automatically. No server content cache can outlive deletion or revocation.

REST routes

Note list/recall/source search, relevance sorting, signed search cursors and optional query/version-bound matches evidence are described in note search. Explicit date sorts keep their existing ordering.

Responses use {success: true, data} or {success: false, error: {code, message, requestId}}. Export is NDJSON.

RoutesAccess
GET /v1/meAuthenticated identity/effective grant and settings
POST /v1/connectAgent starts/resumes its own connection request; API keys require existing scope
GET /v1/connect/:idRequest's agent connection or owning website session
POST /v1/connect/:id/approveOwning website session; transactional project link and grant
POST /v1/connect/:id/cancelRequest's agent connection or owning website session
GET, POST /v1/projects; PATCH /v1/projects/:idApproved scope; create needs all-project access or website session
GET /v1/projects?status=archived; GET /v1/projects/:id/lifecycleArchived listing and full-subtree preview; owner website session only
POST /v1/projects/:id/archive, /restore, /deleteOwner-only, version/snapshot-checked subtree lifecycle; deletion is soft only
POST /v1/memories; PATCH /v1/memories/:idmemory:write
GET /v1/memories; POST /v1/memories/search; GET /v1/memories/:idmemory:read
GET /v1/memories/:id/revisionsmemory:read, current scope
GET /v1/memories/:id/revisions/:versionExact historical revision; current scope, deletion and expiry checks
/v1/assistance, /v1/notebook-visitsOwning website session; notebook assistance
POST /v1/memories/:id/archive; …/restorememory:write, operation ID and current version
POST /v1/memories/deletememory:delete
POST /v1/recallmemory:read
POST /v1/tools/:toolSame tool schemas and scoped capabilities as MCP; notebook lifecycle remains owner-only
POST /v1/askScoped memory:read; cited answer or source search
GET, POST /v1/conversations; GET, DELETE /v1/conversations/:idOwning website session only; saved chat history
POST /v1/conversations/searchOwner-only history search: { query?, after? }; titles/questions, 30 results and signed cursor
POST /v1/conversations/:id/turns; …/turns/:turnId/apply; …/undoOwning website session only; contextual replies and previewed note changes
/v1/conversations/:id/documents; /v1/memories/:id/document-sourcesOwning website session only; private upload/evidence/conversion/original routes; see documents
POST /v1/briefs; POST /v1/briefs/refreshScoped memory:read / memory:write; body {projectId, taskId?}
POST /v1/memories/:id/reprocessScoped memory:write; body {expectedVersion}
GET /v1/models; GET /v1/account/usageWebsite session; masked settings / account usage
PATCH /v1/models; POST /v1/models/testConfigured self-hosted installation administrator only
GET, POST /v1/connections; PATCH, DELETE /v1/connections/:idWebsite session only
POST /v1/keysWebsite session only; secret returned once
POST /v1/logoutRevoke calling agent's connection
PATCH /v1/account/settings; POST /v1/account/deleteWebsite session only
/v1/exports, /v1/imports, /v1/tasksSession-owner durable work; see jobs
POST /v1/webhooks/clerkSvix signature, replay receipt and event ordering
GET /health/live, /health/readyPublic, content-free

Use POST search so query text stays out of URLs. Cursors are signed and bound to account, connection, filters, and creation-time ceiling. Pagination is bounded, not a database snapshot of concurrent edits. Idempotency-Key may supply the body operation ID; conflicting identifiers are rejected. Restore can select an older revision and creates a new revision; durable: true promotes a handoff to a fact.

Library filters also accept sourceAgent, updatedAfter, lifetime (permanent/ephemeral), and sort (updated_desc/updated_asc/created_desc). POST /v1/ask accepts query, optional projectId, includePersonal, previousQuestions (up to four), and mode (answer/search). Omitted project scope searches all authorized notebooks; null selects Personal. Replies include sources and a structured, exactly cited answer, or an explicit no-evidence/disabled status. Aborted requests cancel inference. No question or answer is stored as a note.

The website's Ask mode uses durable conversations. Create with a client UUID, optional projectId and includePersonal. Submit turns with a client UUID, query (up to 6,000 characters), format (plain/markdown), and expectedVersion from the conversation. Retries reuse the same body/UUID; changed payloads conflict. Optional context: { notes: UUID[], notebooks: UUID[], only: boolean } selects per-turn evidence (12 individual notes/six direct-member notebooks, unique IDs, at least one selector). Strict mode excludes unselected retrieval/history/web evidence; large notebooks use bounded in-scope keyword retrieval, with at most12 supplied notes and explicit result.contextCoverage. Selectors persist on turns and in exports. context_unavailable (409) rejects invalid/inaccessible selectors before provider dispatch or conversation advancement. Source contract details evidence/citation distinctions, selected edit/merge previews and recovery. GET /v1/conversations?after=<last-id> returns 30 recent conversations per page. The history browser uses POST /v1/conversations/search with optional query (up to 200 characters) and after (opaque signed cursor). It searches titles and user questions with literal case-insensitive matching, returning summary fields, a bounded question preview, turnCount and nextCursor. Search text stays in the body. Cursors bind account and query and retain the exact PostgreSQL timestamp, so deleting the previous page's final row does not break pagination. Results are most-recent-first; deleted/foreign chats and assistant payloads are excluded. The cursor identifies an account-owned row; it contains no query text. History pagination reflects concurrent activity rather than a frozen snapshot.

Without strict source selection, reference resolution uses the latest eight completed turns, then retrieves current scoped evidence. Replies cite exact revisions and can propose explicit note edits, creation/merge, notebook organization, or archive/restore/delete. Lifecycle previews name exact notes and count full notebook subtrees. apply and undo take {} and atomically fence affected versions and subtree fingerprints. Deletion has no Undo; merges archive other originals. See Ask tools. Generation runs outside transactions, with final account/session, provider/settings and source checks. A conversation is limited to100 turns with five-minute attempt leases. Deleted conversations retain hidden history; account deletion revokes access and soft deletes content, and account exports include saved history. Migration 009 and restore rules are in deploy.

Persistence and jobs

Connection setup keeps one bounded JSON request on the existing RLS-protected connection row. Requests expire after ten minutes while pending. Request IDs alone authorize nothing; the account and OAuth/key connection are rechecked on every call. Approval defaults and protocol details are in Cloud onboarding. Manual grant edits and revocation invalidate outstanding requests; repeated approval returns its existing result without reapplying permissions.

lib/database uses Knex/Objection/pg with explicit open/close and transaction-local tenant context. Ownership-aware foreign keys cover projects, memories, revisions, embeddings and jobs. Runtime startup rejects superuser, BYPASSRLS and table-owner credentials. Migration credentials are separate. Security-definer entrypoints are narrow, fixed-search-path functions with public execution revoked.

The worker claims jobs with FOR UPDATE SKIP LOCKED, a 120-second lease, revision identity, bounded retries and terminal failure. Completion rechecks the lease, account and current revision in one transaction. Tombstones and generation fences prevent stale worker completion from restoring content. Embedding profiles carry checked dimensions; Cloud uses full 4,096-dimensional Qwen vectors with scoped exact search. Self-hosted defaults to local MiniLM and can configure each inference role. disabled embedding mode is explicitly lexical. Classification and generation use revision-fenced jobs; source-linked artifacts obey the same scope and lifecycle. See models for provider settings, enrichment/brief contracts, quotas, reset and reindex operations.

Account deletion first revokes access, then hides retained application content even during an identity-provider outage. Clerk deletion retries separately. Minimal subject and operation tombstones prevent delayed webhook/retry reprovisioning. Backups require the retention and deletion procedures in the deployment guide.