Keyboard-first, local-first scratchpad & snippet workspace for Windows.
One global hotkey opens the same local workspace — notes, prompts, commands, snippets, project scratchpads and small file bundles. No browser, no cloud, no account.
Guides: English · Русский · Deutsch · Eesti · 日本語
The main workspace: hierarchical scratchpads on the left, a full Markdown editor on the right, project tabs on top.
FastPrompter is for text you repeatedly need while working: temporary notes,
prompts, commands, snippets, project scratchpads and small file bundles.
One global hotkey (Alt+X) opens the same local workspace from anywhere —
a browser, an IDE, a terminal — without switching to a cloud notebook.
Changed text is saved automatically; there is no save button to remember.
Your data stays yours: primary state lives beside the executable, and nothing leaves your machine unless you ask it to.
- Global summon hotkey —
Alt+X/F15(rebindable, two slots) pops the window up at your cursor from any application. - Project-oriented organization — up to 100 project tabs; each holds up to
100 auto-saved scratchpads ("silos"), 10
F1–F10snippets, and an archive. - Auto-saved hierarchical scratchpads — silos nest into a tree and support
pins, completion ticks, recency tints and multi-select;
Ctrl+Zundoes text and silo operations. - Markdown & code editing — live highlighting, clickable checkboxes, folding, code fences with syntax tints, line numbers and one-click copy.
- Per-silo file containers — drop any files into a silo's drawer; it is a plain folder on disk, browsable in Explorer without the app.
- Local-first portable storage — SQLite (WAL) database,
.bakrotation, daily Markdown snapshots, an optional one-way mirror and a restorable trash. No cloud, no account, no telemetry. - Optional local automation — a watcher can queue prompts from a silo and send them into a target app when the app is idle.
Portable EXE (recommended). Download FastPrompter.exe from the
Releases page, run it,
press Alt+X. No install, no Python, no admin rights. Data lives in a data/
folder next to the EXE — copy that folder and you have your backup and your
install in one move.
From source (Python 3.11+):
git clone https://github.com/vacterro/FastPrompter.git
cd FastPrompter
uv sync
uv run python FastPrompter.pyw # or: pip install -r requirements.txt; python FastPrompter.pywBuild your own portable EXE (≈28 MB, unused Qt modules stripped):
uv run python tools/build.pyWhere your data lives. Primary state is a per-profile SQLite database —
local_data_v15.db for profile 1, local_data_v15_pN.db for profile N — in a
data/ folder beside the executable (falling back to
%LOCALAPPDATA%\FastPrompter\ if that folder is not writable). Each profile
owns an independent File Container root: profile 1 keeps the legacy
layout, while profile 2+ are namespaced under data/_profiles/pN/, so one
profile can never read, adopt or delete another profile's folders. Inside that
root, every project/category maps to a stable physical folder component
(a sanitized, collision-resistant derivative recorded in category_file_dirs)
— the on-disk name is not the raw UI category name, and a renamed category
keeps its physical folder. Each silo's files live in a sub-folder derived from
its content; the trash lives under the same profile root. There is no cloud,
no account and no telemetry; the core app makes no network calls.
What leaves the machine. Nothing by default — no network calls, no telemetry, no account. Two opt-in features extend beyond the app: the daily Markdown snapshot folder (written to your local Documents, see below) and the watcher, which sends queued prompts into a target application you choose and explicitly arm.
How it survives.
- Transactional saves — SQLite in WAL mode; every save is a single transaction. Changed text is autosaved on a 10-second timer and on hide, close and silo/profile switches.
- Database backup — a
.bakcopy is taken at startup and refreshed at most once a minute after real changes; each new copy is validated before it replaces the previous one, and a fresh or empty database never overwrites a healthy backup. - Daily Markdown snapshots — every project's silos, snippets and archive
are exported as plain
.mdtoDocuments\.fastprompter\YYYY-MM-DD\(on by default, at most every 2 minutes, last 7 days kept). A snapshot is only marked complete after every export succeeded; a failed snapshot keeps the previous day's copy. Readable without FastPrompter. - Optional one-way mirror — point Settings at any folder and silos are
mirrored there as
.mdshortly after you save (and flushed when you close). It never reads back and never deletes. - Undo across restarts — the latest undo snapshots are written to
<database>_undo.jsonand reloaded on the next launch. - Trash, not destruction — clearing or trashing a silo moves its text and files into the trash under the active profile's File Container root; the Trash dialog restores them.
The honest failure model lives under Known limits.
Mechanisms, not marketing:
- Stack — Python 3.11, PyQt6, SQLite (standard library), Win32 APIs; packaged as a portable single-file EXE with Nuitka.
- Persistence — SQLite in WAL mode (
synchronous=NORMAL) with transactional delta saves: only changed rows are written, and snapshots are only taken after a commit succeeds (core/state.py,utils/portable_backup.py). - Single-instance IPC — a
QLocalServernamed pipe (FastPrompter_Server_V15) with a temp-file token and an ACK handshake; a second launch hands off to the running instance instead of stacking (core/ipc_server.py). - Two hotkey layers — Win32
RegisterHotKeyplus a native event filter dispatches global keys with layout-independent VK resolution (QWERTY, JCUKEN, AZERTY, QWERTZ); in-app keys are QtQShortcuts. Both layers are rebindable with two slots per action (core/hotkeys.py,core/hotkey_filter.py). - Custom editor stack — a
QPlainTextEditsubclass with a live Markdown highlighter, a line gutter with fold arrows, section folding, code-fence copy, clickable checkboxes, collapsible image pills, a four-zone file drop overlay and hide-markup mode (ui/editor.py,ui/markdown_highlighter.py). - Filesystem-backed containers — each silo owns a stable, unique folder
under its profile's File Container root; the physical category component is
the sanitized
category_file_dirsentry (independent of the UI name), so it is rename-safe and recoverable through the trash (ui/file_container.py). - Multi-layer recovery model — transactional DB + startup/throttled
.bak- daily plain-Markdown snapshots + optional one-way mirror + persisted undo
- soft-delete trash. Each layer catches a different failure class.
- Watcher as a finite-state machine — explicit
DISARMED → ARMED → WATCHING → SENDINGstates with settle, rate and failure boundaries (core/watcher/engine.py). - Tests — a unit suite plus a smoke/integration suite that boots the real
application offscreen; CI gates compilation, ruff, Bandit Medium+, and the
full suite on
windows-latest(see Development).
- Silos — up to 100 auto-saved scratchpads per project; nest into a hierarchy, pin, tick, tint by recency, multi-select, middle-click to trash.
- Snippets — named text blocks pasted with
F1–F10(orCtrl+Shift+1–0), with variable placeholders. - Projects — up to 100 tabs, each with its own silos, snippets, archive and files; right-click to add/rename/delete, wheel to switch.
- Search — multi-word AND matching across silos (
foo barfinds both). - Archive — one click stores a silo or snippet out of the way, restorable.
- File containers — per-silo plain folders under
data/files/; drag files in/out, preview images, link originals, Explorer-style views. - Drop zones — dragging a file onto the editor offers insert-as-text, insert-link, copy-to-Files, or shortcut.
- Folder templates — build a predefined structure (IN/OUT, assets, …) inside a silo's container with one click.
- Trash — middle-click moves a silo (text and files) to
data/files/_trash/; nothing is destroyed behind your back.
- Global hotkeys (rebindable, two slots each):
Alt+X/F15toggle window,Shift+Alt+Xpie menu,Alt+Elock position,Alt+Salways on top,Alt+Dsidebar,Alt+Ahide on click-out,Ctrl+Alt+Shift+Qquit. - Window modes — frameless, lock-in-place, always-on-top,
Ctrl+Qsnap to corners/zones, three-stage zen mode. - Themes — 9 built-in (Win95-style dark-golden, OLED, Dracula, Nord, Solarized Dark, …) plus a full custom color editor.
- Scaling — the whole UI scales 50–150% (
Ctrl+Plus/Ctrl+Minusfor fine steps). - Extras — analog clock, date widget, Pomodoro-style timer, optional UI sounds with per-event sound settings, and 33 interface languages with flag icons (including the bonus «Дед» grandpa voice).
- Watcher — queue prompts from a silo and have them typed into a target
app when the app is idle. This is a local workflow automation, not a bot:
you arm it per session against one target you choose. It waits until the
target is observed idle, sends one prompt at a time with a minimum gap, a
per-session send cap and a consecutive-failure cutoff, and never persists
its armed state across restarts. Targets are declared as TOML adapters
(Claude Code, opencode, freebuff, Antigravity, …) over Win32 message or
Chromium CDP transports (
core/watcher/, see the Watcher Engine wiki). - SAIPEN — FastPrompter previously shipped a small viewer for
.saipen/state files (STATE/BOARD/LOG); it was removed in v0.8.4. The canonical SAIPEN protocol lives in its own repository: github.com/vacterro/saipen. The watcher above is generic and does not depend on SAIPEN.
Main workspace — project tabs, silo sidebar and the Markdown editor.
Drop zones — dragging a file onto the editor lets you embed it, link it, or copy it into the silo's folder.
Settings — toggle everything from line numbers to the analog clock.
Global hotkeys — rebind any action to fit your workflow and avoid clashes with other software.
More images live in the Wiki gallery.
uv sync --group dev
uv run python -m compileall -q src FastPrompter.pyw
uv run ruff check src/ tests/ tests_smoke/
uv run bandit -q -r src/fastprompter -ll
uv run pytest tests/ tests_smoke/ -q- The suite spans the headless unit tree in
tests/and the offscreen real-app integration suite intests_smoke/(which builds the actual window). The authoritative test count and pass/fail state are produced by the full gate run on the target Windows build at the exact revision under test — do not assume a specific total or an all-green result without that run. The live collection count can be obtained withuv run pytest tests/ tests_smoke/ --collect-only -q. - CI (GitHub Actions on
windows-latest) runs all four commands above on every push tomainand every pull request. Any failure blocks the job. - Pre-commit runs ruff with fixes, YAML validation, merge-conflict detection, and a 500 KB added-file limit. It does not run the full CI matrix.
mypyandpyrightare declared dev dependencies but do not currently gate CI or pre-commit. Bandit does gate CI at Medium severity and above (-ll).
- Guides — English · Русский · Deutsch · Eesti · 日本語 — the friendly, grandpa-voiced explanation of every feature.
- CHANGELOG — version history with the reasoning behind each release.
- GitHub Wiki — Architecture, Module Structure, Core API, Configuration, Keyboard Shortcuts, User Guide, Watcher Engine, Deployment.
Freshness policy: the README and the code in src/ are canonical. Wiki
pages describe the v0.8.x codebase they were written against; when a page
and the code disagree, the code wins.
The version lives in pyproject.toml; every release is tagged v<version>.
Portable EXE builds are published to the
Releases page via
tools/release.py. The last published EXE can lag the latest source tag —
check the release date before downloading.
- Autosave window — text is written on a 10-second timer plus lifecycle events; a forced process kill can lose up to ~10 seconds of typing.
- Power loss — SQLite runs with
synchronous=NORMAL; a sudden power cut can cost the most recent transaction. The WAL journal bounds the damage, and the daily Markdown snapshots are the archive. .bakis a single generation — a rollback point, not an archive.- Snapshots keep 7 days — older day folders are pruned.
- Watcher — detection is best-effort (file/sqlite/window/process probes); a wrong reading can cost at most one prompt within a rate-limit window. It only ever sends into a target you armed.
MIT — see LICENSE.
Built with Python, PyQt6 and ❤️ by vacterro