Skip to main content

JFox - Zettelkasten 知识管理 CLI 工具

Project description

JFox

License: MIT Python Platform

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:

  1. Exact ID — if text matches a note ID
  2. Exact title — case-insensitive title match
  3. 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

MIT

Acknowledgments

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jfox_cli-0.4.1.tar.gz (455.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

jfox_cli-0.4.1-py3-none-any.whl (78.9 kB view details)

Uploaded Python 3

File details

Details for the file jfox_cli-0.4.1.tar.gz.

File metadata

  • Download URL: jfox_cli-0.4.1.tar.gz
  • Upload date:
  • Size: 455.6 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

Hashes for jfox_cli-0.4.1.tar.gz
Algorithm Hash digest
SHA256 6d3cf1b487d01f88869b56480978a9989ad69ba0f508cfb6b71cdcf1df88e0c8
MD5 042eb16cdf80600881b892f09416101d
BLAKE2b-256 43888acbf431c17f16397424c929310c097ea44312fe07532ed85836e43c1d37

See more details on using hashes here.

File details

Details for the file jfox_cli-0.4.1-py3-none-any.whl.

File metadata

  • Download URL: jfox_cli-0.4.1-py3-none-any.whl
  • Upload date:
  • Size: 78.9 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

Hashes for jfox_cli-0.4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0891c798d0539fef69974cecab85a1fa92bbe4f64b5511a25208b72e7a003bed
MD5 e752b7fefbeb5d0677f27f079ab0437d
BLAKE2b-256 121b454276e9b95489ef4e1eedf39371ee49900169a8abf9db22c95b7de79027

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page