CLAUDE.md — Cabinet
What is this project?
Cabinet is an AI-first self-hosted knowledge base and startup OS. All content lives as markdown files on disk. The web UI provides WYSIWYG editing, a collapsible tree sidebar, drag-and-drop page organization, and an AI panel that can edit pages via Claude CLI.
Core philosophy: Humans define intent. Agents do the work. The knowledge base is the shared memory between both.
Tech Stack
- Framework: Next.js 16 (App Router), TypeScript
- UI: Tailwind CSS + shadcn/ui (base-ui based, NOT Radix — no
asChildprop) - Editor: Tiptap (ProseMirror-based) with markdown roundtrip via HTML intermediate
- State: Zustand (tree-store, editor-store, ai-panel-store, app-store)
- Fonts: Inter (sans) + JetBrains Mono (code)
- Icons: Lucide (no emoji in system chrome)
- Markdown: gray-matter (frontmatter), unified/remark (MD→HTML), turndown (HTML→MD)
- AI: Claude CLI headless mode (
claude -p) for page editing
Architecture
src/
app/api/tree/ → GET tree structure from /data
app/api/pages/[...path]/ → GET/PUT/POST/DELETE/PATCH pages
app/api/upload/[...path]/ → POST file upload to page directory
app/api/assets/[...path]/ → GET/PUT static file serving + raw file writes
app/api/search/ → GET full-text search
app/api/tasks/ → GET/POST task board CRUD
app/api/agents/ → GET/POST agent sessions
app/api/jobs/ → GET/POST scheduled jobs
app/api/git/ → Git log, diff, commit endpoints
app/api/ai/edit/ → POST instruction → Claude edits page
stores/ → Zustand (tree, editor, ai-panel, task, app)
components/sidebar/ → Tree navigation, drag-and-drop, context menu
components/editor/ → Tiptap WYSIWYG + toolbar, website/PDF/CSV viewers
components/ai-panel/ → Right-side AI chat panel
components/tasks/ → Kanban board
components/agents/ → Agent dashboard
components/jobs/ → Jobs manager UI
components/terminal/ → xterm.js web terminal
components/search/ → Cmd+K search dialog
components/layout/ → App shell, header
lib/storage/ → Filesystem ops (path-utils, page-io, tree-builder, task-io)
lib/markdown/ → MD↔HTML conversion
lib/git/ → Git service (auto-commit, history, diff)
lib/agents/ → Agent session manager
lib/jobs/ → Job scheduler (node-cron)
server/
terminal-server.ts → Standalone WebSocket server for PTY sessions
data/ → Content directory (KB pages, tasks, jobs)
Key Rules
- No database — everything is files on disk under
/data - Pages are directories with
index.md+ assets, or standalone.mdfiles. PDFs and CSVs are also first-class content types. - Frontmatter (YAML) stores metadata: title, created, modified, tags, icon, order
- Path traversal prevention — all resolved paths must start with DATA_DIR
- shadcn/ui uses base-ui (not Radix) — DialogTrigger, ContextMenuTrigger etc. do NOT have
asChild - Dark mode default — theme toggle available, use
next-themeswithattribute="class" - Auto-save — debounced 500ms after last keystroke in editor-store
- AI edits — Claude edits files DIRECTLY using its tools (read/edit), NOT by returning full content as stdout. The
/api/ai/editendpoint gives Claude the file path and instruction — Claude uses its file editing tools to make targeted changes. - Version restore — users can restore any page to a previous git commit via the Version History panel
- Embedded apps — dirs with
index.html+ noindex.mdrender as iframes. Add.appmarker for full-screen mode (sidebar + AI panel auto-collapse) - Linked repos —
.repo.yamlin a data dir links it to a Git repo (local path + remote URL). Agents use this to read/search source code in context. Seedata/CLAUDE.mdfor full spec.
AI Editing Behavior (CRITICAL)
When the AI panel sends an edit request:
- Claude gets the file path and instruction — it should READ the file, then make TARGETED edits
- NEVER replace the entire file — only modify the specific parts the user asked about
- PRESERVE existing content — "add X" means INSERT, not REPLACE
- The output shown in the AI panel is Claude's summary of what it changed, NOT the file content
- If content gets corrupted — users can restore from Version History (clock icon → select commit → Restore)
The AI panel supports @ mentions — users type @PageName to attach other pages as context. The mentioned pages' content is fetched and appended to the prompt so Claude has full context.
Commands
npm run dev # Start Next.js dev server on localhost:3000
npm run dev:terminal # Start terminal WebSocket server on localhost:3001
npm run dev:all # Start both servers
npm run debug:chrome # Launch Chrome with CDP on localhost:9222 for frontend debugging
npm run build # Production build
npm run lint # ESLint
Frontend Debugging
Use npm run debug:chrome when you need a debuggable browser session. It launches Chrome or Chromium with --remote-debugging-port=9222, opens Cabinet at http://localhost:3000 by default, and prints the DevTools endpoints:
http://127.0.0.1:9222/json/versionhttp://127.0.0.1:9222/json/list
This makes it possible to attach over CDP and inspect real DOM, network, and screenshots instead of guessing at frontend state.
Progress Tracking
After every change you make to this project, append an entry to PROGRESS.md using this format:
[YYYY-MM-DD] Brief description of what changed in 1-3 sentences.
This is mandatory. Do not skip it. The PROGRESS.md file is the changelog for this project.