Omniscio documentation
Browse all documentation
  1. Getting Started13
  2. Sessions & Agents115
  3. Inbox & Notifications59
  4. Projects & Tasks95
  5. Automation & Scheduling75
  6. Knowledge & Memory26
  7. AI Features60
  8. Integrations100
  9. Plugins & Marketplace33
  10. Cloud & Teams56
  11. Settings & Customization58
  12. Account & Billing28
  13. Troubleshooting84
  14. CLI & API Reference22
  15. Legal & Policies4
  16. Uncategorised22

KMS agent tools — expose your Markdown vault to spawned agents

An opt-in extension that lets the Claude sessions Omniscio starts read and write your KMS vault through agent tools — searching, fetching, listing and traversing notes, and separately creating, appending and editing them. The read and write halves are gated by two different switches, off by default.

What it is

KMS is Omniscio's built-in Markdown vault editor (described in kms.md) — point Omniscio at a folder of .md notes, and an indexer + chokidar watcher keep an in-app TipTap editor in sync with the files on disk. KMS agent tools are an opt-in extension that lets every Claude Code session Omniscio spawns interact with that vault through MCP tools. There are two tiers: ten read tools (search, fetch, list, traverse, semantic search, inventory, and three image tools) and four write tools (create, append, update properties, insert at position). Read tools are gated by one toggle; write tools have their own separate toggle plus rate limiting and folder restrictions. The user-visible surface is at Settings → Workflow → Features, off by default.

Once on, every new Claude CLI session Omniscio starts has an extra MCP server in its curated .mcp.json — a private per-session file Omniscio hands to the CLI, not one written into your project folder. The agent calling kms_search or any of the other tools reaches an out-of-process Node subprocess (no UI, no API spend, no network) that reads and writes the same SQLite database the in-app editor uses, applies the same hidden-note filter, and returns JSON.

Where to find it

Settings → Workflow → Features, where the read and write halves are two separate toggles, both off by default. The tools themselves are invisible in normal use — they appear to the agent, not to you.

How it behaves

How to use it

  1. Turn on KMS first. Settings → Workflow → Features → Enable KMS. Pick a vault root if you haven't already (the vault root is the folder full of .md files). This step lights up the editor; the agent tools toggle is hidden until KMS is on.
  2. Turn on read tools. Same panel, the row labeled "Expose KMS vault to spawned agents". Off by default. Flipping this on does not retroactively re-spawn live sessions — it applies to the next session Omniscio starts.
  3. Turn on write tools (optional). A separate toggle labeled "Allow agents to write to KMS vault" appears once read tools are on. This enables kms_create, kms_append, kms_update_properties, and kms_insert_at. Write tools have additional safety controls (see below).
  4. Use Claude normally. When the agent asks itself a question your vault can answer ("what did I write about the kestrel migration?"), it can now call kms_search and read the matching note bodies directly via kms_read. With write tools on, the agent can also create and edit notes. There is no UI surface for the call itself — it happens inside the spawned session's tool-use stream, the same way file reads and bash commands do.
  5. Verify the wiring (optional). In a new session, paste: Use your kms_list_recent tool to show me the 5 most recently updated notes. If the tool is wired, the agent responds with the list; if not, it replies that the tool isn't available.
  6. Turn it off any time. Same toggle. Already-running sessions keep the tools until they end; new sessions don't get the .mcp.json block.

The ten read tools

