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.
Designed and built with AI agents
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.
Inside the tool
The design decisions behind it
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.
How it fits together
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.
- 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.
What it demonstrates
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