AgentSwarm is a TypeScript monorepo whose runtime shape is a Docker Compose stack. A Fastify API server orchestrates tasks, a Next.js web app provides the browser UI, isolated agent containers execute Codex and Claude work, and Redis carries the real-time event stream that keeps the UI in sync. Understanding how these pieces fit together makes it easier to navigate the codebase, debug problems, and contribute safely.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/coretracker/agentswarm/llms.txt
Use this file to discover all available pages before exploring further.
Monorepo Structure
The repository is organised as an npm workspaces monorepo. The top-level layout is:apps/server
The Fastify backend. Handles authentication, task lifecycle, repository management, scheduling, agent spawning, GitHub webhooks, and all API routes. Runs on port 4000 inside the Docker network.
apps/web
The Next.js frontend. Calls backend APIs and receives real-time updates over Socket.IO. Runs on port 3217 (dev) and communicates with the server through the nginx reverse proxy.
packages/shared-types
The
@agentswarm/shared-types package. Defines all TypeScript types that cross the server/web boundary — tasks, runs, events, repositories, and more. Contains no business logic.agent-runtime-codex / agent-runtime-claude
Container images launched on-demand by the server for each task run. Each image bundles the provider CLI (Codex or Claude), Git tooling, and a runner script that streams logs and diffs back to the server.
Runtime Shape
The Docker Compose stack wires together five long-running services plus the ephemeral agent containers:| Service | Image | Purpose |
|---|---|---|
proxy | nginx | Reverse proxy. Routes /api/* requests to the server; all other traffic to the web app. |
server | @agentswarm/server | Fastify API on port 4000. Orchestrates tasks, manages stores, handles webhooks. |
web | @agentswarm/web | Next.js on port 3217. Serves the browser UI and connects via Socket.IO for real-time updates. |
postgres | postgres | Durable data store for tasks, repositories, users, settings, and all other application data. |
redis | redis | Sessions, task queues, webhook jobs, GitHub outbound queue, and real-time pub/sub event channel. |
| agent containers | agentswarm-agent-runtime-codex:latest / agentswarm-agent-runtime-claude:latest | Launched on-demand by the server’s SpawnerService for each task run. Terminated when the run completes. |
PUBLIC_PORT (default 3217). The server and web services are not exposed directly outside the Docker network in production configurations.
Data Flow
A task run follows this path from browser click to streamed output:Task creation
The user submits a task in the web UI. The web app calls
POST /api/tasks (or a related import/draft route) on the server through the nginx /api/* proxy.Scheduling
The
SchedulerService picks up the new task from the taskQueueStore (backed by Redis) and decides when to run it based on concurrency limits and provider settings.Spawning
The
SpawnerService launches a new Docker container from the appropriate runtime image (CODEX_RUNTIME_IMAGE or CLAUDE_RUNTIME_IMAGE). The container is mounted with the task workspace directory so that both the server and the runtime container share the same filesystem path.Execution
Inside the runtime container, the agent CLI (Codex or Claude) executes the task prompt against the cloned repository. The runner script streams structured log lines and Git diffs back to the server over the shared workspace.
Real-time updates
The server publishes
RealtimeEvent payloads (task status changes, log lines, run updates, change proposals) to the Redis pub/sub channel. The server’s Socket.IO layer subscribes to this channel and forwards events to authenticated browser clients.Shared Types Package
@agentswarm/shared-types (packages/shared-types/) is the single source of truth for data contracts that cross the server/web boundary. Both apps/server and apps/web depend on it as an npm workspace package:
Server Modules
The server (apps/server/src/) is organised into focused modules:
routes/
Fastify route handlers for every API surface:
auth.ts, tasks.ts, task-drafts.ts, repositories.ts, users.ts, roles.ts, settings.ts, snippets.ts, sequences.ts, imports.ts, and github-webhooks.ts.services/
Stateful services injected into routes:
task-store.ts, spawner.ts, scheduler.ts, sequence-execution-service.ts, github-import-service.ts, github-outbound-service.ts, webhook-delivery-service.ts, and the Postgres store factories.lib/
Pure orchestration and utility logic: task start orchestration, Git operations, provider config, auth, Docker socket access, MCP config, and interactive terminal management.
config/env.ts
Typed environment configuration parsed and validated with Zod at startup. All environment variables are accessed through the
env object — never via process.env directly.src/index.ts) bootstraps all services in order: Fastify app → Redis clients → Postgres pool → migrations → stores → auth → routes → Socket.IO → scheduler → ready.
Real-Time Events
The server publishes events to a Redis pub/sub channel. The Socket.IO server subscribes to that channel and forwards events to authenticated browser clients scoped to the resources each user can access. Events are typed as theRealtimeEvent union from @agentswarm/shared-types:
| Event type | Payload | When fired |
|---|---|---|
task:created / task:updated | Task | Task is created or its status/fields change. |
task:deleted | { id, repoId, ownerUserId } | Task is deleted. |
task:log | { taskId, runId, line, timestamp } | A log line arrives from a running agent container. |
task:message / task:message_updated | TaskMessage | An agent message is added or updated. |
task:run_updated | TaskRun | A run record changes status or metadata. |
task:git_operation | TaskGitOperation | A Git operation (push, merge, revert) completes. |
task:change_proposal | TaskChangeProposal | The agent proposes a change for review. |
task:pushed | { taskId, repoId, branchName, … } | Task branch is pushed to the remote. |
task:merged | { taskId, repoId, sourceBranch, targetBranch, … } | Task branch is merged. |
settings:updated | SystemSettings | Provider or system settings change. |
repository:created / repository:updated / repository:deleted | Repository | Repository record changes. |
snippet:created / snippet:updated / snippet:deleted | Snippet | Snippet record is created, updated, or deleted. |
sequence:created / sequence:updated / sequence:deleted | Sequence | Sequence record is created, updated, or deleted. |
sequence:run_updated | SequenceRun | A prompt sequence run progresses. |
socket.io-client and updates component state without requiring a page reload.
Boundary Rules
Architecture boundaries are enforced mechanically byscripts/harness/boundary-check.mjs, which runs as part of both check.sh and pr-ready.sh.
Rule 1 — Web must not import server code
Rule 1 — Web must not import server code
Any file under
apps/web importing from apps/server is a violation. Browser code cannot depend on backend internals.Fix: Move shared logic to packages/shared-types or call server APIs instead.Rule 2 — Server must not import web code
Rule 2 — Server must not import web code
Any file under
apps/server importing from apps/web is a violation. Backend services must not depend on UI implementation details.Fix: Move shared contracts to packages/shared-types or keep the logic in a server module.Rule 3 — shared-types must not import from apps
Rule 3 — shared-types must not import from apps
Rule 4 — Apps must use the package import for shared types
Rule 4 — Apps must use the package import for shared types
Rule 5 — No deep imports from shared-types
Rule 5 — No deep imports from shared-types