A terminal UI for browsing and managing Obsidian vaults -- featuring vim keybindings, rich markdown rendering, fuzzy search, graph view, and AI-powered chat, search, and suggestions.
Built with Ink (React for CLI) and TypeScript. Zero AI SDK dependencies -- all LLM calls use raw fetch().
- Tree-style sidebar with folder expand/collapse
- Note preview pane with fade effect
- Fuzzy finder (name, content, and semantic search)
- Tag browser with two-pane drilldown
- Backlinks panel with context snippets
[[Wiki-link]]following with overlay selector- Content search with context lines
- Command palette (Ctrl+K)
- Bookmarks with reorder support
- Note pinning (pinned notes always visible at top of sidebar)
- Full inline formatting: bold, italic,
code,strikethrough, ==highlight== - Tables, fenced code blocks with language labels
- 20+ callout types with unicode icons (note, tip, warning, danger, etc.)
- Word wrapping that preserves inline formatting
- Heading color hierarchy
- Three modes: normal, insert, visual
- Full motion support:
h/j/k/l,w/b/e,0/$,^,gg/G,%,f/F - Operators with motions:
d,c,y(e.g.dw,c$,yy) - Line operations:
o/O,J,p/P,x/X,r - Numeric count prefixes (e.g.
5j,3dw) - Visual mode with selection highlight
- Undo/redo (
u,Ctrl+R) - Dot repeat (
.) - Command mode:
:w,:q,:wq,:q!,:<line> - Block/line cursor styles per mode
- ASCII graph with circular layout and Bresenham line drawing
- Global graph (all notes and links) and local graph (current note's connections)
- Node selection, focus mode, toggle between local/global
- Empty state handling
- RAG Chat (Ctrl+Y): Ask questions about your vault with
[[source]]citations - Note Summarization (
s): 2-4 sentence summaries, cached by content hash - Tag & Link Suggestions (
S): Accept withato write directly to frontmatter/note - Semantic Search: Ctrl+S cycles name -> content -> semantic (with 300ms debounce)
- Similar Notes (Ctrl+N): Find related notes by cosine similarity
- Note Generation: Create new notes from a description via command palette
- Daily AI Brief: Auto-generates daily note content from recent vault activity
- Persistent Chat History: Conversations saved, Ctrl+N new chat, Ctrl+H cycle history
Supports Anthropic (Claude), OpenAI, and Ollama (fully local) -- all via raw fetch() with SSE streaming.
- Create/open today's daily note (
d) - Navigate previous/next (
[/]) - Reads existing Obsidian daily-notes configuration
- Quick capture to Inbox.md (Ctrl+X)
- Pomodoro focus timer (start/stop via command palette, countdown in status bar)
- Kanban board view (Ctrl+B) -- scans checkboxes across notes into 3 columns
- Outline/TOC sidebar (
O) -- heading tree with level-based indentation - Navigation history (Ctrl+O back, Ctrl+I forward -- vim jumplist style)
- Templates with
{{title}}/{{date}}/{{time}}variable replacement - Auto-detects Obsidian config (daily notes, templates, periodic notes, templater)
- File watcher with 500ms debounce for auto-refresh on disk changes
- Help screen (
?) with full keybinding reference
- Node.js 20+ (use nvm to manage versions)
- A terminal with 256-color support
git clone https://github.com/atr0t0s/obsitui.git
cd obsitui
npm install
npm run build# Development (no build step)
npx tsx src/cli.tsx /path/to/your/vault
# After building
node dist/cli.js /path/to/your/vault
# Or link globally
npm link
obsitui /path/to/your/vaultIf no vault path is given, the current directory is used.
AI features are optional. Without configuration, all non-AI features work normally.
# For Anthropic (Claude) -- default chat provider
export ANTHROPIC_API_KEY="your-key"
# For OpenAI -- default embedding provider
export OPENAI_API_KEY="your-key"Create .obsitui.json in your vault root for more control:
{
"ai": {
"chatProvider": "anthropic",
"embeddingProvider": "openai",
"anthropicApiKey": "sk-...",
"anthropicModel": "claude-sonnet-4-20250514",
"openaiApiKey": "sk-...",
"openaiEmbeddingModel": "text-embedding-3-small",
"openaiChatModel": "gpt-4o-mini",
"ollamaUrl": "http://localhost:11434",
"ollamaChatModel": "llama3.2",
"ollamaEmbeddingModel": "nomic-embed-text"
}
}For a completely offline setup, configure both chat and embeddings to use Ollama:
{
"ai": {
"chatProvider": "ollama",
"embeddingProvider": "ollama",
"ollamaChatModel": "llama3.2",
"ollamaEmbeddingModel": "nomic-embed-text"
}
}Press Ctrl+E to build the embedding index. This is required for semantic search and similar-notes features. The index is stored in .obsitui-index/embeddings.json in your vault and updates incrementally.
| Key | Action |
|---|---|
? |
Toggle help screen |
/ or Ctrl+P |
Fuzzy finder |
Ctrl+K |
Command palette |
Ctrl+G |
Graph view |
Ctrl+S |
Cycle search modes (name/content/semantic) |
Ctrl+Y |
AI chat (RAG) |
Ctrl+E |
Build embedding index |
Ctrl+X |
Quick capture to Inbox |
Ctrl+B |
Kanban board |
Ctrl+R |
Refresh vault |
Ctrl+O / Ctrl+I |
History back / forward |
q |
Quit |
| Key | Action |
|---|---|
j/k |
Navigate |
Enter / l |
Open note / expand folder |
h |
Collapse / go to parent |
g / G |
Top / bottom |
d |
Daily note |
t |
Tag browser |
b |
Backlinks |
n |
New note |
m |
Bookmarks |
p |
Toggle preview |
B |
Toggle bookmark |
| Key | Action |
|---|---|
j/k |
Scroll |
g / G |
Top / bottom |
h / Esc |
Back to browse |
Tab |
Follow [[wiki-link]] |
i |
Inline vim editor |
e |
Edit in $EDITOR |
s |
AI summarize |
S |
AI suggestions |
O |
Toggle outline / TOC sidebar |
P |
Toggle pin note |
/ |
Search within note (n/N cycle matches) |
R |
Rename |
D |
Delete |
[ / ] |
Previous / next daily note |
| Key | Action |
|---|---|
Esc |
Normal mode / exit editor |
i / a / o / O |
Insert mode variants |
v |
Visual mode |
h/j/k/l |
Movement |
w / b / e |
Word motions |
0 / $ / ^ |
Line start / end / first non-blank |
gg / G |
Document start / end |
d+motion |
Delete (e.g. dw, dd, d$) |
c+motion |
Change (e.g. cw, cc, c$) |
y+motion |
Yank (e.g. yw, yy) |
p / P |
Paste below / above |
x / X |
Delete char forward / backward |
r+char |
Replace character |
J |
Join lines |
u |
Undo |
Ctrl+R |
Redo |
. |
Repeat last command |
f+char / % |
Find char / match bracket |
: |
Command mode (:w :q :wq :q! :<line>) |
Ctrl+S |
Save and exit |
| Key | Action |
|---|---|
j/k |
Select node |
Enter |
Open selected note |
f |
Focus on selected node |
l |
Toggle local / global |
Esc |
Close |
| Key | Action |
|---|---|
Ctrl+N |
New conversation |
Ctrl+H |
Cycle history |
Ctrl+W |
Delete conversation |
Ctrl+U / Ctrl+D |
Scroll up / down |
Ctrl+E |
Snap to bottom |
Esc |
Close |
| Key | Action |
|---|---|
h/l |
Switch columns |
j/k |
Navigate items |
Enter |
Toggle item status |
o |
Open source note |
Esc |
Close |
src/
cli.tsx # Entry point, arg parsing, $EDITOR lifecycle
App.tsx # Main app -- all state, keybindings, rendering
types.ts # Mode union type (19 modes)
theme.ts # Design system (violet/amber/teal palette, unicode icons)
hooks/
useTerminalSize.ts # Terminal dimensions
useFileWatcher.ts # fs.watch with debounce
usePomodoro.ts # Pomodoro timer hook
lib/
vault.ts # Vault scanner, note loading, link resolution
markdown.ts # Markdown parser + word wrap with inline formatting
fuzzy.ts # Fuzzy search (fzf-style scoring)
cache.ts # VaultIndex (tags, backlinks, content search)
editor.ts # Vim-style editor (pure functional, immutable state)
graph.ts # ASCII graph with circular layout
outline.ts # Heading extraction for TOC
daily.ts # Daily notes (create, navigate)
fileops.ts # File CRUD, $EDITOR integration
history.ts # Navigation history (back/forward)
bookmarks.ts # Bookmarks + pinning, persisted to .obsitui.json
templates.ts # Template detection + variable replacement
capture.ts # Quick capture to Inbox.md
pomodoro.ts # Pomodoro timer logic
kanban.ts # Kanban board from checkboxes
obsidian-config.ts # Reads .obsidian config files
ai/
provider.ts # Multi-provider (Anthropic/OpenAI/Ollama) via raw fetch
config.ts # Config from .obsitui.json + env vars
embeddings.ts # Vector index + cosine similarity
rag.ts # RAG chat with keyword fallback
summarize.ts # Note summarization + caching
suggest.ts # Tag/link suggestions, daily fill, note generation
chat-history.ts # Persistent chat conversations
components/ # 22 Ink (React) presentational components
tests/ # 20 test files, 301 tests
- Ink (React for terminal) -- components render via
<Box>and<Text>, styled with hex colors mapped to 256-color terminal palette - Single App.tsx -- all state management and key handling lives in one file; components are purely presentational
- Pure functional editor -- all
editor.tsoperations return newEditorStateobjects, no mutation - No AI SDK dependencies -- raw
fetch()to Anthropic/OpenAI/Ollama APIs with SSE streaming - ESM only --
"type": "module"in package.json,.jsextensions in imports - VaultIndex -- single-pass cache of all notes for tags, backlinks, and content search, with incremental updates
# Type check (must have 0 errors)
npx tsc --noEmit
# Run tests
npx vitest run
# Run a single test file
npx vitest run tests/editor.test.ts
# Watch mode
npx vitest301 tests across 20 files covering: vault scanning, markdown parsing, fuzzy search, vim editor (61 tests), graph building, daily notes, file operations, caching, bookmarks, templates, kanban, pomodoro, capture, outline, AI config, embeddings, summarization, and chat history.
obsitui reads your existing Obsidian configuration from the .obsidian/ folder:
- Daily notes -- respects your date format and folder settings
- Templates -- auto-detects template folder location
- Periodic notes -- reads periodic-notes plugin config
- Templater -- reads templater-obsidian plugin config
Your vault files are never modified unless you explicitly perform a write action (create, rename, delete, edit, accept AI suggestion, or capture).
MIT