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

Scratchpads (persistent notes and the quick-capture overlay)

Scratchpads is a Chrome-style persistent notes feature inside Omniscio: open the Scratchpads virtual project for a two-pane pad list and editor, or press Ctrl+Shift+S from anywhere for a quick-capture overlay. This page covers what a scratchpad is, the overlay, popping one out into its own window, undo, find and global search.

What it is

Scratchpads is a Chrome-style persistent notes feature inside Omniscio — open it from the Scratchpads virtual project in the Omniscio sidebar group. Each pad is one note; the pad list lives in the left pane, the active pad's body editor fills the right pane. Pads auto-save 500 ms after you stop typing, with a "Saved" pill in the header. There are no folders — it is a deliberately tiny "jot it down before I forget" surface, not a notebook. The body editor is a rich contenteditable (since 2026-05-18) so you can paste images inline; rich-text paste from a webpage is otherwise reduced to plain text. An optional markdown styling toggle (the Type icon in the pad header) renders headings, bold, italic, inline code, blockquotes, list markers, links, and fenced code blocks on top of the raw source — the syntax characters (**, ##, `, >, - , 1. , fence lines, link URLs) stay visible but dimmed while the toggle is on, so you can always see exactly what you typed; flip it off any time to switch back to flat plain-text rendering.

Pads are local-only. Rows live in the scratchpads SQLite table in mission-control.db (your OS user-data directory), and pasted images are embedded as data: URLs inside the pad body — nothing syncs to any cloud service and no file mirror is written. The view itself is responsive: opened on a phone over the web / tailscale renderer it collapses from the two-pane layout to a single-pane drill-down (the data still lives on the desktop and is reached over the in-app bridge). See scratchpads-mobile-layout-contract.md.

CLI control surface (added 2026-06-08). Scratchpad CRUD is reachable two ways: in-app over IPC (SCRATCHPAD_CREATE / _GET / _UPDATE / _DELETE / _LIST / _SET_PINNED / _TRASH_LIST / _RESTORE / _DELETE_FOREVER), and over Omniscio's local control server — GET /scratchpads, GET /scratchpads/trash, GET /scratchpads/:id, POST /scratchpads, POST /scratchpads/:id/pin, PATCH /scratchpads/:id, DELETE /scratchpads/:id (soft-delete → Trash), POST /scratchpads/:id/restore, DELETE /scratchpads/:id/forever (bearer-auth, apply-immediately). So an external script or an AI driving Omniscio over the CLI control API can now list / read / create / edit / pin / delete / trash / restore pads — it could not before this date. See the CLI control section below and the omniscio-control scratchpads spoke. The pads stay local-only — the control server is localhost-bound and nothing syncs to any cloud service. (The on-device UI also renders responsively on mobile — a separate concern.)

Where to find it

UI Surface

  • Sidebar entry — the Scratchpads virtual project in the Omniscio group. Click it to open the two-pane view in the main panel.
  • Two-pane layout (desktop) — pad list on the left (pinned pads first, then sorted most-recently-updated), contenteditable body on the right. Each row shows a pin toggle (hover-reveal when unpinned, always visible when pinned).
  • Responsive (mobile) layout — below the md breakpoint (e.g. a phone over the web / tailscale renderer) the two panes collapse to a single-pane drill-down: the full-width pad list, then the full-width editor with a "← Scratchpads" back bar when a pad is open. Tapping a pad or + opens the editor; back returns to the list (flushing the draft first). Desktop is unchanged. Driven by useIsMobile(); the Quick Capture overlay also has its own full-screen mobile layout (see the Quick capture overlay → Mobile subsection below). Both locked by scratchpads-mobile-layout-contract.md.
  • Header bar — pad title (inline-editable; defaults to the pad's first line), a "Saved" pill (replaces with "Saving…" during the 500 ms debounce), a Markdown styling toggle (Type icon — on layers heading sizes / bold / italic / code / blockquote borders / list spacing / link colour / fenced code-block backgrounds on top of the raw source, with the syntax characters kept on screen but dimmed; off keeps the body as flat plain text), a Copy all button (uses CopyConfirmButton; copies the body as plain text so HTML wrappers don't leak into the clipboard), a Trash button (with a count badge showing the number of trashed pads — opens the ScratchpadTrashPopover to browse/restore/permanently-delete trashed pads), and a Delete button (opens a confirm dialog; deleting moves the pad to Trash with an "Undo" toast that restores it immediately).
  • Stats row — a thin footer under the editor shows chars · lines · ~tokens (and N images when at least one image is present). Tokens are an estimate (chars ÷ 4, marked with ~).
  • List filter — a search box at the top of the pad list filters pads by title + body, case-insensitive.
  • Empty state — when no pads exist, the panel shows a "No scratchpads yet" card with a Create button.
  • Save from chat — the message overflow menu (⋯ button) on both agent and user messages includes a "Save to scratchpad" action (StickyNote icon). Clicking it creates a new scratchpad from the message's cleaned markdown content (tool lines stripped for agent messages, plain content for user messages). The title is auto-derived from the first line (heading markers stripped, truncated to 200 chars). A success toast offers a "View" link that navigates to the Scratchpads virtual project and selects the new pad. Empty-after-stripping messages show a "Nothing to save" toast instead.

