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 (the Vault) — notes, editor, search and sharing (part 5)

Part 5 of the KMS page: what the AI adds to the vault — the note summaries and agent tools, asking a question seeded from a note, keeping the vault loaded so it opens instantly, the standalone window, deep links to a note, and publishing one to a public web address.

What it is

This is part 5 of the KMS page. It covers the parts of the vault that reach outside it: the AI summaries and tools, asking a question based on a note, the ways to open the vault faster or in its own window, linking straight to a note, and publishing one for someone else to read.

Where to find it

From the KMS panel and from Settings. Publishing produces a public web address you can share; deep links are URLs you can keep or send.

How it behaves

Phase 6 — AI summaries + read-only agent tools

Phase 6 wired two independent slices on top of the Phase 1-5 foundation.

Per-note AI summaries. Each note can carry a <!-- kms:summary v=1 hash=… -->…<!-- /kms:summary --> HTML-comment marker block at the top of its body containing an AI-written paraphrase (≤300 chars). Omniscio tracks drift via a canonical SHA-256 hash of the body (with the marker stripped, whitespace normalized, image URLs token-replaced) and flips the summary to stale on content change, or user_edited (locked) on summary text change. An in-editor SummaryStatusChip in the status bar surfaces six states (Up to date / Stale / Locked / Generating / Budget reached / hidden when none); single-click on stale regenerates, right-click opens the full menu. An opt-in background worker (off by default — Settings → Features: nothariAutoRegenEnabled + scan interval + per-note cooldown) regenerates stale-and-unlocked summaries; concurrency 2 / 50-per-tick are fixed. Spend goes through api_cost_log via trackApiCost(accountId, 'kms-summary', model, in, out) with a per-account daily $ cap (nothariSummaryCostCapUsd, default $2, local-midnight reset). Four IPC operations: kms:generate-summary (with force to bypass the lock), kms:get-summary-status (the only cost-capped reporter), kms:clear-summary, kms:set-summary-user-edited. Bulk-seed worker for first-time vault-wide generation has its own cap (nothariBulkSeedCostCapUsd, default $5). Full mechanics: kms-summaries.md.

Read-only agent tools (MCP). When nothariAgentToolsEnabled is on (gated by the master toggle), every Claude Code session Omniscio spawns gets a .mcp.json entry pointing at a local Node subprocess that exposes five tools: kms_search, kms_read, kms_list_tags, kms_list_recent, kms_get_backlinks. The agent can query your vault during its turn — local SQLite only, zero API spend, hidden notes filtered out, payload-capped at 100 KB per call with cursor pagination, cross-vault scope. Write/delete/rename counterparts were planned (6h/6i/6j) but cut from scope — destructive operations remain available as bash file-system operations against the .md files directly. Full mechanics: kms-agent-tools.md.

The image analyzer (Phase 5f), summary service (6b), bulk-seed (6d), and auto-regen worker (6e P2) all share a common cost-tracking pattern via trackApiCost() and the per-account daily ledger in src/main/services/kms/cost-cap-ledger.ts (Phase 6c). Each path has its own configurable cap so a runaway summary worker can't exhaust the image-analysis budget and vice-versa.

Ask your vault (one-click note-seeded chat)

From an open note you can hand the whole vault to Claude in one click. The KMS editor header carries an Ask AI button (a ✨ Sparkles trigger) that drops a small menu with three actions — Summarize this note, Find related notes, and Ask a question — and the same three live as command-palette rows (ai.summarize-note, ai.find-related, ai.ask-about-vault). Picking any of them spawns a Claude session scoped to the vault (the __nothari__ project), flips the KMS main pane to its Sessions view (kmsViewMode: 'sessions'), and streams the answer there. Because that session already carries the vault primer plus the eight read-only kms_* retrieval tools (the same tools the "Agent sessions" tab and the MCP surface above expose), the answer reads and cites your real notes rather than guessing.

