Skip to main content
orbi setup verifies the local prerequisites and CLI, aligns repository labels, installs user units, and checks the configured checkout. orbi setup is the one-time, config-driven initialization entry for a new machine or a new task-pool repository. It verifies or reinstalls the editable CLI install, verifies the local prerequisites, aligns the platform labels, installs the systemd user units, checks the checkout, and reports the optional model proxy — in one command, with a stable machine-readable result.
--config remains available for a non-default config path. When the default orbi.toml is absent, setup creates it from the adjacent .orbi.example.toml when one exists and otherwise from the example shipped inside the CLI package (Issue #163), and never overwrites an existing file. Run it once per machine (and once per new task-pool repository). It is idempotent: re-running it never creates duplicate labels, units or timers, and never touches business Issues or business labels.

What it does, in order

Setup is fail-fast: a core prerequisite failure stops the run before any later mutation, with the concrete reason on stderr and a non-zero exit code.
  1. Commands — git, gh, python3, uv and the installed orbi CLI on the PATH (you install these yourself — setup only checks them; a missing one fails fast with the actionable install guidance, e.g. required command missing: uv (not on PATH) — install uv first: curl -LsSf https://astral.sh/uv/install.sh | sh), and a reachable systemctl --user user bus (a container or headless session without a user bus fails with the bus error). gh must be ≥ 2.94.0 — the queue scans need gh api --paginate --slurp and the blockedBy field, so an older distribution package (Ubuntu 24.04 ships 2.45.0) passes this check but fails every tick; Getting started carries the official install source and the repair.
  2. CLI editable install (Issue #152) — the official local deployment is the EDITABLE uv tool install (the why — the ExecStartPre checkout sync — is defined in Getting started step 2). The install acts on the deployment home (deploy_home, defaulting to repo_dir — Issue #330): when the running process already imports from the configured deploy_home the step verifies it (no uv call, cli=verified); otherwise it runs the exact force editable reinstall (uv tool install --force --reinstall --editable --python <interpreter> <deploy_home>, cli=installed). <interpreter> follows the compatible selection rule (Issue #861): --python python3 when the system Python satisfies Orbi’s requires-python floor (>= 3.14 — Fedora 43 and current Arch ship it), otherwise --python 3.14 so uv provisions or selects a compatible interpreter (Ubuntu 24.04 ships Python 3.12 — an exact-path pin to that system interpreter exits 1 with a dependency resolution failure, while the bare python3/3.14 forms let uv select or provision a satisfying one). In the external single-repo mode the CLI is NEVER (re)installed from the delivery checkout — repo_dir may be a foreign repo X without any orbi packaging input. A failing install fails fast — no unit install, no half-initialized state. The step never touches a running Runner process (the new source is loaded by the next CLI start).
  3. Auth — gh auth status (logged in with a usable token).
  4. Per target repository (every configured source_repos entry by default; exactly one with --repo OWNER/REPO):
    • the repo exists and the viewer has write permission (gh repo view → viewerPermission must be WRITE, MAINTAIN or ADMIN). A GitHub App installation token (ghs_) reports an empty viewerPermission although its issues:write manages labels (Issue #613): setup decides the empty field with a one-shot create+delete label probe (gh api) and reports permission=INSTALLATION; a user token keeps the plain permission requirement;
    • the fourteen platform labels (ai-ready, ai-in-progress, ai-pr-opened, ai-fix-needed, ai-merged, ai-blocked, ai-awaiting-merge, p0, ai-epic, ai-release, ai-content-only, ai-ops-only, ai-human-review, ai-needs-detail) are aligned declaratively from the deployment home’s labels.toml (<deploy_home>/labels.toml, Issue #330) — the single source of truth for label name, color and description: a missing label is created, a drifted label is updated, nothing is deleted, and business labels (bug, enhancement, …) are never touched. In the external single-repo mode the labels come from the orbi checkout, never from the delivery checkout X.
  5. Systemd units — the deployment home’s templates (<deploy_home>/systemd/[email protected], <deploy_home>/systemd/[email protected]; in bootstrap mode the orbi checkout, Issue #330) are installed idempotently into the user unit directory (the same install install-units performs: copy, migrate the pre-#149 non-templated units away once, daemon-reload, then enables @1 for max_concurrency = 1 or @1 and @2 for 2 (and disables surplus timers) — the service is never started, stopped or restarted), then each timer instance’s enabled/active state and next trigger time are reported.
  6. Checkout + git transport — check of the configured delivery checkout repo_dir (the orbi checkout in bootstrap mode, the user repo X in the external single-repo mode): the origin remote’s transport (Issue #114, #580), selected by git_transport in orbi.toml. ssh (default): git data operations (fetch, push — including .github/workflows/*.yml) go over SSH ([email protected]:owner/repo.git), so an existing HTTPS origin is migrated here with the plain git remote set-url origin [email protected]:owner/repo.git (setup is the human-authorized migration path — the Runner itself never rewrites a remote). https (the token-only sandbox path): the origin STAYS on https://github.com/<repo>.git and the credentials come from the gh credential helper (gh auth login --with-token) — an SSH origin is migrated to the HTTPS URL here, and no SSH key is required anywhere. In both modes the URL must match the first configured source repo — a remote pointing at a DIFFERENT repo is never migrated (the rewrite would re-target the checkout at another repository) and fails with setup_failed reason=... origin remote repo mismatch ... — and git ls-remote <expected-url> must exit 0 (the configured transport reachable and authenticated — a failure is setup_failed reason=... ssh_unreachable ... in ssh mode or ... transport_unreachable ... in https mode, no fallback). Then the read-only parts: current branch, clean worktree (a dirty checkout fails: the timer’s ExecStartPre fast-forward refuses a dirty worktree, so the Runner could never start), and base freshness (local HEAD vs freshly fetched origin/<base_branch> — reported, not a failure: the timer fast-forwards a clean checkout at each start).
  7. Optional model proxy — the local-llm-kv-cache proxy health endpoint (http://127.0.0.1:18082/health) is checked and reported as optional: its absence or unhealthiness is a warning in the output and never blocks the core GitHub/Orbi setup.
Setup never creates business Issues, never claims a task, never starts Pi, and never modifies a protected branch.

External single-repo mode (deploy_home)

In the external single-repo mode (Issue #330, PR #334) the config separates the two checkouts: deploy_home is the orbi source checkout and repo_dir is the user repo X. Setup routes accordingly — steps 2 (CLI editable install), 4 (labels.toml) and 5 (unit templates) act on deploy_home, while step 6 (checkout + git transport) checks repo_dir: X’s origin must match the configured git_transport for the first configured source repo, X’s worktree must be clean, and X’s base freshness is reported. Note that in external mode the timer’s ExecStartPre fast-forward acts on the deploy home (the orbi checkout), not on X — X is only read from when the Runner creates task worktrees. deploy_home absent means bootstrap mode: everything acts on repo_dir exactly as before. One practical consequence: the installed systemd unit reads its config from <deploy_home>/orbi.toml (the {{ORBI_REPO_DIR}} placeholder renders the deploy home path), so in external mode orbi.toml and the optional .orbi/env live in the orbi checkout — run setup with --config <deploy_home>/orbi.toml.

Options

Output

The default output is stable key=value lines (one per concern; values containing spaces are quoted), so agents and scripts can parse it:
cli=verified means the running CLI already imports orbi from the deployment checkout (the editable install is in place); cli=installed means the force editable reinstall ran. labels=12/12 means all twelve platform labels match labels.toml. There is one timer= line per timer instance and its next is that instance’s next trigger time (- when it has none). model_provider=NOT CONFIGURED is a warning: it never changes the setup exit code; the following model_provider_guide line tells you where to configure it. optional_proxy is healthy, unhealthy or unavailable and never changes the exit code. migrated=true means setup rewrote an origin on the opposite transport to the configured transport’s URL (a re-run then reports migrated=false); ssh_reachable is the SSH git ls-remote probe result (- in https mode — no SSH probe runs there) and transport_reachable is the probe result of the ACTIVE transport (Issue #580). --json prints the equivalent JSON document:

Success and failure examples

Success (exit code 0):
(The optional proxy is down here — note optional_proxy=unhealthy — but the core setup still succeeds with exit code 0.) Failures (non-zero exit code, setup_failed reason=... on stderr):
A missing prerequisite command (e.g. uv), a wrong repo, missing labels that cannot be created (permission), a dirty checkout, an an unreachable transport (no fallback) or a missing systemd user bus all stop the setup with the concrete reason — nothing is half-initialized without a clear signal.

Idempotency

Re-running setup on an already-initialized machine is a no-op for the external state: labels that already match are not rewritten, the unit templates are re-copied from the repo (drift repair), the configured timers retain their enabled or disabled states, and no Issues or business data are created or modified. The reported hashes and states are stable across runs. The transport migration is one-shot: after the first run the origin remote matches the configured git_transport and re-runs only re-verify it (migrated=false).