How it works
The roles, where the agents may act on their own, how providers plug in, how it deploys, and what it does not do yet. Each claim links to the file or command behind it.
Four roles. One writes code.
The executor writes the diff. The reviewer, the tech-lead and the product role judge it, handle stalls, and decide what enters the queue. Which engine runs each role is configuration, per project and per role.
Executor
Works the ticket inside a sandbox that has already built the project, against the project's own gates. Runs on Claude Code, Codex, Kimi or OpenCode. The choice is a registry value.
Reviewer
Gets the specification, the diff and the gate results, and not the author's reasoning. Returns a decision, a score and findings tied to the acceptance criteria. It can run on a different harness and model than the executor.
Tech-lead
Called when a job stalls. Clones the repo, reads the failure against the code, classifies it by what would fix it, resolves what it safely can, and escalates the rest to a person.
Product role
Talks to the requester, reads the board, and proposes tickets, each citing its requirement. Reading the codebase yields observations, not requirements. Only a person accepting one turns it into a commitment.
The panel is the reference surface and ships with the core. A chat channel such as Slack is an add-on package.
Where it acts alone, and where it stops
The tech-lead classifies each failure by what would fix it. The class decides who acts and how many times.
GitHub rate-limited the API, the most self-healing failure there is. The factory parked the ticket, held the floor for eighteen hours, ran nothing else and notified nobody. The diagnosis that should have written the alert could not run either. The classification below came out of that.
| Class | Example | Who resolves it |
|---|---|---|
transient | API throttling, a network blip | the factory: waits out the window, retries |
credential | a token revoked or exhausted | the factory: rotates, escalates only if the whole pool is bad |
environment | a missing permission, a broken image | a named person, with the specific thing to change |
code | the change is wrong | an engineer, with the diagnosis |
requirement | the ticket is ambiguous or contradicts itself | the product role |
unknown | it cannot tell | a person, told that it cannot tell |
Budgets are per failure class
Waiting is free. A throttled call retried after its window costs no tokens, so that budget is generous. Re-running an agent costs money, so that budget is small.
A remedy that has failed twice is not tried a third time. unknown
never degrades to retry: repeating a failure nobody understands only spends money.
What it never does
- Resume work a person already skipped.
- Retry anything classified
unknown,codeorrequirement. - Exceed its budget. An exhausted budget is itself an escalation.
- Touch production. Releases need a human login, always.
Anyone in the project's channel can ask for status. No gate.
resume and skip need a user on the project's allowlist. The allowlist is empty by default.
Never actionable from chat, not even for an admin. An unauthorized attempt is refused and logged.
Classification will sometimes be wrong, so the bias is toward escalation. A wrong retry costs money and delays a real escalation. A wrong escalation costs a person a minute. Every action records what it did and what it tries next.
What is different from an agent with repo access
The box is proven before any agent runs
On the container sandbox, the project's own image, setup and gates run once with no agent before a ticket is picked up. A box that cannot build the project is found before tokens are spent. The worktree sandbox has no image to prove, so the gate does not apply there.
No silent stalls
A stall either self-heals within its budget or puts a question on the card, with
wait / merge / skip as options a person picks
and the factory executes. Tests treat going quiet as a bug.
Failure is never an answer
Every adapter separates an unreadable result from an empty one.
None = I could not read. [] = I read it, and there is nothing.The review is a second agent
It can run on a different engine and never sees the author's reasoning. It has rejected a diff that met its criteria but landed in the wrong repository, before any person looked at it.
Merging is policy
merge_policy: human opens the PR and waits. auto merges
only when gates are green, the review did not reject, and no high-risk component
was touched. A project that declares no gates is held, not passed.
It never deploys
It merges or tags, then watches your pipeline. Deployment stays in your CI with your credentials. Production promotion needs a human login, always.
Three claims you can check
A provider is a registry entry
Tracker, board, forge, CI, harness and sandbox each dispatch through a registry, and the axes are independent: Jira for tickets and GitHub for code is two lines of configuration. An unknown provider fails at startup and names what is supported. It never falls back to a default. docs/STATUS.md lists every axis and what implements it.
| Axis | Providers today |
|---|---|
| Tracker | github · jira · azure_devops |
| Board | github · jira · azure_devops |
| Forge | github · azure_devops |
| CI / environment | github_actions · azure_pipelines |
| Harness | claude_code · codex · kimi · opencode |
| Sandbox | worktree · container · fargate (add-on: openfactory-aws) |
Read from openfactory/adapters/tracker/registry.py and its siblings.
Verified end to end. GitHub: ticket to merged PR, with a live client in production. Jira: requirement to PR to merge, with the client's GitHub Actions deploy observed. Azure DevOps: work item to reviewed PR in Azure Repos with no GitHub involved, including a three-repository product where the card names its own repo.
Harness and model are per project and per role
Four coding agents behind one contract, chosen in the registry. The reviewer can run on a different engine than the executor.
harness: opencode model: executor: eu.anthropic.claude-sonnet-5 reviewer: eu.anthropic.claude-haiku-4-5 # a cheaper, independent second opinion
Model routes are configuration too: Anthropic direct, Amazon Bedrock, Vertex, or a corporate gateway. Keeping everything inside your own AWS account is one config value. This platform's own tickets have been written by Claude Code and by OpenCode, both over Bedrock.
Fewer tokens per ticket
A module map of the codebase goes into the agent's context, so it reads less to find the same code. The numbers and their caveats are on the home page.
Runs on your machines
No cloud SDK is a core dependency. boto3 is optional, every cloud import
is function-level, and each observability axis has a cloud-free option. A test blocks
every cloud SDK in a subprocess and imports the core to prove it.
AWS and Azure are add-on packages. Without the Fargate add-on, jobs run in local containers. The only vendor coupling is where your data already lives: your tracker and your pipeline.
docker compose up
pytest tests/test_the_core_does_not_need_a_cloud.py
Adding a provider
A new provider is one module and one registry row. A published conformance suite checks it against the adapter contract, and every adapter is runtime-checked against its Protocol, so a partial implementation fails at load rather than in production.
The code is Apache-2.0 and may be forked freely. The OpenFactory name is reserved for builds that pass the conformance suite.
openfactory conformance-adapter tracker my_pkg.my_tracker:MyTracker openfactory conformance <project>
Tests and decisions
pytest -q passes in fixed and randomised order; the count and the commit it
was measured at are in
docs/STATUS.md ·
every architecture decision is recorded in
docs/adr/ ·
providers verified live on GitHub, Jira and Azure DevOps · Apache-2.0.
What it does not do yet
- One deployment serves one GitHub organisation. A GitHub App installation belongs to one org and the forge credential is process-global. Registering a project in a second org is refused by name.
- The knowledge map reads Python, TypeScript/JavaScript and C#. Other stacks get a structural map or none. The map reports which extensions it skipped.
- No GitLab or Bitbucket. Adding one is a module and a registry row. Nobody has written it yet.