Guidance for AI/code agents working in the SpeleoDB Compass Sidecar repository.
This file is intentionally opinionated and feature-focused so agents can make correct changes without re-discovering architecture every session.
SpeleoDB Compass Sidecar is a Tauri v2 + Yew desktop application that bridges SpeleoDB (cave survey database) with Compass (desktop cave surveying software). It manages project synchronization, authentication, and launches Compass for editing.
- Simplicity First: Make every change as simple as possible. Impact minimal code.
- No Laziness: Find root causes. No temporary fixes. Principal Engineer standards
- Minimat Impact: Changes should only touch what's necessary. Avoid introducing bugs or changing unrelated parts of the code.
- Readability & Maintainability: Preserve product behavior while improving maintainability.
- Performance Conscious: Be aware of the performance impact of your changes and try to minimize the impact on performance.
- Refactor as necessary: Prefer centralized logic over duplicated code, conditionals or per-call custom checks.
- Tests are cheap: Every behavior should be tested. Untested code is broken code.
- Plan First: Write plan to
tasks/todos/with checkable items - Verify Plan: Check in before starting implementation
- Track Progress: Mark items complete as you go
- Explain Changes: High-level summary at each step
- Document Results: Add review section to tasks/todo.md"
- Capture Lessons: Update
tasks/lessons/after corrections - Documentation is Key: Document each feature and design inside
docs/. What is the feature being implemented, the design space and intents and a rapid summary of the approach taken with key APIs & concepts.
- Enter plan mode for ANY non-trivial task (3+ steps or architectural decisions)
- If something goes sideways, STOP and re-plan immediately - don't keep pushing
- Use plan mode for verification steps, not just building
- Write detailed specs upfront to reduce ambiguity
- Use subagents liberally to keep main context window clean
- Offload research, exploration, and parallel analysis to subagents
- For complex problems, throw more compute at it via subagents
- One tack per subagent for focused execution
- After ANY correction from the user: update
tasks/lessons/with the pattern - Write rules for yourself that prevent the same mistake
- Ruthlessly iterate on these lessons until mistake rate drops
- Review lessons at session start for relevant project
- Never mark a task complete without proving it works
- Diff behavior between main and your changes when relevant
- Ask yourself: "Would a staff engineer approve this?"
- Run tests, check logs, demonstrate correctness
- For non-trivial changes: pause and ask "is there a more elegant way?"
- If a fix feels hacky: "Knowing everything I know now, implement the elegant solution"
- Skip this for simple, obvious fixes - don't over-engineer
- Challenge your own work before presenting it
- When given a bug report: just fix it. Don't ask for hand-holding
- Point at logs, errors, failing tests - then resolve them
- Zero context switching required from the user
- Go fix failing CI tests without being told how
For map viewer/frontend changes, validate tests:
npm run test:js
Backend/API changes should also run relevant pytest targets:
pytest
New tests should respects coding existing structures
Run make lint to validate the codebase. This depends on:
make lint-fmt—cargo fmt --all -- --checkmake lint-clippy—cargo clippy --workspace --all-targets --all-features -- -D warnings
Clippy runs with -D warnings so any clippy lint blocks the lint stage and
CI. Fix the lint at its root rather than #[allow(...)]-annotating it
unless there is a documented reason.
When changing feature behavior or architecture, update docs under docs/
for the impacted topic:
- feature intent
- engineering scope and ownership boundaries
- testing and verification strategy
- performance implications
Do not only document "what changed"; include "why this architecture exists".
Before finishing map viewer work, check:
- No duplicated permission matrix logic was added.
- Depth mode toggles still avoid per-feature rescans.
- Public and private map viewers still initialize shared modules correctly.
- Lint and tests pass from root.
- Tailwind outputs still generate from root scripts.
- Prefer shared utilities/modules over code duplication.
- Add focused tests when changing anything of significance.
- Be performance conscious.
- Systematically document all features & architectural decisions.
- Duplicate code or logic.
- Introduce "quick patches" that hinder long term maintainability.
- Add expensive computations.
# Development with hot-reload
make dev
# or: cd app && cargo tauri dev
# Build release
make build-tauri
# or: cd app && cargo tauri build
# Build UI only (WASM)
make build-ui
# or: cd app && trunk build --releaseAll tests make real HTTP requests - no mocks. Requires .env file with valid credentials.
# Setup: copy .env.dist to .env and add credentials
cp .env.dist .env
# Edit .env with TEST_SPELEODB_INSTANCE and TEST_SPELEODB_OAUTH
# Test everything (Rust + WASM)
make test
# Test only Rust (excludes WASM UI)
make test-rust
# Test specific crates
make test-tauri # Tauri backend only
make test-common # Common crate only
make test-ui # WASM UI tests (requires wasm-pack)
# Verbose output
make test-rust-verbose
# Run specific test
cargo test native_auth_request
# Run tests serially (prevents race conditions)
cargo test -- --test-threads=1Five Cargo workspace members (resolver v3, Rust edition 2024):
- api/ - SpeleoDB REST API client (auth, project CRUD, mutex acquire/release)
- app/ - Yew WASM frontend (
speleodb-compass-sidecar-ui, components + IPC to backend) - app/src-tauri/ - Tauri backend (
speleodb-compass-sidecar, commands, state management, Compass integration) - common/ - Shared types (ApiInfo, OauthToken, ProjectInfo, UiState, LoadingState, LocalProjectStatus)
- errors/ - Single Error enum with ~30 variants, serializable for frontend
Workspace dependencies defined in root Cargo.toml: bytes, log, serde, serde_json, thiserror, tokio, toml, url, uuid.
-
Authentication: Frontend calls
auth_requestcommand → backend calls api crate → credentials stored in~/.compass/user_prefs.json(TOML format, 0o600 permissions on Unix) -
Project Sync: Backend fetches from SpeleoDB API → compares with local
.revision.txtfiles → emits LocalProjectStatus (RemoteOnly, EmptyLocal, UpToDate, OutOfDate, Dirty, DirtyAndOutOfDate) -
Compass Launch: Backend acquires project mutex via API → launches wcomp32.exe (Windows) → monitors process via sysinfo crate → releases mutex when Compass closes. On macOS/Linux, opens the project folder in the system file explorer instead.
-
Background Tasks:
AppStateruns a background async task polling every 120s for remote project updates and every 1s for local status changes (including Compass process monitoring on Windows).
Backend (app/src-tauri/src/)
lib.rs- Tauri app setup: plugins (updater, dialog), command registration, window close prevention if Compass is open, menu with sign-out, Sentry initcommands.rs- Tauri commands:about_info,auth_request,clear_active_project,create_project,discard_changes,ensure_initialized,import_compass_project,open_project,pick_compass_project_file,reimport_compass_project,release_project_mutex,save_project,set_active_project,sign_outstate.rs-AppStatewith Mutex-protected fields (api_info, project_info HashMap, active_project, compass_pid, loading_state), background task,emit_app_state_change()to pushUiStateto frontend viaUI_STATE_EVENTpaths.rs- Path constants and helpers:~/.compass/home dir,~/.compass/projects/{uuid}/indexandworking_copylayout, file logger setupuser_prefs.rs-UserPrefspersistence: load/save TOML credentials, env var fallback for tests (TEST_SPELEODB_INSTANCE,TEST_SPELEODB_OAUTH)project_management/mod.rs-ProjectManager: local status detection, project download/upload, mutex managementproject_management/local_project.rs-LocalProject: Compass file handling (.MAK,.DAT,.PLT), dirty detection (index vs working_copy), ZIP packing, project import viacompass_datacrateproject_management/revision.rs-.revision.txtread/write for tracking synced commit hash
Frontend (app/src/)
main.rs- WASM entry: panic hook, wasm_logger, rendersAppapp.rs- Root component: subscribes toUI_STATE_EVENT, callsensure_initialized(), routes to AuthScreen / MainLayout / LoadingScreen based onLoadingStatespeleo_db_controller.rs-SpeleoDBControllersingleton wrapping Tauriinvoke()calls with input validation (OAuth = 40 hex chars)error.rs- FrontendErrorenum (Command, Serde variants)ui_constants.rs- Color palette constants (warn, alarm, good, blue, grey)components/mod.rs- Module declarations for all componentscomponents/auth_screen.rs- Login UI with OAuth token and email/password tabs, instance URL dropdown (stage/production)components/main_layout.rs- Two-pane authenticated layout: project listing + project details, header with user email and sign-outcomponents/project_listing.rs- Scrollable project list fromUiState.project_statuscomponents/project_listing_item.rs- Individual project row with status indicatorcomponents/project_details.rs- Project detail view: open in Compass, download, commit form, read-only indicator, mutex statuscomponents/create_project_modal.rs- New project form (name, description, country, coordinates)components/loading_screen.rs- Loading state display with status textcomponents/modal.rs- Generic modal component (Success, Error, Info, Warning, Confirmation types)
API (api/src/)
lib.rs- Module declarations, global HTTP client (reqwest) with 10s timeouthttp.rs- Centralized v2 plumbing:v2_url(),authenticated(),send_json(),send_raw(),map_status_to_error(). Single chokepoint for status-code → typedErrormapping (401/403→Unauthorized, 404→NotFound, 422→Unprocessable, 409/423→Conflict, otherwiseApi{status,message})auth.rs-authorize_with_token()andauthorize_with_email()againstapi/v2/user/auth-token/project.rs-create_project(),fetch_project_info(),fetch_projects(),acquire_project_mutex()(Conflict→ProjectMutexLocked),release_project_mutex(),download_project_zip()(Unprocessable→NoProjectData),upload_project_zip()— all underapi/v2/projects/test_support.rs(test-only) -.envautoloader,test_api_info(),unauthorized_api_info(),fixture_project_id()(lazy shared OnceCell),build_minimal_compass_zip(). Seedocs/api-v2.mdfor the testing strategy.
Common (common/src/)
lib.rs- Re-exports, conditionalAPI_BASE_URL(stage in debug, production in release)api_info.rs-ApiInfo(instance URL, email, oauth_token),OauthTokennewtypeapi_types.rs-ProjectInfo,CommitInfo,ProjectType(ARIANE, COMPASS),ProjectSaveResultui_state.rs-UiState,LoadingState,LocalProjectStatus,ProjectStatus,Platformerror.rs- SingleErrorenum covering auth, file I/O, project state, network, OS/Compass, serialization. HTTP-derived variants:Unauthorized(String),NotFound(String),Unprocessable(String),Conflict(String), genericApi{status,message}— every variant carries the server-provided message.
- Frontend → Backend:
invoke()calls viatauri-sys(JSON serialized withserde-wasm-bindgen) - Backend → Frontend:
emit()events viaUI_STATE_EVENT("ui-state-update") - Frontend listens with Yew stream subscription in
Appcomponent
~/.compass/
├── user_prefs.json # Credentials (TOML format despite .json extension)
├── speleodb_compass*.log # Application logs (flexi_logger)
└── projects/
└── {project-uuid}/
├── index/ # Last synced remote copy
│ ├── .compass/ # compass.toml with SpeleoDb metadata
│ └── ... # Compass project files
├── working_copy/ # User's editable copy
│ └── ... # Compass project files (.MAK, .DAT, .PLT)
└── .revision.txt # Commit hash of last sync
Logs written to: ~/.compass/speleodb_compass*.log
# Real-time logs
tail -f ~/.compass/speleodb_compass*.log
# Search logs
grep "pattern" ~/.compass/speleodb_compass*.log- Tauri 2 with plugins:
tauri-plugin-dialog,tauri-plugin-updater - Yew 0.22 (CSR mode) with
yew_icons(FontAwesome) - compass_data 0.0.7 - Parses Compass survey file formats
- sentry 0.46 - Error tracking
- reqwest 0.12 (rustls-tls) - HTTP client for SpeleoDB API
- sysinfo 0.33 (Windows only) - Compass process monitoring
- zip 7 - Project packaging for upload/download
Requires Windows toolchain with MinGW:
rustup toolchain install stable-x86_64-pc-windows-gnu
rustup default stable-x86_64-pc-windows-gnu
rustup target add wasm32-unknown-unknown
cargo install tauri-cli --version "^2.0.0" --locked
cargo install trunk --locked
cargo install wasm-packAlso requires MSYS2 with base-devel and mingw-w64-ucrt-x86_64-toolchain packages.
ci.yml- Runs on push/PR to main, executesmake teston Windows. Uses cargo-binstall for trunk/wasm-pack.publish.yml- Triggered by git tags, depends on CI passing. Builds for macOS (aarch64) and Windows viatauri-action. Creates signed GitHub release with updater artifacts.dependabot.yml- Automated dependency updates
- Cargo.toml and tauri.conf.json:
0.1.0 SPELEODB_COMPASS_VERSIONconstant inlib.rs:1.0.0