---
title: Sticky Notes
---
# Sticky Notes

## What it is

Floating scratch-pad notes that persist across sessions and app restarts. Each note is draggable, resizable, and color-coded. Notes live in a portal overlay above the main UI and are toggled from the toolbar.

## Where to find it

### UI Surface

- **Toolbar icon** — the sticky-note icon in the top-right toolbar pill (visible when the feature is enabled in Settings → Features → "Enable Sticky Notes", default on). The icon lights up in accent color when notes are visible.
- **First click** — if no notes exist yet, the toolbar click creates the first one and shows the overlay. Subsequent clicks toggle visibility on/off. The overlay's open/closed state persists to `localStorage` so it survives renderer reloads.
- **Note title bar** — each note has a drag handle (grip icon) on the left and four buttons on the right: **+** (new note, offset from current), **palette** (6-color picker), **–** (minimize to a small chip), **×** (delete, behind a confirm).
- **Closing the last note hides the overlay** — deleting the final remaining note turns the overlay off (the toolbar icon un-highlights) rather than leaving an empty portal with no reachable "New note" button. The *feature* stays enabled; clicking the toolbar icon again brings the overlay back and mints a fresh note. The auto-close writes through the same `stickyNotesOverlayOpen` path as the toolbar toggle, so it survives a reload.
- **Content area** — a textarea with auto-save (500ms debounce). Placeholder text ("Write something...") disappears on focus. Text and icon colors auto-adjust for contrast against the note's background color.
- **Resize handle** — three dots in the bottom-right corner; drag to resize (120–800px width, 100–800px height).
- **Minimized state** — collapses to a small 48×32 chip at the note's position. Drag to reposition; click (without dragging) to expand.
- **Settings search** — searchable as "sticky", "notes", "notepad", "scratchpad", "memo", "post-it", etc.

## How it behaves

### Scope

- **Desktop-rendered, but CLI-reachable.** Each note is an absolutely-positioned, draggable, resizable overlay widget keyed to on-screen pixel coordinates, so the *overlay* is desktop-bound — but the note DATA is not. The localhost CLI control server serves `GET /sticky-notes`, `POST /sticky-notes`, `PATCH /sticky-notes/:id` and `DELETE /sticky-notes/:id` (`src/main/services/cli/cli-server-sticky-notes-routes.ts`), so an AI or automation can list, create, edit and delete notes. Each write emits `STICKY_NOTES_CHANGED`, which an open overlay picks up via the live-sync subscription — including an external delete that empties the list, which hides the overlay the same way closing the last note by hand does.

## For agents

### Architecture

### Data Model

`sticky_notes` SQLite table (migration v172):

| Column         | Type    | Default       | Notes                  |
| -------------- | ------- | ------------- | ---------------------- |
| `id`           | TEXT PK | UUID          |                        |
| `content`      | TEXT    | `''`          | Max 10,000 chars (Zod) |
| `position_x`   | INTEGER | 100           | 0–10,000               |
| `position_y`   | INTEGER | 100           | 0–10,000               |
| `width`        | INTEGER | 240           | 120–800                |
| `height`       | INTEGER | 200           | 100–800                |
| `color`        | TEXT    | `#FFF9E6`     | Hex `#RRGGBB`          |
| `is_minimized` | INTEGER | 0             | Boolean                |
| `created_at`   | TEXT    | ISO timestamp |                        |
| `updated_at`   | TEXT    | ISO timestamp |                        |

### IPC Channels

| Channel                | Schema                                                   | Response                  |
| ---------------------- | -------------------------------------------------------- | ------------------------- |
| `sticky-notes:list`    | `{}`                                                     | `{ notes: StickyNote[] }` |
| `sticky-notes:create`  | content, positionX/Y, width/height, color (all optional) | `{ id: string }`          |
| `sticky-notes:update`  | `id` + any updatable field                               | `{}`                      |
| `sticky-notes:delete`  | `{ id }`                                                 | `{}`                      |
| `sticky-notes:changed` | Push event (no payload)                                  | —                         |

### Key Files

| Layer           | File                                                                    | Purpose                                                     |
| --------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------- |
| Migration       | `src/main/db/incremental-migrations.ts`                                 | v172 `CREATE TABLE sticky_notes`                            |
| Queries         | `src/main/db/queries-sticky-notes.ts`                                   | CRUD (list, create, update, delete)                         |
| IPC handlers    | `src/main/ipc/sticky-notes-handlers.ts`                                 | Zod-validated wrapHandler + push                            |
| Shared types    | `src/shared/types.ts`                                                   | `StickyNote` interface, `stickyNotesEnabled` in AppSettings |
| Shared channels | `src/shared/ipc-channels/`                                              | 5 channel constants                                         |
| Shared schemas  | `src/shared/ipc-schemas.ts`                                             | Zod schemas for all 4 mutations                             |
| Store           | `src/renderer/src/stores/sticky-notes-store.ts`                         | Zustand store (load, toggleOpen, CRUD)                      |
| Widget          | `src/renderer/src/features/sticky-notes/StickyNoteWidget.tsx`           | Individual note UI                                          |
| Overlay         | `src/renderer/src/features/sticky-notes/StickyNotesOverlay.tsx`         | Portal container                                            |
| Settings        | `src/renderer/src/features/settings/sections/features/feature-rows.tsx` | Toggle row                                                  |
| Toolbar         | `src/renderer/src/features/toolbar/toolbar-items.ts`                    | Item definition                                             |
| Toolbar render  | `src/renderer/src/features/toolbar/ToolbarPinnedItem.tsx`               | Switch case                                                 |
| App wiring      | `src/renderer/src/App.tsx`                                              | Lazy overlay + toolbar prop threading                       |
| Tests           | `tests/unit/db/queries/queries-sticky-notes.test.ts`                            | 4 CRUD unit tests                                           |

### Color Contrast

The widget uses luminance-based color selection. `isLightColor()` computes perceived brightness via the ITU-R BT.601 formula. Light backgrounds get dark text (`#1a1a1a`), dark backgrounds get light text (`#f5f5f5`). All icons, placeholder text, resize dots, and the text cursor follow the same rule — no Tailwind CSS-var colors are used on the note surface.

### Default Colors

Six pastel presets: yellow (`#FFF9E6`), blue (`#E6F9FF`), green (`#E6FFE6`), pink (`#FFE6F0`), purple (`#F0E6FF`), orange (`#FFE6D5`).

## Related

Scratchpads is the other note-taking surface in Omniscio — persistent notes that live in a pane and feed the global search, rather than notes that float over the window.
