Configuration reference
Orbi readsorbi.toml from the deployment home; set ORBI_CONFIG to select another file. Relative paths are resolved from that file. Run orbi check to validate it before starting a tick.
Repositories and paths
| Key | Type | Default | Allowed values | Meaning |
|---|---|---|---|---|
source_repos | list of strings | required | non-empty owner/repo names | One owner/repo task pool scanned each tick. Multiple entries fail fast because the current execution layer has only one checkout; multi-repo workspaces are not available yet (Issue #133) |
repo_dir | path | . | any path | The delivery checkout: the repository whose Issues the Runner delivers. Task worktrees are created from its frozen origin/<base_branch> SHA, PRs open against it, and the slot locks live in <repo_dir>/.orbi/slots/. In bootstrap mode this is the orbi checkout itself; in the external single-repo mode (Issue #330) it is a foreign user repo X |
deploy_home | path | repo_dir | any path; must exist | The orbi SOURCE checkout (Issue #330): the editable CLI install source (the self-update), the systemd/ unit templates, labels.toml, and the prompt defaults (prompts/prompt.md, prompts/prompt_review.md when unset). Absent = repo_dir (bootstrap mode, unchanged). Set it to the orbi checkout when repo_dir is a foreign repo X. Must be a non-empty string; a missing directory fails the start fast |
workspace_root | path | .. | any path | Directory that contains the task worktrees and the repositories the agent may modify |
base_branch | string | main | any non-empty string | Delivery base branch; every task worktree is created from the frozen origin/<base_branch> SHA |
git_transport | string | ssh | ssh | https | Delivery checkout transport (Issue #580). ssh (default): git data operations go over [email protected]:owner/repo.git with the machine’s SSH key; setup migrates an HTTPS origin. https: the origin stays on https://github.com/<repo>.git and the git ls-remote/fetch/push credentials come from the gh credential helper (gh auth login --with-token) — the token-only sandbox path with no SSH private key. Anything else fails the config load fast |
engine_source_track | string | main | main, branch:<name>, release, tag:<name>, or sha:<40-hex> | Engine source update channel (Issue #535, host/deploy-only — never a repository’s .github/orbi.toml): what the deploy home checkout follows at every service start. absent/main: fast-forward origin/main (the pre-#535 dogfood behavior) — the development mainline, changing with every commit. branch:<name>: fast-forward origin/<name>. release (alias: stable): the newest official semver tag (pre-releases excluded), detached — follows the newest PUBLISHED version, changing only when a release ships. tag:<name>/sha:<40-hex>: exact lock, detached — never moves until you edit the value, so a version change is always a deliberate operation (pin a reproducible deployment this way); rollback is editing the value back. A dirty checkout, a missing tag/SHA or any unverifiable state fails the start with a structured line (see Operations) |
allow_stale_runner | boolean | false | true | false | Offline escape hatch for the runner source freshness gate (Issue #525): before any slot or claim the Runner proves the code it executes matches the configured engine source channel — engine_source_track (Issue #535), origin/main by default, never the delivery base_branch (the import checkout’s HEAD for an editable install; the installed version vs the latest release tag for a non-editable one — local git reads only). A stale or unverifiable source logs the structured runner_source_stale line (facts + fix) and fails the start. true downgrades the SAME line to a warning so an offline/restricted-network machine keeps running — it never skips the check. Invalid values fail fast |
Scheduling
| Key | Type | Default | Allowed values | Meaning |
|---|---|---|---|---|
max_concurrency | integer | 1 | 1–5 | Concurrent Orbi tasks and enabled Runner timers on this machine (1..5, the MAX_RUNNER_INSTANCES declaration cap — Issue #827; the real sustainable capacity depends on CPU/memory, measure before raising it) |
unit_name | string or null | unset | letters, numbers, -, _ | Optional per-deployment systemd name. website installs orbi-website@1/2.timer and matching services; unset keeps the compatible orbi@1/2 names. |
active_milestone | string or null | unset | any non-empty string | Claim scope for the fresh-claim scans (Issue #139): the active GitHub Milestone title (e.g. v0.2.0). Set it to restrict the p0/bug/plain ready scans to that Milestone (the milestone:"<title>" qualifier is part of the gh search query — an Issue of another or no Milestone never enters the queue); ai-ready stays the execution switch, the pickup order is unchanged, P0 does not cross milestones, and resume states (opened PRs, in-flight restarts) are never gated by it. The ONE exception is the external-takeover scan (Issue #842, decision D1): the fifth, last ready scan carries no Milestone qualifier, so an external triage ticket (body marker <!-- orbi:external-pr:N -->) stays claimable — an external contribution belongs to no version’s scope and must never block the release gate. Unset = every ai-ready Issue is claimable (pre-#139 behavior). Advance it with orbi milestone set <title> (see Operations; the Runner’s next tick publishes the ORBI_ACTIVE_MILESTONE variable) |
auto_next_milestone | boolean | true | true | false | Controls idle advancement after the active milestone closes and its queue is empty. false leaves active_milestone unchanged, logs a pending warning, and creates one confirmation Issue without ai-ready or p0 so it cannot be picked up; stale notices are closed after a manual move. Invalid values fail fast |
worktree_retain_hours | number | 72 | finite positive number | Retention window for the tick-start task-worktree reclamation (Issue #760, host/deploy-only — never a repository’s .github/orbi.toml): a registered task worktree whose Issue has been CLOSED for at least this many hours is removed automatically (open Issues and in-flight runs are never touched). The mechanism and the worktree_reclaimed journal line: Operations. Must be a finite positive number of hours; anything else fails the start fast |
Model provider
| Key | Type | Default | Allowed values | Meaning |
|---|---|---|---|---|
pi_providers | path or null | unset | any path to a providers JSON file | Path to a JSON file in Pi’s models.json shape that adds or overrides providers in Pi’s catalog for every run (Issue #157). Unset = Pi uses its own agent dir unchanged (step 4) |
pi_provider | string or null | unset | any non-empty string | The provider id selected for every run (Issue #119) — passed to Pi as --provider; must be defined when a pi_providers file is set |
pi_model | string or null | unset | any non-empty string | The model id within the selected provider — passed to Pi as --model; must exist in the provider’s models list |
pi_thinking | string or null | unset | off | minimal | low | medium | high | xhigh | max | Thinking level passed to Pi as --thinking (off, minimal, low, medium, high, xhigh, max) |
pi_extensions | list of tables | [] | pinned npm:/git source or existing local path | Repeatable extension tables: source is a pinned npm:/git source or an existing config-relative local path; enabled defaults to true and env is injected only into that Pi child. Every run passes --no-extensions, so global Pi extensions are never discovered. |
review_pi_provider | string or null | unset | any non-empty string | Provider override for review sessions; unset falls back to pi_provider |
review_pi_model | string or null | unset | any non-empty string | Model override for review sessions; unset falls back to pi_model |
review_pi_thinking | string or null | unset | same thinking levels as pi_thinking | Thinking-level override for review sessions; unset falls back to pi_thinking |
model_wait_probe_url | URL or null | unset | non-empty http:// or https:// URL | Swallowed-model-request probe (Issue #233): the model’s /slots endpoint (e.g. http://127.0.0.1:18082/slots, the agent-facing port — the local-llm-kv-cache proxy passes it through from llama.cpp). While Pi is frozen in model_wait the Runner probes it and kills the Pi session fast when every slot stays idle for the model_wait_probe_seconds grace. Field semantics (the swallow scene, the bypass boundary): the model_wait_swallowed journal line in Operations. Unset = the probe is disabled (the pre-#233 behavior). Must be a non-empty http:///https:// URL; anything else fails the start fast |
model_wait_probe_seconds | number | 60 | finite positive number | The sustained-idle grace for the swallowed-model-request probe (Issue #233): how long the “every slot idle” state must hold (while in model_wait) before the request is declared swallowed and Pi is killed. Must be a finite positive number; anything else fails the start fast |
model_wait_dead_seconds | number | 1800 | finite positive number | Hung-model-request threshold (Issue #228): seconds of model_wait silence before the Runner kills the Pi session and fails fast. Field semantics (silence between complete events, the slow-generation boundary): the model_wait_dead journal line in Operations. Must be a finite positive number; anything else fails the start fast |
review_pi_* rows let the independent review run on a different model than the implementation — see Reviewing with a different model.
Prompts and context
| Key | Type | Default | Allowed values | Meaning |
|---|---|---|---|---|
prompt | path | prompts/prompt.md | any path | Implementer prompt template (placeholders like {{SOURCE_REPO}} are rendered by the Runner) |
prompt_review | path | prompts/prompt_review.md | any path | Review prompt template for the independent post-PR review session |
skills | list of paths | [] | absolute, ~, or config-relative paths | Optional Pi skill paths (absolute, ~, or relative to the config file) |
context_files | list of paths | [] | paths | Optional Markdown context files injected into the prompt as paths |
attribution_footer | boolean | true | true | false | Append a one-line Built by Orbi backlink to Orbi-created PR bodies and Release notes. Set to false to omit it; must be a boolean |
Delivery behaviour
| Key | Type | Default | Allowed values | Meaning |
|---|---|---|---|---|
dispatch_label | string or null | unset → ai-ready | any non-empty string | Ready label for repository policy; see the repository configuration table. |
human_review_gate | boolean | false | true | false | Human acceptance gate (Issue #763, host/deploy-only — a repository’s .github/orbi.toml can never carry it): when true, every delivery posts ONE acceptance checklist to the Issue when its PR opens (column 1: what the run already verified — the real test result and covered layer; column 2: the machine-unverifiable minimum derived from the changed paths — business intent, UI visuals and copy, external environment, missing-evidence items). While column 2 is non-empty the review round short-circuits BEFORE any Pi session: the ticket returns to ai-ready (the opened-PR label stays as the resume anchor), the slot is released, and each later tick costs one label read — the wait never burns the review-round budget. A person confirms the checklist with the human-only ai-human-review label and the next tick reviews/merges exactly as before (--match-head-commit untouched). An empty column 2 is the target state: the checklist says no human intervention is needed and the delivery passes without the label. The gate is OFF by default: with it off, delivery/review/merge/release behave exactly as before. Must be a boolean; anything else fails the config load fast |
issue_comments_limit | integer | 20 | positive integer | Trusted-comment injection cap (Issue #745, host/deploy-only — never a repository’s .github/orbi.toml): how many of the Issue’s trusted comments (OWNER/MAINTAINER/MEMBER/COLLABORATOR or the runner’s own App — the same authorAssociation trust set as the recovery scene) the {{ISSUE_COMMENTS}} prompt placeholder receives, oldest first, newest kept. Over the cap the oldest trusted comments are dropped and the injected block states how many were omitted — never a silent truncation. A template without the placeholder fetches nothing (the pre-#745 behavior). Must be a positive integer; anything else fails the start fast |
release_ci_wait_seconds | number | 1800 | finite positive number | Release gate CI bound (Issue #268): the release state machine’s in-tick upper bound for pending checks (queued/in_progress) on the release commit before failing with its own timeout reason — never a delivery-wait mechanism (Issue #788 removed the delivery path’s CI wait: a pending check defers the delivery to the next tick). The wait is visible as release_waiting_ci journal lines and progress-comment updates; the final conclusion decides. Must be a finite positive number; anything else fails the start fast |
release_deliveries_wait_seconds | number | 1800 | finite positive number | Release delivery wait (Issue #381): when gate 1 finds open delivery Issues, the release emits release_waiting_deliveries, returns to ai-ready and releases the slot for the next tick. The wait timeout is reported as a delivery wait timeout, distinct from CI failure. Must be a finite positive number |
Steering
Steering lets the Runner poll the Issue for a trusted correction and restart the active delivery with that correction.steering_max_rounds bounds those restarts so an active delivery cannot be redirected forever. A polling failure is a pure bypass: it is logged, but never makes the delivery fail.
See the delivery_steered, steering_limit_reached, and steering_poll_failed rows in Operations.
| Key | Type | Default | Allowed values | Meaning |
|---|---|---|---|---|
steering_enabled | boolean | true | true | false | Enables trusted Issue correction polling. |
steering_poll_seconds | number | 60.0 | finite positive number | Interval between steering polls. |
steering_max_rounds | integer | 3 | non-negative integer | Maximum steering restarts per delivery. |
Health
| Key | Type | Default | Allowed values | Meaning |
|---|---|---|---|---|
health_alert_repo | string or null | unset | any non-empty owner/repo string | Repository receiving Runner crash-loop and stale-pickup health Issues; unset derives it from the deploy-home origin. |