Agent orchestration · self-hosted · MIT

Issue in.Reviewed pull request out.

embry0 runs on your own host. Label an issue and a triage agent plans the work, a developer agent writes the code, a reviewer agent gates it and, when the change needs it, a QA agent checks it in a real browser. Then embry0 opens the pull request.

example runissue #142 · labelled embry0
  1. triageplan accepted · confidence 0.91
  2. developerbranch pushed
  3. reviewerchanges requested · 2 findings
  4. developerfindings fixed · branch pushed
  5. reviewerapproved
  6. verifyno new test failures
  7. qa6/6 criteria passed in a browser
  8. embry0pull request #143 opened
ready for your review

From a labelled issue to a pull request.

Triage, developer, reviewer, verify and QA are nodes in a LangGraph state graph, checkpointed so a job can pause to ask you and resume when you answer. The triage, developer and reviewer agents share the job's sandbox; QA gets a sandbox for each app it checks.

changesrequestedfailuresummaryIssueTriageDeveloperReviewerVerifyQAPull request
QA, dashed, runs only when the change needs it.
TriageReads the issue, scores its confidence, splits oversized work and configures the job: model tier, validator mode, sandbox profile. When it is not confident, it asks you first: on the dashboard, in Telegram or as a comment on the issue.Runs in: the job's sandbox
DeveloperWrites the code on its own branch, runs your checks, commits and pushes. It cannot open a pull request.Runs in: the job's sandbox
ReviewerReads the diff against the issue. Changes requested send the work back to the developer with findings; approval moves it on.Runs in: the job's sandbox
VerifyNo agent and no model. embry0 runs the repository's configured test commands on the base commit and on the branch, and records new failures. With VERIFICATION_MODE=on, a new failure ends the job.Runs in: the job's sandbox
QAWhen the change needs it and the repository's QA config can boot the app, a QA agent starts the app's compose stack in Docker-in-Docker and drives a real browser against the issue's acceptance criteria. A failure goes back to triage with a failure summary.Runs in: a sandbox per app
Pull requestembry0 opens it from the pushed branch. A job that fails after pushing its branch still gets one, labelled human-merge-only, with the reason it stopped.Runs in: the orchestrator

While it runs, the dashboard streams the job over WebSocket: agent reasoning, tool calls, cost per step and the pipeline graph.

Beyond one issue at a time.

OrganizationsAdd a GitHub organization or user, or a GitLab group, with the credential embry0 acts with there. Discovery reads every repository under it and lists what embry0 still needs to maintain each one; register, webhook, onboard and watch run from that list, and each can be previewed as a dry run. Nothing changes for a repository until a person acts.Unreleased Rediscovery on a schedule, which proposes deactivating a repository that has gone and never deactivates it on its own.Organizations
Design standardsHold the repositories under an owner to its design standard: the token roles, type scale and component rules, filled with the owner's own colours and fonts, and versioned. Each repository has a mode, off by default. A read-only design audit measures a repository's frontend against the standard and scores it from 0 to 100, the same score for the same commit.Unreleased
Specialist agentsEight read-only agents that each return one report on a repository: kintsugi (a ledger of its cracks), gardener (one piece of dead code, stale doc or unused dependency that can go with no change in behaviour), interrogator (a four-angle review of a branch or pull request), why and how (answers from its history and code), blast-radius (what a change could break, and the one fact it is safe because of, proven by running code or marked unproven), comment-sicko (the comments a diff adds) and design-auditor (the design audit). Their tools are Read, Glob, Grep and Bash; they edit nothing and open no pull request.Unreleased
Log watcherOff by default. It reads your stack's error lines from Loki, has an agent analyse them, and files a draft ticket in Linear or GitHub Issues with the evidence, the suspected cause and a suggested next step. Adding the trigger label accepts it and starts a job. Each finding is a healing case, tracked from detection through merge and deploy to a verdict on whether it healed.Self-watching
Merge approvalsDry run by default. For the repositories you enable, embry0 asks in the chat you choose whether to merge a pull request it opened, with a recommendation from fixed rules, never a model's opinion. Your answer, relayed through the MCP merge_decide tool, is checked again (the head unchanged, CI green, verification not blocking, GitHub mergeable) before embry0 squash-merges.Merge approvals
MCP serverembry0's API as MCP tools: issues, jobs, agents, pipeline templates, logs, the watcher, healing cases, merge approvals, environment variables, organizations, hosts, repositories, QA configs and credentials. Run it over stdio (embry0-mcp) or use the stack's hosted HTTP endpoint, which passes each caller's API key through. Destructive tools refuse to act without confirm=true.MCP server
ProvidersAnthropic (a Claude subscription token or an API key) and xAI (an API key or a subscription). Each agent runs on its definition's model unless a default model, a template step or the job names another; the model's name picks the provider, and models can be switched off one by one.Providers