How it behaves

Quick capture overlay

Ctrl+Shift+S (rebindable at Settings → Keyboard Shortcuts → Quick scratchpad) opens a large centered overlay — roughly 80% of the viewport width and 85% of its height, a comfortable near-full-screen note surface, but still a modal with a visible backdrop — for jotting a note without leaving your current view. The Scratchpad toolbar button (NotebookPen icon) is pinned to the toolbar by default — alongside Notifications / Feedback / Settings — so the overlay is reachable from the title bar without opening the overflow menu.

The overlay opens as a single editor surface — the editor fills the modal, both its full width and its full height (from the toolbar down to the stats row). A pad list is available behind a header toggle so you can swap between recent pads without leaving the quick-capture surface, but it stays out of the way by default:

  • Collapsed by default, every open. The list pane is hidden on every single open of the overlay (no persistence). To reveal it, click the "N notes" pill — a pill-shaped toggle in the second header row (the row beneath the title) showing a panel icon plus a live count, e.g. ▷ 37 notes. Clicking expands the pane, flips the icon (PanelLeftOpen → PanelLeftClose), and tints the pill in the accent colour; click again to hide. The count is baked into the pill text — no separate count chip, no chevron, no standalone "Notes" word — and stays visible whether the list is open or closed, so the pill always tells you how many notes you can open. You can also toggle the list with Ctrl+L (mnemonic: List of notes) or Tab — press either to show the list, press again to hide it. Shift+Tab always closes it (a dedicated hide).
  • Left pane (when expanded) — a + New button at the top, then the pad list sorted most-recently-updated first. Each row shows the title, relative time (e.g. "5m ago"), and a body snippet. Click any row to swap the editor to that pad in place — the overlay stays open, the list stays open, and the autosave for the previous pad flushes before the swap.
  • + New — clears the editor to fresh-draft mode (no pad selected); the next save creates a new pad. Also clears the 60-second reattach window so a quick "wait, one more pad" never reattaches to the previous one.
  • Editor pane — the same contenteditable body editor the two-pane view uses, sized to the overlay. It is mounted from the moment the overlay opens (the toggle only adds / removes the list pane beside it; toggling never remounts the editor or drops typed content). The editor remounts when the active pad changes (via a resetKey that includes the pad id) so its DOM and undo stack start clean.
  • Empty state — when no pads exist, the (expanded) left pane shows "No scratchpads yet."; while the initial fetch is in flight, it shows "Loading…". The pad list is hydrated eagerly on every open so the moment you expand it the rows are already there.

