I recently launched Claspt, a desktop app that combines markdown note-taking with AES-256 encrypted secret storage. This post covers the technical decisions behind it — what worked, what didn't, and what I'd do differently.
Why Tauri over Electron
The numbers tell the story:
- Bundle size: ~5MB vs ~200MB
- Memory at idle: ~40MB vs ~150MB
- Startup time: <1s vs 2-3s
- Backend: Rust (native speed) vs Node.js
Tauri 2.x gives you a Rust backend with a WebView frontend. The frontend is React + TypeScript + Tailwind. The backend handles everything performance-sensitive: encryption, file I/O, full-text search, Git operations.
The trade-off: WebView rendering varies slightly across platforms (especially font rendering and scrollbar behavior). And the ecosystem is younger — fewer plugins, smaller community, more DIY.
Worth it? Absolutely. Users notice the speed difference immediately.
Encryption Architecture
The key hierarchy:
- Master password → Argon2id (64MB memory, 3 iterations, 32-byte salt) → Master key (256-bit)
- Master key encrypts/decrypts individual secret blocks
- Each secret block: AES-256-GCM with unique 96-bit nonce
- Master key stored in
vault.key(encrypted with itself — bootstrapped from password)
Why per-block encryption instead of encrypting the whole file?
- Markdown content stays plaintext → readable in any editor, searchable, git-diffable
- Only the sensitive parts are encrypted
- Each block has its own nonce → compromising one block doesn't help with others
- Labels stay visible for organization →
:::secret[AWS Access Key]is plaintext, the value inside is ciphertext
The Argon2id parameters (64MB, 3 iterations) are based on OWASP recommendations. On a modern machine, key derivation takes ~200ms — imperceptible on unlock, painful for brute force.
Search Engine: tantivy
I considered three options:
- SQLite FTS5: Simple, embedded, works everywhere. Used this on mobile.
- tantivy: Rust-native, Lucene-like, field-level boosting. Used this on desktop.
- Custom inverted index: Maximum control, maximum effort. Rejected.
tantivy won for desktop because:
- Field-level boosting: title (3x), tags (2x), secret labels (2x), content (1x)
- Sub-100ms search across thousands of documents
- Rust-native = no FFI overhead, compiles with the rest of the backend
- Incremental indexing on save
Critical design decision: secret values are never indexed. The search index only contains titles, tags, labels, and non-secret content. Even if someone extracts the search index files, no secret values are exposed.
The MCP Server
This is the feature I'm most excited about. Claspt exposes a Model Context Protocol (MCP) server on localhost. AI tools like Claude Code, Cursor, and Windsurf can connect to it and use your vault as persistent memory.
How it works:
- MCP server runs on a configurable local port
- Two-tier token auth: notes-only token (read/write notes) and secrets token (can also read secrets)
- AI tools connect via the MCP protocol and get tools like
read_page,search,create_page - Your AI assistant can store and retrieve information across sessions
Use case: "Remember this deployment procedure for next time" → stored as a note in your vault, available in every future conversation.
Markdown-First: Why .md Files, Not a Database
The vault is literally a folder:
~/Claspt/
general/
my-note.md
credentials/
aws-setup.md
.securenotes/
config.json
vault.key
index/
Each page is a standalone .md file with YAML frontmatter. This means:
- No vendor lock-in: Your notes are readable without Claspt
- Git-friendly: Every save auto-commits. Full version history for free.
- Backup-friendly: It's a folder. rsync, Time Machine, whatever you use.
- Sync-friendly: Git remotes, Google Drive, Dropbox — anything that syncs folders works.
The trade-off: no relational queries, no structured data beyond frontmatter. But for a personal vault, folder + search is enough.
What I'd Do Differently
- Start with @dnd-kit from day one. HTML5 drag-and-drop doesn't work in Tauri's WebView. Wasted time debugging before switching to pointer events.
- Design the config system earlier. Settings grew organically and the config struct is now 30+ fields. Should have used a more modular approach.
- Write the browser extension in parallel. It's the most-requested feature and designing it after the desktop app means some architectural retrofitting.
Try It
Free forever on desktop. No account required.
- Website: https://claspt.app
- Security model: https://claspt.app/security/
- Docs: https://docs.claspt.app
The code is Rust + TypeScript. If you're building with Tauri, happy to discuss architecture decisions in the comments.
Top comments (0)