Database Schema
LoopTroop currently uses two SQLite databases plus filesystem artifacts.
That split is intentional:
- the app database stores global application configuration
- each attached project has its own operational database
- ticket artifacts and runtime logs live in the project worktree filesystem
Database Locations
| Database | Default location | Configuration |
|---|---|---|
| App DB | ~/.config/looptroop/app.sqlite | LOOPTROOP_CONFIG_DIR or LOOPTROOP_APP_DB_PATH |
| Project DB | <project>/.looptroop/db.sqlite | derived from the attached project root |
Both databases are opened with WAL mode enabled.
App Database
The app database is initialized in server/db/index.ts.
Tables
| Table | Purpose |
|---|---|
profiles | Singleton profile with model and workflow defaults |
app_meta | Small app-level key/value metadata |
attached_projects | Registry of attached project roots |
profiles
Key columns:
main_implementermain_implementer_variantcouncil_memberscouncil_member_variantsmin_council_quorumper_iteration_timeoutexecution_setup_timeoutcouncil_response_timeoutinterview_questionscoverage_follow_up_budget_percentmax_coverage_passesmax_prd_coverage_passesmax_beads_coverage_passesmax_iterationstool_input_max_charstool_output_max_charstool_error_max_chars
This table provides the baseline configuration that projects and tickets inherit from when they start.
Project Database
The project database is initialized in server/db/project.ts and uses the schema definitions from server/db/schema.ts.
Tables
| Table | Purpose |
|---|---|
projects | Project metadata and project-level overrides |
tickets | Ticket records and workflow snapshot fields |
phase_artifacts | Structured phase artifacts with phase and attempt numbers |
ticket_phase_attempts | Attempt history per phase |
opencode_sessions | Owned OpenCode session records |
ticket_status_history | Status transition history |
ticket_error_occurrences | Persisted blocked-error occurrences and resolution history |
projects
Important columns:
nameshortnameiconcolorfolder_pathprofile_id- project-level overrides for council and timeout settings
ticket_counter
tickets
Important columns:
external_idproject_idtitledescriptionprioritystatusxstate_snapshotbranch_namecurrent_beadtotal_beadspercent_completeerror_message- locked model and planning settings, including interview coverage passes plus PRD/beads coverage pass caps frozen at ticket start
started_atplanned_date
This table is the operational center of a ticket, but it is not the only place ticket truth lives. Review artifacts and runtime logs still live in .ticket/**.
phase_artifacts
Columns:
ticket_idphasephase_attemptartifact_typecontentcreated_atupdated_at
Important note:
- the current DB schema does not include a
file_pathcolumn - the frontend artifact normalizer accepts
filePathin API payloads, but that field is not a physical column inphase_artifacts
ticket_phase_attempts
Tracks retry or restart history for individual phases.
Columns:
ticket_idphaseattempt_numberstatearchived_reasoncreated_atarchived_at
opencode_sessions
This table is what makes restart-safe session ownership possible.
Columns:
session_idticket_idphasephase_attemptmember_idbead_iditerationstepstatelast_event_idlast_event_at
ticket_status_history
A simple transition log:
ticket_idprevious_statusnew_statusreasonchanged_at
ticket_error_occurrences
Stores repeated blocked states as explicit occurrences rather than one mutable error blob.
Columns:
ticket_idoccurrence_numberblocked_from_statuserror_messageerror_codesoccurred_atresolved_atresolution_statusresumed_to_status
Relationship Overview
What Is Not In SQLite
SQLite is not the whole system.
Important non-DB state includes:
.ticket/relevant-files.yaml.ticket/interview.yaml.ticket/prd.yaml.ticket/beads/<flow>/.beads/issues.jsonl.ticket/runtime/execution-log.jsonl.ticket/runtime/state.yaml.ticket/runtime/execution-setup-profile.json
The database tracks and indexes workflow state. The filesystem stores the user-facing and execution-facing artifacts.
Indexes And Runtime Behavior
The project DB also creates indexes for:
- ticket status
- ticket external id
- artifact lookup by ticket and phase attempt
- session lookup by ticket, phase, and ownership fields
- error occurrence lookup
Combined with WAL mode, this keeps the workflow responsive while the UI polls and the backend streams updates.