← Back to home CASE STUDY

Agent Orchestration

A deterministic, self-hosted approach to agentic engineering.

A self-hosted control plane that turns issues into merged pull requests. It runs AI coding agents in isolated containers, has a separate agent review each change, then ships the result through an explicit, recoverable lifecycle.

TypeScriptNode.js + FastifyReact 19 + ViteTailwindSQLite (WAL)Docker / dockerodeMCPOAuth 2.1Forgejo

Self-hosted · source private · solo project

I built Agent Orchestration by directing AI coding agents through its architecture, state machine, container runtime, and OAuth-secured MCP server, then used the finished system to keep improving itself. It is a platform for running AI agents that was, in large part, built by running AI agents.

I built it to develop my own agentic-engineering skills and to provide a reusable, self-hosted foundation for future projects. The work involved more than writing code. It required decomposing an ambitious system into agent-sized tasks, defining the guardrails that let agents operate safely, reviewing their output critically, and delivering production-grade infrastructure on that basis.

Orchestrator dashboard
The control plane: live agents, the queue, host resource usage, and recent completions, updated in real time over WebSockets.
Task detail view
Per-task observability: a lifecycle timeline, streamed agent output, and the full attempt history with the exact harness and model used each round.

A deterministic task state machine

Every task flows queued → preparing → in-progress → in-review → approved → merged, with bounded rework cycles. Agents fail, retry, and crash — so the lifecycle is explicit, recoverable, and auditable, not a fire-and-forget script.

Hard container isolation

Each task runs in a fresh, ephemeral Docker container as a non-root user, with git credentials scoped so agents can only push to agent/* branches. Branch protection keeps machine output off main. Blast-radius thinking from the ground up.

Agents that review agents

A separate review agent gates every pull request. Its feedback becomes the next attempt's prompt, and the work slot is held through rework so nothing is lost — implement, review, rework, merge, all autonomously.

Harness- and provider-agnostic

Swap Claude Code, the Claude Agent SDK, OpenCode, or pi; route to Anthropic, OpenAI, Gemini, Mistral, DeepSeek, OpenRouter, or a local Ollama. Reusable agent profiles pair a harness with a model and timeout, resolved per task, per repo, or globally.

One command for developers (MCP)

The orchestrator exposes an OAuth 2.1-secured Model Context Protocol server and ships as a Claude Code plugin, so a teammate can queue a task with a slash command — no git credentials, no Docker, no friction.

Built to survive the real world

Crash recovery reconciles actual container and branch state on boot, the scheduler pools work by memory and CPU, providers carry concurrency limits, and every state change is logged as an issue comment with live output streamed over WebSockets.

The system is built from a few logical components with clear, separate responsibilities. A control plane coordinates the work, a Git server holds the code and the record of what happened, and disposable sandboxes run the agents themselves. They communicate only over standard protocols, which keeps the boundaries between them explicit.

Agent Orchestration architecture Access surfaces talk to a control plane, which coordinates a Git server and ephemeral agent sandboxes. Agents reach the Git server directly over Git with a scoped token. REST · WebSockets · MCP REST · webhooks launches containers git · scoped token Access surfaces Dashboard · MCP plugin Control plane orchestrator · scheduler Git server Forgejo · source of truth Agent sandboxes dev agent · review agent
The control plane is the only component that writes to the Git server. Agents run in isolated sandboxes and reach the Git server directly over Git with a scoped token.
Control plane
A single Node and Fastify service owns the workflow: it runs the scheduling loop, launches and reaps agent sandboxes, talks to the Git server, persists state in an embedded database, serves the dashboard, and exposes the task-creation API. It is the only component permitted to write to the Git server, so opening pull requests, merging, relabelling, and commenting all flow through one accountable actor.
Git server
A self-hosted Git, issues, and pull-request server (Forgejo) holds the code and acts as the system's source of truth. Each task's state lives as a label on its issue, and every transition is written back as an issue comment, giving a human-readable audit trail for work that otherwise runs unattended.
Ephemeral agent sandboxes
Each task runs in a fresh, throwaway container: a dev agent implements the change and a separate review agent grades it. Agents hold only a narrowly scoped Git credential, so the container, rather than the network, is the isolation boundary, and a container exiting is the authoritative signal that an agent has finished.
Access surfaces
A real-time dashboard streams task state and live agent logs over REST and WebSockets, and an optional OAuth 2.1-secured MCP server lets developers queue tasks from any editor through a plugin, with no Git credentials or local setup of their own.

Communication runs over ordinary network protocols: the control plane and the Git server exchange REST calls and webhooks, while agents reach the Git server over plain Git with a scoped token. Because the components are decoupled this way, the architecture makes no assumption about where they run. The whole system can run on a single machine, or the Git server, the control plane, and the pool of agent sandboxes can be separated across several, with no change to the design.

The project demonstrates a working understanding of agentic engineering across the full stack. It combines distributed-systems thinking (an explicit state machine, crash recovery, and resource-aware scheduling), security (container isolation, OAuth 2.1, and scoped credentials), and product design (a real-time dashboard and a one-command developer plugin). Its harness- and provider-agnostic design keeps the platform portable and avoids vendor lock-in, and the system was delivered by directing AI agents rather than writing every line by hand.

← Back to all projects