JFox - Zettelkasten 知识管理 CLI 工具
Project description
JFox
A local-first Zettelkasten knowledge management CLI. Bidirectional links, semantic search, knowledge graphs — all offline, all on CPU.
JFox (J + Fox / "box") is a command-line tool that helps you build a personal knowledge base using the Zettelkasten method. Notes live as plain Markdown files on your disk, connected by [[wiki links]] and indexed for instant semantic search.
Table of Contents
Features
- Three note types — Fleeting (quick capture), Literature (reading notes), Permanent (refined knowledge)
- Bidirectional links — Write
[[Note Title]]to connect notes; backlinks are auto-generated - Hybrid search — BM25 keyword search + semantic vector search, fused with Reciprocal Rank Fusion
- Knowledge graph — NetworkX-powered link analysis: clusters, orphans, hubs, shortest paths
- File watcher — Real-time index updates when you edit notes with any editor
- Multi knowledge bases — Manage separate KBs for work, personal, research, etc.
Architecture
Three-Layer Design
graph TB
subgraph CLI ["CLI Layer"]
cmd["jfox commands<br/>(Typer)"]
end
subgraph Storage ["Storage Layer"]
note[note.py]
models[models.py]
md[("Markdown Files<br/>YAML Frontmatter")]
end
subgraph Index ["Index Layer"]
se[search_engine.py<br/>HybridSearchEngine]
vs[vector_store.py<br/>ChromaDB]
bm[bm25_index.py<br/>BM25Okapi]
emb[embedding_backend.py<br/>all-MiniLM-L6-v2]
daemon["daemon/<br/>HTTP Server"]
end
subgraph Analysis ["Analysis Layer"]
gph["graph.py<br/>NetworkX DiGraph"]
end
subgraph Watcher ["File Watcher"]
idx[indexer.py<br/>watchdog]
end
cmd --> note & se & gph
note --> models --> md
se --> vs & bm
vs --> emb
emb -.->|"preferred"| daemon
idx --> vs
Module Map
| Module | Role |
|---|---|
cli.py |
All CLI commands (~2500 lines). Each command delegates to a _xxx_impl() helper |
config.py |
Per-KB config (ZKConfig) + use_kb() context manager for KB switching |
global_config.py |
Multi-KB registry in ~/.zk_config.json |
kb_manager.py |
KB lifecycle: create, rename, remove, switch |
note.py |
CRUD on Markdown files with dual-index updates |
models.py |
Note dataclass with YAML frontmatter serialization |
search_engine.py |
HybridSearchEngine — dispatches to semantic/keyword/hybrid with RRF fusion |
vector_store.py |
ChromaDB wrapper with cosine similarity search |
bm25_index.py |
BM25 keyword index with Chinese/English tokenizer |
embedding_backend.py |
Lazy-loaded SentenceTransformer (all-MiniLM-L6-v2, 384-dim vectors) |
daemon/ |
Embedding HTTP 守护进程,常驻模型避免重复加载 |
graph.py |
NetworkX DiGraph built from links + wiki links; BFS, clusters, hubs |
indexer.py |
File watcher (watchdog) with debounce for incremental ChromaDB updates |
formatters.py |
Output in JSON, CSV, YAML, Table, Paths, Tree formats |
performance.py |
Batch processing, model caching, bulk import pipeline |
Data Flows
Note Creation
When you run jfox add, the system parses wiki links, creates the Markdown file, updates both indexes, and propagates backlinks:
sequenceDiagram
participant U as User
participant CLI as cli.py
participant NM as note.py
participant MD as Filesystem
participant VS as VectorStore
participant BM as BM25Index
participant T as Target Note
U->>CLI: jfox add "content with [[Link]]"
CLI->>CLI: extract_wiki_links() → ["Link"]
CLI->>CLI: find_note_id_by_title_or_id()
Note over CLI: Match: exact ID → exact title → substring
CLI->>NM: create_note(content, links=[id1])
NM->>NM: generate_id() → timestamp + random
NM->>MD: write Markdown + YAML frontmatter
NM->>VS: add_note() → embed + store in ChromaDB
NM->>BM: add_document() → tokenize + update index
CLI->>T: load target → append backlink → save
Index Rebuild
jfox index rebuild reconstructs both the vector index and the keyword index from all Markdown files on disk:
sequenceDiagram
participant U as User
participant CLI as cli.py
participant IDX as Indexer
participant VS as VectorStore
participant BM as BM25Index
participant FS as Filesystem
U->>CLI: jfox index rebuild
CLI->>VS: clear() — wipe ChromaDB collection
CLI->>FS: rglob("*.md") — scan all notes
loop Each note file
FS-->>IDX: parse Markdown + frontmatter
IDX->>VS: add_or_update_note()
Note over VS: embed → store in ChromaDB
end
CLI->>FS: list all notes
CLI->>BM: rebuild_from_notes()
Note over BM: tokenize all → rebuild BM25Okapi → persist
Hybrid Search (BM25 + Semantic → RRF)
jfox search runs two independent search paths in parallel and fuses results using Reciprocal Rank Fusion:
sequenceDiagram
participant U as User
participant SE as HybridSearchEngine
participant VS as VectorStore
participant BM as BM25Index
participant EMB as EmbeddingBackend
U->>SE: search("knowledge management", mode=hybrid)
par Semantic Path
SE->>EMB: encode(query) → 384-dim vector
EMB-->>VS: cosine similarity search
VS-->>SE: ranked results with scores
and Keyword Path
SE->>BM: tokenize(query) → BM25 scoring
BM-->>SE: ranked results with scores
end
Note over SE: Graceful fallback if one path fails
SE->>SE: RRF Fusion: score = Σ 1/(k + rank), k=60
SE-->>U: merged, re-ranked results
Query with Graph Traversal
jfox query combines hybrid search with knowledge graph BFS to find semantically related notes and their neighbors:
sequenceDiagram
participant U as User
participant CLI as cli.py
participant SE as SearchEngine
participant KG as KnowledgeGraph
participant NX as NetworkX
U->>CLI: jfox query "Luhmann's methodology" --depth 2
CLI->>SE: hybrid search → top results
SE-->>CLI: ranked search results
CLI->>KG: build() — 3-pass graph construction
Note over KG: Pass 1: nodes from files<br/>Pass 2: edges from frontmatter links<br/>Pass 3: edges from [[wiki links]]
loop For each search result
CLI->>KG: get_related(note_id, depth=2)
KG->>NX: BFS traversal (predecessors + successors)
NX-->>KG: neighbors grouped by depth
end
CLI-->>U: results enriched with graph context
Quick Start
Install
# Recommended
uv tool install "git+https://github.com/zhuxixi/jfox.git"
# Or with pip
pip install -e ".[dev]"
See Installation Guide for details, Windows PATH setup, and uninstall instructions.
Create Your First Note
jfox init
jfox add "The Zettelkasten method uses atomic notes connected by links" \
--title "Zettelkasten Introduction" --type permanent
Add Links
jfox add "[[Zettelkasten Introduction]] was invented by Niklas Luhmann" \
--title "Luhmann and the Card Box" --type permanent
The [[Zettelkasten Introduction]] syntax automatically creates a bidirectional link. Backlinks are propagated to the target note.
Search
# Semantic + keyword hybrid search
jfox search "knowledge management method"
# Hybrid search + graph traversal
jfox query "Luhmann's methodology" --depth 2
Command Reference
Knowledge Base
| Command | Description |
|---|---|
jfox init |
Initialize a knowledge base |
jfox init --name work --desc "Work notes" |
Initialize a named KB |
jfox kb list |
List all knowledge bases |
jfox kb use work |
Switch default KB |
jfox kb info work |
Show KB details and stats |
jfox kb rename old new |
Rename a KB |
jfox kb remove name --force |
Delete a KB and its data |
Notes
| Command | Description |
|---|---|
jfox add "content" --title "Title" --type permanent |
Create a note |
jfox add --content-file note.txt --title "Title" |
Create from file content |
jfox list |
List all notes |
jfox list --type permanent --limit 20 |
Filter by type |
jfox status |
Show knowledge base status |
jfox edit NOTE_ID |
Edit note in $EDITOR |
jfox delete NOTE_ID --force |
Delete a note |
jfox daily |
Show today's notes |
jfox daily --date 2026-03-20 |
Show notes for a date |
jfox inbox |
Show fleeting notes |
jfox suggest-links "content" |
Suggest notes to link from content |
jfox bulk-import notes.json |
Bulk import from JSON (optimized) |
jfox ingest-log |
Import git commit history as notes |
jfox show NOTE_ID |
View full note content in terminal |
Search & Analysis
| Command | Description |
|---|---|
jfox search "query" |
Hybrid search (default) |
jfox search "query" --mode semantic |
Semantic search only |
jfox search "query" --mode keyword |
BM25 keyword search only |
jfox query "concept" --depth 2 |
Search + graph traversal |
jfox refs |
Show link statistics for all notes |
jfox refs --search "keyword" |
Filter refs by title |
jfox refs --note NOTE_ID |
Show links for a specific note |
jfox graph --stats |
Graph statistics |
jfox graph --orphans |
Find isolated notes |
jfox graph --note NOTE_ID --depth 2 |
Subgraph around a note |
Index Management
| Command | Description |
|---|---|
jfox index status |
Show index health |
jfox index rebuild |
Rebuild vector + BM25 indexes |
jfox index verify |
Cross-check files vs indexed entries |
Templates
| Command | Description |
|---|---|
jfox template list |
List built-in and custom templates |
jfox template show quick |
Display template content |
jfox template create my-template |
Create a custom template |
jfox template edit my-template |
Edit in $EDITOR |
jfox template remove my-template |
Delete a custom template |
Performance & Debug
| Command | Description |
|---|---|
jfox perf report |
Show performance metrics |
jfox perf clear-cache |
Clear embedding model cache |
Daemon
| Command | Description |
|---|---|
jfox daemon start |
Start embedding daemon (background process) |
jfox daemon stop |
Stop embedding daemon |
jfox daemon status |
Show daemon PID, port, model info |
Global Options
| Option | Description |
|---|---|
--kb NAME |
Target a specific knowledge base |
--format json|table|csv|yaml|paths|tree |
Output format |
--json |
Shortcut for --format json |
--version |
Show version |
Note Format
Directory Structure
~/.zettelkasten/
├── default/ # Default knowledge base
│ ├── notes/
│ │ ├── fleeting/ # Quick captures
│ │ ├── literature/ # Reading notes
│ │ └── permanent/ # Refined knowledge
│ └── .zk/
│ ├── chroma_db/ # Vector index
│ ├── bm25_index.pkl # Keyword index
│ ├── templates/ # Jinja2 templates
│ └── config.yaml # KB config
├── work/ # Named KB example
│ ├── notes/
│ └── .zk/
└── ~/.zk_config.json # Global KB registry
File Format
Each note is a Markdown file with YAML frontmatter:
---
id: '20260321011528'
title: Machine Learning Overview
type: permanent
created: '2026-03-21T01:15:28'
updated: '2026-03-21T01:15:28'
tags:
- ml
- ai
links:
- 20260321011546
backlinks:
- 20260321011550
---
# Machine Learning Overview
[[Deep Learning]] is a subfield of machine learning...
Note Types
| Type | Purpose | Filename |
|---|---|---|
fleeting |
Quick ideas, temporary captures | YYYYMMDD-HHMMSSNNNN.md |
literature |
Reading notes, paper summaries | YYYYMMDDHHMMSSNNNN-slug.md |
permanent |
Refined, lasting knowledge | YYYYMMDDHHMMSSNNNN-slug.md |
Link Resolution
[[Link Text]] matches notes by priority:
- Exact ID — if text matches a note ID
- Exact title — case-insensitive title match
- Substring — title contains the link text
Contributing
git clone https://github.com/zhuxixi/jfox.git
cd jfox
uv sync --extra dev
uv run pytest tests/ -v
See Troubleshooting for common issues.
License
Acknowledgments
- sentence-transformers — text embeddings
- ChromaDB — vector database
- NetworkX — graph algorithms
- Typer — CLI framework
- Rich — terminal formatting
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file jfox_cli-0.4.0.tar.gz.
File metadata
- Download URL: jfox_cli-0.4.0.tar.gz
- Upload date:
- Size: 452.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ccf5a01e3e7f84840b855945fbe251ce21c7aa7aadc911b19adc11d445091b4a
|
|
| MD5 |
1f6cdaaae587f191dd3714305336d938
|
|
| BLAKE2b-256 |
1196e440c718b7995765498f1a06becac0408defd260816b8e766cb3a589e818
|
File details
Details for the file jfox_cli-0.4.0-py3-none-any.whl.
File metadata
- Download URL: jfox_cli-0.4.0-py3-none-any.whl
- Upload date:
- Size: 77.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.7 {"installer":{"name":"uv","version":"0.11.7","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
18b67919cf232890ef61df055a7c22853947a7d73605f4a2798c0e697222bb9f
|
|
| MD5 |
9b2246f42b75ba56ff77e01ce36b880a
|
|
| BLAKE2b-256 |
8d3f263d178296d1d914bef055710b424f122cb7c77757972296a7789d7594f0
|