Unreleased: running in the maintainers' own deployment of embry0, not in the public repository.

What the sandbox holds, and what it does not.

What holds

A container per job
Every job runs in its own container inside Docker-in-Docker, as a non-root user, with cap-drop ALL and no-new-privileges, which a sandbox profile cannot change. The job's triage, developer and reviewer agents share that container; QA checks each affected app in a sandbox of its own. Each is destroyed when its work ends.
Forge tokens stay out
Git and forge-API proxies add your GitHub or GitLab token on the way out, for the job's repository only, and accept a push only to the job's branch. Each sandbox has its own enrollment with them. The agent can push without ever reading the token.
Private networks are out of reach
Traffic to private, carrier-grade NAT and link-local addresses is dropped, which keeps a sandbox off your LAN, the stack's own services, cloud metadata and other sandboxes. The exceptions are embry0's own proxies and the private targets a sandbox profile declares; an operator can declare one on your LAN.
Cloned only inside the sandbox
Your repository is cloned only inside the sandbox and deleted with it, except the QA caches listed under “Some code is kept”; the orchestrator never checks it out on the host.

What does not hold

The LLM credential is inside
The agent's LLM credential (a Claude subscription token, an Anthropic API key or an xAI API key) and the global and per-repository environment variables, secrets included, are in the sandbox's environment, so any code a job runs can read them. An xAI subscription token is the exception: it stays in a proxy. Use a dedicated LLM account with a spending limit.
Internet by default
The default sandbox profile is on the public internet, because the Claude CLI calls its API from inside the sandbox. To seal a sandbox, give the job a profile without sandbox-internet: it then reaches only embry0's proxies, and a Claude agent cannot reach its API from there.
The command denylist is not a boundary
41 regular expressions refuse matching Bash commands, after Unicode NFKC normalization, before the command runs. They catch accidents and naive attempts. The denylist is defence in depth, not a boundary: it reads command text, so a program the agent writes and then runs is not checked.
Docker access is root
A repository you grant Docker access controls the daemon that runs every proxy and every other sandbox, and that daemon runs privileged. Grant it only to code you would run as root on the host.
Operators can read secrets
An operator-tier key or session can run commands in a sandbox, through a QA boot command or the issue text that steers the agent, so it can read the LLM credential and the repository's secrets. Give operator access only to people you would trust with those.
A shared kernel
A sandbox is a container on the host's kernel. A kernel escape is a host compromise, and so, under the default runtime, is a container-runtime escape.
Some code is kept
The job log, in your own Postgres, keeps each tool call's input, such as the code agents wrote and edited and the commands they ran (up to 64 KiB per string in that input), and each tool result, such as what they read (up to 4,000 characters). Each agent's saved session, in the same Postgres, keeps its conversation so the job can resume it. A pre-built QA image keeps a checkout in the stack's registry. A QA cache volume set to per-repo keeps a checkout on the host between jobs. None of these expire. A retention setting for job logs is being added.

SECURITY.md in the repository is the full threat model: what holds, and a list of what does not. Read that list before you point embry0 at a repository. What does not hold

Autonomous, not unaccountable.

Budgets
Per-job, daily and monthly caps. The daily and monthly caps refuse new jobs. The per-job cap is checked after each agent turn and never cuts a turn short: hard mode fails the job at that check, and the default soft mode lets the current step finish, then pauses the job and asks you. A job can end above its cap.
Access
Auth0 SSO, per-user and service API keys with scoped tiers, session control.
Audit
An audit log API with a retention sweep. Admins see every row, other callers the rows they wrote.
Repos
A central registry: per-repo QA config, environment secrets, install commands, sandbox profiles.

It plugs into where the work already lives.