Every read tool excludes notes whose hidden_at column is set (the "hide from tree" stamp you can apply in the in-app editor — agent visibility tracks UI visibility). Every tool's output is capped at 100 KB of serialized JSON per call; over-cap responses return { truncated: true, cursor: "<last-id>" } so the agent can narrow its query.

  • kms_search(query, limit?) — FTS5 search across every vault's notes. Returns BM25-ranked hits with title, excerpt (~200 chars with the match highlighted), positive-scaled score (the underlying bm25 is negated so "higher = better" matches LLM intuition), tags, and updated-at timestamp. Default limit 10, max 50. Empty query returns [] without hitting the DB. Malformed FTS5 syntax (unbalanced quotes, stray colons) returns { error: 'invalid-input' } so the agent can retry with a cleaner query.

  • kms_read(noteId) — Fetch one note by id. Returns title, body (with the AI summary marker block stripped), tags, the structured summary (state + hash + extracted text when a marker is present), and updated-at. Unknown id or hidden id returns { error: 'not-found' } — hidden notes are not surfaced through direct read either.

  • kms_list_tags() — Every distinct tag in every vault with its note count. Sorted by count DESC, tag ASC. Tags whose only carriers are hidden notes don't surface.

  • kms_list_recent(limit?) — N most recently updated notes across every vault. Sorted by updated_at DESC, then id ASC for stable ordering. Default limit 10, max 50.

  • kms_get_backlinks(noteId, limit?) — Every note that wiki-links to the given target via [[Title]] syntax. Returns source title + id + a short snippet of context around the link. Self-links are excluded; hidden source notes are excluded; a hidden target returns not-found (same intent as kms_read). Default limit 25, max 50.

  • kms_semantic_search(query, limit?) — Hybrid semantic + keyword search across every vault's notes. Embeds the query with the all-MiniLM-L6-v2 model and combines FTS5 BM25 keyword hits with embedding cosine similarity via Reciprocal Rank Fusion (RRF). Finds notes by meaning — e.g. "error handling in auth" finds relevant notes even if they use different words. Each hit includes a matchType field ('keyword', 'semantic', or 'both') so the agent knows WHY it matched. Falls back gracefully to keyword-only search when the embedding model isn't ready. Default limit 10, max 50.

  • kms_inventory(cursor?, limit?) — Paginated inventory of every visible note across every vault. Each entry carries { noteId, title, tags, updatedAt, summary: { state, text }, tokenEstimate, sizeBytes }. Summary text is decoded from the body HEAD only — no full bodies are read and no summaries are generated. Pages via an opaque cursor: when more rows remain the result carries nextCursor — re-call with it to continue. Order is newest-first (updatedAt DESC, noteId ASC). Default limit 100, max 500. Zero cost (local SQLite only). On a rare payload-cap overflow returns { truncated: true, cursor } where cursor is the SAME input cursor so the agent re-calls with a smaller limit without skipping notes. See kms-vault-overview.md for the equivalent user-facing panel.

  • kms_list_images — the most recently analyzed images across every vault, newest first, read from the same image-analysis table the in-app image view uses. Spend and token fields are stripped from the output, since the agent has no use for them.

  • kms_search_images — BM25 search over the images' own text (tags, category, description) across every vault, with the rank negated so higher-is-better, matching the kms_search convention. An empty or whitespace-only query returns { results: [] } without touching the database.

  • kms_image_details — one image's full analysis, looked up by its content hash. Scoped to a single vault when you name one; without a vault it walks the vaults in registration order and the first match wins.

Cross-vault scope: none of these take a vaultId. The agent sees the union of every registered vault. If you have one vault (the common case), this is a non-issue; if you have many, results from different vaults can mix and the agent uses the snippet/title to disambiguate.

The four write tools

Write tools require a three-flag progressive opt-in: nothariEnabled + nothariAgentToolsEnabled + nothariAgentWriteToolsEnabled — all three must be on. They are subject to rate limiting and an optional folder allowlist (see Safety model below). Every write is recorded in the nothari_tool_invocations provenance table (see Provenance tracking below).

  • kms_create(title, content?, tags?, folder?) — Create a new note. title becomes the filename (auto-sanitized: colons → dashes, slashes → dashes, capped at 200 chars). content is optional Markdown body (max 100 KB). tags is an optional array of hashtags (validated against ^[a-zA-Z0-9][a-zA-Z0-9_-]*$, max 50 per note). folder places the note inside a vault subfolder (validated against the folder allowlist if one is configured). Returns { noteId, title, path }. Duplicate titles in the same folder return { error: 'already-exists' }.
  • kms_append(noteId, content, heading?, separator?) — Append content to an existing note by id. content is the Markdown to add (max 50 KB). heading (optional) targets a specific heading — the content is inserted after the heading's last line rather than at the end of the note. separator controls how the appended block is separated from existing content (default '\n\n'). Uses optimistic concurrency: the tool captures the note's updated_at timestamp, and if the note was modified between read and write, it retries once automatically; a second conflict returns { error: 'conflict' }.
  • kms_update_properties(noteId, set, remove?) — Update YAML frontmatter properties on a note. set is a record of key-value pairs to add or overwrite (values can be strings, numbers, booleans, or arrays). remove is an optional array of keys to delete. The kms_provenance key is reserved and cannot be set. Tags are reconciled: setting a tags property in the frontmatter merges with inline #hashtags; removing a tag from frontmatter removes it from the note. This tool is exempt from the folder allowlist (it modifies metadata only, not file location).
  • kms_insert_at(noteId, content, position) — Insert content at a specific position in a note. position is one of four targeting modes: { afterHeading: "## Section" } inserts after the named heading's content, { beforeHeading: "## Section" } inserts before the heading line, { afterBlockContaining: "search text" } inserts after the paragraph containing the given text, or { atLine: N } inserts at an exact line number (1-based). Max 50 KB content. Same optimistic concurrency as kms_append.

