Run Autolith from CI
The run-job boundary runs one non-interactive job with a data-only S-expression envelope and a structured-output contract. No terminal, no mid-flight approvals, one result artifact.
Write the job
(:autolith-job
:version 1
:id "nightly-lint"
:role "task"
:prompt "Run ./script/check in the workspace and report every failure."
:input (:branch "main")
:output-contract
(:type :object
:properties (("status" (:type :string))
("failures" (:type :array :items (:type :string))))
:required ("status"))
:timeout-seconds 1800)
Every field is required. :role names a discovered
task role; task is the general one. The contract
speaks a deliberately small schema dialect: types with
:enum, objects with :properties,
:required, and
:additional-properties, arrays with
:items, :min-items, and
:max-items.
Run it
$ autolith run-job --input job.sexp --output result.sexp
The reader accepts exactly one data-only form: keywords, strings, and finite numbers, at most one mebibyte across 65,536 nodes, 128 levels deep, with strings up to 512 KiB. No symbols, no function calls, no reader tricks. Timeouts run from one second to one day.
Read the result
(:autolith-job-result
:version 1
:id "nightly-lint"
:status :succeeded
:result (:status "pass" :failures nil)
:trace-id "..."
:usage (:input-tokens 4182 :output-tokens 917 :provider-requests 2)
:started-at "2026-09-06T02:14:09Z"
:finished-at "2026-09-06T02:19:44Z")
The envelope is written atomically. Failures replace
:result with :failure, carrying a
stable category and a bounded message, so pipelines branch on
data instead of scraping logs.
Command and tool authorization run fail-closed under the configured permission mode: full access, sandboxed, or automatic classification. Anything undecided is denied, never waved through.