AGENTS
This file provides guidance to coding agents, such as Claude Code (claude.ai/code), when working with code in this repository.
General Behavior
- When the user provides a URL or references external content, fetch/read it FIRST before responding. Do not begin analysis or planning without the referenced material.
Task Interpretation
- When asked to create Linear issues or update project management tools, do NOT explore the codebase or begin implementation unless explicitly asked. Focus solely on the PM task first.
- When the user asks for a plan or design discussion, stay in planning mode. Do not start implementation unless explicitly instructed to proceed with coding.
Linear Integration
- When setting Linear labels, always use label IDs rather than label names. Fetch available labels first if IDs are unknown.
- Before creating a new Linear/Jira issue, always search for existing issues with similar titles or descriptions to avoid duplicates. Confirm with the user if a potential duplicate is found.
Database & Migrations
- Do not assume database migrations have been applied in local environments. Always verify migration state before proceeding.
- Check
.envfiles for available connection strings before claiming they don’t exist.
Prerequisites
Required Tools
- Node.js ≥22.0.0
- pnpm ≥10.0.0 (
npm install -g pnpm@10.30.1) - Rust (latest stable, edition 2024) with
rustup component add clippy rustfmt - uv (
brew install uvon macOS, or https://docs.astral.sh/uv/) — Python package manager for python-sidecar - gitleaks (
brew install gitleakson macOS) — required by pre-commit hook - dprint (
brew install dprinton macOS) — Markdown formatter (table alignment, line wrapping)
Platform-Specific Dependencies
macOS: Xcode Command Line Tools (xcode-select --install)
Linux (Debian/Ubuntu):
sudo apt-get install -y libwebkit2gtk-4.1-dev \ libappindicator3-dev librsvg2-dev patchelf libssl-dev libgtk-3-devBuild & Development Commands
# Developmentpnpm dev # Start all packages via Turbopnpm desktop:dev # Start desktop app only (Vite + Tauri)
# Buildpnpm build # Build all packagespnpm desktop:build # Build desktop app
# Type Generation (Rust -> TypeScript)pnpm generate:types # Required before dev/build/typecheck
# Linting & Formattingpnpm lint # oxlint for TypeScriptpnpm typecheck # TypeScript type checkingcargo clippy # Rust lintingcargo fmt # Rust formattingdprint check # Markdown formatting checkdprint fmt # Markdown auto-format
# Pre-commit Quality Gate (automatic via husky)# - gitleaks secret scanning (only hook — formatting/linting removed)
# Quality Gate (manual, scoped to changed files vs main)./tools/precheck.sh # Diff vs main (check only)./tools/precheck.sh --fix # Auto-fix formatting/linting, then check./tools/precheck.sh --base dev # Diff vs specific ref./tools/precheck.sh --no-test # Skip cargo test./tools/precheck.sh --full # Full workspace (all crates, all tests)
# Testingpnpm test # All tests via Turbocargo test # Rust tests only
# Reset App Data./tools/dev/reset-app-data.sh # Clear all app data (interactive)./tools/dev/reset-app-data.sh --force # Clear without confirmationArchitecture
Polyglot modular monolith with Clean Architecture. For the complete architecture reference including file paths, layer
breakdown, and system map, see apps/codex/src/content/docs/architecture/overview.mdx.
Key Directories
| Directory | Purpose |
|---|---|
crates/domain/ | Pure business entities, no external dependencies |
crates/application/ | Use cases + service trait abstractions |
crates/commands/ | Transport-agnostic command layer (validation, error sanitization) |
crates/infrastructure/ | Concrete implementations (sqlite, onnx, supabase, llm, agent-core, etc.) |
apps/desktop/src-tauri/ | Tauri framework layer (commands, DI wiring, MCP server) |
apps/desktop/src-react/ | React frontend (TypeScript, TipTap editor, Zustand state) |
apps/codex/ | Codex documentation site (Astro) |
apps/http-bridge/ | HTTP bridge for QA testing (Axum REST) |
apps/python-sidecar/ | Python sidecar (DSPy, LLM pipeline) |
packages/contracts/ | Generated Rust→TypeScript types (Specta) |
apps/web/ | Marketing website (Astro + Cloudflare) |
tests/core/ | Integration tests (real SQLite) |
tests/e2e/ | End-to-end tests via HTTP bridge |
Layer Dependencies
Dependencies flow inward: Framework → Infrastructure → Application → Domain. Separate crates enforce this at compile time.
Documentation Split
| Location | Content |
|---|---|
apps/codex/src/content/docs/ | Permanent architecture docs — system docs, data flows, domain rules |
docs/ | Developer process docs — ADRs, solutions, how-tos, tutorials, reference |
Loro CRDT Editor Integration
The editor uses loro-crdt and loro-prosemirror (npm) to bind TipTap to a LoroDoc. The LoroSync TipTap extension
(apps/desktop/src-react/lib/loro-sync/) registers LoroSyncPlugin (bidirectional ProseMirror ↔ Loro sync) and LoroUndoPlugin
(Loro-backed undo/redo that persists across sessions). On save, both the LoroDoc snapshot bytes and materialized
markdown text are sent to the backend.
Glossary
| Term | Definition |
|---|---|
| aggregate root | DDD concept: top-level entity that owns a cluster of related domain objects and coordinates access |
| BLOB | Binary Large Object; raw byte storage in SQLite columns |
| bounded context | DDD concept: logical boundary within which a particular domain model applies consistently |
| Capability | Permission enum variant representing a specific action a user/agent can perform (19 variants) |
| CDP | Chrome DevTools Protocol; browser automation and debugging interface |
| CRDT | Conflict-free Replicated Data Type; enables concurrent editing without coordination |
| DSPy | Offline prompt optimization framework for LLM pipelines |
| FTS5 | SQLite Full-Text Search extension version 5 |
| Loro/LoroDoc | CRDT library for block content; LoroDoc is a document instance |
| LWW | Last-Writer-Wins; conflict resolution strategy for metadata sync |
| MCP | Model Context Protocol; standardized agent integration interface |
| nextest | cargo-nextest; fast Rust test runner with per-test process isolation |
| oxlint | Fast JavaScript/TypeScript linter used for all TypeScript linting |
| PermissionGuard | Unforgeable proof-of-authorization token; module-private constructor ensures only CapabilityResolver can issue |
| PostgREST | REST API layer for PostgreSQL; used by Supabase for auto-generated APIs |
| ProseMirror | Toolkit for building rich text editors; underlies TipTap |
| Rig | Rust crate for multi-provider LLM abstraction |
| RLS | Row Level Security; PostgreSQL feature for per-row access control |
| rmcp | Rust MCP SDK crate for building MCP servers and clients |
| RRF | Reciprocal Rank Fusion; algorithm for merging ranked search results |
| sccache | Shared compilation cache for Rust; speeds up CI builds |
| Specta | Rust-to-TypeScript type generation library |
| TipTap | ProseMirror-based rich text editor framework used for the editor |
| Turbo/Turborepo | Monorepo build orchestrator; runs tasks across packages with caching |
| WAL | Write-Ahead Logging; SQLite journaling mode enabling concurrent reads |
| WriteEffectCoordinator | Side-effect dispatch pipeline that coordinates sync queue, embedding, and UI events after writes |
| Zustand | Lightweight React state management library |
Document Hierarchy (Authority Order)
When conflicts arise between documents, defer to sources in this order:
| Priority | Document | Role |
|---|---|---|
| 1 | README.md | Canonical product vision and positioning |
| 2 | Domain Rules | Business invariants (constraints) |
| 3 | Development Guide | Methodology (how, not what) |
Principle: Vision constrains requirements. Requirements constrain implementation. Domain rules are invariants at all levels.
Development Methodology
See docs/guides/development-guide.md for full details.
Vertical Slicing
All features are implemented end-to-end through layers, not layer-by-layer:
- Domain (Rust entity/validation)
- Application (Rust use case + service traits)
- Infrastructure (storage implementation)
- Framework (Tauri command)
- Frontend (React component)
Rule: If you can’t demo it, you haven’t finished it.
File-Per-Use-Case Pattern
crates/application/src/page/├── mod.rs # Re-exports├── services.rs # PageRepository trait + errors├── get.rs # GetPageUseCase├── create.rs # CreatePageUseCase└── update.rs # UpdatePageUseCaseType Generation Pipeline
Rust structs -> Specta -> TypeScript types in packages/contracts/generated/
Run pnpm generate:types after modifying Rust types.
Domain Rules (Enforced in Rust)
See apps/codex/src/content/docs/architecture/domain-rules.mdx for full details.
| Rule | Summary |
|---|---|
| Min 1 block per page | Creating page atomically creates initial block |
| No cycles | Cannot move page to become descendant of itself |
| Cascade deletion | Deleting page deletes all descendants |
| Workspace scoping | All entities belong to exactly one workspace |
| Flat workspaces | No nested workspaces |
| Block-workspace inherit | Blocks inherit workspace through page |
Testing Strategy
See docs/guides/development-guide.md#testing-strategy for full details.
- Domain layer: Pure unit tests, 100% coverage goal
- Application layer: Unit tests with mocked repos, >90% coverage
- Infrastructure: Unit tests with temp dirs, >80% coverage
- Integration tests (
tests/core/): Real use cases wired to real SQLite —cargo test -p core-tests - Frontend integration (
apps/desktop/tests/): Playwright tests with mocked Tauri backend - End-to-end (
tests/e2e/): End-to-end tests via HTTP bridge using Playwright Test Agents —pnpm test:e2e
Test naming: test_[what]_[condition]_[expected]
Test File Organization
Tests use the sibling tests.rs submodule pattern:
- Source file contains
#[cfg(test)] mod tests;(declaration, no body) - Tests live in sibling
tests.rswithuse super::*; foo.rs→foo/tests.rs;mod.rs→ siblingtests.rs- Inline
mod tests { }acceptable only for files < 200 LOC with simple tests - Shared test helpers go in
test_helpers.rswhen substantial and reused
Key Technical Decisions
- Storage: SQLite database per workspace (
inklings.db) with FTS5 for search. Block content stored as LoroDoc BLOBs for CRDT history; materialized text kept alongside for FTS indexing. - Loro CRDT: Block content uses Loro CRDTs (
loroRust crate,loro-crdt/loro-prosemirrornpm). Enables operation-level history, cross-session undo/redo, and multi-device sync. - Import: External markdown files imported via
MarkdownImporter, wiki-links converted - Links: Wiki-style
[[Page Name]]with backlink tracking - Versioning: Event log + CRDT content history + named bookmarks (git-backed checkpoint system removed)
- Embedding model: Auto-downloaded from HuggingFace on first workspace open (~585 MB). Background
tokio::spawnwith streaming progress via Tauri events (embedding-model:download-progress). SHA-256 verified. Controlled bysemantic_search_enabledsetting (default true).model_downloader.rsin src-tauri. Dev script (tools/dev/download-embedding-model.sh) still available for CI/dev.
Development Environment
The app uses environment-aware paths to isolate dev/test data from production:
| Environment | Workspaces | Settings File |
|---|---|---|
| Dev | {project}/.data/workspaces/ | {project}/.data/settings.json |
| Production | ~/Inklings/Workspaces/ | ~/Library/Application Support/Inklings/settings.json |
Detection logic (in apps/desktop/src-tauri/src/paths.rs): debug builds (pnpm desktop:dev) → dev mode, release builds
(pnpm desktop:build) → production mode.
The .data/ directory is git-ignored and can be cleared with ./tools/dev/reset-app-data.sh.
Was this page helpful?
Thanks for your feedback!