Autolith is a terminal agent running in a live Common Lisp image. It works on Linux x86-64 and macOS.
You can launch autolith by typing its name into your favorite terminal:
autolithIf you haven’t authenticated already, you can check out the README for how to do that.
Autolith’s prompt window can also evuluate lisp forms directly:
(help)
(resource.read :uri "workspace:.")
(prompt (read-file "review-notes.org"))This can be frequently helpful since you can use the exact same tools the clanker can, and the same machinery is exposed to you.
Use (goal "OBJECTIVE") for lightweight autonomous work. Use (goal "pause"),
(goal "resume") or (goal "clear") to control it. For externally verifiable
work, install explicit acceptance policy with (mission "start PLIST"), or
evaluate:
(application-mission-start
*active-application*
'(:objective "Deliver the accepted build"
:turn-limit 40 :token-limit 100000 :wall-seconds 3600
:criteria ((:id "build" :description "The build passes" :gates ("build"))
(:id "review" :description "The user accepts the result"))
:gates ((:id "build" :kind :command :command "make check"
:inputs ("Makefile" "src/main.lisp") :deterministic-p t
:attempt-limit 3 :timeout-seconds 300))))Use (mission "run") to begin, (mission "status") to inspect the complete
durable state, and (mission "verify") to request harness verification. The model can
also call mission.status, mission.verify, mission.stop and
mission.invalidate. Only the primary agent may mutate mission policy through
these model operations. Configure acceptance criteria yourself; the model
cannot weaken them or supply user acceptance.
Each criterion has a unique :id, a :description and optional ordered gate
IDs in :gates. Criteria without gates require your explicit evidence:
(mission "accept (\"review\" \"I inspected the artifact and accept the result\")")
(mission "resume")
(mission "verify")The model’s completion marker requests verification. Passing a gate proves only the criteria you explicitly associated with it. Verification requires all gates and all criteria. Inspect the acceptance mapping before beginning work.
The turn allowance counts provider inference calls across the primary agent, children, compaction and recursive inference, including mapped and nested frames. Reported billable tokens use the provider API’s usage normalization and exclude known prompt-cache reads. Admissions and settlements are serialized within a mission; provider requests execute concurrently. Each admission reserves a turn and an output ceiling from the unspent, unreserved tokens. The default ceiling divides those tokens among the remaining turns; an explicit provider output cap replaces that division. Reviewer requests reserve from both allowances. Settlement releases the ceiling and charges reported input and output usage, so a request can exhaust the token allowance. Missing usage is recorded as unknown and blocks further inference. Install a new explicit budget to proceed after unknown usage.
The wall-clock deadline includes gate execution, delegated tools, pauses and
time away. Work runs under cl-jobpond supervision. Use (goal "pause") and
(mission "resume") without resetting any mission budget; use
(mission "cancel REASON") to terminate it. Terminal states are verified, exhausted, cancelled
and failed. A blocked mission retains the evidence needed to resolve its
blocker and resume. Interrupted inference restores as blocked when its usage
cannot be recovered. Gate attempts, fingerprints and evidence restore with the
conversation and survive compaction independently of model summaries.
Gates run in order, stopping at the first failure. Command gates use the ordinary
shell authorization and sandbox boundary. Artifact gates require :path and
optionally an expected :sha256. Lisp gates require a :predicate string and
run an assertion in the existing isolated Lisp worker. Every gate supports
:timeout-seconds and a separate :attempt-limit, defaulting to 60 seconds and
three executions. Each gate retains bounded evidence.
For deterministic gates, declare all relevant file paths in :inputs and set
:deterministic-p t. File contents and missing-file states form the fingerprint;
directory paths are rejected. Unchanged passing gates supply current proof, and
unchanged failed gates are withheld while the model works on their relevant
inputs. For remote state, omit deterministic policy or invalidate a particular
gate explicitly:
(mission "invalidate (\"build\" \"The remote build configuration changed\")")Invalidation permits another execution without replenishing its attempt budget. Before acceptance, every gate fingerprint is checked again under the workspace mutation lock. Changes from a later gate invalidate earlier passing evidence. Collect terminal results and outstanding inference usage before verifying.
Attach a reviewer to an active mission with mission-review.configure, or evaluate:
(application-mission-review-configure
*active-application*
'(:id "release-review" :phase :final-acceptance
:inputs ("src/main.lisp" "tests/main-tests.lisp")
:context "Review the changed behavior and test coverage. Report concrete findings."
:turn-limit 4 :token-limit 16000 :run-limit 3))Declare the complete relevant file set. The reviewer receives an independent
snapshot and background, returns contracted findings, and has no tools or spawning
permission. Reviewer call and token allowances are cumulative across changed
snapshots and also count against the mission allowances. :run-limit bounds the
number of distinct snapshots reviewed.
Use mission-review.trigger with id to review a checkpoint and
mission-review.inspect to read its durable findings, decisions and usage.
Unchanged snapshots reuse completed, failed or interrupted runs. Resolve or reject
each finding through mission-review.decide with id, finding, decision
(resolve or reject) and an evidence-bearing reason. Only the primary agent
or local user may configure, trigger and adjudicate reviews.
Final verification runs configured final-acceptance checkpoints. Pending
findings and failed or interrupted reviews block acceptance. For
before-integration and after-edit-set checkpoints, trigger the named review
explicitly at the chosen boundary. Reviewer findings are advisory; mission gates
and user acceptance supply harness evidence.
Attach explicit wakeups to the current mission with mission-schedule.add.
Supply an immutable id, continuation content, and a time policy: at is an
absolute Common Lisp universal time, interval is a positive number of seconds,
and event names an external event instead of a time policy. For example:
(application-mission-schedule-add
*active-application* :id "build-followup"
:content "Check the pending build and continue the mission."
:at (+ (get-universal-time) 300) :missed-policy :latest)For recurring wakeups, choose missed-policy latest (the default), all or
skip to select the newest missed occurrence, every missed occurrence or none.
Use mission-schedule.event with an event name and stable external event id;
repeated delivery of that ID is deduplicated. The local daemon listener hosts time
wakeups. Due work enters the ordinary primary command queue as a persisted
(mission-wakeup "TICKET") command and executes as a mission continuation under the existing
turn, token and wall-clock budgets.
Only the primary agent may use the mission-schedule tools. Each wakeup retains
its exact mission identity and version, checked at admission and execution;
replaced or inactive mission work is cancelled. Use mission-schedule.inspect
to read schedules, occurrence IDs and claim tokens, and mission-schedule.cancel
with the schedule id to cancel future and pending work.
Interrupted admissions and executions restore as uncertain outcomes. Inspect the
external effects before calling mission-schedule.resolve with the readable
occurrence ID, current token and action completed, failed or retry.
Retry is an explicit decision and is refused while the occurrence is executing.
Cancellation retains claim and duplicate history.
Configure your ACP-compatible editor to launch:
autolith acpAuthenticate the selected provider with autolith auth before starting the
editor session. ACP uses UTF-8 JSON-RPC on stdin/stdout; diagnostics go to stderr.
The normal launch loads durable mutations and user initialization. For AUI, use
autolith --permissions auto acp. Use --pristine when recovering from a damaged
mutable image.
New sessions use the editor’s absolute working directory and a durable Autolith conversation ID. Load that ID to replay messages, visible reasoning, tool calls, and results. Text prompts, resource links, and embedded text resources are supported. File and process operations use the native Autolith tools.
The default ask mode requests command and external-tool approval in the editor.
An approval for the session covers the exact command and working directory, or
external tool identity and arguments. Select auto, sandboxed, or full-access
through ACP session modes; use --permissions auto|sandbox|full on the command
line. Changing modes clears session approvals.
Client-supplied stdio and HTTP MCP servers are merged with native registrations for that session. Literal environment values and headers are ephemeral and redacted from server output. Cancel a prompt to stop its provider, tools, and owned jobs; close the session or disconnect to release its resources and lease. One primary prompt, setting mutation, tool invocation, or session setup runs at a time in each ACP process. Catalog reads and owned-job controls can run alongside it.
Request _autolith/capabilities to discover installed methods and schema version.
Include sessionId in every other extension request. Responses contain outcome
(ok, condition, busy, unsupported, or cancelled), with value on success
and a bounded report on failure. Unknown measurements are JSON null.
| Method suffix | Value or action |
|---|---|
state | Session, turn, model, permission, usage, plan and health snapshot |
settings, models, operations | Typed catalog items |
set-setting | Set name to value; return the updated setting row |
invoke | Invoke operation with JSON arguments; return presented text |
steer, queue | Durably admit primary text; return accepted and delivery |
conversations | Page durable conversations using limit and cursor; optionally filter cwd |
jobs, job | Page owned jobs or inspect one jobId |
job-transcript | Read jobId with offset, limit and output (text or structured) |
job-send, job-cancel | Send text to or cancel an owned jobId |
resource | Read bounded workspace: lines or shell-log: bytes from uri |
Prefix these suffixes with _autolith/. Catalog operations expose admission and
availability; tools use their native decoders and ACP approval callbacks.
Terminal-only operations return an explicit unsupported outcome. Workspace resource
windows use startLine and lineCount and include the observed revision. Shell-log
windows use byteOffset and byteCount and require session ownership.
Invoke ordinary commands with arguments: {"input": "..."}, using native command
arguments without the command name. text is an alias for input. Commands such
as skills, hurry-up and papercuts return their presented text. Operations with
terminalWithoutArguments require an argument to avoid a terminal picker. During
an active turn, native inspection and execution policies apply; boundary-applied
commands return delivery: "scheduled" and present their results as ACP updates.
steer delivers text at the next safe boundary, including submissions made while
an approval is pending. Late steering is promoted ahead of ordinary queued
follow-ups. queue appends a follow-up for the next available primary turn.
Both accept up to 262144 characters and return delivery: "steering" or "queued".
Display accepted input separately until its durable user_message_chunk arrives.
Cancellation pauses pending input; a new submission resumes it. Accepted input
survives session close and reload. ACP has no per-item withdrawal operation.
For structured child transcripts, value.updates contains ordinary ACP
SessionUpdate bodies, with messages, reasoning, tool calls and result content.
Offsets count updates from zero; the default limit is 100 and the maximum is 200.
The typed response envelope is bounded to 262144 UTF-8 bytes. A single update over
that bound returns a condition instead of advancing the cursor. nextOffset is
JSON null when complete is true, meaning the current snapshot is exhausted.
For a running child, poll again from total to read later updates. Text output
uses character offsets and retains its existing numeric end cursor.
Treat _autolith/event state and catalog notifications as invalidation hints.
Refetch the affected snapshot after a sequence gap. Events with kind turn are
ordered lifecycle boundaries: data contains state (running or idle), an
integer epoch, source (prompt, queue, completion, or invoke), and a terminal
outcome (end-turn, cancelled, or condition; null while running). Match the
epoch when handling approvals, cancellation and transcript boundaries.
Automatic job continuations stream through ordinary ACP updates. Cancellation or an inference failure pauses continuation; submit an explicit prompt to resume.
Autolith’s image can be your Common Lisp development image. emacs/autolith.el
in the source tree sets up one frame with three windows: your code, a sly REPL
connected to Autolith’s own image, and an agent-shell conversation with the same
Autolith. What you define in the REPL lives beside the agent, which can inspect
it and advise.
The sly REPL spans the bottom quarter of the whole frame. Above it, edit code on the left and converse in the right third.
Install sly and agent-shell, load the file, and run M-x autolith-ide from the
buffer you are editing:
(load "/path/to/autolith/emacs/autolith.el")Optional Sly contribs need their Lisp dependencies in Autolith’s image. For
sly-stepper, install agnostic-lizard in a persistent ASDF source registry
visible to the Autolith process before Slynk starts.
autolith-ide starts the Emacs server if needed and launches autolith acp
through agent-shell with three environment variables:
AUTOLITH_SLYNK_DIRECTORYis your sly’s ownslynk/directory, so the server speaks exactly your client’s protocol. Autolith loads thatslynk.asdby path and compiles it into the ASDF cache on first use.AUTOLITH_SLYNK_PORT_FILEreceives the loopback port once Slynk listens, orerror: REASONwhen it cannot start.autolith-idewaits for it, up toautolith-slynk-timeoutseconds, and connects sly.AUTOLITH_EMACS_SERVERis this Emacs’s server socket and enables theemacs:resources andemacs.*tools.
M-x autolith-agent-shell starts only the conversation, with Emacs access and
without Slynk. The same variables, or the :slynk-directory,
:slynk-port-file and :emacs-server-socket settings, work outside Emacs. In
the terminal, (slynk) starts Slynk and shows the port for M-x sly-connect,
and (slynk "stop") closes it.
The agent reaches your definitions with lisp.describe, lisp.source and
lisp.apropos using target self, or with self.eval. While Slynk serves, a
context note tells it so. Your Emacs appears to the agent only while the
configured server socket exists:
emacs:current, read withresource.read, lists authorized visible windows with point, the active region and open file buffers, each by itsemacs:buffer/NAMEURI. Outside-root files and non-file buffers require full-access approval; denied buffers are omitted from this snapshot.emacs:buffer/NAMEis a live buffer’s text, unsaved edits included, with the buffer name percent-encoded.resource.editapplies line operations to the buffer itself: the change stays unsaved and undoable, and is refused as stale when you edited the buffer since the agent read it. A buffer visiting a file outside the workspace and source roots asks the same permission as that path.emacs.visitshows a file position in a file window of the selected frame.emacs.evalevaluates Emacs Lisp. It asks command authorization foremacs.eval -- FORMand runs only with full access.
Slynk listens on 127.0.0.1 only. Like ordinary sly it has no authentication
beyond the optional ~/.sly-secret, so anyone who can reach loopback on this
machine can evaluate in the image. Your code shares the agent’s heap: a fatal
error or (sb-ext:exit) ends the session, which recovers like any crash.
Slynk’s debugger and output hooks stay off for Autolith’s own threads, so your
REPL sees only your evaluations. A checkpoint stops Slynk, closing sly
connections, and serves the same port again; reconnect with
M-x autolith-ide-reconnect. A checkpoint waits for in-flight sly evaluations
and fails if they exceed the shutdown timeout.
Autolith uses the ordinary inline terminal presentation by default. Opt into the application-owned fullscreen viewport for a session with:
autolith --fullscreenSave the preference for future launches at the Autolith prompt:
(preferences-set-fullscreen (application-configuration *active-application*) t)The fullscreen viewport keeps the transcript scrollable and pins the composer to
the bottom. Use PageUp and PageDown for page movement, Ctrl-PageUp and
Ctrl-PageDown to jump between the user and assistant messages while skipping
the reasoning and tool activity in between, Ctrl-Home and Ctrl-End for the
oldest and newest transcript positions, and the mouse wheel for incremental
scrolling. The --fullscreen command-line option enables it for one launch
without changing the saved preference.
Pass nil to preferences-set-fullscreen to return future launches to inline mode.
Because the viewport owns the mouse, hold Shift while dragging to select text
with the terminal emulator. Fullscreen history lives in the application rather
than the terminal emulator’s native scrollback.
For input with matching saved memories, a dim @ N relevant memories exist line
appears below your message. Its count is the number offered to the model for that
request. Each input gets one notice across tool calls and provider retries.
Input recall includes every user message, command, and Lisp submission in the conversation. Automatic messages and assistant output are excluded. On first use, the complete input-only sidecar is built from the conversation records; later submissions are appended to it. Resuming reads this sidecar instead of replaying archived transcript chunks.
Clicking a web address in the fullscreen transcript opens it in the default
browser, and every fenced code block ends with a ⧉ copy label that copies the
block’s source. Copies go to the host clipboard through wl-clipboard, xclip or
xsel, pbcopy, or the Windows clipboard, and the terminal also receives an OSC 52
request, so a terminal reached over SSH or a localgroup relay copies on your own
machine. Web addresses in every mode are emitted as OSC 8 hyperlinks, which
terminals open with their usual modifier-click.
Fullscreen startup presents a brief Lisp-machine boot screen with a centered tip and a rock mascot that adapts to short viewports, then the session banner and transcript above the composer. Mouse wheel scrolling also works through a controlling local-session attachment.
The boot screen then waits for Space or Enter before opening the listener,
rotating the startup tip every ten seconds while it waits. Ctrl-C on the
waiting boot screen halts the session. Turn the wait off for future launches
with (setf (config :boot-screen-linger-p) nil) or for one launch with
AUTOLITH_BOOT_LINGER=off, and change the rotation with
(setf (config :boot-screen-tip-seconds) 30) or AUTOLITH_BOOT_TIP_SECONDS.
The animation takes (config :boot-screen-seconds) in total, 3.5 by default
and also set by AUTOLITH_BOOT_DURATION, shared evenly by its phases. Skip the
boot screen entirely with (setf (config :boot-screen-p) nil) or
AUTOLITH_BOOT_SCREEN=off; (settings) lists all four.
autolith --almightyforces the fullscreen viewport and presents the Almighty Lisp theme from
almightylisp.com: near-white text on the site’s
blue, yellow for everything emphasized, cyan for code and strings, and an
ALMIGHTY LITH boot mark. Terminals that advertise true color through
COLORTERM get the exact colors; others get the nearest indexed or basic
ones. The theme sets the terminal’s default colors only while the viewport is
active and restores them on exit. Save it for future launches with
(setf (config :terminal-theme) :almighty); :autolith restores the default
presentation. Detached sessions carry the theme across handoff.
Nix is the simplest way to install Autolith:
nix run github:luciusmagn/autolithThe first launch builds Lisp images Autolith needs to launch.
These images live under ${XDG_DATA_HOME:-~/.local/share}/autolith/nix/images/}.
It is possible to install autolith on Linux x86_64 via a shell installer:
curl -fsSL https://sh.lambda-symbolics.com/autolith | shThe installer verifies the release archive’s SHA-256 before extraction. The checksum must identify that exact archive; malformed or missing checksums abort installation. The initial shell script is fetched over HTTPS.
Read the installer before piping it to a shell, or use Nix if that tradeoff is unwelcome. Linux binary releases require OpenSSL and Bubblewrap. Bubblewrap provides the filesystem and network isolation used for sandboxed command execution. The installer names the missing dependency instead of installing a release that cannot offer sandboxed or safe automatic execution. The launcher uses the installation layout, rather than an environment marker alone, to distinguish binary, Nix, and source starts.
Autolith automatically checks for updates at most once every 20 hours. To install the latest binary release and exit without starting a session:
autolith updateThe command exits successfully when updated or already current, and returns a
nonzero status if checking or installing fails. autolith --update is an
equivalent update-and-exit alias. Run autolith afterward to start the new
release. Both spellings accept --help or -h; extra arguments exit with status
64 before checking for updates. Use your flake or Nix profile to update Nix
installations; update the checkout and run ./script/bootstrap for source
installations. These installations explain their update mechanism without
building or starting Lisp images.
To update from a session and restart it with its original command arguments:
(update)Release archives are built and checked by the installer host. GitHub publishes release metadata after the host checksum is available. See Release service.
For a fresh macOS machine:
brew install sbcl rust cmake pkg-config openssl@3
curl -o /tmp/quicklisp.lisp https://beta.quicklisp.org/quicklisp.lisp
sbcl --no-sysinit --no-userinit --load /tmp/quicklisp.lisp \
--eval '(quicklisp-quickstart:install)' --quitOn Linux, also install Bubblewrap with your distribution’s package manager.
Autolith uses its bwrap executable to isolate the host filesystem and network
for sandboxed commands and the sandboxed decisions made by automatic permission
mode. Nix installations include it. Bubblewrap is not a macOS or BSD dependency.
Without platform sandbox support, the sandbox choice is unavailable; explicit
once, always, and full approvals run with the user’s full privileges.
With Quicklisp in ~/quicklisp, bootstrap and check the checkout:
./script/bootstrap
./script/checkThe check runs FiveAM tests in isolated SBCL processes, defaulting to the available logical CPU count (one worker if detection fails), and verifies the pristine recovery image. Each run first saves an active image of the checked source, so cases that start a fresh Autolith boot that core instead of loading the system. List or select test suites and individual cases with:
./script/check --list
./script/check --suite workspace-resource --suite fixtures
./script/check --test test-workspace-file-resources --jobs 1
./script/check --jobs 8 --timeout 900Selected runs skip recovery probes. Selectors are exact, case-insensitive names
and can be repeated; unknown names fail. --jobs controls process concurrency,
and --timeout sets the deadline per worker in seconds (default 600). Results
include per-case timings and the slowest cases. AGENTS.md documents test
registration, reusable fixtures, and interactive Lisp entry points.
To put a checkout into PATH:
mkdir -p ~/.local/bin
ln -sfn "$PWD/bin/autolith" ~/.local/bin/autolithThis is assuming you have .local/bin/ in PATH.
For the Windows x86-64 development artifact, extract the archive into a writable
folder and run .\bin\autolith.cmd from PowerShell. Use Windows 10 version 1903
or newer. The bundled SBCL executable has a UTF-8 process manifest for Unicode
paths; system-wide locale changes and 8.3 filenames are unnecessary. The first
launch builds per-user cores under .autolith-images beside the release.
To build the source checkout, install Git for Windows, Rust with the MSVC toolchain
and Cargo, and Quicklisp under %USERPROFILE%\quicklisp. Put clang on
PATH for the ColorLisp syntax library. An SBCL 2.6.6 or newer on PATH is
used when present; otherwise the bootstrap downloads the official SBCL Windows
binary pinned in sbcl-windows-releases.sha256, verifies its SHA-256, and
unpacks it below the data root without registering it with Windows. OpenSSL 3
comes from Git for Windows, from AUTOLITH_OPENSSL_DIRECTORY, or from a
native\openssl directory beside the sources.
From PowerShell, bootstrap and check the checkout:
script\bootstrap.ps1
script\check.ps1script\check.ps1 takes the same selectors as ./script/check. Checks that
need FIFOs, forked children, pseudo-terminals, POSIX file modes, or the POSIX
shell are recorded as skipped. To package a Windows archive, install the Windows
SDK (including mt.exe) and run script\package-windows-release.ps1 -Tag VERSION.
The POSIX release-server scripts are not built on Windows.
Start a session with bin\autolith.cmd or bin\autolith.ps1; both take the
arguments bin/autolith takes. Windows Terminal is the primary console;
legacy consoles without virtual-terminal input are refused with a message.
Windows sandboxed commands use the bundled AppContainer helper. They can write in the workspace and a private temporary directory, read system applications and explicit tool directories, and have no network access. Repository metadata is protected. Bootstrap builds the helper with Clang; release archives include it.
Windows supports supervised detached sessions, client-first starts, and exact-heap
restart checkpoints. It withholds fork-based checkpoint saving and the unix
management REPL transport.
To remove Autolith and keep your data:
autolith uninstallThe launcher lists what it will remove, asks for confirmation, and exits without
starting a session; --yes skips the prompt, which is required when no terminal
is attached. It removes the packaged installation and its command link, managed
SBCL runtimes, the active and recovery images, retained generation cores, saved
worker images, Nix image trees, release markers, crash capsules, launcher
pointers, session sockets and leases, provider caches, and the cache root.
User data stays in place: conversations, inference traces, memories, papercuts, agendas, plans, pending input, private image commits, the mutation journal and mutation history, permissions, preferences, credentials, and the configuration root. Stop running sessions first. A source checkout stays as well; delete it yourself. Nix installations also need the package removed from the flake or profile. On Windows the launcher prints the folders to delete, because the runtime in use lives inside them.
Ordinary text is a prompt to the primary agent. It is equivalent to:
(prompt :to 'autolith "Review this change")autolith is reserved, case-insensitively, for the primary agent.
As a shortcut, if you want to submit something to the main agent, you don’t need to include the :to parameter:
(prompt "Shut yourself down homie")prompt can also compute text or attach local images:
(prompt (read-file "request.org"))
(prompt :images "/tmp/diagram.png" "Review this diagram")
(prompt :to 'test-review "Run focused tests and report failures.")If you message a sub-agent, it can respond to you in the main conversation thread if it wants to.
Start a message with ( to evaluate it as Common Lisp in the active image:
(help)
(resource.read :uri "workspace:.")
(eval-now (setf *print-pretty* nil))Use (help) for a short overview. Choose a topic or look up one command:
(help :conversations)
(help :workspace)
(help 'resume)
(help "lisp.eval")Keyword topics open sections. Quoted symbols and strings open command or tool
help, including usage and parameter descriptions. Browse tools by namespace with
(help :lisp), list all commands with (help :commands), or request the full
reference with (help :all). Help uses the terminal Markdown renderer and Lisp
syntax highlighting.
Press Tab after =(help = to browse topics and registered operations. Command
options also appear after a command name and a space, for example =(ste =.
Type @ in prose or inside a Lisp string to fuzzy-search workspace files
through fff. Accepting a match inserts the path and drops the @.
Directories keep a trailing slash so you can keep completing. A completed
file stays in the draft.
The clanker sees both your source input and its evaluated result apart from any other effects it may have.
Start input with ? followed by whitespace to evaluate one form asynchronously
in the active image. Use this for a blocking operation or a bare variable:
? *package*
? (progn (sleep 10) (values :finished 42))The editor displays ? in place of the normal prompt. Submit with Enter, then
continue using the session while the form runs. ?? and ?text are chat;
spaces, tabs, and line breaks after ? select asynchronous Lisp. Continue an
incomplete form on another line as with ordinary Lisp input.
Inspect or cancel the returned exec:N job with job.get, job.wait, or
job.cancel. Standard output, error output, and Lisp diagnostic streams are
captured with bounded retention and rate-limited, sanitized terminal display.
On completion, receive all returned values or the error, together with captured
output. Asynchronous evaluation uses noninteractive error handling and EOF input
rather than a restart picker.
The submitted form and its eventual result are retained in the originating session, including across a session switch. The model receives these messages at a safe request boundary; submitting a form does not start a model turn.
When local Lisp or an interactive command signals a serious condition, the
restart debugger keeps the signaling stack and its live restarts available. Use
Ask Autolith why this failed to run an independent diagnosis while the failed
operation remains suspended. Diagnosis can offer up to three explicitly selected
recoveries that invoke a live restart, run repair source first, retry the whole
operation, return replacement values when supported, or abort the operation.
Retry does not roll back effects completed before the failure.
The debugger shows the condition type and report, followed by available details such as the offending value, expected type, operation, filename, and reader location. These fields come from the condition itself and are also included in model diagnosis.
Escape during diagnosis cancels only the diagnosis and returns to the live restarts. Escape at the ordinary restart picker aborts the failed operation. During an active provider turn, Escape cancels the turn and continues queued steering in submission order, oldest first. Ctrl-C cancels and pauses queued work until you submit input; a second interrupt within the force-exit window exits the application.
Run (vault-store) to move queued work and unconsumed steering into the recovery
input vault immediately, including during an active turn. Active work continues.
Use (vault-contents) to read the parked entries in restoration order and setf
to replace the whole list or one zero-based entry:
(vault-store)
(vault-contents)
(setf (vault-contents 0) '(:message "Revised task"))
(setf (vault-contents) '((:message "First task") (:lisp "(+ 1 2)")))
(vault-restore)Entries are (:message INPUT), (:command TEXT), or (:lisp SOURCE).
Direct vault reads and top-level setf forms containing only vault-contents
places execute during an active turn. Returned lists are detached snapshots;
publish edits with setf. Use (setf (vault-contents) nil) to clear parked input.
Run (vault) for a summary or (vault-restore) to prepend parked work to the
live queue.
resource.read observes durable state and returns an opaque revision.
resource.edit applies a resource-specific operation only against that exact
observation.
For multi-file semantic changes, Autolith prepares a cl-resources change set
against retained file revisions and validates every member before publication.
Each file is published atomically. On a later failure, Autolith restores earlier
members; conflicting external updates require explicit recovery rather than
replacement. File moves preserve source permissions captured during staging.
Papercuts use current-workspace resource URIs:
papercut:currentlists active reports and acceptspapercut-report.papercut:id/<percent-encoded-stable-id>reads one active report and acceptspapercut-closewith a complete resolution.
The existing papercut.report tool and (papercuts), (papercut "ID"), and
(papercut-close "ID") commands remain convenient direct interfaces.
Conversation history uses read-only resource URIs:
conversation:currentis the current conversation’s complete durable history, including the records compaction removed from the model context. A plain read returns the newest records;start-sequenceandrecord-count(default 20, maximum 200) page by durable record sequence. A window holds at most 7,000 characters and shortens long records, so read a record alone to see all of it.- With
query, the read lists the newest records containing every whitespace-separated term, each with its sequence and an excerpt. ASCII letters match in either case and other characters match exactly.max-resultsdefaults to 20 and is capped at 50. Messages, assistant replies, reasoning summaries, tool call arguments and outputs, web searches, and compaction summaries are searched. conversation:id/<id>reads or searches another conversation by its identifier. Searches never span several conversations.
Each model report is acknowledged durably in the conversation, and a report that repeats an active papercut of the workspace is not recorded again: a title matching word for word, or a title and body whose words largely overlap a report from the last day, answers with that existing report instead. A conversation re-filing within an hour of its own report is matched more loosely, since rewritten repeats share fewer words.
Use the same portable archive from the command line or an active session:
autolith data export all.sexp --all
autolith data export project.sexp --workspace /home/al/code/project
autolith data import project.sexp --workspace /home/al/src/project(data.export "all.sexp" :all)
(data.export "project.sexp" :workspace "/home/al/code/project")
(data.import "project.sexp" :workspace "/home/al/src/project")Export defaults to all workspaces and global data. A workspace export contains its conversations, memories, agendas, plans, papercuts, and associated session assets. The archive contains Autolith data rather than the repository files; clone or copy the repository separately. Credentials, configuration, executable image state, and caches are excluded.
Import preserves stable identifiers and merges into local data. Identical data
is skipped; a conflicting identity aborts the import before publication. For a
single-workspace archive, --workspace DIRECTORY or :workspace "DIRECTORY"
sets its new home directory. Without that option, workspace locations are
preserved. Relative paths are resolved against the current working directory.
Export creates a new private archive and refuses to overwrite an existing file.
The CLI exits without starting a session: success is 0, invalid arguments are
64, and transfer failures are 1. Both command groups provide --help.
A session gets an immediate local title from its first prompt or image. After the third actual user turn, Autolith may ask the active model for one concise replacement and persist it with the conversation. The local title does not depend on provider generation.
Provider-generated refreshes are enabled by default. Use (titles),
(titles "on") or (titles "off") to inspect or change the durable global
preference.
(resume) displays titles in its picker while an explicit (resume "ID")
continues to address the stable conversation identifier. The
terminal status bar and local session status display the title when one is
available and otherwise show the conversation ID.
A resumed conversation runs in a fresh process, so background jobs,
asynchronous shell runs, and Lisp worker state from before the restart no
longer exist. The first user turn after a resume carries a request-local notice
telling the model so, which keeps it from polling or waiting on dead jobs. Only
durable child task results stay readable through job.get.
Inspect a saved conversation without resuming or locking it with:
autolith replay ID
autolith replay ID turn 12
autolith replay ID date 2026-08-28
autolith replay ID time 2026-08-28T10:30:00
autolith replay ID sequence 1200On an interactive terminal, replay behaves like a small debugger over durable
conversation events. next and previous step records; turn, date, time,
and sequence jump to a location; raw shows the selected replay form; and
quit exits. Replay reads complete persisted forms without acquiring the
conversation lease or repairing, appending, or resuming the conversation.
Every running Autolith session publishes a private authenticated local endpoint.
Its session ID is the active conversation ID, shared with resume and stable
across detach, restart and checkpoint quiescence. Selecting another conversation
with new, resume or fork moves the endpoint to that conversation ID while
attached terminals continue using the same connection. Inspect endpoints with:
autolith localgroup status
autolith localgroup status --sexpidle means that the process is at input with no active work of any kind.
Control a sessions with the following commands:
autolith localgroup tell SESSION-ID "message"
autolith localgroup pause SESSION-ID
autolith localgroup attach SESSION-ID
autolith localgroup attach SESSION-ID --read-only
autolith localgroup attach SESSION-ID --take-over
autolith localgroup detach SESSION-ID
autolith localgroup kill SESSION-IDUse a full SESSION-ID or a prefix that matches one session. Prefixes accept
IDs with or without the display hyphen, for example b, b-6, or b6 for
b-6uouHJ. Full IDs take priority over prefix matches. If a prefix matches
more than one session, the error lists the matching IDs; use a longer prefix.
Current IDs are case-sensitive. Legacy hexadecimal IDs accept either case.
tell uses input to tell something to a session and resumes a paused session.
pause cancels active work and holds queued primary work.
kill requests graceful shutdown.
Detaching hands a session to a supervised process group that outlives the
terminal. Windows has no process groups or detached sessions, so sessions
there always run directly in the terminal that started them: (detach) and
client-first starts report that the handoff is withheld, while the loopback
endpoint and the localgroup commands work as elsewhere.
Autolith stores configuration, durable data, process state, and replaceable
caches below ${XDG_CONFIG_HOME:-~/.config}/autolith/,
${XDG_DATA_HOME:-~/.local/share}/autolith/,
${XDG_STATE_HOME:-~/.local/state}/autolith/, and
${XDG_CACHE_HOME:-~/.cache}/autolith/. XDG base-directory values must be
nonempty absolute paths; invalid values use these defaults. Newly created
Autolith roots have mode 0700.
On Windows the same four roots are, unless an absolute XDG variable overrides
one, %APPDATA%\autolith\, %LOCALAPPDATA%\autolith\data\,
%LOCALAPPDATA%\autolith\state\, and %LOCALAPPDATA%\autolith\cache\.
Private files and directories carry an access control list granting only the
owner and SYSTEM, which is what mode 0600 and 0700 mean there; a file
Autolith publishes read-only withholds write access through that list and
keeps the read-only attribute clear, so it can still be replaced and deleted.
Conversation leases, Localgroup endpoint records, and recovery state live under
${XDG_STATE_HOME:-~/.local/state}/autolith/ rather than XDG_RUNTIME_DIR.
They must survive logout so detached sessions, handoffs, and crash recovery can
continue across login sessions. Autolith uses authenticated loopback TCP rather
than filesystem sockets for its inference and Localgroup protocols, and cleans
stale Localgroup records itself.
Autolith loads the optional user file
${XDG_CONFIG_HOME:-~/.config}/autolith/init.lisp after tracked code, a
selected private image commit, and any site or trusted directory
configuration. It reloads on retained generation reconnect.
The file is ordinary Common Lisp in package AUTOLITH, with your full
privileges. It is not copied into private replay or the pristine recovery
image.
Packagers may supply one separate, read-only configuration tree with
--site-config-root DIRECTORY or AUTOLITH_SITE_CONFIG_ROOT. The directory
must already exist and be absolute. It may contain init.lisp, mcp.sexp,
skills/, and agents/. Site configuration loads before user configuration,
so it provides defaults without replacing the user’s normal XDG tree. A site
init.lisp has the same full privileges as user initialization and is not a
security boundary.
Executable initialization loads in this order:
- site
init.lisp - trusted directory
.autolith/init.lispfiles, outermost to nearest - the user XDG
init.lisp
Missing files are ordinary. A present file that cannot be read or evaluated
fails startup or reload with its exact pathname. directory-scopes.sexp
is user-owned.
Every knob Autolith exposes is a named setting with a type, a description, a
default, and, where the choices are finite, its options. (settings) opens the
settings page: a picker listing each setting with its current value and where
that value came from. Choosing an adjustable setting opens its options;
choosing a read-only one explains why it cannot change in a running session.
The page returns to the list after every change until you cancel.
The same operations work without the page. (settings "NAME") describes one
setting, (settings "NAME" "VALUE") changes it, and (settings) called from
a script, where no picker can open, prints every setting grouped by area. Values are written as they appear on the page: on
and off for switches, option names for choices, and integers or paths as
text. A change to a durable setting is saved at once for future sessions.
Settings live in one of four scopes. Durable settings, such as the model,
reasoning effort, Fast mode, reasoning traces, compact view, timestamps,
cache miss notices, Simple Technical English, generated titles, fullscreen,
and the saved permission mode, persist in preferences.sexp under the state
directory. Session settings, such as hurry-up mode, last until exit. Process
settings, such as the immutable flag, the management endpoint, and the roots,
come from the command line, the environment, or defaults at startup and stay
fixed. Derived settings, such as the context window and provider endpoint,
follow the model. The window uses a declared model value, else the catalog
value, else the default.
A durable value is chosen at startup from the first source that supplies it: an explicit command-line choice, the setting’s environment variable, then the saved file. A saved model or effort that no registered provider serves is dropped rather than applied.
From Lisp, user initialization and replay scripts read a setting with
(config :model), which uses the current configuration, or
(config :model configuration) for an explicit one, and change it with
(setf (config :reasoning-traces-p) t). Unknown setting names signal a
configuration error. Create an independent configuration with
configuration-copy.
The preferences file uses version 8: one flat record of setting names and values that keeps unknown keys. Before upgrading a preferences file from versions 1 through 7 to 0.54 or later, run a 0.53 release once to write version 8.
Install your language server, then configure it in lsp.sexp under Autolith’s
user configuration directory, alongside init.lisp. For example:
(:version 1
:servers ((:name "clangd"
:command "clangd"
:arguments ("--background-index")
:extensions (".c" ".h")
:language-id "c"
:root-markers ("compile_commands.json" ".git")
:timeout-seconds 30)))Configuration is declarative. Supply a unique :name, executable :command,
nonempty :extensions list, and :language-id for each entry. Arguments are
literal strings. Optional :initialization-options and :settings are JSON
object strings; :disabled-p t disables an entry. The request timeout is an
integer from 1 through 120 seconds, defaulting to 30.
Only configure commands you trust: language servers run with your privileges
and inherited environment, outside the shell approval sandbox. Keep credentials
out of this file. Executables must already be installed; commands are resolved
on PATH. Repository-local LSP configuration is not loaded.
Autolith exposes the lsp tools only when lsp.sexp defines at least one
enabled server; without it the registry omits them. A malformed lsp.sexp
keeps the tools registered so the configuration error surfaces when a tool
runs. When at least one server is enabled, each provider request includes a
context note naming those servers.
Ask Autolith to use these tools:
lsp.status: inspect configuration and running project/server pairs.lsp.query: requestdefinition,references,hover,implementation,type-definition,document-symbols, orworkspace-symbolsfor a workspace file. Position queries require one-basedlineandcharactercoordinates, with columns measured in UTF-16 code units. For workspace symbols, supplyquery; the file selects the project and server.lsp.diagnostics: synchronize a file and retrieve diagnostics.lsp.restart: stop servers and reload the configuration after changing it.
Use lsp.semantic for revisioned transformations:
prepare-rename: inspect the symbol atpath,lineandcharacter.rename: propose a symbol rename with those coordinates andnew-name.code-actions: discover choices for a range, usingline,character,end-lineandend-character. Optionally filteronlyaction kinds or supplydiagnostics.resolve: retrieve a complete action using its returnedchoiceID.propose: retain an action’s edit as an applicable proposal usingchoice.move: propose server preparatory edits followed by movingpathtonew-path. Both paths must identify regular files or a missing destination.inspect: review a retainedproposalID.apply: apply a retainedproposal. Obtain explicit approval for annotations withneedsConfirmation, then include their IDs inapproved-annotations. Confirm each syntheticlsp.semantic-confirmationrequest through the ordinary command-permission prompt. Without a permission callback, confirmation is denied.
Proposals preserve ordered text, create, move and delete effects. Every affected
file passes the ordinary resource authority checks before observation and again
before application. Resource revisions cover file kind and content; synchronized
document versions must also match. Request a fresh proposal after a conflicting
edit or server restart. Moves preserve the source permissions captured during
staging, including edited multi-hop moves. Publication is atomic per file with
change-set rollback on failure. Proposals and action choices own their exact
snapshots and are conversation-local. Retain up to 32 choices, 240,000 encoded
characters per choice, 128 resources per choice, and 512 resources or 16 MiB of
UTF-8 snapshots per conversation. Older choices expire when those budgets fill.
Server commands are presented as data for separate explicit execution.
Use local file:/// URIs; directories, service resources and URI authorities
are unsupported.
Servers start lazily on file requests, including diagnostic requests after a
successful resource.edit workspace edit. All enabled entries with matching
filename suffixes are queried. The project root is the nearest ancestor with a
configured root marker, bounded by the workspace; otherwise it is the workspace.
Open files are refreshed from disk before queries, including shell edits.
Results contain native file URIs and zero-based UTF-16 ranges. Push and pull
reports are retained independently and combined, removing duplicate items.
Diagnostic state received identifies versioned reports, unversioned means a
report’s snapshot cannot be confirmed, and pending means no report arrived.
The sources field gives push and pull freshness separately.
Explicit diagnostics allow two seconds for push reports and use the configured
request timeout for pull requests. Edit follow-ups have one shared one-second
blocking deadline across lock acquisition, startup, synchronization, and all
matching servers, with at most half a second for push settling. Failed startup
also reaps its process. If automatic diagnostics time out, use lsp.diagnostics
for the full server timeout. Reports retain at most 200 diagnostics per file and
mark truncation. Files are limited to 2 MiB, with 64 open documents per server
and 16 live project/server pairs per registry. Use lsp.restart to release them.
Server shutdown occurs when the tool runtime is retired.
The management REPL is a separate opt-in subsystem for trusted programs that
must evaluate Common Lisp in the running AUTOLITH image. It is image-daemon’s
evaluation endpoint, whose eval-connect and eval-call form a complete Lisp
client, and does not use the localgroup protocol, Swank, or Slynk. It is
disabled unless AUTOLITH_MANAGEMENT_REPL is set to on.
Every connection authenticates with a fresh random nonce and HMAC-SHA-256. The
client never sends the reusable token. Put a nonempty token in a regular file
owned by the current uid with mode 0600. Autolith opens that file without
following symbolic links only while checking a proof, wipes the token octets,
and retains only the token-file pathname.
The following environment variables configure newly created applications:
| Variable | Default | Meaning |
|---|---|---|
AUTOLITH_MANAGEMENT_REPL | off | Enable the endpoint. |
AUTOLITH_MANAGEMENT_REPL_TRANSPORT | unix, or tcp on Windows | unix or tcp. |
AUTOLITH_MANAGEMENT_REPL_UNIX_SOCKET | ${XDG_STATE_HOME:-~/.local/state}/autolith/management/repl.sock | Unix socket pathname. |
AUTOLITH_MANAGEMENT_REPL_TCP_ADDRESS | 127.0.0.1 | IPv4 loopback listener address. |
AUTOLITH_MANAGEMENT_REPL_TCP_PORT | 4141 | TCP listener port. |
AUTOLITH_MANAGEMENT_REPL_TOKEN_FILE | ${XDG_CONFIG_HOME:-~/.config}/autolith/management-repl.token | Mode-0600 token file. |
AUTOLITH_MANAGEMENT_REPL_TIMEOUT | 10 | Evaluation deadline in seconds. |
AUTOLITH_MANAGEMENT_REPL_MAX_FRAME | 1048576 | Maximum wire-frame octets. |
AUTOLITH_MANAGEMENT_REPL_MAX_SOURCE | 262144 | Maximum UTF-8 source octets. |
AUTOLITH_MANAGEMENT_REPL_MAX_OUTPUT | 262144 | Maximum captured output and value text. |
AUTOLITH_MANAGEMENT_REPL_QUEUE_CAPACITY | 8 | Maximum queued evaluations. |
AUTOLITH_MANAGEMENT_REPL_MAX_CLIENTS | 8 | Maximum accepted clients, including authentication. |
AUTOLITH_MANAGEMENT_REPL_AUTH_TIMEOUT | 10 | Absolute authentication deadline in seconds. |
TCP accepts IPv4 loopback addresses only. This endpoint does not provide server
TLS, and arbitrary Lisp results may contain secrets. Challenge-response prevents
bearer-token replay, but an unauthenticated local process can relay a challenge
and proof between trusted local clients. Treat loopback TCP clients as locally
trusted. Unix transport creates a
mode-0700 private directory and a mode-0600 socket. Startup refuses an active
socket and any alien or non-socket path; it removes a socket only after proving
that it is a stale current-user endpoint. Windows has no filesystem sockets, so
unix is refused there with a message and tcp is the default.
Each message is a four-octet unsigned big-endian length followed by exactly that
many UTF-8 octets containing one readable S-expression. Length zero, oversized
or truncated frames, invalid UTF-8, malformed syntax, and trailing forms are
rejected. Readers use standard I/O syntax, a fresh standard readtable, and
*read-eval* nil.
The server starts each connection with:
(:challenge :version 1 :algorithm :hmac-sha-256 :nonce HEX)HEX encodes 32 random nonce octets as 64 lowercase hexadecimal characters.
The client reads its token file, computes HMAC-SHA-256(token, nonce), and
replies:
(:authenticate :proof HEX)A valid proof receives (:authenticated :version 1). A proof is valid only for
that connection’s nonce. Authentication failure closes the connection without
a reusable credential or detailed oracle response.
After authentication, send one request at a time:
(:evaluate :source "(values (+ 20 22) *package*)")The source string must contain exactly one form. A dedicated serial evaluator
thread reads it in package AUTOLITH, applies the configured deadline, prevents
interactive debugger entry, and captures standard, error, trace, query, debug,
and terminal output in a bounded Gray stream. Successful responses have this
shape:
(:evaluation-result
:status :ok
:values ("42" "#<PACKAGE \"AUTOLITH\">")
:values-truncated-p nil
:output ""
:output-truncated-p nil):values contains one bounded readable string for every multiple value.
Conditions return :status :condition, a bounded :condition-type and
:report, captured output, and truncation flags. Deadline expiry returns
:status :timeout. The client may submit further requests on the authenticated
connection.
Evaluation deadlines use in-process interrupts and are best effort for trusted
forms; a form that suppresses interrupts may outlive its deadline. Checkpointing
stops the listener, clients, evaluator, and queue before saving the image and
restarts the endpoint afterward. If an evaluator cannot quiesce within the
documented two-second shutdown bound, checkpointing aborts with a
management-repl-error whose operation is :quiesce rather than saving live
management threads.
Normal shutdown is idempotent and
removes only the exact Unix socket created by that runtime.
Autolith has a concept of ephemeral notes, which can be used to add temporary additional information to the context that will eventually disappear:
(define-context-contributor release-advice (request)
"Add advice for release requests."
(when (search "release" (or (request-context-latest-user-text request) "")
:test #'char-equal)
(make-context-contribution
:identifier "release-check"
:instruction "Verify release artifacts before publishing."
:lifetime ':turn
:priority 40)))- A contributor sees a read-only request snapshot
- It can return none, one, or many contributions
- Notes stack unless they deduplicate, supersede, or conflict
- Priority only comes into play when the advice budget is full
- You can use
(context)
Note that these are provider-request-only, and don’t not count as a conversation turn, and do not get attached to your messages.
Register selective project or user advice as a declarative rule:
(register-context-rule
'(:id "lisp-edits"
:when (:paths ("src/") :languages ("common-lisp")
:events ("tool-success"))
:instruction "Check the changed declarations before committing."
:priority 30 :lifetime :while-relevant))Use :paths, :languages, :tools, :namespaces, :roles,
:diagnostics and :events in :when. Fields are conjunctive; values
within a field are alternatives. Paths match prefixes; other values match
exactly. Add an absolute :workspace directory for project scope. Authorized
tool operations and structured LSP severities supply bounded current-turn
metadata. Asynchronous completions use their originating turn identity.
Rules share the ordinary advice budget, priority, lifetime and deduplication
policy. Inspect delivery with context-status; remove a rule with
unregister-context-rule and its original ID.
The status line keeps a context meter visible while idle. It shows used tokens
and the full model window. | marks the automatic compaction point. The
ChatGPT subscription catalog currently reports a 272K-token window for the
GPT-6.1, GPT-6, and GPT-5.6 models, which compact at about 218K tokens by default:
ctx [==========|..] 218K / 272K used
At narrow widths, the meter keeps the used and window counts and drops the bar.
Use (compact) to compact the current conversation immediately,
regardless of the meter. It uses the same provider-native checkpoint and portable
summary path as automatic compaction. During an active turn, the command waits
in the idle queue. An empty conversation needs no provider request. Compaction
adds a durable checkpoint without adding a user message or starting a model turn.
The native checkpoint and the portable summary are two provider requests. Each
is recorded with its usage as a numbered request of the turn, so the request
count and the persisted usage cover compaction work instead of hiding it.
Before either request, Autolith captures a fixed history cutoff. The checkpoint
includes unresolved calls with correlated actual or interrupted/unknown outputs,
plus results and steering received during summarization. Running jobs and
undelivered outcomes are recorded separately from the model-written summary.
Ordinary requests include bounded authoritative job references and an omitted
count; inspect job.continuity, job.* and their resources for full details.
Provider-family changes use the portable handoff and exclude foreign private
context.
Providers bill context served from their prompt cache at a fraction of the
uncached input price, so a request that re-reads context the previous request
had cached costs noticeably more. (cache-misses "on")
enables a dim notice after any request whose cache reads fell below half of the
previous prompt, and after any request whose cache reads stopped growing while
the prompt grew and at least a sixteenth of the previous prompt, never less
than 4096 tokens, was re-read. The notice gives the re-read and total prompt
token counts and the likely cause: a model change, an idle gap past the roughly
five-minute provider cache lifetime, rewritten earlier context, a resumed
conversation whose cache had expired, a changed prompt prefix, or a stalled
prefix, which means the request reached a provider backend without the newest
cached context. When the provider attributes cache reads to request fields, the
notice adds whether the instructions and tools were re-read or still cached, so
a changed prefix is told apart from lost routing. The first request after
compaction is expected to miss and stays quiet. Autolith carries no price
table, so the notice reports tokens rather than currency. The setting is off by
default and persists across restarts.
Register a OpenAI-compatible provider:
(register-openai-compatible-provider
:name "my-provider"
:description "My OpenAI-compatible provider"
:endpoint "https://api.example.com/v1/chat/completions"
:models-endpoint "https://api.example.com/v1/models")List every model ID known to Autolith without authenticating or starting a session:
autolith models | grep gptThe command prints one sorted, deduplicated model ID per line from built-in and locally configured catalogs.
Inside a session, (auth) without a
provider picks one interactively, and (auth "my-provider") selects one
explicitly. Use
autolith auth my-provider to authenticate during startup.
After a key is saved, static metadata or the last good cache keeps models
available. (models) triggers discovery. You can also pass non-secret
:headers and static :models for descriptions, windows, efforts, or
providers that have no model-list endpoint.
Built-in ChatGPT subscriptions use browser OAuth with PKCE and a local callback
on localhost:1455 or localhost:1457 by default. Use
(auth "chatgpt" "device") or
autolith auth chatgpt device to select the device-code flow instead. The
browser authorization URL is always printed for manual use. Grok and Nous
Research use browser device flows. Gemini uses Google installed-application
OAuth with a local loopback callback.
Anthropic, Fireworks, OpenCode, OpenRouter, Mistral, and user-registered
OpenAI-compatible providers use API keys.
Authenticate a GitHub Copilot subscription with autolith auth copilot
or (auth "copilot"). Approve the displayed device code at
GitHub. Credentials are stored in the private copilot-auth.sexp under the
state root. Tokens renew automatically before expiry.
Login discovers tool-capable picker models and copilot/auto, and attempts to
enable unconfigured picker models. Models are named copilot/<model-id> locally
to avoid collisions with direct vendor subscriptions. Successful Copilot login
selects Auto and saves it as the default, unless the current Copilot model is
still available. Use (models) to refresh the catalog, then
(model "copilot/auto") to select Auto on an existing installation, or launch
with --model copilot/auto. Normal startup reads the last successful catalog
without a network request.
Use Auto with Copilot Student or Free plans, which do not offer manual model
selection. Each request resolves an account-authorized concrete model and uses
its Chat Completions, Responses, or Messages protocol with a short-lived session
token. Auto keeps the previous concrete model while it is available. Hidden
named models are not offered as manual choices. For other plans, select an
available named model with (model). Disabled picker models are excluded.
For GitHub Enterprise Cloud with data residency, set
AUTOLITH_COPILOT_DOMAIN to your TENANT.ghe.com hostname during both login
and subsequent launches. Tokens are pinned to that host and streams use the
subscription-specific endpoint returned by Copilot. Chat Completions,
Responses, and Anthropic Messages reuse the existing transports. This
integration uses GitHub’s internal Copilot endpoints, following pi and VS Code,
so it may require updates when GitHub changes that service.
ChatGPT Codex Fast mode sends service_tier=priority when the active Codex model
advertises Fast support. Fast responses count more heavily against plan usage;
the exact rate is set by OpenAI per model and is not tracked here. The built-in
GPT-6.1, GPT-6, and GPT-5.6 models support it. Use (fast) or (fast "status") to inspect it, and (fast "on") or
(fast "off") to change the saved preference. The activity status line displays
FAST while the active model uses Fast mode. Other providers and unknown Codex
models keep the preference but use the standard path. Set
AUTOLITH_CODEX_FAST_MODE=on or off to override the saved choice for one
process; while it is set, (fast "on") and (fast "off") are unavailable.
A request that fails before the model has produced anything is retried up to six times with jittered delays, since the failed attempt cost only the wait. Once reasoning or output has started streaming, every reconnect bills a fresh generation of the same prompt, so at most two such retries are made before the request fails with a stream-abandoned error. Every failed attempt is recorded in the conversation next to its request number with the attempt count, the elapsed seconds, whether output had been received, and the provider’s identifiers, so retry storms can be audited after the fact.
ChatGPT Codex uses standard Responses requests and native Responses compaction. Normal requests enable provider parallel tool calls. Autolith executes independent calls concurrently, then records their results in provider wire order. Calls requiring a provider round trip, exclusive tools, and calls sharing one mutable runtime execute in separate ordered waves.
GPT-5.4 and later Codex models use native Responses tool search. Autolith sends
stable namespace names and descriptions up front, marks each function
defer_loading=true, and declares a client-executed tool_search. When the
model searches, Autolith answers from its own registry over the namespaces
that request advertised, scoring namespace names, tool names, and description
words, and appends the tool_search_output as a durable provider item. The
expansion replays intact in every later request, which keeps those tools
loaded and the prompt prefix cacheable; only native compaction requests replay
it empty. Other models and providers receive the complete eager tool array.
Authenticate Gemini with autolith auth gemini or
(auth "gemini"). Autolith stores its Google OAuth credentials separately at
gemini-auth.sexp under the state root. The provider uses the Gemini CLI Code
Assist subscription service directly, including streaming text and thinking,
tool calls, token usage, account onboarding, and managed companion projects.
AUTOLITH_GEMINI_OAUTH_CLIENT_ID may replace the public installed-application
client ID; AUTOLITH_GEMINI_OAUTH_CLIENT_SECRET supplies a client secret when a
deployment requires one.
autolith auth nousNous models are discovered from the authenticated account. Run (models) after
login to refresh the catalog. Model identifiers beginning with anthropic/
use the native Anthropic Messages route; the rest use OpenAI-compatible Chat
Completions. Hermes model identifiers are omitted from the catalog because they
are not reliable for agentic tool calling.
The Nous integration accepts three deployment overrides:
AUTOLITH_NOUS_PORTAL_URLselects the OAuth portal.AUTOLITH_NOUS_INFERENCE_BASE_URLselects the/v1inference base used for model discovery, Chat Completions, and Messages.AUTOLITH_NOUS_PROVIDER_ENDPOINToverrides only the Chat Completions endpoint.
Autolith stores Nous OAuth state separately at nous-auth.sexp under its state
root and serializes rotating refresh-token updates across processes sharing that
root.
Mistral models are discovered from the authenticated account and filtered to
models advertising Chat Completions support. MISTRAL_API_KEY takes precedence
over Autolith’s private Mistral key. AUTOLITH_MISTRAL_PROVIDER_ENDPOINT and
AUTOLITH_MISTRAL_MODELS_ENDPOINT override the chat and discovery endpoints
independently.
OpenRouter models are discovered from the authenticated catalog and use
openrouter/<vendor>/<model> identifiers locally. Discovery includes only models
that emit text and advertise function tools, tool choice, and normalized
reasoning, matching the request shape Autolith sends. OPENROUTER_API_KEY takes
precedence over Autolith’s private OpenRouter key. Authenticate with
autolith auth openrouter or (auth "openrouter").
AUTOLITH_OPENROUTER_PROVIDER_ENDPOINT and
AUTOLITH_OPENROUTER_MODELS_ENDPOINT override the chat and discovery endpoints
independently.
Set :openrouter-provider-routing to a JSON map of wire model names to
OpenRouter provider preference objects. Omit the local openrouter/ prefix
from model keys. Use * for models without their own entry. For example:
(setf (config :openrouter-provider-routing)
"{\"deepseek/deepseek-v4.1-flash\":{\"order\":[\"baseten\",\"together\"],\"allow_fallbacks\":true}}")You can also supply this JSON through AUTOLITH_OPENROUTER_PROVIDER_ROUTING.
Supply an empty string to use OpenRouter’s normal routing.
Provider preference fields are sent as supplied, including order,
allow_fallbacks, only, ignore, sort, and max_price.
(define-application-command my-version-command
(:name "/my-version"
:argument "[LABEL]"
:description "show a labeled local integration version"
:tip "shows the version supplied by init.lisp."
:busy-behavior :inspect
:terminal-behavior :shared
:callable t)
(application &optional (label "integration"))
(application-present application (format nil "~A 3" label))
:continue)- Missing interactive arguments open the restart debugger.
supply-argumentstakes one Lisp form of replacement arguments. Excess slash arguments are rejected before dispatch. Programmatic calls keep ordinary Common Lisp arity rules. - Busy behavior is
:inspect,:execute,:apply,:hold, or:cancel. During active work,:executeruns immediately,:applyapplies its change at the turn’s next safe provider boundary, and:holdwaits for the idle queue. Argument-free:inspectand:applyinvocations only display state, so they run immediately. An unknown command reports its error immediately instead of being scheduled. - Terminal behavior is
:shared,:exclusive, or:exclusive-without-arguments. It declares which invocations open a modal picker so active work keeps them off the immediate reader path. A modal picker requires exclusive terminal input when open. The responsive reader continues animating until then. :static-optionsreplaces:argumentfor one finite positional parameter. It derives the help hint and both slash and parenthesized completions.
Use self.redefine to install loaded Lisp definitions, new or replacing,
including functions and methods outside the Autolith package. self.define
names the same tool. Qualify the target symbol in the source,
or supply the package argument to select its reader package. Use qualified
symbols with self.set for foreign global bindings.
Installation, discard and replay temporarily unlock the reader and target packages, then restore their locks. New definition records include the target’s owning package separately from the reader package. Replay skips stale definitions whose ownership moved to another library. Reapply an old skipped definition to record an intentional replacement under its current owner.
Tracked source stays authoritative over private replay. Each published
definition records the tracked source it shadowed, or that it introduced a new
name. Startup replay skips a definition whose tracked definition changed, was
removed, or appeared since publication, lists every skip in one startup notice
grouped by reason, and leaves it out of the next self.commit. Commits published before
this record replay their tracked overrides only while the image runs the source
revision the lineage was published against. Reapply a skipped definition
against the current source to restore it, or use (fix-skipped-definitions)
to hand every skipped definition to the model
with its persisted source, the tracked source it was written against, and the
current tracked source. The model rebuilds each override on the current source
with self.redefine, drops any the tracked source already covers, and
publishes the result with self.commit. During an active turn, the command
waits in the idle queue.
Use self.refine to record trajectory evidence, choose the smallest useful target
or none, and exercise existing memory, context, skill, role, RLM or mutation
operations. Every transition names the proposal ID and its observed revision.
Evaluation records actual task observations separately from owner compile/replay
checks. Inspect proposals with (refine) and supply a local assessment before
promotion:
(refine "(:assess \"PROPOSAL-ID\" 3 :passed \"Evidence from a separate task\")")Promotion proceeds from session to project to global scope, with renewed evaluation at each scope and an owner-state guard against intervening changes. Recover an interrupted operation explicitly using recorded evidence; replay never repeats its effects automatically.
Use skill.load with an exact catalog name to select prose instructions for the
logical turn. To publish executable behavior, put a bounded data-only
EXECUTABLE.sexp beside SKILL.md or SKILL.sexp. Declare the Skill and ASDF
system versions, entrypoint, input/output contracts, capabilities and exact host
tool names. An executable manifest has this shape:
(:skill-executable :format-version 1 :skill-version "1.0.0"
:system "my-workflow" :system-version "1.0.0"
:entrypoint ("MY-WORKFLOW" "RUN")
:self-test ("MY-WORKFLOW" "SELF-TEST")
:verify ("MY-WORKFLOW" "VERIFY")
:capabilities ("workspace-read") :tools ("resource.read")
:input (:type :object) :output (:type :object))The invocation function accepts input &key context; self-test and verification
functions accept &key context. Input and output use the native portable JSON
representation, such as (:object ("status" "ready")). Install the declared
ASDF system in the worker environment, or supply its authorized asd pathname.
Call skill.invoke with name and contract-valid input:
{"name":"my-workflow","input":{},
"asd":".autolith/skills/my-workflow/my-workflow.asd","async":true}Use skill.verify with name to run the self-test; set entrypoint to verify
for the verification function. Each operation requires ordinary explicit
full-access code authorization and runs in a fresh disposable worker. Capabilities
are declarations for admission; only declared exact host tools allowed by the
originating agent policy enter the callback bridge. Source and sidecar identity
and the complete manifest are rechecked before loading executable code; declared
ASDF versions are checked during authorized system resolution.
Invocation output is contract-validated and retained with its executable identity
as native execution evidence. Result publication is bounded to 1 MiB and read as
one data-only form after stopping the worker. Use async: true for managed jobs;
completion policy applies as described below. Inspect full results with job.get
or deliberately await them with job.wait. Mission accounting and ordinary
execution supervision apply to workflows and their callbacks.
Supply host-tools, an array of exact tool names, to lisp.eval or
lisp.scratchpad-run for an explicitly authorized workflow request. Inside that
request, call:
(autolith:worker-tool-call "resource.read" "{\"uri\":\"workspace:src/main.lisp\"}")
(autolith:worker-tool-context)Read :success-p, :content, :code and :details from the returned result.
The host dispatch retains the originating conversation, callbacks, capability
policy, mission context and job lineage. Requests and results are bounded and
correlated in the conversation audit. Sequential callbacks are supported; choose
a different REPL for nested worker operations. Omit host-tools for ordinary
worker execution.
For a Lisp-controlled workflow, branch on returned native results and make the
next authorized call from the same evaluation. For example, pass these arguments
to lisp.eval:
{"host-tools":["resource.read"],
"forms":["(let ((result (autolith:worker-tool-call \"resource.read\" \"{\\\"uri\\\":\\\"workspace:README.org\\\"}\"))) (if (getf result :success-p) (getf result :content) (getf result :code)))"]}Host calls pass through ordinary registry authorization with the captured
mission admission, including its absence. An interrupted callback is recorded as
unknown-outcome in the audit. Inspect effects before repeating a mutating call.
Load the optional autolith/structural system and configure an ast-grep
executable before creating the tool registry:
(asdf:load-system "autolith/structural")
(setf autolith:*structural-program* "/path/to/ast-grep")Use structural.query with an observed workspace URI and revision. Use
structural.rewrite to retain a complete preview, inspect the proposal, then
publish with structural.apply. Executable and file access require ordinary
command authorization. Proposals are conversation-owned, bounded and single-use;
publication uses the same stale-revision checks as resource edits.
For an existing registry, call structural-register-tools explicitly with
:program. Run the optional checks with CLASTED_AST_GREP set to the backend
path and (asdf:test-system "autolith/structural/tests").
Load autolith/debug before creating a registry. Configure an adapter in user
initialization, or pass an explicit adapter to debug.launch / debug.attach:
(asdf:load-system "autolith/debug")
(setf autolith:*debug-adapter-program* "/path/to/debug-adapter"
autolith:*debug-adapter-arguments* nil)For an existing registry, call debug-register-tools with :program and
literal :arguments. Loading the system starts no adapter. Adapter execution,
launch, attach and expression evaluation require exact full-access command
approval. Authorize source and program paths through ordinary path permissions.
Use the returned session ID for debug.breakpoints, debug.continue,
debug.pause, debug.step, debug.threads, debug.stack, debug.scopes,
debug.variables and debug.evaluate. Inspect bounded queued events with
debug.events, using count and wait-for as needed. Session IDs belong to
the originating conversation. Use debug.cancel to interrupt an operation,
and debug.terminate to close the session and reap its adapter. Timeouts and
cancellation close the owned adapter. Run the optional checks with
(asdf:test-system "autolith/debug/tests").
Roles load from these directories. First match wins:
.autolith/agents/${XDG_CONFIG_HOME:-~/.config}/autolith/agents/<site-config-root>/agents/- bundled roles
A higher-precedence malformed role is reported, not silently replaced.
A role is one bounded UTF-8 *.sexp property list:
- required:
:name,:description,:instructions - optional:
:tools,:spawns,:models,:reasoning-effort,:output,:blocking-p
Roles cannot grant self.*, task.*, or yield.*. Grant job.* when a role
needs to inspect, await, or cancel asynchronous work. Children can access only
their own jobs and descendant jobs, not parent or sibling jobs. This is
independent of permission to spawn another child.
:toolsmay benil,:all, or canonical tool names and namespace patterns.:spawnsmay benil,:all, or role names. Task depth still applies.:reasoning-effortnames a supported effort. Omitting it or writing:autoselectsmedium, so routine delegated work does not inherit the parent’s effort. Children never inherit Codex Fast mode.:outputis the native schema DSL. There,nilis JSON false and:nullis JSON null.
Example:
(:name "reviewer"
:description "Review a change for regressions."
:instructions "Report concrete, evidence-backed findings."
:tools ("resource.read" "search.*")
:spawns nil
:models ("@parent")
:reasoning-effort :high
:blocking-p t)task.agents shows effective roles. task.run starts one task or an
independent batch. Nonblocking work detaches by default. blocking: true
waits. A role with :blocking-p t always waits. Each child must finish
with one yield.submit of success, failed, or aborted.
Persisted child results must contain one data-only form with valid terminal
status and field types. The default reading limits are 16 MiB, 128 nesting
levels, and 262,144 tree nodes.
Set completion-policy to continue (the default) or notify on asynchronous
tools and task.run. A batch inherits its outer policy unless an item overrides
it. The policy also applies after the synchronous grace period hands work off.
In a primary terminal session, continue independent work while jobs run. When
only job results are pending, yield the current turn. Receive a bounded result
summary, truthful outcome and artifact reference in the exact owning conversation.
Idle completions within a one-second window share one automatic turn through the
ordinary controller. Busy turns receive results at their next safe request
boundary. With notify, receive results on the next ordinary turn instead.
An active goal or mission does not urge the model on while a job that will wake
it is queued, running or undelivered. Its automatic continuations wait, the
goal stays active, and the transcript shows ∙ continuing with job results
when the wakeup arrives. The goal’s continuations resume after that turn.
Delivery receipts survive restart and conversation compaction. Notification
reconstruction reads terminal artifacts without repeating job effects. Cancellation,
paused or terminal missions, spent budgets, and conversation ownership constrain
automatic turns. Inspect retained results with job.get, job.continuity or (tasks).
Child-owned outcomes are inspection-only outside their exact conversation; completing
a child does not reopen it or redirect descendant results into the primary context.
ACP sessions also own a completion controller and stream automatic turns to the
connected client. Interfaces without an input controller deliver results on
subsequent ordinary turns. Use job.wait when deliberate waiting is appropriate.
Use (tasks) for a compact nonmodal inventory of owned live and durable work,
including lineage, timing, reported usage, recent activity and artifact paths:
(tasks "get JOB-ID")
(tasks "transcript JOB-ID 0 4000")
(tasks "send JOB-ID Inspect the failing check before continuing.")
(tasks "cancel JOB-ID")Transcript arguments are a character offset and window limit, defaulting to
0 and 4000; use the returned :next-offset for another window. get, send
and cancel use the ordinary owned job operations and authorization.
Use job.continuity with action list or get to classify retained work as
live detached, completed, reconstructible from a checkpoint, safe to restart,
abandoned or needing a decision. List pages contain whole records with
:total, :next-offset and :more-p; offset defaults to 0 and limit to 20
(maximum 100). Supply a visible job or durable execution id for other actions.
The primary owner may declare allow-restart with a safety rationale and
authorize: true, or declare checkpoint with a compatible saved worker
image, target repl and the same explicit authority. A safety rationale is
an assertion about repeating external effects. Revival reattaches live work,
starts the named REPL from its saved image, or dispatches a new child from a safe
retained shared-workspace task specification:
(tasks "revive JOB-ID authorize")
(tasks "abandon EXECUTION-ID authorize")Equivalent job.continuity actions are revive and abandon with id and
authorize: true. The durable recovery decision precedes dispatch and links the
old execution to the new execution. Failed or interrupted revival consumes its
claim and records an uncertain outcome for explicit inspection. Resuming a
conversation presents this inventory for a decision rather than replaying work.
The primary owner establishes directional communication with peer.grant.
Supply an immutable grant id, sender and receiver as primary-visible job
IDs or primary. For example, these arguments grant one child permission to send
coordination data to the primary:
{"id":"build-report","sender":"CHILD-JOB-ID","receiver":"primary","context":true}Each participating actor uses peer.discover to inspect its current grants and
exact endpoint identities. Call peer.send with a stable message id, the
receiver’s endpoint ID from discovery, and text of 1 to 8192 characters.
The sender is the actual executing actor. peer.receive claims incoming work
and returns a delivery token; use peer.ack with id and token after handling
it. peer.wait waits for incoming work or a named message acknowledgment, with
timeout bounded to five seconds. peer.inspect returns scoped metadata pages
or the payload and recovery token for an exact message id.
With context: true on the grant, receive coordination data at the existing
safe steering boundary. Acknowledgment follows durable persistence of that
input. Peer text is coordination data, not additional tool or execution authority.
Children need their ordinary role permission for each peer tool; grants do
not expose parent or sibling job-control operations.
Cross-session communication requires paired explicit grants on both sessions.
Set remote-session and direction (outgoing or incoming); name a remote
child with both remote-job and remote-execution, or omit both for its primary.
Transport uses authenticated local daemon discovery. peer.revoke durably
revokes a grant. Endpoints include exact execution identity, so a replacement
child does not inherit its predecessor’s grant.
Grants and messages restore with the session; interrupted deliveries become
uncertain. Keep the same stable message ID when transport completion is unknown.
Only the primary may call peer.resolve with id, current token and action
acknowledge, retry or cancel; retry requires a current grant. Final session
finish closes its mailbox, while transient daemon handoff preserves delivery
state.
Select the bundled engineering role or give a native role :output :engineering.
Its version-1 contract requires schemaVersion, baseline (kind, workspace,
revision), change (kind, reference), paths, checks, evidence, issues
and integrationNotes. symbols is optional. Each check names the command,
status (passed, failed, skipped or not-run) and summary, with optional
evidence references. Use baseline kind unknown when no revision is available
and change kind none when no change was produced.
Extend the common contract in a native role:
:output (:type :engineering
:properties (("review" (:type :string)))
:required ("review"))Common properties cannot be overridden. The usual structured yield.submit and
durable result transport validate and retain these values. Checks and evidence
are child-reported observations; mission gates establish harness acceptance.
A failed or aborted child follows the ordinary error-only terminal contract.
Supply an isolation object in a flat task.run call or in each selected batch
item. Omit it for the ordinary shared workspace. The object accepts baseline
(a commit-resolving revision, default HEAD), dirtyPolicy (reject by default,
or explicit ignore), and artifactKind (patch by default, or commit-range).
With ignore, use only the committed baseline; staged, unstaged and untracked
source edits are excluded. Git isolation is unavailable for non-Git workspaces.
Sandboxed commands in an isolated child may write its owned checkout and the repository’s Git administrative directories, including a linked worktree’s common Git directory. Integration requires authorization for the target workspace.
The child edits and tests in its detached checkout. Before it starts, persist the
source repository, exact resolved baseline, isolated path and conversation-qualified
owner. Stage new files before yielding. A patch includes committed and uncommitted
tracked changes; a commit range requires a clean checkout and ancestor baseline.
Terminal results, including aborted tasks, identify the secured engineering artifact.
Extraction failures retain the checkout and report :worktree-error; a successful
child without a complete artifact is reported as failed.
Use task.worktree with an explicit action:
inspectreturns provenance, touched paths and the durable artifact pathname;extractexplicitly retries extraction after repairing an incomplete checkout. Supply a visible terminal jobidor its durable execution ID.checkverifies patch applicability without mutation.applyapplies the patch to the clean target’s index and working tree;commitscherry-picks the recorded commit range. Supplyidand an explicittargetrepository.conflictsinspects unmerged paths;abortexplicitly aborts an interrupted cherry-pick. Supply the target repository.cleanupremoves only the task’s owned checkout. Dirty cleanup requiresdiscardDirty: true. Secured artifacts are independent of checkout removal.discoverlists this conversation’s active and absent owned records. Supplysourceto recover interrupted registry publication from Git markers.cleanup-orphanuses a discovery worktreeidand explicitsource, including after task-result publication failed. Unrelated worktrees are excluded.
Git lifecycle and integration commands use ordinary command authorization and execution policy. Target paths use ordinary tool-path authorization. Isolation is an accidental-overlap boundary, not hostile-code confinement. The parent chooses integration order and resolves conflicts deliberately.
Primary shell and Lisp executions and child agents appear as live rows with
spinners and elapsed time. The command and agent strips share a viewport bound,
and provider activity remains visible below them. shell.run accepts an optional
short :description for its row label; otherwise it derives one from the command.
Use POSIX shell syntax for commands on POSIX hosts and PowerShell syntax on
Windows. Both Windows authorization modes use native PowerShell; MSYS/Git Bash
requires a shared object namespace that AppContainer does not permit.
Windows sandboxed commands execute serially while temporary filesystem ACLs
are installed. Their writable temporary directory is removed after completion
or cancellation. Add existing read-only tool directories through
*win32-sandbox-read-roots* for tools installed outside system application directories.
Windows scopes must be local directories without reparse points or hard-linked files. Unsupported
scopes or an unavailable helper fail instead of running without isolation.
The default pool admits eight concurrent children.
AUTOLITH_TASK_MAX_CONCURRENCY raises that up to 32. Child jobs have no
deadline unless AUTOLITH_TASK_MAX_RUNTIME_MS is set positive.
Use shell.run for synchronous commands, detached commands and command mission
gates. Each authorized invocation receives private execution-owned raw captures
before launch. Results include exit, timeout and cancellation status, retained and
observed byte counts, capture completeness, and stable shell-log: references.
The inline preview samples the beginning and end, with most space reserved for
trailing diagnostics. Set separate-output: true to capture stdout and stderr
independently; the preview allocates more space to stderr.
Read a reference with resource.read using zero-based byte-offset and
byte-count (default and maximum 4096 bytes). Use query for a literal UTF-8
search, optionally max-results and byte-offset. Continue with the returned
next offset. Each search scans at most 1 MiB and returns at most 20 excerpts.
Text rendering replaces invalid UTF-8; the retained files contain the original
bytes. Access follows the owning conversation and ordinary task-descendant
inspection authority.
References are included in job inspection, durable tool-result metadata and completion notices. Reopen them after restart or compaction without executing the command again. Missing, interrupted and pruned captures return diagnostics.
Defaults are 64 MiB per stream, 1 GiB of reserved capture capacity and 256
retained artifacts. Eligible completed captures become pruneable after seven
days or under capacity pressure, on the next allocation. Active captures and
undelivered completion evidence are protected. Adjust
*shell-log-capture-byte-limit*, *shell-log-retention-byte-limit*,
*shell-log-retention-count-limit* and *shell-log-retention-age* in trusted
configuration. Captures exceeding their limit are explicitly incomplete.
Session export collects task metadata independently of local log storage.
run-job executes one caller-supplied child role without an interactive
terminal. It uses normal project, user, and bundled task-agent discovery,
provider and MCP configuration, role tool and spawn policy, task traces, usage
accounting, and native structured-output contracts.
autolith --permissions auto run-job \
--input /path/to/job.sexp \
--output /path/to/result.sexpThe input is exactly one bounded data-only S-expression:
(:autolith-job
:version 1
:id "job-identifier"
:role "project-role"
:prompt "Perform the assigned work."
:input (:caller-owned "opaque data")
:output-contract (:type :object
:properties (("answer" (:type :string)))
:required ("answer")
:additional-properties nil)
:timeout-seconds 900)The supplied output contract applies only to that run and does not alter the
role definition. The terminal artifact is atomically installed at --output
as (:autolith-job-result :version 1 ...). Structured objects and arrays use
:OBJECT and :ARRAY tags, so false, null, and empty arrays remain distinct.
Failures use stable categories and statuses :failed, :cancelled, or
:timed-out. Successful jobs use :succeeded and include the contracted
result. Trace and usage fields are included when available.
Headless execution never opens an approval picker. auto classifies shell
commands and denies decisions that would require approval. sandbox permits
only sandboxed commands. full permits full command execution. External tool
calls whose configured policy requires approval are denied unless full access
was selected. The role allowlist remains the child capability boundary.
Add --events sexp to observe a run on stdout. Capture diagnostics separately on
stderr and read the authoritative terminal result from --output:
autolith --permissions auto run-job \
--input /path/to/job.sexp --output /path/to/result.sexp \
--events sexp >events.sexp 2>diagnostics.logRead consecutive top-level data forms, rather than splitting physical lines. Strings may contain newlines. Each version-one record has this shape:
(:autolith-event :version 1
:run-id "a-generated-run-uuid" :seq 1 :time "2026-10-08T09:00:00Z"
:kind :run-started :data nil)The event kinds are :run-started, :job-started, :tool-started, :progress,
:tool-finished, :job-finished, :usage, :warning, :progress-omitted, and
:run-finished. Ignore unknown versioned kinds. Sequence numbers increase
strictly within one run. Job and execution identifiers are opaque execution
UUIDs; provider call identifiers are pseudonymous within that run. Tool names
come from the registered tool catalog. Observe only the requested root and its
owned descendants, excluding other roots in the same conversation. Event data
contains allowlisted statuses and numeric counters, not prompts, tool arguments,
tool output, or provider payloads.
Interactive input is EOF, and diagnostic/query streams go to stderr in the
initiating thread and its workers.
Use run-job-event-read-stream to read one validated record at a time, returning
NIL at EOF. It uses the bounded sexp-config data grammar with *read-eval* NIL.
Only approved keywords, strings, NIL/T, bounded nonnegative integers, and finite
proper lists are accepted. The maximum record size is 16 KiB of UTF-8; character
streams supplied to the library must already use UTF-8. Binary streams receive
UTF-8 octets.
Root :job-finished and final :run-finished records follow atomic result
publication. Published terminal job events include a :result-uri resource
reference; descendant references identify execution-qualified artifacts. The
final data includes :status and :published-p; successful publication also
includes :output-path. An output write failure reports
:failed, :published-p nil, and :category :result-publication-failed, with a
nonzero exit status. Inspect the result artifact for contracted data and full
failure details.
Delivery is best effort through one bounded queue and a single writer. Progress
may be omitted under backpressure, with :progress-omitted reporting its count.
Lifecycle overflow is reported with :warning and :code :queue-full; final
delivery has a reserved slot. A slow or disconnected consumer may miss the
terminal record; execution and result publication continue. There is no replay
or reconnect cursor. For a new invocation, expect a new run UUID and sequence
beginning at one.
From Lisp, call run-job-run with :events :sexp and :event-output STREAM.
Without the events option, use the existing artifact-only interface.
(checkpoint) requires a clean Git worktree and a passing ./script/check.
On POSIX it saves a retained image without stopping the active session. On
Windows it saves the exact live heap, restarts through the stable launcher, and
resumes the active conversation after the saved image passes its probe.
(generations)lists retained images.(rollback ID)selects a compatible image and exits through recovery.
Inspect or boot retained generations from the CLI:
autolith --recovery --list
autolith --recovery --generation GENERATION-IDRecovery starts the separately built pristine core, not the damaged active core. If that image is missing or invalid, it falls back to source.
Automatic recovery boots a private clean checkout of current committed source
with --pristine. It does not load retained generations or private mutation
replay. An intentional (rollback ID) still boots the selected generation.
Explicit generation selection may use an older revision.
To start a rescue session directly, use:
autolith resume --pristine --permissions full--pristine forces tracked source instead of a saved active core and skips the
selected private image commit, mutation journal reconstruction, and executable
user initialization for this process. It implies --immutable so ordinary
self-mutation tools cannot replace the selected private commit. It does not
erase any mutation or conversation data. Ordinary startup remains unchanged.
A fatal active failure publishes a private crash capsule and restores the terminal. Recovery restores the conversation without duplicating scrollback. With a valid capsule, it queues one read-only diagnosis turn before ordinary input.
That turn can inspect:
- bounded crash context
- workspace and tracked source
- indexed source
- active state
It has no shell, MCP, hosted provider, image, write, mutation, checkpoint, or rollback tools. It asks before any repair. A manually started recovery image does not queue diagnosis.
Saved cores require their recorded SBCL version, OS build, and architecture.
Source remains authoritative. To reconstruct without a core, check out the
manifest revision, run ./script/bootstrap, load autolith, then load the
manifest’s ordered reconstruct.lisp in package AUTOLITH:
(asdf:load-asd (truename "autolith.asd"))
(asdf:load-system :autolith)
(load #P"/path/from/generation/manifest/reconstruct.lisp")