Most coding agents begin in the middle.
They receive a task, open a repository, change files, and perhaps run a test. That is useful, but it is not software delivery. The hard part often happened before the first edit: deciding what problem deserves work, checking whether it already exists, resolving ambiguity across repositories, choosing an implementation boundary, and agreeing on what “done” means. More hard parts wait afterward: independent review, failure handling, release authority, deployment, and learning from what broke.
minion_base is my attempt to make that whole path visible and operable. The larger system is a self-hosted software factory for MINION: a request can become a durable proposal, a reviewed implementation specification, an isolated development run, a tested pull request, and eventually a deployment. Agents do much of the mechanical work. People retain the decisions whose cost cannot be recovered by simply rerunning a container.
This is both a working system and a proposal for how it should mature. The lifecycle board, request conversations, two-pass specifications, isolated runs, bounded repair, cross-provider review, pipeline telemetry, durable agent memory, monitor intake, and deployment train exist today. Release authority is no longer one universal rule: high-stakes work remains human-gated, while a narrow maintenance lane can auto-merge documentation, test, and dependency changes only after the self-test, independent review, and GitHub checks are green.
One request leaves a chain of reviewable artifacts
The request agent reads repository context and helps turn an incomplete idea into a testable problem statement.
Accessible diagram transcript
A request conversation becomes a durable proposal, crosses an intent gate, becomes a two-pass reviewed specification, crosses a plan gate, enters an isolated development and test run, receives adversarial review, and reaches a policy gate. Low-stakes maintenance may auto-merge; consequential changes require a person.
Why: prompts are a poor system of record
A prompt can express intent, but it is a weak place to preserve it. It mixes the original need with assumptions introduced during the conversation. It is difficult to compare with old work, awkward to review as a stable artifact, and easy to lose once an agent starts compressing context around implementation details.
The first design decision is therefore not which model writes the code. It is that conversation must produce an artifact before it produces a branch.
The request surface is the creative zone. An agent can read the project map and planning history while a person talks an idea into shape. Before creating anything, it searches existing proposals and specifications for overlaps. Under uncertainty it preserves the new idea and flags a possible duplicate rather than silently collapsing two intentions. The output is a versioned proposal containing the problem in the user's language, motivation, a rough approach, affected repositories, alternatives, risks, and a testable definition of done.
That proposal does not start a run. It enters the first human gate.
The distinction matters. “Approved” means this is worth specifying, not an agent may now change production code. Separating eligibility from execution prevents a status field from becoming an accidental launch button.
How, part one: the plan gets a second author
Once intent is approved, the factory runs a two-pass specification pipeline.
In pass one, a planning agent reads the proposal, the repository instructions, related specifications, and the cross-project impact map. It turns the idea into vertical implementation slices with file-level scope, assumptions, acceptance checks, operational risks, and a definition of done that another process can actually execute.
Pass two starts fresh. The reviewer did not participate in the first pass and does not inherit its hidden reasoning. It inspects the specification against the codebase, corrects it in place, and writes a separate review record. That sidecar matters: the final spec says what should be built, while the review explains which assumptions were challenged and why the plan changed.
The result crosses a second human gate. Approval still means this plan is safe enough to execute, but it now has a concrete consequence: a passed, approved specification can automatically queue its first implementation slice. The gate authorizes a bounded next step rather than relying on someone to notice an idle card.
This extra friction is intentional. Agents are fast enough that generating another answer is cheap. A wrong architectural assumption propagated through several repositories is not.
How, part two: the dashboard is not the factory
The product has several surfaces, and each one owns a different kind of truth.
minion_base is the private control room. It shows request conversations, the Proposal → Spec → Development → Testing → Deployment board, work-type tags, gate actions, live runs, logs, codified practices, and repository health. Its landing page now measures queue pressure, throughput, pass rates, cost and token use by stage, failure categories, auto-queued runs, and recovery requeues. A settings surface maps each provider to low, medium, and high performance tiers. The board still mirrors GitHub and committed proposal/spec indexes; dragging a card would only decorate a lie.
minion_factory is the execution plane. A self-hosted runner accepts an approved artifact or a bounded task, queues it, and launches a sibling agent container. It is not the source of truth for product intent, and it does not own deployment.
GitHub remains the code-review and workflow record. The meta repository remains the planning record. Repository CI/CD remains the release mechanism.
Control, execution, evidence, and release stay separate
FOLLOW THE ARROWSThe private control room exposes request conversations, lifecycle cards, human gates, active runs, logs, and repository status.
Accessible diagram transcript
minion_base is the control surface, the meta repository stores proposals and specifications, minion_factory runs bounded agent containers, GitHub stores code review and workflow state, and repository CI/CD owns deployment. The board reads from those sources rather than replacing them.
This separation also defines the security model. The browser never receives the factory bearer secret. minion_base proxies a small allowlist of factory routes through its authenticated server. A run container receives one model credential and a repository-scoped GitHub token, not the production application's secrets. Repositories join the runner through an allowlist only after their self-test is credible.
The queue is a decision surface, not a to-do list
The latest minion_base work changed my idea of what the control room should optimize. A conventional board answers where is the card? The factory needs to answer harder questions: which revision was reviewed, what decision was made, did that decision actually dispatch work, which evidence is current, and what still requires a person?
Those distinctions now exist in the product. Compact cards no longer carry consequential one-click actions. A decision opens in the detail view, requires an explicit confirmation, and is bound to both the expected lifecycle status and the exact GitHub blob revision the operator reviewed. The server accepts only legal source-to-target transitions and uses a compare-and-swap write, so a stale browser cannot silently overwrite a newer decision. Repeating an already-applied transition is safe.
The result is not collapsed into one optimistic “success.” The UI keeps separate, persistent receipts for approved and queued, approved but queue pending, revision conflict, invalid transition, and failed action. Approval and dispatch are related, but they are not the same fact. If the planning artifact commits but the runner is unavailable, the control room says so and leaves reconciliation to the scheduled sweep.
The board is also becoming more honest about evidence. Status, risk, and integrity now have a shared label-and-symbol language rather than relying on color. Issues open as internal work details with their source, triage state, history, and lineage together. The Testing column shows only a workflow's latest relevant state; an old red run stops masquerading as a current blocker after a newer run passes. CI details can point back to the proposal that caused the pipeline work, and minion_base and minion_factory themselves are now first-class members of the monitored fleet.
The newest performance view makes the same move from activity to evidence. It separates queue depth and wait time from completed throughput; compares passed, failed, errored, and canceled outcomes by phase; shows average and median duration; breaks down model calls, turns, tokens, and available cost data; and keeps review failures, self-test failures, infrastructure errors, auto-queued runs, and recovery requeues visible as different phenomena. A high run count is not automatically a healthy factory.
Two approved minion_base slices were running when I inspected the production ledger on August 18. One is extracting a reusable interaction family for asynchronous decisions and a mobile-safe shell. The other is normalizing every card into a typed WorkDetail model that puts decision → risk → proof → detail → history in that order. Missing evidence and unsupported evidence are meant to remain visibly different; neither may be converted into a reassuring zero or a green state. These are active draft pull requests, not shipped capabilities yet.
The same queue exposed a less flattering lesson. In a single day, several branches accumulated ten or eleven ledger entries after a passed attempt was followed by repeated rebase errors. The requeue endpoint prevents two children from the same failed run, but each child is a new origin, so “once per run” is not yet “once per work lineage.” Recovery can therefore generate motion without new information.
That changes the next improvement. Recovery needs a lineage-wide budget, failure-fingerprint comparison, and a check against the current pull-request and merge state before another container starts. Repeated infrastructure evidence should converge into one visible intervention, not a family tree of equivalent retries. The queue is useful precisely because it made this failure legible.
The model I am building toward keeps five facts separate: the artifact reviewed, the decision recorded, the work dispatched, the evidence returned, and the release performed. Collapsing any two of them makes the interface feel simpler while making the system harder to trust.
What happens inside a development run
An approved specification rides into the container as the plan. The run creates an isolated branch and opens a draft pull request before development is allowed to present itself as complete. The pull request is not the victory condition; it is the durable envelope for the task, stages, commits, test evidence, external reviews, and eventual release decision.
The required development stage can use Claude or Codex. Instead of baking one model name into each workflow, the control room maps providers to low, medium, and high performance tiers. When one provider develops at a given tier, the reviewer is paired with another provider at the same tier. Quota, authentication, rate-limit, or provider outages trigger one cross-provider fallback; exhausting the task's turn budget does not, because that signals task size rather than provider health. The runner still enforces limits outside the prompt: a turn cap, a thirty-minute wall clock, a maximum of five test/fix attempts, and container CPU and memory bounds.
After each development attempt, two gates run.
First, the branch must contain an implementation change. This closes a surprisingly important loophole: an agent that edits nothing can otherwise “pass” because the repository was green before it arrived.
Second, the repository's own self-test must pass. minion_base, for example, composes its design-token lint, Svelte synchronization, type checking, and production build. Another repository can define a different command. The factory does not pretend one global test means the same thing everywhere.
Autonomy escalates only when evidence justifies it
The development harness works against the approved task or specification inside its isolated branch.
Accessible diagram transcript
The agent must produce a real code change before the repository self-test matters. A green test can move the pull request toward review; a red test returns concrete evidence to another bounded attempt. Repeated failure stops the current run, while a separate recovery policy decides whether the same branch retries or escalates.
A failed test feeds its recent output into the next attempt. If two failures repeat identically, or the loop reaches five attempts, the current run stops early. The factory preserves useful commits and the draft pull request instead of discarding partial work.
There is now a second, coarser recovery loop around that run. A failed development run with an open pull request can retry on the same branch, then make one higher-reasoning attempt. After three run-level attempts it files a monitor item for human judgment and stops. Transient failures take a different route: clone operations retry with backoff, surviving containers are re-adopted after a runner restart, and an hourly facilitator may requeue an infrastructure failure once. A canceled run is never resurrected; cancellation is an operator decision.
Recovery also has memory. Specification and development agents can consult a curated Markdown index, a searchable SQLite observation store, and semantic memory. After a failed self-test, the prompt explicitly asks the next attempt to search for the failure signature before changing code. A run may write back a short durable lesson, but routine logs stay out of memory. The point is not to make the context window larger. It is to stop paying for the same mistake twice.
Once the self-test is green, a separate reviewer inspects the final diff against the base branch and repository playbook. It also gathers available Claude and Copilot review findings, judges each under its own responsibility, applies the findings it accepts, records why it dismissed the others, and reruns the self-test after any fixes. Only a real diff, a green test, and a passing review can mark the pull request ready.
Ready means the evidence gates passed. Whether it may merge now depends on the work's policy class.
Authority is a policy, not a universal button
The product lane still has three explicit human decisions:
- Approve the proposal: this problem deserves a plan.
- Approve the specification: this plan is safe enough to execute.
- Merge the pull request: this evidence is sufficient to release higher-stakes work.
The maintenance lane now introduces one deliberate exception. A pull request tagged only docs, test, or deps may be squash-merged by a periodic sweep when the development run passed, cross-provider review passed, the pull request is no longer a draft, and every GitHub check has completed without failure. The sweep merges at most three pull requests per cycle and has an environment kill switch. Any logic, ui, security, data, perf, or infra tag keeps the human merge gate.
That distinction is more useful than either “agents never merge” or “the factory is autonomous.” Authority is granted by an explicit, inspectable policy whose current scope comes from specification tags. Low-stakes work can flow; mixed or consequential work stops. Re-deriving those tags from the actual diff is a planned hardening step. The weekly promotion train still prepares the development-to-production pull request rather than silently promoting the whole fleet.
The factory also watches the factory
Event-driven systems often miss the state that changed while they were offline. The reconciliation loop uses a different idea: inspect the current proposal set and converge it toward a canonical state.
On a schedule, a bounded agent looks for true duplicates, possible revivals of rejected work, and ambiguous overlap. Definite duplicates are preserved as tombstones pointing to the richer proposal rather than deleted. Uncertain matches are routed back to review. Concurrent writers rebase and regenerate derived indexes before pushing, because the request agent, dashboard gates, spec pipeline, and reconciler can all touch the planning record.
The same sweep watches the latest completed workflow on each fleet deployment branch. A red workflow becomes a draft proposal with a bounded, tool-less diagnosis. Runtime monitors can enter through a secret-scoped webhook: fingerprints deduplicate repeated alerts, a flood cap prevents board spam, stale fingerprints can re-file after 24 hours, and external payloads are fenced as untrusted evidence rather than instructions. The failure does not bypass product thinking; it enters the same proposal → spec → development path as a feature request.
That closes the loop. Deployment is not the end of the factory; observed failure becomes new intent.
What exists now, and what is still missing
The current system already spans two private products and the existing repository infrastructure:
- a live lifecycle board across MINION repositories;
- request-agent conversations that can write bounded proposals;
- two-pass specifications with separate review records;
- explicit proposal and specification gates, followed by automatic first-slice queueing for approved specs;
- revision-bound legal transitions with persistent receipts for committed, pending, conflicting, and failed decisions;
- isolated container runs with provider tiers, cross-provider verification, and outage fallback;
- draft pull requests, repository self-tests, bounded repair, same-branch recovery, and adversarial review;
- active-run status and logs joined back onto lifecycle cards;
- three-tier agent memory with failure-triggered recall and selective write-back;
- scheduled proposal reconciliation, fleet-wide CI watch, and guarded runtime-monitor intake;
- phase-level telemetry for outcome mix, average and median duration, queue delay, stage cost/tokens, failure taxonomy, and autonomy;
- policy-scoped auto-merge for docs/test/deps, repository-owned CI/CD, and a human-gated promotion train for consequential releases.
The commits and the production ledger also exposed the next gaps. The board can still show work as active after its implementation has already shipped, so a planned G0 reconciler must reason backward from merged pull requests and deployment evidence. Recovery caps are still run-local rather than lineage-wide. The mobile shell, reusable decision primitives, and summary-first WorkDetail model are in active draft pull requests. Proposed G1–G5 scorecards would grade artifact quality at every boundary, but those scores are not yet enforced. Cost and token telemetry exists; daily and per-run budget gates do not. Monitor intake and CI watch are live, while automated handoff-marker sweeps, merge-deficiency scans, and PostHog wiring remain staged work. Keeping this list explicit matters: a specification is evidence of intent, a running slice is evidence of motion, and neither proves shipment.
The thesis is not “AI writes software now.” It is narrower and more useful:
A software factory becomes trustworthy when every uncertain idea becomes a durable artifact, every loop is bounded by evidence and memory, and release authority is encoded as a narrow, reversible policy rather than implied by the presence of an agent.
minion_base is being built to keep that distinction visible. The factory can move quickly; the control room must still distinguish movement from progress.