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 2)

Part 2 of the KMS page: the editor itself — its toolbar and slash commands, how links, tables, footnotes, lists, headings and code are written and rendered, how the view behaves while you type and save, and what happens to an imported note that is not perfectly formed.

What it is

This is part 2 of the KMS page. It covers writing in the vault: the editor's toolbar and its slash commands, the syntax for links, tables, footnotes and lists, how code and long content are rendered, and how the editor behaves around autosave and imported notes.

Where to find it

The KMS panel — open any note and the editor fills the pane. Every feature described here is reached from inside that editor rather than from a separate screen.

How it behaves

Editor toolbar (2026-06-06 layout)

The horizontal formatting strip above the editor (between the tabs strip and the document) is a single row, no flex-wrap. It was collapsed on 2026-05-22 from a 22-button five-group grid into inline primaries plus two dropdowns; on 2026-06-06 Undo, Redo, and Numbered list were promoted out of the ⋯ More menu onto the inline strip so the controls a user reaches for are always visible. The inline order:

  • Undo / Redo — lead the strip (Docs/Word convention). They grey out when there's nothing to undo / redo (the buttons read the editor's can() check, refreshed on each editor transaction).
  • Bold (Ctrl+B)
  • Italic (Ctrl+I)
  • Heading ▾ — opens a dropdown with seven rows: Normal · H1 · H2 · H3 · H4 · H5 · H6 (the full OneNote / Google-Docs heading ladder). The trigger lights up in accent colour whenever the caret sits inside any heading; the specific level (H1–H6) shows active inside the dropdown so you can see at a glance what's currently applied.
  • Bullet list
  • Numbered list
  • Link
  • ⋯ More — opens an overflow menu containing the remaining secondary commands, in this order: Underline, Strikethrough, Highlight, Blockquote, Code block, Task list, Image (opens an OS file picker), Hidden block, Column block, Insert table, Decrease indent, Increase indent. (The two indent commands were added for mobile — where there's no Tab key — but the catalog-completeness contract requires every command occupy exactly one desktop list, so on desktop they land here in the overflow; the keyboard Tab / Shift+Tab stays the primary desktop path.)

Both dropdowns follow the standard WAI-ARIA menu contract: ↓ / ↑ moves the highlight (with wraparound at the ends), Home / End jump to the first / last row, Enter or Space activates the highlighted row, Esc or Tab closes the menu and restores focus to the trigger. Mouse hover also moves the highlight; click-outside dismisses without picking.

The non-formatting View and Bookmark icons that live to the right of this strip (Toggle side panel, source-view, find/replace, bookmark current note) are rendered by KmsView itself — they're a separate strip and were not touched by the collapse.

When the editor is unmounted or destroyed (closing the last tab, switching away from the KMS panel mid-render), every button greys out and click-handlers short-circuit. This replaces the prior crash path where Undo / Redo's enable check called editor.can() against a torn-down editor and surfaced "Something went wrong" in the panel's error boundary — the mobile quick bar (below) adopts the same isDestroyed-guarded editor-state subscription, so promoting Undo/Redo onto it is crash-safe too. The layout is data-driven from TOOLBAR_GROUPS + the PRIMARY_COMMAND_IDS / HEADING_MENU_COMMAND_IDS / OVERFLOW_COMMAND_IDS lists (desktop) plus MOBILE_QUICKBAR_COMMAND_IDS (the mobile quick bar's curated subset) in /src/renderer/src/features/kms/toolbar/toolbar-commands.ts; a CI lint test pins the contract that every catalog id maps to exactly one of the three desktop layout lists (no phantoms, no duplicates) so the layout can't silently drop a button or grow a stray one. The mobile list is a curated subset (not part of that partition — the action sheet still renders the full catalog, so nothing is unreachable).

The dropdown primitive shared by both menus lives at /src/renderer/src/features/kms/toolbar/ToolbarMenu.tsx and reuses the WAI-ARIA useMenuKeyboard hook that the rest of Omniscio's overflow menus use, so the keyboard contract is identical to (for example) the app-toolbar's overflow menu.

Link popover — open, edit, or remove an existing link

Inserting a link (the toolbar Link button or Ctrl+K) opens a small edit form — a URL field plus an optional display-text field. Acting on a link that already exists surfaces a compact bubble with three actions — Open (launches the URL externally), Edit (switches to the edit form), Remove (unlinks) — alongside the URL and a close button.

How that bubble is revealed is surface-split:

  • Desktop — it appears when you hover the mouse over a link, not when you place the text cursor on it. (Merely moving the caret onto a line that contains a link used to pop the bubble and cover the surrounding note content; it no longer does.) A short hover delay avoids flicker, and the bubble stays open while you move the pointer from the link into it, so its buttons stay clickable.
  • Mobile / touch — there is no hover, so tapping into a link opens the bubble (unchanged — long-press contextmenu is unreliable on iOS, so tap remains the phone's reliable path to link actions).

On every surface the same three actions also live on the editor's right-click / long-press context menu (Open link · Edit link · Remove link), and Ctrl+K edits the link under the caret. The bubble is positioned to never cover the link line it points at — it sits fully below the link (or above, when there's no room), and clips at the viewport edge rather than landing on the link.

Source: LinkPopover.tsx (the bubble), useEditorPopovers.ts (the hover / tap trigger + hover bridge), popover-positioning.ts (the avoidAnchor placement). Invariants: kms-link-hover-contract.md.

Slash commands

Typing / anywhere in the editor opens a command menu — a filtered list of block-level formatting commands grouped by category (Headings, Lists, Blocks, Insert). Continue typing to narrow results; the menu matches against title, description, category, and search-term aliases (e.g. /hr → Horizontal Rule, /todo → Todo List, /h1 → Heading 1). Arrow Up/Down to navigate (wraps), Enter or Tab to pick, Esc to dismiss.

Available commands: Heading 1–6, Bullet List, Numbered List, Todo List (GFM checkboxes), Blockquote, Code Block, Horizontal Rule, Image (opens file picker).

Source: SlashCommandExtension.ts (command definitions) + SlashCommandSuggestion.tsx (popup UI).

Pasting outlines and lists

Pasting a nested outline keeps its nesting. When you copy a multi-level list from Google Docs, Word, Notion, a web page, or plain-text notes — where the sub-levels are shown with letters (a. b.) or extra indentation — the sub-items paste as properly-indented nested list items instead of collapsing to flush-left plain text. The editor detects the outline (numeric / letter markers plus indentation), rebuilds it through the note's markdown pipeline so pasted nesting matches typed nesting, and it round-trips to disk. It stays conservative: ordinary prose, a flat single-level list, and a rich-HTML list that already carries its own nesting all paste unchanged.

Source: OutlinePasteHandler.ts + outline-paste.ts. Invariants: kms-outline-paste-contract.md.

Editor keyboard shortcuts

Almost every formatting command has a keyboard shortcut, so you rarely have to reach for the toolbar. The defaults follow OneNote conventions, and many commands additionally accept the Google-Docs / Microsoft-Word shortcuts so muscle memory from either app works — the list toggles, the full heading ladder (H1–H6 plus "Normal text"), strikethrough, and clear-formatting each accept both apps' keys.

These keys are rebindable. Open Settings → Keyboard Shortcuts → KMS Notes: the Panel commands group rebinds the command-palette keys (Bold, Italic, Underline, headings, Insert link, Find / Replace, Search vault, Toggle source, Command palette), and the Editor formatting group rebinds the formatting toggles (bulleted / numbered / task list, strikethrough, clear formatting, code block, blockquote, duplicate block). Press Rebind, then your combination; the X disables a key, Default restores it. (The structural editor keys — Tab/Shift+Tab indent, Ctrl+Delete delete-block, Alt+Shift+↑/↓ move-block — stay fixed.)

Formatting

Action Shortcut
Bold Ctrl+B
Italic Ctrl+I
Underline Ctrl+U
Strikethrough Alt+-, Ctrl+- (OneNote), or Alt+Shift+5 (Google Docs)
Bullet list Ctrl+. (OneNote) or Ctrl+Shift+8 (Google Docs / Word)
Numbered list Ctrl+/ (OneNote) or Ctrl+Shift+7 (Google Docs / Word)
Task / checkbox list Ctrl+1
Heading 1 – 6 Ctrl+Alt+1 … Ctrl+Alt+6 (OneNote / Google Docs)
Normal text (clear heading) Ctrl+Alt+0 (Google Docs)
Blockquote Ctrl+Shift+.
Code block Ctrl+Shift+C
Clear formatting Ctrl+Shift+N or Ctrl+\ (Google Docs)

Block editing

Action Shortcut
Indent / outdent any list line — incl. the first Tab / Shift+Tab, or Alt+Shift+→ / Alt+Shift+←
Duplicate block Ctrl+D
Delete block Ctrl+Delete
Move block up / down Alt+Shift+↑ / Alt+Shift+↓

Insert & navigate

Action Shortcut
Insert / edit link Ctrl+K
Find in note Ctrl+F
Replace in note Ctrl+H
Search the whole vault Ctrl+P
Jump to top / bottom of note Ctrl+Home / Ctrl+End
Toggle source (raw-markdown) view Ctrl+Shift+M
Image gallery Ctrl+Shift+G
Command palette Ctrl+Shift+P

The list shortcuts are toggles: pressing the bullet shortcut again while the caret is already inside a bullet list lifts the line back out to a plain paragraph. The same goes for numbered lists, headings, blockquote, and code block.

Tables (GFM pipe tables)

The editor supports GitHub-Flavored Markdown pipe tables. Insert a table via the ⋯ More toolbar menu → Insert table (inserts a 3×3 table with a header row), or type /table in the editor to use the slash command.

Editing:

  • Tab / Shift+Tab navigate between cells (forward / backward). These keys only intercept while the caret is inside a table — outside a table they still handle list indentation as normal.
  • Add / remove rows and columns via the table toolbar that appears on hover (provided by the TipTap table extension).

Column alignment: each column can be aligned left, center, or right. The alignment is stored as a per-column attribute on the table node and serialized to GFM alignment markers in the separator row (:--- left, :---: center, ---: right).

Markdown roundtrip: tables serialize to standard GFM pipe syntax and parse back identically — alignment, inline formatting within cells (bold, italic, code, links), and empty cells all survive the roundtrip. The underlying parser (marked, used by @tiptap/markdown) handles the tokenization natively.

How it's wired (repo detail). The implementation lives in /src/renderer/src/features/kms/editor/extensions/TableExtension.ts, which exports a TableExtensions array of 5 extensions (KmsTable, KmsTableRow, KmsTableHeader, KmsTableCell, TableTabNavigation). KmsTable extends the official @tiptap/extension-table with a colAlignment JSON attribute and custom parseMarkdown / renderMarkdown hooks. Contract: kms-table-extension-contract.md.

Tab indents any list line — even the first one. Normally Tab tucks a line under the line above it (real Markdown nesting). When a line has nothing above it to tuck under — the very first item of a list, or the first child of a sub-list — Tab still pushes it one level to the right and Shift+Tab brings it back. That extra indent is stored invisibly inside the note (plain Markdown has no nesting for it to live in), so it survives saving and reopening; every other Markdown app still sees a normal list. (Pinned as invariant I8; before 2026-06-04 the first line simply refused to indent.)

Ctrl+Delete (delete block) deletes the current line. If that line has indented sub-items beneath it, the sub-items are lifted up one level to take its place — they are kept, not deleted (so deleting a parent bullet promotes its children rather than wiping them). A plain line with no sub-items is removed entirely, and a single Ctrl+Z undoes the whole thing. (Behavior pinned as invariant I7 in the editor contract; before 2026-05-30 it only cleared the line's text, stranding an empty line and its sub-items.)

Ctrl+Home / Ctrl+End jump to the top / bottom of the note. They move the caret to the very start / end of the document and scroll the note there in one keystroke — handy in a long note. (Fixed 2026-06-13 and pinned as invariant I16; before that the editor moved the caret but never scrolled, so the keys looked dead — the scroll container was looked up by a CSS marker the editor wrapper had lost in the port from the old Knowledge Management Tool.)

These are in-note editing keys. Ctrl+Alt+N is now the global hotkey that opens the standalone KMS window (shipped — see "Standalone KMS window" below). It is unrelated to the deferred Phase 7 Quick-Compose capture window.

How the shortcuts are wired (repo detail). Two cooperating layers handle these keys. A window-level capture hook (/src/renderer/src/features/kms/hooks/useKmsShortcuts.ts) fires first and owns the bold / italic / underline, heading, link, find / replace, source-toggle, gallery, vault-search, and command-palette keys; any key it does not recognise — notably the list toggles — passes straight through to the editor's own ProseMirror keymap (/src/renderer/src/features/kms/editor/extensions/KeyboardShortcuts.ts), which owns the list and block-editing keys. The Google-Docs aliases Ctrl+Shift+8 / Ctrl+Shift+7 are matched on the physical key (event.code = Digit8 / Digit7) rather than the typed character, because holding Shift turns 8 into * and 7 into & on a US layout — matching on the character alone would silently miss. OneNote's strikethrough Ctrl+- collides with Omniscio's app-wide "shrink text size" shortcut, so the global dispatcher (/src/renderer/src/hooks/useKeyboardShortcuts.ts) stands down for that one key while focus is inside the notes panel — the same panel-scoped yield Ctrl+B / Ctrl+K / Ctrl+\ already use; Ctrl+= (zoom in) is left alone, since it has no editor meaning. Both layers, plus the event.code rule, are pinned by /tests/unit/features/kms/editor/KeyboardShortcuts.test.ts; the full architecture and a safe-change checklist live in the KMS editor styling & hotkey contract.

List markers, headings, and the focus border

The note editor renders into a plain contenteditable surface that inherits Omniscio's global stylesheet. Omniscio is built with Tailwind, whose "preflight" reset deliberately strips list markers (ul, ol { list-style: none }) and flattens the heading scale (h1–h6 all inherit the body size) so stray browser defaults never leak into the app's chrome. That reset also reached the note editor: toggling a bullet or numbered list created real list items, but they showed no bullet or number, and headings looked like ordinary body text. Separately, Omniscio paints a 2-pixel accent-coloured focus ring around any focused element — and because that accent is near-white in several themes, the editor box appeared to gain an ugly white border whenever you were typing in it.

Both are fixed by a small scoped stylesheet block that re-declares the list markers (disc → circle → square as lists nest; decimal → lower-alpha → lower-roman for numbered lists), resets the task-list marker so checkbox items render as a [checkbox] text row instead of inheriting a stray bullet, restores the H1–H3 size-and-weight scale, keeps nested bullet and numbered rows evenly spaced at every level (so the gaps no longer grow as lists nest deeper), and removes the focus outline. Every rule is namespaced under a .kms-prose wrapper class, so it applies only to the KMS note editor and can never leak into the other TipTap editing surfaces in the app (the agent chat composer, automation editors, and so on). Source of truth: the .kms-prose .ProseMirror … block in /src/renderer/src/styles/globals.css, applied via the kms-prose class on the editor wrapper in /src/renderer/src/features/kms/editor/KmsEditor.tsx. The styling invariants are pinned by /tests/unit/lint/kms-editor-css-contract.test.ts; full rationale and the safe-change checklist live in the KMS editor styling & hotkey contract.

Numbered lists keep counting across an interrupting note. A paragraph, link, or image dropped between two numbered items splits the underlying markdown into two separate lists, and the editor normalizes every list to start at 1 — so an outline with a reference note in the middle used to render 1, 1, 2 instead of 1, 2, 3. The OrderedListContinuation extension fixes this at render time: it carries the count straight through the interruption so the list reads 1, 2, 3, …. It works per column and restarts at a heading (a new section is a new count), touches only the top level (nested a/i levels are unchanged), and is display-only — it never rewrites the numbers saved in your .md file. Pinned by invariant I18 of the styling contract.

Code syntax highlighting

Fenced code blocks (```python … ```) render with language-specific syntax coloring** — keywords, strings, comments, and other tokens are highlighted so code reads naturally inside a note. The editor uses CodeBlockLowlight with the same curated 29-language subset the rest of Omniscio uses (js, ts, python, rust, go, java, c#, c++, c, ruby, php, swift, kotlin, bash, shell, powershell, json, yaml, xml, markdown, ini, css, scss, sql, diff, makefile, dockerfile, graphql, plaintext). If you type a language fence the editor doesn't recognize (e.g. ```elixir), the block renders as plain monospace — no crash, no error. The language tag round-trips through markdown save/load, so highlighting reappears on reload. No new CSS was needed — the existing github-dark.css token classes and the scoped .kms-prose .ProseMirror pre container rules handle both light and dark themes. Pinned by invariant **code-blocks-syntax-highlighted in the editor styling contract.

How it's wired (repo detail). KmsEditor.tsx disables StarterKit's built-in CodeBlock (codeBlock: false) and registers CodeBlockLowlight.configure({ lowlight: kmsLowlight }) after StarterKit, before KeyboardShortcuts. The kmsLowlight instance at /src/renderer/src/features/kms/editor/extensions/kms-lowlight.ts calls createLowlight(subsetLanguages) using the same language map from rehype-highlight-subset.ts. Invariants pinned by kms-editor-css-contract.test.ts (wiring lint) + kms-code-highlight.test.ts (language registration + CodeBlockLowlight integration).

Content always fits — no horizontal scroll

However wide a note's content gets — a two-column layout, a very long unbroken word or URL, a wide image — the page never scrolls sideways: the editor itself only ever scrolls up and down. (Before this, a wide two-column page could run off the right edge and get cut off — the original bug report showed exactly that.) On a roomy screen the columns shrink to share the pane, long words and links wrap, and images are capped to the pane width. The only things that get their own small internal sideways-scroll are blocks that genuinely can't shrink any further — a fenced code block scrolls inside its own frame instead of pushing the whole page over, and on a phone-width screen (≤767px) a multi-column block does the same: instead of crushing 2–5 columns into ~90px of character-by-character word-wrap (Export → Exp/ort), each column keeps a readable width and you swipe the block sideways to reach the rest — the page itself still never moves. This holds at every Editor width setting (below); it isn't the same control. The rules live in the same scoped .kms-prose block in /src/renderer/src/styles/globals.css (the editor root scrolls vertical-only; columns get min-width: 0 so they shrink to fit on desktop, while a @media (max-width: 767px) override gives them a readable min-width plus a contained overflow-x: auto on a phone; the prose wraps via overflow-wrap: anywhere), are pinned by /tests/unit/lint/kms-editor-css-contract.test.ts, and are invariant content-fits-the-pane in the editor styling contract. The same scoped block also gives a multi-column layout visible borders — a thin rounded box around the block plus a divider line between columns (the first column has none, so you only ever see dividers between columns), matching the original KMS desktop app it was ported from. The border uses Omniscio's theme-aware divider tone (--color-surface-200, the same weight the KMS panels use) so it reads in every theme. (Restored 2026-06-19 — the port had dropped every border rule, so the columns floated with nothing between them.)

Resilient loading of imported / malformed notes

Notes imported from other tools (Google Docs especially) sometimes carry odd Markdown the editor must open without crashing. The load path is hardened two ways:

  • The editor never crashes on a mark it can't place. The LinkNormalizer extension auto-converts a raw [text](url) typed or pasted as plain text into a real link — but only where a link mark is schema-legal. Text inside a code block, or inside a malformed list item an import left holding bare text, can't hold a link mark, so the normalizer skips it (worst case the text stays literal) instead of attempting an invalid replace. Before this, such a replace threw ProseMirror's Called contentMatchAt on a node with invalid content and blanked the whole KMS panel with the "Something went wrong" card (ref ecec4d3f, 2026-07-12). Guard lives in /src/renderer/src/features/kms/editor/extensions/LinkNormalizer.ts.
  • Empty list markers with indented content are healed on open. A Google-Docs import can produce an empty bullet whose image + link sit on the indented lines beneath it (- then ![img] / [link]). @tiptap/markdown mis-parses that blank-first-line item, so on load healEmptyMarkerContinuation (markdownIo.ts, part of preflightMarkdown) pulls the first continuation line up onto the marker — the image + link then render and the bullet is preserved. Load-only; the healing never rewrites a note you didn't edit.

Full incident + the DO-NOT-RETRY list: kms-linknormalizer-invalid-content-crash postmortem.

Footnotes ([^label] references and [^label]: definitions)

The editor supports standard Markdown footnotes. Type [^label] inline to insert a footnote reference — it renders as a superscript accent-coloured link. At the bottom of the note (or anywhere a block starts), type [^label]: text to create the matching definition. The reference and definition are clickable cross-links: clicking a reference scrolls to its definition, and clicking a definition's label scrolls back to the reference.

Multi-line definitions are supported: indent continuation lines with 4 spaces or a tab. Blank lines within the continuation are preserved (multi-paragraph footnotes). The label grammar is [a-zA-Z0-9_-]+ — alphanumeric, hyphens, and underscores.

v1 is read-only in the rich editor. Definitions render as styled blocks (accent label + muted content) but are edited via the source-view toggle (Shift+Ctrl+M). The markdown round-trips losslessly — footnote syntax survives save → reload byte-for-byte. Rich inline editing of definitions is a future enhancement.

How it's wired (repo detail). Two TipTap nodes in FootnoteRef.ts and FootnoteDef.ts: footnoteRef (inline atom) and footnoteDef (block atom), both following the HiddenBlock/TasksBlock opaque-passthrough pattern. Each has a markdownTokenizer (inline-level for ref, block-level for def), parseMarkdown, and renderMarkdown on the extension's .config — integrated with @tiptap/markdown. NodeViews render the click-to-jump navigation via data-footnote-ref / data-footnote-def DOM attributes + scrollIntoView({ behavior: 'smooth', block: 'center' }). CSS lives in the scoped .kms-prose .ProseMirror .footnote-* block in globals.css. Invariants pinned in Footnote.test.ts (42 tests). Contract: kms-footnote-contract.md.

Related

Getting around the vault — the file tree, tabs and adding a note — is the KMS page, and appearance plus search is part 3. Images and media are part 4.

Last verified 2026-09-23