https://github.com/singhpratech/notepatra
Native C++/Rust code editor for the AI era — Linux/macOS/Windows, ~9 MB bare binary, 226 file extensions / 92 language lexers, Rust-powered search, 6 AI backends (Ollama / llama.cpp / OpenRouter / Ollama Cloud / OpenAI / Azure OpenAI). Free forever, GPL-3.0.
https://github.com/singhpratech/notepatra
ai code-editor cpp cross-platform developer-tools free ide lightweight linux local-ai macos notepad notepad-plus-plus ollama open-source qscintilla qt5 rust text-editor windows
Last synced: 24 days ago
JSON representation
Native C++/Rust code editor for the AI era — Linux/macOS/Windows, ~9 MB bare binary, 226 file extensions / 92 language lexers, Rust-powered search, 6 AI backends (Ollama / llama.cpp / OpenRouter / Ollama Cloud / OpenAI / Azure OpenAI). Free forever, GPL-3.0.
- Host: GitHub
- URL: https://github.com/singhpratech/notepatra
- Owner: singhpratech
- License: gpl-3.0
- Created: 2026-03-22T03:53:32.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-05-25T07:27:26.000Z (about 1 month ago)
- Last Synced: 2026-05-25T10:31:07.445Z (about 1 month ago)
- Topics: ai, code-editor, cpp, cross-platform, developer-tools, free, ide, lightweight, linux, local-ai, macos, notepad, notepad-plus-plus, ollama, open-source, qscintilla, qt5, rust, text-editor, windows
- Language: C++
- Homepage: https://notepatra.org
- Size: 14.9 MB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Security: SECURITY.md
- Agents: AGENTS.md
Awesome Lists containing this project
README
Notepatra
The first code editor built for the AI era.
C++ + Rust · under-12 MB bare native executable · Zero Electron · 238 file types · 82 language lexers · Local AI formatters
Website ·
Download ·
Features ·
The Story ·
Install ·
Plugins ·
AI ·
Contributing ·
Security ·
Changelog
---
## The Story
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 — under 12 MB bare (~11.5 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.111 downloads: 4.1 MB Linux x64 (tarball, Qt from the system), 27.5 MB on macOS (DMG with bundled Qt), 32.7–42.4 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.**
---
## Features
### Editor — Battle-tested basics done right
- **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)
- **Tabbed editing** — drag, reorder, middle-click close, double-click empty area for new tab
- **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)
- **3 themes** — Light, Dark, Monokai (Settings > Theme)
- **Session persistence** — close Notepatra, reopen tomorrow, same files, same cursor positions, same window size
- **Crash recovery** — if Notepatra crashes (it shouldn't, but life happens), your unsaved work is recovered on next launch
- **File change detection** — someone else edits your file? Notepatra asks: reload or keep yours?
- **2 GB file support** — memory-mapped I/O via Rust; files up to ~1.86 GB load fully, larger open truncated + read-only
- **Double-click word highlight** — double-click any word, all occurrences light up in orange
- **Ctrl+B brace matching** — jump between matching `{}` `[]` `()`, highlights both braces + selects everything between
- **Macro recording** — Start Recording (Ctrl+Shift+M), Stop, Playback (Ctrl+Shift+P), Run Multiple Times, Save/Load macros
- **Code folding**, **bookmarks**, **auto-complete**, **indent guides**, **line numbers**
- **Custom scrollbars** — clean, modern, rounded
### Search — Find anything, anywhere
- **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.
- **5-tab Find/Replace dialog** — Find, Replace, Find in Files, Mark, Go to
- **3 search modes** — Normal, Extended (`\n`, `\r`, `\t`, `\xNN`), Regular expression
- **Find All in Current Document** — results appear in bottom panel, double-click any result to jump to that exact line
- **Find All in All Opened Documents** — search across every open tab at once
- **Replace All in All Opened Documents** — one click, every file updated
- **Find in Files** — search entire directories recursively with file filters
- **Mark All** — highlight every occurrence with visual indicators
- **Aho-Corasick search engine** (Rust) — faster than regex for literal patterns
### Plugins — The real power
Every plugin opens in its own tab. Real UI, not just a menu click.
#### JSON Tools (inbuilt)
| 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 |
#### HTML Tools (inbuilt)
| 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 |
#### Bracket Tools (inbuilt)
| 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 |
#### SQL Formatter (inbuilt)
- Format with **UPPERCASE** or **lowercase** keywords
- Configurable indent width
- Supports T-SQL, PL/SQL, MySQL, PostgreSQL, SQLite
#### Compare / Diff (inbuilt)
- Pick **any two tabs** or **any tab vs file on disk**
- Side-by-side **Scintilla editors** with a ComparePlus-style **overview/nav bar**
- `+` green for added, `-` red for deleted, `#` amber for changed
- **Word-level LCS intra-line diff** — within a changed line, the specific
*tokens* that were removed are highlighted in red on the left pane; the
tokens that were added are highlighted in green on the right pane. Works
on actual word boundaries, not just common-prefix/suffix.
- **Dark-mode aware** — colours track your Notepatra theme (Light / Dark /
Monokai) so diffs stay readable on both black and white backgrounds.
- **Prev/Next diff** navigation, inline overview-bar jump
- **Ignore whitespace**, **ignore case**, **ignore empty lines** checkboxes
- **Unlock for editing** mode — edit either pane and re-diff in place
- Powered by Rust Myers diff (line-level) + C++ LCS (word-level)
- **Visual UX inspired by [ComparePlus](https://github.com/pnedev/comparePlus) by Pavel Nedev** — credit where credit is due.
#### Git Integration (inbuilt)
- **Staged / Unstaged trees** — porcelain v2 parser, inline `+` / `−` buttons per row to stage/unstage
- **Branch chip with ahead/behind** — shows `main ↑3 ↓1` when diverged
- **Commit box (Ctrl+Enter)** — line-count indicator, blocks commit when nothing's staged
- **Sync row** — one-click Pull / Push / Fetch with live ahead/behind refresh
- **Collapsible history + stash menu** — recent commits expandable; stash / pop / list / drop
- **Git gutter** — green/yellow/red markers in editor margin for changed lines
### AI Powered — local-first, cloud-optional
Backend 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.
#### AI Assistant — side-dock (`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:
- the selection (or full file if no selection is active)
- the full text of the current file
- excerpts of every other open editor tab
- a flat listing of all files under the workspace root (`.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.
#### AI Setup
```bash
# 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.
#### 👁 AI Interaction Log — see exactly what your AI did (`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.*
#### 📝 Noter — meeting notes that turn into reminders (`Ctrl+Alt+N`)
A local-first, two-pane meeting workspace (notes list · editor) — no accounts, no bots; notes live under `~/Documents/Notepatra/Noter/`.
- **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.
- **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.
- **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. Click to open the note, pencil to reschedule, ✕ to delete. Re-running Extract flags what's already scheduled so you never pile up duplicates.
#### 📐 Diagram tool — flow / ER / system diagrams from text (`.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).
- **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.
- **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, label-overflow→hover, 4 palettes (+ default fallback), infinite pan/zoom canvas.
- **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.
### More Features
| 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 |
### Keyboard Shortcuts
| 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 |
---
## Architecture
```
┌──────────────────────────────────────────────┐
│ 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?**
- **C++** because Qt and QScintilla are C++ — zero friction for UI
- **Rust** because file I/O, text processing, and parsing must never crash — Rust's ownership system guarantees memory safety
- **Result**: the speed of C++, the safety of Rust. The bare executable is **under 12 MB** on every platform (~11.5 MB Linux x64, similar on macOS / Windows). Latest v0.1.111 download sizes: **4.1 MB** Linux x64 tar.gz · **3.9 MB** Linux ARM64 tar.gz · **27.5 MB** macOS DMG (with bundled Qt) · **42.4 MB** Windows MSI · **32.7 MB** Windows NSIS · **37.3 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._
---
## Install
### One-command install
**Linux / macOS:**
```bash
curl -fsSL https://notepatra.org/install.sh | sh
```
**Windows (PowerShell):**
```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.
### Or download manually — [Latest release: v0.1.111](https://github.com/singhpratech/notepatra/releases/latest)
| Platform | Download | Size | What's inside |
|---|---|---|---|
| 🐧 **Linux x64** | [`.tar.gz`](https://github.com/singhpratech/notepatra/releases/latest) | **4.1 MB** | Bare `notepatra` binary. Qt5 from your distro. |
| 🐧 **Linux ARM64** | [`.tar.gz`](https://github.com/singhpratech/notepatra/releases/latest) | **3.9 MB** | Bare `notepatra` binary for `aarch64` / ARM64 Linux. |
| 🍎 **macOS Apple Silicon** (M1–M4) | [`.dmg`](https://github.com/singhpratech/notepatra/releases/latest) | **27.5 MB** | `Notepatra.app` with Qt frameworks bundled. Drag to Applications. |
| 🪟 **Windows x64 (MSI)** | [`.msi`](https://github.com/singhpratech/notepatra/releases/latest) | **42.4 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`](https://github.com/singhpratech/notepatra/releases/latest) | **32.7 MB** | NSIS installer. Registers in Settings → Apps → Installed apps. Uninstall via Control Panel works. |
| 🪟 **Windows x64 (portable)** | [`.zip`](https://github.com/singhpratech/notepatra/releases/latest) | **37.3 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.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 (~10 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.
> **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.
**Why are the download sizes different?** Bare `notepatra` executable is **under 12 MB** on each platform (~11.5 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.1 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 5–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-13` runner has been unreliable. Intel Mac users — `git clone` and run `./build.sh`. Builds in ~3 minutes.
### Admin / Fleet install — for IT, DevOps, and regulated teams
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`](https://github.com/singhpratech/notepatra/releases/latest) | `msiexec /i notepatra-0.1.111.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`](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. |
| 🐧 **Debian / Ubuntu / Mint / Pop!_OS** (x64 + ARM64) | [`notepatra_0.1.111_amd64.deb`](https://github.com/singhpratech/notepatra/releases/latest) | `sudo apt install ./notepatra_0.1.111_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.111-1.x86_64.rpm`](https://github.com/singhpratech/notepatra/releases/latest) | `sudo dnf install ./notepatra-0.1.111-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.111-x86_64.AppImage`](https://github.com/singhpratech/notepatra/releases/latest) | `chmod +x Notepatra-0.1.111-x86_64.AppImage && sudo cp Notepatra-0.1.111-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` + `.pem` for keyless Sigstore verification and SLSA build provenance. See **[Verify your download](#verify-your-download)** below.
#### 🔒 `notepatra-local-ai` — cloud-free build for regulated environments
For 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.111.msi`](https://github.com/singhpratech/notepatra/releases/latest) | `msiexec /i notepatra-local-ai-0.1.111.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.111_amd64.deb`](https://github.com/singhpratech/notepatra/releases/latest) | `sudo apt install ./notepatra-local-ai_0.1.111_amd64.deb` |
| 🐧 **Debian/Ubuntu ARM64** | [`notepatra-local-ai_0.1.111_arm64.deb`](https://github.com/singhpratech/notepatra/releases/latest) | `sudo apt install ./notepatra-local-ai_0.1.111_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]`
- RFC1918 (`10.x`, `172.16-31.x`, `192.168.x`)
- CGNAT range (`100.64.0.0/10` — covers Tailscale, corp VPN)
- IPv6 unique-local (`fc00::/7`)
- DNS suffixes `.local`, `.lan`, `.internal`, `.intranet`, `.corp`, `.home`
Local 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.111_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.111` for the lite build and `Notepatra v0.1.111` for the full build (DuckDB bundled), plus `Notepatra Local AI Lite v0.1.111` / `Notepatra Local AI v0.1.111` for the cloud-free (local-ai) builds; the same name shows in the window title bar and the About dialog.
### Verify your download
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.
```bash
# 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](SECURITY.md).
### Stay up to date — safe in-app updater
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:
1. **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).
2. **Stream-download it** to `~/Downloads/*.part` with a cancellable progress dialog.
3. **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.**
4. **Atomic-rename `.part` → final name** once verified.
5. **Hand off to the OS installer** — `msiexec /i` on Windows, `open ` 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).
### Windows: refresh "Open with" entry after upgrading from v0.1.23 → v0.1.24
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:
```powershell
# 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.
### Build from source
Linux (Ubuntu/Mint/Debian)
```bash
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
```
macOS
```bash
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
```
Windows (MSVC)
**Prerequisites**
1. **Visual Studio 2022** with the *"Desktop development with C++"* workload
2. **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)
3. **CMake** ≥ 3.16 — `winget install Kitware.CMake` or [cmake.org/download](https://cmake.org/download)
4. **Rust** stable — [rustup.rs](https://rustup.rs)
**Build QScintilla via the CMake wrapper** *(once)*
```powershell
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**
```powershell
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**
```powershell
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` — 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.
---
## Plugin System
Drop a shared library in `~/.config/notepatra/plugins/` and restart.
- Linux: `.so` files
- macOS: `.dylib` files
- Windows: `.dll` files
### Write your own plugin in 30 seconds:
```cpp
// 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
}
}
```
```bash
# 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
```
---
## Why not just use...?
| 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 / 42.4 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.111. Linux is just the binary (Qt is system-installed). macOS and Windows include bundled Qt. The bare `notepatra` executable inside is under 12 MB on every platform (Linux 11.5 MB, similar on macOS / Windows). Compressed download is much smaller because tar.gz / DMG / MSI all compress the binary plus shared libraries.*
---
## Tests
Focused automated regression tests are wired through CMake + CTest and run in CI — **52 test suites** on the Full build (51 on Lite, which omits the WebEngine chart suite); all green, each with many assertions. A representative sample:
- `test_lexers` — verifies every shipped QScintilla lexer produces real styling
- `test_palette` — verifies the canonical 9-hue palette colors and bold/italic styles
- `test_fmtpanel_diff` — verifies formatter panels keep diff state and emit signals
- `test_compare_widget` — verifies the inbuilt Compare panel diff/edit/close paths
- `test_sqlfmt` — 33 assertions across 11 SQL dialects through the AST pretty-printer
- `test_updater` — verifies `pickAssetForPlatform`, SHA256 parsing, and asset scoring (18 assertions)
- `test_projectsearch` — verifies the Rust-backed project search streaming path
- `test_projectsearch_ui` — verifies the Project Search UI bindings
- `test_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 path
- `test_ai_context` — verifies the AI workspace-context summarizer
Run them locally with:
```bash
./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.
---
## Releases
Notepatra 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.
| Version | Date | Highlights |
|---|---|---|
| [**v0.1.111**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.111) | 2026-05-31 | **The lovable AI agent wave — four assistant UX features that make agentic editing trustworthy (grade B- → B+/A-).** Agent mode now shows an **Approve / Reject** write-confirmation gate before `write_file` / `apply_diff` ever touches disk, so autonomous edits never land silently. A **context-transparency** chip + popover reveals exactly what codebase context is sent to the model, with per-source exclude toggles to drop a file or folder before it leaves your machine. Every **Composer Apply** is now drift-protected and byte-exact — one "Undo apply" restores the file precisely and refuses if it changed underneath you. And the **Ctrl+I inline edit** renders a real, theme-aware Myers diff so you see exactly what changed before accepting. UX/behaviour only — no new deps, same bare binary, download sizes unchanged. 52/52 ctest pass. |
| [**v0.1.110**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.110) | 2026-05-31 | **AI coding assistant — trust & clarity pass (driven by a deep usability audit, grade C+ → B-).** The assistant header now shows your full posture at a glance — `AI · CODING · COMPOSE` (review-before-write, teal) vs `AI · CODING · AGENT` (writes hit disk live, red) — so you never guess whether the AI will edit your files. Coding now defaults to the safe **Compose** lane (propose-then-review), not autonomous Agent, so reopening never silently drops you into live disk writes. Applying a proposed edit now marks each file **✓ applied**, drops a confirmation, and disables re-apply (no more "did it land?" or accidental double-write). Inline edit (Ctrl+I) now uses **your selected model** (not a fixed small default — fixes the no-hardcoded-model rule) and groups its change as **one undo** so a single Ctrl+Z reverts the whole AI edit. UX/state only — no new deps, same bare binary, download sizes unchanged. 51/51 ctest pass. |
| [**v0.1.109**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.109) | 2026-05-31 | **The full build drops its "Full" name tag — the default build now self-identifies simply as "Notepatra".** `notepatra --version`, the window title bar and the About dialog show **Notepatra** for the full (DuckDB-bundled) build instead of "Notepatra Full" — the full edition is the default, so it carries no qualifier. The bare build still says **Notepatra Lite** so you can tell it apart, and the cloud-free builds are **Notepatra Local AI** / **Notepatra Local AI Lite**. Naming only — the Lite vs Full *downloads* are unchanged (Full still bundles the DuckDB engine), as are the binary's features and download sizes. 51/51 ctest pass. |
| [**v0.1.108**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.108) | 2026-05-31 | **Data Analyst mode writes sharper SQL — three filter-correctness idioms added to the built-in analyst prompt.** Case-insensitive text search: "description contains X" now lower-cases both sides (`LOWER(col) LIKE '%x%'`) instead of a case-sensitive match that silently skipped Capitalized rows and undercounted. Exact-code matching: when a question names a coded value ("LOINC 8480-6", "CVX 140") the analyst matches the bare stored code and stops, instead of bolting on a guessed `SYSTEM=`/`CATEGORY=`/redundant `LIKE` predicate that could drop every matching row. No more inventing a category/type literal from the question's English label ("obese", "active") without verifying it exists. **Prompt-only** — same bare Lite binary, no new dependencies, download sizes unchanged; the three idioms were validated against a multi-domain text-to-SQL evaluation (the production model's lone remaining synthetic-EHR defect was fixed, with no regressions). 51/51 ctest pass. |
| [**v0.1.107**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.107) | 2026-05-30 | **Lite + Full downloads for all three platforms, with DuckDB v1.1.3 bundled in Full.** Previously only Linux published a `-full` build; the macOS DMG / Windows MSI shipped without WebEngine despite the docs (the v0.1.106 Windows zip had zero WebEngine DLLs). Now every platform offers a Lite (bare) and a Full download — Full bundles **DuckDB v1.1.3** everywhere (in-process Parquet / JSON / S3 / SQLite federation), plus the QtWebEngine inline Vega-Lite chart renderer on Linux/Windows (macOS Full is DuckDB-only; the native fenced ```chart QtCharts renderer works on every platform). The app now **names its build flavor** in `--version` / title bar / About (Notepatra Lite / Full, and Notepatra Local AI Lite / Full). **Fixed:** 13 double-mapped file extensions resolved only by hash order (`.hh` opened as Hack not C++) — deduped and locked by tests; `Ctrl+Shift+K` was bound to both Delete Line and Uncomment Line (Uncomment moved to `Ctrl+Alt+U`). 51/51 ctest pass. |
| [**v0.1.106**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.106) | 2026-05-29 | **A reliability + security hardening release — every change hardens a code path that already shipped, no new features.** Session restore could write unsaved content to the wrong file when a restored tab pointed at an unreadable/already-open file (now lands orphaned content in a fresh untitled tab). CredScrub now runs over the AI tool-result channel (`read_file`/`git_diff` bodies were forwarded verbatim to the backend); the read-file deny-list adds the dotenv family incl. `app.env`/`database.env`, `secrets.json`, and `*.tfvars`/`*.tfstate`; chart HTML export is XSS-escaped (both build paths); dry-run edits now queue an absolute path so they can't clobber `$HOME`; an interior-NUL heap over-read in the Rust core (Base64 decode) is fixed. Plus a large-file memory soft-gate. |
| [**v0.1.105**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.105) | 2026-05-29 | **The per-symbol diagram colours from v0.1.104 now appear by default in the ER and System starter templates, not just the flow chart.** Colour was never gated on diagram type — it has always worked on database cylinders and icon nodes — so this is purely a discoverability fix: the ER starter now colour-groups entities (green master / blue transactional) and the System starter groups by tier (teal edge / blue app / purple data), and Help states colour works on every node type and diagram. Colour stays opt-in. |
| [**v0.1.104**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.104) | 2026-05-29 | **Diagrams gain optional per-symbol colours and chained arrows — both opt-in, both native, both staying monochrome by default.** Add a `#hex` or named colour after a node's shape (`node proc [Process] #1565c0`, `node start (Start) green`) for auto-contrast coloured symbols on any palette/theme; connect a run of nodes on one line (`a -> b -> c`, label rides the last hop). Plus `.npd` parser hardening surfaced by an adversarial parse audit — node ids may contain colons/URLs (`http://x -> y`), node labels may contain `->`, and an untrusted diagram title can no longer inject a live tag into exported HTML/SVG. |
| [**v0.1.103**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.103) | 2026-05-27 | **Diagrams now render natively in the default binary — on every platform, including macOS Apple Silicon and the Windows installer — with no WebEngine, no Chromium, and no separate "Full" download.** v0.1.102 drew diagrams inside an embedded Chromium (QtWebEngine + dagre.js), so the picture never appeared on the default lite binary, on macOS Apple Silicon, or anywhere WebEngine wasn't bundled. v0.1.103 replaces that whole pipeline with a native `QPainter` renderer (`src/diagram/diagram_render.{h,cpp}`): longest-path layering + barycenter crossing-reduction, border-anchored bezier connectors, ~55 hand-drawn icons (~150 aliases) for system/ER/flowchart, 5 palettes, scroll-zoom/drag-pan. Export to PNG/JPEG/PDF on every build, plus SVG/HTML where the Qt Svg module is present and WebP where the WebP image plugin is present — the export menu shows exactly what your build supports. No more Full vs Lite split for diagrams. |
| [**v0.1.102**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.102) | 2026-05-25 | **Diagrams — flow / ER / system from a text DSL, with AI generation, a live canvas, and PNG/SVG/PDF/HTML export.** New first-class diagram tool (Full flavor): the text-first `.npd` DSL is the source of truth and the canvas is a live projection. Create three ways — **AI Generate** (describe it → review the generated `.npd` → Insert), templates, or write `.npd` directly (plus **Import Mermaid**). 5 shapes, 12 icons, directed/labelled/bidirectional arrows, label-overflow→hover, 5 palettes, infinite pan/zoom. Toolbar button next to Noter + in-tool Help cheat-sheet + `samples/diagram_showcase.npd` + `npd_render` CLI. **Also fixed:** `CMAKE_AUTORCC` was never enabled, so `.qrc` resources (`vega.qrc` inline charts, `icons.qrc`, the diagram render layer) weren't bundling in Full builds — now corrected. 53/53 ctest pass. |
| [**v0.1.101**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.101) | 2026-05-25 | **In-app updater finalizes even when a prior download is locked.** On macOS the update downloaded + verified, then failed with "Could not finalize the download file." `Updater::runUpdate()` moved the verified `~/Downloads/.part` to `` with `if (exists) remove(); rename();` but ignored the remove result — and on macOS a `.dmg` the updater previously `open`ed stays MOUNTED in Finder, which macOS won't let you delete, so `QFile::rename` then refused to overwrite it and every retry re-wedged. Fix: new `uniqueDestPath()` lands the file under a browser-style ` (1).dmg` when the destination can't be removed, plus a copy+remove fallback. Net improvement on all platforms. New `test_updater` cases cover the dedup for `.dmg`/`.tar.gz`/`.msi`/`.deb`/`.AppImage` (a version-dot edge case was caught + fixed pre-release). 47/47 ctest pass. |
| [**v0.1.100**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.100) | 2026-05-25 | **🎉 100th release — window opens centred on Windows.** On a cold start / file-double-click the window could open with its title bar above the top of the screen, hiding the min/max/close buttons. Root cause: position was saved with `QWidget::x()`/`y()` (Qt FRAME coords, incl. the title bar) but restored with `setGeometry()` (CLIENT coords), so on Windows the title bar climbed up by its own height each launch until the controls left the screen; the ≥100 px on-screen clamp didn't catch a body-on-screen / title-bar-off-top window. Fix: new `centeredWindowRect()` helper — both restore sites (config + session) now centre on the **saved size** with a title-bar-height top margin instead of restoring the saved x/y. Maximized state + window size preserved; only on-screen position is dropped (always centred). Also confirmed (no change): the AI Interaction Log at `%APPDATA%\Notepatra\ai-logs\` persists across upgrades and survives uninstall (installers never touch `%APPDATA%`). 47/47 ctest pass. |
| [**v0.1.99**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.99) | 2026-05-25 | **Noter sidebar renders light on macOS.** The Notes/Reminders/Trash tree drew on a dark background while the rest of the Noter panel stayed light — a stale stylesheet selector after the list→tree migration. `sidebarStyle()` still carried the old `QListWidget#noterMeetingList` rules and had none for the migrated `QTreeWidget#noterSidebarTree`; a Qt item-view paints its viewport from its own `QPalette::Base`, which the parent panel's QSS `background` doesn't reach, so the unstyled tree fell through to the dark system base on macOS (Linux/Windows default to a light base, so it never showed there). Fix: explicit `QTreeWidget#noterSidebarTree` light-background rules **plus** a `QPalette::Base`/`Text` pin in `buildSidebar()` as a belt-and-braces fallback; `::branch` left native so disclosure arrows survive. Cosmetic-only — Noter worked throughout. 47/47 ctest pass. |
| [**v0.1.98**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.98) | 2026-05-25 | **Windows in-app updater fixed.** The v0.1.96 EOL-OpenSSL guard hard-disabled **Check for Updates** on any OpenSSL 1.0.x / 1.1.x runtime, popping an "in-app update check disabled" dialog for every Windows user. That was a misdiagnosis — "end-of-life" (no upstream security patches) ≠ "broken": the bundled **OpenSSL 1.1.1w** speaks the TLS `api.github.com` requires, and the real v0.1.96 launch-hang was the session-restore loop (fixed separately in v0.1.96). The gate is removed; the update check keeps its existing, sufficient safety net — async `QNetworkAccessManager`, an **8-second abort timer**, a `QSslSocket::supportsSsl()` guard, and a TLS-aware "Open Releases Page" fallback. **One-time:** v0.1.96 / v0.1.97 Windows builds still carry the gate, so download v0.1.98 manually once; in-app updates work from then on. (Bundling OpenSSL 3 on Windows — the Qt 5.15.2 ABI targets OpenSSL 1.1 — remains queued as separate security hygiene.) 47/47 ctest pass. |
| [**v0.1.97**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.97) | 2026-05-25 | **Noter reminders grow up + cloud-AI fixes.** New **central Reminders** sidebar root (between Notes and Trash) lists every scheduled reminder grouped Overdue / Today / This week / Later — click to open the note, pencil to reschedule, ✕ to delete; overdue rows render red; painter-drawn amber clock icon. **Extract now schedules real reminders** (the "Remind" checkboxes were previously cosmetic) via new `NotesTodos::addReminder()`; resolves natural-language times ("10am tomorrow") to a concrete LOCAL wall-clock (was UTC, which shifted the hour); returns a plain-English **summary** shown in the dialog + saved above the action items; and **flags already-scheduled** actions on re-run (fuzzy match) so you don't pile up duplicates. Remind defaults ON only when a concrete time was extracted. **Three cloud-AI fixes:** double-`/v1` URL (`…/api/v1/v1/models` → 404 "unreachable") normalized via `openAiV1Base()`; streaming 401 no longer spins ~60s silently — surfaces a prompt auth error; and cancelling the Extract result no longer crashes (the dialog deferred off the network signal so a trailing `downloadProgress` can't hit freed memory). **AI Interaction Log** surfaced as a first-class privacy feature (Features → AI Interaction Log…) in the in-app Help, README, and website. 47/47 ctest pass (new `test_stream_error`, `test_notes_todos` §13, `test_notes_panel_widget` §21–23, sweep-prompt local-time + summary). |
| [**v0.1.96**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.96) | 2026-05-24 | **Same-day Windows hotfix for v0.1.95.** Three root causes of a reproducible launch-hang permanently addressed. (1) **Platform-conventional config dir** — pre-fix Notepatra wrote to `~/.config/notepatra/` on every OS; Windows users' `%APPDATA%\Notepatra\` appeared empty while session state sat in `C:\Users\\.config\notepatra\`, invisible to IT tooling / backup tools / group policy. New `Config::appConfigDir()` returns `%APPDATA%\Notepatra` on Windows, `~/Library/Application Support/Notepatra` on macOS, `$XDG_CONFIG_HOME/notepatra` on Linux (unchanged). One-time copy-migration from the legacy path on first launch; legacy cleanup queued for v0.1.97. All ~6 hard-coded call sites migrated (config.json, session.json, recovery/, ai-logs/interactions.db, db-connections.json, plugins/). (2) **Crash-safe session restore** — `MainWindow::restoreSession()` now writes a `session.json.restoring` marker before opening files and deletes it on success. On next launch, if the marker exists, the previous restore was interrupted (kill / hang) — session.json is moved aside to `session.json.failed-` (preserving the tab list) and a deferred dialog tells the user where to find it. No more "reopen the same bad file on every launch" loop. (3) **EOL-OpenSSL update-check gate** — runtime check on `QSslSocket::sslLibraryVersionString()` hard-skips the GitHub update check if the bundled OpenSSL is 1.0.x or 1.1.x (EOL since Sept 2023). The TLS handshake against modern endpoints can stall the UI thread on a broken stack; bypassing eliminates that path. Bundling OpenSSL 3.x in the Windows MSI queued for v0.1.97 (CI workflow change). All v0.1.95 tests carry forward green (~1325 total, 0 failing) plus new unit tests for `appConfigDir()` per-platform via env override. |
| [**v0.1.95**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.95) | 2026-05-24 | **Windows crash hardening + Noter full redesign.** Three Windows crash / hang classes fixed: Save / Save As / right-click-Save reliable crash (root cause: `QFileDialog::setProxyModel` + `QIdentityProxyModel` synthetic-column crash on `QFileSystemModel`'s async `QFileInfoGatherer`; removed the proxy entirely, dropped the Date Created column); multi-PID on double-click launcher (root cause: listen-after-MainWindow-construction + 300ms probe + unconditional `removeServer()` orphaning the running instance; now bind pipe before constructor, two-stage 500+1500ms probe, conditional removeServer); invisible main window after monitor change (root cause: persisted coords from disconnected secondary monitor; new `clampWindowToScreens` intersect-tests against connected screens, recenters on primary if no overlap). Plus surfaced 3 silent-save-failure dialogs at File→Save / right-click Save / closeTab Save sites where the `bool` return was being ignored. **Noter full redesign** (the meeting-notes tab): rewrote `src/notes.cpp` from scratch into a two-pane sidebar+editor shape inspired by Apple Notes / Bear / Granola; deleted the 6-button insert bar, slash menu (`src/notes_slashmenu.{cpp,h}`), 5-button header row, edge-strip icons, and WebEngine path (`src/notes_bridge.{cpp,h}`, `src/notes_editor.{cpp,h}`); added markdown shortcuts (`- [ ]` + Space → ☐; F4 toggle), inline ✕ delete button on every meeting + every todo row, Trash + restore for meetings (`Noter/Trash/.trashed--.html`) AND todos (`status='trashed'`), inline-editable todo titles via QStackedWidget [QLabel, QLineEdit], calendar pickers in Add-todo dialog (Due + Remind, each with today / tomorrow / 1h-before-due / clear quick-picks), right-click context menus on todo rows with Set due / Set reminder / Mark done / Delete (soft) / Restore / Delete permanently, AI model selector in editor footer auto-populated from `OllamaClient::listModels()`, single ✨ Extract button bottom-right runs `NoterSweepPrompt` against Ollama and inserts an Action Items section on Apply. **Tool brand-color palette unified** — new `src/tool_colors.{h,cpp}` is the single source of truth for tab strips + feature-toolbar icons + Welcome cards (`notepatraToolAccent(toolKey)`). Palette overhauled to 12 visibly-distinct hues spread ~30° apart, resolving 5 collisions (AI / JSON both blue → royal blue / cyan; HTML / Project Search both orange → HTML hot pink; Noter / Git both red → Git lime; Brackets / Project Search same hue). **Light QMenu styling forced per-instance** on every Noter context menu — Qt's QSS doesn't cascade through widgets that set their own stylesheet so the rules must be on each menu. Fixes dark-on-dark right-click that the user reported. **~303 Noter tests** (was 257) — `test_notes_panel_widget.cpp` (NEW 24-case integration test) + 14 new editable-row cases + 22 new trash-lifecycle cases. **~1325 total tests pass** across the wider Notepatra suite. All v0.1.93 fixes carry forward unchanged. |
| [**v0.1.93**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.93) | 2026-05-19 | **Project Search: intelligent flood protection, live phrase-relevance ranking, `match=N%` badges, cross-platform completion notifications.** Replaces the v0.1.92 unbounded-emit model that OOM-killed the app on `import os` over `$HOME` with an informed search experience. **Soft warning at 10k matches** (amber progress bar + status note, no interruption). **Hard checkpoint popup at 50k** with Continue / Show me these / Cancel — clicking *Show me these* flips the UI phase to Idle immediately so the timer doesn't keep ticking while threads wind down; clicking *Cancel* re-enables the Search button instantly instead of waiting for the worker to unwind. **Match all words default OFF** — `import os` runs as exact-phrase by default; power users tick the box for any-order any-line AND semantics. **`match=N%` self-describing badge on every result row** (100% = full phrase on this line, 99% = all tokens scattered, lower = partial; column is fixed-width and visually consistent in every mode). **Live phrase-relevance ranking on both axes** — within-file `std::stable_sort` descending on per-line %, cross-file *live re-positioning* in the tree (take + insert at the correct slot) the moment a file's best-line % improves, so 100% files surface to the top *during* the scan instead of only at the end. **Cross-platform desktop notification** when a search ≥ 3s completes with the window unfocused — one code path (`QSystemTrayIcon::showMessage`) routes to libnotify/D-Bus on Linux, Toast on Windows, NSUserNotificationCenter on macOS, no visible tray icon added. **Bug fixes**: modal dialog double-`%%` ("Scanned X of Y (4%%)"), "⏳ stalled on:" wording replaced with neutral "· current:" when the scan is just slow on one big file, title 🔍 emoji-font fallback on Linux so the header looks the same as Win/Mac, "Show me these" no longer leaves the status saying "Searching…" for 47 seconds. **39/39 ctest pass** (unchanged). All v0.1.92 fixes carry forward unchanged. |
| [**v0.1.92**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.92) | 2026-05-19 | **SQL formatter deep-dive: 9 dialect bugs fixed in one pass.** User-reported regression — `[onelook-db-1]` mangled to `[ onelook - db - 1 ]` — fixed via T-SQL bracket-identifier preservation; 9 other latent bugs found in the same audit also fixed. **Bumped `sqlparser-rs` 0.52 → 0.55** (13 distinct breaking AST shape changes migrated: `Statement::Update.from` now `UpdateTableFromKind` enum, `Insert.table` now `TableObject`, `OrderBy` restructured with `OrderByKind`, `OrderByExpr.options.{asc,nulls_first}`, `ObjectNamePart::Identifier`, `Case.conditions` now `Vec`, `SelectItem::QualifiedWildcard` now `SelectItemQualifiedWildcardKind` enum, `JoinOperator` 5 new variants for unqualified forms, `JoinConstraint::Using` now `Vec`). **New `Statement::Merge` Writer arm**: MERGE INTO ... USING ... ON ... WHEN MATCHED/NOT MATCHED THEN ... — was collapsing to one line via Display fallback. **`DISTINCT ON (cols)` rendering**: previously emitted bare `DISTINCT`, silently dropped the column list. **`FETCH FIRST N ROWS [PERCENT] [WITH TIES \| ONLY]`** — `q.fetch` field was never read by Writer pre-v0.1.92. **T-SQL `GO` batch separator pre-split**: new `split_tsql_go_batches()` walks input with string/comment-state tracking, formats each batch independently, rejoins with `GO`. **T-SQL `PRINT` pre-mask**: sqlparser doesn't recognize PRINT; we mask it as a parseable placeholder, restore verbatim. **`apply_keyword_case()` token-aware case helper** replaces `.to_lowercase()` whole-string on Display-emitted ON CONFLICT / MERGE INSERT bodies — preserves identifiers like `Email`, `Name`, and MySQL function `VALUES(a)` from being mangled to lowercase in lowercase-keyword mode. **10 new regression tests + hardened bracket-id test**: 34 → 44 in `sql_fmt` module; 39/39 ctest still green. Zero C++ changes; same FFI surface (`npc_format_sql` in `src/rustbridge.cpp:213/222` binary-compatible with new `librust_core.a`). All v0.1.91 fixes carry forward unchanged. |
| [**v0.1.91**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.91) | 2026-05-19 | **Notepad++-style per-line change-history strip + holistic path-separator sweep + status-bar change counter + Find/Replace UX upgrade.** Margin 3 now paints a 4 px per-line strip: **orange** while edited, **green** after save (Notepad++ behaviour). Manual implementation via `SCN_MODIFIED` / `SCN_SAVEPOINTREACHED` / `SCN_SAVEPOINTLEFT` because Ubuntu 24.04's QScintilla 2.14.1 ships Scintilla compiled WITHOUT `SCI_SETCHANGEHISTORY` (the message round-trips as a no-op; confirmed via PyQt5). `FullRectangle` marker shape — never `Background` (whole-line paint bug from pre-v0.1.91 git-diff gutter that filled markdown drafts with green). Safety nets: `m_loadingFile` flag stops wholesale `setText()` from marking every line orange on open; `SCN_MODIFIED.line` recomputed from `position` via `SCI_LINEFROMPOSITION` (QScintilla 2.14.1 only fills `line` for fold events); `onSavePointReached()` does `markerDeleteAll(23)` belt-and-braces + full `update()` because some X11 compositors don't synthesise margin repaints from marker state alone. **Status bar gains `N modified · M saved` counter** between cursor-position and EOL fields — hidden when both zero. O(1) via parallel `QSet` members + `changeHistoryUpdated()` signal pattern; no buffer walking. **Holistic `QDir::toNativeSeparators` sweep** — 16 new sites across 6 files (findreplace / fileexplorer / mainwindow / tabmanager / gitpanel / welcome) wrapped so Windows shows `\` everywhere paths display; no-op on Linux/macOS. **Find/Replace dialog upgrade**: Notepad++-style italic bottom status bar (single source of truth for every tab; pre-v0.1.91 Replace tab results silently dropped because `m_resultsOutput` was nullptr); Find↔Replace string carry-forward (with non-clobber guard so retyping on the destination tab survives a re-switch); two-step wrap at cycle end (Find Next stops at last match with "Reached end — press again to wrap" notice; SECOND consecutive press actually wraps). Dialog min size 660×400 → 720×440 + `setWordWrap(true)` so the longest status message fits. **6 new test executables, 78 assertions**: `test_change_history` (16) · `test_change_history_mainwindow` (12) · `test_change_history_watcher` (6) · `test_change_history_stress` (20) · `test_changehistory_statusbar` (14) · `test_findreplace_carry_forward` (20). **39/39 ctest pass** (was 33/33). All v0.1.90 fixes carry forward unchanged. |
| [**v0.1.90**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.90) | 2026-05-16 | **Save As detail view now shows a "Date Created" column.** v0.1.88 shipped the dialog UX baseline (960×640 geometry, Detail view default, sort by Date Modified descending) but the user-requested Date Created column was deferred — the first attempt used a hand-rolled `QSortFilterProxyModel` whose `index(row, extraCol)` returned a `createIndex()` with no source mapping, crashing Qt's tree view on Ctrl+S. v0.1.90 ships the column via the supported `QIdentityProxyModel` pattern. New `src/savedialogfsmodel.h/cpp` wraps QFileDialog's internal QFileSystemModel with one extra column whose `data()` returns `QFileInfo::birthTime()` for ext4 (kernel ≥ 4.11), falls back to `metadataChangeTime()` (ctime) on filesystems that don't store birth time, and renders an em-dash when both are invalid — so the cell never crashes the row layout. `mapToSource()` maps the extra column to source column 0 so Qt's model APIs that traverse back to the file system can resolve. Wired into `configureSaveDialogUx()` for both `saveFileAs()` and the close-tab "Save before close?" prompt. **Why a proxy and not a `QFileSystemModel` subclass**: QFileDialog builds its own QFileSystemModel internally; the supported extension point is `setProxyModel()`. Subclassing the model and `tv->setModel()` would break path-bar / name-edit / selection wiring hard-coded to the d-pointer's model. 32/32 ctest pass. |
| [**v0.1.88**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.88) | 2026-05-15 | **Save As file-type dropdown now actually drives the saved extension.** v0.1.88 user-reported same day: dropdown populated with 72 entries but picking "Python" + typing `foo` still saved as `foo` (no extension). Root cause: `QFileDialog::setDefaultSuffix` was never wired so the selected filter didn't drive the extension. Fixed in `src/mainwindow.cpp` (both saveFileAs() and closeTab() unsaved-prompt) by wiring setDefaultSuffix from the preselected filter at init AND from the `filterSelected` signal so switching mid-dialog stays in sync. Post-Accept safety net via new `applySaveAsFilterSuffix(path, filter)` helper for platform dialogs that silently ignore setDefaultSuffix (some Linux GTK builds, certain macOS dialog states). New `firstExtensionFromFilter("Python (*.py *.pyw *.pyx)") → "py"` extractor handles bare-name filters (Dockerfile / CMakeLists.txt / .gitignore) and "All Files (*)" correctly. **New `test_save_as_filters` regression — 16 contract assertions** that drive the user-visible end-to-end flow: bare 'foo' + Python → foo.py · foo.py + Python → unchanged · foo.txt + Python → foo.txt.py (filter wins) · All Files → unchanged · bare Dockerfile name match → unchanged · etc. Codifies the v0.1.88 ship miss: proxy assertions ("function called", "list populated") instead of contract assertions ("the bytes on disk match the selected filter"). New memory rule: **test the user-visible contract, NOT proxy properties**. 32/32 ctest pass (was 31 in v0.1.88). |
| [**v0.1.88**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.88) | 2026-05-15 | **Save As file-type dropdown + large-file load speed-up.** Two user-reported pain points fixed: dead Save As dropdown vs Notepad++ (`src/mainwindow.cpp:1655` was passing only `"All Files (*)"` so the bottom-of-dialog dropdown had one entry), and 100+ MB files slower than the "up to 2 GB" promise. New `buildSaveAsFilters()` helper in `src/lexerutils.{h,cpp}` returns ~72 language entries matching Notepad++ behaviour (Plain Text · Markdown · Python · JS/TS · C/C++ · Rust · Go · SQL · JSON · YAML · TOML · CSV · HTML · CSS · …); pre-selects the filter matching the current tab's language. Same fix in `closeTab()` "Save before close?" prompt which had no filter at all. **Large-file load — 3 fixes that compound:** (1) UTF-8 fast path in `rust-core/src/file_io.rs` — skip `UTF_8.decode()` when mmap bytes are already valid UTF-8 (was allocating a fresh 118 MB String even when not needed; saves 118 MB heap + 250 ms on 118 MB file). (2) EOL detection bounded to first 64 KB — was scanning 118 MB twice for ~300 ms. (3) Drop `CString` round-trip in Rust→C FFI — `FileLoadResult.text` now allocates a `Box<[u8]>` instead of a CString (skips O(N) NUL scan + extra 118 MB allocation + appended NUL byte). New `npc_free_file_text(ptr, len)` reclaims the boxed slice by length. **Large-file UX gates**: files > 50 MB also disable word wrap + indent guides + edge column. **NOTE**: shipped with the Save As filter-extension bug fixed in v0.1.88. 31/31 ctest + 130/130 cargo test pass. |
| [**v0.1.86**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.86) | 2026-05-15 | **Factual-audit gate, BGR-bug sweep, download-size truth-up — no new features.** Post-v0.1.85 audit caught two classes of inaccuracy that had been drifting across releases. **Two more Scintilla BGR byte-order bugs**: `src/findreplace.cpp:770` Find→Mark All indicator passed raw `0x0000FF` (intended blue, byte-swapped to red); `src/merge_helper_widget.cpp:185` merge-conflict annotation text passed raw `0x00204050` (intended dark blue, byte-swapped to olive-brown). Both now BGR-packed correctly — Mark All renders Tailwind blue-500 `#3B82F6`, conflict text renders `#204050`. Same root cause as v0.1.85's editor.cpp fix. **Six download-size claims** on `docs/index.html` / `docs/docs.html` / README narrative were inflated by ~1.5 MB across every platform (3.6 / 28.7 / 42.5 / 33.7 / 38.4 MB) while actual artifact bytes were 3.45 / 26.86 / 40.56 / 32.18 / 36.68 MB. All reconciled to within ±0.05 MB of `gh release view` output. The README install table at lines 262-267 was already correct and used as the cross-check reference. **bare-binary marketing claim was both stale AND false**: bare binary is 9.71 MB (not 9), AND CI has no `strip` step so the shipped binary is unstripped (carries 2.65 MB of DWARF debug info; stripped it would be 7.06 MB). Live marketing now reads "under 10 MB (~9.7 MB on Linux x64)" without the misleading "stripped" word; forensic release-notes rows preserved unchanged. **The miss**: `feedback_release_factual_audit.md` had been in memory since v0.1.80 saying "run a fact-check pass every release because `stale-text-check.sh` doesn't catch download sizes" — and the operator (Claude) skipped it under release-time load. Same pattern as v0.1.83's memory→gate promotion. **The new gate** `scripts/verify-download-sizes.sh` calls `gh release view "v$VERSION" --json assets`, finds the closest "X.Y MB" claim across the three docs for each artifact, and asserts drift ≤ ±0.15 MB. Also downloads the Linux tarball and runs `file ... \| grep ", stripped$"` to verify the "stripped" claim is honest. Wired into `scripts/release-check.sh` as a Phase 2 step. New post-mortem memory `feedback_factual_audit_must_be_a_gate.md`. CI strip step (drops binary to 7.06 MB) queued for a future release in `project_next_release_ci_strip_step.md` — separate scope so the CI change can be verified end-to-end. 31/31 ctest pass. |
| [**v0.1.85**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.85) | 2026-05-15 | **Markdown Light palette overhaul, Claude-Code-blue selection, neon-orange match highlight, and a real Scintilla byte-order bug fix.** The v0.1.84 Solarized MD palette landed yesterday and felt off in front of the user — too rainbow, with the classic yellow-H2-on-pale-paper legibility issue. After iterating through Solarized → jewel-tone purple/magenta/blue → final SSMS, MD Light now reuses the same six-hue palette users already know from `.sql` files: H1 magenta `#FF00FF`, H2 blue `#0000FF`, H3 maroon `#7F0000`, H4 navy `#000080`, H5 orange `#FF8000`, H6 green `#008000`. Inline code chip on slate-800 (`#1E293B`) text + slate-300 (`#CBD5E1`) paper for a denser, more present "code pill" feel. Light theme text selection bumped from VS Code's pale `#ADD6FF` wash to `#5BC8FA` — the bright cyan-sky Claude Code uses on its prompt focus rings. **Real bug fix in `src/editor.cpp:664-679`**: Scintilla's `SCI_INDICSETFORE` expects a Win32 COLORREF (BGR byte order), but the indicator setup passed `QColor::rgb() & 0xFFFFFF` (Qt RGB) — so the double-click word-match indicator had been rendering the wrong color since the feature was first added (`#E8A848` clay-orange was painting as a light blue-purple). Now BGR-packed correctly; indicator 9 also bumped to neon orange `#FF5500` (alpha 160 fill / 255 outline) so matches pop. Dark + Monokai MD palettes verified unchanged. |
| [**v0.1.84**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.84) | 2026-05-15 | **Biggest syntax-highlighting refresh since v0.1.31.** Every supported language got reserved-word coverage updated from primary vendor sources (postgresql.org, learn.microsoft.com, tc39.es, cppreference, dart.dev, …). Two brand-new lexers — **Plain Text** and **CSV / TSV** — replace previous monochrome fallbacks. Markdown / YAML / CSS palettes refreshed across Light + Dark + Monokai (Markdown H1–H6 contrast gradient, inline-code chip paper-tint, YAML unquoted-value tint, Markdown prose softening, CSS pseudo-class branch). New `src/sql_keywords.h` carries comprehensive SQL keyword union for **six dialects including DuckDB** (T-SQL / PG / MySQL / DuckDB / SQLite / Oracle) — MERGE, RETURNING, LATERAL, JSONB, OVER PARTITION BY, WITHIN GROUP, OPENROWSET, ASOF JOIN now all paint as keyword in every `.sql` tab. New `src/lang_keywords.h` carries primary-source keyword constants for ~50 languages wired via `populateExtraKeywords()` in `lexerutils.cpp` immediately after `setLexer()`. **11 concrete keyword bugs fixed** across R (`repeat`+`return`), Groovy (`yields`→`yield`+`volatile`+`this`), Crystal (`next`+`until`), Dart (`Record`+`augment`), GDScript (`@rpc`+`@tool`+`@warning_ignore`+`namespace`+`Rect2i`+`Vector4i`), Solidity (`blockhash`+`blobhash` for EIP-4844), Mojo (`ref`), Julia (`outer`+`public`+`Float16`), F# (`ValueOption`+`ValueTuple`), Protobuf (WKT siblings), HCL (template directives). **74 sample files** in `samples/` (one rich exemplar per supported lexer, all synthetic — no PII). **Test infrastructure hardened**: three previously-stale "Not Run" tests (`test_network_policy`, `test_chart_types`, `test_fontpack`) wired into `notepatra_all_tests` meta-target. **31/31 ctest pass** (was 28/31). Hard-cap `paint()` closure pattern codified as memory rule for all future custom Scintilla lexers. |
| [**v0.1.83**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.83) | 2026-05-14 | **Stale-version-ref sweep + release-check gate.** v0.1.82 shipped the security hardening sweep cleanly, but the website had eleven user-facing strings still pointing at v0.1.81 (hero badge, sticky download CTA aria-label + visible text, main download section label, both "Get Notepatra v…" buttons, JSON-LD FAQ "Latest v0.1.81 download sizes" + "as of v0.1.81", page body "As of v0.1.81: 226 file types" lead, lexer paragraph). This release: sweeps all eleven, swaps the latest release card from v0.1.82 → v0.1.83, AND wires a stale-version-ref scanner into `scripts/stale-text-check.sh` so `release-check.sh` fails when user-facing version strings drift. The check uses a `__V__` placeholder substituted twice (once with current version literal, once with `0\.1\.[0-9]+` regex) and compares match counts on each enumerated phrase. Older versions in CHANGELOG / release-notes / past release-card descriptions are untouched. No C++ / Rust changes — same binary as v0.1.82, all security hardening (install-script hard-fail SHA, cosign verify, 38/38 actions SHA-pinned, AI Base URL validation, credscrub patterns) carries forward unchanged. 31/31 ctest pass. Memory rule promoted from "remember to sweep" → "the gate enforces sweep" (the canonical example of memory-to-gate promotion). |
| [**v0.1.82**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.82) | 2026-05-14 | **Security hardening sweep + tab-numbering fix.** Outcome of a deep audit across 6 attack surfaces. **Install scripts hard-fail SHA**: `docs/install.sh` + `docs/install.ps1` previously soft-failed (silently skipped verification) if the `SHA256SUMS` fetch returned a network error — an MITM that blocked just the sums file would bypass verification. Both now refuse to install if sums are unreachable or the artifact is missing from them. **Cosign verification automatically run** by install scripts and the in-app auto-updater when `cosign` is on `PATH`, with the cert-identity pinned to the literal release workflow + tag (was a permissive regex matching any workflow in the repo). **All 38 of 38 GitHub Actions SHA-pinned** (was 0/38 — including `dtolnay/rust-toolchain@stable` which was on a branch ref the action owner could fast-forward at any time). **New `install-canary.yml`** workflow diffs the served `notepatra.org/install.{sh,ps1}` against repo daily; opens an issue on drift. **AI Base URL validation** in `src/preferences.cpp` rejects malformed URLs, plain-http public hosts (API key would travel in plaintext), and warn-confirms non-vendor hosts (closes a known "use this faster mirror" phishing pattern). **Credential scrubber** adds Cloudflare, DigitalOcean, npm, Twilio, Azure `AccountKey=`, GCP service-account, HTTP auth-header patterns. **Tag protection ruleset** on `refs/tags/v*`; **Dependabot security updates enabled**. **`release-check.sh`** gains `cargo clippy -D warnings` + `cargo fmt --check` + `cargo audit --deny warnings` as required gates. **Tab-numbering fix** in `src/mainwindow.cpp`: `updateTabTitle()` used to re-derive the name from `index + 1` on every modification event (closing "new 1" made the next keystroke in the surviving "new 2" rename it to "new 1"); `m_newCount` reset on every launch so session restore brought back "new 5" but the next `Ctrl+N` created "new 2". Fixed by dynamic max-scan in `newFile()` + preserve-existing-name in `updateTabTitle()`. **`SECURITY.md`** reconciled with the live ruleset reality. 31/31 ctest pass. All v0.1.81 fixes carry forward unchanged. |
| [**v0.1.81**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.81) | 2026-05-14 | **Polish + housekeeping. Linux in-app updater dialog now matches the downloaded file type; deep dependency refresh.** `src/updater.cpp::installReleaseInteractive()` Linux branch was hard-coded to say *"move the new AppImage into place"* regardless of what was downloaded. We ship the `.AppImage` for Linux x86_64 only — on **Linux ARM64** the picker falls back to the `.tar.gz` at priority 30, so ARM64 users were told to move an AppImage they didn't have. (The original symptom in issue #12 was reported against v0.1.17, which shipped no AppImage at all — same fallback path.) Now `.appimage` gets the original wording plus a `chmod +x` reminder; `.tar.gz` / `.tgz` / `.tar.xz` gets a copy-paste-ready `tar xzf … && mv notepatra ~/.local/bin/` example; anything else gets a generic fallback. Closes issue #12 finding 2. (Subtle note: the dialog is rendered by the *currently-running* binary, so ARM64 users still see the old "AppImage" text on v0.1.80 → v0.1.81; the fix kicks in from v0.1.81 → v0.1.82. Linux x86_64 users get the AppImage path — correct text both before and after.) **GitHub Actions matrix bumped past the Node 20 cliff**: `actions/checkout` v4 → v6 (#5), `actions/download-artifact` v4 → v8 (#4), `github/codeql-action` v3 → v4 (#8). Same 51 signed artifacts, same cosign + SLSA guarantees. **RustCrypto family to 0.11**: `md-5`, `sha1`, `sha2` all 0.10 → 0.11 (#6 / #7 / #11). The 0.10 → 0.11 release moved the digest output from `GenericArray` to `Array` (no longer impls `LowerHex`); `compute_hash()` updated to use a small `hex_encode()` helper. **MD5/SHA-1/SHA-256/SHA-512 hex output is byte-identical to v0.1.80.** **`sqlformat` 0.3.5 → 0.5.0** (#9) with `..FormatOptions::default()` for future-proofing. **`libc` 0.2.183 → 0.2.184** (#10). Plus `cargo fmt` sweep (191 LoC, 5 files, pure whitespace) and four pre-existing `cargo clippy -- -D warnings` fixes (`explicit_auto_deref`, `if_same_then_else`, `redundant_closure`, two `collapsible_match`). 130/130 cargo tests + 31/31 ctest still green. All v0.1.80 fixes carry forward unchanged. |
| [**v0.1.80**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.80) | 2026-05-14 | **Two paper-cut fixes: Windows `.txt` file icons + Search Clear button no longer hides the ✕.** `installers/windows.wxs` — `` now sets `Icon="NotepatraExe" IconIndex="0"`, generating the missing `HKCR\Notepatra.Document\DefaultIcon\(Default) = "...\notepatra.exe,0"` registry value. Pre-v0.1.80 the MSI registered the ProgId tree but without `DefaultIcon`; for `.txt` specifically Windows has a special-cased fallback to the cached `txtfile`/Notepad icon, so `.txt` files kept the old Notepad icon after Notepatra was set as default (every other extension flipped correctly). Now matches what the sideloaded `installers/register-associations.bat` already wrote. `src/searchresults.cpp::clear()` — clicking **Clear** in the Project-Search results header no longer hides the ✕ close button. Pre-v0.1.80 it hid both, collapsing two distinct user actions (Clear = wipe contents · ✕ = dismiss panel) into one state with no recovery path — empty panel pinned open with no way to dismiss. Only the Clear button hides itself now (nothing left to clear); the ✕ stays visible. All v0.1.79 focus-handoff fixes carry forward unchanged. |
| [**v0.1.79**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.79) | 2026-05-14 | **Double-click-from-file-manager focus handoff fix — Linux X11 and Windows.** Targeted patch on top of v0.1.78 — no editor, AI, or core changes. Notepatra is single-instance: when you double-click a file with it already running, the second process forwards the path over the local IPC socket and exits. Pre-v0.1.79, the new tab opened in the background while the file manager stayed focused, and on Linux a busy-cursor spinner ticked until the WM's 15 s timeout. **Linux X11 fix**: `src/mainwindow.cpp::handleRemoteOpen` now ports wmctrl's three-part `activate_window` sequence — `_NET_ACTIVE_WINDOW` (source=2 / pager) + `xcb_map_window` + `xcb_configure_window(STACK_MODE_ABOVE)` + round-trip fence (`xcb_get_input_focus_reply`) before disconnect. The `xcb_configure_window` ConfigureRequest path bypasses Cinnamon/Muffin's focus-stealing prevention which was demoting plain activate ClientMessages to `_NET_WM_STATE_DEMANDS_ATTENTION`. `StartupNotify=false` in the generated `.desktop` stops the infinite spinner. Spec-compliant `remove: ID=""` startup-notify message sequence also wired in `src/main.cpp::sendStartupNotifyComplete` for other DEs that respect the protocol. **Windows fix**: second-instance process calls `AllowSetForegroundWindow(ASFW_ANY)` before exiting so the running instance's `SetForegroundWindow()` succeeds instead of just flashing the taskbar — Explorer hands foreground rights to the newly spawned process, not the running one, so we surrender them before exit. Belt-and-braces TOPMOST flip guarantees z-order. `handleRemoteOpen` signature extended to forward `DESKTOP_STARTUP_ID` (captured before `QApplication`'s constructor strips it from the env) for `_NET_STARTUP_ID` property handoff. `libxcb` linked explicitly on Linux. All v0.1.78 encoding fixes carry forward unchanged. 31/31 tests pass. |
| [**v0.1.78**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.78) | 2026-05-13 | **Encoding & file-open fixes — UTF-16 / UTF-32 BOM parity with Notepad++.** Reordered BOM detection in `rust-core/src/file_io.rs` so UTF-16 LE text (50 % nulls by design — SQL Server `Generate Scripts`, `sqlcmd -o`, PowerShell `Out-File`, Java `-Dfile.encoding=UTF-16`) is no longer mis-flagged as binary. UTF-32 LE/BE detected before UTF-16 LE so the shared `FF FE` prefix doesn't collide. No-BOM UTF-16 sniffed via even/odd null-column ratio (matches Notepad++/uchardet). Manual UTF-32 decoder added (encoding_rs intentionally doesn't ship one). `src/editor.cpp` save path now preserves UTF-16 / UTF-32 BOMs on round-trip — pre-v0.1.78 the BOM was silently stripped because `QTextCodec("UTF-16LE")` emits no BOM. Encoding menu lists 4 new BOM variants: `UTF-16 LE BOM`, `UTF-16 BE BOM`, `UTF-32 LE BOM`, `UTF-32 BE BOM`. 11 new rust-core unit tests + new `rust_core_tests` ctest target wires `cargo test` into `release-check.sh`. 31/31 tests pass. |
| [**v0.1.77**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.77) | 2026-05-11 | **Expanded chart catalogue (4 → 12), hover tooltips, modal viewer + PNG export, AI picks the chart for the data.** 8 new chart types in `src/chartrender.cpp` — `area`, `horizontal-bar`, `stacked-bar`, `stacked-horizontal-bar`, `grouped-bar`, `donut`, `histogram`, `boxplot` — all via QtCharts so they work in both lite (~9 MB) and full builds. Histogram auto-bins a numeric column; boxplot computes 5-quantile per group. Multi-series specs (`grouped-bar`, `stacked-bar`, `stacked-horizontal-bar`) take `y` as array of column names. Rewrote Data Analyst system prompt with explicit data-shape → chart-type mapping so the AI picks the right chart instead of defaulting to bar. New `src/chart_modal.{h,cpp}` — every inline chart now has a ⛶ expand button; click → 960×640 modal with chart at full size + Save as PNG (HiDPI-correct, defaults to `~/Pictures/`) + Copy image (clipboard) + Close. Hover tooltips wired on every series — bars show category/value, line/scatter/area show x/y, pie/donut show label/value/percentage, boxplot shows full 5-quantile summary. New `test_chart_types.cpp` (26 sub-checks); updated `test_ai_dataanalyst.cpp` for the new 12-type catalogue. **30/30 ctest pass.** All v0.1.75 features (font-pack downloader, MSI Component-GUID fix, AI dock fixes, network policy allowlist) carry forward. |
| [**v0.1.75**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.75) | 2026-05-11 | **Runtime font-pack downloader — 27 premium open-source fonts on demand.** New `Settings → Manage Fonts…` dialog lists a curated catalogue of JetBrains Mono, Fira Code, Cascadia Code, Source Code Pro, IBM Plex Mono, Hack, Geist Mono, Inconsolata, Roboto Mono, Fira Mono, Noto Sans Mono, Space Mono, Anonymous Pro, Victor Mono, Comic Mono, Inter (variable), Roboto, Manrope, Source Serif 4 (variable), Merriweather — every entry SIL OFL 1.1 / Apache 2.0 / MIT, grouped by category (Code · Monospace / UI · Sans-serif / Serif · Prose / Display · Distinctive). Pick rows, click *Install*, dialog downloads each TTF / OTF from its pinned upstream HTTPS URL to `~/.local/share/notepatra/fonts/` and registers it with `QFontDatabase` immediately — no restart. **Bare binary stays at ~9 MB** because nothing is bundled; same on-demand pattern as the Charts Pack / DuckDB extensions. **HTTPS-only manifest** enforced by `test_fontpack.cpp` so network attackers can't swap bytes. **Air-gapped friendly**: drop TTFs into the font-pack directory manually; startup hook (`NotepatraFontPack::loadInstalledFonts()`) scans on every launch. New files: `src/fontpack.{h,cpp}` (~300 LoC manifest + Installer queue), `src/fontpack_dialog.{h,cpp}` (Qt5 dialog), `test_fontpack.cpp` (23 sub-checks). 29/29 ctest pass. All v0.1.74 fixes carry forward unchanged. |
| [**v0.1.74**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.74) | 2026-05-11 | **`notepatra-local-ai` MSI upgrade fix + website cleanup.** Targeted patch on top of v0.1.73 — no editor, AI, or core changes. Fixes the Windows MSI upgrade flow for the `notepatra-local-ai` (cloud-free) flavor: when users had both regular and local-ai installed side-by-side, upgrading local-ai from v0.1.72/v0.1.73 dropped into the Repair/Remove maintenance UI instead of running MajorUpgrade. Root cause: three hardcoded Component GUIDs (`MainExecutable` / `ApplicationShortcut` / `DesktopShortcut`) were shared between both flavors' MSIs — Windows Installer reference-counted them as the same component, so the upgrade couldn't release v0.1.72/v0.1.73 components while the regular install's reference held them. Fixed by switching all three to `Guid="*"` (WiX auto-generates a deterministic GUID from each component's KeyPath, which differs by `INSTALLFOLDER` between flavors). Also added `AllowSameVersionUpgrades="yes"` to `` so re-running same-version MSIs runs install flow instead of maintenance UI. **Website cleanup**: `docs/index.html` no longer shows slim "horizontal line" rows for older releases — only the latest detail card remains, plus the single "See every release on GitHub" link. v0.1.0–v0.1.73 live exclusively on GitHub Releases. 82-line deletion. **Deferred to v0.1.75**: runtime font-pack downloader (Settings → Manage Fonts… with ~25 premium open-source fonts fetched on demand). All other features carry forward from v0.1.73. |
| [**v0.1.73**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.73) | 2026-05-11 | **AI dock blank-on-reopen fix (patch on v0.1.72).** Two coordinated fixes for the close → reopen flow. The red ✕ close button in the panel header now routes through `MainWindow::setAiDockVisible(false)` (via a new `closeDockRequested` signal) instead of poking `parentWidget()->setVisible(false)` directly — pre-fix the × bypassed `Config::aiDockVisible` persistence, the toolbar button's checked state, and the splitter rebalance bookkeeping, so subsequent re-opens via the toolbar sometimes showed a 0-px-wide blank dock. Additionally `rebalanceAiDockSplit()` now detects "collapsed slot" (width ≤ 40 px) and re-applies the 60/40 split even when `m_aiDockSizedOnce` is true — pre-fix the bailout protected against clobbering mid-session user drags but also blocked the rescue path after a full hide → show cycle. Two new regression scenarios (`test_ai_fullscreen_exit.cpp` S16 + S17): hide-show round-trip width assertion + ✕ close → toolbar reopen round-trip. 28/28 ctest pass on the lite build, 53 sub-checks in `test_ai_fullscreen_exit` (up from 47 in v0.1.72). Installer matrix from v0.1.72 carries forward unchanged. |
| [**v0.1.72**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.72) | 2026-05-11 | **Enterprise-ready Linux installers + cloud-free `notepatra-local-ai` build.** Notepatra now ships `.deb` for Debian/Ubuntu (x64 + ARM64), `.rpm` for Fedora/RHEL/CentOS/Rocky/Alma (x64 + ARM64), and a universal `Notepatra-0.1.72-x86_64.AppImage` for Arch / openSUSE Tumbleweed / Manjaro / any glibc 2.38+ distro. All three formats install to `/opt/notepatra/` with symlink at `/usr/bin/notepatra`, hicolor icons across all sizes, full `.desktop` registration, and bundled QScintilla 2.14.1 so the same upstream binary runs across distro packaging differences. Admins push silently via `apt install ./*.deb` / `dnf install ./*.rpm` / Ansible-friendly. **`notepatra-local-ai` cloud-free flavor** (built via `-DNOTEPATRA_NO_CLOUD=ON` CMake flag, shipped as `notepatra-local-ai_0.1.72_*_.deb`) — the binary physically cannot reach `api.openai.com` / `api.anthropic.com` / `api.mistral.ai` / `generativelanguage.googleapis.com` / `openrouter.ai` / `api.groq.com` / `api.together.xyz` / `api.deepseek.com` / `api.cohere.com` / `api.x.ai` / any other public LLM endpoint. Every `QNetworkAccessManager` request goes through `NotepatraNetworkPolicy::isPrivateNetworkHost()` (49-case unit-tested allowlist of loopback / RFC1918 / CGNAT-100.64/10 / IPv6 ULA fc00::/7 / `.local`/`.lan`/`.internal`/`.intranet`/`.corp`/`.home` suffixes). The cloud-URL paste box is stripped from the AI panel; the Backend dropdown only shows Ollama + llama.cpp. `apt` Conflicts ensures `notepatra` and `notepatra-local-ai` can't coexist. `notepatra --version` self-identifies as `Notepatra v0.1.72 (cloud-free / local-ai)` so users can verify. Ollama, llama.cpp, LM Studio, Jan, vLLM, self-hosted Ollama on the LAN — all continue to work. For regulated industries (finance / healthcare / legal / gov), data-sovereignty regions (EU / India / China), air-gapped fleets. New files: `src/network_policy.{h,cpp}` (~95 LoC, 49-case unit test), `installers/debian/build-deb.sh`, `installers/rpm/{notepatra.spec.in, build-rpm.sh}`, `installers/appimage/build-appimage.sh`. 28/28 tests pass on both regular and cloud-free builds. |
| [**v0.1.71**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.71) | 2026-05-11 | **AI Interaction Log — audit every cloud + local LLM exchange.** `Tools → AI Interaction Log…` opens a viewer onto `~/.config/notepatra/ai-logs/interactions.db` (SQLite, WAL mode) that records every cloud (OpenRouter, OpenAI, Azure OpenAI, Ollama Cloud) + local (Ollama, llama.cpp, LM Studio / Jan / vLLM via OpenAI-compat) call: timestamp, session id, backend tag, model, mode (chat/coding/data), role (user/system/assistant/tool_call/tool_result), full content, tool name + args + result, prompt + eval tokens, elapsed ms, error string. Rows older than 7 days are pruned on every app start; DB file capped at 50 MB. Viewer dialog has backend/mode/model filters, row-click → full content panel, **Export JSON** (up to 10,000 events), **Prune now** button, and a **Toggle "Log AI interactions"** for in-place opt-out. **`Config::aiInteractionLogging` default ON** — privacy-as-transparency by default, flip off anywhere and the recorder becomes a no-op (DB file isn't even opened). **Credential scrubber** before every write masks `Bearer …`, OpenAI `sk-…`, Anthropic `sk-ant-…`, GitHub PATs (`ghp_/ghs_/gho_/ghu_/ghr_…`), AWS `AKIA…`, Google `AIza…`, and `-----BEGIN ... PRIVATE KEY-----` PEM blocks. No network egress — purely local SQLite. New `OllamaClient::setMode("chat"\|"coding"\|"data")` lets the panel tag each turn for filter purposes. Records at every `responseStats` emit site (Ollama `/api/generate` + `/api/chat` done frame, OpenAI-compat `[DONE]` frame, OpenAI-compat `finish_reason` frame); each resolves the backend tag from `m_baseUrl` (`openai.azure.com` → `azure-openai`, `api.openai.com` → `openai`, `ollama.com` → `ollama-cloud`, `openrouter.ai` → `openrouter`, else `openai-compat`). New files: `src/ai_interaction_log.{h,cpp}` (~280 LoC), `src/ai_log_dialog.{h,cpp}` (~250 LoC). 27/27 tests pass. |
| [**v0.1.70**](https://github.com/singhpratech/notepatra/releases/tag/v0.1.70) | 2026-05-11 | **AI cleanup + Notepad++-style session persistence + Data Mode actually shows what's attached.** Closing the app no longer prompts — every open buffer (file-backed, untitled, modifie
