Stickies (Claude Code plugin)
A small, deterministic sticky-note layer for Claude Code. You pin a note โ a decision, a
blocker, a todo โ and it survives session resets, /clear, and closing the terminal. Next
session in that project, the notes that still matter are handed back to Claude automatically.
Stickies is not a memory system, and it doesn't try to be one. It won't watch your session
and decide what to remember. It's the opposite: a handful of notes you (or Claude, on request)
write down on purpose, that expire on their own, and that you can read, prune, and trust. No
vectors, no LLM summarization pass, no cloud. If you want an AI that auto-remembers everything,
use Claude Code's built-in memory โ it's on by default.
Stickies is for when you want the twenty notes that actually matter, and you want them to expire.
Two things here you won't find elsewhere:
- Zero-turn capture. Claude parks a note by writing one line in a reply it was already
writing โ
!!sticky todo P1 :: fix the auth leak โ and a Stop hook persists it. No extra
tool call, no extra turn, no tokens spent on a round-trip. (Details: auto-capture.)
- Importance-graded injection. The session-start digest degrades by importance, not by
position: P1 in full, P2 truncated, P3 a bare count. It never just chops the list at N lines.
New here? Read USAGE.md โ plain-terms guide (the three verbs, what P1/P2/P3
control, project vs global). For the phone/desktop story, see PHONE.md. This README
is the reference: components, internals, install.
Everything runs locally. SQLite on your disk, a deterministic auto-capture hook, a loopback
web dashboard. Optional git-backed sync through a repo you own โ off unless you configure it, and
the only thing that ever touches the network.
Clients โ what's shipped vs planned (full detail in PHONE.md):
| Surface | State | How |
|---|
| Terminal (Claude Code) | โ
full loop | plugin: hooks + commands + MCP |
| Claude Desktop (Windows/Mac) | โ
read/write | MCP tools only โ no hooks, pass the project path |
| iPhone / web | โ
full loop via Remote Control | run claude remote-control on your machine; the phone drives that local session (nothing to build) |
| iPhone / web (cloud sandbox) | โ
full loop via repo-mode | stickies init-repo commits a store + hooks into the repo; notes persist and converge to main (see repo-mode) |
| Anywhere, read-only | โ
| Discord session report |
Components
| Component | File | Purpose |
|---|
| MCP server | src/server.js (via .mcp.json) | tools stickies_write, stickies_read, stickies_dismiss |
| SessionStart hook | src/session-start.js (via hooks/hooks.json) | injects a digest into the live session via the hook's additionalContext (no file is touched) |
| Stop hook (auto-capture) | src/auto-capture.js, src/directives.js | persists !!sticky โฆ directives from each turn, deduped |
| Local dashboard | src/dashboard.js, src/dashboard-page.js | loopback web UI to view/add/dismiss stickies |
| Slash command | commands/stickies.md | /stickies, /stickies all, /stickies add <text>, /stickies dismiss <id>, /stickies dashboard |
| CLI | src/cli.js | backs the slash command; also usable directly |
| Store / DB | src/store.js, src/db.js | sticky CRUD + schema + TTL logic + auto-capture dedup |
| Sync engine | src/sync.js | export/import a sync document, last-writer-wins merge |
| Git sync | src/git-sync.js | pull โ merge โ export โ commit โ push against a repo you own |
| Project identity | src/project-key.js, src/store-path.js | machine-independent project key (git remote, else path) |
| Digest | src/digest.js | digest formatting; one-time cleanup of the deprecated CLAUDE.md managed section |
| Redaction | src/redact.js | scrubs secrets from content on write |
| Repo-mode | src/repo-mode/ (engine.mjs, install.js, stickies-sync.yml) | cloud/mobile-native: committed store + hooks + reconcile Action; installed by stickies init-repo |
Auto-capture directive
In a reply, the model can capture a durable fact with one line โ a Stop hook persists it:
!!sticky <category> [P1|P2|P3] [global] [#tag ...] :: <content>
!!sticky decision P1 #storage :: storage is node:sqlite, no native deps
!!sticky todo P1 global :: cut the npm release
category required; importance defaults to P2; deduped. global and tags are optional and
may appear in any order. Without global a note is scoped to the current project; with it
the note is unscoped and surfaces in every project.
The Stop hook scans the assistant text of the whole completed turn โ the turn boundary is
the human's message, not merely the last transcript entry of type user (Claude Code
logs tool results as user entries too). So a directive written mid-turn survives any tool
calls that follow it. Directives inside subagent (isSidechain) replies are ignored.
Clients
Notes belong to the project, not the client: one DB, scoped by project key. What differs
is how much is automatic.
| Claude Code (terminal + desktop app) | Claude Desktop (chat app) |
|---|
| Digest injected at session start | โ
SessionStart hook | โ no hook support |
!!sticky auto-capture | โ
Stop hook | โ no hook support |
/stickies command | โ
| โ |
stickies_write/read/dismiss | โ
| โ
(MCP) |
| Knows the current project | โ
from cwd | โ pass project_path explicitly |
Claude Code needs no setup beyond installing the plugin. Claude Desktop supports only the
MCP tools โ add to claude_desktop_config.json (%APPDATA%\Claude\ on Windows,
~/Library/Application Support/Claude/ on macOS):
{
"mcpServers": {
"stickies": {
"command": "node",
"args": ["--disable-warning=ExperimentalWarning", "/abs/path/to/stickies/src/server.js"]
}
}
}
Both clients read the same ~/.stickies/stickies.db, so notes written in one are visible
in the other with no sync step.
Repo-mode (cloud / mobile)
The plugin above is user-scoped โ it lives in ~/.claude, so it does not exist in a cloud
session (the iPhone app / claude.ai/code run in an ephemeral VM that only sees files committed in
the repo it cloned). Repo-mode makes Stickies work there, with no plugin and nothing to install:
That commits a self-contained, zero-dependency engine and wires it up:
.stickies/notes.json โ the store (source of truth) + a human-readable .stickies/NOTES.md mirror
.claude/settings.json โ a SessionStart hook (injects the digest) and a Stop hook (captures !!sticky โฆ)
CLAUDE.md โ teaches Claude the !!sticky convention (the plugin's MCP instructions aren't present in the cloud)
.github/workflows/stickies-sync.yml โ converges notes from every session branch into main
In a cloud session Claude reads the repo's notes at start and captures new ones into
.stickies/notes.json; because that's committed, the note survives the disposable VM. Cloud
sessions write to their own claude/* branch, so the bundled GitHub Action merges each note into
main (union + dismiss-wins + dedupe) โ one converged board per repo, hands-off. Secrets are
redacted before the store and before Discord, exactly as in the local plugin.
Repo-mode is per-repo (notes live in that repo). The user-scope plugin remains the way to get
the cross-project shared board on your desktop. Both use the same !!sticky grammar and redaction.
Dashboard
npm run dashboard
node src/cli.js dashboard --open
node src/cli.js dashboard --detach
Loopback only; mutations are gated by an in-page token (CSRF-safe).
Sync (git-backed, opt-in)
Stickies sync through a git repo you own โ no third-party service, no new account.
Each note records a machine-independent project_key derived from the project's git
remote (SSH and HTTPS collapse to the same key). So a project's notes follow you between
machines even though the checkout lives at a different path on each โ not just globals.
Projects without a git remote fall back to a path-based key (same-machine scope).
export STICKIES_SYNC_REPO=/path/to/your/stickies-data
node src/cli.js sync
node src/cli.js export -f notes.json
node src/cli.js import -f notes.json
Merge is whole-record last-writer-wins by updated_at โ conflict-free and order-independent.
Pull/push are skipped if the repo has no remote, so a purely local repo works too. Sync is
the only feature that can reach the network, and only when you configure a remote.
Auto-sync (opt-in)
export STICKIES_SYNC_REPO=/path/to/your/stickies-data
export STICKIES_AUTO_SYNC=1
With both set, Stickies pulls on session start (so your digest reflects other machines)
and pushes when a turn captures a new sticky. Off by default โ with STICKIES_AUTO_SYNC
unset, nothing syncs automatically and you sync manually with /stickies sync.
Sticky model
Fields: id, content (โค500 chars), category, importance (P1/P2/P3),
project_path (absolute, or null for global), tags[], created_at, updated_at,
expires_at, source (auto/manual), status (active/stale/dismissed).
Default TTLs: decision 30d ยท blocker 7d ยท preference 90d ยท context 14d ยท todo never
expires (a task is done when you dismiss it, not when a timer runs out).
Task lists
todo + global makes stickies usable as a task list: per-project todos live in the
project's drawer, cross-project ones (global) surface everywhere. Neither expires, so an
unfinished task can't silently vanish. Finish one by dismissing it:
node src/cli.js list
node src/cli.js add "ship it" -c todo -i P1
node src/cli.js add "ship it" -c todo -p global
node src/cli.js dismiss <id> -r "done"
Storage
One SQLite file shared across all projects, scoped per-project by project_path.
Location: $STICKIES_DB if set, else ~/.stickies/stickies.db.
Uses Node's built-in SQLite (node:sqlite, requires Node โฅ 22.5) rather than a
native addon, so the plugin has zero compiled dependencies and survives Claude Code's
plugin-cache copy on any machine. (node is invoked with
--disable-warning=ExperimentalWarning to mute the node:sqlite experimental notice.)
P1 shown in full ยท P2 summarised to first 100 chars ยท P3 count only. The digest is handed to
the session through the SessionStart hook's additionalContext โ it reaches Claude without
writing to any file. (Earlier versions wrote the digest into the project's CLAUDE.md
between <!-- stickies:start --> / <!-- stickies:end --> markers; that mutated a git-tracked,
often team-shared file, so a note could land in a diff. The SessionStart hook now removes that
managed section on next run โ a one-time cleanup.)
Install
Requires Node โฅ 22.5 (for the built-in node:sqlite). Check with node -v.
claude plugin marketplace add dumbspacecookie/stickies
claude plugin install stickies@stickies --scope user
Then restart Claude Code โ hooks and the MCP server are read at startup. Install once at user
scope and it's available in every project; per-project scoping is by project_path on each
note, not by per-project install.
Local dev (working on Stickies itself):
git clone https://github.com/dumbspacecookie/stickies
claude plugin marketplace add ./stickies
claude plugin install stickies@stickies --scope user
npm test
How Stickies compares
Persistent-notes-for-Claude-Code is a crowded space. Being honest about it:
- Claude Code's built-in memory โ on by default,
the model decides what to save, no expiry, no importance tiers, no cross-project globals,
per-repo only. Stickies is the deterministic, human-authored, expiring alternative for people
who turned that off.
- Knowledge-graph / vector memory servers (mem0, OpenMemory,
server-memory, basic-memory) โ
fuzzy retrieval over everything you've said. Different job. Stickies stores a small typed set,
not an embedding index.
- Hook-based memory plugins โ several exist and some are excellent. Stickies' narrow bets are
the three above: zero-turn
!!sticky capture, importance-graded injection, and a global tier
that surfaces across projects alongside per-repo scoping.
If you want auto-recall of your whole history, use one of those. Stickies is for a short,
trustworthy, self-pruning list.
CLI usage
node src/cli.js list
node src/cli.js list --all
node src/cli.js add "text" -c todo -i P1
node src/cli.js dismiss <id> -r "done"