# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

Anteroom is a self-hosted, private ChatGPT-style web UI and agentic CLI that connects to any OpenAI-compatible API. It provides two interfaces: a FastAPI web UI with vanilla JS frontend, and a Rich-based CLI REPL with built-in tools and MCP integration. Single-user, local-first, SQLite-backed.

## Development Commands

```bash
pip install -e ".[dev]"             # Install for development
aroom                               # CLI REPL (default entry point)
aroom web                           # Web UI at http://127.0.0.1:8080
aroom chat --plan                   # Start in planning mode
aroom init                          # Interactive setup wizard
aroom --test                        # Validate AI connection
aroom --approval-mode auto          # Override safety mode
aroom --allowed-tools bash,write_file  # Pre-allow tools
aroom --denied-tools bash,run_agent   # Hard-block tools

pytest tests/ -v                    # All tests
pytest tests/unit/ -v               # Unit tests only
pytest tests/e2e/ -v                # E2e tests (requires uvx/npx)
pytest tests/e2e/ -m real_ai -v    # Agent evals (requires API key)
ruff check src/ tests/              # Lint
ruff format src/ tests/             # Format (120 char line length)
mypy src/ --ignore-missing-imports  # Type check (must pass with 0 errors)

# Evals and demos
npx promptfoo eval --config evals/promptfoo.yaml   # Prompt regression
npx promptfoo eval --config evals/agentic.yaml     # Agentic behavior
npx promptfoo redteam run --config evals/redteam.yaml  # Red teaming
cd demos && make demos              # Build demo GIFs (requires VHS)
```

### Worktree Development

When working with git worktrees (multiple features in parallel), each worktree **must** have its own virtual environment. Editable installs (`pip install -e .`) are global to the Python interpreter — the last worktree to install wins, causing import errors in all other worktrees.

```bash
# In each worktree:
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]" -q
make install-hooks

# Run tests/lint/typecheck with the worktree's venv:
.venv/bin/python -m pytest tests/unit/ -v
.venv/bin/ruff check src/ tests/
.venv/bin/python -m mypy src/ --ignore-missing-imports
```

## Architecture

### Dual Interface, Shared Core

Both the web UI and CLI share the same agent loop (`services/agent_loop.py`) and storage layer. Changes to tool handling, streaming, or message building affect both interfaces.

```
Web UI (routers/)  ──┐
                     ├──→ agent_loop.py → ai_service.py → OpenAI-compatible API
CLI (cli/)         ──┘         │
  repl.py (main loop)    tools/ + mcp_manager.py
  commands.py (/cmds)         │
  renderer.py            storage.py → SQLite
```

### Key Modules

#### Entry Points & Core
- **`__main__.py`** — Argparse dispatch: init, config (validate/view/explain/sources/history/diff/restore), chat, exec, db, usage, audit, artifact, pack, space, mission, workflow, start, stop, status, unpack subcommands. See source for flags
- **`unpack.py`** — Extracts bundled auxiliary files (tests, docs, evals, etc.) to a directory for offline development. Used with `anteroom[kitchensink]` extra
- **`app.py`** — FastAPI app factory, middleware stack (auth, rate limiting, CSRF, security headers, body size limit). Auth via Ed25519 identity key HMAC-SHA256. Lifespan: initializes encrypted DB and retention worker
- **`config.py`** — YAML config loader: layered precedence (defaults < team < packs < personal < space < project < env < CLI). `AppConfig` dataclass hierarchy. Enforces team `enforce` list. Validated via `config_validator.py`
- **`identity.py`** — Ed25519 keypair generation, UUID4 user IDs, PEM serialization
- **`tls.py`** — Self-signed cert generation for localhost HTTPS

