Repository navigation
Architecture
CodingDude is three process roles over one SQLite store. The canonical, claim-by-claim description is docs/TECHNICAL-DESIGN-MANUAL.md; this page is the map.
Browser (React/Vite SPA, frontend/src)
│ SSE (run events, artifact deltas) + HTTP JSON
▼
Server (server.py — FastAPI/uvicorn, loopback-only)
│ spawns one subprocess per run; bridges worker WebSocket ⇄ browser SSE
│ persists sessions/messages/runs/artifacts/planning to SQLite (db.py)
▼
Worker (worker.py — python -m codingdude.worker)
│ builds config, constructs the engine, streams trace events
▼
Engine (engine.py — pydantic-ai agent loop)
│ tool calls (workdir-contained) │ MCP servers / plugins
▼ ▼
Filesystem · shell · git · gh LLM providers (user-configured)
Headless (codingdude run) is the same engine in-process — no server, no
worker.
- Server never runs the agent (ADR-0002). It owns HTTP/SSE, auth, persistence, the run registry and worker supervision.
- Worker — one subprocess per run, dials back over a local WebSocket, dies with its run. A crash or a killed run cannot take the server with it.
-
Engine — the pydantic-ai loop, shared by the worker and headless paths;
run_pipeline.pyorchestrates a whole run (onboarding, context, memory, planning loop, toolsets, gates, memory-extraction tail).
-
One live worker per session. Starting a new run terminates any live worker
for that session and pushes
RUN_CANCELLEDto the old viewers. -
Reaper. After a worker's socket closes, if no terminal event was delivered
the server synthesises
RUN_ERROR(worker_died) and records the run end — idempotently. - Janitor. A 2 s sweep, independent of any socket: reaps exited workers, and terminates a worker that never connected within 60 s.
-
Terminal replay grace. A finished channel stays registered for 300 s so
EventSourceauto-reconnects replay the terminal and settle. -
Boot reconciliation. At startup, runs still marked
runningbecomeinterrupted; dead process rows get durable end states. -
Prompts travel by file (
~/.codingdude/prompts/<run_id>.prompt), not argv — Windows has a 32k command-line limit. Stale files older than 24 h are cleaned at boot.
| Module | Responsibility |
|---|---|
server.py |
FastAPI app factory, HTTP/SSE/WS endpoints, static serving, run channels, janitor |
worker.py |
per-run subprocess; applies project [models] overrides, runs the pipeline, streams events |
engine.py |
agent construction: model resolution, toolsets, approvals, budget, failover |
run_pipeline.py |
full-run orchestration, including the per-request compaction guard |
context.py |
token estimate, needs_compaction, plan_compaction, mechanical compaction |
agent_caps.py |
cache capability profiles (RUN / ONE_SHOT) — the single seam every agent takes caching from |
limits.py |
the per-agent.run() spend ceilings (max_cost_usd, max_total_tokens) |
review_gate.py |
pre-push review gate: content-addressed diff key, record_review, require_review
|
approvals.py |
tiered approval engine (cards, pattern approvals, always-gated set) |
tools.py |
core toolsets: files, shell, git/gh, web, delegation, coverage, knip, CI, audit, ask-user |
ast_tools.py, callgraph.py, cfg.py, structure.py, impact.py, deadcode.py, mutation.py, fuzzing.py, bench.py
|
analysis tools |
roadmap.py |
planning store: roadmap, tickets, decisions, PRDs, tech designs (+ ROADMAP.md parser) |
planning.py |
plan store and step tracking for the planning loop |
memory.py, skills.py, directives.py, onboarding.py
|
continuity and instruction layering |
checkpoints.py, artifacts.py, processes.py
|
snapshots/rewind, interactive artifacts, shell process tracking |
sandbox.py, worktrees.py, delegation.py
|
sandboxes, git worktrees, sub-agent plumbing |
telemetry.py, traces.py, evals.py
|
usage/cost accounting, JSONL traces, scenario record/replay |
security.py |
security gate (Bandit, Semgrep, secret regexes) — fails closed |
scaffold.py, seed.py
|
project scaffolding; ~/.codingdude seeding |
config.py, db.py, cli.py, mcp_config.py, codegraph_boot.py
|
config, store, CLI, MCP, index boot |
SQLite under the config home, in WAL mode. Tables (all additive):
sessions, messages, session_notes, project_notes, approvals, memory,
usage, embeddings, plans, projects, roadmap_items, tickets,
ticket_execution, reference_sections, reference_meta, artifacts,
renders, processes, runs, design_decisions, prds, tech_designs.
Notes:
-
runs.statushas a CHECK constraint;RUN_CANCELLEDis stored asinterrupted. - Session traces are JSONL files, not a table.
-
ROADMAP.mdin the workdir is canonical when present —GET /planningparses it directly and the DB is the fallback. PRDs and tech designs are DB-only, keyed by workdir; designs carry an optionalprd_id.
React + Vite + Tailwind SPA. The workspace is a single dockable shell
(dockview-react, pinned): every surface is a panel registered in
workspace/catalogue.ts — the single source of truth for panels and presets —
arranged by Workspace.jsx, moved via the command palette (Ctrl+Shift+P) or
drag, persistable to localStorage, and poppable to OS windows. Data flows through
a visibility-gated store (one 2 s scheduler, visible topics only) rather than
per-panel polling. App.jsx keeps only the session/SSE state machine and login.
Build output is frontend/dist, served by the server when present — single
command deployment. The frontend bakes __APP_VERSION__ at build; the backend
version comes from package metadata, which is why a stale dist/ is visible as a
version mismatch in the StatusFooter.
| Extend by | How |
|---|---|
| New LLM provider | config-only ([providers.name] with base_url) |
| New MCP server |
mcp.json (global or project), toggled per session |
| New skill |
SKILL.md in a skills dir — see Skills and Directives
|
| New tool | module-level toolset builder + registration; must honour path containment |
| New checklist |
reference/checklists/*.md (seeded into projects) |
| Plugins | the plugins/ package hook points |
Start
How it works
Using it
Project