{
  "markdown": "<p align=\"center\">\n  <a href=\"https://notepatra.org\"><img src=\"resources/notepatra-256.png\" alt=\"Notepatra — click for notepatra.org\" width=\"128\" height=\"128\"></a>\n  <h1 align=\"center\"><a href=\"https://notepatra.org\" style=\"text-decoration:none;color:inherit;\">Notepatra</a></h1>\n  <p align=\"center\"><em>The first code editor built for the AI era.</em></p>\n  <p align=\"center\">\n    <strong>C++ + Rust</strong> · <strong>~13 MB bare native executable</strong> · <strong>Zero Electron</strong> · <strong>238 file types</strong> · <strong>82 language lexers</strong> · <strong>Local AI formatters</strong> · <strong>MCP server</strong>\n  </p>\n  <p align=\"center\">\n    <strong>MCP:</strong> <a href=\"https://notepatra.org/mcp.html\"><code>notepatra-mcp</code></a> 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.\n  </p>\n  <p align=\"center\">\n    <a href=\"https://notepatra.org\">Website</a> ·\n    <a href=\"https://github.com/singhpratech/notepatra/releases/latest\">Download</a> ·\n    <a href=\"#ai-assistants-mcp--new-in-v01118\">MCP</a> ·\n    <a href=\"#features\">Features</a> ·\n    <a href=\"#the-story\">The Story</a> ·\n    <a href=\"#install\">Install</a> ·\n    <a href=\"#plugins\">Plugins</a> ·\n    <a href=\"#ai-powered\">AI</a> ·\n    <a href=\"CONTRIBUTING.md\">Contributing</a> ·\n    <a href=\"SECURITY.md\">Security</a> ·\n    <a href=\"CHANGELOG.md\">Changelog</a>\n  </p>\n  <p align=\"center\">\n    <a href=\"https://github.com/singhpratech/notepatra/actions/workflows/build.yml\"><img src=\"https://github.com/singhpratech/notepatra/actions/workflows/build.yml/badge.svg\" alt=\"Build\"></a>\n    <a href=\"https://github.com/singhpratech/notepatra/actions/workflows/codeql.yml\"><img src=\"https://github.com/singhpratech/notepatra/actions/workflows/codeql.yml/badge.svg\" alt=\"CodeQL\"></a>\n    <a href=\"https://github.com/singhpratech/notepatra/releases/latest\"><img src=\"https://img.shields.io/github/v/release/singhpratech/notepatra?color=39FF14&label=release\" alt=\"Release\"></a>\n    <a href=\"https://github.com/singhpratech/notepatra/blob/main/LICENSE\"><img src=\"https://img.shields.io/badge/license-GPL--3.0-blue\" alt=\"License\"></a>\n    <a href=\"SECURITY.md\"><img src=\"https://img.shields.io/badge/security-disclosure%20policy-39FF14\" alt=\"Security\"></a>\n  </p>\n  <p align=\"center\">\n    <a href=\"https://github.com/singhpratech/notepatra/releases\"><img src=\"https://img.shields.io/github/downloads/singhpratech/notepatra/total?color=39FF14&label=total%20downloads\" alt=\"Total downloads\"></a>\n    <a href=\"https://github.com/singhpratech/notepatra/stargazers\"><img src=\"https://img.shields.io/github/stars/singhpratech/notepatra?style=flat&color=39FF14\" alt=\"GitHub stars\"></a>\n    <a href=\"https://github.com/singhpratech/notepatra/network/members\"><img src=\"https://img.shields.io/github/forks/singhpratech/notepatra?style=flat\" alt=\"Forks\"></a>\n    <a href=\"https://github.com/singhpratech/notepatra/issues\"><img src=\"https://img.shields.io/github/issues/singhpratech/notepatra?color=blue\" alt=\"Open issues\"></a>\n    <a href=\"https://github.com/singhpratech/notepatra/commits/main\"><img src=\"https://img.shields.io/github/last-commit/singhpratech/notepatra\" alt=\"Last commit\"></a>\n  </p>\n</p>\n\n---\n\n## The Story\n\nI'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.\n\nEvery 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.\n\nSo I built Notepatra.\n\nNot a port. Not a wrapper. Something new — **for everyone**.\n\nI 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?**\n\nThe 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.\n\nNotepatra 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.\n\n**Notepatra is what I wish had existed — on every platform.**\n\n---\n\n## Features\n\n### Editor — Battle-tested basics done right\n- **238 file extensions** mapped to **82 language lexers** — Python, C/C++, C#, Java, Kotlin, JavaScript, TypeScript, Rust, Go, Swift, Dart, Solidity, Zig, Vala, Hack, Julia, R, Protobuf, F#, HCL/Terraform, Thrift, GraphQL, GDScript, Nim, Cython, Mojo, Crystal, Elixir, Scala, Groovy, Apex, SQL (6 dialect presets), HTML, CSS, JSON, JSON5, YAML, TOML, Markdown, Bash, Fish, Nushell, Fortran, VHDL, Verilog, MATLAB, LaTeX, BibTeX, Jinja, Liquid, Twig, Dockerfile, DotEnv, Gitignore, and more. Rust / Go / Swift / Kotlin / TypeScript / PowerShell ship as Notepatra-local lexers (not just C-family fallbacks)\n- **Tabbed editing** — drag, reorder, middle-click close, double-click empty area for new tab\n- **Tab right-click menu** — Close, Close All BUT This, Close All to the Left/Right, Close All, Save, Save As, Rename, Copy Full Path, Copy Filename, Copy Directory Path, Open Containing Folder, Open Terminal Here, Read-Only toggle, **Color Tag** (7 named colors + custom + Remove)\n- **3 themes** — Light, Dark, Monokai (Settings > Theme)\n- **Session persistence** — close Notepatra, reopen tomorrow, same files, same cursor positions, same window size\n- **Crash recovery** — if Notepatra crashes (it shouldn't, but life happens), your unsaved work is recovered on next launch\n- **File change detection** — someone else edits your file? Notepatra asks: reload or keep yours?\n- **2 GB file support** — memory-mapped I/O via Rust; files up to ~1.86 GB load fully, larger open truncated + read-only\n- **Double-click word highlight** — double-click any word, all occurrences light up in orange\n- **Ctrl+B brace matching** — jump between matching `{}` `[]` `()`, highlights both braces + selects everything between\n- **Macro recording** — Start Recording (Ctrl+Shift+M), Stop, Playback (Ctrl+Shift+P), Run Multiple Times, Save/Load macros\n- **Code folding**, **bookmarks**, **auto-complete**, **indent guides**, **line numbers**\n- **Custom scrollbars** — clean, modern, rounded\n\n### Search — Find anything, anywhere\n- **Project Search (`Ctrl+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- **5-tab Find/Replace dialog** — Find, Replace, Find in Files, Mark, Go to\n- **3 search modes** — Normal, Extended (`\\n`, `\\r`, `\\t`, `\\xNN`), Regular expression\n- **Find All in Current Document** — results appear in bottom panel, double-click any result to jump to that exact line\n- **Find All in All Opened Documents** — search across every open tab at once\n- **Replace All in All Opened Documents** — one click, every file updated\n- **Find in Files** — search entire directories recursively with file filters\n- **Mark All** — highlight every occurrence with visual indicators\n- **Aho-Corasick search engine** (Rust) — faster than regex for literal patterns\n\n### Plugins — The real power\n\nEvery plugin opens in its own tab. Real UI, not just a menu click.\n\n#### JSON Tools (inbuilt)\n| Button | What it does |\n|---|---|\n| **Format** | Pretty-print with preserved key order |\n| **Minify** | Compact to one line |\n| **Fix + Format** | Rust-powered auto-repair: fixes missing braces, trailing commas, single quotes, unquoted keys, missing `{` after `[` — shows detailed report of every fix |\n| **AI Fix (Ollama)** | Sends truly broken JSON to your local AI — fixes what regex can't |\n\n#### HTML Tools (inbuilt)\n| Button | What it does |\n|---|---|\n| **Format (2/4 spaces)** | Proper HTML indentation |\n| **Minify** | Strip all whitespace |\n| **Fix + Format** | Auto-close unclosed tags, detect missing closers, report issues |\n| **AI Fix (Ollama)** | AI repairs broken nesting, malformed tags, missing attributes |\n\n#### Bracket Tools (inbuilt)\n| Button | What it does |\n|---|---|\n| **Check** | Detailed report: line numbers of every mismatched `()` `[]` `{}`, keyword mismatches (`begin`/`end`, `if`/`fi`) |\n| **Auto-Fix** | Adds missing closers in correct nesting order |\n| **AI Fix (Ollama)** | AI understands your code structure and fixes all bracket issues |\n\n#### SQL Formatter (inbuilt)\n- Format with **UPPERCASE** or **lowercase** keywords\n- Configurable indent width\n- Supports T-SQL, PL/SQL, MySQL, PostgreSQL, SQLite\n\n#### Compare / Diff (inbuilt)\n- Pick **any two tabs** or **any tab vs file on disk**\n- Side-by-side **Scintilla editors** with a ComparePlus-style **overview/nav bar**\n- `+` green for added, `-` red for deleted, `#` amber for changed\n- **Word-level LCS intra-line diff** — within a changed line, the specific\n  *tokens* that were removed are highlighted in red on the left pane; the\n  tokens that were added are highlighted in green on the right pane. Works\n  on actual word boundaries, not just common-prefix/suffix.\n- **Dark-mode aware** — colours track your Notepatra theme (Light / Dark /\n  Monokai) so diffs stay readable on both black and white backgrounds.\n- **Prev/Next diff** navigation, inline overview-bar jump\n- **Ignore whitespace**, **ignore case**, **ignore empty lines** checkboxes\n- **Unlock for editing** mode — edit either pane and re-diff in place\n- Powered by Rust Myers diff (line-level) + C++ LCS (word-level)\n- **Visual UX inspired by [ComparePlus](https://github.com/pnedev/comparePlus) by Pavel Nedev** — credit where credit is due.\n\n#### Git Integration (inbuilt)\n- **Staged / Unstaged trees** — porcelain v2 parser, inline `+` / `−` buttons per row to stage/unstage\n- **Branch chip with ahead/behind** — shows `main ↑3 ↓1` when diverged\n- **Commit box (Ctrl+Enter)** — line-count indicator, blocks commit when nothing's staged\n- **Sync row** — one-click Pull / Push / Fetch with live ahead/behind refresh\n- **Collapsible history + stash menu** — recent commits expandable; stash / pop / list / drop\n- **Git gutter** — green/yellow/red markers in editor margin for changed lines\n\n### AI Powered — local-first, cloud-optional\n\nBackend 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.\n\n#### AI Assistant — side-dock (`Ctrl+Shift+A`)\nThe 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.\n\n**Workspace awareness.** Every prompt carries:\n- the selection (or full file if no selection is active)\n- the full text of the current file\n- excerpts of every other open editor tab\n- a flat listing of all files under the workspace root (`.git`, `node_modules`, `target`, `dist`, etc. filtered out)\n\nSo 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.\n\n**One-click actions** (hidden by default, click \"▸ Quick actions\" to reveal):\nExplain · 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.\n\n**Speech-to-text** — optional mic button, uses local `arecord` + `whisper` CLI when installed. No audio ever leaves the machine.\n\n#### AI Setup\n```bash\n# Easiest path: Ollama\ncurl -fsSL https://ollama.com/install.sh | sh\nollama pull qwen2.5-coder:3b   # 2 GB, best for code on CPU-only / 16 GB RAM\nollama serve\n```\nNotepatra 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.\n\n#### 🔐 Password Generator — passwords, passphrases and SSH keys, with an honest entropy figure (`Tools > Password Generator — Passwords / Passphrases / SSH keys`)\n\nA 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.\n- **Password** — random characters, 4–256 (default 20) from a-z / A-Z / 0-9 / a 27-character symbol set, plus a free-text field for any extra characters you want, with optional *exclude look-alikes* (drops `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.\n- **Passphrase** — 3–24 words (default 6) from a **2,048-word list compiled into the binary** (no dictionary file is read at runtime), so each word is worth exactly **11 bits** and six words is 66 bits; pick a hyphen / period / underscore / space / no separator, optionally capitalise each word or append two digits. Both text modes generate **1 to 100** independent values at once, with Generate · Copy · Insert into editor · Open in new tab.\n- **SSH key** — a real OpenSSH key pair, generated locally: **Ed25519** (recommended), **ECDSA P-256 / P-384**, **RSA 3072 / 4096**, and **RSA 2048** marked *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` 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.\n- **The bits number is a count, not a score** — it is the base-2 logarithm of how many distinct values your current settings can produce, not a heuristic guess at how complicated the output *looks*, which is what most meters show. Tick *at least one from each set* and the figure **drops slightly**: it is recomputed by inclusion–exclusion over the selected sets, because the guarantee rules out every password that misses a set, so fewer passwords exist. Most generators advertise the unconstrained number while enforcing the constraint, which overstates the result. Default settings read **129 bits**.\n- **Real randomness, and nothing kept** — every draw comes from the **OS random source** (`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…**.\n\n#### 👁 AI Interaction Log — see exactly what your AI did (`Features → AI Interaction Log…`)\n\n**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.*\n\n#### 📝 Noter — meeting notes that turn into reminders (`Ctrl+Alt+N`)\n\nA local-first, two-pane meeting workspace (notes list · editor) — no accounts, no bots; notes live under `~/Documents/Notepatra/Noter/`.\n- **Write fast** — a top toolbar drops in *Action Items / What I plan / To-dos* headers and checkbox bullets; check a line to strike it through.\n- **Extract** (`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.\n- **Reminders** — set one on a note (right-click) or schedule action items straight from Extract; they all collect in a central **Reminders** list grouped *Overdue / Today / This week / Later*, with desktop notifications at the due time while Notepatra is running (missed ones arrive as one summary at next launch). Click to open the note, pencil to reschedule, ✕ to delete. Re-running Extract flags what's already scheduled so you never pile up duplicates.\n\n#### 📐 Diagram tool — flow / ER / system diagrams from text (`.npd`)\n\nA 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).\n- **Create three ways** — **AI Generate** describes it in plain English and a local model writes the `.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`.\n- **Why not just Mermaid?** — Mermaid needs a browser or JS runtime; `.npd` renders natively, offline, in the Lite binary, with AI Generate, node-pinned `note`s, `legend`s, 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](https://notepatra.org/docs.html#diagram-vs-mermaid).\n- **Drawn flat, like an engineering diagram** — no gradients, no drop shadows: a 1.5 px border, the app's own font, and a tighter grid. Two **light** palettes ship — `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`.\n- **Rich visuals** — 5 shapes (pill / box / decision diamond / database cylinder / icon), ~55 hand-drawn icons (~150 aliases) for system / ER / flowchart, directed + labelled + bidirectional arrows, **dashed edges** (`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.\n- **Say what a picture can't** — `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.\n- **Export** — **PNG / JPEG / PDF** on every build, plus **SVG / HTML** where the Qt Svg module is present and **WebP** where the Qt WebP image plugin is present (the menu shows exactly what your build supports). A **Help** button has the full cheat-sheet; `samples/diagram_showcase.npd` shows every element; the `npd_render` CLI renders any `.npd` to an image headless.\n\n### More Features\n\n| Feature | Shortcut |\n|---|---|\n| **Built-in Terminal** | `Ctrl+`` — opens as a tab, runs real commands |\n| **REST Client** | `Ctrl+Shift+R` — send HTTP requests, see responses with pretty JSON |\n| **Hex Editor** | View > Hex Editor — color-coded hex dump of any binary file |\n| **Markdown Converter** | Features > Markdown — convert selection to table, list, code block, bold, link, heading, or strip HTML to markdown |\n| **File Explorer** | `Ctrl+Shift+E` — tree view sidebar |\n| **Function List** | View > Function List — lists all functions/classes, double-click to navigate |\n| **Preferences** | Settings > Preferences — 6 tabs of configuration |\n| **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 |\n\n### Keyboard Shortcuts\n\n| Category | Shortcut | Action |\n|---|---|---|\n| **File** | `Ctrl+N` | New |\n| | `Ctrl+O` | Open |\n| | `Ctrl+S` | Save |\n| | `Ctrl+W` | Close tab |\n| **Edit** | `Ctrl+D` | Duplicate line |\n| | `Ctrl+Shift+K` | Delete line |\n| | `Ctrl+/` | Toggle comment |\n| | `Ctrl+Shift+U` | UPPERCASE |\n| | `Ctrl+U` | lowercase |\n| **Search** | `Ctrl+F` | Find |\n| | `Ctrl+H` | Replace |\n| | `Ctrl+Shift+G` | Project Search (folder-wide names + contents) |\n| | `F3` / `Shift+F3` | Find Next / Previous |\n| | `Ctrl+G` | Go to line |\n| | `Ctrl+B` | Go to matching brace |\n| | `Ctrl+F2` / `F2` | Toggle / Next bookmark |\n| **View** | `F11` | Full screen |\n| | `Ctrl+=` / `Ctrl+-` | Zoom in / out |\n| | `Alt+0` | Fold all |\n| **Macro** | `Ctrl+Shift+M` | Start recording |\n| | `Ctrl+Shift+T` | Stop recording |\n| | `Ctrl+Shift+P` | Playback |\n| **Features** | `Ctrl+`` | Terminal |\n| | `Ctrl+Shift+A` | AI Assistant |\n| | `Ctrl+Shift+E` | File Explorer |\n| **Tabs** | `Ctrl+Tab` | Next tab |\n| | Middle-click | Close tab |\n| | Double-click empty | New tab |\n\n### AI assistants (MCP) — new in v0.1.118\n\nFrom v0.1.118, Notepatra ships **`notepatra-mcp`** — a stdio JSON-RPC 2.0 [Model Context Protocol](https://modelcontextprotocol.io) 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.\n\n**49 tools in three tiers**:\n\n| Tier | Tools | Gate |\n|---|---|---|\n| **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 |\n| **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 |\n| **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 |\n\n`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.\n\nHook it up in one line each (from v0.1.118):\n\n```sh\n# Claude Code (Anthropic)\nclaude mcp add notepatra -- notepatra-mcp --socket\n```\n\n```toml\n# Codex CLI (OpenAI) — ~/.codex/config.toml\n[mcp_servers.notepatra]\ncommand = \"notepatra-mcp\"\nargs = [\"--socket\"]\n```\n\nFull 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](docs/mcp.html) / [notepatra.org/mcp.html](https://notepatra.org/mcp.html).\n\n---\n\n## Architecture\n\n```\n┌──────────────────────────────────────────────┐\n│            C++ Layer (Qt5 + QScintilla)       │\n│   UI · Menus · Tabs · Dialogs · Editor       │\n│   Terminal · AI Panel · Compare · Plugins     │\n├──────────────────────────────────────────────┤\n│                C FFI boundary                 │\n├──────────────────────────────────────────────┤\n│            Rust Core Library                  │\n│   File I/O (mmap) · Search (Aho-Corasick)    │\n│   Diff (Myers) · JSON/HTML/SQL Formatters    │\n│   Bracket Fixer · Hash · Base64 · Encoding   │\n└──────────────────────────────────────────────┘\n```\n\n**Why this hybrid?**\n- **C++** because Qt and QScintilla are C++ — zero friction for UI\n- **Rust** because file I/O, text processing, and parsing must never crash — Rust's ownership system guarantees memory safety\n- **Result**: the speed of C++, the safety of Rust. The bare executable is **~13 MB** on every platform (~13.4 MB Linux x64, similar on macOS / Windows). Latest v0.1.129 download sizes: **4.7 MB** Linux x64 tar.gz · **4.4 MB** Linux ARM64 tar.gz · **28.0 MB** macOS DMG (with bundled Qt) · **43.9 MB** Windows MSI · **33.0 MB** Windows NSIS · **37.8 MB** Windows portable zip. _Installed footprint on Windows is ~75-85 MB after the MSI extracts bundled Qt + QScintilla DLLs — normal for any Qt-based installer._\n\n---\n\n## Install\n\n### One-command install\n\n**Linux / macOS:**\n```bash\ncurl -fsSL https://notepatra.org/install.sh | sh\n```\n\n**Windows (PowerShell):**\n```powershell\nirm https://notepatra.org/install.ps1 | iex\n```\n\nThat's it. Auto-detects your OS, downloads the right binary, installs it, adds to PATH, creates shortcuts.\n\n### Or download manually — [Latest release: v0.1.129](https://github.com/singhpratech/notepatra/releases/latest)\n\n| Platform | Download | Size | What's inside |\n|---|---|---|---|\n| 🐧 **Linux x64** | [`.tar.gz`](https://github.com/singhpratech/notepatra/releases/latest) | **4.7 MB** | Bare `notepatra` binary. Qt5 from your distro. |\n| 🐧 **Linux ARM64** | [`.tar.gz`](https://github.com/singhpratech/notepatra/releases/latest) | **4.4 MB** | Bare `notepatra` binary for `aarch64` / ARM64 Linux. |\n| 🍎 **macOS Apple Silicon** (M1–M4) | [`.dmg`](https://github.com/singhpratech/notepatra/releases/latest) | **28.0 MB** | `Notepatra.app` with Qt frameworks bundled. Drag to Applications. |\n| 🪟 **Windows x64 (MSI)** | [`.msi`](https://github.com/singhpratech/notepatra/releases/latest) | **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. |\n| 🪟 **Windows x64 (installer)** | [`.exe`](https://github.com/singhpratech/notepatra/releases/latest) | **33.0 MB** | NSIS installer. Registers in Settings → Apps → Installed apps. Uninstall via Control Panel works. |\n| 🪟 **Windows x64 (portable)** | [`.zip`](https://github.com/singhpratech/notepatra/releases/latest) | **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`. |\n\n> ⚠ **Download size vs. installed size are different.** The numbers above are **download sizes** — the `.msi` / `.dmg` / `.tar.gz` files 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 after `xattr` removal.\n\n> **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 (the `generate_chart` tool). **macOS Full is DuckDB-only**: Homebrew `qt@5` no 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 `.npd` diagram tool work on **every** platform in **both** flavors.\n\n**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.\n\n> macOS Intel: not shipped pre-built. Apple stopped selling Intel Macs in 2023 and the GitHub Actions `macos-13` runner has been unreliable. Intel Mac users — `git clone` and run `./build.sh`. Builds in ~3 minutes.\n\n### Admin / Fleet install — for IT, DevOps, and regulated teams\n\nFor 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:\n\n| OS | Artefact | Silent admin install |\n|---|---|---|\n| 🪟 **Windows** | [`notepatra-x.x.x.msi`](https://github.com/singhpratech/notepatra/releases/latest) | `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. |\n| 🍎 **macOS** | [`Notepatra.dmg`](https://github.com/singhpratech/notepatra/releases/latest) | 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. |\n| 🐧 **Debian / Ubuntu / Mint / Pop!_OS** (x64 + ARM64) | [`notepatra_0.1.129_amd64.deb`](https://github.com/singhpratech/notepatra/releases/latest) | `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`. |\n| 🐧 **Fedora / RHEL / CentOS Stream / Rocky / Alma** (x64 + ARM64) | [`notepatra-0.1.129-1.x86_64.rpm`](https://github.com/singhpratech/notepatra/releases/latest) | `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. |\n| 🐧 **Arch / openSUSE Tumbleweed / Manjaro / EndeavourOS / other glibc 2.38+** | [`Notepatra-0.1.129-x86_64.AppImage`](https://github.com/singhpratech/notepatra/releases/latest) | `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. |\n\n> All artefacts ship with cosign `.sig` + `.pem` for keyless Sigstore verification and SLSA build provenance. See **[Verify your download](#verify-your-download)** below.\n\n#### 🔒 `notepatra-local-ai` — cloud-free build for regulated environments\n\nFor 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**:\n\n| OS | Artefact | Silent admin install |\n|---|---|---|\n| 🪟 **Windows** | [`notepatra-local-ai-0.1.129.msi`](https://github.com/singhpratech/notepatra/releases/latest) | `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\". |\n| 🐧 **Debian/Ubuntu x64** | [`notepatra-local-ai_0.1.129_amd64.deb`](https://github.com/singhpratech/notepatra/releases/latest) | `sudo apt install ./notepatra-local-ai_0.1.129_amd64.deb` |\n| 🐧 **Debian/Ubuntu ARM64** | [`notepatra-local-ai_0.1.129_arm64.deb`](https://github.com/singhpratech/notepatra/releases/latest) | `sudo apt install ./notepatra-local-ai_0.1.129_arm64.deb` |\n\n**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:\n\n- `localhost` / `127.0.0.1` / `[::1]`\n- RFC1918 (`10.x`, `172.16-31.x`, `192.168.x`)\n- CGNAT range (`100.64.0.0/10` — covers Tailscale, corp VPN)\n- IPv6 unique-local (`fc00::/7`)\n- DNS suffixes `.local`, `.lan`, `.internal`, `.intranet`, `.corp`, `.home`\n\nLocal 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.\n\nOn 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.\n\n### Verify your download\n\nEvery 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.\n\n```bash\n# Linux / macOS — checksum\ncurl -sL -O https://github.com/singhpratech/notepatra/releases/latest/download/SHA256SUMS\nsha256sum -c SHA256SUMS --ignore-missing\n\n# Anywhere — cosign verify (Sigstore)\n# Replace `linux-x64` with `linux-arm64` if you downloaded the ARM64 build.\ncosign verify-blob \\\n  --certificate-identity-regexp '^https://github.com/singhpratech/notepatra/' \\\n  --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \\\n  --certificate notepatra-linux-x64.tar.gz.pem \\\n  --signature  notepatra-linux-x64.tar.gz.sig \\\n  notepatra-linux-x64.tar.gz\n\n# Anywhere — SLSA build provenance\n# Replace `linux-x64` with `linux-arm64` if needed.\ngh attestation verify notepatra-linux-x64.tar.gz --owner singhpratech\n```\n\nFull instructions, threat model, and disclosure policy in [SECURITY.md](SECURITY.md).\n\n### Stay up to date — safe in-app updater\n\nNotepatra 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:\n\n1. **Pick the right artifact for your OS + architecture** — Linux x64 / ARM64 tar.gz, macOS DMG, Windows MSI (with NSIS `.exe` and portable `.zip` as fallbacks).\n2. **Stream-download it** to `~/Downloads/*.part` with a cancellable progress dialog.\n3. **Fetch the release's `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.**\n4. **Atomic-rename `.part` → final name** once verified.\n5. **Hand off to the OS installer** — `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.\n\n**Safety contract — the updater will never leave you with a broken install:**\n\n| Failure | What happens |\n|---|---|\n| No internet | Error dialog, zero disk writes |\n| Download cancelled | `.part` deleted, nothing else touched |\n| Power / crash mid-download | `.part` orphan in `~/Downloads`, current binary untouched |\n| SHA-256 mismatch | `.part` deleted, critical dialog shown, current binary untouched |\n| No `SHA256SUMS` in release | Refuses to auto-install, opens release page for manual verify |\n| No matching platform asset | Refuses to auto-install, opens release page |\n| OS installer cancelled or fails | Installer's own rollback — current binary untouched |\n\nThe 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).\n\n**Check manually:** `Help → Check for Updates` or `?` menu. The check is also visible on first launch (silent if up to date).\n\n### Windows: refresh \"Open with\" entry after upgrading from v0.1.23 → v0.1.24\n\nIf 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.\n\n**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:\n\n```powershell\n# 1. Wipe Notepatra's stale entries from MuiCache (the cache that has the â€\" text)\n$mui = \"HKCU:\\Software\\Classes\\Local Settings\\Software\\Microsoft\\Windows\\Shell\\MuiCache\"\nGet-Item $mui | Select-Object -ExpandProperty Property | Where-Object { $_ -match \"notepatra\" } | ForEach-Object {\n    Remove-ItemProperty -Path $mui -Name $_ -Force\n    Write-Host \"Cleared MuiCache: $_\" -ForegroundColor Green\n}\n\n# 2. Wipe stale \"Open with\" associations pointing to old notepatra.exe paths\nRemove-Item \"HKCU:\\Software\\Classes\\Applications\\notepatra.exe\" -Recurse -Force -ErrorAction SilentlyContinue\n$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\")\nforeach ($ext in $exts) {\n    Remove-Item \"HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\$ext\\OpenWithList\" -Recurse -Force -ErrorAction SilentlyContinue\n    Remove-Item \"HKCU:\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\FileExts\\$ext\\OpenWithProgids\" -Recurse -Force -ErrorAction SilentlyContinue\n}\nWrite-Host \"Cleared OpenWithList for $($exts.Count) extensions\" -ForegroundColor Green\n\n# 3. Force shell to rebuild association cache\nie4uinit.exe -show\nie4uinit.exe -ClearIconCache\nWrite-Host \"Rebuilt shell cache\" -ForegroundColor Green\n\n# 4. Restart Explorer (drops in-memory cache)\nStop-Process -Name explorer -Force\nStart-Process explorer\nWrite-Host \"Restarted Explorer — right-click any file now to verify\" -ForegroundColor Cyan\n```\n\n**What it does — line by line:**\n\n| Step | What & why |\n|---|---|\n| 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. |\n| 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. |\n| 3. `ie4uinit.exe -show` + `-ClearIconCache` | Built-in Windows tool that rebuilds shell association + icon caches. The red ❌ overlay disappears here. |\n| 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. |\n\n**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).\n\n**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.\n\n### Build from source\n\n<details>\n<summary>Linux (Ubuntu/Mint/Debian)</summary>\n\n```bash\nsudo apt install cmake qtbase5-dev libqscintilla2-qt5-dev\ncurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh\nsource ~/.cargo/env\ngit clone https://github.com/singhpratech/notepatra.git\ncd notepatra\ncd rust-core && cargo build --release && cd ..\nmkdir build && cd build && cmake .. && make -j$(nproc)\n./notepatra\n```\n</details>\n\n<details>\n<summary>macOS</summary>\n\n```bash\nbrew install qt@5 cmake\ncurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh\nsource ~/.cargo/env\ngit clone https://github.com/singhpratech/notepatra.git\ncd notepatra\n# Build QScintilla from source (brew's version links Qt6)\n./build.sh\n```\n</details>\n\n<details>\n<summary>Windows (MSVC)</summary>\n\n**Prerequisites**\n1. **Visual Studio 2022** with the *\"Desktop development with C++\"* workload\n2. **Qt 5.15.2** for `msvc2019_64` — install via [Qt Online Installer](https://www.qt.io/download-qt-installer) or [aqtinstall](https://github.com/miurahr/aqtinstall)\n3. **CMake** ≥ 3.16 — `winget install Kitware.CMake` or [cmake.org/download](https://cmake.org/download)\n4. **Rust** stable — [rustup.rs](https://rustup.rs)\n\n**Build QScintilla via the CMake wrapper** *(once)*\n```powershell\ngit clone --depth 1 https://github.com/farleyrunkel/QScintilla.git $env:TEMP\\qsci-src\ncmake -S $env:TEMP\\qsci-src -B $env:TEMP\\qsci-src\\build -G \"Visual Studio 17 2022\" -A x64 `\n  -DCMAKE_BUILD_TYPE=Release `\n  \"-DCMAKE_PREFIX_PATH=C:\\Qt\\5.15.2\\msvc2019_64\" `\n  \"-DCMAKE_INSTALL_PREFIX=$env:TEMP\\qsci-install\"\ncmake --build $env:TEMP\\qsci-src\\build --config Release\ncmake --install $env:TEMP\\qsci-src\\build --config Release\n```\n\n**Build Notepatra**\n```powershell\ngit clone https://github.com/singhpratech/notepatra.git\ncd notepatra\ncd rust-core; cargo build --release; cd ..\nmkdir build; cd build\ncmake .. -G \"Visual Studio 17 2022\" -A x64 `\n  \"-DCMAKE_PREFIX_PATH=C:\\Qt\\5.15.2\\msvc2019_64\" `\n  \"-DQSCINTILLA_INCLUDE=$env:TEMP\\qsci-install\\include\" `\n  \"-DQSCINTILLA_LIB=$env:TEMP\\qsci-install\\lib\\qscintilla2_qt5.lib\"\ncmake --build . --config Release\n```\n\n**Bundle Qt + QScintilla DLLs next to the exe**\n```powershell\nmkdir notepatra-win\ncopy build\\Release\\notepatra.exe notepatra-win\\\nwindeployqt notepatra-win\\notepatra.exe\ncopy $env:TEMP\\qsci-install\\bin\\qscintilla2_qt5.dll notepatra-win\\\n.\\notepatra-win\\notepatra.exe\n```\n\n> If you hit `LNK2019 unresolved external symbol QsciScintilla::staticMetaObject` — verify `CMakeLists.txt` defines `QSCINTILLA_DLL` for 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.\n</details>\n\n---\n\n## Plugin System\n\nDrop a shared library in `~/.config/notepatra/plugins/` and restart.\n- Linux: `.so` files\n- macOS: `.dylib` files\n- Windows: `.dll` files\n\n### Write your own plugin in 30 seconds:\n\n```cpp\n// myplugin.cpp\nextern \"C\" {\n    const char* notepatra_plugin_name()    { return \"My Plugin\"; }\n    const char* notepatra_plugin_version() { return \"1.0\"; }\n    const char* notepatra_plugin_author()  { return \"Your Name\"; }\n\n    char* notepatra_plugin_run(const char* text, int len) {\n        // Your magic here — transform text, return malloc'd result\n        // Return NULL to keep text unchanged\n    }\n}\n```\n\n```bash\n# Linux\ng++ -shared -fPIC -o myplugin.so myplugin.cpp\n\n# macOS\nclang++ -shared -o myplugin.dylib myplugin.cpp\n\n# Windows\ncl /LD myplugin.cpp /Fe:myplugin.dll\n```\n\n---\n\n## Why not just use...?\n\n| Editor | Download size | Native | Local AI | Built-in JSON fixer | 2 GB files | Linux | Win | Mac | Free |\n|---|---|---|---|---|---|---|---|---|---|\n| **Notepad++** | ~4 MB | ✓ | ✗ | plugin only | ✗ | ✗ | ✓ | ✗ | ✓ |\n| **VS Code** | ~300 MB | ✗ Electron | extension | extension | ✗ | ✓ | ✓ | ✓ | ✓ |\n| **Vim / Neovim** | ~3 MB | ✓ | ✗ | ✗ | ✓ | ✓ | ✓ | ✓ | ✓ |\n| **Sublime Text** | ~30 MB | ✓ | ✗ | ✗ | ✓ | ✓ | ✓ | ✓ | $99 |\n| **Kate / Gedit** | ~30 MB | ✓ | ✗ | ✗ | ✓ | ✓ | ✗ | ✗ | ✓ |\n| **Notepatra** | **4.1 / 27.5 / 43.9 MB** | ✓ C++/Rust | ✓ Ollama | ✓ regex + AI | ✓ Rust mmap | ✓ | ✓ | ✓ | ✓ GPL-3 |\n\n> *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 `notepatra` executable 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.*\n\n---\n\n## Tests\n\nFocused 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:\n\n- `test_lexers` — verifies every shipped QScintilla lexer produces real styling\n- `test_palette` — verifies the canonical 9-hue palette colors and bold/italic styles\n- `test_fmtpanel_diff` — verifies formatter panels keep diff state and emit signals\n- `test_compare_widget` — verifies the inbuilt Compare panel diff/edit/close paths\n- `test_sqlfmt` — 33 assertions across 11 SQL dialects through the AST pretty-printer\n- `test_updater` — verifies `pickAssetForPlatform`, SHA256 parsing, and asset scoring (18 assertions)\n- `test_projectsearch` — verifies the Rust-backed project search streaming path\n- `test_projectsearch_ui` — verifies the Project Search UI bindings\n- `test_ollama` — verifies live Ollama model detection (skips cleanly when offline)\n- `test_aifix` — exercises the AI-fix cleanup path against a real Ollama daemon (skips cleanly when offline)\n- `test_llamacpp` — exercises the llama.cpp backend path\n- `test_ai_context` — verifies the AI workspace-context summarizer\n\nRun them locally with:\n\n```bash\n./build.sh --tests\n```\n\nThe Ollama / llama.cpp / AI-fix tests skip cleanly when no inference backend is running, so local and CI runs stay deterministic.\n\n---\n\n## Releases\n\nNotepatra follows [Keep a Changelog](https://keepachangelog.com/) and [Semantic Versioning](https://semver.org/). Every release is tagged, signed, and published to GitHub Releases with binaries for Linux x64, Linux ARM64, macOS Apple Silicon, and Windows x64.\n\n| Version | Date | Highlights |\n|---|---|---|\n| [**v0.1.129**](https://github.com/singhpratech/notepatra/releases/tag/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|TB`, dashed edges `a -.-> b`, `group \"Label\" : a b c`, `note <id> \"text\"`, and `legend dashed \"…\"` / `legend #hex \"…\"`; per-node colours render as tints on light palettes; Mermaid import maps `-.->` and `subgraph`. `group`, `note`, `legend`, `direction` and `layout` are now **reserved words**. Suites: `test_passwordgen` 67 · `test_passwordgen_panel` 99 · `test_npd_parser` 117 · `test_mermaid_import` 44 · `test_diagram_view` 19 · cargo 175 — full offscreen ctest **79/79** green. |\n| [**v0.1.128**](https://github.com/singhpratech/notepatra/releases/tag/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. |\n| [**v0.1.127**](https://github.com/singhpratech/notepatra/releases/tag/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. |\n| [**v0.1.126**](https://github.com/singhpratech/notepatra/releases/tag/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`. |\n| [**v0.1.125**](https://github.com/singhpratech/notepatra/releases/tag/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 ",
  "bytes": 60000,
  "sha": "db9b93cbbf27b9d03b4cb7143e23c066b524af1be017cde9d9c741de333fe006",
  "repo_slug": "singhpratech/notepatra",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_singhpratech_notepatra_mcp_a8607cce/readme"
}