The chat is not a separate inline panel — it reuses the exact session the KMS "Agent sessions" tab already spawns (the main-pane SessionPanel), so there is no second chat/streaming stack to maintain; the launcher only makes that session launchable in one click and optionally pre-seeded with a prompt about the active note. The seed is a short instruction that names the note by title + vault-relative path and tells the agent to read it with its tools — the note body is never embedded in the prompt (a 167 KB note would blow the token budget). Summarize this note and Find related notes need an open note (they seed from it) and disable when none is open; Ask a question only needs a vault. Everything is gated on a configured vault root — with no vault set, the header trigger and the note-seeded palette rows render disabled and a click surfaces a humanized toast instead of a spawn. Each chat is a normal user-initiated session tracked by Omniscio's usual session cost path — there is no separate per-feature cost cap (summaries keep their own daily cap; this does not).

How it's wired (repo detail). The launcher seam is useAskVault.ts — useAskVault() returns { askVault, canAskVault }; askVault() resolves the __nothari__ project id at call time, flips setKmsViewMode('sessions'), and calls launchSession(projectId, …, 'kms-session-host', seedPrompt?) — the exact path KmsSessionsList.tsx uses, with the mandatory 'kms-session-host' source, plus the pure seed builders buildSummarizeSeed / buildRelatedSeed. The header dropdown is AskAiMenu.tsx (a ToolbarMenu, editor view only), rendered from KmsView.tsx, which also threads askVault / canAskVault onto the CommandContext. The three previously-disabled ai.* rows in commands/registry.ts are now live; ai.continue-writing stays a deliberately disabled stub (inline in-editor generation is out of scope for this wave). Full invariants — seed-never-embeds-body, the reused session seam, the vault gate, never-throws-to-caller, and the summary auto-regen ignition that shipped alongside — live in the KMS Ask-Your-Vault contract.

Keep KMS loaded for instant switching (keep-warm)

By default (desktop), once you open KMS its editor stays loaded in the background when you switch to a chat session or another project, so switching back into KMS is an instant display flip instead of a cold rebuild of the TipTap editor. It uses the same "permanent display-toggled layer" technique Omniscio already uses for the AutoHotkey editor and plugin webviews.

  • Setting: Settings → Performance → "Keep KMS loaded for instant switching" (kmsKeepWarmEnabled, default on / opt-out). Turn it off to load KMS fresh each time (the older behavior).
  • Cost: one editor held in memory, and only after you've opened KMS at least once — nothing is held until then.
  • Desktop only. Phones mount a single panel, so there is nothing to keep warm; the setting has no effect there.
  • Env kill switch: AMC_DISABLE_KMS_KEEP_WARM=1 force-disables it regardless of the setting.
  • The KMS editor is mounted in exactly one place at a time — the warm layer when keep-warm is on, or the dashboard overlay when it is off, never both. It hides automatically when KMS yields to a session chat (Sessions view + a session) or when a file/diff/inbox view takes the main pane.

Contract + invariants: kms-keep-warm-contract.md. For an always-open second window instead, see Standalone KMS window below.

Standalone KMS window

A separate OS window that hosts the full KMS experience — file tree + editor and a real session host — so the user can work KMS (notes and AI sessions) on a second monitor while Omniscio runs in the main window. Both surfaces mount the same KmsView/stores over the same vault and stay in sync in real time. Ctrl+T in the pop-out launches a KMS session and opens its chat right there — see "Session host" below.

Spec: /docs/superpowers/specs/2026-05-30-kms-standalone-window-design.md

Window chrome — the note tabs live in the title strip

The window is frameless (titleBarStyle: 'hidden', shared with the Scratchpad window). Instead of the Scratchpad's label-only StandaloneWindowTitleBar, the KMS window renders its own KmsWindowTitleBar that hosts the note tabs (TabBar) directly in that slim top strip with custom HTML caption buttons (WindowControls) at the trailing edge — so the pop-out reclaims the row the in-pane tabs bar used to spend, putting the editor ~one bar higher. The strip stays the window's drag region (only its tab controls and caption buttons opt out via .no-drag / a scoped .kms-window-titlebar … { -webkit-app-region: no-drag } rule in globals.css, so the window still moves while tabs stay clickable / drag-to-reorder), keeps the shared 40px height, and reserves space so tabs never tuck under the buttons (trailing on Windows, leading inset on macOS). KmsView renders its in-pane TabBar only when not isStandaloneWindow, so the tabs never double up; the in-app dashboard panel is unchanged. Contract: scratchpad-window-contract.md (frameless-chrome-shared-with-the-kms-window) and window-controls-contract.md.

