A 3D cockpit for your markdown knowledge vault — and a live window into the AI agents working inside it.
🌐 Landing page: chuong1224.github.io/agents-knowledge-base
Point it at a folder of markdown notes (an Obsidian-style vault) and it serves a local web app: an interactive, synthwave-styled 3D force graph of every note, tag and attachment — with a built-in reader, full-text finder, tabbed workspace, and a layer no PKM tool has: real-time visualization, replay and analytics of AI-agent activity (Claude Code out of the box; any agent via a simple JSONL hook).
Python stdlib server + vanilla ES modules + vendored three.js. No pip install to run the app, no npm, no build step. Optional
PyYAMLenables the strict YAML-frontmatter integrity lamp.
Two agents tearing through 120 notes at full speed — comet trails, hyperspace hops, impact ripples, live
The full cockpit: reader, finder tree, live agent feed and retrieval chains around the graph
The aftermath — Claude's blue and Nova's yellow trails woven across every continent
All screenshots come from the bundled synthetic demo vault — spin it up yourself.
- Force-directed 3D graph of notes, tags and attachments, colored by tag groups, with a bloom "neon" glow and adjustable intensity
- Degree-aware physics (hubs get room, leaves hug their hub), optional 🧲 cluster-magnet mode per color group, collision guard, smooth settling when filtering
- Layout presets — Expand, Calm, and 🪐 Universe (arranges notes by the index tree: root at the center, each index a hub, leaves on a Fibonacci sphere around it), deterministic across reloads
- Two deliberate filter semantics: color groups spotlight (dim but keep context), tag/extension filters declutter (remove entirely); your tag and color-group choices persist across sessions
- Accessibility: AA-contrast panel palette, keyboard-operable controls, respects
prefers-reduced-motion
- A
PostToolUsehook (Claude Code example below) logs every file operation an agent performs in the vault - Events fire cinematic effects: comet chains along retrieval paths, three-phase "hyperspace jump" hops between notes, per-agent colors, dwell trails that linger like a starfield
- Retrieval chains are grouped and replayable; hot links glow in the agent's color
- ⏱ Cockpit — scrub through a full day of agent activity on a timeline (play/pause/speed), plus a dashboard: per-agent stats, hourly histogram, top notes
- 🔥 Heatmaps — recent-window and long-term cumulative access frequency; hot notes swell and glow
- Click a node → read the note in place (markdown-it): wikilinks resolve, image/video embeds, backlinks
- Click or press Enter on a Reader image → open an in-app lightbox: natural-size 100%, 80vw × 80vh fit, cursor-anchored zoom, clamped pan, keyboard focus trap, and Copy image/link/Open/Download with honest GIF/SVG/large-image fallbacks
- Folder-tree sidebar (drag to resize) + quick switcher
Ctrl+P: file names,#tags, and diacritic-insensitive full-text search - Workspace: multi-tab reading, ⧉ two-pane split, ☆ pinned notes, 🕘 reading history — all persisted across sessions
- Retrieval health (
/insight): what your agents actually reach — hottest notes this week vs last, notes cooling off, notes nobody has touched in a while (with an age histogram that needs no threshold), notes never on any retrieval path, weakly connected clusters on the note-to-note graph, and coverage per area. It also describes taxonomy adherence with deterministic lexical TF-IDF: B3 scope leakage flags leaf sections closer to a sibling note than their parent note, while B4 reports the Spearman relationship between tree distance and content distance. A deterministic review worklist turns those measurements into prioritized proposals with a stable ID, exact target, and evidence: connect an unseen note to its nearest ancestor index, reduce repeated reads, add a shortcut across a long retrieval chain, or review a high-margin scope leak. The worklist is alwaysproposal_only, requires human review, and never edits or moves notes automatically. The same function powers a CLI report generator (python insight.py --report) - Integrity lamps (
/integrity): what is actually broken. Four structural checks need no configuration — dangling[[wikilinks]], broken![[embeds]],[[Note#Heading]]anchors that no longer match, orphaned images/videos. Wikilinks, embeds and headings shown inside inline or fenced code are treated as documentation, not graph edges. A strict YAML check parses each complete frontmatter block withyaml.safe_loadand reports the exact file, line and column. Five more contract checks read your own rules — required frontmatter fields, binary attachments never summarised in the note, tags outside your controlled vocabulary, index files carrying the wrong tags, andtitlethat no longer matches the filename and the H1. Click any finding to open the note right where it is - Both refresh on demand (no background polling). Integrity honours per-note opt-outs (
_-prefixed filenames,gate_ignore: true) - Turning the contract checks on: copy
docs/vault-rules.example.jsonto your vault root asvault-rules.json(or into.graph3d/, or pointGRAPH3D_VAULT_RULESat its folder) and edit it to your own vocabulary — it is a template, not a drop-in. Each check reads only its own slice, so a file declaring justmandatory_frontmatterlights that one lamp and leaves the rest off; add keys as you go. No file at all: the five lamps switch off cleanly and the structural four still run - Deliberate exceptions are declared, not guessed:
title_rule.exceptionspins the allowedtitle(andh1) for a file whose name cannot match its heading. Being listed is not an exemption — drift past the pinned value is still reported, and an exception naming a note that no longer exists is reported too, so the list cannot rot python integrity.pyprints the same report in a terminal and exits 0 when clean, 1 when something is broken, or 2 when PyYAML is unavailable. Install the optional checker withpython -m pip install pyyaml; without it the app still runs, but integrity is explicitly degraded instead of reporting a false clean result
- Point the app at a folder with no notes at all and it offers three ways in — the bundled demo vault (own port, your real server untouched), a starter vault written into that folder on one click, or a one-minute guide with a rescan button
- Until the first note exists, the empty tree, graph controls, and technical
0/0health figures stay out of the way — the onboarding choices are the whole first screen - It also catches the most common first-run mistake: if the app folder isn't named
.graph3d, it is reading the folder above the clone as your vault — the app says which folder that is, shows the right clone command, and offers a "this really is my vault" button if you know better - Scaffolding the starter vault opens the first note for you, and the invitation stays one click away at the bottom of the screen until the vault has notes
- Writing files is deliberately narrow: the in-app action only scaffolds an empty vault; the CLI can add the guide notes to an existing vault with
--force, but neither path ever overwrites an existing file - The two endpoints that have side effects are the only non-GET routes in the app, and they check the request origin — everything else is read-only
- If your vault keeps a machine-readable map of open work, the app renders it as a branching tree: one band per area, columns by dependency depth (leaves on the left), arrows meaning must be done first
- Click any item to open the note where that work was declared; the "ready only" filter shows just what is actionable on the machine you are sitting at
- The server imports the map's own script and caches by mtime — classification rules live in the vault, never duplicated in the app. Point
GRAPH3D_WORKMAP_DIRat your work-map folder (it must exposework.pywithload()/export_data()pluswork.json). No map → the endpoint returns 404 and the panel says so
- Per-host activity journals live inside the vault → two machines syncing the same vault (OneDrive, Drive, Syncthing…) merge their histories automatically; no server needed on the second machine
- Single-instance server keyed by port: verifies health by boot id, auto-restarts when source changes, cleans up stale processes — and refuses to kill anything it cannot verify as its own
- Loopback only (
127.0.0.1) — your vault is never exposed to the network
Requirements: Python 3.9+ and a modern browser. PyYAML is optional for the app and required only for strict YAML-frontmatter validation (python -m pip install pyyaml). Primary platform is Windows (process management shells out to PowerShell); the server itself is cross-platform and mac/linux support is on the roadmap.
git clone https://github.com/chuong1224/agents-knowledge-base
cd agents-knowledge-base
python try_demo.pyThat runs the cockpit on the bundled 120-note demo vault — the same one every screenshot and GIF above comes from. Fly around, click nodes to read them, press Ctrl+P to search, hit ▶ Demo hiệu ứng to see the agent effects.
# clone INTO your vault as a dot-folder (keeps it invisible to your note tools)
# ⚠ replace "path/to/YourVault" with the real path to YOUR vault — the folder
# that holds your markdown notes, e.g. "D:/Notes" or ~/Documents/Vault
git clone https://github.com/chuong1224/agents-knowledge-base "path/to/YourVault/.graph3d"
cd "path/to/YourVault/.graph3d"
python ensure_graph3d.pyThat's it — the app opens at http://127.0.0.1:8321. The vault root is simply the parent folder of .graph3d/. Re-running ensure_graph3d.py is idempotent (reuses a healthy server, replaces a stale one). On Windows you can also double-click Start-Graph3D.bat.
Give it a real launcher (Windows). Once per machine:
python install_launcher.py --hotkey "CTRL+ALT+G"You get a Start Menu + Desktop shortcut that runs pythonw ensure_graph3d.py --app — so a click opens the cockpit in its own app window: no address bar, no tab lost among twenty others. To give the running taskbar button its own neon icon too, open the app once in Edge and choose ⋯ → Apps → Install this site as an app. On later launches, ensure opens the packaged AppUserModelID registered in Windows through shell:AppsFolder (current Edge), or uses an installed Chromium shortcut's --app-id on older setups; if no site-app is installed it falls back to --app=<url> exactly as before. Set GRAPH3D_PWA_SHORTCUT only if an older Chromium setup uses a renamed or moved shortcut. --status shows what is installed, --uninstall removes the Python launcher, and --python pins a specific interpreter. By default, the installer discovers a registered Python before falling back to the current runtime; Microsoft Store package paths are converted to their stable app-execution alias when available, so a Store update does not strand the shortcut. Because there is no console, everything ensure prints goes to %LOCALAPPDATA%\claude-graph3d\launcher.log.
The point isn't the icon — it's that the path to your vault belongs to the machine, so it lives in the shortcut instead of in a note you have to open first.
Here's the secret: a vault is just a folder of markdown files. You don't need Obsidian or any special app to start one — any text editor works, and an AI agent can do the writing for you. (Obsidian is a great editor to adopt later; it opens the exact same folder.)
This repo ships a starter-vault/ — 9 short notes that teach notes, [[wikilinks]], tags, and hub notes by being read inside the app itself (Vietnamese summary included).
The app offers all of this to you, in the UI. Open it on a folder with no notes and instead of an empty void you get three doors:
- 🌌 See the demo vault — starts a second server on port 8322 for the bundled 120-note vault; the one on your own vault is left running, untouched
- 🌱 Create your first vault right here — copies
starter-vault/into the folder you opened, reloads the graph in place, and never overwrites a file that already exists - 📖 Do it yourself — 1 minute — three steps and a rescan button
Same two actions from a terminal, if you prefer:
python ensure_graph3d.py --demo # demo vault, own port, nothing installed
python ensure_graph3d.py --init-starter "path/to/MyVault" # create a new starter vault
python ensure_graph3d.py --init-starter "path/to/MyVault" --force # add guides safely; never overwriteOr lay it out by hand:
# copy the starter vault anywhere you like, then install the app into it
cp -r starter-vault "path/to/MyVault"
git clone https://github.com/chuong1224/agents-knowledge-base "path/to/MyVault/.graph3d"
cd "path/to/MyVault/.graph3d"
python ensure_graph3d.pyOpen Start Here in the Reader and follow along — in ten minutes you'll have edited your first note and watched the graph react.
Claude Code — add to your vault's .claude/settings.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Read|Grep|Glob|Edit|Write|MultiEdit|NotebookEdit",
"hooks": [
{
"type": "command",
"command": "python \"$CLAUDE_PROJECT_DIR/.graph3d/log_activity.py\"",
"shell": "bash",
"async": true,
"timeout": 15
}
]
}
]
}
}Any other agent or script: pipe the same hook-style JSON payload into log_activity.py and label the stream with --agent "MyAgent" — each agent gets a stable color on the graph. See the module docstring for the payload shape.
Remove the hook and the app still works fully — you just lose the live layer.
| What | Where |
|---|---|
| Tag → color groups | TAG_COLORS in build_graph_data.py (order = priority) + GROUP_ORDER in src/state.js |
| Folders excluded from the graph | EXCLUDED_DIRS in build_graph_data.py |
| Port | python ensure_graph3d.py --port 9000 |
| Physics feel | constants in physics() in src/graph.js |
| Default neon intensity | S.neon in src/state.js |
The default tag taxonomy reflects the author's vault — moving it to a config file is the top roadmap item.
Note on language: the UI ships in English and Vietnamese. It picks up your browser language on first run; the VI | EN switch next to the logo changes it any time and the choice is remembered. Your own content is never translated — note names, tags, colour groups and paths appear exactly as they are in your vault.
python tests/selfcheck.py # ~3s: compile checks + behavior contracts + unit tests
python tests/selfcheck.py --slow # adds port/kill-policy integration tests (~16s)The suite is designed to run with the app installed inside a real vault. Each run gets an isolated scratch directory, so private and public clones can be checked in parallel without deleting each other's journal fixtures (v1.54.1).
- Config file for tag groups & colors (no code edits needed)
- Standalone mode (
--vault path) without installing into the vault - Cross-platform process management (mac/linux)
- Semantic search for vaults that outgrow full-text
This is the daily driver for the author's own agent-operated knowledge base: AI agents read and write the vault all day, and this cockpit is how that work is watched, replayed and measured. It has grown through 30+ versioned iterations — graph first, then reader, finder, cockpit and workspace — pair-programmed with Claude, with a contract-encoded test suite guarding against every regression that ever actually happened.
Buồng lái 3D cho vault ghi chú markdown — và cửa sổ realtime nhìn các AI agent đang làm việc bên trong. (Toàn bộ ảnh chụp phía trên lấy từ demo vault tổng hợp kèm repo — không phải dữ liệu thật.)
Trỏ vào một thư mục note markdown (vault kiểu Obsidian), app phục vụ giao diện web local: graph 3D synthwave toàn bộ note/tag/file, kèm panel đọc note, tìm kiếm full-text, workspace đa tab — và lớp đặc sản: hiển thị realtime + replay + thống kê hoạt động AI agent (Claude Code dùng ngay; agent khác qua hook JSONL đơn giản).
- Chạy thử 60 giây (không cần vault): clone repo →
python try_demo.py→ mở ngay demo vault 120 note (nguồn của mọi ảnh/GIF phía trên). - Cài đặt vào vault của bạn: chỉ cần Python 3.9+ — clone vào vault thành thư mục
.graph3d(trong lệnh mẫu, thayYourVaultbằng đường dẫn thư mục vault của bạn — thư mục chứa các note markdown, ví dụD:/Notes), chạypython ensure_graph3d.py, app mở tạihttp://127.0.0.1:8321. Không npm, không build;PyYAMLlà tuỳ chọn để bật phép kiểm cú pháp frontmatter thật (python -m pip install pyyaml). Windows có thể double-clickStart-Graph3D.bat. - Lối vào đàng hoàng (Windows): chạy MỘT lần mỗi máy
python install_launcher.py --hotkey "CTRL+ALT+G"→ shortcut Start Menu + Desktop chạypythonw ensure_graph3d.py --app: click là ra cửa sổ app riêng, không thanh địa chỉ, không lẫn giữa hai chục tab. Muốn nút taskbar đang chạy cũng có icon neon riêng, mở app một lần trong Edge rồi chọn ⋯ → Apps → Install this site as an app; các lần sauensuremở AppUserModelID packaged mà Windows đăng ký quashell:AppsFolder(Edge hiện hành), hoặc dùng--app-idtừ shortcut Chromium kiểu cũ; chưa cài thì lùi về--app=<url>. Chỉ cần đặtGRAPH3D_PWA_SHORTCUTkhi bản Chromium kiểu cũ dùng shortcut đã đổi tên/di chuyển.--statusxem launcher đang cài gì ·--uninstallgỡ launcher ·--pythonghim interpreter cụ thể. Mặc định installer tìm Python đã đăng ký trước khi lùi về runtime hiện hành; đường Store Python có số build được đổi sang app-exec alias ổn định khi alias tồn tại, nên Store cập nhật không làm shortcut chết. Không có console nên thông báo của ensure nằm ở%LOCALAPPDATA%\claude-graph3d\launcher.log. Ý nghĩa thật: đường dẫn vault là thuộc tính của máy, nên nó nằm trong shortcut chứ không nằm trong một note mà bạn phải mở ra trước. - Chưa có vault? KHÔNG cần Obsidian trước. Vault chỉ là một thư mục chứa file
.md— soạn bằng Notepad cũng được. Obsidian là editor tuỳ chọn về sau, dùng chung đúng thư mục này. - Mở app trên thư mục chưa có note nào → app tự mời 3 lối đi thay vì graph rỗng: 🌌 xem demo 120 note (server riêng cổng 8322, server trên vault thật của bạn vẫn chạy nguyên), 🌱 tạo vault đầu tiên ngay tại đó (chép
starter-vault/9 note — dạy note/wikilink/tag/hub ngay trong app, có bản tiếng Việt; không bao giờ đè file đã có), 📖 tự làm 1 phút + nút quét lại. Khi chưa có note, app ẩn cây/panel/control graph và các số kỹ thuật0/0để màn đầu chỉ còn đúng hướng dẫn cần thiết. - CLI có lối an toàn cho vault đang dùng:
python ensure_graph3d.py --init-starter "đường/dẫn/VaultCuaBan" --forcethêm bộ note hướng dẫn nhưng vẫn tuyệt đối không đè file trùng tên. Cài nhầm chỗ thì app cũng nói rõ thư mục đang bị đọc, đưa lệnh clone đúng, và có nút "đây đúng là vault của tôi" nếu bạn cố ý. Tạo starter vault xong app mở luôn note đầu tiên; lời mời vẫn nằm sẵn một nút ở đáy màn hình chừng nào vault còn trống. - Graph: physics co giãn theo degree, 🧲 gom cụm theo nhóm màu, chống chồng node, preset bố cục 🪐 Vũ Trụ (xếp note theo cây index: root làm tâm, lá quây quanh index, deterministic qua reload), lọc tag / đuôi file / nhóm màu (spotlight vs declutter, nhớ qua phiên), heatmap tần suất truy cập, độ chói neon chỉnh được, hỗ trợ tiếp cận (AA, bàn phím, reduced-motion).
- Agent: hook
PostToolUsecủa Claude Code (mẫu ở phần tiếng Anh) ghi mọi thao tác đọc/sửa → hiệu ứng sao chổi, cú nhảy siêu không gian giữa các note, chuỗi truy xuất replay được, thanh tua cả ngày + dashboard per-agent. Agent khác truyền--agent "Tên"là có màu riêng. - Đọc & tìm: click node đọc note ngay (wikilink, ảnh, backlink); click/Enter ảnh mở lightbox nội bộ với 100% tự nhiên, fit 80vw × 80vh, zoom neo con trỏ, pan clamp và menu copy/link/mở/tải có fallback đúng; cây thư mục kéo-giãn,
Ctrl+Ptìm tên /#tag/ nội dung không dấu, tab + 2 pane + ghim + lịch sử đọc (persist). - Sức khoẻ vault: 🩺 truy xuất (
/insight) — note nóng tuần này so với tuần trước, note đang nguội đi, phân bố tuổi lần đụng cuối, note chưa bao giờ vào đường truy xuất, cụm ít kết nối trên đồ thị note–note, coverage theo khu vực; thêm hai descriptor taxonomy bằng TF-IDF lexical xác định: B3 scope leakage bắt section lá gần note anh em hơn note cha, còn B4 đo tương quan Spearman giữa khoảng cách cây và khoảng cách nội dung. Một worklist để người duyệt chuyển số đo thành đề xuất có ưu tiên, ID ổn định, đích chính xác và bằng chứng: nối note chưa được thấy vào index tổ tiên gần nhất, giảm đọc lặp, rút ngắn chuỗi truy xuất dài, hoặc duyệt lại scope leak có margin cao. Worklist luôn ở chế độproposal_only, bắt buộc người duyệt và không tự sửa hay di chuyển note (kèm CLIpython insight.py --reportsinh note báo cáo); 🧪 toàn vẹn (/integrity) — 4 check cấu trúc không cần cấu hình, bỏ qua wikilink/nhúng/heading minh hoạ trong inline code hoặc code fence, 1 check YAML thật báo đúng file/dòng/cột, và 5 check contract đọc luật của chính bạn. Click một mục là mở đúng note đó. CLIpython integrity.pytrả exit 0 sạch · 1 có lỗi · 2 thiếu PyYAML; thiếu dependency thì đèn báo degraded, không xanh giả. Bật phép kiểm YAML bằngpython -m pip install pyyaml. Bật 5 check đọc policy: chépdocs/vault-rules.example.jsonra gốc vault thànhvault-rules.json(hoặc vào.graph3d/, hoặc trỏGRAPH3D_VAULT_RULES) rồi sửa theo vocabulary của bạn — đây là bản mẫu, không phải bản dùng ngay; mỗi check chỉ đọc phần luật của nó nên khai một khoá là sáng đúng một đèn; không có file thì 5 đèn policy tự tắt êm, còn YAML + 4 check cấu trúc vẫn chạy. - Work map (tuỳ chọn): vault nào giữ bản đồ việc-đang-mở dạng máy đọc thì app vẽ luôn thành cây rẽ nhánh — băng ngang là nhóm, cột là độ sâu phụ thuộc (lá bên trái), mũi tên nghĩa là phải xong trước; click một việc mở note đã khai nó; lọc "chỉ việc làm được" theo đúng máy đang ngồi. Server import chính script của bản đồ (cache theo mtime) nên luật phân loại chỉ có một bản trong vault; trỏ
GRAPH3D_WORKMAP_DIRtới thư mục đó, không có thì panel nói rõ. - 2 máy: journal per-máy nằm trong vault — 2 máy sync chung vault (OneDrive/Drive/Syncthing) tự thấy lịch sử của nhau, máy thứ hai không cần chạy server.
- Ngôn ngữ: giao diện có song ngữ VI/EN — lần đầu tự nhận theo ngôn ngữ trình duyệt, đổi bằng nút VI | EN cạnh logo (nhớ lựa chọn). Nội dung của bạn không bị dịch: tên note, tag, nhóm màu, đường dẫn giữ nguyên như trong vault.
- Cấu hình: nhóm màu tag ở
TAG_COLORS(build_graph_data.py) +GROUP_ORDER(src/state.js); loại folder ởEXCLUDED_DIRS; đổi port bằng--port. Taxonomy mặc định đang theo vault của tác giả — tách ra file config là mục roadmap số một. - Test:
python tests/selfcheck.py(~3s; thêm--slowcho test port/kill ~16s). Mỗi lượt có scratch theo run-id, nên clone private/public có thể tự kiểm song song mà không xoá fixture journal của nhau (v1.54.1).
Giấy phép MIT.