GitHub
Webhook-triggered or dispatched by hand. Issues in, pull requests out, questions asked as issue comments when the agent needs you.
GitLab
Webhook triggers on issue labels, on gitlab.com or a self-managed host; merge requests opened; the same credential proxies and sandbox clone as GitHub. Covered by the test suite, not run against a live GitLab project; some dashboard screens refuse subgroup repositories.
Linear
Label an issue “embry0” and a job dispatches against the mapped repo. The outcome and the agent's decision trail post back to the ticket.
Telegram
Human-in-the-loop, wherever you are. When an agent pauses to ask, answer on the dashboard, in Telegram or in a GitHub issue comment, and the pipeline resumes.

Run it on your own host.

Host
x86_64 Linux
Software
Docker with the Compose plugin, and Python 3.12 or newer
Memory
about 24 GB for the stack, and up to 8 GB more for each job's sandbox
Disk
about 20 GB for a first install, with its images and build cache

The stack runs Docker-in-Docker in a privileged container.

shell
git clone https://github.com/sudoTomas/embry0.gitcd embry0cp .env.example .env# in .env: API_KEY, PROXY_ADMIN_TOKEN, ENVIRONMENT_SECRET_KEY,# POSTGRES_PASSWORD and MINIO_ROOT_PASSWORD (openssl rand -hex 32 each),# GITHUB_TOKEN, and one Claude credential (the README shows both kinds)python3 -m venv .venv && . .venv/bin/activatepip install -e .embry0 start

Then open http://localhost:8200, sign in with your API_KEY and create an issue. To start jobs straight from GitHub, set up webhooks.

The quick start in the README

What engineers ask before they trust it.

What happens when the triage agent is not confident?

It does not guess. Low-confidence issues trigger a question to a human: on the dashboard, in Telegram, or as a comment on the issue. The job checkpoints and waits. When you answer on the dashboard, in Telegram or in a GitHub issue comment, it resumes where it paused. Oversized issues get split instead of botched.

Does embry0 keep my code?

There is no embry0 service to send it to: you run embry0 on your own host, and the agents send what they read to your LLM provider. Your repository is cloned into the job's sandbox and deleted with it. The exceptions keep code with no expiry: the job log and the agents' saved sessions in your own Postgres keep the code agents wrote, edited and read, a pre-built QA image keeps a checkout in the stack's registry, and a QA cache volume set to per-repo keeps one on the host. A retention setting for job logs is being added.

Can the agent leak my tokens?

Your forge token, no: git and forge-API calls leave the sandbox through proxies that add the token on the way out, scoped to the job's repository, so the agent can push its branch without reading the token. Your LLM credential, yes: it is in the sandbox's environment and public egress is open, so any code the job runs can read it and send it out. The same goes for the global and per-repository environment variables, secrets included. SECURITY.md lists this as accepted: use a dedicated LLM account with a spending limit, and rotate it if you suspect misuse.

What does the QA gate actually run?

Your app. The QA agent boots the repo's compose stack inside Docker-in-Docker, waits for it to come up, and drives headless Chromium via Playwright against the acceptance criteria from the issue. A failure goes back to triage with a failure summary. The evidence (screenshots, console, network, and container logs) stays in embry0 on the job's dashboard page, and the verdict with a per-app breakdown is posted as a comment on the GitHub or GitLab issue. A Linear ticket gets the job's outcome and the pull request link.

What is it built on?

LangGraph for orchestration: a checkpointed state graph, so a job can pause to ask you and resume. The Claude Agent SDK runs the agents, FastAPI serves the API, React draws the dashboard, PostgreSQL holds state, MinIO holds QA artifacts and WebSocket carries the live stream.

Who reviews the agent's work?

First a reviewer agent, in a loop the developer must satisfy. Then verify compares your configured tests on the base and the branch, and, when the change needs it, the QA gate checks it in a browser. Then you. embry0 merges nothing unless you turn on merge approvals and answer yes.

Is there a hosted version?

No. You run embry0 on your own host, from the MIT-licensed source on GitHub.

What does a runaway job cost me?

Its cap, plus the work in progress when it crosses it. The per-job cap is checked after every agent turn, and a turn in progress is never cut short. In hard mode the job fails at that check; in the default soft mode the current step finishes, then the job pauses and asks you. Daily and monthly caps refuse new jobs. Costs stream live on the dashboard per step, so a job that is spending strangely is visible while it runs, not on the invoice.

the loop

Give it an issue.

Label an issue. Get a reviewed pull request, checked in a browser when the change needs it. That is the whole loop.

Questions and bugs go to the issues