Architecture
The core design principle: dumb server, smart agents.
The server has zero AI. It makes no LLM calls, holds no API keys, and forms no opinions about your codebase. It’s a pure CRUD coordination layer with atomic task pickup. All planning, decomposition, and reasoning happens in the agents.
System layers
┌─────────────────────────────────────────────────────┐
│ Agents (any machine, any tool) │
│ Claude Code · Codex · Cursor · Copilot · scripts │
└──┬──────────────────────────────────┬──────────────┘
│ │
│ cpk scan / cpk code │ cpk task / cpk docs
│ (offline — direct SQLite) │ (HTTP to daemon)
│ ▼
│ ┌────────────────────────────────┐
│ │ codepakt server (Hono) │
│ │ ├── REST API /api/* :41920 │
│ │ └── Dashboard / (same port) │
│ └────────────┬───────────────────┘
▼ ▼
┌──────────────────────────────────────────────────────┐
│ <project>/.codepakt/data.db (SQLite, WAL mode) │
│ tables: tasks, agents, events, docs, │
│ symbols, imports │
└──────────────────────────────────────────────────────┘
Two execution paths reach the same local SQLite file:
- Code intelligence (
cpk scan,cpk code *): opens the DB directly via better-sqlite3. No HTTP, no daemon. Fast and offline-capable. - Task coordination (
cpk task *,cpk board *,cpk agent *,cpk docs *): goes through the Hono server because atomic pickup needsBEGIN IMMEDIATEacross concurrent agent processes.
Technology stack
| Layer | Choice | Reason |
|---|---|---|
| HTTP framework | Hono | Lightweight, fast, TypeScript-native |
| Database | better-sqlite3 | Synchronous API, WAL mode, zero config, embeds in npm package |
| CLI | Commander.js | Mature, minimal, well-typed |
| Validation | Zod | Runtime type safety at API boundaries |
| Query layer | Typed functions, no ORM | SQL is readable; ORMs add abstraction without benefit here |
| Code parsing | tree-sitter WASM (web-tree-sitter) | Works with npx (no native compilation). Grammar WASMs for TS, TSX, JS, Python, Go ship in grammars/ |
Single npm package
Everything ships in one package: codepakt.
- CLI binary (
cpk) - HTTP server (Hono)
- SQLite driver (better-sqlite3)
- Dashboard HTML/JS (served from the same process)
- tree-sitter WASM grammars for 5 languages (~6MB unpacked)
No docker. No separate database service. No config file beyond what cpk init creates. Install and run.
Code intelligence scanner
cpk scan parses every supported source file with tree-sitter WASM:
- Collect files — walk the project tree, respect
.gitignoreand.codepaktignore, filter by extension - Load grammar — lazy-load the right WASM grammar per language (cached after first use)
- Parse — produce a concrete syntax tree from the source
- Extract — walk the CST to emit symbol and import records (functions, classes, interfaces, types, methods, exported vars, imports with resolved paths)
- Persist — replace project data in a single SQLite transaction
Incremental mode (cpk scan --incremental) uses git diff --cached to get staged files, then processes only those. The pre-commit hook runs this automatically, keeping the index fresh with millisecond updates per commit.
Atomic task pickup
Two agents calling cpk task pickup simultaneously must not receive the same task.
Solution: BEGIN IMMEDIATE transaction in SQLite.
BEGIN IMMEDIATE;
SELECT id FROM tasks
WHERE status = 'open'
AND deps_met = 1
ORDER BY CASE priority WHEN 'P0' THEN 0 WHEN 'P1' THEN 1 ELSE 2 END, created_at ASC
LIMIT 1;
UPDATE tasks SET status = 'in-progress', assignee = :agent WHERE id = :task_id;
COMMIT;
BEGIN IMMEDIATE acquires a write lock at transaction start, before the SELECT. Any concurrent transaction attempting to start waits. The first writer wins; others retry. This is SQLite’s built-in serialization — no application-level locking needed.
This is the reason task coordination still needs the server: multiple CLI processes calling pickup simultaneously all need to coordinate through the same daemon for the lock to work. Code intelligence doesn’t need this because cpk scan runs from a single process (or git hook) and reads are inherently lock-free in WAL mode.
Audit trail
Every mutation (task creation, status change, pickup, completion) writes to an events table:
events
id TEXT PRIMARY KEY
task_id TEXT
agent TEXT
action TEXT -- 'task_created', 'task_pickup', 'task_complete', etc.
detail TEXT -- JSON payload
created_at TEXT
This is an append-only log. Nothing is ever deleted from events. It’s the source of truth for “what happened and when.”
Dependency resolution
When a task reaches review (agent calls cpk task done), the server runs a dependency check:
- Find all tasks whose
depends_onincludes the completed task’s ID - For each, check whether all other dependencies are in
reviewordone - If yes, set
deps_met = trueand transition frombacklogtoopen
Dependencies resolve on review, not on done. This means the pipeline keeps moving without waiting for human approval. The check runs synchronously inside the same transaction.
Database schema
| Table | Purpose |
|---|---|
projects | Project metadata (id, name, created_at) |
tasks | Task records with status, priority, deps, verify, notes |
agents | Agent records (auto-created on first interaction) |
events | Append-only audit log |
docs | Knowledge base documents |
symbols | Code intelligence: functions, classes, interfaces, methods, etc. |
imports | Code intelligence: file-to-file import relationships |
metadata | Key/value settings |
schema_version | Migration tracking |
Schema version is 3 (as of v0.2). Migrations in src/server/db/index.ts handle upgrades automatically when a DB is opened.
Dashboard delivery
The dashboard is a static HTML/JS application served from the Hono server at /. The JS makes fetch calls to /api/* — the same origin, no CORS needed. There is no separate deployment step.
What’s not in the server
- No authentication or authorization (single-user, localhost)
- No LLM calls
- No file watching or filesystem access (scans are on-demand)
- No webhooks or external integrations
- No background job queue
- No Postgres (planned for a later release)
Keeping the server simple is a deliberate choice. Complexity lives in the agents, where it can be reasoned about, tested, and replaced independently.
Related
- cpk scan — the scanner in practice
- cpk code — querying the index
- Agents & Coordination — how the “smart” part works