Slop Docs Home
Slop ยท Codebase

Source Tree Analysis

Annotated directory structure and critical file reference for the Slop codebase.

TypeScript Next.js App Router Prisma Vitest

Repository Root

The top-level layout separates source code, data, configuration, test infrastructure, and the harness that gets deployed to watched repos.

├─ src/All TypeScript source — app, db, lib, server, types
├─ prisma/Schema + 40 migrations, prisma.config.ts at root
├─ e2e/Playwright end-to-end tests
├─ scripts/Build utilities — build-surface-map.mts, prisma-migrate-dev.ts
├─ harness/Agent skills + rules deployed to watched repos via bootstrap.sh; excluded from lint/typecheck
├─ data/SQLite DB files (slop.db, slop_test.db) and static data assets
├─ docs/Project documentation — SPEC.md, surface-map.md, feature docs, design guide
├─ .github/workflows/CI/CD — ci.yml (lint, typecheck, test) + claude-review.yml
├─ MakefileDev task runner — install, dev, start, test, lint, format, build, seed, map
├─ biome.jsonLint + format config (Biome replaces ESLint + Prettier)
├─ vitest.config.tsMain test config — per-file coverage floors on critical paths
├─ vitest.config.scripts.tsLightweight scripts test config — no DB, no Next.js
└─ tsconfig.jsonstrict: true; @/* path alias maps to src/*

src/app/

Next.js 16 App Router. Pages, layouts, React components, Server Actions, and REST API routes all live here. The root route (/) is the Kanban board.

src/app/
├─ _components/Shared React components, organized by domain
│ ├─ ui/Primitives — buttons, badges, dialogs, copy-to-clipboard
│ ├─ nav/Sidebar navigation and repo switcher
│ ├─ worker/Worker cards, event log, merge button, overrides form
│ ├─ repo/Repo state panel, PR cards, CI badges
│ ├─ report/Worker report renderer, run report viewer
│ └─ agents/Agent harness selector, skill run controls
├─ actions/Server Actions split by domain
│ ├─ _shared.tsgetRunningDaemon(), ActionResult type, shared validators
│ └─ batch · config · internal-issue · issue · pr · repo · runs · worker
├─ api/REST route handlers — all force-dynamic
│ └─ agents · bmad-stories · docs · events · features · health · internal-issues · labels · repo · runs · workers
├─ page.tsxBoard root "/" — Kanban columns, worker list, ready queue
├─ layout.tsxRoot layout — font loading, nav sidebar, daemon guard check
└─ globals.cssTailwind 4 @theme tokens — all color, radius, and spacing variables

src/db/

One repo file per Prisma model concern. Repository functions are pure Prisma passthroughs — no try/catch, no business logic. Each ships with a paired .test.ts against the real SQLite test DB.

client.ts
PrismaClient singleton export used across all repos.
config.repo.ts
Global Config row — implementMode, timeouts, flags, GitHub token.
worker.repo.ts
Worker rows — create, status CAS updates, appendEvent, list, delete.
event.repo.ts
WorkerEvent rows — append and paginated list by workerId.
ready-issue.repo.ts
ReadyIssue join table — scoped by repoId, ready-queue membership.
ready-order.repo.ts
ReadyOrder priority list — fractional indexing for drag-to-reorder.
issue-config.repo.ts
IssueConfig overrides per issue — implementMode, review level, model.
repo.repo.ts
Repo rows — slug, local path, baseBranch, parallelism cap.
repo-snapshot.repo.ts
RepoSnapshot rows — cached GitHub state, open PRs, CI status.
internal-issue.repo.ts
InternalIssue rows — title, body, state, labels, comments.
label.repo.ts
Label rows — name, color, description, scoped by repoId.
run.repo.ts
Run rows — skill runs and worker report runs, status, events.
worker-report.repo.ts
WorkerReport rows — folded session stats attached to a worker.
batch.repo.ts
Batch + BatchItem rows — issue grouping and ordering.
reset.test-support.ts
Utility to truncate all tables between test runs.

src/lib/

Shared utilities with no circular dependencies. Pure functions; no DB access; no daemon imports. Organized into subdirectories by concern.

src/lib/agent/
agent-model.tsMaps implement mode + harness to model ID and effort level. Used by run-impl and skill runs.
implement-mode.tsResolves effective implement mode — merges global config with per-issue overrides.
src/lib/process/
concurrency.tsMutex and semaphore primitives for the daemon's per-repo parallelism cap.
reap-process.tsKills a process tree by PID; used during worker cancel and worktree cleanup.
sample-memory.tsSamples resident set size for the Claude Code subprocess during a run.
src/lib/repo/
ready-order.tsFractional-index helpers for computing insertion positions in the ready queue.
repo-lens.tsDerives display paths and worktree root from a Repo row.
repo-snapshot.tsDiffs two RepoSnapshot shapes to produce a change summary for events.
watched-repo.tsValidates and normalizes a watched-repo input before writing to the DB.
Top-level utils
auto-mode.tsHeuristic that selects implementMode from issue size signals.
bmad-stories.tsParses BMAD-format markdown story files into structured story objects.
event-format.tsFormats raw Claude Code subprocess output lines into WorkerEvent payloads.
logger.tsStructured pino logger — prefixed by component, level-filtered in test.
skills.tsSkill name allowlist and argument shape registry for skill runs.
story-points.tsFibonacci-scale point buckets and formatting for issue complexity scores.
time.tsDuration formatting (ms → human-readable) used in worker reports.
slop-paths.tsCentral path constants — data dir, DB file, worktrees root.
docs.tsALLOWED_DOC_FILES allowlist and doc-serving helpers for the API route.

src/server/daemon/

The daemon is a Node.js singleton that runs the poll cycle, manages worker lifecycles, and owns all state mutations. It boots once per server process and is accessed by Server Actions via getRunningDaemon().

src/server/daemon/
├─ index.tsDaemon singleton; implements the Daemon interface; wires all ops modules
├─ tick.ts13-step poll cycle: lifecycle, claim, CI health, snapshot, notifications, and more
├─ types.tsDaemon interface, DaemonState shape, DaemonDeps injection contract
├─ boot.tsBoot sequence: DB lock acquisition, config seed, guard check enforcement
├─ lifecycle-poll.tsReconciles running workers against GitHub — detects merged/closed PRs
├─ claim-worker.tsClaims next ready issue respecting per-repo concurrency cap; spawns worker
├─ runner-registry.tsIn-memory registry of running worker promises; double-spawn guard
├─ ci-health-controller.tsMonitors base branch CI; triggers fix-base-ci when checks are failing
├─ completion-report.tsGenerates and persists WorkerReport after a worker finishes
├─ config-seed.tsSeeds default Config row on first boot if absent
├─ database-durability.tsWAL mode enforcement and SQLite pragma setup at startup
├─ repo-snapshot-poll.tsScheduled GitHub poll to refresh RepoSnapshot for all watched repos
├─ worker-resource-poll.tsSamples memory of running Claude Code subprocesses; writes to worker events
├─ guard-check.tsChecks guard-passed flag; blocks daemon start until setup wizard completes
└─ ops/Operation modules injected into the daemon index
├─ admin-ops.tsaddRepo, removeRepo, wipeDatabase, enableGuards
├─ boot-ops.tsstart(), stop() — wires boot.ts into the daemon lifecycle
├─ config-ops.tsConfig mutations called from config Server Actions
├─ context.tsShared DaemonContext type threaded through all ops
├─ fix-base-ci-ops.tsfixBaseCi(), syncBranch() — dispatches repair skill runs
├─ helpers.tsShared guards — assertWorkerExists, assertRepoExists
├─ issue-ops.tsstartIssue, setIssueReady, returnIssueToBacklog, reorderReadyIssue
├─ pr-ops.tsmergePr, closePr, reviewPr, addressPr, mergeWorker
└─ worker-ops.tspauseWorker, restartWorker, cancelWorker, overrideToMerged

src/server/workers/

The per-issue worker pipeline. Each worker is a long-running async function that progresses through phases: implement, verify, CI-fix, conflict resolution, PR review, and address-comments. All collaborators are injected via the RunWorkerDeps / Deps object.

src/server/workers/
├─ worker.tsrunWorker() entry point — timeout wrapper, abort signal wiring, top-level error handling
├─ lifecycle.tsState machine — status transitions with compare-and-swap DB writes; pause/resume logic
├─ phase-runner.tsPhase orchestration — loops through phases, catches errors, decides retry vs fail
├─ run-impl.tsImplementation phase — constructs Claude Code invocation, dispatches agent subprocess
├─ run-verify.tsVerify-gate skill loop — runs the verify skill until it passes or exceeds attempt budget
├─ run-ci-fix.tsCI fix phase — runs fix-ci skill, waits for CI checks to pass
├─ run-conflict.tsConflict resolution phase — rebases and resolves merge conflicts via agent
├─ run-pr-review.tsPR review gate — polls review status, blocks merge until review clears
├─ run-address.tsAddress-comments phase — re-runs agent with review comments as context
├─ agent.tsSpawns Claude Code subprocess, streams stdout events into the event log
├─ git.tsGit operations: branch creation, commit, push, rebase onto base
├─ worktree.tsGit worktree create/delete/list — nested at WORKTREES_ROOT/<repoId>/<issueNumber>
├─ shipping.tsPR creation via GitHub API, auto-merge enabling, post-merge cleanup
├─ local-merge.tsExecutes local squash merge when remote merge is not available
├─ session-stats.tsAccumulates token counts and cost across all agent invocations; folds into WorkerReport
├─ implement-context.tsConstructs the issue context prompt injected into the implementation invocation
└─ coverage.tsParses Vitest coverage output to extract per-file coverage floors for the report

src/server/github/

Thin REST wrapper around the GitHub API. All callers receive the client through dependency injection — from-env.ts constructs the real client; tests use fake.ts.

src/server/github/
├─ client.tsGitHubClient class — all REST calls (issues, PRs, CI checks, refs, labels)
├─ types.tsGitHubIssue, GitHubPR, GitHubCheckRun, and related shape types
├─ fake.tsIn-memory fake GitHubClient for tests — controllable state, no network
├─ from-env.tsConstructs the real client from GITHUB_TOKEN env var
└─ index.tsRe-exports GitHubClient and types for consumers

src/server/runs/

Skill run orchestration — separate from the per-issue worker pipeline. Handles standalone agent invocations: suggesting story points, generating worker reports, running doc-editing skills, and PR review automation.

src/server/runs/
├─ driver.tsDrives a skill run through its lifecycle — spawn, stream events, write status
├─ skill-run.tsCreates a Run row and enqueues a skill invocation via the run registry
├─ run-registry.tsIn-memory registry of active skill run promises; prevents concurrent duplicates
├─ harness-availability.tsChecks whether the configured agent harness is available in the target repo
├─ pr-review.tsDispatches the PR review skill and maps result back to a review decision
├─ suggest-points.tsRuns the suggest-points skill; returns point estimate and harness used
├─ summarize.tsSummarizes a finished worker run into a short prose report
└─ worker-report-issue.tsCreates an internal issue from a worker report for human review

src/types/

Shared TypeScript types that cross module boundaries. No runtime code — pure type declarations. Consumers import from @/types/<feature>.

Convention: cross-cutting types live here. Module-local types stay in the file that owns them. If a type is used by more than two files, move it to src/types/.

prisma/

SQLite via Prisma ORM. The schema defines all models. Migrations are checked in and run sequentially — never edited after creation. Use pnpm exec tsx scripts/prisma-migrate-dev.ts to create a new migration (this script backs up the DB first).

prisma/
├─ schema.prismaAll model definitions — Repo, Config, Worker, WorkerEvent, ReadyIssue, ReadyOrder, IssueConfig, RepoSnapshot, InternalIssue, Label, Run, WorkerReport, Batch, BatchItem
└─ migrations/40 sequential migration directories, each containing migration.sql
Test DB: data/slop_test.db is reset between test runs by vitest.global-setup.ts via prisma db push --accept-data-loss. Never run migrations against the test DB manually.

Critical Files

The 25 files most likely to be the right edit target for any given task. When in doubt, start here.

FilePurpose
src/server/daemon/index.tsDaemon singleton implementation — the central coordinator for all background work
src/server/daemon/types.tsDaemon interface contract — add new operations here first
src/server/daemon/tick.ts13-step poll cycle — controls what happens every N seconds
src/server/daemon/claim-worker.tsNext-issue selection logic with concurrency cap enforcement
src/server/daemon/lifecycle-poll.tsGitHub reconciliation — detects external PR merges and closures
src/server/workers/worker.tsWorker entry point — timeout, abort signal, top-level error handler
src/server/workers/lifecycle.tsStatus state machine — all valid transitions and CAS writes
src/server/workers/phase-runner.tsPhase loop — decides which phases to run and in what order
src/server/workers/run-impl.tsImplementation phase — Claude Code invocation construction
src/server/workers/shipping.tsPR creation, auto-merge, and post-merge cleanup
src/server/workers/agent.tsClaude Code subprocess spawn and event streaming
src/server/workers/git.tsAll git operations used by the worker pipeline
src/server/workers/worktree.tsWorktree lifecycle — nested at WORKTREES_ROOT/repoId/issueNumber
src/server/github/client.tsGitHub REST client — all external API calls
src/app/actions/_shared.tsgetRunningDaemon(), ActionResult type, shared action utilities
src/app/actions/worker.tsWorker Server Actions — startWorker through clearFinishedWorkers
src/app/actions/issue.tsIssue lifecycle Server Actions — setIssueReady, startIssue, reorder
src/app/api/events/route.tsSSE stream route — board live updates
src/db/worker.repo.tsWorker table access — most-read repo in the codebase
src/db/config.repo.tsGlobal config access — read on every tick
src/db/ready-issue.repo.tsReady queue membership — claim-worker reads this on every cycle
src/lib/agent/agent-model.tsModel + effort level resolution — controls which Claude model is used
src/middleware.tsAuth enforcement for all routes — guards the API and UI pages
prisma/schema.prismaSingle source of truth for the data model
docs/surface-map.mdSignatures-only index of all edit seams — start here when locating code

Migration History

40 migrations tracing the feature evolution from initial schema to the current state. Each directory contains a single migration.sql.

Initial Schema — May 28
TimestampMigration name
20260528_130143init
20260528_132733add_worker_issue_title_url
20260528_160312add_worker_status_index
20260528_204649add_worker_notified_at
Report + Snapshot — May 29 – Jun 1
TimestampMigration name
20260529_150000add_worker_report_and_repo_snapshot
20260529_152241add_issue_chat
20260530_055239add_event_level
20260601_014236add_event_raw_content
Verification + Overrides — Jun 2 – 6
TimestampMigration name
20260602_002512add_worker_session_resume
20260603_193518add_worker_verification_attempts
20260604_011226per_issue_overrides
20260604_030924issue_config
20260605_160655per_issue_review_overrides
20260605_224613ready_issue_drop_graph
20260606_012934add_waiting_merge_tracking
20260606_133631add_status_before_report
Multi-Repo + Runs — Jun 7
TimestampMigration name
20260607_182149add_points_auto_scored
20260607_190000add_run_agent_metadata
20260607_193000multi_repo
20260608_000000drop_issue_chat
20260608_120000add_worker_issue_source
20260608_130000surface_internal_issues_in_kanban
20260608_194400restart_sync
Internal Issues + Labels — Jun 8 – 11
TimestampMigration name
20260608_113958add_internal_issue_store
20260609_211213add_label
20260610_000000remove_invalid_labels
20260610_151643add_run_report
20260611_033823restart_sync
20260611_034335add_session_harness
20260611_050522plan_artifacts
20260611_060000add_run_repo_id
20260611_120000story_ordering_epic_hierarchy_schema
20260611_143010story_ordering_epic_hierarchy_schema (rev)
20260611_221719graph_feature
20260611_234441drop_plan
Batch Import + Kind — Jun 12
TimestampMigration name
20260612_012331add_batch
20260612_020806add_repo_parallelism_cap
20260612_045905add_kind_to_worker
20260612_050000add_internal_issue_id_to_worker
20260612_084201add_status_before_pause