Moirai: Orchestrating Thin LLM Agents Without the Bespoke Wiring
How I extracted two LLM agents — Curator and Auditor — into independent repos, then built an orchestrator that lets any of my projects install them with one command.
The first time you wire an LLM agent into a CI pipeline, it's a workflow file. The second time, it's a workflow file plus a config plus a prompt — almost the same shape as the first but you copy-paste and tweak. By the fourth or fifth, you have five subtly different setups, none of them improvements over the others, and any change to the agent's behaviour means editing five places.
That's roughly where I was last week. I had two LLM agents living inside monospace.studio — Curator, a nightly scanner that files GitHub issues for cleanup candidates, and Auditor, a PR-scoped reviewer that surfaces coherence problems into my session inbox. Both worked. Neither was reusable. The prompts, the config, the workflow wiring, the secrets handling — all entangled with this one repo.
So I split them. And I built the thing that lets them plug in cleanly.
What Moirai Is
Moirai (named for the Greek fates — Clotho spins the thread, Lachesis measures, Atropos cuts) is an orchestrator for thin LLM agents. It's not an agent host. It's the glue.
Three layers, separated cleanly:
| Layer | What it is | Examples |
|---|---|---|
| Agent repo | One agent, one purpose. AGENT.md (persona), PROMPT.md (instructions), schema.json (config shape), defaults.yml (sane defaults). No workflows, no config values, no host-specific wiring. | derrybirkett/curator, derrybirkett/auditor |
| Moirai | Registry, protocol spec, host adapters, installer. The substrate that lets thin agents work the same way everywhere. | derrybirkett/moirai |
| Consuming repo | Submodules Moirai. Per agent, has .github/agents/<name>/config.yml (validated against the agent's schema) + a workflow per trigger. | monospace.studio, future adopters |
The core idea is composition over inheritance. Each agent is independent and versionable. A consuming repo mounts the ones it needs. When an agent improves — sharper prompt, better scope detection, smarter dedup — every consumer inherits the improvement on a single submodule bump.
The agent definition is the compounding asset. Per-repo tuning is local and disposable.
Installing an Agent
In the consuming repo:
git submodule add https://github.com/derrybirkett/moirai .moirai
.moirai/bin/install curator
That single install command does four things:
- Reads Moirai's
registry.ymlto find the agent and its pinned tag. - Submodules the agent at that tag under
.agents/curator/. - Scaffolds
.github/agents/curator/config.ymlfrom the agent'sdefaults.yml(the consumer overrides; unset fields fall back). - Renders
.github/workflows/curator.ymlfrom the chosen adapter's template, with permissions and tool access derived from the declared sink.
Edit the config to taste, commit four files, push. The agent runs on its trigger.
The Walking Skeleton
I built Moirai bottom-up. Top-down spec-first risks over-design — you describe a protocol that solves problems that don't exist. So I extracted one agent end-to-end, built the thinnest possible orchestrator around it, and only then started writing the spec.
Step 1 — Curator. Lifted out of a submodule and into its own repo. Adapted the prompt to read its config from $AGENT_CONFIG_PATH (host-injected) instead of a hard-coded path. Replaced the literal config.yml with defaults.yml + a JSON Schema. Two days ago this was Moirai v0.1.0.
Step 2 — orchestrator. Wrote protocol/SPEC.md, registry.yml, the bash installer, the GitHub Actions adapter with a parameterised workflow template.
Step 3 — consume. Refactored monospace.studio to install Curator via Moirai. First real test of the installer. Found one bug immediately — bin/install tried to place agent submodules inside the Moirai submodule, which git forbids. Fixed (agents now live at .agents/<name>/, sibling to .moirai/). Curator filed five real GitHub issues that night.
Step 4 — the moment of truth. Extracted Auditor as the second agent. This is the test of whether the protocol I wrote for Curator actually accommodates a different shape. Auditor's trigger is pull_request, not schedule. Its sink is inbox (writes to a markdown file the host commits back), not issues. Its envelope needs additional environment variables — PR_NUMBER, PR_BASE_SHA, PR_HEAD_SHA.
The protocol mostly held. The bits that needed adding — conditional template blocks, the inbox commit-back contract, a fork-safety skip — shipped cleanly as Moirai v0.2.0 without rewriting Curator's path. Auditor ran on its own PR and the auditor-bot pushed back the audit block. End-to-end validated across two agents with fundamentally different shapes.
That's the whole loop: build the thinnest possible version of the system, prove it works, then extract the next thing and let the friction tell you what to fix.
What You Get For Free
Beyond the running agent, Moirai installs a set of guarantees:
A typed sink interface. Every agent declares what it writes to: issues | inbox | summary | pr-comment. The installer derives the right GitHub Actions permissions from the sink. Curator gets issues: write; Auditor gets contents: write (for the inbox commit-back) + pull-requests: read. The consumer doesn't have to think about it.
The envelope. Every agent receives the same environment-variable contract: AGENT_NAME, AGENT_CONFIG_PATH, AGENT_REPO_DIR, TODAY. PR-triggered agents additionally receive PR_NUMBER, PR_BASE_SHA, PR_HEAD_SHA. Agents read their config from a path the host injects; they never assume a location.
Stable schemas for inter-agent reads. A future meta-agent — call it Conductor — can read across [curator] <category>: issue titles and ## Audit — YYYY-MM-DD (PR #N) blocks in notes/inbox.md and propose cross-cutting action. Thin agents don't have to know about each other; the substrate enables emergence.
One-command install. Pinning a new agent in registry.yml is the entire "add to catalog" step. From the consumer's side, bin/install <name> is the entire "adopt" step.
Version-locked behaviour. Both agents and Moirai itself are tagged. A consumer pins .moirai and .agents/<name> to specific tags. Changes are opt-in via submodule bumps, never surprise.
What You Still Have To Build
Moirai is honest about its scope.
- The agents themselves. Moirai doesn't write prompts. Each agent is its own repo with its own prompt, scopes, and config schema. The agent's quality is entirely the agent's concern.
- Cross-LLM portability. Today there's exactly one adapter, for Claude Code via
anthropics/claude-code-action@v1on GitHub Actions. The architecture is designed so an OpenAI Assistants adapter or a local CLI runner could slot in without changing any agent. I haven't built one yet. - The meta-agent. The interop pattern is there in the protocol — typed sinks, stable schemas — but no agent currently reads across sinks. That's the next horizon.
Is It For You?
Moirai is opinionated. It assumes:
- You're shipping LLM-driven automation across multiple repos.
- You'd rather decompose a workflow into thin specialised agents than build one monolithic "do-everything" agent.
- You're willing to put up with a small protocol spec in exchange for not maintaining five bespoke workflow files.
If you have one repo and one agent, Moirai is overhead. If you have five repos that all want the same scanner running, or one repo that wants Curator and Auditor and (next) Advisor and a chained Conductor reading their outputs, the protocol is leverage.
The payoff compounds with both number of consuming repos and number of agents in the catalog. Add a new repo, install three agents in 30 seconds. Improve Curator's dedup logic, every consuming repo benefits on the next pointer bump.
What's Next
Moirai is public from day one: github.com/derrybirkett/moirai, v0.2.0 tagged. The two registered agents are at github.com/derrybirkett/curator and github.com/derrybirkett/auditor.
The immediate roadmap:
- A third agent — Advisor, currently still in-repo at
monospace.studio, will graduate to its own repo the moment a second project wants it. (The graduation rule is concrete: an agent moves to its own repo when a second consumer wants it. Until then it stays local.) - A second consumer — install Moirai in one of the standalone repos in my Delta Suite. The second consumer is where the real bugs surface.
- A meta-agent — read across
issuesandinboxsinks, propose cross-cutting action. The thin-agents-compound payoff.
The framework reveals itself through the agents.