Files
tolaria/docs/GETTING-STARTED.md
lucaronin 90a3ff8194 refactor: flatten vault structure — simplify migration API and flatten demo vault
- Simplify flatten_vault API to return usize instead of MigrationResult struct
- Add KEEP_FOLDERS: attachments/ and _themes/ alongside type/, config/, theme/
- Use HashSet for collision tracking in unique_filename
- Update wikilinks from path-based [[folder/slug]] to title-based [[slug]]
- Clean up empty directories after flattening
- Flatten demo-vault-v2: move all notes from type-based subfolders to root
- Update smoke tests for flat vault structure
- Remove migrate_to_flat_vault from repair_vault (one-time migration only)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 23:40:47 +01:00

17 KiB

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

# 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 />)
│   ├── 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:

if (isTauri()) {
  result = await invoke<T>('command', { args })
} else {
  result = await mockInvoke<T>('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

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

# 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/<slug>.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())