All four write tools return a result envelope on success or an error envelope (not-found, feature-disabled, rate-limited, conflict, folder-denied, already-exists, invalid-input). A rate-limited error includes a retryAfterMs hint.

Safety model (write tools)

Write tools have three layers of protection against runaway agents:

  • Rate limiting — a per-session sliding-window counter. Default: 10 writes per minute and 200 writes per session (both configurable in Settings). When either limit is hit, the tool returns { error: 'rate-limited', retryAfterMs }. The limiter resets when the session ends. Rate limits are enforced in the MCP server process, not in Omniscio main.
  • Folder allowlist — an optional list of vault subfolders the agent is allowed to write into (configured in Settings as a list of folder paths, supports single-segment globs like drafts/*). When configured, kms_create, kms_append, and kms_insert_at check the target note's folder against the allowlist and return { error: 'folder-denied' } if it doesn't match. An empty allowlist means "all folders allowed." kms_update_properties is always exempt (metadata-only).
  • No destructive operations — there is no kms_delete, kms_rename, or kms_move tool. Agents cannot delete, rename, or relocate notes. The kms_append and kms_insert_at tools add content; they do not replace or remove existing content. kms_update_properties can remove frontmatter keys but cannot touch the note body.

Provenance tracking

Every write tool invocation is recorded in the nothari_tool_invocations table with: tool name, session id, note id, a summary of the input, result status (success / error / conflict), line count added, and timestamp. This table is FTS5-indexed for search integration — provenance records surface as a fourth result type in the unified KMS search.

Read-tool access tracking (nothari_tool_reads table) was designed but the write path was never wired, so no read-access data is currently recorded.

What the agent does and doesn't see

  • Sees (read tools): every note body (excluding hidden), every tag, every wiki-link, the AI summary text (when present), updated-at timestamps. The same content the in-app editor renders.
  • Can do (write tools, when enabled): create new notes, append content, update frontmatter properties, insert at specific positions. Every write is provenance-tracked and rate-limited.
  • Cannot do: delete, rename, or move notes. There is no kms_delete, kms_rename, or kms_move tool. Agents also cannot overwrite existing content — kms_append and kms_insert_at are additive only. Destructive file operations remain available as bash file-system tools if needed.
  • Doesn't pay: tools hit local SQLite only. Zero API spend. No network. The agent's per-turn input/output cost goes up by the bytes of the returned JSON because the agent has to read the response, but no Anthropic-billed call is made on Omniscio's side.

Known limitations

  • No destructive tools. There is no delete, rename, or move tool. Agents can only add content. Destructive operations remain available as bash file-system tools.
  • Write tools are additive only. kms_append and kms_insert_at add content; there is no "replace" or "overwrite" mode.
  • Cross-vault aggregation. Multi-vault users get unified results; if you need to scope, the agent can search for vaultName: patterns in the snippet text, but a dedicated vaultId parameter isn't there yet.
  • Payload cap is 100 KB hard (read tools). Tools that exceed it return { truncated, cursor } rather than a partial result — the agent must narrow its query.
  • Flipping the toggle off mid-session doesn't tear down the spawned MCP subprocess. The toggle change applies to new sessions.
  • No Settings UI for write tool configuration yet. The four new settings (nothariAgentWriteToolsEnabled, rate limits, folder allowlist) work via the existing settings system and are configurable through the CLI, but the Settings panel section is planned for a follow-on PR.
  • Session-to-note capture (structured capture of decisions/findings at session end, auto-capture rules) is designed but not yet implemented (Phase 2b/2c).

For agents

How it works

The toggle nothariAgentToolsEnabled lives in /src/shared/types.ts (default false) and is surfaced at /src/renderer/src/features/settings/sections/features/KmsFeatureSettings.tsx under the existing KMS Features section. The toggle is gated by the parent nothariEnabled flag — both must be on for tools to appear.

When Omniscio spawns a new Claude CLI session, the process manager runs /src/main/services/mcp/mcp-config-orchestrator.ts which composes a single .mcp.json file at a private per-session path (not the session's working directory; handed to the CLI via --mcp-config — see backend-spawn-contract.md §12). The orchestrator composes the enabled servers — Zapier, Playwright, Google Drive, Mobbin, Canva, plus any user-configured custom MCP servers (ResolvedCustomMcpServer rows). Each built-in server entry is built by a tiny pure-function builder (for example /src/main/services/zapier/mcp-config-entry.ts and /src/main/services/drive-mcp/mcp-config-entry.ts) so the orchestrator can mix-and-match without any feature owning the file write. MemPalace, KMS, Google Workspace, Fathom, JLS Image Studio and Webapp Verify were retired from composition on 2026-09-19 (see the note on McpOrchestratorOpts in /src/main/services/mcp/mcp-compose.ts) — and the KMS vault keeps serving agents through the control server's /kms/* routes and its skill instead of a spawned per-session process. The KMS and memory per-session entry builders were deleted with the retirement; the Google Workspace one is deliberately retained as the written-down shape a revival would restore, and its own comment says not to read it as a live path.

The KMS MCP server itself lives at /src/main/services/kms-mcp-server/ and is bundled to out/mcp/nothari-server.js by /scripts/build-kms-mcp.js (esbuild, externalizes better-sqlite3 + electron + electron-log). On spawn, the orchestrator launches it via ELECTRON_RUN_AS_NODE=1 + process.execPath — the same pure-Node-via-Electron pattern MemPalace uses to avoid bundling a separate Node runtime. The server reads three env vars from its process environment: KMS_DB_PATH (absolute path to mission-control.db), KMS_ENABLED ('1'/'0' — parent feature flag), and KMS_AGENT_TOOLS_ENABLED ('1'/'0' — agent-tools sub-feature flag). It opens the database in WAL mode and builds a frozen feature gate from the two flag vars; the gate is checked on every tool call but never re-read, so flipping a toggle mid-session takes effect on the next session spawn. The server then serves the tools through the standard MCP ListToolsRequestSchema + CallToolRequestSchema handler pair.

The tool functions themselves are pure: they take a Database.Database handle, the parsed input, and a gate object, and return either a result envelope, a { error } envelope, or a { truncated: true, cursor } envelope. The read tools live in /src/main/services/kms/agent-tools-read.ts.

The write half is GONE. agent-tools-write.ts and its two siblings were deleted 2026-09-29: the KMS MCP server only ever registered and dispatched the ten READ tools, on a read-only DB handle, so the write cluster could never be listed or called and its only consumer was its own unit test. Sessions write to the vault the way the session primer tells them to — as plain .md files, with their own file tools.

Write tools use direct DB writes with optimistic concurrency (CAS via WHERE updated_at = ?) rather than going through note-crud-service.ts's file-based path, since the MCP server doesn't have filesystem access to the vault. The kms_create tool uses gray-matter for frontmatter serialization (same library the in-app editor uses). Every successful write records a row in nothari_tool_invocations for provenance. Read tools now record aggregated access in nothari_tool_reads (one row per note+session pair, UPSERT on each read).

Sub-feature gating is enforced in the spawned server (defense in depth) — even if Omniscio's main process wrote the .mcp.json block while the toggle was on, flipping the toggle off mid-session would cause new calls to return feature-disabled because the env var is read once on subprocess start. The same hidden-note + payload-cap contract is enforced at the tool function level, not by the calling MCP adapter. The write gate checks all three flags independently: nothariEnabled, nothariAgentToolsEnabled, and nothariAgentWriteToolsEnabled.

Force-disable: Search-window and Ask-Omniscio sessions are isolated from the user's data by design, so the orchestrator's mempalaceForceDisabled / kmsForceDisabled overrides are set when those sessions spawn (/src/main/process/process-manager.ts) regardless of the user's settings. No .mcp.json is written if every server is disabled.

The integration registry entry for KMS (/src/shared/integration-registry.ts) declares agentToolPrefixes: ['kms_'] so the integration completeness lint covers the new tool surface; the per-feature lint at /tests/unit/lint/kms-agent-tool-registry.test.ts cross-checks that every name in READ_ONLY_TOOLS has a matching Zod schema export and handler function. The read tools are covered by /tests/unit/services/kms/agent-tools-read.test.ts (39 tests) against a real :memory: SQLite with full migration.

Related

  • kms.md — the parent Markdown vault feature
  • kms-summaries.md — the AI summary marker codec the tools' summary field surfaces
  • mempalace-memory.md — the other MCP server Omniscio injects into spawned sessions; uses the same orchestrator

Last verified 2026-10-01