jfox-cli 0.2.2__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/CLAUDE.md +4 -2
  2. jfox_cli-0.3.0/PKG-INFO +464 -0
  3. jfox_cli-0.3.0/README.md +424 -0
  4. jfox_cli-0.3.0/docs/installation.md +72 -0
  5. jfox_cli-0.3.0/docs/superpowers/specs/2026-04-14-show-command-design.md +44 -0
  6. jfox_cli-0.3.0/docs/troubleshooting.md +43 -0
  7. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/jfox/__init__.py +1 -1
  8. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/jfox/cli.py +124 -0
  9. jfox_cli-0.3.0/jfox/daemon/__init__.py +15 -0
  10. jfox_cli-0.3.0/jfox/daemon/__main__.py +5 -0
  11. jfox_cli-0.3.0/jfox/daemon/client.py +99 -0
  12. jfox_cli-0.3.0/jfox/daemon/process.py +225 -0
  13. jfox_cli-0.3.0/jfox/daemon/server.py +126 -0
  14. jfox_cli-0.3.0/jfox/embedding_backend.py +112 -0
  15. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/pyproject.toml +6 -2
  16. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/skills-recommend/README.md +2 -0
  17. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/skills-recommend/claude-code/jfox-common/SKILL.md +11 -0
  18. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/skills-recommend/claude-code/jfox-ingest/SKILL.md +7 -0
  19. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/skills-recommend/claude-code/jfox-organize/SKILL.md +5 -0
  20. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/skills-recommend/claude-code/jfox-search/SKILL.md +3 -1
  21. jfox_cli-0.3.0/skills-recommend/claude-code/jfox-session-summary/SKILL.md +96 -0
  22. jfox_cli-0.3.0/tests/unit/test_show.py +73 -0
  23. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/uv.lock +37 -2
  24. jfox_cli-0.2.2/PKG-INFO +0 -639
  25. jfox_cli-0.2.2/README.md +0 -602
  26. jfox_cli-0.2.2/jfox/embedding_backend.py +0 -64
  27. jfox_cli-0.2.2/skill/evals/evals.json +0 -185
  28. jfox_cli-0.2.2/skill/knowledge-base-notes/SKILL.md +0 -278
  29. jfox_cli-0.2.2/skill/knowledge-base-workspace/SKILL.md +0 -242
  30. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/.githooks/pre-push +0 -0
  31. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/.github/workflows/integration-test.yml +0 -0
  32. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/.github/workflows/publish.yml +0 -0
  33. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/.gitignore +0 -0
  34. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/.python-version +0 -0
  35. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/AGENTS.md +0 -0
  36. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/CHANGELOG.md +0 -0
  37. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/DEVELOPMENT_PLAN.md +0 -0
  38. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/SESSION.md +0 -0
  39. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/SESSION_SUMMARY.md +0 -0
  40. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/docs/superpowers/plans/2026-04-11-bulk-import-bm25-fix.md +0 -0
  41. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/docs/superpowers/plans/2026-04-11-edit-command.md +0 -0
  42. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/docs/superpowers/plans/2026-04-11-unify-format-option.md +0 -0
  43. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/docs/superpowers/plans/2026-04-12-ci-coverage-optimization.md +0 -0
  44. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/docs/superpowers/plans/2026-04-12-edit-content-file.md +0 -0
  45. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/docs/superpowers/plans/2026-04-12-fix-index-rebuild-clear.md +0 -0
  46. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/docs/superpowers/plans/2026-04-12-fix-index-verify-id-mismatch.md +0 -0
  47. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/docs/superpowers/plans/2026-04-12-fix-jfox-health-skill-kb-param.md +0 -0
  48. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/docs/superpowers/plans/2026-04-12-index-kb-param.md +0 -0
  49. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/docs/superpowers/plans/2026-04-12-lazy-import-perf.md +0 -0
  50. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/docs/superpowers/plans/2026-04-12-skill-redesign.md +0 -0
  51. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/docs/superpowers/specs/2026-04-03-bugfixes-design.md +0 -0
  52. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/docs/superpowers/specs/2026-04-12-skill-redesign-design.md +0 -0
  53. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/docs/superpowers/specs/2026-04-13-pr-auto-code-review-design.md +0 -0
  54. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/jessica-jones-static-cable.md +0 -0
  55. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/jfox/__main__.py +0 -0
  56. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/jfox/bm25_index.py +0 -0
  57. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/jfox/config.py +0 -0
  58. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/jfox/formatters.py +0 -0
  59. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/jfox/git_extractor.py +0 -0
  60. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/jfox/global_config.py +0 -0
  61. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/jfox/graph.py +0 -0
  62. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/jfox/indexer.py +0 -0
  63. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/jfox/kb_manager.py +0 -0
  64. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/jfox/models.py +0 -0
  65. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/jfox/note.py +0 -0
  66. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/jfox/performance.py +0 -0
  67. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/jfox/search_engine.py +0 -0
  68. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/jfox/template.py +0 -0
  69. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/jfox/template_cli.py +0 -0
  70. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/jfox/vector_store.py +0 -0
  71. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/pytest.ini +0 -0
  72. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/run_full_test.ps1 +0 -0
  73. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/COVERAGE_PLAN.md +0 -0
  74. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/MIGRATION.md +0 -0
  75. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/TESTS.md +0 -0
  76. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/conftest.py +0 -0
  77. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/integration/__init__.py +0 -0
  78. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/integration/test_backlinks.py +0 -0
  79. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/performance/__init__.py +0 -0
  80. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/performance/test_performance.py +0 -0
  81. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/test_advanced_features.py +0 -0
  82. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/test_cli_format.py +0 -0
  83. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/test_config_unit.py +0 -0
  84. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/test_core_workflow.py +0 -0
  85. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/test_hybrid_search.py +0 -0
  86. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/test_integration.py +0 -0
  87. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/test_kb_current.py +0 -0
  88. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/test_suggest_links.py +0 -0
  89. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/unit/__init__.py +0 -0
  90. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/unit/test_bm25_batch.py +0 -0
  91. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/unit/test_edit.py +0 -0
  92. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/unit/test_format_unify.py +0 -0
  93. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/unit/test_formatters.py +0 -0
  94. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/unit/test_git_extractor.py +0 -0
  95. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/unit/test_global_config.py +0 -0
  96. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/unit/test_index_kb_param.py +0 -0
  97. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/unit/test_indexer_clear_before_rebuild.py +0 -0
  98. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/unit/test_indexer_verify.py +0 -0
  99. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/unit/test_kb_manager.py +0 -0
  100. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/unit/test_lazy_import.py +0 -0
  101. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/unit/test_logging_config.py +0 -0
  102. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/unit/test_template.py +0 -0
  103. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/unit/test_template_cli.py +0 -0
  104. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/unit/test_vector_store_clear.py +0 -0
  105. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/utils/__init__.py +0 -0
  106. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/utils/assertions.py +0 -0
  107. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/utils/jfox_cli.py +0 -0
  108. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/utils/note_generator.py +0 -0
  109. {jfox_cli-0.2.2 → jfox_cli-0.3.0}/tests/utils/temp_kb.py +0 -0