Three open affordances (all call kmsWindow.open())

All three call the same show-or-focus entrypoint — opening the window when closed, or bringing it to the front when already open. The window is never toggled-to-hide.

  1. Pop-out button in the KMS toolbar — an ExternalLink icon in the toolbar's View group, tooltip "Open KMS in a separate window".
  2. Global hotkey — default Ctrl+Alt+N (CommandOrControl+Alt+N), system-wide OS-level shortcut. Customizable and toggleable under Settings → Keyboard Shortcuts ("KMS window" row).
  3. Tray menu — "Open KMS" item in the Omniscio system-tray menu.

Session host (Ctrl+T + chat)

The pop-out is a full session host, not only a notes surface. It boots the session store (useSessionSync + a KMS-project fetch, mirroring the detached single-session window), so the Sessions tab in its sub-sidebar goes live, and it renders the session chat (the pooled SessionPanel) in place of the editor when you are on the Sessions view with a session active — the shared pickKmsMainPane decides. Closing the chat drops back to the note editor in place (a multi-session host never self-closes on chat-close).

Ctrl+T launches a new KMS session and opens its chat in the window. Chromium swallows Ctrl+T before the DOM sees it, so the main process intercepts it in kms-window.ts via before-input-event and delivers a targeted KMS_WINDOW_NEW_SESSION webContents.send to this window ONLY (never emitPush/broadcast) — so a Ctrl+T in the main window can never spawn in the pop-out and vice-versa. KmsWindowApp handles it by launching into the KMS project with the kms-session-host source (the same path the sidebar "+ New" uses) and activating the new row.

Live sync

The standalone window forwards to the renderer exactly the channels in KMS_WINDOW_ALLOWLIST (defined in /src/main/services/detached-push-filter.ts):

KMS_NOTE_CHANGED, KMS_ACTIVE_VAULT_CHANGED, KMS_BOOKMARKS_CHANGED, KMS_SUMMARY_UPDATED, KMS_IMAGES_CHANGED, SETTINGS_CHANGED, CUSTOM_THEMES_CHANGED, KMS_OPEN_NOTE

