# Getting Started How to navigate the codebase, run the app, and find what you need. ## Prerequisites - **Node.js** 18+ and **pnpm** - **Rust** 1.77.2+ (for the Tauri backend) - **git** CLI (required by the git integration features) - **qmd** (optional — for search indexing; auto-installed if missing) ## Quick Start ```bash # Install dependencies pnpm install # Run in browser (no Rust needed — uses mock data) pnpm dev # Open http://localhost:5173 # Run with Tauri (full app, requires Rust) pnpm tauri dev # Run tests pnpm test # Vitest unit tests cargo test # Rust tests (from src-tauri/) pnpm playwright:smoke # Playwright smoke tests ``` ## Directory Structure ``` laputa-app/ ├── src/ # React frontend │ ├── main.tsx # Entry point (renders ) │ ├── App.tsx # Root component — orchestrates layout + state │ ├── App.css # App shell layout styles │ ├── types.ts # Shared TS types (VaultEntry, Settings, etc.) │ ├── mock-tauri.ts # Mock Tauri layer for browser testing │ ├── theme.json # Editor theme configuration │ ├── index.css # Global CSS variables + Tailwind setup │ │ │ ├── components/ # UI components (~98 files) │ │ ├── Sidebar.tsx # Left panel: filters + type groups │ │ ├── SidebarParts.tsx # Sidebar subcomponents │ │ ├── NoteList.tsx # Second panel: filtered note list │ │ ├── NoteItem.tsx # Individual note item │ │ ├── PulseView.tsx # Git activity feed (replaces NoteList) │ │ ├── Editor.tsx # Third panel: tabs + editor orchestration │ │ ├── EditorContent.tsx # Editor content area │ │ ├── EditorRightPanel.tsx # Right panel toggle │ │ ├── editorSchema.tsx # BlockNote schema + wikilink type │ │ ├── RawEditorView.tsx # CodeMirror raw editor │ │ ├── Inspector.tsx # Fourth panel: metadata + relationships │ │ ├── DynamicPropertiesPanel.tsx # Editable frontmatter properties │ │ ├── AIChatPanel.tsx # AI chat (API-based) │ │ ├── AiPanel.tsx # AI agent (Claude CLI subprocess) │ │ ├── AiMessage.tsx # Agent message display │ │ ├── AiActionCard.tsx # Agent tool action cards │ │ ├── SearchPanel.tsx # Search interface │ │ ├── SettingsPanel.tsx # App settings │ │ ├── StatusBar.tsx # Bottom bar: vault picker + sync │ │ ├── CommandPalette.tsx # Cmd+K command launcher │ │ ├── TabBar.tsx # Tab management │ │ ├── BreadcrumbBar.tsx # Breadcrumb + word count + actions │ │ ├── WelcomeScreen.tsx # Onboarding screen │ │ ├── GitHubVaultModal.tsx # GitHub vault clone/create │ │ ├── GitHubDeviceFlow.tsx # GitHub OAuth device flow │ │ ├── ThemePropertyEditor.tsx # Interactive theme editor │ │ ├── ConflictResolverModal.tsx # Git conflict resolution │ │ ├── CommitDialog.tsx # Git commit modal │ │ ├── CreateNoteDialog.tsx # New note modal │ │ ├── CreateTypeDialog.tsx # New type modal │ │ ├── UpdateBanner.tsx # In-app update notification │ │ ├── inspector/ # Inspector sub-panels │ │ │ ├── BacklinksPanel.tsx │ │ │ ├── RelationshipsPanel.tsx │ │ │ ├── GitHistoryPanel.tsx │ │ │ └── ... │ │ └── ui/ # shadcn/ui primitives │ │ ├── button.tsx, dialog.tsx, input.tsx, ... │ │ │ ├── hooks/ # Custom React hooks (~87 files) │ │ ├── useVaultLoader.ts # Loads vault entries + content │ │ ├── useVaultSwitcher.ts # Multi-vault management │ │ ├── useVaultConfig.ts # Per-vault UI settings │ │ ├── useNoteActions.ts # Tab management, navigation, CRUD │ │ ├── useTabManagement.ts # Tab ordering + lifecycle │ │ ├── useAIChat.ts # AI chat state │ │ ├── useAiAgent.ts # AI agent state + tool tracking │ │ ├── useAiActivity.ts # MCP UI bridge listener │ │ ├── useAutoSync.ts # Auto git pull/push │ │ ├── useConflictResolver.ts # Git conflict handling │ │ ├── useEditorSave.ts # Auto-save with debounce │ │ ├── useTheme.ts # Flatten theme.json → CSS vars │ │ ├── useThemeManager.ts # Vault theme lifecycle │ │ ├── useIndexing.ts # Search indexing management │ │ ├── useNoteSearch.ts # Note search │ │ ├── useCommandRegistry.ts # Command palette registry │ │ ├── useAppCommands.ts # App-level commands │ │ ├── useAppKeyboard.ts # Keyboard shortcuts │ │ ├── useSettings.ts # App settings │ │ ├── useOnboarding.ts # First-launch flow │ │ ├── useCodeMirror.ts # CodeMirror raw editor │ │ ├── useMcpBridge.ts # MCP WebSocket client │ │ ├── useMcpStatus.ts # MCP registration status │ │ ├── useUpdater.ts # In-app updates │ │ └── ... │ │ │ ├── utils/ # Pure utility functions (~48 files) │ │ ├── wikilinks.ts # Wikilink preprocessing pipeline │ │ ├── frontmatter.ts # TypeScript YAML parser │ │ ├── ai-agent.ts # Agent stream utilities │ │ ├── ai-chat.ts # Chat API client + token estimation │ │ ├── ai-context.ts # Context snapshot builder │ │ ├── noteListHelpers.ts # Sorting, filtering, date formatting │ │ ├── themeSchema.ts # Theme editor schema builder │ │ ├── configMigration.ts # localStorage → vault config migration │ │ ├── iconRegistry.ts # Phosphor icon registry │ │ ├── propertyTypes.ts # Property type definitions │ │ ├── vaultListStore.ts # Vault list persistence │ │ ├── vaultConfigStore.ts # Vault config store │ │ └── ... │ │ │ ├── lib/ │ │ └── utils.ts # Tailwind merge + cn() helper │ │ │ └── test/ │ └── setup.ts # Vitest test environment setup │ ├── src-tauri/ # Rust backend │ ├── Cargo.toml # Rust dependencies │ ├── build.rs # Tauri build script │ ├── tauri.conf.json # Tauri app configuration │ ├── capabilities/ # Tauri v2 security capabilities │ ├── src/ │ │ ├── main.rs # Entry point (calls lib::run()) │ │ ├── lib.rs # Tauri setup + command registration (61 commands) │ │ ├── commands.rs # All Tauri command handlers │ │ ├── vault/ # Vault module │ │ │ ├── mod.rs # Core types, parse_md_file, scan_vault │ │ │ ├── cache.rs # Git-based incremental caching │ │ │ ├── parsing.rs # Text processing + title extraction │ │ │ ├── trash.rs # Trash auto-purge │ │ │ ├── rename.rs # Rename + cross-vault wikilink update │ │ │ ├── image.rs # Image attachment saving │ │ │ ├── migration.rs # Frontmatter migration │ │ │ └── getting_started.rs # Getting Started vault creation │ │ ├── frontmatter/ # Frontmatter module │ │ │ ├── mod.rs, yaml.rs, ops.rs │ │ ├── git/ # Git module │ │ │ ├── mod.rs, commit.rs, status.rs, history.rs │ │ │ ├── conflict.rs, remote.rs, pulse.rs │ │ ├── github/ # GitHub module │ │ │ ├── mod.rs, auth.rs, api.rs, clone.rs │ │ ├── theme/ # Theme module │ │ │ ├── mod.rs, create.rs, defaults.rs, seed.rs │ │ ├── search.rs # qmd search integration │ │ ├── indexing.rs # qmd indexing + progress streaming │ │ ├── claude_cli.rs # Claude CLI subprocess management │ │ ├── ai_chat.rs # Direct Anthropic API client │ │ ├── mcp.rs # MCP server lifecycle + registration │ │ ├── settings.rs # App settings persistence │ │ ├── vault_config.rs # Per-vault UI config │ │ ├── vault_list.rs # Vault list persistence │ │ └── menu.rs # Native macOS menu bar │ └── icons/ # App icons │ ├── mcp-server/ # MCP bridge (Node.js) │ ├── index.js # MCP server entry (stdio, 14 tools) │ ├── vault.js # Vault file operations │ ├── ws-bridge.js # WebSocket bridge (ports 9710, 9711) │ ├── test.js # MCP server tests │ └── package.json │ ├── e2e/ # Playwright E2E tests (~26 specs) ├── tests/smoke/ # Smoke tests (~10 specs) ├── design/ # Per-task design files ├── demo-vault-v2/ # Getting Started demo vault ├── scripts/ # Build/utility scripts │ ├── package.json # Frontend dependencies + scripts ├── vite.config.ts # Vite bundler config ├── tsconfig.json # TypeScript config ├── playwright.config.ts # E2E test config ├── ui-design.pen # Master design file ├── CLAUDE.md # Project instructions └── docs/ # This documentation ``` ## Key Files to Know ### Start here | File | Why it matters | |------|---------------| | `src/App.tsx` | Root component. Shows the 4-panel layout, state flow, and how all features connect. | | `src/types.ts` | All shared TypeScript types. Read this first to understand the data model. | | `src-tauri/src/commands.rs` | All 61 Tauri command handlers. This is the frontend-backend API surface. | | `src-tauri/src/lib.rs` | Tauri setup, command registration, startup tasks, WebSocket bridge lifecycle. | ### Data layer | File | Why it matters | |------|---------------| | `src/hooks/useVaultLoader.ts` | How vault data is loaded and managed. The Tauri/mock branching pattern. | | `src/hooks/useNoteActions.ts` | Tab management, wikilink navigation, frontmatter CRUD. The biggest hook. | | `src/hooks/useVaultSwitcher.ts` | Multi-vault management, vault switching, Getting Started vault. | | `src/mock-tauri.ts` | Mock data for browser testing. Shows the shape of all Tauri responses. | ### Backend | File | Why it matters | |------|---------------| | `src-tauri/src/vault/mod.rs` | Vault scanning, frontmatter parsing, entity type inference, relationship extraction. | | `src-tauri/src/vault/cache.rs` | Git-based incremental caching — how large vaults load fast. | | `src-tauri/src/frontmatter/ops.rs` | YAML manipulation — how properties are updated/deleted in files. | | `src-tauri/src/git/` | All git operations (commit, pull, push, conflicts, pulse). | | `src-tauri/src/github/` | GitHub OAuth device flow + repo clone/create. | | `src-tauri/src/search.rs` | qmd search integration (keyword/semantic/hybrid). | | `src-tauri/src/claude_cli.rs` | Claude CLI subprocess spawning + NDJSON stream parsing. | ### Editor | File | Why it matters | |------|---------------| | `src/components/Editor.tsx` | BlockNote setup, tab bar, breadcrumb bar, diff/raw toggle. | | `src/components/editorSchema.tsx` | Custom wikilink inline content type definition. | | `src/utils/wikilinks.ts` | Wikilink preprocessing pipeline (markdown ↔ BlockNote). | | `src/components/RawEditorView.tsx` | CodeMirror 6 raw markdown editor. | ### AI | File | Why it matters | |------|---------------| | `src/components/AiPanel.tsx` | AI agent panel — Claude CLI with tool execution, reasoning, actions. | | `src/components/AIChatPanel.tsx` | AI chat panel — API-based chat without tools. | | `src/hooks/useAiAgent.ts` | Agent state: messages, streaming, tool tracking, file detection. | | `src/utils/ai-context.ts` | Context snapshot builder for AI conversations. | ### Styling & Themes | File | Why it matters | |------|---------------| | `src/index.css` | All CSS custom properties. The design token source of truth. | | `src/theme.json` | Editor-specific theme (fonts, headings, lists, code blocks). | | `src/hooks/useThemeManager.ts` | Vault theme lifecycle (switch, create, apply, live preview). | | `docs/THEMING.md` | Full theme system documentation. | ### Settings & Config | File | Why it matters | |------|---------------| | `src/hooks/useSettings.ts` | App settings (API keys, GitHub token, sync interval). | | `src/hooks/useVaultConfig.ts` | Per-vault UI preferences (zoom, view mode, colors). | | `src/components/SettingsPanel.tsx` | Settings UI including GitHub OAuth connection. | ## Architecture Patterns ### Tauri/Mock Branching Every data-fetching operation checks `isTauri()` and branches: ```typescript if (isTauri()) { result = await invoke('command', { args }) } else { result = await mockInvoke('command', { args }) } ``` This lives in `useVaultLoader.ts` and `useNoteActions.ts`. Components never call Tauri directly. ### Props-Down, Callbacks-Up No global state management (no Redux, no Context). `App.tsx` owns the state and passes it down as props. Child-to-parent communication uses callback props (`onSelectNote`, `onCloseTab`, etc.). ### Discriminated Unions for Selection State ```typescript type SidebarSelection = | { kind: 'filter'; filter: SidebarFilter } | { kind: 'sectionGroup'; type: string } | { kind: 'entity'; entry: VaultEntry } | { kind: 'topic'; entry: VaultEntry } ``` ### Command Registry `useCommandRegistry` + `useAppCommands` build a centralized command registry. Commands are registered with labels, shortcuts, and handlers. The `CommandPalette` (Cmd+K) fuzzy-searches this registry. The native macOS menu bar also triggers commands via `useMenuEvents`. ## Running Tests ```bash # Unit tests (fast, no browser) pnpm test # Unit tests with coverage (must pass ≥70%) pnpm test:coverage # Rust tests cargo test # Rust coverage (must pass ≥85% line coverage) cargo llvm-cov --manifest-path src-tauri/Cargo.toml --no-clean --fail-under-lines 85 # Playwright smoke tests (requires dev server) BASE_URL="http://localhost:5173" pnpm playwright:smoke # Single Playwright test BASE_URL="http://localhost:5173" npx playwright test tests/smoke/.spec.ts ``` ## Common Tasks ### Add a new Tauri command 1. Write the Rust function in the appropriate module (`vault/`, `git/`, etc.) 2. Add a command handler in `commands.rs` 3. Register it in the `generate_handler![]` macro in `lib.rs` 4. Call it from the frontend via `invoke()` in the appropriate hook 5. Add a mock handler in `mock-tauri.ts` ### Add a new component 1. Create `src/components/MyComponent.tsx` 2. If it needs vault data, receive it as props from the parent 3. Wire it into `App.tsx` or the relevant parent component 4. Add a test file `src/components/MyComponent.test.tsx` ### Add a new entity type 1. Create a type document: `type/mytype.md` with `type: Type` frontmatter (icon, color, order, etc.) 2. The sidebar section groups are auto-generated from type documents — no code change needed if `visible: true` 3. Update `CreateNoteDialog.tsx` type options if users should be able to create it from the dialog 4. Notes of this type are created at the vault root with `type: MyType` in frontmatter — no dedicated folder needed ### Add a command palette entry 1. Register the command in `useAppCommands.ts` via the command registry 2. Add a corresponding menu bar item in `menu.rs` for discoverability 3. If it has a keyboard shortcut, register it in `useAppKeyboard.ts` ### Add or modify a theme 1. **Vault-based** (preferred): Create/edit a markdown note in `theme/` with `type: Theme` frontmatter 2. **Programmatic**: Edit defaults in `src-tauri/src/theme/defaults.rs` 3. See `docs/THEMING.md` for the full property reference ### Work with the AI agent 1. **Agent system prompt**: Edit `src/utils/ai-agent.ts` (inline system prompt string) 2. **Context building**: Edit `src/utils/ai-context.ts` for what data is sent to the agent 3. **Tool action display**: Edit `src/components/AiActionCard.tsx` 4. **Claude CLI arguments**: Edit `src-tauri/src/claude_cli.rs` (`run_agent_stream()`)