@@ -56,7 +56,7 @@ Notes are Markdown files with YAML frontmatter stored under `~/.zettelkasten/<kb
56
56
 
57
57
  | Module | Role |
58
58
  |--------|------|
59
- | `cli.py` | All CLI commands (~1800 lines). Commands follow pattern: `@app.command()` → `_xxx_impl()` helper for reuse |
59
+ | `cli.py` | All CLI commands (~2500 lines). Commands follow pattern: `@app.command()` → `_xxx_impl()` helper for reuse |
60
60
  | `config.py` | `ZKConfig` + `use_kb()` context manager for multi-KB switching |
61
61
  | `global_config.py` | `GlobalConfigManager` managing `~/.zk_config.json` |
62
62
  | `kb_manager.py` | Knowledge base lifecycle (create, rename, remove) |
@@ -66,7 +66,8 @@ Notes are Markdown files with YAML frontmatter stored under `~/.zettelkasten/<kb
66
66
  | `models.py` | `Note` data model with frontmatter serialization |
67
67
  | `search_engine.py` | `HybridSearchEngine` with `SearchMode` enum, RRF fusion |
68
68
  | `bm25_index.py` | BM25 keyword search index |
69
- | `embedding_backend.py` | Sentence-transformers embedding backend |
69
+ | `embedding_backend.py` | Sentence-transformers embedding backend(支持 daemon 代理) |
70
+ | `daemon/` | Embedding 模型 HTTP 守护进程(可选依赖 `[daemon]`),`jfox daemon start/stop/status` |
70
71
  | `vector_store.py` | ChromaDB vector store for semantic search |
