atoll-runner runs one claimed issue at a time with Codex. Atoll controls
assignment, project access, repository authorization, and lease ownership.
The runner keeps machine-local checkout bindings and recovery evidence.
Install and activate a runner
You do not need an Atoll source checkout. Install the released CLI package and confirm that it contains both commands:git --version succeeds. Apple Git can remain blocked
until you review and accept the Xcode Command Line Tools license. That legal and
administrator action must be completed by the machine operator.
Create a named profile for the agent and organization, then find the opaque
repository reference authorized for the project:
doctor cannot
fully pass yet, and --dry-run does not register the runner. When the runner
appears, immediately pause it in Workspace Settings → Runners and verify
that the fleet row shows Paused. Now complete the read-only checks:
blocked_reason: intake_paused.
For unattended macOS operation, install and verify the user service:
doctor passes, required bindings validate, Codex is
authenticated, the service is loaded, the optional loopback page responds, and
there is no unexpected current or retained job. Resume new work in hosted Atoll
only after these checks. Then confirm that the fleet row shows Connected and
Accepting, and that local status reports connected with active intake.
Resuming can immediately claim eligible assigned work.
One machine can run several named profiles, including profiles for different
organizations. Each process and macOS service is fixed to one profile, agent
identity, and organization. Give each enabled diagnostics UI a unique port:
Prerequisites
Use a CLI build that includes the real Codex worker. Configure a named Atoll profile with an agent key and organization. The package pins both@openai/codex-sdk and @openai/codex to 0.153.4.
The pinned runtime must have valid Codex authentication. An unrelated global
Codex installation is not a fallback. Use saved Codex login credentials.
The worker does not inherit API keys, runner tokens, proxy credentials, or
arbitrary environment variables from its parent process.
Your issue’s project must have exactly one currently verified repository.
You need a local non-bare Git checkout whose origin matches that repository.
Credential-bearing HTTPS origins are rejected. Use a credential-free origin
and a Git credential helper for repository access.
Zero or multiple verified repositories block execution. A local binding does
not select a preferred repository or grant project access.
Configured external Git clean, smudge, or process filters block worktree
preparation. This includes global Git LFS filter configuration, even when the
selected repository does not use LFS. Use a checkout and Git configuration
without these external filters. The runner does not disable required filters
or change your Git configuration. Runner Git commands disable hooks and
filesystem-monitor commands to protect the primary checkout.
Bind a local checkout
Use the opaquerepo_ref from the project’s authorized repository mapping.
Pass the issue UUID to verify that project’s mapping during binding.
Check and run
0600 plist in
~/Library/LaunchAgents/ with canonical Node and runner entry paths, the
selected profile, and optional loopback UI arguments. The plist contains no
API key, Codex token, lease token, environment variables, checkout path, or
shell command. An unknown or changed plist is rejected instead of overwritten.
Package installation is passive and never installs or starts this service.
The documented upgrade path is service uninstall, package upgrade, doctor,
then service install; pause hosted intake first when a no-work maintenance
window is required.
service status is read-only and reports only bounded installation, load,
plist, executable, PID, and last-exit fields. service uninstall bootstraps
down the exact label and removes only the exact owned plist. It leaves runner
configuration, journals, tokens, logs, branches, and worktrees in place.
Status and uninstall validate local ownership and remain available after profile
or key removal; install remains authenticated.
doctor and status report bounded Codex availability, version, and
authentication health without account output or credentials. These checks do
not submit a model turn. --dry-run is a read-only dispatch check, not proof
that a model turn or worktree preparation has succeeded.
Before turn intent, the runner resolves the server’s default ref to an exact
commit and prepares an owned branch and worktree under its local storage.
It preserves the primary checkout, including unrelated changes, and verifies
that snapshot again before terminal reporting and lease finalization. Codex runs
with workspace-write, approval policy never, no added writable directories,
and sandbox network access disabled. The task can change files in its owned
worktree. It does not automatically create a PR, merge, deploy, or publish.
Manage pause and resume in hosted Workspace Settings → Runners. Intake is
read-only in localhost. Legacy local pause and resume commands return
RUNNER_INTAKE_HOSTED_ONLY and do not change server state.
Pause does not cancel a held lease. The current worker can finish or reconcile
that lease. Loss of lease ownership aborts the model stream.
The parent closes its process-local intake gate immediately on SIGINT or
SIGTERM. The current child has up to 30 seconds to drain; only a journaled PID
with the same process-start identity can receive SIGTERM and, after a further
10 seconds and a final identity check, SIGKILL. A wall-clock gap over 30
seconds is treated as a possible wake: the child is stopped, durable lease and
mutation state is reconciled, and local intake reopens only after that pass. A
wake may release a worker only to report and finalize an already durable result;
a stop never releases a worker. No hosted pause request is sent. Protocol errors
are reported as bounded RUNNER_PROTOCOL_MISMATCH failures and leave the
pending journal available for replay or operator reconciliation.
Open local setup and diagnostics
http://127.0.0.1:4735 URL. Use run --ui --ui-port 4736
or ui --port 4736 if needed. There is no LAN bind option. Do not expose the
page through a proxy or tunnel. A port conflict or missing frontend asset does
not stop headless runner operation. Without --ui, the runner opens no UI port.
--dry-run cannot be combined with --ui.
Select the existing Atoll credential profile with --profile at process start.
The page shows that profile; it cannot switch a live installation or accept
credentials. Use atoll auth to repair a profile, then reload configuration.
The diagnostics-only command can show malformed or unreadable runner config
without resetting it or dispatching work.
The page has five sections:
An authorized repository remains visible when unbound. Enter its local checkout
path and select Bind checkout. This uses the canonical runner config writer;
it does not require an assigned issue. Symlink inputs are resolved before saving.
A saved canonical path that later points elsewhere fails revalidation. Wrong
origins, missing paths, unsafe filters, or insufficient filesystem permissions
block eligibility. Validation does not change the primary checkout.
A project with multiple verified repositories can have local bindings, but
issue dispatch remains blocked until the upstream routing contract identifies
exactly one repository. Local setup never selects a default. A revoked mapping
leaves any local binding visible as inert diagnostic data.
Refresh, Reload config, Revalidate, and Run preflight read current
state without submitting a Codex turn. Remove binding changes only local
configuration. Bind/remove are blocked while the runner has a current job.
Policy reads and preflight become stale after 60 seconds. The page refreshes
while visible and idle; it does not replace text while you edit a binding.
The worker independently rechecks authority, runtime, and repository identity
before execution. A green diagnostic row does not reserve work or grant access.
Atoll failure invalidates repository eligibility immediately on failed readback.
Previously persisted runner self state may remain visible as stale context.
Local config, jobs, and logs stay available. Authentication failures direct you
to profile repair; Codex failures direct you to runtime/auth preflight.
There are no local intake, terminal, process-control, arbitrary file-write,
model retry, or branch/worktree deletion controls. Cleanup-ready is a read-only
state, not deletion authorization. The existing runner loop owns safe lease
reconciliation; uncertain model outcomes remain quarantined.
Recovery and retained evidence
The runner keeps one active recovery journal under~/.atoll/runner/ and
stores lease tokens separately with restricted permissions. It persists the
thread ID before it accepts turn-start evidence, and persists completion
before lease finalization. Raw model messages, reasoning, commands, and tool
payloads are not copied into the runner journal or lifecycle comments.
A definitive Codex turn.failed event is saved as a bounded failure result
and finalized as failed. Raw error text is not included in lifecycle reports.
A dead worker after turn intent without durable completion becomes
uncertain_outcome. The SDK cannot prove whether an interrupted submitted
turn ran. The runner therefore does not submit another turn, create another
thread, or resume the same prompt automatically. Keep the evidence for
operator reconciliation.
A valid attention-resume claim can use only the exact retained thread with
matching runner ownership and worktree evidence. Invalid routing stops the
resume; it never starts a fresh thread as a fallback. Report-only and
acknowledgement-only recovery do not run Codex again.
Lifecycle comments contain bounded completion information and real thread/host
source metadata. The comment API does not support idempotent creation. If a
comment response is lost, recovery reads back the exact prior report. If it
cannot find that report, progress stops for operator reconciliation instead
of sending a possible duplicate.
Terminal branches, worktrees, and local thread evidence remain available for
inspection. The runner does not delete them automatically. An uncertain
outcome or active writer is not eligible for cleanup.
Manual local smoke
The real Codex path is an opt-in developer harness available only in an Atoll source checkout. It is not included in the installed npm CLI. Loopback remains the normal default. Repository owners may run one bounded production validation turn from a clean source checkout with an exact canonical origin, organization, project, authenticated agent, issue, runner host and instance, and the live project repository mapping’s opaquerepo_ref and repository full
name. The supplied repo_ref is checked against live issue routing and must
never be hard-coded. The smoke derives the canonical source root from its own
script, requires a clean source checkout, rebuilds the candidate in the
invocation, and records the source root, source HEAD, and worker-entry
SHA-256 in bounded mode-0600 evidence. Exact production admission
performs zero presence PUT/upsert operations for either connected or
disconnected targets. Registration and refresh belong to separate operator setup
outside this invocation. The invocation reads the connected runner identity
before claim and rechecks it immediately before the claim; a disconnected target
fails closed. The runner does not explicitly select a model. The Codex runtime
and local Codex configuration supply model selection. @openai/codex and
@openai/codex-sdk are pinned to package/runtime version 0.153.4; this
version is not a model name. Use the internal AH-2088 production smoke
runbook for the owner-only command and cleanup procedure.
For the normal loopback fixture profile, use a clean fixture profile with no
current or conflicting retained job, against a local Atoll base URL, from
packages/cli:
0600 evidence contains only fixture issue, runner host,
lease generation, retained branch/worktree, base/head SHA, thread ID, terminal
state, and timestamps, and is written outside the checkout. A timeout is
always failure; retained journal state is authoritative. The harness never
pushes or deletes retained state, publishes, deploys, or installs a service.
Codex Desktop visibility is a separate operator observation; automated tests
use a fake SDK and do not spend Codex usage.
