This document describes the current canonical architecture of lit-critic.
lit-critic is organized as three explicit layers:
- Core (
core/) — stateless reasoning engine - Platform (
orchestrator/) — workflow + persistence owner - API server (
api/) and VS Code extension (vscode-extension/) — thin client layers
| Layer | Owns | Must Not Own |
|---|---|---|
| Core | Analyze/discuss/re-evaluate reasoning over versioned contract payloads | Filesystem paths, session lifecycle, SQLite orchestration |
| Platform | Scene/index loading, session state machine, persistence, retry/backoff, Core transport | Client-specific presentation/UI concerns |
| Clients | Interaction, navigation, rendering, command surfaces | Workflow orchestration or direct Core coupling |
VS Code Extension
|
| /api/*
v
REST API Surface (api/routes.py)
|
| Platform services + facade
v
Orchestrator (orchestrator/*)
/ | \
/ | \
v v v
Project files SQLite (.lit-critic.db) Core (core/api.py)
(scenes/indexes) (native + derived data) ^
| ^ |
| parse/hash | store/query | /v1/* contracts
+------------------>+---------------------+
projection services
|
+-- session/discussion services consume authored + projected data
- Default: all components local (localhost)
- Remote Core: Platform stays close to project data; Core can be remote behind TLS + auth gateway
Core is stateless and contract-first.
GET /healthPOST /v1/analyzePOST /v1/discussPOST /v1/re-evaluate-finding
- Accepts text + structured payloads only
- No direct file or database access
- Returns deterministic, validated contract responses
Platform is the workflow boundary and source of orchestration truth.
facade.py— scene/index loading and contract request assemblycore_client.py— transport, timeout, retry/backoff, error mappingcontext.py— condensed discussion context generationsession_state_machine.py— state transitions and review behavior helperspersistence/*— SQLite lifecycle and data accessservices/*— session/discussion/learning orchestration servicesservices/scene_projection_service.py+services/index_projection_service.py— build DB projections from authored filesservices/scene_status_service.py+services/index_status_service.py— single source of truth for scene and index staleness (computed on every call, not persisted; seespecs/loop-redesign-architecture.md§3)services/project_knowledge_service.py— orchestrates knowledge refresh workflows; delegates staleness queries to the status services above
- Session lifecycle consistency across all clients
- Immediate persistence of user actions
- Moved-scene recovery and scene-change re-evaluation
- Uniform error handling and retry policy
All clients are presentation and interaction layers over Platform behavior.
- FastAPI HTTP endpoints consumed by the VS Code extension
- Streaming progress + discussion
- Diagnostics, findings tree, discussion panel
- Local API process management for developer workflow
The extension is decomposed into focused modules to keep extension.ts as a thin composition root:
| Module | Responsibility |
|---|---|
extension.ts |
Activation wiring only — instantiates services, registers commands, delegates startup |
bootstrap/startupService.ts |
Repo-root discovery, repo-path recovery, server startup with busy UI, auto-load sidebars, activity-view reveal |
commands/registerCommands.ts |
Centralised command-ID → handler mapping; keeps command palette surface enumerable and testable |
workflows/sessionWorkflowController.ts |
All session/finding command handlers (analyze, resume, accept, reject, review, rerun, etc.) |
workflows/stateStore.ts |
Mutable runtime session state (findings cache, current index, totals, notices) — injected as a unit to enable deterministic tests |
ui/workbenchPresenter.ts |
Status bar transitions, findings/sessions tree reveal, discussion panel coordination, diagnostics updates |
domain/findingLogic.ts |
Pure finding-navigation helpers (fallback resolution, index clamping, context-change detection) |
domain/sessionDecisionLogic.ts |
Pure session-entry decision helpers (repo-path error parsing, session label formatting) |
domain/modelSelectionLogic.ts |
Pure model/preset selection helpers (configured model resolution, status message building) |
All VS Code surface interactions are injected through narrow port interfaces (StartupPorts, WorkflowUiPort, WorkflowDeps) so that unit tests can use simple fakes without loading the VS Code runtime.
| Test file | What it tests |
|---|---|
test_startupService.ts |
Startup service branches: repo discovery, recovery loop, progress UI, activity reveal |
test_sessionWorkflowController.ts |
Workflow command handlers with fake ports — no VS Code or server required |
test_registerCommands.ts |
Command-ID coverage and handler-wiring correctness |
test_domain_*.ts |
Pure helper logic — zero mocking |
test_extension_real.ts |
Integration-style: activation wiring, command registration, auto-start behavior |
lit-critic uses a three-part ownership model so each layer has clear responsibility:
- Authored data (human-edited): scene files + index files in the project filesystem
- Derived data (machine-built, reproducible): scene/index projections in SQLite
- Native runtime data (workflow state): sessions/findings/learning in SQLite
- Scene text files
- Author-authored knowledge files (
CANON.md,STYLE.md)
CAST.md,GLOSSARY.md,THREADS.md, andTIMELINE.mdare no longer maintained as files. Their content is extracted automatically from prose and stored in the project database.
Owned by Platform for:
- native workflow state:
- sessions
- findings
- learning
- derived project-knowledge projection state:
scene_projection(scene metadata + file hash + refresh timestamp)index_projection(index hash + parsed entries blob when applicable — CANON.md and STYLE.md)
- extracted knowledge state:
extracted_scene_metadata(per-scene LLM-extracted metadata)extracted_characters,extracted_terms,extracted_threads,extracted_thread_events,extracted_timeline(auto-extracted knowledge from prose)knowledge_overrides(author corrections applied on top of extracted values; survive re-extraction)
The projection layer is a deterministic cache derived from authored project files.
- Refresh can be explicit (
scenes refresh,indexes refresh,/api/project/refresh) or lazy (ensure_project_knowledge_fresh) - Staleness is computed on demand by
scene_status_serviceandindex_status_serviceusing file-content hashes; unchanged files are skipped STYLE.mdis tracked hash-only (no structured entries)- If projection rows are missing or stale, they are rebuildable from filesystem sources
The loop is a single-pass state machine that reads computed scene and index statuses and advances work through a five-status lifecycle: extraction_due → extracted → analysis_due → analyzed, with a failed status for backoff. Each cycle calls decide() (a pure function mapping statuses + cool-down gates to actions) then executes the chosen action. All decisions are logged at INFO level for observability. See specs/loop-redesign-architecture.md for full design detail.
Key persisted multi-scene fields include:
- session scene set (
scene_paths) - per-finding source scene (
finding.scene_path)
Persistence is auto-applied on each mutation (accept/reject/discuss/navigate).
- Client starts analysis via
/api/analyze - Platform loads one or more consecutive scenes + indexes
- Platform concatenates selected scenes and tracks line/source mapping
- Platform calls Core
/v1/analyze - Results are mapped back to scene-local lines with per-finding
scene_path - Results are persisted and returned to client
- Client posts message via
/api/finding/discuss(or streaming variant) - Platform builds condensed context + current finding state
- In multi-scene sessions, discussion scope is constrained to the finding's source scene
- Platform calls Core
/v1/discuss - Outcome (revised/withdrawn/etc.) is persisted and broadcast to client
- Client requests
/api/resume - Platform restores active session from SQLite
- Scene hash/path validation runs (with recovery when needed)
- Review continues from persisted index
- Transport retries/backoff are applied by Platform (
core_client.py) - Persistence lock contention is handled with bounded retries
- Remote Core deployments require gateway-authenticated TLS
- Clients should reconcile state before replaying mutating actions
See:
- Stateless Core boundary
- Single orchestration owner (Platform)
- Client interoperability through shared persisted state
- Contract-first compatibility
- Local-first data ownership