(CUSTOM_THEMES_CHANGED was added so the KMS's own custom-theme override picks up an imported / deleted custom theme live in the pop-out window — see "Custom theme options". KMS_OPEN_NOTE is the quick-find → pop-out signal: when the Find Note search picks a note and this window is open, the handler foregrounds it and pushes the note here to open via the shared requestOpenNote sink — see "Find Note quick-switcher".)

The window is registered under role: 'kms' with its KMS project id. On top of KMS_WINDOW_ALLOWLIST, the fan-out also forwards the global chrome channels (DETACHED_GLOBAL_ALLOWLIST — theme / network / focus / app-update, the same set the detached single-session window gets, since the pop-out now hosts a real SessionPanel) and this project's session-scoped channels — matched by the pre-resolved sessionProjectId, so the live session list + open chat stay current. That last group is project-scoped on purpose: a non-KMS session's high-frequency SESSION_OUTPUT never reaches the pop-out, so a large concurrent-session fleet doesn't tax the second renderer. Everything else is dropped. Drift is prevented by /tests/unit/lint/kms-window-push-listener-coverage.test.ts — that lint fails if a new KMS push listener appears in the renderer without a matching entry in KMS_WINDOW_ALLOWLIST (the targeted KMS_WINDOW_NEW_SESSION is exempt — a point-to-point send, not a broadcast).

Key implementation files

Concern File
Window manager (singleton, lazy-created) /src/main/services/kms-window.ts
IPC handler (KMS_WINDOW_OPEN / 'kms:window-open') /src/main/ipc/kms-window-handlers.ts
Push allowlist (KMS_WINDOW_ALLOWLIST) /src/main/services/detached-push-filter.ts
Renderer HTML entry /src/renderer/kms-window.html
Renderer TS entry /src/renderer/src/kms-window.tsx
Root component (KmsWindowApp) /src/renderer/src/features/kms/KmsWindowApp.tsx
Title strip (frameless; hosts the note tabs) /src/renderer/src/features/kms/KmsWindowTitleBar.tsx
Vite rollup input (kmsWindow) electron.vite.renderer-shared.ts
Allowlist drift guard /tests/unit/lint/kms-window-push-listener-coverage.test.ts

Position memory

Window bounds (x/y/width/height) are persisted in the FK-free detached_window_positions table under the sentinel key '__kms_window__' — the same table used by the detached-session window. No migration was needed because session_id is a plain TEXT PRIMARY KEY and the sentinel key '__kms_window__' is a valid value. Defaults: 1100×760, centered on the primary display. Bounds are saved on move/resize (500 ms debounce) and synchronously on close.

Window chrome

Frameless like the main window: titleBarStyle: 'hidden' + a slim draggable title strip with custom HTML caption buttons (WindowControls), with the native "View/Window" menu removed (removeMenu()). The window backgroundColor is the dark-first #09090b (matches kms-window.html). Chrome is shared with the scratchpad window via standaloneWindowChromeOptions() / applyStandaloneWindowChrome() — see scratchpad-window-contract.md frameless-chrome-shared-with-the-kms-window and window-controls-contract.md.

Deep linking to a note

A specific note can be opened from outside Omniscio (an email, another note, a dashboard, a script) via the omniscio:// protocol:

omniscio://note/<vault-relative-path>[?vault=<vaultId>]
  • The path is the note's vault-relative path, percent-encoded. omniscio://note/Architecture.md, omniscio://note/One-on-Ones/Brett.md, and omniscio://note/Column%20Layout%20Demo.md all work; sub-folders may be passed as real / separators OR a single %2F-encoded segment (both rebuild to the same path). new URL collapses any ./.. traversal before the parser runs, so a link can never escape the vault root.
  • ?vault=<vaultId> is optional — it targets a specific vault; omit it to use the active / only vault.
  • The link navigates (activates the KMS panel + dashboard view) and opens the note as a tab. It is non-destructive — no session spawn, no message send — so, unlike new-session / open-superprompt, it is NOT confirmation-gated (it matches the trust level of navigate-session / activate-project).
  • A cold link (KMS panel not yet mounted, no vault loaded) still lands: requestOpenNote stashes the path in the store's pendingOpenNotePath, and the tail of loadTree opens it once activeVaultId + the note list have hydrated (epoch-guarded so a racing vault switch can't open into a stale vault).
  • KMS disabled → the KMS virtual project is absent from the project list and the router surfaces a "KMS is not enabled" toast. A path that no longer matches an indexed note (renamed / deleted since the link was made) surfaces a "couldn't find note" toast instead of opening a blank tab.

A dev / sandbox instance running alongside production uses the per-instance scheme agentmc-<id>://note/... (see getInstanceDeepLinkPrefix()); production uses bare omniscio://.

Wiring (main → renderer): the OS hands the URL to /src/main/app/single-instance.ts → handleDeepLinkArgs → parseDeepLinkUrl (/src/main/services/deep-link.ts, returns { action: 'open-note', relativePath, vaultId? }). open-note is not the paid new-session path, so single-instance forwards it verbatim over the DEEP_LINK_ACTION push. The renderer's /src/renderer/src/lib/deep-link-router.ts (case 'open-note') activates the KMS virtual project (KMS_PROJECT_ID) and calls openKmsNote, wired in /src/renderer/src/hooks/useDeepLinkListener.ts to the store's requestOpenNote / consumePendingOpenNote (/src/renderer/src/features/kms/kms-store.ts). Tests: /tests/unit/deep-link-open-note.test.ts (parser), /tests/unit/lib/deep-link-router-open-note.test.ts (router), /tests/unit/features/kms/request-open-note.test.ts (store cold/warm/switch/not-found).

