Notepatra editor MCP server — 35 tools; every write human-approved in the editor; local-only.
Runs on your machine from its package; the steps are below.
At most: creates or changes data: records, files, settings.
Odel charges nothing per call. The publisher may charge for its own service.
Runs locally over stdio
This server isn't hosted — your MCP client launches it from a package registry. Use one of the commands below, or drop the config into your client (e.g. Claude Desktop).
Distributed via cargo as `notepatra-mcp`.
The first code editor built for the AI era.
C++ + Rust · ~13 MB bare native executable · Zero Electron · 238 file types · 82 language lexers · Local AI formatters · MCP server
MCP: notepatra-mcp now ships a prebuilt signed Windows sidecar and a one-click Claude Desktop bundle — connect Claude Desktop, Claude Code, OpenAI Codex, and any MCP client to the running editor. 49 tools (Git, read-only SQL, saved-connection queries, charts, Noter notes); every write human-approved in-window; nothing leaves your machine.
Website · Download · MCP · Features · The Story · Install · Plugins · AI · Contributing · Security · Changelog
I'm Prateek Singh. A developer who spent years on Linux wanting a small, fast, free native code editor that could fix things in seconds — broken JSON, messy SQL, tangled HTML — and finding only Wine hacks or bloated Electron editors eating 500 MB of RAM to show a text file.
Every text editor told me to pick two of three: fast, powerful, native. Vim is fast and native but cryptic. Modern Electron editors are powerful but heavy. The truly tiny native ones either don't have AI or don't run cross-platform.
So I built Notepatra.
Not a port. Not a wrapper. Something new — for everyone.
I asked: what would a small native code editor look like if it was built today, in 2026, when AI is part of every developer's workflow, and ran natively on Linux + macOS + Windows from one codebase?
The answer: a tiny native executable — ~13 MB bare (~13.4 MB on Linux x64) on every platform — with a Rust-powered core, Scintilla editing engine, and local-first AI integration (cloud backends optional). v0.1.129 downloads: 4.7 MB Linux x64 (tarball, Qt from the system), 28.0 MB on macOS (DMG with bundled Qt), 32.8–43.9 MB on Windows (MSI/zip/setup.exe with bundled Qt DLLs). An editor that can fix your broken JSON with regex in milliseconds — and when regex isn't enough, it asks your AI to figure it out — local by default, six cloud backends one click away when you want a frontier model. No telemetry. No subscription. No mandatory API key.
Notepatra started on Linux — because that's where the gap was. But great tools shouldn't have borders. Notepatra runs on Linux, Windows, and macOS. Same codebase. Same features. No one gets left behind.
Notepatra is what I wish had existed — on every platform.
{} [] (), highlights both braces + selects everything betweenCtrl+Shift+G) — recursive search across file names AND file contents in any text-based file. Any size, any language (Python, SQL, C/C++, JS/TS, Rust, Go, HTML, JSON, YAML, Markdown, logs, config). Streams line-by-line so a 2 GB log searches the same as a 2 KB script. Each match shows exact line:col coordinates — double-click to jump the caret to the character.\n, \r, \t, \xNN), Regular expressionEvery plugin opens in its own tab. Real UI, not just a menu click.
| Button | What it does |
|---|---|
| Format | Pretty-print with preserved key order |
| Minify | Compact to one line |
| Fix + Format | Rust-powered auto-repair: fixes missing braces, trailing commas, single quotes, unquoted keys, missing { after [ — shows detailed report of every fix |
| AI Fix (Ollama) | Sends truly broken JSON to your local AI — fixes what regex can't |
| Button | What it does |
|---|---|
| Format (2/4 spaces) | Proper HTML indentation |
| Minify | Strip all whitespace |
| Fix + Format | Auto-close unclosed tags, detect missing closers, report issues |
| AI Fix (Ollama) | AI repairs broken nesting, malformed tags, missing attributes |
| Button | What it does |
|---|---|
| Check | Detailed report: line numbers of every mismatched () [] {}, keyword mismatches (begin/end, if/fi) |
| Auto-Fix | Adds missing closers in correct nesting order |
| AI Fix (Ollama) | AI understands your code structure and fixes all bracket issues |
+ green for added, - red for deleted, # amber for changed+ / − buttons per row to stage/unstagemain ↑3 ↓1 when divergedBackend dropdown ships 6 entries — Ollama (local default · localhost:11434), llama.cpp (GGUF) (local · localhost:8080), OpenRouter (cloud · 100+ models), Ollama Cloud (cloud · gpt-oss:120b / qwen3-coder:480b / deepseek-v3.1:671b), OpenAI (cloud · GPT-4o / GPT-5 / o-series), Azure OpenAI (enterprise). Per-provider key slots — no cross-provider bleed. The llama.cpp entry also accepts a user-configured base URL via Settings → Preferences → AI, so you can route it to any OpenAI-compatible HTTP server you have installed separately. Local backends keep code on your machine; cloud backends are opt-in. No telemetry. No subscription. No mandatory API key.
Ctrl+Shift+A)The AI chat lives in a persistent right-side dock, not an editor tab. One conversation, preserved across tab switches. Tick Coding Mode to open the 3-column coding layout (file tree · editor · AI chat) 3-pane layout.
Workspace awareness. Every prompt carries:
.git, node_modules, target, dist, etc. filtered out)So the model can reason about files you haven't opened yet — "import from utils.py" works even when utils.py isn't in a tab. Budget-capped so small local models (3B, 4K–8K context) don't overflow.
One-click actions (hidden by default, click "▸ Quick actions" to reveal): Explain · Find Bugs · Refactor · Write Tests · Add Comments · Generate Docs · Optimize · Translate. Or type a custom prompt. Responses stream in, each has a Copy link, and the last response can be inserted at the cursor or replace the selection with one click.
Speech-to-text — optional mic button, uses local arecord + whisper CLI when installed. No audio ever leaves the machine.
# Easiest path: Ollama
curl -fsSL https://ollama.com/install.sh | sh
ollama pull qwen2.5-coder:3b # 2 GB, best for code on CPU-only / 16 GB RAM
ollama serve
Notepatra auto-detects the running Ollama and picks the most CPU-friendly model installed. For llama.cpp / OpenRouter / Ollama Cloud / OpenAI / Azure OpenAI, pick the backend from the dropdown at the top of the AI panel; base URL and API key are editable inline. The llama.cpp entry also accepts a user-configured base URL via Settings → Preferences → AI, so you can route it to any OpenAI-compatible HTTP server you have installed separately.
Tools > Password Generator — Passwords / Passphrases / SSH keys)A generator built into the binary, opened from the Password button on the Built-in Tools toolbar (third, immediately after AI) — press it again while the tab is focused and the tab closes. A left rail switches between three pages: Password, Passphrase and SSH key (Alt+1 / Alt+2 / Alt+3). It ships in every build, including the default Lite binary and works fully offline: no network, no download, no backend, no AI.
0 O 1 l I) and at least one from each set (on by default). The symbol set deliberately omits the quotes, backslash, backtick, pipe and space — the characters that break a password pasted into a shell command, a YAML file or a database connection string.aes256-ctr + bcrypt-pbkdf, the same construction ssh-keygen uses. The comment field is empty by default, on purpose: ssh-keygen defaults it to user@host, which copies your username and machine name into every authorized_keys file the key is ever pasted into. The public line and its SHA256 fingerprint are shown immediately; the private key stays hidden until you tick Show private key. Save private key… creates the file, sets it to 0600, then writes it, refuses to overwrite an existing file, and writes the .pub companion (0644) beside it. Generation runs off the GUI thread, so the window stays responsive while RSA-4096 takes its 1.6–5.9 s. Interoperability is checked against the system ssh-keygen in the test suite — -y reproduces the public line, -lf the fingerprint, and -y -P opens the encrypted key and rejects the wrong passphrase. The pure-Rust crypto (RustCrypto ssh-key) costs about 0.6 MB of binary.getrandom on Linux, the platform equivalent elsewhere) through the Rust core. Qt's QRandomGenerator::system() is now only the fallback, not the source — it was the source before v0.1.129, and on x86-64 that meant the CPU's RDRAND instruction first, which is a different provenance than most readers assume. SSH keys come from the same OS source. Draws use rejection sampling so no character is favoured just because the alphabet size doesn't divide 2^32, and the set guarantee is enforced by drawing again until it holds, not by placing one character per set and shuffling — placement would make some strings likelier than others and turn the bits figure into a lie. The panel is a plain widget rather than an editor, and session save/restore, the AI-context sweep and the MCP read verbs are all gated on the tab being an editor, so a generated value never lands in session.json, never reaches an AI backend, and is not readable by a connected MCP client. Copy takes the value back off the clipboard after 30 seconds — but only if the clipboard still holds it, so it never clobbers something you copied since. The 30-second wipe arms for the private key only, never for the public line. Nothing is written to disk unless you choose Save private key….Features → AI Interaction Log…)Total transparency, on by default. Every request and response to any AI backend — local (Ollama / llama.cpp) or cloud (OpenRouter / OpenAI / Azure / Ollama Cloud), including Noter's Extract — is written to a local SQLite log you can open and read: timestamp, backend, model, mode, full prompt + full response, token counts, latency. It never leaves your machine (zero network egress), entries auto-prune after 7 days, and a built-in credential scrubber masks API keys / bearer tokens / PEM private keys before anything is stored. The viewer has backend/model/mode filters, Export JSON, Prune now, and a one-click opt-out toggle. You are never guessing what got sent to a model — you can audit every byte. Privacy as transparency, not as a promise.
Ctrl+Alt+N)A local-first, two-pane meeting workspace (notes list · editor) — no accounts, no bots; notes live under ~/Documents/Notepatra/Noter/.
Ctrl+Alt+E) runs your AI backend over the note and returns a summary plus action items / decisions / questions / risks. A task that mentions a time ("ship the build 10am tomorrow") comes back with that date/time pre-filled..npd)A first-class diagramming surface that renders in the default binary on every platform (incl. macOS Apple Silicon and the Windows installer — native Qt renderer, no WebEngine), opened from the toolbar next to Noter. The tiny .npd text DSL is the source of truth; the canvas is a live projection of it (so undo/redo and version control just work).
.npd, shown in a review pane before it touches the canvas (undo/redo after); or start from a Flow / ER / System template; or write .npd directly. Import Mermaid converts an existing flowchart, now mapping -.-> to a dashed edge and subgraph … end to a group..npd renders natively, offline, in the Lite binary, with AI Generate, node-pinned notes, legends, built-in icons, theme-following palettes, and an export_diagram MCP tool. Mermaid still wins on diagram types (sequence, class, Gantt) and on GitHub rendering it inline — the full comparison is in the docs.paper and slate — alongside the older dark ones (clay / ocean / forest / mono / default), and the new default palette auto follows the app theme: light theme → paper, dark theme → default.a -.-> b, a <.-> b) for the async / optional / best-effort hop, label-overflow→hover, infinite pan/zoom canvas. A per-node colour renders as a tint on a light palette (soft wash, full-strength border, normal dark text) and as a solid fill with auto-contrast text on a dark one.direction LR lays the diagram out left-to-right (TB is the default), group "Edge tier" : cdn api draws a labelled container behind those nodes, note api "Rate-limited to 100 rps" pins a small card beside one, and legend dashed "async" / legend #cc785c "hot path" build a legend box (which appears only if you write at least one legend line). group, note, legend, direction and layout are now reserved words — an existing file that uses one as a node id needs the id renamed.samples/diagram_showcase.npd shows every element; the npd_render CLI renders any .npd to an image headless.| Feature | Shortcut |
|---|---|
| Built-in Terminal | `Ctrl+`` — opens as a tab, runs real commands |
| REST Client | Ctrl+Shift+R — send HTTP requests, see responses with pretty JSON |
| Hex Editor | View > Hex Editor — color-coded hex dump of any binary file |
| Markdown Converter | Features > Markdown — convert selection to table, list, code block, bold, link, heading, or strip HTML to markdown |
| File Explorer | Ctrl+Shift+E — tree view sidebar |
| Function List | View > Function List — lists all functions/classes, double-click to navigate |
| Preferences | Settings > Preferences — 6 tabs of configuration |
| Password Generator | Tools > Password Generator — Passwords / Passphrases / SSH keys — random characters, a 2,048-word passphrase, or an OpenSSH key pair (Ed25519 / ECDSA / RSA); the bits readout is the exact number of values the settings can produce |
| Category | Shortcut | Action |
|---|---|---|
| File | Ctrl+N | New |
Ctrl+O | Open | |
Ctrl+S | Save | |
Ctrl+W | Close tab | |
| Edit | Ctrl+D | Duplicate line |
Ctrl+Shift+K | Delete line | |
Ctrl+/ | Toggle comment | |
Ctrl+Shift+U | UPPERCASE | |
Ctrl+U | lowercase | |
| Search | Ctrl+F | Find |
Ctrl+H | Replace | |
Ctrl+Shift+G | Project Search (folder-wide names + contents) | |
F3 / Shift+F3 | Find Next / Previous | |
Ctrl+G | Go to line | |
Ctrl+B | Go to matching brace | |
Ctrl+F2 / F2 | Toggle / Next bookmark | |
| View | F11 | Full screen |
Ctrl+= / Ctrl+- | Zoom in / out | |
Alt+0 | Fold all | |
| Macro | Ctrl+Shift+M | Start recording |
Ctrl+Shift+T | Stop recording | |
Ctrl+Shift+P | Playback | |
| Features | `Ctrl+`` | Terminal |
Ctrl+Shift+A | AI Assistant | |
Ctrl+Shift+E | File Explorer | |
| Tabs | Ctrl+Tab | Next tab |
| Middle-click | Close tab | |
| Double-click empty | New tab |
From v0.1.118, Notepatra ships notepatra-mcp — a stdio JSON-RPC 2.0 Model Context Protocol server that connects external AI assistants (Claude Desktop, Claude Code, OpenAI Codex, the OpenAI Agents SDK, and any spec-compliant MCP client) to the running editor over a local socket. Nothing leaves your machine: stdio to the client, local socket to the editor, no network connections.
49 tools in three tiers:
| Tier | Tools | Gate |
|---|---|---|
| Read (24) | tabs, selection, status, recent files, in-tab + project search, Noter notes, reminders, read-only Git (status / diff / log / show / branch), .npd validation, read-only SQL (run_sql), language list (list_languages), capability probe (get_capabilities), .npd source read (get_diagram_source), saved connections (list_connections / run_query / list_tables) | None — observation only |
| Act (13) | open file, new tab, go to line, set language, compare tabs, format JSON/SQL/HTML, open note, create diagram, open Noter, open Data Analyst (open_data_analyst), render chart (render_chart) | None — visible, non-destructive |
| Write (11) | insert text, replace selection, find-and-replace, save, create note, append note, set reminder, export diagram, set diagram source, export query results (export_query_results), export chart (export_chart) | Approve/Deny card inside the editor — 120 s auto-deny, FIFO one card at a time, no headless bypass |
find_in_tab and search_project also take an optional regex flag. run_sql is SELECT-only (rejected by the SQL classifier otherwise) and, on the Full/DuckDB edition, runs in an engine sandbox — the target file is materialized into an in-memory table, then DuckDB's external filesystem access is disabled (enable_external_access=false) before the untrusted query runs, so it cannot read host files. Since v0.1.119 the sidecar also supports Windows over a named pipe.
Hook it up in one line each (from v0.1.118):
# Claude Code (Anthropic)
claude mcp add notepatra -- notepatra-mcp --socket
# Codex CLI (OpenAI) — ~/.codex/config.toml
[mcp_servers.notepatra]
command = "notepatra-mcp"
args = ["--socket"]
Full tool reference, Claude Desktop / Agents SDK snippets, security model, and honest limitations (editor must be running; prebuilt Windows sidecar zip + one-click .mcpb bundle ship from the next release — until then Windows uses cargo install notepatra-mcp; cloud-only connector surfaces can't reach a desktop editor): docs/mcp.html / notepatra.org/mcp.html.
┌──────────────────────────────────────────────┐
│ C++ Layer (Qt5 + QScintilla) │
│ UI · Menus · Tabs · Dialogs · Editor │
│ Terminal · AI Panel · Compare · Plugins │
├──────────────────────────────────────────────┤
│ C FFI boundary │
├──────────────────────────────────────────────┤
│ Rust Core Library │
│ File I/O (mmap) · Search (Aho-Corasick) │
│ Diff (Myers) · JSON/HTML/SQL Formatters │
│ Bracket Fixer · Hash · Base64 · Encoding │
└──────────────────────────────────────────────┘
Why this hybrid?
Linux / macOS:
curl -fsSL https://notepatra.org/install.sh | sh
Windows (PowerShell):
irm https://notepatra.org/install.ps1 | iex
That's it. Auto-detects your OS, downloads the right binary, installs it, adds to PATH, creates shortcuts.
| Platform | Download | Size | What's inside |
|---|---|---|---|
| 🐧 Linux x64 | .tar.gz | 4.7 MB | Bare notepatra binary. Qt5 from your distro. |
| 🐧 Linux ARM64 | .tar.gz | 4.4 MB | Bare notepatra binary for aarch64 / ARM64 Linux. |
| 🍎 macOS Apple Silicon (M1–M4) | .dmg | 28.0 MB | Notepatra.app with Qt frameworks bundled. Drag to Applications. |
| 🪟 Windows x64 (MSI) | .msi | 43.9 MB | WiX-built MSI. Per-machine install, upgrade-code handled, file-type associations for .txt, .log, .md, .json, .py, .cpp etc., adds Notepatra to PATH. Best for enterprise / SCCM deploy. |
| 🪟 Windows x64 (installer) | .exe | 33.0 MB | NSIS installer. Registers in Settings → Apps → Installed apps. Uninstall via Control Panel works. |
| 🪟 Windows x64 (portable) | .zip | 37.8 MB | notepatra.exe + Qt DLLs + QScintilla DLL. Unzip and run anywhere. No installer, no registry. Optional: double-click register-associations.bat inside the zip to add Notepatra to the "Open with" menu for .txt/.md/.py/.json/etc. — HKCU only, no admin needed. Undo with unregister-associations.bat. |
⚠ Download size vs. installed size are different. The numbers above are download sizes — the
.msi/.dmg/.tar.gzfiles you grab from GitHub Releases. After install, the on-disk footprint is larger because the installer extracts the bundled Qt DLLs, QScintilla DLL, and Rust core library out of the compressed payload. Typical installed size on Windows: ~75-85 MB. Linux installs are still tiny (~13 MB on disk) because Qt5 comes from your distro repo, not the tarball. macOS Notepatra.app on disk is ~50-60 MB afterxattrremoval.
Lite vs Full. The downloads above are the default Lite build. Each release also ships an opt-in Full variant (
-full) that bundles the DuckDB query engine on every platform — plus, on Linux and Windows, the QtWebEngine inline Vega-Lite chart renderer (thegenerate_charttool). macOS Full is DuckDB-only: Homebrewqt@5no longer ships QtWebEngine and there is no Apple-Silicon Qt5 WebEngine, so inline Vega charts are a Linux/Windows Full feature. The native fenced```chart(QtCharts) renderer and the.npddiagram tool work on every platform in both flavors.
Why are the download sizes different? Bare notepatra executable is ~13 MB on each platform (~13.4 MB Linux x64 — slightly smaller on Windows/macOS than on Linux because clang + MSVC emit denser code than gcc). On Linux, Qt5 is a standard system package (apt install qtbase5-dev libqscintilla2-qt5-dev), so the download is just the binary (~4.7 MB compressed). On macOS and Windows, Qt isn't pre-installed, so we bundle the Qt frameworks / DLLs alongside the executable for portability — same approach Krita, Kdenlive, and every cross-platform Qt app uses. Even with Qt bundled, Notepatra installs at ~12–85 MB depending on platform vs 300+ MB for VS Code.
macOS Intel: not shipped pre-built. Apple stopped selling Intel Macs in 2023 and the GitHub Actions
macos-13runner has been unreliable. Intel Mac users —git cloneand run./build.sh. Builds in ~3 minutes.
For one-time-install-then-every-user-sees-it on a shared machine, or silent push to a fleet via SCCM / Jamf / Ansible / Salt, every supported platform has a per-machine artefact:
| OS | Artefact | Silent admin install |
|---|---|---|
| 🪟 Windows | notepatra-x.x.x.msi | msiexec /i notepatra-0.1.129.msi /quiet — installs to C:\Program Files\Notepatra\, adds system PATH, registers HKCR file associations, all-users Start Menu. WiX-built, MajorUpgrade-aware, SCCM-friendly. |
| 🍎 macOS | Notepatra.dmg | Mount + sudo cp -R "/Volumes/Notepatra/Notepatra.app" /Applications/ from a deployment script. Or open the DMG manually and drag to /Applications (admin password). Notarised + stapled. |
| 🐧 Debian / Ubuntu / Mint / Pop!_OS (x64 + ARM64) | notepatra_0.1.129_amd64.deb | sudo apt install ./notepatra_0.1.129_amd64.deb — installs to /opt/notepatra/ + symlink at /usr/bin/notepatra, hicolor icons, .desktop registration. ARM64: replace amd64 → arm64. |
| 🐧 Fedora / RHEL / CentOS Stream / Rocky / Alma (x64 + ARM64) | notepatra-0.1.129-1.x86_64.rpm | sudo dnf install ./notepatra-0.1.129-1.x86_64.rpm — same layout as the .deb. ARM64: replace x86_64 → aarch64. Bundles QScintilla 2.14.1 alongside the binary because Fedora ships an incompatible packaging. |
| 🐧 Arch / openSUSE Tumbleweed / Manjaro / EndeavourOS / other glibc 2.38+ | Notepatra-0.1.129-x86_64.AppImage | chmod +x Notepatra-0.1.129-x86_64.AppImage && sudo cp Notepatra-0.1.129-x86_64.AppImage /opt/notepatra.AppImage && sudo ln -s /opt/notepatra.AppImage /usr/local/bin/notepatra. Requires glibc 2.38+ (Ubuntu 24.04+, Fedora 40+, Arch, Tumbleweed). Older distros: use the .deb / .rpm. |
All artefacts ship with cosign
.sig+.pemfor keyless Sigstore verification and SLSA build provenance. See Verify your download below.
notepatra-local-ai — cloud-free build for regulated environmentsFor teams that can't or won't send code to public LLM endpoints — regulated industries (finance, healthcare, legal, gov), data-sovereignty regions (EU GDPR, India RBI, China), air-gapped networks, or anyone who wants by-construction privacy — there's a dedicated cloud-free build, available for Linux and Windows:
| OS | Artefact | Silent admin install |
|---|---|---|
| 🪟 Windows | notepatra-local-ai-0.1.129.msi | msiexec /i notepatra-local-ai-0.1.129.msi /quiet — installs to C:\Program Files\Notepatra Local AI\, distinct UpgradeCode so SCCM treats it as its own product. Add/Remove Programs shows "Notepatra Local AI". |
| 🐧 Debian/Ubuntu x64 | notepatra-local-ai_0.1.129_amd64.deb | sudo apt install ./notepatra-local-ai_0.1.129_amd64.deb |
| 🐧 Debian/Ubuntu ARM64 | notepatra-local-ai_0.1.129_arm64.deb | sudo apt install ./notepatra-local-ai_0.1.129_arm64.deb |
The binary physically cannot reach api.openai.com, api.anthropic.com, openrouter.ai, api.mistral.ai, generativelanguage.googleapis.com, or any other public LLM endpoint. Every QNetworkAccessManager request goes through an allowlist that only accepts:
localhost / 127.0.0.1 / [::1]10.x, 172.16-31.x, 192.168.x)100.64.0.0/10 — covers Tailscale, corp VPN)fc00::/7).local, .lan, .internal, .intranet, .corp, .homeLocal Ollama, local llama.cpp, self-hosted Ollama on the LAN, and any other OpenAI-compatible server you have installed locally or on your private network — all continue to work in the cloud-free build. Only public-cloud LLM endpoints are blocked. The cloud-URL paste box is stripped from the UI as well, so users can't even type a public host. Auditors can confirm by running strings notepatra | grep -c openai.com — zero hits.
On Linux the two flavors share the same notepatra binary name on disk; apt Conflicts ensures only one of notepatra / notepatra-local-ai is installed at a time, swap transactionally with sudo apt install ./notepatra-local-ai_0.1.129_amd64.deb. On Windows the two MSIs are independent products (different UpgradeCode + ProductName + install dir) so they can coexist if needed; admins typically push one or the other based on policy. notepatra --version self-identifies the build by name — only the bare lite build carries an edition suffix: Notepatra Lite v0.1.129 for the lite build and Notepatra v0.1.129 for the full build (DuckDB bundled), plus Notepatra Local AI Lite v0.1.129 / Notepatra Local AI v0.1.129 for the cloud-free (local-ai) builds; the same name shows in the window title bar and the About dialog.
Every release ships with SHA-256 checksums, Sigstore (cosign) signatures, and SLSA build provenance. The install.sh and install.ps1 scripts above already verify SHA-256 automatically and refuse to install on mismatch — but if you downloaded manually you should verify yourself.
# Linux / macOS — checksum
curl -sL -O https://github.com/singhpratech/notepatra/releases/latest/download/SHA256SUMS
sha256sum -c SHA256SUMS --ignore-missing
# Anywhere — cosign verify (Sigstore)
# Replace `linux-x64` with `linux-arm64` if you downloaded the ARM64 build.
cosign verify-blob \
--certificate-identity-regexp '^https://github.com/singhpratech/notepatra/' \
--certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
--certificate notepatra-linux-x64.tar.gz.pem \
--signature notepatra-linux-x64.tar.gz.sig \
notepatra-linux-x64.tar.gz
# Anywhere — SLSA build provenance
# Replace `linux-x64` with `linux-arm64` if needed.
gh attestation verify notepatra-linux-x64.tar.gz --owner singhpratech
Full instructions, threat model, and disclosure policy in SECURITY.md.
Notepatra checks github.com/singhpratech/notepatra/releases/latest on launch (silent on no-match) and pops a "A new version is available" dialog when something newer exists. Click Download and the updater will:
.exe and portable .zip as fallbacks).~/Downloads/*.part with a cancellable progress dialog.SHA256SUMS and verify the download's hash. If the hash does not match, the .part file is deleted and you are shown an error — nothing on your system is modified..part → final name once verified.msiexec /i on Windows, open <dmg> on macOS (Finder drag to Applications), xdg-open on the Downloads folder on Linux so you replace the binary yourself.Safety contract — the updater will never leave you with a broken install:
| Failure | What happens |
|---|---|
| No internet | Error dialog, zero disk writes |
| Download cancelled | .part deleted, nothing else touched |
| Power / crash mid-download | .part orphan in ~/Downloads, current binary untouched |
| SHA-256 mismatch | .part deleted, critical dialog shown, current binary untouched |
No SHA256SUMS in release | Refuses to auto-install, opens release page for manual verify |
| No matching platform asset | Refuses to auto-install, opens release page |
| OS installer cancelled or fails | Installer's own rollback — current binary untouched |
The Notepatra process never rewrites or replaces the running binary. Only the OS installer you explicitly clicked through may do that, and those installers all have their own transactional rollback (MSI MajorUpgrade, DMG copy-on-drag, user-driven file-manager swap on Linux).
Check manually: Help → Check for Updates or ? menu. The check is also visible on first launch (silent if up to date).
If you upgraded from v0.1.23 or earlier and your right-click → Open with menu still shows Notepatra â€" native code editor (mojibaked text) and/or a red ❌ overlay on the icon, that's Windows shell-cache lag, not a Notepatra bug. Windows' MuiCache permanently caches the FileDescription string the first time it reads an executable's VERSIONINFO, and never re-reads it on upgrade. The new v0.1.24 binary embeds clean ASCII; Windows is just showing the cached old string.
One-time fix — open PowerShell (no admin needed, all changes are HKCU-scoped) and paste this whole block. Tested and confirmed working on Windows 11:
# 1. Wipe Notepatra's stale entries from MuiCache (the cache that has the â€" text)
$mui = "HKCU:\Software\Classes\Local Settings\Software\Microsoft\Windows\Shell\MuiCache"
Get-Item $mui | Select-Object -ExpandProperty Property | Where-Object { $_ -match "notepatra" } | ForEach-Object {
Remove-ItemProperty -Path $mui -Name $_ -Force
Write-Host "Cleared MuiCache: $_" -ForegroundColor Green
}
# 2. Wipe stale "Open with" associations pointing to old notepatra.exe paths
Remove-Item "HKCU:\Software\Classes\Applications\notepatra.exe" -Recurse -Force -ErrorAction SilentlyContinue
$exts = @(".txt",".log",".md",".json",".py",".cpp",".js",".html",".css",".xml",".sql",".sh",".yml",".yaml",".ini",".conf",".csv",".rs",".go",".java",".rb",".php",".c",".h",".hpp",".tsx",".ts",".jsx")
foreach ($ext in $exts) {
Remove-Item "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$ext\OpenWithList" -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\$ext\OpenWithProgids" -Recurse -Force -ErrorAction SilentlyContinue
}
Write-Host "Cleared OpenWithList for $($exts.Count) extensions" -ForegroundColor Green
# 3. Force shell to rebuild association cache
ie4uinit.exe -show
ie4uinit.exe -ClearIconCache
Write-Host "Rebuilt shell cache" -ForegroundColor Green
# 4. Restart Explorer (drops in-memory cache)
Stop-Process -Name explorer -Force
Start-Process explorer
Write-Host "Restarted Explorer — right-click any file now to verify" -ForegroundColor Cyan
What it does — line by line:
| Step | What & why |
|---|---|
| 1. MuiCache wipe | Clears the per-user cache where Windows stores FileDescription strings shown in "Open with" / File Properties → Details. This is the cache holding the â€" mojibake. |
| 2. Per-extension cache wipe | Removes OpenWithList + OpenWithProgids for 28 common file types. Forces Windows to re-query the .exe's actual VERSIONINFO next time the menu opens. |
3. ie4uinit.exe -show + -ClearIconCache | Built-in Windows tool that rebuilds shell association + icon caches. The red ❌ overlay disappears here. |
| 4. Restart Explorer | Drops the in-memory copy of the cache (the fourth and final layer). Without this, the menu can stay stale until you log out / reboot. |
Verify it worked: right-click any .txt or .json file → Open with → the Notepatra entry should now read Notepatra native code editor for the AI era with a clean icon. If you still see the old text after this, log out and back in (forces every kernel-side cache layer to flush).
New v0.1.24 installs on a clean machine never see this — it only affects upgrades from v0.1.23 or earlier where the mojibaked string was first cached.
sudo apt install cmake qtbase5-dev libqscintilla2-qt5-dev
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env
git clone https://github.com/singhpratech/notepatra.git
cd notepatra
cd rust-core && cargo build --release && cd ..
mkdir build && cd build && cmake .. && make -j$(nproc)
./notepatra
brew install qt@5 cmake
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env
git clone https://github.com/singhpratech/notepatra.git
cd notepatra
# Build QScintilla from source (brew's version links Qt6)
./build.sh
Prerequisites
msvc2019_64 — install via Qt Online Installer or aqtinstallwinget install Kitware.CMake or cmake.org/downloadBuild QScintilla via the CMake wrapper (once)
git clone --depth 1 https://github.com/farleyrunkel/QScintilla.git $env:TEMP\qsci-src
cmake -S $env:TEMP\qsci-src -B $env:TEMP\qsci-src\build -G "Visual Studio 17 2022" -A x64 `
-DCMAKE_BUILD_TYPE=Release `
"-DCMAKE_PREFIX_PATH=C:\Qt\5.15.2\msvc2019_64" `
"-DCMAKE_INSTALL_PREFIX=$env:TEMP\qsci-install"
cmake --build $env:TEMP\qsci-src\build --config Release
cmake --install $env:TEMP\qsci-src\build --config Release
Build Notepatra
git clone https://github.com/singhpratech/notepatra.git
cd notepatra
cd rust-core; cargo build --release; cd ..
mkdir build; cd build
cmake .. -G "Visual Studio 17 2022" -A x64 `
"-DCMAKE_PREFIX_PATH=C:\Qt\5.15.2\msvc2019_64" `
"-DQSCINTILLA_INCLUDE=$env:TEMP\qsci-install\include" `
"-DQSCINTILLA_LIB=$env:TEMP\qsci-install\lib\qscintilla2_qt5.lib"
cmake --build . --config Release
Bundle Qt + QScintilla DLLs next to the exe
mkdir notepatra-win
copy build\Release\notepatra.exe notepatra-win\
windeployqt notepatra-win\notepatra.exe
copy $env:TEMP\qsci-install\bin\qscintilla2_qt5.dll notepatra-win\
.\notepatra-win\notepatra.exe
If you hit
LNK2019 unresolved external symbol QsciScintilla::staticMetaObject— verifyCMakeLists.txtdefinesQSCINTILLA_DLLfor Windows targets. Without it, MSVC won't emit__declspec(dllimport)and the linker will fail to resolve symbols against the import library. This is the gotcha that took 12 CI iterations to find.
Drop a shared library in ~/.config/notepatra/plugins/ and restart.
.so files.dylib files.dll files// myplugin.cpp
extern "C" {
const char* notepatra_plugin_name() { return "My Plugin"; }
const char* notepatra_plugin_version() { return "1.0"; }
const char* notepatra_plugin_author() { return "Your Name"; }
char* notepatra_plugin_run(const char* text, int len) {
// Your magic here — transform text, return malloc'd result
// Return NULL to keep text unchanged
}
}
# Linux
g++ -shared -fPIC -o myplugin.so myplugin.cpp
# macOS
clang++ -shared -o myplugin.dylib myplugin.cpp
# Windows
cl /LD myplugin.cpp /Fe:myplugin.dll
| Editor | Download size | Native | Local AI | Built-in JSON fixer | 2 GB files | Linux | Win | Mac | Free |
|---|---|---|---|---|---|---|---|---|---|
| Notepad++ | ~4 MB | ✓ | ✗ | plugin only | ✗ | ✗ | ✓ | ✗ | ✓ |
| VS Code | ~300 MB | ✗ Electron | extension | extension | ✗ | ✓ | ✓ | ✓ | ✓ |
| Vim / Neovim | ~3 MB | ✓ | ✗ | ✗ | ✓ | ✓ | ✓ | ✓ | ✓ |
| Sublime Text | ~30 MB | ✓ | ✗ | ✗ | ✓ | ✓ | ✓ | ✓ | $99 |
| Kate / Gedit | ~30 MB | ✓ | ✗ | ✗ | ✓ | ✓ | ✗ | ✗ | ✓ |
| Notepatra | 4.1 / 27.5 / 43.9 MB | ✓ C++/Rust | ✓ Ollama | ✓ regex + AI | ✓ Rust mmap | ✓ | ✓ | ✓ | ✓ GPL-3 |
Notepatra download sizes are Linux x64 tar.gz / macOS DMG / Windows MSI from v0.1.120. Linux is just the binary (Qt is system-installed). macOS and Windows include bundled Qt. The bare
notepatraexecutable inside is ~13 MB on every platform (Linux 13.4 MB, similar on macOS / Windows). Compressed download is much smaller because tar.gz / DMG / MSI all compress the binary plus shared libraries.
Focused automated regression tests are wired through CMake + CTest and run in CI — 79 test suites on the Full build (76 on Lite, which omits the two DuckDB suites and the WebEngine-gated Noter-export suite); all green, each with many assertions. A representative sample:
test_lexers — verifies every shipped QScintilla lexer produces real stylingtest_palette — verifies the canonical 9-hue palette colors and bold/italic stylestest_fmtpanel_diff — verifies formatter panels keep diff state and emit signalstest_compare_widget — verifies the inbuilt Compare panel diff/edit/close pathstest_sqlfmt — 33 assertions across 11 SQL dialects through the AST pretty-printertest_updater — verifies pickAssetForPlatform, SHA256 parsing, and asset scoring (18 assertions)test_projectsearch — verifies the Rust-backed project search streaming pathtest_projectsearch_ui — verifies the Project Search UI bindingstest_ollama — verifies live Ollama model detection (skips cleanly when offline)test_aifix — exercises the AI-fix cleanup path against a real Ollama daemon (skips cleanly when offline)test_llamacpp — exercises the llama.cpp backend pathtest_ai_context — verifies the AI workspace-context summarizerRun them locally with:
./build.sh --tests
The Ollama / llama.cpp / AI-fix tests skip cleanly when no inference backend is running, so local and CI runs stay deterministic.
Notepatra follows Keep a Changelog and Semantic Versioning. Every release is tagged, signed, and published to GitHub Releases with binaries for Linux x64, Linux ARM64, macOS Apple Silicon, and Windows x64.
| Version | Date | Highlights |
|---|---|---|
| v0.1.129 | 2026-08-22 | SSH keys behind a rail, and diagrams that look drawn by an engineer. The Password Generator's two radio buttons become a left rail — Password / Passphrase / SSH key (Alt+1 / Alt+2 / Alt+3), and Tools > Password Generator — Passwords / Passphrases / SSH keys. The new SSH key page generates a real OpenSSH pair: Ed25519 (recommended), ECDSA P-256 / P-384, RSA 3072 / 4096, RSA 2048 (legacy); an optional passphrase encrypts the private key with aes256-ctr + bcrypt-pbkdf, the same construction ssh-keygen uses. The comment field is empty by default on purpose — ssh-keygen defaults it to user@host, which copies your username and machine name into every authorized_keys the key is pasted into. The public line and its SHA256 fingerprint show immediately; the private key stays hidden until Show private key; Save private key… creates the file, sets 0600, then writes, refuses to overwrite, and drops the .pub beside it. Generation runs off the GUI thread (RSA-4096 measured 1.6–5.9 s) and the 30-second clipboard wipe arms for the private key only. Keys come from the OS random source (getrandom) via the Rust core — and every password draw now uses that source too, with Qt's generator demoted to a fallback. Interop is asserted against the system ssh-keygen (-y, -lf, -y -P). Binary grows ~0.6 MB for the pure-Rust crypto (RustCrypto ssh-key). Diagrams (.npd) are now flat — no gradients, no shadows, 1.5 px borders, the app font — with two light palettes (paper, slate) and a new default palette auto that follows the app theme, so an existing file with no palette line now renders light on a light theme. New grammar: `direction LR |
| v0.1.128 | 2026-08-20 | A password generator whose entropy figure is a count, not a compliment. New built-in Password Generator — the Password button on the Built-in Tools toolbar (third, right after AI), or Tools > Password Generator — Random / Passphrase — producing either random characters (4–256, default 20; a-z / A-Z / 0-9 / a 27-character symbol set that omits the quotes, backslash, backtick, pipe and space so the result survives a shell command, a YAML file or a connection string; free-text extra characters; optional look-alike exclusion) or a passphrase (3–24 words from a 2,048-word list compiled into the binary, so each word is worth exactly 11 bits and six words is 66 bits), 1 to 100 at a time. The bits readout is the base-2 logarithm of how many values the current settings can produce — not a heuristic score of how complicated the output looks — so ticking at least one from each set makes the number drop, recomputed by inclusion–exclusion because the guarantee rules out every password that misses a set; most generators advertise the unconstrained figure while enforcing the constraint. Draws use QRandomGenerator::system() (the OS CSPRNG) with rejection sampling, and the set guarantee is met by re-drawing rather than placing-and-shuffling, which would skew the distribution and make the bits figure a lie. The panel is a plain widget, not an editor, so a generated value never reaches session.json, an AI backend, or a connected MCP client · Copy takes the value back off the clipboard after 30 seconds, but only if it still holds it · nothing is written to disk. Ships in every build including Lite, no new dependency, fully offline · two new suites (test_passwordgen, test_passwordgen_panel) take the Full build to 78/78 ctest green. No MCP verbs, lexers or file extensions changed. |
| v0.1.127 | 2026-08-07 | Five doors refused a private key. The sixth handed it over in chunks. Retesting v0.1.126 found select_range + get_selection returning credential-file contents that open_file, read_tab, find_in_tab, search_project and resources/read all correctly refused — get_selection had been exempted on the reasoning that a selection is human-made, but select_range lets the client choose the range, which makes that reasoning false. apply_edit was a quieter form of the same thing: reading the buffer as a match oracle, so "no match" versus a card naming the match reports a file's contents one probe at a time. The fix is structural. This is the third release with the same shape — v0.1.125 unified two hand-maintained copies of the deny list, v0.1.126 added the check to four verbs, and the retest found a fifth and sixth. Every fix was correct and none converged, because what kept going stale was the enumeration. Buffer text now leaves the editor through exactly one accessor that refuses before returning, select_range will not even stage a selection over a credential file, and a test lints the bridge source and fails the build on any direct buffer read that bypasses it. Also fixed: read_tab's marker claimed [truncated at 5 MB] whatever cap actually applied (now [truncated: showing N of M characters], and the v0.1.126 claim that it "always reports truncated and total_chars" is corrected — true of the wire, not the tool result) · select_range advertised tab_id in its schema and rejected it with -32602, so a test now walks the whole tool list asserting every advertised selector is accepted · list_open_tabs emitted id where verbs take tab_id, both ship for one release. |
| v0.1.126 | 2026-08-07 | v0.1.125 taught search_project to skip credential files — it never told open_file or read_tab, so an agent that asked for ~/.ssh/id_rsa by name still got the whole key back. A deep retest confirmed all four v0.1.125 Windows fixes on real hardware and found nine more defects underneath. open_file, read_tab, find_in_tab and both legs of search_project now check the same deny-list — v0.1.125 had guarded only the filesystem walk, so the same file sitting in an open tab was read straight out of the buffer. format_json invented data and reported success: it called the JSON panel's auto-fixer, so [1,2 came back as [1,2] with isError:false — a truncated config file made syntactically valid and semantically invented. The MCP path validates strictly now; the panel keeps its fixer. Fixed: a search with zero matches was reported as "No workspace folder is open", which is a different fact about the world · workspace_searched/scope were sent by the bridge and dropped by the Rust struct, so no client ever saw the fields v0.1.125 promised · without --socket every response was fabricated with no marker, so a dropped flag produced an assistant describing three files that do not exist · find_in_tab rejected a title that read_tab accepted · an invalid pagination cursor was ignored and the full list returned. Changed: tabs now have a stable id — tab_index is positional and re-points at a different document when a tab closes, and out-of-range was the lucky case · read_tab takes max_bytes and always reports truncated and total_chars. |
| v0.1.125 | 2026-08-07 | A one-word MCP search could return the contents of your SSH private key — fixed, along with three other defects found by testing the MCP server on Windows. No new editor features; every change is a fix. The credential deny-list existed in two hand-maintained copies that had drifted in both directions (ai_tools.cpp had *.tfvars/*.tfstate/.pypirc/the .env family; git_hunk_apply.cpp had *.jks and an unanchored id_rsa; neither was a superset) and search_project consulted neither — so read_file refused ~/.ssh/id_rsa while a one-word search returned its lines. src/path_denylist.h is now the single list, built as the union, with all three callers routed through it. search_project also walked the entire home directory: FileExplorer's constructor set m_rootPath = QDir::homePath() as a display placeholder, and four guards read it as "the workspace" — including the AI CSV sandbox and a security guard that had therefore never once closed. workspaceRoot() now stays empty until a folder is opened, and a workspace-less search reports workspace_searched and scope so a partial search cannot pass for a complete one. Fixed: goto_line past EOF reported {"line": 99999, "ok": true} from the top of the document, so an assistant aiming at the end of a file wrote at the beginning behind a correct-looking approval card · insert_text with col but no line silently dropped col and wrote at the cursor · the sidecar hung on every unrecognised argument (--version printed nothing and blocked on stdin; --sokcet silently started the mock server so the client received fabricated tabs) · the AI workspace root flapped on every Ctrl+Tab, swapping chat history and cancelling pending write approvals · Windows binaries reported version 0.1.0 to winget, SCCM, Intune and File Properties for 124 releases — the .rc is generated from CMake now, with a CI step reading VersionInfo back off the shipped .exe. Every new test red-state verified by restoring the pre-fix code, not by negating a condition. |
| v0.1.124 | 2026-07-28 | Invisible characters are now visible — 527 of them, where Notepad++ draws 113 — and two Find/Replace bugs that were destroying text are fixed. A file containing a zero-width space used to look exactly like a file without one: symbol support was only whitespace dots and EOL markers, so every zero-width, bidirectional and exotic-space codepoint was undrawable. View → Show Symbol is rebuilt to Notepad++'s eight-item structure in its order (Show Space and Tab · Show End of Line · Show Non-Printing Characters · Show Control Characters & Unicode EOL · Show Every Other Invisible Character · Show All Characters · Show Indent Guide · Show Wrap Symbol). The non-printing (49) and control/Unicode-EOL (64) tables are transcribed from Notepad++'s source byte-for-byte, abbreviations included (ZWNBSP for U+FEFF, OSPM for U+1680, SGCI for U+0099). "Show Every Other Invisible Character" adds the 414 codepoints Notepad++'s fixed tables miss — variation selectors, the TAG block U+E0020–E007F, the Hangul fillers, the combining grapheme joiner. Blobs can show codepoints (U+200B) instead of abbreviations, and every Show Symbol setting now persists across restarts and applies to all tabs. Defaults match Notepad++ — everything off except the control-character display, so non-printing characters are off out of the box. Fixed: Replace All silently deleted any replacement containing $ (handed to the regex engine as a substitution template, so $100 parsed as capture group 100 and expanded to nothing) · Replace reported replacements it had not made and overwrote unrelated selections · Find in Files' default *.* filter skipped extensionless files like Makefile and .gitignore · Mark All highlighted the wrong spans (offsets computed into a lowercased copy, and lowercasing is not length-preserving in UTF-8) · indent guides rendered as a white-on-black barber pole in Dark and Monokai. Three new suites (75 total Full), each red-state verified. |
| v0.1.123 | 2026-07-23 | The "Save As" dialog is now the native OS file dialog — the Windows Explorer tree everyone knows. Save As was the only dialog still forced to Qt's own plain "Look in:" list (no folder tree); it now uses the native Windows / macOS / Linux dialog, matching Open, Open Folder, and Save a Copy As, which were already native. The 72-language file-type dropdown is preserved and extensions stay correct (bare name on a Python tab → .py; a typed extension is always honoured). It went non-native back in v0.1.88.1 because native dialogs dropped the "which type did you pick" signal and could save the wrong extension — now sidestepped by driving the default extension from the current tab's language instead of the dialog filter. Verified in the running app. |
| v0.1.122 | 2026-07-23 | Save & Open dialogs remember your last folder — on every platform. Saving a brand-new file, "Save a Copy As", "Open", and "Open Folder as Workspace" previously reopened at your home folder every time; they now start in the directory you last used and persist it across restarts. "Save As" still prefers the current file's own folder when it has one — the remembered directory is only the fallback for untitled buffers and secondary dialogs, so nothing regresses. Self-healing: a remembered folder that was deleted or lived on an unplugged removable drive falls |