71
72
  | `graph.py` | NetworkX knowledge graph from links/backlinks |
72
73
  | `template.py` / `template_cli.py` | Jinja2 template system for structured note creation |
@@ -97,6 +98,7 @@ Notes are Markdown files with YAML frontmatter stored under `~/.zettelkasten/<kb
97
98
  - **Adding a CLI command**: Add `@app.command()` in `cli.py`, implement `_xxx_impl()` helper, add `--kb` and `--format json` support
98
99
  - **Adding a search mode**: Add to `SearchMode` enum in `search_engine.py`, implement in `HybridSearchEngine.search()`, update CLI `--mode` help text
99
100
  - **Modifying data models**: Update `Note` class in `models.py`, update `to_markdown()`/`from_markdown()`, consider backward compat
101
+ - **Viewing note content**: `jfox show <id_or_title>` 复用 `find_note_id_by_title_or_id` 定位笔记,只读输出完整 Markdown
100
102
 
101
103
  ## Test Infrastructure
102
104
 
@@ -0,0 +1,464 @@
1
+ Metadata-Version: 2.4
2
+ Name: jfox-cli
3
+ Version: 0.3.0
4
+ Summary: JFox - Zettelkasten 知识管理 CLI 工具
5
+ Project-URL: Homepage, https://github.com/zhuxixi/jfox
6
+ Project-URL: Repository, https://github.com/zhuxixi/jfox
7
+ Author-email: User <user@example.com>
8
+ License: MIT
9
+ Keywords: cli,jfox,knowledge-management,note-taking,zettelkasten
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Requires-Python: >=3.10
19
+ Requires-Dist: chromadb>=0.5.0
20
+ Requires-Dist: jinja2>=3.0
21
+ Requires-Dist: networkx>=3.0
22
+ Requires-Dist: pydantic>=2.0
23
+ Requires-Dist: pyyaml>=6.0
24
+ Requires-Dist: rank-bm25>=0.2.2
25
+ Requires-Dist: rich>=13.0.0
26
+ Requires-Dist: sentence-transformers>=3.0
27
+ Requires-Dist: typer>=0.12.0
28
+ Requires-Dist: watchdog>=3.0
29
+ Provides-Extra: daemon
30
+ Requires-Dist: fastapi>=0.110.0; extra == 'daemon'
31
+ Requires-Dist: uvicorn[standard]>=0.27.0; extra == 'daemon'
32
+ Provides-Extra: dev
33
+ Requires-Dist: black>=23.0; extra == 'dev'
34
+ Requires-Dist: pytest-cov>=4.0; extra == 'dev'
35
+ Requires-Dist: pytest-timeout>=2.0; extra == 'dev'
36
+ Requires-Dist: pytest-xdist>=3.0; extra == 'dev'
37
+ Requires-Dist: pytest>=7.0; extra == 'dev'
38
+ Requires-Dist: ruff>=0.1.0; extra == 'dev'
39
+ Description-Content-Type: text/markdown
40
+
41
+ # JFox
42
+
43
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
44
+ [![Python](https://img.shields.io/badge/python-3.10+-blue.svg)](pyproject.toml)
45
+ [![Platform](https://img.shields.io/badge/platform-Windows%20%7C%20macOS%20%7C%20Linux-lightgrey.svg)](#)
46
+
47
+ > A local-first Zettelkasten knowledge management CLI.
48
+ > Bidirectional links, semantic search, knowledge graphs — all offline, all on CPU.
49
+
50
+ **JFox** (**J** + **Fox** / "box") is a command-line tool that helps you build a personal knowledge base using the [Zettelkasten method](https://en.wikipedia.org/wiki/Zettelkasten). Notes live as plain Markdown files on your disk, connected by `[[wiki links]]` and indexed for instant semantic search.
51
+
52
+ ---
53
+
54
+ ## Table of Contents
55
+
56
+ - [Features](#features)
57
+ - [Architecture](#architecture)
58
+ - [Data Flows](#data-flows)
59
+ - [Quick Start](#quick-start)
60
+ - [Command Reference](#command-reference)
61
+ - [Note Format](#note-format)
62
+ - [Contributing](#contributing)
63
+ - [License](#license)
64
+
65
+ ---
66
+
67
+ ## Features
68
+
69
+ - **Three note types** — Fleeting (quick capture), Literature (reading notes), Permanent (refined knowledge)
70
+ - **Bidirectional links** — Write `[[Note Title]]` to connect notes; backlinks are auto-generated
71
+ - **Hybrid search** — BM25 keyword search + semantic vector search, fused with Reciprocal Rank Fusion
72
+ - **Knowledge graph** — NetworkX-powered link analysis: clusters, orphans, hubs, shortest paths
73
+ - **File watcher** — Real-time index updates when you edit notes with any editor
74
+ - **Multi knowledge bases** — Manage separate KBs for work, personal, research, etc.
75
+
76
+ ---
77
+
78
+ ## Architecture
79
+
80
+ ### Three-Layer Design
81
+
82
+ ```mermaid
83
+ graph TB
84
+ subgraph CLI ["CLI Layer"]
85
+ cmd["jfox commands<br/>(Typer)"]
86
+ end
87
+ subgraph Storage ["Storage Layer"]
88
+ note[note.py]
89
+ models[models.py]
90
+ md[("Markdown Files<br/>YAML Frontmatter")]
91
+ end
92
+ subgraph Index ["Index Layer"]
93
+ se[search_engine.py<br/>HybridSearchEngine]
94
+ vs[vector_store.py<br/>ChromaDB]
95
+ bm[bm25_index.py<br/>BM25Okapi]
96
+ emb[embedding_backend.py<br/>all-MiniLM-L6-v2]
97
+ daemon["daemon/<br/>HTTP Server (可选)"]
98
+ end
99
+ subgraph Analysis ["Analysis Layer"]
100
+ gph["graph.py<br/>NetworkX DiGraph"]
101
+ end
102
+ subgraph Watcher ["File Watcher"]
103
+ idx[indexer.py<br/>watchdog]
104
+ end
105
+
106
+ cmd --> note & se & gph
107
+ note --> models --> md
108
+ se --> vs & bm
109
+ vs --> emb
110
+ emb -.->|"preferred"| daemon
111
+ idx --> vs
112
+ ```
113
+
114
+ ### Module Map
115
+
116
+ | Module | Role |
117
+ |--------|------|
118
+ | `cli.py` | All CLI commands (~2500 lines). Each command delegates to a `_xxx_impl()` helper |
119
+ | `config.py` | Per-KB config (`ZKConfig`) + `use_kb()` context manager for KB switching |
120
+ | `global_config.py` | Multi-KB registry in `~/.zk_config.json` |
121
+ | `kb_manager.py` | KB lifecycle: create, rename, remove, switch |
122
+ | `note.py` | CRUD on Markdown files with dual-index updates |
123
+ | `models.py` | `Note` dataclass with YAML frontmatter serialization |
124
+ | `search_engine.py` | `HybridSearchEngine` — dispatches to semantic/keyword/hybrid with RRF fusion |
125
+ | `vector_store.py` | ChromaDB wrapper with cosine similarity search |
126
+ | `bm25_index.py` | BM25 keyword index with Chinese/English tokenizer |
127
+ | `embedding_backend.py` | Lazy-loaded SentenceTransformer (`all-MiniLM-L6-v2`, 384-dim vectors) |
128
+ | `daemon/` | Embedding HTTP 守护进程(可选依赖 `[daemon]`),常驻模型避免重复加载 |
129
+ | `graph.py` | NetworkX DiGraph built from links + wiki links; BFS, clusters, hubs |
130
+ | `indexer.py` | File watcher (watchdog) with debounce for incremental ChromaDB updates |
131
+ | `formatters.py` | Output in JSON, CSV, YAML, Table, Paths, Tree formats |
132
+ | `performance.py` | Batch processing, model caching, bulk import pipeline |
133
+
134
+ ---
135
+
136
+ ## Data Flows
137
+
138
+ ### Note Creation
139
+
140
+ When you run `jfox add`, the system parses wiki links, creates the Markdown file, updates both indexes, and propagates backlinks:
141
+
142
+ ```mermaid
143
+ sequenceDiagram
144
+ participant U as User
145
+ participant CLI as cli.py
146
+ participant NM as note.py
147
+ participant MD as Filesystem
148
+ participant VS as VectorStore
149
+ participant BM as BM25Index
150
+ participant T as Target Note
151
+
152
+ U->>CLI: jfox add "content with [[Link]]"
153
+ CLI->>CLI: extract_wiki_links() → ["Link"]
154
+ CLI->>CLI: find_note_id_by_title_or_id()
155
+ Note over CLI: Match: exact ID → exact title → substring
156
+ CLI->>NM: create_note(content, links=[id1])
157
+ NM->>NM: generate_id() → timestamp + random
158
+ NM->>MD: write Markdown + YAML frontmatter
159
+ NM->>VS: add_note() → embed + store in ChromaDB
160
+ NM->>BM: add_document() → tokenize + update index
161
+ CLI->>T: load target → append backlink → save
162
+ ```
163
+
164
+ ### Index Rebuild
165
+
166
+ `jfox index rebuild` reconstructs both the vector index and the keyword index from all Markdown files on disk:
167
+
168
+ ```mermaid
169
+ sequenceDiagram
170
+ participant U as User
171
+ participant CLI as cli.py
172
+ participant IDX as Indexer
173
+ participant VS as VectorStore
174
+ participant BM as BM25Index
175
+ participant FS as Filesystem
176
+
177
+ U->>CLI: jfox index rebuild
178
+ CLI->>VS: clear() — wipe ChromaDB collection
179
+ CLI->>FS: rglob("*.md") — scan all notes
180
+ loop Each note file
181
+ FS-->>IDX: parse Markdown + frontmatter
182
+ IDX->>VS: add_or_update_note()
183
+ Note over VS: embed → store in ChromaDB
184
+ end
185
+ CLI->>FS: list all notes
186
+ CLI->>BM: rebuild_from_notes()
187
+ Note over BM: tokenize all → rebuild BM25Okapi → persist
188
+ ```
189
+
190
+ ### Hybrid Search (BM25 + Semantic → RRF)
191
+
192
+ `jfox search` runs two independent search paths in parallel and fuses results using Reciprocal Rank Fusion:
193
+
194
+ ```mermaid
195
+ sequenceDiagram
196
+ participant U as User
197
+ participant SE as HybridSearchEngine
198
+ participant VS as VectorStore
199
+ participant BM as BM25Index
200
+ participant EMB as EmbeddingBackend
201
+
202
+ U->>SE: search("knowledge management", mode=hybrid)
203
+ par Semantic Path
204
+ SE->>EMB: encode(query) → 384-dim vector
205
+ EMB-->>VS: cosine similarity search
206
+ VS-->>SE: ranked results with scores
207
+ and Keyword Path
208
+ SE->>BM: tokenize(query) → BM25 scoring
209
+ BM-->>SE: ranked results with scores
210
+ end
211
+ Note over SE: Graceful fallback if one path fails
212
+ SE->>SE: RRF Fusion: score = Σ 1/(k + rank), k=60
213
+ SE-->>U: merged, re-ranked results
214
+ ```
215
+
216
+ ### Query with Graph Traversal
217
+
218
+ `jfox query` combines hybrid search with knowledge graph BFS to find semantically related notes and their neighbors:
219
+
220
+ ```mermaid
221
+ sequenceDiagram
222
+ participant U as User
223
+ participant CLI as cli.py
224
+ participant SE as SearchEngine
225
+ participant KG as KnowledgeGraph
226
+ participant NX as NetworkX
227
+
228
+ U->>CLI: jfox query "Luhmann's methodology" --depth 2
229
+ CLI->>SE: hybrid search → top results
230
+ SE-->>CLI: ranked search results
231
+ CLI->>KG: build() — 3-pass graph construction
232
+ Note over KG: Pass 1: nodes from files<br/>Pass 2: edges from frontmatter links<br/>Pass 3: edges from [[wiki links]]
233
+ loop For each search result
234
+ CLI->>KG: get_related(note_id, depth=2)
235
+ KG->>NX: BFS traversal (predecessors + successors)
236
+ NX-->>KG: neighbors grouped by depth
237
+ end
238
+ CLI-->>U: results enriched with graph context
239
+ ```
240
+
241
+ ---
242
+
243
+ ## Quick Start
244
+
245
+ ### Install
246
+
247
+ ```bash
248
+ # Recommended
249
+ uv tool install "git+https://github.com/zhuxixi/jfox.git"
250
+
251
+ # Or with pip
252
+ pip install -e ".[dev]"
253
+ ```
254
+
255
+ See [Installation Guide](docs/installation.md) for details, Windows PATH setup, and uninstall instructions.
256
+
257
+ ### Create Your First Note
258
+
259
+ ```bash
260
+ jfox init
261
+ jfox add "The Zettelkasten method uses atomic notes connected by links" \
262
+ --title "Zettelkasten Introduction" --type permanent
263
+ ```
264
+
265
+ ### Add Links
266
+
267
+ ```bash
268
+ jfox add "[[Zettelkasten Introduction]] was invented by Niklas Luhmann" \
269
+ --title "Luhmann and the Card Box" --type permanent
270
+ ```
271
+
272
+ The `[[Zettelkasten Introduction]]` syntax automatically creates a bidirectional link. Backlinks are propagated to the target note.
273
+
274
+ ### Search
275
+
276
+ ```bash
277
+ # Semantic + keyword hybrid search
278
+ jfox search "knowledge management method"
279
+
280
+ # Hybrid search + graph traversal
281
+ jfox query "Luhmann's methodology" --depth 2
282
+ ```
283
+
284
+ ---
285
+
286
+ ## Command Reference
287
+
288
+ ### Knowledge Base
289
+
290
+ | Command | Description |
291
+ |---------|-------------|
292
+ | `jfox init` | Initialize a knowledge base |
293
+ | `jfox init --name work --desc "Work notes"` | Initialize a named KB |
294
+ | `jfox kb list` | List all knowledge bases |
295
+ | `jfox kb use work` | Switch default KB |
296
+ | `jfox kb info work` | Show KB details and stats |
297
+ | `jfox kb rename old new` | Rename a KB |
298
+ | `jfox kb remove name --force` | Delete a KB and its data |
299
+
300
+ ### Notes
301
+
302
+ | Command | Description |
303
+ |---------|-------------|
304
+ | `jfox add "content" --title "Title" --type permanent` | Create a note |
305
+ | `jfox add --content-file note.txt --title "Title"` | Create from file content |
306
+ | `jfox list` | List all notes |
307
+ | `jfox list --type permanent --limit 20` | Filter by type |
308
+ | `jfox status` | Show knowledge base status |
309
+ | `jfox edit NOTE_ID` | Edit note in `$EDITOR` |
310
+ | `jfox delete NOTE_ID --force` | Delete a note |
311
+ | `jfox daily` | Show today's notes |
312
+ | `jfox daily --date 2026-03-20` | Show notes for a date |
313
+ | `jfox inbox` | Show fleeting notes |
314
+ | `jfox suggest-links "content"` | Suggest notes to link from content |
315
+ | `jfox bulk-import notes.json` | Bulk import from JSON (optimized) |
316
+ | `jfox ingest-log` | Import git commit history as notes |
317
+ | `jfox show NOTE_ID` | View full note content in terminal |
318
+
319
+ ### Search & Analysis
320
+
321
+ | Command | Description |
322
+ |---------|-------------|
323
+ | `jfox search "query"` | Hybrid search (default) |
324
+ | `jfox search "query" --mode semantic` | Semantic search only |
325
+ | `jfox search "query" --mode keyword` | BM25 keyword search only |
326
+ | `jfox query "concept" --depth 2` | Search + graph traversal |
327
+ | `jfox refs` | Show link statistics for all notes |
328
+ | `jfox refs --search "keyword"` | Filter refs by title |
329
+ | `jfox refs --note NOTE_ID` | Show links for a specific note |
330
+ | `jfox graph --stats` | Graph statistics |
331
+ | `jfox graph --orphans` | Find isolated notes |
332
+ | `jfox graph --note NOTE_ID --depth 2` | Subgraph around a note |
333
+
334
+ ### Index Management
335
+
336
+ | Command | Description |
337
+ |---------|-------------|
338
+ | `jfox index status` | Show index health |
339
+ | `jfox index rebuild` | Rebuild vector + BM25 indexes |
340
+ | `jfox index verify` | Cross-check files vs indexed entries |
341
+
342
+ ### Templates
343
+
344
+ | Command | Description |
345
+ |---------|-------------|
346
+ | `jfox template list` | List built-in and custom templates |
347
+ | `jfox template show quick` | Display template content |
348
+ | `jfox template create my-template` | Create a custom template |
349
+ | `jfox template edit my-template` | Edit in `$EDITOR` |
350
+ | `jfox template remove my-template` | Delete a custom template |
351
+
352
+ ### Performance & Debug
353
+
354
+ | Command | Description |
355
+ |---------|-------------|
356
+ | `jfox perf report` | Show performance metrics |
357
+ | `jfox perf clear-cache` | Clear embedding model cache |
358
+
359
+ ### Daemon
360
+
361
+ | Command | Description |
362
+ |---------|-------------|
363
+ | `jfox daemon start` | Start embedding daemon (background process) |
364
+ | `jfox daemon stop` | Stop embedding daemon |
365
+ | `jfox daemon status` | Show daemon PID, port, model info |
366
+
367
+ ### Global Options
368
+
369
+ | Option | Description |
370
+ |--------|-------------|
371
+ | `--kb NAME` | Target a specific knowledge base |
372
+ | `--format json\|table\|csv\|yaml\|paths\|tree` | Output format |
373
+ | `--json` | Shortcut for `--format json` |
374
+ | `--version` | Show version |
375
+
376
+ ---
377
+
378
+ ## Note Format
379
+
380
+ ### Directory Structure
381
+
382
+ ```
383
+ ~/.zettelkasten/
384
+ ├── default/ # Default knowledge base
385
+ │ ├── notes/
386
+ │ │ ├── fleeting/ # Quick captures
387
+ │ │ ├── literature/ # Reading notes
388
+ │ │ └── permanent/ # Refined knowledge
389
+ │ └── .zk/
390
+ │ ├── chroma_db/ # Vector index
391
+ │ ├── bm25_index.pkl # Keyword index
392
+ │ ├── templates/ # Jinja2 templates
393
+ │ └── config.yaml # KB config
394
+ ├── work/ # Named KB example
395
+ │ ├── notes/
396
+ │ └── .zk/
397
+ └── ~/.zk_config.json # Global KB registry
398
+ ```
399
+
400
+ ### File Format
401
+
402
+ Each note is a Markdown file with YAML frontmatter:
403
+
404
+ ```markdown
405
+ ---
406
+ id: '20260321011528'
407
+ title: Machine Learning Overview
408
+ type: permanent
409
+ created: '2026-03-21T01:15:28'
410
+ updated: '2026-03-21T01:15:28'
411
+ tags:
412
+ - ml
413
+ - ai
414
+ links:
415
+ - 20260321011546
416
+ backlinks:
417
+ - 20260321011550
418
+ ---
419
+
420
+ # Machine Learning Overview
421
+
422
+ [[Deep Learning]] is a subfield of machine learning...
423
+ ```
424
+
425
+ ### Note Types
426
+
427
+ | Type | Purpose | Filename |
428
+ |------|---------|----------|
429
+ | `fleeting` | Quick ideas, temporary captures | `YYYYMMDD-HHMMSSNNNN.md` |
430
+ | `literature` | Reading notes, paper summaries | `YYYYMMDDHHMMSSNNNN-slug.md` |
431
+ | `permanent` | Refined, lasting knowledge | `YYYYMMDDHHMMSSNNNN-slug.md` |
432
+
433
+ ### Link Resolution
434
+
435
+ `[[Link Text]]` matches notes by priority:
436
+
437
+ 1. **Exact ID** — if text matches a note ID
438
+ 2. **Exact title** — case-insensitive title match
439
+ 3. **Substring** — title contains the link text
440
+
441
+ ---
442
+
443
+ ## Contributing
444
+
445
+ ```bash
446
+ git clone https://github.com/zhuxixi/jfox.git
447
+ cd jfox
448
+ uv sync --extra dev
449
+ uv run pytest tests/ -v
450
+ ```
451
+
452
+ See [Troubleshooting](docs/troubleshooting.md) for common issues.
453
+
454
+ ## License
455
+
456
+ [MIT](LICENSE)
457
+
458
+ ## Acknowledgments
459
+
460
+ - [sentence-transformers](https://www.sbert.net/) — text embeddings
461
+ - [ChromaDB](https://www.trychroma.com/) — vector database
462
+ - [NetworkX](https://networkx.org/) — graph algorithms
463
+ - [Typer](https://typer.tiangolo.com/) — CLI framework
464
+ - [Rich](https://rich.readthedocs.io/) — terminal formatting