Map of Cmdr's major subsystems. Each directory has detailed docs in their CLAUDE.md file!
All under apps/desktop/src/lib/.
| Directory | Purpose |
|---|---|
file-explorer/ |
Dual-pane file explorer: pane orchestration, selection, navigation, sorting |
file-explorer/views/ |
Virtual-scrolling file lists (Brief + Full modes), 100k+ file support |
file-explorer/drag/ |
Native drag-and-drop (drag-out, drop-in, pane-to-pane, macOS image swizzle) |
file-explorer/rename/ |
Inline rename with validation, conflict resolution, extension change |
file-explorer/selection/ |
Space/Shift/Cmd selection, range operations |
file-explorer/navigation/ |
Back/forward history, breadcrumb, path utilities |
file-explorer/network/ |
Network browser UI (SMB share browsing, login form) |
file-explorer/git/ |
Git browser frontend (complete). Breadcrumb chip, status-column helpers, reactive RepoInfo store, Lucide-rendered git portal icons via selection/FileIcon.svelte. General > Git settings section lives in settings/sections/GitSection.svelte and can live-disable the backend portal for raw .git access |
file-explorer/pane/ |
Per-pane orchestration: cursor, scroll, focus, dual-pane coordination |
file-explorer/tabs/ |
Tab bar and per-pane tab state |
file-explorer/operations/ |
Pane-scoped operation hooks (delete, refresh, swap) wired into the command registry |
file-explorer/quick-look/ |
Frontend Quick Look (Shift+Space) trigger and keyboard plumbing |
file-operations/ |
Transfer dialogs (copy/move/mkdir) with progress and conflict resolution |
file-viewer/ |
Read-only file viewer (opens in separate window, virtual scrolling) |
settings/ |
Settings UI + registry-based architecture, reactive state |
shortcuts/ |
Keyboard shortcut customization, scope hierarchy, conflict detection |
ipc/ |
Auto-generated tauri-specta bindings (bindings.ts). Do not edit by hand; bindings-fresh regenerates it. Call through tauri-commands/ rather than importing directly |
tauri-commands/ |
Typed TypeScript wrappers around ipc/bindings.ts. Canonical import path for all backend IPC; never import the bindings file directly |
command-palette/ |
Fuzzy command search (~45 commands) |
commands/ |
Command registry (~50 commands), fuzzy search engine for command palette |
licensing/ |
License validation, commercial reminders, expiration modals |
logging/ |
Unified logging: LogTape config, batching bridge to Rust, verbose toggle |
error-reporter/ |
Error report dialog (Flow A preview), auto-send toast (Flow B), shared error-report-flow entry point |
crash-reporter/ |
Frontend half of the crash pipeline: detects the persisted crash file on next launch and offers to send it |
ai/ |
Local LLM features (folder suggestions), download flow. Runtime states only (downloading, installing, ready, starting); first-launch consent is owned by lib/onboarding/ |
indexing/ |
Drive index state, events, priority triggers, scan status overlay |
query-ui/ |
Shared filter-and-act-on primitives consumed by Search and (M7+) Selection: QueryBar, ModeChips, AiPromptStrip, FilterChips (size/modified/scope/pattern), QueryResults (path pills + row menus), EmptyState, recent-items/ footer + popover with adapter pattern, createQueryFilterState() factory, shared keyboard contract |
search/ |
Whole-drive file search dialog (first query-ui consumer): thin orchestrator + Search-only extras (scope, system-dir exclusions, AI label/pattern), snapshot store + virtual search-results volume, "Open in pane" handoff, MCP open_search_dialog tool, index lifecycle |
selection-dialog/ |
"Select files…" / "Deselect files…" dialog (second query-ui consumer, M7): pure matcher (glob/regex + size/date predicates over the focused-pane snapshot), folder-name sampler for AI context, cloud-only AI translation, recent-selections store, commit-on-Enter handoff via applyIndicesToFocusedPane |
mtp/ |
MTP (Android device) file browsing UI |
onboarding/ |
Soft-sheet onboarding wizard: Full Disk Access, AI provider, and optional-settings steps |
ui/ |
Shared UI primitives: ModalDialog, Button, AlertDialog, LoadingIcon, Notification, dialog registry, SectionCard grouped-card wrapper |
routes/dev/components/ |
Dev-only catalog of every primitive in lib/ui/ (Storybook replacement). Surfaced in the Debug window's "Components" sidebar entry; also reachable at http://localhost:<port>/dev/components |
tooltip/ |
Lightweight tooltip primitive used across the UI |
stores/ |
App-wide reactive Svelte stores: volume list, restricted-paths state |
updates/ |
Auto-updater UI |
utils/ |
Filename validation, confirm dialog utilities |
font-metrics/ |
Character width measurement for accurate Brief mode column sizing |
Frontend text measurement always uses @chenglou/pretext. When the frontend needs to know the pixel width of a
string (column shrink-wrapping, middle-truncation, viewer line heights, etc.), call
createPretextMeasure(font, pretext) from lib/utils/shorten-middle.ts rather than rolling a Canvas measureText or
DOM-reflow path. Pretext matches the browser's own text shaping and is dynamically imported so it doesn't bloat the
initial bundle. The separate font-metrics/ module above is a distinct concern: it ships per-character widths to Rust
for backend column sizing.
All under apps/desktop/src-tauri/src/.
| Directory/file | Purpose |
|---|---|
file_system/listing/ |
Directory reading, streaming, caching, sorting (serves virtual scroll) |
file_system/write_operations/ |
Copy/move/delete with safety patterns (temp+rename, staging, rollback) |
file_system/volume/ |
Volume trait + implementations (Local, MTP, SMB, InMemory). Has a checklist and capability matrix for adding new backends; start there |
file_system/git/ |
Git browser (complete). Repo discovery + info + status, watcher, friendly errors. Virtual .git portal (branches/, tags/, commits/, stash/, worktrees/, submodules/, raw/) wired through the Volume hooks so cross-volume copy plucks files from refs for free. redirect_to_path pivots worktree/submodule entries to their working dirs. M4 adds a live-toggleable portal hook (fileExplorer.git.showVirtualGitPortal) and FriendlyError integration end-to-end via a sentinel-encoded payload on VolumeError::IoError |
file_viewer/ |
Three-backend file viewer (FullLoad, ByteSeek, LineIndex) |
network/ |
SMB: mDNS discovery, share listing (smb-rs + smbutil), mounting, Keychain |
clipboard/ |
File clipboard (Cmd+C/X/V) with NSPasteboard interop; tracks cut state and validates clipboard consistency at paste |
secrets/ |
Pluggable secret storage: Keychain on macOS, Secret Service on Linux, encrypted-file fallback. Holds SMB credentials and AI provider API keys |
mtp/ |
MTP device management, file ops, event-based watching |
mcp/ |
MCP server (19 tools, YAML resources, agent-centric API) |
ai/ |
llama-server lifecycle, model download, inference client |
licensing/ |
Ed25519 license verification, server validation |
settings/ |
Settings persistence (tauri-plugin-store) |
indexing/ |
Background drive indexing (SQLite, jwalk, FSEvents), recursive directory sizes |
search/ |
In-memory search index (lazy load, rayon parallel scan, glob/regex) and AI query translation pipeline (search/ai/) |
selection/ |
Selection dialog backend (M5): persistent recent-selections store (selection-history.json, separate from search history) plus cloud-only AI translation (selection/ai/) for natural-language → glob/regex. The matcher itself runs in JS against the focused folder; this module only owns history and AI |
font_metrics/ |
Binary font metrics cache, per-directory width calculation |
text_size.rs |
macOS Accessibility text-size watcher. Reads UIPreferredContentSizeCategoryName from NSGlobalDomain, observes com.apple.accessibility.api distributed notifications, emits system-text-size-changed to the frontend. Both the key and the notification are undocumented Apple APIs (see source for risk notes). Frontend compounds this with appearance.textSize in lib/text-size.ts. |
system_strings.rs |
Localized macOS pane labels ("Full Disk Access", "Privacy & Security", "System Settings", ...) loaded from .loctable files in system bundles. Picks the user's preferred language from NSUserDefaults.AppleLanguages (independent of the app's UI language) and falls back to English on misses. Backend friendly-error builders call expand("... {full_disk_access} ..."); frontend caches the snapshot via lib/system-strings.svelte.ts. See module-level docs in the file for the loctable catalog and risks. |
volumes/ |
macOS location/volume discovery (Favorites, MainVolume, AttachedVolume, CloudDrive) and NSWorkspace mount/unmount watcher. Distinct from file_system/volume/, which is the cross-platform Volume trait |
volumes_linux/ |
Linux equivalent: location discovery plus mount/unmount watching via /proc/mounts and GVFS |
space_poller.rs |
Live disk-space polling: per-volume-type intervals via Volume::space_poll_interval(), threshold-based change detection, emits volume-space-changed |
fda_gate.rs |
Full Disk Access startup gate. Prevents stacking macOS TCC popups during onboarding by blocking TCC-protected reads and NSWorkspace icon calls until the user grants or denies FDA. See critical rules in AGENTS.md |
stubs/ |
Linux compilation stubs for macOS-only modules (used by Docker E2E pipeline) |
menu/ |
Native menu bar: platform-specific construction, dispatch mapping, accelerator sync, context-aware enable/disable |
quick_look/ |
macOS-only QLPreviewPanel integration (Shift+Space). Singleton controller behind Mutex, QLPreviewPanelDataSource + QLPreviewPanelDelegate via define_class!, key-forward + close events |
drag_image_detection.rs |
macOS method swizzle for drag image size detection |
drag_image_swap.rs |
Rich/transparent drag image swap for self-drags |
crash_reporter/ |
Crash capture (panic hook + signal handler), next-launch detection, report sending |
error_reporter/ |
Error reports: bundle build (manifest + redacted log tail), short-ID + R2 upload, debounced auto-dispatcher for Flow B |
updater/ |
macOS-only custom updater: syncs files into the running .app bundle in place so TCC permissions (Full Disk Access) survive updates. Other platforms use the stock Tauri updater plugin |
redact/ |
Shared PII redactor (path-shape preserving). Used by both crash and error reporters |
logging/ |
Log directory resolver, KeepSome(N) post-rotation pruner, list_recent_log_files helper used by the error reporter bundle builder |
commands/ |
Tauri command definitions (IPC entry points) |
capabilities/ |
Per-window Tauri API permissions; must be updated when using new Tauri APIs from a window |
icons/ |
App icons for all platforms + macOS Tahoe Liquid Glass (Assets.car). See CLAUDE.md for regeneration steps |
| Directory | Purpose |
|---|---|
apps/analytics-dashboard/ |
Private SvelteKit dashboard on CF Pages. Aggregates metrics from Umami, CF Analytics Engine, Paddle, PostHog, GitHub. See CLAUDE.md |
apps/api-server/ |
Cloudflare Worker + Hono. Licensing, telemetry, crash reports, downloads, and admin endpoints. See CLAUDE.md (technical reference) and README (first-time setup) |
apps/website/ |
getcmdr.com marketing site (Astro + Tailwind v4). See README and CLAUDE.md |
apps/website/public/hero/ |
Hero illustration assets (frame + pane cutouts, dark/light). See CLAUDE.md for reshoot process |
scripts/check/ |
Go unified check runner (~40 checks, parallel with dependency graph) |
Whole-drive file search powered by the index DB. The search index loads all entries into memory (~600 MB for 5M files), scans them with rayon in parallel, and returns results sorted by recency. The index is loaded lazily when the search dialog opens and dropped after idle timeout.
Backend (search/): engine.rs has a pure search() function (no I/O) that accepts &SearchIndex +
&SearchQuery and returns SearchResult. types.rs defines data structures, query.rs handles DB-touching operations
(scope resolution, directory sizes), index.rs manages global index state with idle/backstop timers. search/ai/
contains the AI query translation pipeline (prompt, parser, query builder). See src-tauri/src/search/CLAUDE.md.
IPC (commands/search.rs): Thin wrappers. prepare_search_index (starts async load, emits search-index-ready
event), search_files (returns empty if not loaded), release_search_index (starts 5-min idle timer),
translate_search_query (orchestrates search::ai pipeline). resolve_ai_backend handles AI provider config.
Lifecycle: Load on dialog open (2-3s for 5M rows with cancellation check every 100K rows) -> search while loaded -> idle timeout (5 min) or backstop timeout (10 min) drops the index.
Recent searches (search/history.rs, backend): persistent JSON store at {app_data_dir}/search-history.json,
schema-versioned, atomic write, in-memory mutex cache, canonical-key dedupe with move-to-top, configurable cap via
search.recentSearches.maxCount (default 1000, 0 disables). Frontend recent-searches-state.svelte.ts mirrors the
list; only the dialog's "Open in pane" action writes to it (per the §3.5 design call). IPC: get_recent_searches,
add_recent_search, remove_recent_search, clear_recent_searches, apply_recent_searches_max_count.
"Open in pane" virtual volume (frontend-only): volumeId = 'search-results', paths search-results://<sr-N>,
opaque to the filesystem. The snapshot-store.svelte.ts map holds the result entries (capped 10,000) under a monotonic
id; refcounts tie lifetime to pane history entries plus a "last dialog attempt" slot. Nav history caps at
MAX_HISTORY_PER_TAB = 100 (added in this redesign); push() returns dropped entries so the tab-state manager can
release snapshot refs in one step. The pane uses FullList with the new staticEntries + showPathColumn props, no
backend listing. Capabilities (read-only write surface, source-OK) come from search/capabilities.ts. See
apps/desktop/src/lib/search/CLAUDE.md and apps/desktop/src/lib/file-explorer/CLAUDE.md § Search-results virtual
volume.
MCP: open_search_dialog opens the dialog with optional pre-filled query, mode, filters, scope, and autoRun. Acks
on SoftDialogAppeared("search") within the standard 1500 ms budget. See src-tauri/src/mcp/CLAUDE.md.
For detailed architecture patterns (data flow, navigation lifecycle, listing lifecycle, concurrency guards, cancellation, volume mount/unmount, error recovery, persistence), see architecture-patterns.md. Read the relevant section when working on navigation, file operations, or volumes.
Rules that cut across many modules. All existing commands follow these; apply them to new code too.
-
Tauri IPC threading. Synchronous
#[tauri::command]functions block the IPC handler thread. If one command hangs (e.g., a filesystem syscall on a dead network mount), ALL subsequent IPC calls from the frontend queue behind it and the app appears frozen. All filesystem-touching commands areasyncwithblocking_with_timeout(2s default). When adding new commands that touch the filesystem, follow this pattern; seecommands/file_system/for examples. -
Network mount blocking syscalls.
statfs,readdir,metadata(), NSURL resource queries, andrealpathcan all block indefinitely on slow/hung network mounts (kernel waits 30–120s). Every Tauri command that calls these is wrapped inblocking_with_timeout. New commands MUST do the same. Seecommands/CLAUDE.mdfor the full pattern and timeout tiers. -
Two-layer timeout defense. Backend:
blocking_with_timeout(2–15s) wraps syscalls intokio::time::timeout. Frontend:withTimeout(500ms–3s) races IPC calls and returns a fallback on expiry. Both layers are applied for critical paths (volume switching, path resolution, volume space queries). Apply both when adding new IPC calls to slow paths.
- Full Disk Access: checked by trying to read 1 byte from a list of TCC-protected files
(
~/Library/Safari/History.db,~/Library/Mail/V10/MailData/Envelope Index, etc.) until one returns eitherOk(FDA granted) orPermissionDenied(denied; bundle gets registered with TCC). On denial, also firesmmap+NSData dataWithContentsOfFile:+read_dirof the parent (multi-trigger fallback because macOS 26 (Tahoe) can short-circuitread()denials without consulting tccd). Prompt on first launch. Seeapps/desktop/src/lib/onboarding/CLAUDE.md. - Keychain: stores network credentials and trial state. Uses
security-frameworkcrate. - copyfile(3): preserves xattrs, ACLs, resource forks.
COPYFILE_CLONEfor instant APFS clones. - ptpcamerad: auto-claims USB devices. MTP shows workaround dialog with Terminal command.
- File Provider integration:
file_system/cloud_actions.rscallsNSFileProviderManagerfor evict / download on iCloud Drive, Dropbox, Google Drive, OneDrive, Box.file_system/open_with.rsusesNSWorkspace.URLsForApplicationsToOpenURL:for "Open with" candidates. Both APIs descend intofileproviderdXPC for cloud-stub files, which can blow rayon's 2 MB worker stack, so both modules use dedicated 8 MB-stack OS threads. The Services menu (Quick Actions, third-party action extensions) is wired viaPredefinedMenuItem::servicesin thecmdrapp menu.
pnpm devat repo root for hot-reloading Tauri apppnpm dev --worktree <slug>for a per-worktree isolated session (separate data dir, ports, Dock label)- License mock via
CMDR_MOCK_LICENSE=commercial - MCP servers bind ephemeral ports on
127.0.0.1; the actual port lives in<CMDR_DATA_DIR>/mcp.portand<CMDR_DATA_DIR>/tauri-mcp.port.CMDR_MCP_PORTstill pins the Cmdr MCP server for clients that prefer that. See tooling/instance-isolation.md for the per-resource breakdown withGlobalTauri: truein dev mode (security risk if loading remote content)
Go-based unified runner (scripts/check/). Parallel execution with dependency graph. Coverage: 70% threshold enforced,
coverage-allowlist.json exempts Tauri/DOM-dependent files.
Two parallel pipelines feed the maintainer with what went wrong on a user's machine. Both pass payloads through the
shared redact/ module before sending; see docs/security.md for the privacy posture.
- Crash reporter (
crash_reporter/): captures panics + signals, persists a report to disk, and offers to send it on the next launch. TargetsPOST /crash-reportonapi.getcmdr.com. For unexpected aborts only. - Error reporter (
error_reporter/+error-reporter/): captures everything else (MTP weirdness, network glitches, generic "this didn't work"). Two flows: user-initiated (Help > Send error report…, or the button on error toasts, see Flow A) and auto-send opt-in (updates.errorReports, see Flow B). Bundles the manifest + recent debug-level log tail (governed byadvanced.maxLogStorageMb), redacts line-by-line, uploads to R2 viaPOST /error-report, returns a shortERR-XXXXXID. Server posts a Discord notification with a 7-day presigned download link to a private#error-reportschannel.
Dev workflow docs and external service references. All in docs/tooling/.
| Doc | Purpose |
|---|---|
| logging.md | Unified logging, RUST_LOG recipes for every subsystem |
| testing.md | Testing tools inventory (Rust, Vitest, Playwright, Linux E2E, Docker SMB) |
| mcp.md | MCP servers (cmdr, tauri) for agent-driven app testing |
| instance-isolation.md | CMDR_INSTANCE_ID primer: per-resource isolation for parallel dev / E2E |
| css-health-checks.md | Stylelint + Go-based unused CSS checker |
| index-query.md | index_query: query index DB with platform_case collation (sqlite3 can't) |
The check runner and E2E testing docs live colocated with their code:
- Check runner:
scripts/check/CLAUDE.md - E2E overview (all suites, fixtures):
apps/desktop/test/CLAUDE.md - Playwright E2E (tauri-playwright, cross-platform):
apps/desktop/test/e2e-playwright/CLAUDE.md - Linux E2E (Docker, VNC, legacy):
apps/desktop/test/e2e-linux/CLAUDE.md
Renovate (renovate.json in repo root) auto-updates all dependencies (npm, Cargo, Go).
Weekly grouped PRs for non-major updates (auto-merge), monthly for major (manual review). Security vulnerability patches
get immediate auto-merging PRs regardless of schedule.
| Doc | Purpose |
|---|---|
| hetzner-vps.md | Production VPS: SSH access, layout, deploy commands |
| umami.md | Website analytics: API access, DB queries, troubleshooting |
| cloudflare.md | Cmdr zones, workers, Pages, D1 telemetry |
| posthog.md | Cmdr project ID and settings |
| monitoring.md | UptimeRobot: uptime checks, alerts |
| analytics-dashboard.md | Private dashboard at analdash.getcmdr.com aggregating metrics for the maintainer |
| remark42.md | Self-hosted comments engine for the website (Docker on the Hetzner VPS) |
ONLY do read-only operations with these services unless specifically asked to make changes.