Get the link from the UI — right-click → Copy link. A KMS page's deep link is now obtainable without hand-forming it: right-click any page — in the file tree, on its editor tab, or inside the open page (the editor body) — and choose Copy link to copy omniscio://note/<relativePath>?vault=<vaultId> to the clipboard (a Link to "<page>" copied toast confirms; an honest error toast fires if both clipboard paths fail). The tree row is file-only (a folder is not a page); the tab + editor rows (from the shared buildPageShareActions factory, page-share-actions.tsx) act on the open note. The link is built by buildAgentmcNoteUrl(relativePath, vaultId?) (agent-markdown-path-utils.ts) — the build-inverse of the parseDeepLinkUrl reader above, so it round-trips exactly (a page name with sub-folders / spaces / # / & / unicode survives) — and copied through the resilient copyKmsNoteLink chokepoint (copy-kms-note-link.ts), mirroring the session "Copy link". Works in the in-app panel AND the pop-out KMS window. Invariants (one format, the ?vault= param name, file-only, honest toast) are pinned by kms-note-link-contract.md; tests: build-agentmc-note-url.test.ts (build↔parse round-trip), copy-kms-note-link.test.ts, kms-copy-link.spec.ts.

Publish a page to a public web link

Beyond the app-only deep link above, a KMS page can be published to a public web page anyone can open in a browser — on a phone, with no Omniscio install. Right-click a page — on its editor tab, inside the open page, or in the file tree — and choose Publish page….

  • What it produces. A standalone, mobile-responsive web page hosted on Omniscio Shares (https://shares.omniscio.com/s/<token>). It renders the note's text and formatting, and its local vault images are inlined (base64) so they load anywhere without the desktop app's nothari-asset:// scheme. The public URL is copied to your clipboard (a toast confirms).
  • Confirm + sign-in gated. Publishing always pops a confirmation first (the page becomes PUBLIC — anyone with the link can view it) and requires a signed-in Omniscio cloud account (a toast points you to Settings when signed out). There is no accidental one-click publish.
  • Managed in the Shares panel. A published page is a normal Share artifact — it appears in the Shares panel where you can unpublish / revoke it, exactly like any other share.
  • Re-publishing updates the SAME link in place. Edit a page and publish it again and its existing public link updates in place (same URL, new content) instead of piling up a new share each time. The page is associated to its share via shared_links.vault_page_id; the Shares relay's mint-upload op takes an owner-checked existingToken to re-upload to the same token (serveShare reads fresh, so the same URL serves the new content). Requires the Shares relay Cloud Function to be deployed; until then it degrades gracefully to a fresh link (the client detects the relay didn't honor the token and mints a new one).
  • Publish from desktop OR mobile. The desktop right-click menus AND the phone/web KMS action sheet's Publish page… row both work; the desktop main process always does the render + image-inlining (a paired phone just triggers it over the WS bridge — KMS_PAGE_PUBLISH is baselined, not blocked), so the page renders identically either way.

Security. The publish path reuses the audited Share pipeline end-to-end: images are inlined ONLY through the guarded serveVaultAsset resolver (realpath-under-vault containment — a ../ traversal can never leak an off-vault file into the public page), remote http(s) images are left as URLs and never fetched server-side (no SSRF), and the markdown is rendered through the audited renderMarkdown sanitizer (marked + sanitize-html) so a <script> / onerror payload in the note never reaches the artifact.

Wiring (repo detail). The renderer's usePublishPage hook (src/renderer/src/features/kms/hooks/usePublishPage.ts) gates on useShareSignedIn, confirms via useConfirmDialog, then invokes KMS_PAGE_PUBLISH (kms-handlers.ts). Main renders the page via renderVaultPageHtml (publish-page.ts — strip frontmatter → inline local images → renderMarkdown → standalone HTML shell) and publishes it through the shared Share Artifacts service (pastedContent HTML) so one Firebase publisher + dedup cache back both this and the renderer's SHARE_PUBLISH_ARTIFACT. The Copy link + Publish rows on the tab and editor-body menus come from the shared buildPageShareActions factory; the file tree adds Publish alongside its existing Copy link. Tests: publish-page.test.ts (inline security + render/sanitize), page-share-actions.test.tsx.

Related

The vault itself is the KMS page, and the internals — the IPC surface, how it is built, and what it promises about your data — are part 6. The note summaries are covered in more depth on KMS summaries, and the agent tools on KMS agent tools.

Last verified 2026-09-28