3rd/docker/ in the repository
is a community-maintained, unofficial wrapper: one Linux container
that runs the unmodified official deployment — systemd as PID 1 with
a real user manager, the official systemd/[email protected] +
[email protected] user units, the editable CLI install and the idempotent
orbi setup. It is not a second deployment model: on a Linux host
with a systemd user session, always prefer the official path
(see Getting started) — pick one of the two, never
both for the same task pool.
When to use it
- The host has no user systemd session (a NAS, a container platform, a restricted cloud box) but can run Docker.
- You want the runner isolated from the host user session.
Quick start
Pull the published image, then start the runner with onedocker run.
Both registries carry the same tags: latest and the release number
without the v prefix (e.g. 0.5.17).
docker run reaches a real delivery: the GitHub token, the task
pool and the model provider all come from environment variables, and the
entrypoint turns them into the deploy-home env file, the generated
orbi.toml and the generated pi-providers.json on first start
(existing files are never overwritten). Substitute the three quoted
values — token, repo, key; the DeepSeek endpoint is an example, any
OpenAI-compatible endpoint works through the same four variables
(ORBI_PI_PROVIDER, ORBI_PI_MODEL, ORBI_PI_BASE_URL,
ORBI_PI_API_KEY). If you pulled from Docker Hub, use the
docker.io/orbibuild/orbi:latest image reference instead.
docker run, no compose (the runner is a single service). --cgroupns=host plus the read-write /sys/fs/cgroup bind is what
lets systemd run as PID 1 inside the container — without them
/init.scope creation fails under the default private cgroup
namespace (verified; no --privileged needed). All state (the orbi
checkout, the config, the runtime state, the delivery checkout and its
worktrees) lives in the two volumes, so a container rebuild keeps
everything and the idempotent setup re-converges on the next start.
How configuration reaches the runner
The full contract — the generated config, daily operations, and the
failure/repair table — lives in
3rd/docker/README.md.
First delivery
With the runner up, deliver a real task:- In the task pool repo, open an Issue stating ONE runtime outcome in
one of the two shapes: a fix (
when X, should Y, actually Z) or a change (when X, the user should be able to Y; today they cannot because Z). - Add the
ai-readylabel (the first start created the twelve platform labels). - Follow the tick log:
ai-ready → ai-in-progress → ai-pr-opened and a PR opens; it merges
(ai-merged) after the independent review round. No docker exec
configuration step is needed anywhere in this path — one that is
required is a docs or entrypoint defect.
Orbi quick guide
The delivery vocabulary in one place; each link goes to the full reference instead of duplicating it.- The task — an Issue stating ONE runtime outcome in one of the
two shapes: a fix (
when X, should Y, actually Z) or a change (when X, the user should be able to Y; today they cannot because Z), plus a short acceptance list: the user journey as precondition → command/configuration → the success the user sees → the failure path with its repair. - The labels —
ai-readyis the execution switch: the runner only picks up labelled Issues (pickup order:p0first, thenbug, then plain). A claimed Issue walksai-in-progress→ai-pr-opened→ai-merged(terminal; the PR body’sFixes #Ncloses the Issue) orai-fix-needed(the next review round fixes the finding);ai-blocked(terminal) needs a human decision.ai-epicmarks a coordination-only Issue the runner never claims, andai-releasemarks a release task (below). The runner manages the delivery states;ai-ready,ai-epic,ai-release,p0andbugare yours to add and remove. - Watching — the run keeps exactly one progress comment on the
Issue, updated in place at every milestone, and the tick log streams
through the
journalctlcommand above. - What to expect — within two ticks the branch and PR exist
(
Fixes #Nin the body), an independent review session runs (at most 5 rounds), and the merge lands exactly the reviewed head — GitHub then closes the Issue. - Releases — a release is its own Issue labelled
ai-ready+ai-releasewhose body declares a## Releaseblock:version,base_branch, and ascope(a list of#Nitems) orscope_from_milestone. The Runner’s release state machine freezes the base, waits for green CI, bumps the version, tags, publishes the GitHub Release and closes the matching Milestone — no PR; any failure stops atai-blockedfor a human decision.
Operations
In-container commands run as
-u orbi (the user the runner runs as);
systemctl --user / journalctl --user need the user session bus,
which docker exec does not carry automatically — hence
-e XDG_RUNTIME_DIR=/run/user/1000. The orbi CLI installs into the
orbi user’s ~/.local/bin, which is not on the docker exec PATH —
hence the bash -c wrapper (docker exec sets HOME for the -u user).
Upgrading: docker pull the newer tag and recreate the container with
the same volumes and variables — state survives in the volumes and the
entrypoint plus orbi setup re-converge.
Build from source
When you need to change the wrapper itself (the entrypoint, the setup oneshot, the Dockerfile), build the image from a repository checkout instead of pulling:docker run as in the Quick start with orbi-docker
as the image name. The image contains no credentials — configuration is
injected per the table above at docker run time.
Advanced: several providers
The Quick start configures ONE provider from environment variables. To serve several (e.g. deepseek plus groq):- Pass the extra keys at
docker runtime viaORBI_ENV_<NAME>(repeatable):-e ORBI_ENV_GROQ_API_KEY="gsk-xxx"lands in/orbi/.orbi/envasGROQ_API_KEY. - Edit
/orbi/.orbi/pi-providers.json— the entrypoint generated it with one provider and never overwrites an existing file — and add the other providers, eachapiKeyreferencing its env variable ("$GROQ_API_KEY"). - Point
pi_provider/pi_modelin/orbi/orbi.tomlat the provider and model to use, then restart the container:docker restart orbi(both files are yours — the entrypoint never overwrites an existing config).
pi-providers.json was generated; orbi setup scaffolds a starter file
to fill in instead. Verify the endpoint before relying on it:
Boundaries
- Thin wrapper only:
src/orbi/core code is untouched, and a blocker hit inside the container is filed as its own core Issue. - Linux only; no compose, no multi-container orchestration, no automatic image updates; not part of the PyPI release or the getting-started main path.
- Community-maintained: official Issues prioritize the core systemd path.