#### Services (Shared Core)
- **`services/agent_loop.py`** — Shared agentic loop: parallel tool execution, max 50 iterations, cancel-aware. Proactive compaction, prompt queuing, narration cadence, auto-plan threshold. Tool results bounded, DLP/output filter applied. Internal `_`-prefixed metadata stripped. Staged overflow recovery
- **`services/ai_service.py`** — OpenAI SDK wrapper: streaming, token refresh on 401, cancel-aware, exponential backoff. Emits `phase`/`retrying`/`usage`. `complete()` for non-streaming. `create_ai_service()` routes by `ai.provider`
- **`services/debug_diagnostics.py`** — Redacted per-turn diagnostics collector shared by CLI and web debug mode. Summarizes timings, retries, tool metadata, usage, and stop reasons without raw prompts, tokens, tool arguments, or tool output
- **`services/anthropic_provider.py`** — Native Anthropic Messages API provider. Activated when `ai.provider: anthropic`. Translates OpenAI-shaped schema to/from Messages API. Optional: `pip install anteroom[anthropic]`
- **`services/litellm_provider.py`** — LiteLLM multi-provider wrapper. Activated when `ai.provider: litellm`. 100+ providers (OpenRouter, Replicate, Together, Cohere, …) via model-name prefix. Optional: `pip install anteroom[providers]`
- **`services/storage.py`** — SQLite DAL with parameterized queries + UUID IDs, usearch vector storage, source/tag/group/space CRUD, chunking/embeddings, token usage, message JSON metadata, scoped semantic + FTS5 search
- **`services/mcp_manager.py`** — MCP client lifecycle: parallel startup, per-server tool filtering, routes `call_tool()` to correct session. Warns on tool-name collisions
- **`services/context_trust.py`** — Prompt injection defense: trust classification, defensive XML envelopes, sanitization
- **`services/tool_result_compact.py`** — Field-aware tool output compaction shared by agent loop and replay. Strips internal keys, preserves structured metadata, truncates bulk content
- **`services/compaction.py`** — Shared compaction: cancel-aware summary LLM call, history builder, boundary mode, rehydration, staged overflow helpers
- **`services/microcompact.py`** — Proactive in-memory trim. Strategy registry shared with reactive Strategy 1
- **`services/embeddings.py`** — Dual provider: `LocalEmbeddingService` (fastembed, offline-first, default) and `EmbeddingService` (OpenAI-compatible API)
- **`services/embedding_worker.py`** — Background worker for unembedded messages/source chunks/memories. Exp backoff; auto-disables after 10 fails; probes every 10 min
- **`services/vector_index.py`** — Usearch vector indexes with UUID key mapping, crash recovery, iterative widening search. `VectorIndexManager` manages messages, source chunks, memory artifacts; startup rebuild from SQLite metadata
- **`services/document_extractor.py`** — Text extraction from PDF/DOCX/PPTX/XLSX uploads. `ExtractionResult` with warnings for graceful degradation
- **`services/rag.py`** — RAG pipeline: dense/keyword/hybrid retrieval modes. `retrieve_context()` returns `(chunks, reason)`. Space-scoped, token-budget trimmed, graceful degradation
- **`services/reranker.py`** — Cross-encoder reranker for RAG re-scoring. Local (fastembed) or API. Configurable top-K, score threshold, candidate multiplier. Graceful degradation
- **`services/memory_recall.py`** — Per-turn recall of typed memory artifacts. Scope-filtered (user/project/local), independent token budget, untrusted-content wrapping, graceful degradation
- **`services/memory_intent.py`** — Narrow deterministic detector for explicit user memory-save utterances. Routes direct saves to `save_memory` without invoking general skills or LLM intent guessing
- **`services/memory_save_status.py`** — Shared formatter for authoritative `save_memory` lifecycle/status text and compact assistant metadata. Keeps CLI/web memory-save confirmations and replay context in sync
- **`services/memory_promotion.py`** — Candidate→active review pipeline: propose/approve/reject. Stamps reviewer identity + timestamp, enforces per-conversation rate-limit
- **`services/auto_propose_runner.py`** — Auto-propose memory candidates after assistant turns; shared runner + LLM extractor
- **`services/attribution.py`** — Per-turn attribution: IDs+labels across turns/memory/sources/tools/packs. 20-item cap. Persisted to `messages.metadata["attribution"]`; SSE `attribution` event
- **`services/codebase_index.py`** — Tree-sitter codebase index for token-efficient context injection. 10 languages. Graceful degradation. Optional: `pip install anteroom[index]`
- **`services/audit.py`** — Structured JSONL audit log with HMAC-SHA256 chain tamper protection. Append-only, daily/size rotation, retention purge. SIEM-compatible
- **`services/lineage.py`** — Audit lineage emitters for workflow/memory/subagent/hook events; `None`-safe
- **`cli/_audit_helper.py`** — Constructs an identity-PEM-keyed chain-safe `AuditWriter` or `None`
- **`cli/_decision_routing.py`** — HTTPS-as-probe CLI→server routing; local fallback gated on loopback + ECONNREFUSED; bearer auth from identity PEM
- **`services/dlp.py`** — Data Loss Prevention: regex-based sensitive pattern detection. Actions: redact/block/warn. Custom patterns via config
- **`services/injection_detector.py`** — Prompt injection detection: canary tokens, encoding attacks, heuristic patterns. Actions: block/warn/log
- **`services/hooks.py`** — Runtime hook dispatch. Phase-1 (`pre_tool`/`post_tool`) active; phase-2 reserved. `HookDecision` carries `error_type`/`execution_ms`; subagent correlation IDs
- **`services/skill_bundles.py`** — Skill frontmatter parsing and bundled resource helpers shared by the skills registry and pack-sourced skills
- **`services/user_errors.py`** — User-facing error normalization: collapses tracebacks to single-line messages, structured next-step suggestions by error code
- **`services/output_filter.py`** — Output content filter: system prompt leak detection (n-gram). Actions: redact/block/warn
- **`services/egress_allowlist.py`** — Egress domain allowlist for outbound API requests. Fails closed on unparseable URLs
- **`services/feedback.py`** — Feedback/bug reporting: collects redacted diagnostic bundle, dispatches to configured reporters (command or webhook), falls back to local JSON. Reports tracked in `feedback_reports` DB table with bounded retry.
- **`services/context_thresholds.py`** — Model-aware context threshold derivation. Computes `warn`/`auto_compact`/`summary_trigger` token thresholds as buffer offsets from model context window; clamped and validated
- **`services/version_check.py`** — Version-check helpers shared by CLI startup and `/version` command. Async PyPI poll, configurable message template, `VersionCheckStatus` enum
- **`services/project_links.py`** — Project-link metadata profiles for public vs internal fork distributions. `ProjectConfig` dataclass, issue URL/label builders, env `ANTEROOM_PROJECT_PROFILE`
- **`services/docs_project_links.py`** — Renders documentation links through the configured project profile. Rewrites public GitHub URLs to internal equivalents for air-gapped fork docs
- **`services/provider_messages.py`** — Strips local persistence metadata from message dicts before sending to provider APIs. Removes keys not in the provider schema
- **`services/config_editor.py`** — Shared config read/write service with scoped persistence (personal, space, project), team enforcement, field validation, and 7-layer source attribution
- **`services/config_explanation.py`** — Effective config explanation and write guidance. Reconstructs raw source layers, redacts sensitive values, reports winning layer, team enforcement, pack overlay provenance, and smallest effective write scope for CLI config commands
- **`services/config_overlays.py`** — Pack config overlay collection, merging, conflict detection, and provenance. Priority-based merge (lower wins), dot-path collision detection, config source tracking for `--with-sources`/`config sources`, enforced field validation
- **`services/pack_sources.py`** — Git-based pack source cache. Clone/pull repos, URL scheme allowlist, credential sanitization, deterministic cache paths via SHA-256
- **`services/packs.py`** — Pack management: YAML manifests, install/remove with reference counting. `resolve_pack()` with collision detection. Path traversal prevention. Enumerated SQL columns
- **`services/workflow_registry.py`** — Pack-aware workflow resolver. `WorkflowRef`, `resolve_workflow()`, `list_available_workflows()`. Filesystem wins on id collision; FQN form targets a pack namespace
- **`services/pack_policies.py`** — Policy-artifact parser. Allowlists `memory.promotion.*` + `memory.retention.*`; feeds into `config_overlays` merge pipeline
- **`services/pack_refresh.py`** — Background worker: auto-clones and pulls pack source repos, installs/updates on content changes. Exponential backoff
- **`services/pack_lock.py`** — Lock file for reproducible installs. Content hashes, source URLs. `validate_lock()` compares lock vs DB
- **`services/event_bus.py`** — Async pub/sub: in-process via `asyncio.Queue`, cross-process via SQLite `change_log` polling
- **`services/slug.py`** — Slug generation: unique `{word}-{word}` names for conversation resumption
- **`services/trust.py`** — Trust store for ANTEROOM.md files. SHA-256 hash verification. Fails closed
- **`services/team_config.py`** — Team config discovery, loading, merging (deep_merge with named-list support), enforcement
- **`services/config_validator.py`** — Schema validation for raw YAML config dicts. Collects all errors/warnings. Rejects phase-2 hook events and unknown event keys
- **`services/compliance.py`** — Declarative config policy validation: `ComplianceRule` list evaluated against merged `AppConfig`. Fails closed at startup. `aroom config validate` subcommand
- **`services/config_watcher.py`** — Mtime-based config file watcher for live reload
- **`services/config_history.py`** — Config backup history with external-edit detection and recovery
- **`services/discovery.py`** — Walk-up directory discovery. Searches `.anteroom/`, `.claude/`, `.parlor/` with precedence
- **`services/required_keys.py`** — Required keys validation and interactive prompting
- **`services/tool_rate_limit.py`** — Tool call rate limiting: per-minute, per-conversation, and consecutive-failure caps. Block or warn action. Shared across parent and sub-agents
- **`services/session_store.py`** — Memory and SQLite session backends with idle/absolute timeouts
- **`services/ip_allowlist.py`** — IP allowlist checking with CIDR and exact address support. Fails closed on invalid input
- **`services/retention.py`** — Shared retention worker. `run_once()` branches on `retention_days>0` (conversations) and `memory.retention.enabled` (memories). Audit-writer threaded in
- **`services/memory_retention.py`** — Memory-artifact eviction (#625). Age/idle/status rules, pin-respect, per-purge `memory.purge` audit entry
- **`services/workflow_engine.py`** — Workflow engine: step execution (runner/gate/loop/parallel/llm), locks, heartbeat, resume, cancel, compensation, repair, loop break detection
- **`services/workflow_credentials.py`** — Named credential resolution: env vars or shell commands. Values never logged or persisted
- **`services/workflow_storage.py`** — CRUD for workflow runs, steps, events, approvals, locks, schedules, caching. Atomic lock, cancel/approval helpers, repair
- **`services/message_router.py`** — Message-to-run router: keyword heuristics classify follow-up messages against active workflow runs (attach, update, cancel, replace, spawn, ask_user)
- **`services/workflow_runners.py`** — Runner registry and execution. Agent and opaque runners with artifact injection. Workflow input drainer polls `workflow_run_inputs` and injects pending messages via message_queue
- **`services/workflow_hooks.py`** — Notification hooks: webhook and Unix socket with bounded drain
- **`services/workflow_publishers.py`** — Publish adapters for workflow output steps: file and webhook. Adapter registry
- **`services/workflow_executor.py`** — Background run dispatcher with atomic claim and crash recovery
- **`services/workflow_resolution.py`** — Shared workflow definition path resolution
- **`services/workflow_scheduler.py`** — Schedule evaluation, due-schedule claiming, run enqueue
- **`services/workflow_simulator.py`** — Workflow simulation engine for testing definitions with stub runners
- **`services/cron.py`** — 5-field cron evaluator with safety bounds
- **`services/encryption.py`** — SQLCipher encryption at rest (optional). Key derived from Ed25519 via HKDF-SHA256. Graceful degradation to standard sqlite3
- **`services/artifacts.py`** — Universal artifact model with FQN parsing, 7 types, 6 source layers, SHA-256 deduplication
- **`services/artifact_storage.py`** — Artifact CRUD with version tracking and space-scoped filtering
- **`services/artifact_registry.py`** — In-memory artifact index with 6-layer precedence
- **`services/artifact_health.py`** — Health checks: conflicts, collisions, shadows, orphans. `--fix` auto-resolves
- **`services/starter_packs.py`** — Built-in pack templates. Starter packs auto-install on first run, example packs require manual install
- **`services/rule_enforcer.py`** — Hard rule enforcement at tool execution. Checks `enforce: hard` rules before every tool call, returns `(blocked, reason, rule_fqn)`
- **`services/pack_attachments.py`** — Pack attachment tracking at global/space scopes with priority-based conflict resolution
- **`services/local_artifacts.py`** — Discovers artifacts from `.anteroom/artifacts/`, `.anteroom/skills/`, `.claude/skills/`, `.claude/rules/`. Path traversal prevention
- **`services/artifact_import.py`** — Bulk import into artifact DB. Format detection (YAML/Markdown), collision detection, version init
- **`services/spaces.py`** — Space file parser: `SpaceConfig`/`SpaceLocalConfig` frozen dataclasses. Name validation, URL scheme validation, 256KB size limit. YAML serialization. Local vs global space detection
- **`services/space_storage.py`** — Space DB CRUD with column-allowlisted updates. `resolve_space()` with collision detection. `resolve_space_by_cwd()` with parent walk-up. Cascade deletes
- **`services/space_bootstrap.py`** — First-load cloning (shallow `--depth=1`) and pack installation. URL scheme validation, credential sanitization, 120s timeout
- **`services/space_watcher.py`** — Mtime-based space file watcher for hot-reload. TOCTOU-safe
- **`services/server_manager.py`** — Background server process management (PID file, cross-platform start/stop, port probing, log rotation). Parameterized by service name so web and docs coexist.
- **`services/spec_schema.py`** — Spec schema: dataclasses, YAML parsing, phase metadata, templates. Topological sort for task DAGs
- **`services/spec_generator.py`** — LLM-assisted spec generation from prompts and GitHub issues
- **`services/spec_dashboard.py`** — Portfolio dashboard: aggregates lifecycle state, phase statuses, run counts
- **`services/spec_service.py`** — Spec lifecycle: create, read, update, approve/unapprove, traceability, task launch, approval guard
- **`services/spec_diff.py`** — Spec diffing and deterministic invalidation: three rules, stale reason derivation
- **`services/spec_queue.py`** — Review inbox: aggregates specs by phase status, attachment-aware filtering
- **`services/spec_linkage.py`** — Git branch/PR linkage for specs: metadata storage, CLI auto-detection, deduplication
- **`services/spec_conformance.py`** — Deterministic conformance checks: task coverage, run health, phase status
- **`services/spec_gates.py`** — Workflow gate conditions for spec phases
- **`services/workflow_cache.py`** — LLM response caching for workflow steps. Content hashing, configurable TTL, invalidation
- **`services/workflow_diagnosis.py`** — Diagnosis engine for non-success workflow runs. Pattern-matches stop reasons, extracts evidence
- **`services/async_tasks.py`** — Helpers for safely cancelling asyncio tasks without leaking late exceptions
- **`services/detached_subagent_manager.py`** — Detached subagent lifecycle (start/cancel/retry/poll). SSE `description` label; hook config snapshotted at launch. Caps via `SubagentConfig`
- **`services/mission_storage.py`** — Mission CRUD for sessions, items, dependencies, executions, revisions, and events. Scheduler eligibility queries
- **`services/mission_compiler.py`** — Spec-backed (deterministic) and prompt-backed (LLM) plan compilation. Structured patch operations. Execution profile integration
- **`services/mission_profiles.py`** — Execution profiles: preference-driven binding selection with workflow discovery and scoring. Built-in profile registry
- **`services/mission_scheduler.py`** — Deterministic eligibility evaluation, lane/concurrency limits, adapter dispatch, heartbeat polling
- **`services/mission_adapters.py`** — Adapter protocol and implementations: NoopAdapter (instant completion), WorkflowAdapter (enqueues workflow runs)
- **`services/external_checks.py`** — GitHub reality checks via `gh` CLI: issue-closed and merged-PR detection for mission auto-reconciliation

#### Web UI (routers/)
- **`routers/chat.py`** — SSE chat streaming. Per-request registries for space-scoped artifacts, skills, and rule enforcement. Supports prompt queuing, source injection, plan mode, sub-agents, DLP/output filtering, `hook_outcome` SSE event
- **`routers/sources.py`** — Sources API: CRUD, file upload, tags, groups, space linking, `POST /sources/{id}/reprocess` for re-extraction and re-chunking
- **`routers/search.py`** — Semantic (vector) and hybrid (FTS5 + vector) search. Requires usearch
- **`routers/proxy.py`** — OpenAI-compatible proxy for external tools. Opt-in via `proxy.enabled`
- **`routers/approvals.py`** — Web UI safety gate approval flow. Atomic dict pop prevents TOCTOU races
- **`routers/events.py`** — SSE endpoint for real-time UI updates (canvas streaming, approvals)
- **`routers/usage.py`** — Token usage statistics endpoint with per-model aggregation and cost estimates
- **`routers/plan.py`** — Plan mode endpoints: read, approve, reject
- **`routers/artifacts.py`** — Artifact API: `GET /api/artifacts` (list with type/namespace/source filters), `GET /api/artifacts/{fqn}` (show with version history), `DELETE /api/artifacts/{fqn}` (delete artifact and refresh registry)
- **`routers/artifact_health.py`** — Artifact health check endpoint: `GET /api/artifacts/check` (triggers health check, no `fix` parameter). Returns `HealthReport` JSON
- **`routers/packs.py`** — Pack API (read-only Phase 2): list with counts, show by `{namespace}/{name}` or pack ID, remove by ID. Strips `source_path` from responses to prevent info disclosure
- **`routers/spaces.py`** — Spaces API: list/create/show/delete/refresh, source link/unlink, attached packs. `origin` marks local vs global. Path traversal and disclosure prevention
- **`routers/memory.py`** — Memory API: list/show/create/edit/delete + propose/approve/reject candidates. FQN validation; PATCH uses `_MUTABLE_METADATA_FIELDS` allowlist; rate-limit returns 429
- **`routers/config_api.py`** — Config editing API: schema, current merged config, atomic PATCH with layer-aware merging, layer composition, dry-run validation
- **`routers/feedback.py`** — Feedback API: `POST /api/feedback` (submit feedback with optional conversation history, space context)
- **`routers/specs.py`** — Spec lifecycle API: list, create, show, approve/unapprove, diff, stale, portfolio dashboard. FQN/phase validation
- **`routers/workflows.py`** — Workflow monitoring and repair API: list definitions, runs, steps, event history. Action endpoints: cancel, approve, reject. `PATCH /workflow-runs/{run_id}/repair` for governed field edits

#### CLI Modules
- **`cli/repl.py`** — Main REPL with prompt_toolkit. Orchestrates system prompt, space context, trust verification, plan mode, skill auto-invocation. Slash-command dispatch to `commands.py`. Skill args `<skill_args>`-delimited for injection defense
- **`cli/themes.py`** — CLI color theme system. `CliTheme` frozen dataclass with semantic color slots. Four built-in themes. NO_COLOR support
- **`cli/layout.py`** — Shared CLI layout: prompt prefix styling with approval-mode-aware colors, `/command` input lexer, path shortening. Exports `InputLexer`, `input_line_prefix`, `set_approval_mode`, `_shorten_path`
- **`cli/commands.py`** — Shared slash-command engine (35+ commands). Pure dispatch via `execute_slash_command()`; single source of truth for names/descriptions/completions; prevents skill name collisions
- **`cli/command_palette.py`** — Ranked slash-command palette for bare `/` input. Groups commands by intent, surfaces action-oriented descriptions, inserts editable scaffolds instead of executing immediately
- **`cli/renderer.py`** — Rich terminal output: thinking spinner, plan checklist, inline diffs, tool call dedup, subagent, RAG status. `use_stdout_console()` for REPL mode. Renders `[ctx]` footer and hook outcomes
- **`cli/streaming.py`** — Live markdown streaming using Rich Live; throttled repaint cadence, height-preserving blank-before-stop, graceful non-TTY fallback
- **`cli/density.py`** — Tool-result density helpers (MINIMAL/COMPACT/NORMAL/DETAILED). Pure functions; used by renderer for `/density` slash command
- **`cli/attribution_render.py`** — Rich renderer for `/attribution`: five compact tables (turns, memory, sources, tools, packs) from an `AttributionSnapshot` or persisted dict
- **`cli/attribution_counts.py`** — Count helper for attribution snapshots (#1473). Reads canonical count fields, falls back to computation for legacy dicts
- **`cli/exec_mode.py`** — Scripting/CI mode. JSON output, timeout, fail-closed approval. Exit codes: 0/1/124
- **`cli/plan.py`** — Planning mode helpers: `PLAN_MODE_ALLOWED_TOOLS`, plan file I/O, plan command parsing, `enter_plan_mode()`, `leave_plan_mode()`
- **`cli/instructions.py`** — ANTEROOM.md discovery (`.anteroom.md` > `ANTEROOM.md`, walk-up from cwd), global instructions, token estimation
- **`cli/skills.py`** — Skills registry with namespace-aware resolution. Loads from built-in, global, and space-scoped directories. Auto-invocation via synthetic `invoke_skill` tool. Artifact bridge for pack-sourced skills
- **`cli/config_tui.py`** — Full-screen interactive config editor TUI (prompt_toolkit Application, same pattern as resume picker). Two-panel layout, arrow-key navigation, scope cycling, inline editing, save/discard. Used by `/config` command
- **`cli/workflow_cli.py`** — CLI handlers for `aroom workflow` subcommands (run/status/list/history/resume/repair/cancel). `--force` drift override, budget display, live transcript rendering with `--no-transcript` suppression
- **`cli/mission_cli.py`** — CLI handlers for `aroom mission` subcommands (create/list/status/talk/update/revisions/cancel). Spec and prompt compilation, patch preview, conversational REPL launch
- **`cli/memory_cli.py`** — CLI handlers for `aroom memory` subcommands (list/show/create/edit/delete). Rich tables for list view, Rich panel for detail. Shared by the `/memory` REPL slash command
- **`cli/workflow_fmt.py`** — Shared timeline formatters for workflow CLI: status icons, friendly durations, step line rendering, run headers
- **`cli/transcript_renderer.py`** — Renders workflow transcript events in Rich for CLI display. Delegates to chat renderer helpers for visual parity
- **`cli/agent_cli.py`** — CLI handlers for `aroom agent` subcommands (list/status/cancel/retry). Prefers `description` label over title via `get_run_label()` (#1461)
- **`cli/hook_cli.py`** — Hook tooling: list, validate, replay subcommands (#1495)
- **`cli/feedback_cli.py`** — CLI handler for `/feedback` REPL slash command

#### Tools
- **`tools/`** — ToolRegistry. Built-in: read_file, write_file, edit_file, bash, glob_files, grep, create_canvas, update_canvas, patch_canvas, run_agent, ask_user, introspect. Optional (`anteroom[office]`): docx, xlsx, pptx. Safety: tier → pattern → hard-block. File-modifying tools return `_old_content`/`_new_content` (stripped before LLM). PreToolUse/PostToolUse hooks
- **`tools/tiers.py`** — Risk tiers: READ/WRITE/EXECUTE/DESTRUCTIVE. Approval modes: AUTO/ASK_FOR_DANGEROUS/ASK_FOR_WRITES/ASK. Unknown/MCP tools default to EXECUTE
- **`tools/bash.py`** — Shell execution with configurable sandboxing. Network/package/path/command restrictions, `_env` credential binding (#970), Win32 Job Object limits, timeout caps, output truncation, audit logging
- **`tools/security.py`** — Hard-block patterns, path validation, `check_network_command()`, `check_package_install()`, `check_blocked_path()`, `check_custom_patterns()`. Cross-platform: Unix, PowerShell, Windows package managers
- **`tools/sandbox_win32.py`** — Win32 Job Object sandbox via ctypes. Memory/process/CPU limits. No-op on non-Windows. Functions return success/failure, never raise
- **`tools/safety.py`** — Pure detection: `check_bash_command()` (regex patterns), `check_write_path()` (sensitive paths). Returns `SafetyVerdict` with `is_hard_blocked`
- **`tools/canvas.py`** — Canvas create/update/patch with SSE streaming support. Excalidraw diagram language generates JSON scene data rendered in web UI via iframe viewer
- **`tools/mission.py`** — 10 mission steering tools: list/status/hold/resume/drop/reprioritize/add/change deps/change binding/replan. Registered via `register_mission_tools()`
- **`tools/subagent.py`** — `run_agent` tool: isolated child AI sessions, same safety gates. Optional `description` field (max 120 chars) for stable labels. Hook config inherited/snapshotted for detached subagents. Guarded by `SubagentLimiter`
- **`tools/introspect.py`** — Lets AI examine its own runtime context. READ tier (auto-allowed)
- **`tools/save_memory.py`** — Explicit memory saves and agent-proposed memory candidates via `memory_promotion.propose_candidate(proposer="agent")` (#217, #1559). WRITE tier
- **`tools/office_com.py`** — Shared COM lifecycle manager for Windows. Optional: requires pywin32
- **`tools/office_docx.py`** — DOCX tool via python-docx or COM. WRITE tier. Actions: create, read, edit, styles, export_pdf (COM), find_regex, etc.
- **`tools/office_xlsx.py`** — XLSX tool via openpyxl or COM. WRITE tier. Actions: create, read, edit, format, charts, pivot_tables (COM), etc.
- **`tools/office_pptx.py`** — PPTX tool via python-pptx or COM. WRITE tier. Actions: create, read, edit, insert_image/shape, master_layout, etc.

### Security Model

Single-user local app, OWASP ASVS Level 2. Auth: HttpOnly cookies + CSRF double-submit + Origin validation. Ed25519 identity key. Sessions: memory or SQLite-backed, IP allowlisting, concurrent limits, 12h absolute/30m idle. Middleware: rate limiting, body size limit, security headers. Tool safety: 4 risk tiers, 4 approval modes, 3 permission scopes. Path traversal and hard-block detection. Bash sandboxing: network/package/path/command restrictions, timeout caps, audit logging. MCP tools gated. Fails closed. Optional SQLCipher encryption at rest. Configurable retention policy with cascade delete.

### Database

SQLite with WAL journaling, FTS5 for search, foreign keys enforced. Optional SQLCipher encryption. Schema in `db.py`. Key tables: conversations, messages, sources, tool_calls, canvases, artifacts, packs, spaces, workflows, workflow_llm_cache, mission_sessions/items/dependencies/executions/revisions/events, feedback_reports. Embedding metadata: message_embeddings, source_chunk_embeddings, memory_artifact_embeddings. Vector similarity via usearch. Retention cascades deletes.

### Configuration

Config at `~/.anteroom/config.yaml` (backward compat: `~/.parlor/config.yaml`). Env vars override with `AI_CHAT_` prefix. Dynamic API key refresh via `api_key_command`. Ed25519 identity auto-generated on first run.

**Precedence:** defaults < team < **packs** < personal < space < project < env vars < CLI flags (team-enforced fields override all). Pack config overlays are collected from the DB at startup and merged by priority (lower number wins) into the config chain. Space configs require SHA-256 trust verification. Live reload via config watcher.

Key config sections (see `config.py` dataclasses for all fields and defaults):
- **`AIConfig`** — API connection, timeouts, retry, `max_tools` (128), temp/top_p/seed, egress allowlist, `provider` (openai/anthropic/litellm), `max_output_tokens` (4096), `model_family_aliases` for sub-agent routing
- **`ServerConfig`** — HTTP server settings: `max_upload_mb` (default 50, clamped `[1, 1000]`); env `AI_CHAT_SERVER_MAX_UPLOAD_MB`
- **`RateLimitConfig`** — HTTP request rate limiting (sliding window): `max_requests` (120), `window_seconds` (60), `exempt_paths` (`/api/events`), `sse_retry_ms` (5000). Returns 429 on excess
- **`SafetyConfig`** — Approval mode, allowed/denied tools, bash patterns, tier overrides, read-only, rate limiting. Nested `BashSandboxConfig` (timeout, blocking) and `OsSandboxConfig` (Win32 Job limits)
- **`CliConfig`** — Compaction thresholds, tool dedup, retry, visual thresholds, theme (`midnight`), output limits (2000 chars), fold config (`CliFoldConfig`)
- **`CompactionConfig`** — `preserve_tail` (default 6, clamped [0, 200]). Env `AI_CHAT_COMPACT_PRESERVE_TAIL`. Legacy `cli.compact_preserve_tail` accepted as deprecated alias.
- **`PlanningConfig`** — Auto-trigger: `auto_mode` (off/suggest/auto), `auto_threshold_tools`
- **`SkillsConfig`** — `auto_invoke` (default true) enables AI skill invocation
- **`FeedbackConfig`** — Feedback reporters list (`FeedbackReporterConfig`: name, type command/webhook, command/url, timeout). History off by default, retry configurable, 1MB bundle cap. Falls back to local JSON.
- **`SubagentConfig`** — Limits: concurrency (5), total (10), depth (3), iterations (15), timeout (120s)
- **`EmbeddingsConfig`** — Dual provider (local fastembed default or API). Tri-state `enabled`: None=auto-detect, True=force, False=disable. `cache_dir` for vendored/offline model loading
- **`RagConfig`** — RAG pipeline: `max_chunks` (10), `max_tokens` (2000), `similarity_threshold` (0.5), `retrieval_mode` (dense/keyword/hybrid, default dense)
- **`RerankerConfig`** — Cross-encoder reranker: `enabled` (None=auto-detect), `provider` (local only), `model`, `top_k` (5), `score_threshold` (0.0), `candidate_multiplier` (3), `cache_dir` for vendored/offline model loading
- **`CodebaseIndexConfig`** — Tree-sitter index: `map_tokens` (1000), auto-detect languages. Optional dependency
- **`ProxyConfig`** — OpenAI-compatible proxy (opt-in), CORS allowlist
- **`McpServerConfig`** — Per-server `tools_include`/`tools_exclude` (fnmatch), `trust_level` (default `"untrusted"`; controls defensive prompt envelope wrapping for tool outputs)
- **`SessionConfig`** — Session management: `store` (memory/sqlite), `max_concurrent_sessions` (0 = unlimited), `idle_timeout` (1800s), `absolute_timeout` (43200s), `allowed_ips` (CIDR or exact; empty = allow all), `log_session_events` (bool)
- **`StorageConfig`** — Data retention (`retention_days`, `retention_check_interval`) and at-rest encryption (`encrypt_at_rest`, `encryption_kdf`). Purge options for attachments and embeddings.
- **`AuditConfig`** — Structured audit log: `enabled` (default false), `log_path`, `tamper_protection` (hmac/none), `rotation` (daily/size), `retention_days` (90), `redact_content` (true), per-event-type toggles
- **`OutputFilterConfig`** — Output content filtering: `enabled`, `system_prompt_leak_detection`, `leak_threshold`, `custom_patterns`, `action` (redact/block/warn), `redaction_string`, `log_detections`. See config.py for defaults.
- **`ComplianceConfig`** — Declarative compliance rules (`rules` list of `ComplianceRule` with field/value/regex/must_contain checks). Evaluated at startup; non-compliant configs fail closed.
- **`PackSourceConfig`** — Git-based pack source repos: `url`, `branch` (main), `refresh_interval` (30 min), `auto_attach` (bool, true), `priority` (1-100, default 50). URL scheme validation (rejects ext::, file://)
- **`HooksConfig`** — Session-scoped hook definitions: `pre_tool`/`post_tool` lists of `HookEntryConfig`. Trust boundary: personal/team sources executable; pack sources non-executable until #1272. Dedup by `id` (first-seen wins)

### Developer Workflow

Claude Code skills (`.claude/commands/`) and auto-loaded rules (`.claude/rules/`) enforce development standards. See `VISION.md` for product identity and scope guardrails.

**Skills**: `/ideate`, `/new-issue`, `/start-work`, `/commit`, `/submit-pr`, `/pr-check`, `/code-review`, `/deploy`, `/write-docs`, `/dev-help`, `/calm-dev-loop`, `/next`, `/triage`, `/cleanup`, `/a-help`

**Rules**: commit format, issue requirement, output formatting, vision alignment, security patterns, test requirements, feature parity

### Deployment

PyPI: `anteroom`. Deploy via `/deploy` skill (merge PR, CI, version bump, build, `twine upload`).

**Optional Dependencies** (declared in `pyproject.toml`):
- **`anthropic`** — `anthropic>=0.40.0`. Required when `ai.provider: anthropic`. Enable with: `pip install anteroom[anthropic]`
- **`providers`** — LiteLLM multi-provider support (100+ providers). Enable with: `pip install anteroom[providers]`
- **`docs`** — DOCX text extraction. PDF text extraction is included in the default install. Enable with: `pip install anteroom[docs]`
- **`office`** — docx/xlsx/pptx tools. Enable with: `pip install anteroom[office]`
- **`office-com`** — Full COM backend for native Office automation (Windows only). Enable with: `pip install anteroom[office-com]`
- **`encryption`** — SQLCipher at-rest encryption. Enable with: `pip install anteroom[encryption]`
- **`kitchensink`** — Dev tools + offline test/doc bundle. Extract with `aroom unpack`. Enable with: `pip install anteroom[kitchensink]`

## Terminology

- **Source** — a knowledge source (document, URL, text) used for RAG context injection. Managed via `services/storage.py`, API at `routers/sources.py`
- **Artifact source** (`ArtifactSource` enum) — the origin layer of an artifact: `built_in`, `global`, `team`, `project`, `local`, `inline`. Determines precedence in the artifact registry
- **Convention** / **Instruction** — space-level guidance loaded from `ANTEROOM.md`. The `/conventions` and `/instructions` REPL commands are aliases for the same feature
- **Skill** — a YAML-defined prompt template invoked via `/skill_name` or the `invoke_skill` tool. Loaded from filesystem directories and the artifact registry
- **Pack** — a named bundle of artifacts installed from a YAML manifest. Managed via `services/packs.py`. Pack attachments use `project_path` internally (DB column) but user-facing terminology is "directory-scoped"
- **Space** — a workspace binding that auto-detects workspace context from the working directory, bundles repositories, tools, configs, and packs into named workspaces. Unified workspace primitive replacing Projects. Managed via `services/spaces.py` and `services/space_storage.py`

## Testing Patterns

- **Unit tests** (`tests/unit/`, ~6,000 tests): fully mocked, no I/O. `@pytest.mark.asyncio` with `asyncio_mode = "auto"`
- **Integration** (`tests/integration/`): real SQLite databases
- **E2e** (`tests/e2e/`): real servers, mock AI. Markers: `e2e`, `requires_mcp`
- **Agent evals** (`tests/e2e/test_agent_evals.py`): 10 tests with real AI via `aroom exec --json`. Marker: `real_ai`. Auto-skip without API key. Uses `--temperature 0 --seed 42` for reproducibility
- **Prompt regression** (`evals/`): promptfoo suites via OpenAI-compatible proxy. `promptfoo.yaml` (11 prompt regression tests), `agentic.yaml` (6 exec-mode tests), `redteam.yaml` (adversarial). Run: `npx promptfoo eval --config evals/promptfoo.yaml`
- **Demo recordings** (`demos/`): VHS tape scripts producing reproducible GIFs. 3 demos: quickstart, tools, exec-mode. Run: `cd demos && make demos`
- **Type checking**: `mypy src/ --ignore-missing-imports` must pass with zero errors. All new and modified Python code must be fully type-annotated. Do not introduce new mypy errors — fix any that exist in files you touch
- Coverage target: 80%+. See `docs/advanced/testing.md` for full guide

## CI

GitHub Actions: Python 3.10-3.14 matrix, ruff lint+format, mypy type check, pytest with coverage, pip-audit, Semgrep SAST, CodeQL.
