This file provides project context and coding standards for any AI coding assistant (OpenAI Codex, Cursor, Windsurf, Copilot Workspace, Cline, Aider, etc.). For Claude Code-specific instructions, see
CLAUDE.md.
Antec is a self-hosted personal AI assistant. Single Rust binary, zero mandatory dependencies, all data local. 15-crate Cargo workspace under crates/. Full PRD in prd/ (30 documents).
Read prd/01-ARCHITECTURE.md before writing any code.
Run after EVERY change:
cargo build --workspace --lib
cargo test --workspace
cargo clippy --workspace --all-targets -- -D warnings
cargo fmt --all -- --checkAll four must pass before any commit. No exceptions.
| Layer | Choice |
|---|---|
| Language | Rust 2021 edition, async via Tokio 1.x |
| HTTP/WS | Axum (Tower-based) — REST + WebSocket + SSE |
| Database | SQLite 3 (rusqlite, bundled) — WAL mode, FTS5, r2d2 pool (8 conns) |
| Config | TOML (human) + JSON (API) — 5-layer precedence |
| WASM Sandbox | Wasmtime — fuel metering + epoch interrupts |
| Serialization | serde + serde_json; MessagePack for internal wire |
| Crypto | ChaCha20-Poly1305 secret vault, HMAC-SHA256 audit chain |
| CLI | clap |
| Frontend | Vanilla HTML/CSS/JS (ES modules), embedded via rust-embed |
| i18n | Compile-time t!() macro — EN + PL |
antec (workspace root)
├── src/main.rs # Binary entrypoint, CLI, boot
└── crates/
├── antec-core/ # Agent loop, LLM providers, routing
├── antec-gateway/ # Axum HTTP/WS, REST routes, auth
├── antec-channels/ # Discord, WhatsApp, iMessage, Console
├── antec-tools/ # 50+ tools, risk classification
├── antec-memory/ # FTS5, BM25 + TF-IDF + embeddings
├── antec-storage/ # SQLite pool, migrations, repos
├── antec-security/ # Injection detection, vault, audit
├── antec-skills/ # Skill loader, 5 runtimes
├── antec-scheduler/ # Cron, NL scheduling, heartbeat
├── antec-sandbox/ # WASM + OS sandbox, policy engine
├── antec-mcp/ # MCP client (stdio/SSE/HTTP)
├── antec-extensions/ # Integration templates, credentials
├── antec-i18n/ # Translation macro, locale files
├── antec-console/ # Web Console SPA (embedded)
└── antec-hands/ # Operational capabilities
Dependency DAG: prd/01-ARCHITECTURE.md §1.2. No circular dependencies.
Full standard: .claude/skills/rust/SKILL.md (179 rules, 14 categories). Key rules:
- Library crates:
thiserrorfor typed error enums per crate - Application layer:
anyhowfor ergonomic propagation - Never
.unwrap()or.expect()in production code — use? - Chain errors with context:
.map_err(|e| Error::Storage(e))?
- Borrow (
&T) over clone. Clone only when ownership transfer is required &stroverStringin function parametersArc<T>for shared ownership in async — neverRc<T>in async codetokio::sync::Mutex(notstd::sync::Mutex) when holding across.await
- Tokio-only runtime. Never
block_oninside async - Never hold
std::sync::Mutexacross.await - CPU-heavy work:
tokio::task::spawn_blocking - Channels:
mpsc(fan-in),broadcast(fan-out),watch(config),oneshot(request-reply) - Parallel tasks:
JoinSetwith bounded concurrency
- Newtype wrappers for IDs:
SessionId(Uuid), not bareUuid - Builder pattern for complex structs (3+ optional fields)
- Accept
impl Into<String>, return concrete types - Traits for plugin boundaries:
LlmProvider,Channel,MemoryBackend,Tool
- Types:
PascalCase. Functions:snake_case. Constants:SCREAMING_SNAKE_CASE - Constructors:
new(),with_*(). Conversions:as_*()(cheap),to_*()(expensive),into_*()(ownership) - Booleans:
is_*(),has_*(),can_*()
Vec::with_capacity()when size is known&[u8]andCow<'_, str>in parsing hot pathsSmallVecfor small collections (< 8 elements)String::with_capacity+push_str, not repeatedformat!
- Crates form a DAG. No circular dependencies
- Leaf crates (
antec-storage,antec-i18n) depend only on external crates - Cross-crate communication through traits
Every new config field needs: struct field with #[serde(default)], Default impl entry, serde derives, docs in prd/14-CONFIGURATION.md.
New API routes need: handler in route module, router registration in server.rs, request/response types with serde, integration test.
New tools need: Tool trait impl, JSON Schema, risk classification (safe/moderate/dangerous), registry entry, tests.
- Location:
crates/<crate>/src/*.rs— inline#[cfg(test)] mod tests - Run:
cargo test -p antec-<crate> - Mock trait objects — never call real APIs
- Every public function: happy-path + error-path test
- Async:
#[tokio::test]. Filesystem:tempfilecrate
- Location:
tests/at workspace root - In-memory SQLite, localhost Axum on random port, mock LLM
- Each test has isolated environment — no shared state
- Location:
tests/e2e/ - Black box: build binary → subprocess → HTTP/WS interaction
- 30s timeout per test.
assert_cmdfor CLI,tokio-tungstenitefor WS
- No test without assertion
- No flaky tests — fix or remove
- No real network calls — offline-capable
- No shared mutable state
- Descriptive names:
test_memory_search_returns_results_ranked_by_bm25 - Run
cargo testbefore marking any task complete
- Monochrome palette (black/white/gray). Color for status only (green/amber/red)
- Terminal-inspired: JetBrains Mono, dense information, minimal chrome
- Responsive: mobile-first. Breakpoints: <768px, 768-1024px, >1024px
- WCAG 2.1 AA: keyboard nav, screen reader, ARIA, focus management
- CSS variables only — design tokens from
prd/19-UI.md - No heavy dependencies. SSE for real-time
- Web UI ships simultaneously with backend features
- Plan before building for any non-trivial task (3+ steps or architectural decisions)
- If the approach isn't working, stop and re-plan — don't push through
- Write specs upfront to reduce ambiguity
- Ask: "Would a staff engineer approve this?"
- Run all four mandatory checks before declaring done
- Demonstrate correctness — don't just claim it
- Find root causes. No temporary fixes
- Write plans to
tasks/todo.mdwith checkable items - Track progress as you go
- Update
tasks/HANDOVER.mdwhen finishing phases or sessions
- Simplicity First: every change as simple as possible
- Minimize Impact: touch only what's necessary
- No Laziness: senior developer standards at all times
- Data Sovereignty: all data stays local
- Defense in Depth: 9 security layers
| Pitfall | Fix |
|---|---|
| Circular crate dependency | Move shared types to leaf crate or define trait in the dependent |
std::sync::Mutex across .await |
Use tokio::sync::Mutex |
Missing #[serde(default)] on config field |
Breaks existing configs |
| Route not registered in router | 404 despite handler existing |
.unwrap() in production |
Use ? with proper error type |
| SQLite pool exhaustion | Ensure connections returned, check pool size |
| Forgot migrations | New tables missing at runtime |
| WASM fuel/epoch not set | Skill code can loop forever |
| Hardcoded UI colors | Use CSS variables |
| Test depends on network | Mock all external services |
| What | Where |
|---|---|
| Architecture | prd/01-ARCHITECTURE.md |
| Agent loop | prd/02-CORE.md |
| API routes | prd/03-GATEWAY.md |
| Database schema | prd/30-DATABASE.md |
| Security | prd/07-SECURITY.md |
| UI design | prd/19-UI.md |
| Configuration | prd/14-CONFIGURATION.md |
| Deployment | prd/29-DEPLOYMENT.md |
| Rust standard | .claude/skills/rust/SKILL.md |
| Tasks | tasks/todo.md |
| Handover | tasks/HANDOVER.md |