- Rust 48%
- TypeScript 34%
- CSS 10%
- JavaScript 3.2%
- Shell 2.3%
- Other 2.5%
| .agents/skills | ||
| .claude | ||
| .direnv/bin | ||
| docs | ||
| public | ||
| scripts | ||
| src | ||
| src-tauri | ||
| .editorconfig | ||
| .gitignore | ||
| .mcp.json | ||
| AGENTS.md | ||
| bun.lock | ||
| CLAUDE.md | ||
| components.json | ||
| CONTRIBUTING.md | ||
| eslint.config.mjs | ||
| flake.lock | ||
| flake.nix | ||
| LICENSE.md | ||
| next.config.ts | ||
| obsidian-assistant-full-roadmap.md | ||
| package.json | ||
| postcss.config.mjs | ||
| README.md | ||
| README.old.md | ||
| skills-lock.json | ||
| THIRD_PARTY_LICENSES.md | ||
| TODO-deferred.md | ||
| TODO.md | ||
| tsconfig.json | ||
| turbo.json | ||
| versions.json | ||
PKMA — Personal Knowledge Management Assistant
A local-first, AI-powered desktop assistant for your Obsidian vault.
Chat with your notes, search them semantically, and let an agent answer questions against your own writing — without anything leaving your machine.
Table of Contents
- Why PKMA
- Features
- Screenshots
- Tech Stack
- Architecture
- Getting Started
- Configuration
- Roadmap
- Status
- Contributing
- License
Why PKMA
Most "chat with your notes" tools require uploading your knowledge base to a third-party cloud, locking you into one model vendor, or running a heavy server stack. PKMA takes the opposite approach:
- Local-first. Your vault, your index, your provider — all on your machine.
- Provider-agnostic. Bring your own model: Ollama, LM Studio, OpenRouter, or any OpenAI-compatible endpoint, for both chat and embeddings.
- Desktop-native. A single Tauri binary. No Electron, no Docker, no Python service.
- Built for Obsidian. First-class understanding of wikilinks, frontmatter, tags, and the standard
.mdvault layout — plus optional live tools backed byobsidian-clifor fresh task / property / daily-note state.
If you write in Markdown and want a research partner that actually reads your notes, PKMA is for you.
Features
- Conversational vault search — ask in natural language; the agent retrieves, synthesises, and cites notes with clickable
[[Wikilink]]pills. - Hybrid retrieval (
vault_search) — FTS5 full-text and semantic vector search fused with reciprocal-rank fusion. - Agent modes —
Fast,Normal(default), andDeep Research, each with its own tool budgets and retrieval caps. Per-thread override. - Tool backend toggle — switch the search / read / tags surface between the SQLite index (default) and live
obsidian-clitools when configured. - Streaming responses — token-by-token SSE streaming with live tool-call status and thinking-step indicators.
- Wikilink graph awareness — petgraph-backed link traversal (
graph_neighbors, depth 1-3). - Incremental indexing — file watcher with blake3 content-hash dedupe; only changed notes get re-embedded. Quarantine for files the parser can't handle, so they don't cycle through "changed" forever.
- Multi-vault — switch between vaults; each gets its own isolated SQLite + sqlite-vec database. Cancellation-aware vault switching cleanly aborts in-flight indexing.
- Wikilink resolution —
POST /notes/lookupresolves wikilinks with exact / FTS / LIKE fallbacks; the frontend renders match quality on each pill. - Theming — light / dark, four-step typography scale, OKLCH-based design tokens.
Screenshots
Screenshots and demo GIFs coming with the first tagged release. See
docs/design.mdfor the shipped UI spec anddocs/inspo/for reference imagery.
Tech Stack
| Layer | Stack |
|---|---|
| Desktop shell | Tauri v2, Rust 1.82+ |
| Frontend | Next.js 16 (App Router, static export), React 19 (Compiler), TypeScript 5 |
| UI | Handcrafted CSS with OKLCH design tokens; Tailwind v4 and shadcn/ui available for select pieces; Phosphor icons |
| State / data | Custom hooks (useChat, useShell) + TanStack Query (useSettings, useIndexer) |
| Backend (in-process) | Axum on 127.0.0.1:8008, Tokio, Tower, SSE streaming |
| LLM orchestration | Rig — agent loop, tool dispatch, streaming |
| Storage | SQLite (rusqlite, bundled) + FTS5 + sqlite-vec |
| Embeddings | HTTP client against any Ollama / OpenAI-compatible embedding endpoint (default: nomic-embed-text) |
| Vault parsing | obsidian-parser, gray_matter, petgraph |
| Indexing | notify + notify-debouncer-mini (file watching), blake3 (content hashing), walkdir |
| Optional live vault tools | obsidian-cli — backlinks, properties, tasks, outline, daily note, aliases, vault health |
Architecture
PKMA is a single Tauri binary running two things in the same process:
- A Rust core that boots an Axum HTTP server on
127.0.0.1:8008. It owns the per-vault SQLite index (metadata + FTS5 + sqlite-vec), an HTTP-backed embedding client, the file watcher + incremental indexer, and the Rig-based agent loop. - A Next.js 16 webview (statically exported) that talks to the local server over HTTP + SSE.
┌──────────────────────────────────────┐
│ Tauri webview │
│ Next.js 16 (static export) │
│ React 19 + handcrafted OKLCH shell │◄──── HTTP / SSE ────┐
└──────────────────────────────────────┘ │
▼
┌──────────────────────────────────────────────┐
│ Axum @ 127.0.0.1:8008 │
│ /chat /title (SSE, Rig agent) │
│ /models /model/info /settings │
│ /vaults* /notes/lookup /vault/stats │
│ /index /index/events /index/state │
└──────────────────────────────────────────────┘
│ │ │ │
▼ ▼ ▼ ▼
VaultDb EmbedModel File watcher LLM provider
(SQLite + (HTTP, any (notify + (Ollama /
FTS5 + OpenAI-compat blake3 hash LM Studio /
sqlite-vec) embed API) diff) OpenRouter /
custom)
VaultDb (src-tauri/src/db/pool.rs) is a pool of 4 read-only connections + 1 writer, all running inside tokio::task::spawn_blocking so the chat hot path never blocks a Tokio worker on a SQLite lock.
See docs/architecture.md for the full system design and AGENTS.md for the working repo conventions.
Getting Started
Prerequisites
- Rust ≥ 1.82 (rustup.rs)
- Node.js ≥ 20 and Bun (bun.sh) — Bun is preferred; npm works too
- Platform deps for Tauri v2 — see Tauri prerequisites (WebKitGTK on Linux, WebView2 on Windows, Xcode CLT on macOS)
- An LLM endpoint — local (Ollama, LM Studio) or remote (OpenRouter / any OpenAI-compatible)
- An embedding endpoint — the same provider almost always provides one. Default model:
nomic-embed-text(768 dims, served by Ollama). - An Obsidian vault — or any folder of Markdown files.
- (Optional)
obsidian-clionPATHto enable the live Obsidian tool set (backlinks,properties,tasks,outline,daily_read,vault_health,aliases).
Install
git clone ssh://git@git.hegdeatri.com:2222/hegdeatri/pkma-rs.git
cd pkma-rs
bun install
Run (desktop app)
bunx tauri dev
This starts the Next.js dev server and launches the Tauri window pointed at it.
Run (frontend only, against a live backend)
bun dev # Next.js dev server on :3000
The frontend will talk to http://localhost:8008. Run bunx tauri dev (or a separately-started backend) alongside if you want a working chat surface.
Build
bunx tauri build # Production desktop binary (in src-tauri/target/release/bundle/)
bun run build # Frontend static export only
Other useful commands
bun run lint # ESLint
cd src-tauri && cargo test # Rust tests
cd src-tauri && cargo clippy # Rust linter
cd src-tauri && cargo build # Backend-only build
Configuration
On first launch, configure PKMA from the in-app Vaults and Models sections:
- Add a vault — any folder containing
.mdfiles. The watcher picks it up immediately; an incremental index runs in the background and reports progress in the Telemetry panel. - Set your provider — base URL, API key (if needed), chat model, and embedding model. Anything speaking the OpenAI chat-completions wire format works for chat; for embeddings, either Ollama (
POST /api/embed) or OpenAI-compatible (POST /v1/embeddings). - (Optional) Choose defaults —
default_agent_modeanddefault_tool_backendlive in settings; per-thread overrides apply on top.
Settings persist via tauri-plugin-store under the app's data directory.
Roadmap
The original implementation plan lives in obsidian-assistant-full-roadmap.md. Active work items are tracked in TODO.md; deferred ideas in TODO-deferred.md. Design specs for major slices live under docs/superpowers/specs/.
Already shipped:
- Hybrid retrieval (
vault_search) with RRF fusion of FTS5 + semantic. - Agent modes (
Fast/Normal/Deep Research) with per-mode budgets. - Tool profiles, including live Obsidian CLI tools when configured.
- Incremental indexing with content-hash dedupe, parser-quarantine, and cancellation-aware vault switching.
- Wikilink resolution endpoint with exact / FTS / LIKE match quality, surfaced as pill states in the UI.
- Per-thread tool-backend and agent-mode overrides.
Highlights of what's next:
- Note authoring — agent-assisted writing and refactoring of existing notes.
- Plugin surface — user-extensible tools.
- More live Obsidian operations — writes and structured edits, not just reads.
- Polish slices — see
TODO.mdTier 1–3 for the current punch list.
Status
Alpha — not yet recommended for daily use.
PKMA is under active development. APIs, on-disk schemas, and settings shape may change between commits. The index can be safely rebuilt at any time, but expect rough edges.
Contributing
Contributions, bug reports, and design feedback are welcome.
Before opening a pull request or issue, please read CONTRIBUTING.md for:
- the development setup and lint / test commands,
- the architecture conventions (see also
AGENTS.mdanddocs/architecture.md), - the commit-message style used in this repo,
- how to propose larger changes (open an issue first).
If you're filing a bug, include your OS, the PKMA commit hash, and steps to reproduce. If you're proposing a feature, describe the user problem first — implementation second.
License
PKMA is source-available software under the PKMA Personal Use License — see LICENSE.md.
In short: personal, non-commercial use of the unmodified software is permitted; commercial use, enterprise use, reselling, redistribution, and derivative works are not. This is not an OSI-approved open-source license. For commercial licensing inquiries, please open an issue or contact the maintainer.
PKMA incorporates third-party components under their own (mostly permissive) licenses. See THIRD_PARTY_LICENSES.md for the full attribution list and verbatim license texts. The notices file is generated by scripts/generate-notices.sh and should be regenerated before each release.