Close and save behavior:

  • Esc, click-outside, the X button, Ctrl+W / Cmd+W, or Ctrl+Enter closes the overlay. The Ctrl+W path installs a document-level capture-phase listener while the overlay is open so the keystroke never reaches the global closePanel (archive session) binding behind the modal — same outcome the [aria-modal="true"] gate in useKeyboardShortcuts already gives the other close paths, but explicit here as defense in depth.
  • The header is two rows. The top row holds the "Quick scratchpad" title on the left and the X close button on the right. The second row holds the "N notes" pill (show / hide the pad list, described above) on the left, and on the right a Type markdown-toggle button followed by a Copy all button and a Settings gear button. The markdown toggle flips the same global scratchpadRenderMarkdown setting the two-pane editor exposes; the Copy button (same CopyConfirmButton the two-pane view uses) writes the overlay's body to the OS clipboard as plain text (HTML wrappers stripped) and is disabled while the body is empty and image-free; the Settings gear saves the current note, closes the overlay, and opens the Settings panel at the scratchpad settings (System → Auto-Delete Old Scratchpad Notes).
  • View hotkeys. Overlay-local shortcuts toggle the layout without touching your text. Ctrl+L shows / hides the pad-list pane (same as clicking the "N notes" pill). Tab toggles the pane (press once to show it, again to hide it), and Shift+Tab always closes it (a dedicated hide). All are document-level capture-phase listeners scoped to the open overlay, so they fire even while the caret is in the editor and never leak to the app behind the modal. Note Tab / Shift+Tab are the global next/previous-session bindings, but the [aria-modal="true"] gate in useKeyboardShortcuts yields them while the overlay is open (without consuming the event), so session-nav never fires behind the modal AND the overlay still receives the keystroke. Hijacking Tab means it no longer walks focus between the overlay's own controls — an accepted trade-off (the pill stays mouse-clickable, Ctrl+L still toggles, Esc/Ctrl+W close, Ctrl+Enter saves). The list-pane preference does not persist — the list starts collapsed on every open.
  • The footer hint text (desktop only — on a phone the footer is a Copy/Markdown toolbar instead; see the Mobile subsection below) is centered under the editor and always reads "Press Ctrl+Enter, Ctrl+W, or Esc to save and close. Notes under 3 characters are discarded." When scratchpad auto-delete is enabled (Settings → System → Auto-Delete Old Scratchpad Notes), a second sentence is appended: "Notes you haven't edited in {N} days are deleted automatically." The hint is computed by buildHintText() in quick-capture-hint.ts, so it never advertises a deletion policy that is not actually on.
  • Auto-delete (opt-in, off by default). When enabled, scratchpads whose last edit (updated_at) is older than the configured retention (1–365 days, default 30) are moved to Trash (soft-deleted) at startup and every 24h by purgeExpiredScratchpads(), called from the gated retention block in data-retention.ts (resolveScratchpadRetentionDays() returns null when off or mis-configured). It mirrors the session/RSS retention pattern. Auto-deleted pads land in Trash and can be restored for up to 30 days (after which the always-on trash purge hard-deletes them — see Trash below). Editing a note resets its clock. Existing notes already older than the cutoff are moved to Trash on the first launch after you turn it on (the toggle asks for confirmation first).
  • The same chars / lines / ~tokens (and images) stats row appears under the overlay editor (desktop only — hidden on mobile).
  • In fresh-draft mode (no pad selected — the default each time you open the overlay), the body is saved as a new pad on close only if the visible plain-text length is ≥ 3 — under that, the overlay closes without writing anything. A pad consisting only of pasted images is also kept (the visible content is the image).
  • In existing-pad mode (after clicking a row in the list pane), close flushes any pending autosave against that pad and does NOT create a new one — saveQuickCapture is bypassed in favor of flushDraft so the reattach window is not engaged on every existing-pad close.
  • If you re-open the overlay within 60 seconds of a fresh-draft close, Omniscio re-attaches to the last pad instead of creating a new one (so a quick "wait, one more line" doesn't fragment a note across two pads). Switching pads inside the overlay or clicking + New clears this window so intra-overlay flows can never accidentally reattach.
  • The shortcut is global + passthroughInputs: true — it fires even while you are typing in another input.
  • The toolbar entry points (overflow-menu action + pinned-toolbar button) blur the active element before opening the overlay so useFocusTrap does not save the toolbar button as the previously-focused element. Without that blur, closing the overlay restores focus to the toolbar button and the browser's :focus-visible ring leaves the icon looking selected. The Ctrl+Shift+S keybinding path is unaffected — it doesn't focus a button.

Mobile (phone) — full-screen layout

On a phone (useIsMobile() — reached via the pinned toolbar button / mobile header menu, not the desktop-only Ctrl+Shift+S) the overlay drops the shrunk centered-card look and becomes a full-screen capture surface. Everything desktop-only and meaningless on touch is removed; the note is the hero. Desktop is byte-for-byte unchanged (all of the below is gated on useIsMobile()).

  • Full screen — the dialog renders edge-to-edge via DialogShell's mobileFullscreen prop, not a floating 80vw × 85vh card.
  • Top bar — ‹ Notes on the left (opens a full-screen notes list — reuses the same listPaneOpen state; picking a note returns to the editor, + New note starts a blank draft) and a primary Done button on the right that saves & closes (the same handleClose path as the desktop X). The X is hidden on mobile — Done is the single obvious exit.
  • Removed on mobile — the desktop keyboard-shortcut hint ("Press Ctrl+Enter…" — no such keys on a phone) and the chars/lines/~tokens stat row (developer noise on a quick note). Both are desktop-only.
  • Bottom toolbar — Copy (same CopyConfirmButton), Markdown (flips the same global scratchpadRenderMarkdown setting), and Settings (the same gear as desktop — saves and closes the overlay, then opens the Settings panel at the scratchpad settings). The toolbar is lifted above the soft keyboard via useKeyboardInset with a 24px dead-band (KEYBOARD_GAP_THRESHOLD_PX) so the inset signal's ~8px quantization + browser-chrome sliver never leaves stray padding when no keyboard is open.
  • Too-short discard — desktop explains the ≥3-char rule with the persistent footer hint; mobile dropped that hint, so a too-short discard on Done surfaces a one-shot toast ("Too short to save — note discarded."), only when there was visible text.

Locked by scratchpads-mobile-layout-contract.md (M1–M4); the mobileFullscreen shell prop by frontend-modal-contract.md.

Pop out into its own window

Both scratchpad surfaces have a Pop out button (the ⧉ external-link icon) that detaches the scratch pad into a standalone, movable, resizable OS window — so you can keep notes on a second monitor or beside your work while the main app does other things. It mirrors the KMS standalone window.

  • Where the button is — the two-pane Scratchpads view header (next to +) and the Quick Capture overlay header (next to the markdown toggle / Copy all). Desktop only — hidden on mobile (no OS windows) and hidden inside the popped-out window itself (clicking it there would just re-focus the window you're in).
  • What opens — a dedicated scratchpad-window.html BrowserWindow rendering the SAME two-pane ScratchpadsView (list + editor). It opens straight to the pad you were on (passed as ?pad=<id> on first open), otherwise to the last-active pad / list.
  • Singleton, show-or-focus — only one scratch-pad window at a time; clicking Pop out again (from either surface) focuses the existing window rather than spawning a second one. Dismiss it with its own window close / minimize.
  • Position memory — restores its last size + position on open and saves on move / resize / close (reuses the FK-free detached_window_positions table under the sentinel key __scratchpad_window__ — no migration).
  • Theme + window chrome — follows the user's light/dark + visual theme live via the shared useWindowThemeBootstrap (registry entry scratchpadWindow, themePolicy: 'follows-user'). The window is frameless (titleBarStyle: 'hidden', native "View/Window" menu removed): a slim draggable StandaloneWindowTitleBar strip with custom HTML caption buttons (WindowControls) that replace the native titleBarOverlay — the overlay was removed because DWM-drawn buttons clipped through overlapping windows. Chrome is shared with the KMS window via standaloneWindowChromeOptions() / applyStandaloneWindowChrome(); the body backgroundColor is the dark-first #09090b. See scratchpad-window-contract.md frameless-chrome-shared-with-the-kms-window and window-controls-contract.md.
  • Live two-way sync — the window is its own renderer process with its own store; edits autosave to the shared scratchpads table and reconcile via the SCRATCHPADS_CHANGED push, forwarded to the window by the registry 'scratchpad' role + SCRATCHPAD_WINDOW_ALLOWLIST. Editing the SAME pad in two windows is last-writer-wins. Closing the window flushes the pending autosave on pagehide (best-effort — the <500 ms autosave tail can be lost on a hard kill, same as app-quit).
  • From the overlay — popping out persists whatever you've jotted first (fresh-draft → create, existing-pad → flush) so nothing is lost, then opens the window on that pad and closes the overlay. A real save failure keeps the overlay open so you can retry.
  • Open from anywhere (system-wide hotkey) — Ctrl+Shift+S is the single scratchpad hotkey: it raises Omniscio and opens the rich Quick scratchpad overlay (the surface with the note list, pop-out, and settings) from any app while Omniscio runs in the background. A stripped-down floating capture box (scratchpadQuickCaptureHotkey) used to hover over your current app on the same key, but it was removed (owner request 2026-08-25, "we don't need two scratchpad hotkeys" — the rich overlay is the only version); it ships unbound and can be given its own key in Settings → Keyboard Shortcuts → System-wide. Reach the pop-out window from the overlay's pop-out button when you want a detached, second-monitor surface. (The persisted setting keys keep their scratchpadWindow* names for byte-stability.)

Locked by scratchpad-window-contract.md.

Save and start new (Ctrl+T inside the overlay)

Pressing Ctrl+T while the Quick Capture overlay is open saves the current note and resets the editor to a blank fresh draft — without closing the overlay. Use this when you want to jot a series of separate notes back-to-back without each one closing and re-opening the surface.

What it does, by mode:

  • Fresh-draft mode (no pad picked from the list) — if the visible plain-text length is ≥ 3 characters, or if the body contains at least one pasted image, Omniscio creates a new pad and immediately clears the editor. Sub-threshold bodies (1–2 plain characters, no images) are discarded and the editor still clears — same "not worth keeping" contract the close-on-Esc path honors.
  • Existing-pad mode (after clicking a row in the pad list) — the pending 500 ms autosave is flushed against that pad and the editor swaps back to a blank fresh-draft. The just-edited pad stays in the list, your edits are persisted, and the next save will create a separate new pad.

After every successful Ctrl+T:

  • The overlay stays open and the editor surface remounts empty (so the previous note's text is gone from view).
  • The 60-second reattach window from the close-and-reopen flow is cleared, so the next save creates a brand-new pad — Ctrl+T never silently overwrites the pad you just saved.
  • If two Ctrl+T presses race (impatient double-tap), only one save is sent — the second press is coalesced silently while the first is in flight.

If the save fails (e.g. database locked), Omniscio shows an error toast (Could not save scratch pad — please try again.) and preserves the current draft so you can press Ctrl+T again without losing your text.

Ctrl+T outside the overlay keeps its existing meaning — launching a new Claude session in the active project. The two interpretations never fire together: whenever the overlay (or any other modal) is open, the global new-session shortcut is gated off.

Re-press the open hotkey (toggle)

Pressing the open hotkey again while the Quick Capture overlay is already open toggles it, so the same key both opens and dismisses the surface:

  • Totally blank (fresh-draft mode with nothing worth saving — under the 3-visible-character threshold and no image) → the overlay closes, exactly like Ctrl+W / Esc. A one-or-two-character scrap counts as blank and is discarded on close (the same "not worth keeping" contract every close path honours).
  • Has content (a fresh draft worth saving, or an existing pad open from the list) → it saves the current note and opens a fresh new scratchpad without closing — identical to the Ctrl+T "save and start new" flow above (fresh-draft → create, existing-pad → flush). So hammering the hotkey lets you jot a series of notes, and pressing it on an empty surface just dismisses it.

It matches the resolved binding (the default Ctrl+Shift+S, or whatever you rebind Quick scratchpad to at Settings → Keyboard Shortcuts), and — like the overlay's other keys (Ctrl+W / Ctrl+L / Tab) — installs a document-level capture-phase listener while the overlay is open, because the global keydown router yields shortcuts behind the [aria-modal="true"] gate. A bare-letter rebind is guarded so it still types into the editor rather than being swallowed (mirroring how the central buildBindingLookup denies passthrough to bare-letter binds). Locked by the re-trigger cases in tests/unit/features/scratchpads/QuickCaptureOverlay.test.tsx.

Undo / redo

Both scratchpad surfaces (two-pane editor and Quick Capture overlay) support Ctrl+Z to undo and Ctrl+Y / Ctrl+Shift+Z to redo the last text edit. Word-bursts coalesce into a single undo step (one Ctrl+Z undoes a word, not a letter), and the keybinding is scoped to the editor element so a Ctrl+Z press outside the scratchpad still routes through the normal app-level undo handler.

Implementation note: native contenteditable undo is not used on this surface. The markdown styling toggle, when on, rewrites the DOM on every keystroke (stripMarkdownStyling → re-wrap markdown spans), and the seed-on-mount path sets innerHTML directly — both wipe Chromium's native undo stack. Instead, a custom in-memory JavaScript snapshot stack lives per-editor (HTML + caret offset) via the useContentEditableHistory hook. The stack:

  • Resets on pad switch (two-pane editor's resetKey={pad.id}) and on every overlay re-open (resetKey={'open-' + resetTick}).
  • Caps at 100 snapshots per stack; oldest evicted via shift().
  • Debounces at 500 ms to match the textarea sibling (useTextUndoRedo) so the two surfaces feel identical.
  • Restores caret position via the linear text-offset round-trip used by the markdown styler.
  • Empty-stack Ctrl+Z / Ctrl+Y presses fall through (no preventDefault) so the keybinding does not silently swallow input.

Find in a note (Ctrl+F)

Press Ctrl+F / Cmd+F while a note is open to pop a browser-style find bar over the editor — the same find-in-page you get in Settings and the file-preview panel. It highlights every match in the open note's body (the active match emphasized), shows an "N of M" counter, and steps through matches: Enter = next, Shift+Enter = previous, Esc (or the × button) closes it and clears the highlights. Desktop only (a phone has no Ctrl key), and it only opens when a note is actually open.

This is find WITHIN the open note — distinct from the two other search surfaces so the three cover different needs:

  • The list filter (top of the pad list) narrows which notes show, by title + body across all pads.
  • Global search (Ctrl+K) searches across all notes (and every other channel).
  • Ctrl+F finds and steps through the text inside the one note you're reading.

It reuses the shared useFindInPage engine (TreeWalker → DOM Range → CSS Custom Highlight API) that powers Settings find and file-peek find, with its own scratchpad-find / scratchpad-find-current highlight keys so the surfaces never collide. The highlight is a paint-only layer over the contenteditable — it never mutates the note's DOM or moves the caret, so it is safe over the live editor, and the find bar + engine mount only while find is open, adding nothing to the per-keystroke editor hot path. Both the two-pane view and the pop-out standalone window get it (both render ScratchpadsView); the bar resets whenever you switch notes so a stale query never carries across pads. Locked by scratchpad-find-contract.md.

Global search (Ctrl+K)

Scratchpad titles and body text are searchable from the global SearchModal (Ctrl+K). Results appear alongside sessions, SMS, Slack, and other channels. The search is accent-insensitive and case-insensitive via the shared fold() + foldForSearch() pipeline (same as session title search). Body HTML is stripped for the snippet preview (stripHtmlForSnippet — tags removed, whitespace collapsed, truncated to 300 chars). Clicking a scratchpad result navigates to the Scratchpads virtual project and selects the matching pad.

  • Where filter — the SearchModal's "Where" dropdown includes a Scratchpads option (StickyNote icon) so you can scope search to scratchpads only.
  • Status filter — scratchpads carry no session status, so they are excluded when a status filter is active (consistent with SMS/Slack/Telegram/RSS/Webhook).
  • Dedup key — scratchpad:<padId> (same pattern as other channels).

Source: searchScratchpads() in queries-scratchpads.ts; the runChannelSearch call in search.ts; navigation handler in useDashboardSearchHandlers.ts.

Related

INDEX.md is the library index — scratchpads sit alongside the other built-in sidebar areas and feed the global search palette, so the index is the quickest way to find the neighbouring notes, chat and search surfaces. Part 2, scratchpads-part-2.md, covers images, formatting, deletion, the CLI surface and the architectural contracts behind the feature.

Last verified 2026-09-28