Files
Codewalkers/docs/database.md
Lukas May 536cdf08a1 feat: Propagate task summaries and input context to execution agents
Execution agents were spawning blind — no input files, no knowledge of
what predecessor tasks accomplished. This adds three capabilities:

1. summary column on tasks table — completeTask() reads the finishing
   agent's result.message and stores it on the task record
2. dispatchNext() gathers full initiative context (initiative, phase,
   sibling tasks, pages) and passes it as inputContext so agents get
   .cw/input/task.md, initiative.md, phase.md, and context directories
3. context/tasks/*.md files now include the summary field in frontmatter
   so dependent agents can see what prior agents accomplished
2026-03-03 13:42:37 +01:00

7.8 KiB

Database Module

apps/server/db/ — SQLite database via better-sqlite3 + Drizzle ORM with hexagonal architecture.

Architecture

  • Schema: apps/server/db/schema.ts — all tables, columns, relations
  • Ports (interfaces): apps/server/db/repositories/*.ts — 10 repository interfaces
  • Adapters (implementations): apps/server/db/repositories/drizzle/*.ts — 10 Drizzle adapters
  • Barrel exports: apps/server/db/index.ts re-exports everything

All adapters use nanoid() for IDs, auto-manage timestamps, and use Drizzle's .returning() for atomic reads after writes.

Tables

initiatives

Column Type Notes
id text PK nanoid
name text NOT NULL
status text enum 'active' | 'completed' | 'archived', default 'active'
mergeRequiresApproval integer/boolean default true
branch text nullable auto-generated initiative branch (e.g., 'cw/user-auth')
createdAt, updatedAt integer/timestamp

phases

Column Type Notes
id text PK
initiativeId text FK → initiatives (cascade)
name text NOT NULL
content text nullable Tiptap JSON
status text enum 'pending' | 'approved' | 'in_progress' | 'completed' | 'blocked'
createdAt, updatedAt integer/timestamp

phase_dependencies

phaseId FK → phases, dependsOnPhaseId FK → phases. Both cascade delete.

tasks

Column Type Notes
id text PK
phaseId text nullable FK → phases (cascade)
initiativeId text nullable FK → initiatives (cascade)
parentTaskId text nullable self-ref FK (cascade) decomposition hierarchy
name text NOT NULL
description text nullable
type text enum 'auto' | 'checkpoint:human-verify' | 'checkpoint:decision' | 'checkpoint:human-action'
category text enum 'execute' | 'research' | 'discuss' | 'plan' | 'detail' | 'refine' | 'verify' | 'merge' | 'review'
priority text enum 'low' | 'medium' | 'high'
status text enum 'pending_approval' | 'pending' | 'in_progress' | 'completed' | 'blocked'
requiresApproval integer/boolean nullable null = inherit from initiative
order integer default 0
summary text nullable Agent result summary — propagated to dependent tasks as context
createdAt, updatedAt integer/timestamp

task_dependencies

taskId FK → tasks, dependsOnTaskId FK → tasks. Both cascade delete.

agents

Column Type Notes
id text PK
name text NOT NULL UNIQUE human-readable alias (adjective-animal)
taskId text nullable FK → tasks (set null)
initiativeId text nullable FK → initiatives (set null)
sessionId text nullable CLI session ID for resume
worktreeId text NOT NULL path to agent's git worktree
provider text NOT NULL default 'claude'
accountId text nullable FK → accounts (set null)
status text enum 'idle' | 'running' | 'waiting_for_input' | 'stopped' | 'crashed'
mode text enum 'execute' | 'discuss' | 'plan' | 'detail' | 'refine'
pid integer nullable OS process ID
exitCode integer nullable
outputFilePath text nullable
result text nullable JSON
pendingQuestions text nullable JSON
userDismissedAt integer/timestamp nullable
createdAt, updatedAt integer/timestamp

accounts

Column Type Notes
id text PK
email text NOT NULL
provider text NOT NULL default 'claude'
configJson text nullable serialized .claude.json
credentials text nullable serialized .credentials.json
isExhausted integer/boolean default false
exhaustedUntil integer/timestamp nullable
lastUsedAt integer/timestamp nullable round-robin scheduling
sortOrder integer
createdAt, updatedAt integer/timestamp

proposals

Column Type Notes
id text PK
agentId text FK → agents (cascade)
initiativeId text FK → initiatives (cascade)
targetType text enum 'page' | 'phase' | 'task'
targetId text nullable existing entity ID, null for creates
title, summary, content text markdown body
metadata text nullable JSON
status text enum 'pending' | 'accepted' | 'dismissed'
sortOrder integer
createdAt, updatedAt integer/timestamp

pages

Column Type Notes
id text PK
initiativeId text FK → initiatives (cascade)
parentPageId text nullable self-ref FK (cascade) root page has NULL
title text NOT NULL
content text nullable Tiptap JSON
sortOrder integer
createdAt, updatedAt integer/timestamp

projects

Column Type Notes
id text PK
name text NOT NULL UNIQUE
url text NOT NULL UNIQUE git repo URL
defaultBranch text NOT NULL default 'main'
createdAt, updatedAt integer/timestamp

initiative_projects (junction)

initiativeId + projectId with unique index. Both FK cascade.

messages

Self-referencing (parentMessageId) for threading. Sender/recipient types: 'agent' | 'user'.

agent_log_chunks

Column Type Notes
id text PK
agentId text NOT NULL NO FK — survives agent deletion
agentName text NOT NULL snapshot for display
sessionNumber integer spawn=1, resume=prev+1
content text NOT NULL raw JSONL chunk
createdAt integer/timestamp

Index on agentId for fast queries.

conversations

Inter-agent communication records.

Column Type Notes
id text PK
fromAgentId text NOT NULL FK→agents ON DELETE CASCADE
toAgentId text NOT NULL FK→agents ON DELETE CASCADE
initiativeId text FK→initiatives ON DELETE SET NULL
phaseId text FK→phases ON DELETE SET NULL
taskId text FK→tasks ON DELETE SET NULL
question text NOT NULL
answer text nullable until answered
status text enum pending, answered
createdAt integer/timestamp
updatedAt integer/timestamp

Indexes: (toAgentId, status) for listen polling, (fromAgentId).

Repository Interfaces

11 repositories, each with standard CRUD plus domain-specific methods:

Repository Key Methods
InitiativeRepository create, findById, findAll, findByStatus, update, delete
PhaseRepository + createDependency, getDependencies, getDependents, findByInitiativeId
TaskRepository + findByParentTaskId, findByPhaseId, findPendingApproval, createDependency
AgentRepository + findByName, findByTaskId, findBySessionId, findByStatus
MessageRepository + findPendingForUser, findRequiringResponse, findReplies
PageRepository + findRootPage, getOrCreateRootPage, findByParentPageId
ProjectRepository + junction ops: setInitiativeProjects (diff-based), findProjectsByInitiativeId
AccountRepository + findNextAvailable (round-robin), markExhausted, clearExpiredExhaustion
ProposalRepository + findByAgentIdAndStatus, updateManyByAgentId, countByAgentIdAndStatus
LogChunkRepository insertChunk, findByAgentId, deleteByAgentId, getSessionCount
ConversationRepository create, findById, findPendingForAgent, answer

Migrations

Located in drizzle/. Applied via ensureSchema() on startup using Drizzle's migrate().

Key rules:

  • Never use raw SQL for schema initialization
  • Run npx drizzle-kit generate to create migrations
  • See database-migrations.md for full workflow
  • Snapshots stale after 0008; migrations 0008+ are hand-written

Current migrations: 0000 through 0026 (27 total).