Skip to content

Latest commit

 

History

History
363 lines (264 loc) · 11.2 KB

File metadata and controls

363 lines (264 loc) · 11.2 KB

New User Guide

Intro

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:

autolith

If 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.

Install and update

Nix

Nix is the simplest way to install Autolith:

nix run github:luciusmagn/autolith

The first launch builds Lisp images Autolith needs to launch. These images live under ${XDG_DATA_HOME:-~/.local/share}/autolith/nix/images/}.

Linux binary release

It is possible to install autolith on Linux x86_64 via a shell installer:

curl -fsSL https://sh.lambda-symbolics.com/autolith | sh

Read the installer before piping it to a shell, or use Nix if that tradeoff is unwelcome. You need OpenSSL and bubblewrap installed on your system

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, but if you like, you can update it from cli or from inside a session:

CLI:

autolith --update

Session:

(update)

Release archives are built and checked by the installer host. GitHub publishes release metadata after the host checksum is available. See Release service.

Source checkout

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)' --quit

The linux setup is the same, except you have to also have bubblewrap installed, and naturally, use your distros package manager (or nix).

With Quicklisp in ~/quicklisp, bootstrap and check the checkout:

./script/bootstrap
./script/check

To put a checkout into PATH:

mkdir -p ~/.local/bin
ln -sfn "$PWD/bin/autolith" ~/.local/bin/autolith

This is assuming you have .local/bin/ in PATH.

Talk to Autolith

Prose, Lisp, and commands

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))

Parenthetical (commands) are the canonical form now, but there is a /command syntactic sugar to help you with the transition.

Use // to send a message beginning with a literal slash.

The clanker sees both your source input and its evaluated result apart from any other effects it may have.

Local sessions

Every running Autolith session publishes a private authenticated local endpoint. Inspect them with:

autolith localgroup status
autolith localgroup status --sexp

idle 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-ID

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.

Configure Autolith

Autolith loads optional ${XDG_CONFIG_HOME:-~/.config}/autolith/init.lisp after tracked code and a selected private image commit, before provider requests. 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.

Context

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.

Providers

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")

Authenticate with autolith auth my-provider or (auth "my-provider").

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.

Commands

(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
     :call-lambda-list    (&optional (label "integration"))
     :slash-argument-mode :first)
    (application &optional (label "integration"))
  (application-present application (format nil "~A 3" label))
  :continue)
  • Interactive arity errors open the restart debugger. supply-arguments takes one Lisp form of replacement arguments.
  • Programmatic calls keep ordinary Common Lisp arity rules.
  • Busy behavior is :inspect, :execute, :apply, :hold, or :cancel. During active work, :execute runs immediately, :apply applies its change at the turn’s next safe provider boundary, and :hold waits for the idle queue. Argument-free :inspect and :apply invocations 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.

Child roles

Roles load from these directories. First match wins:

  • .autolith/agents/
  • ${XDG_CONFIG_HOME:-~/.config}/autolith/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.*, job.*, or yield.*.

  • :tools may be nil, :all, or canonical tool names and namespace patterns.
  • :spawns may be nil, :all, or role names. Task depth still applies.
  • :output is the native schema DSL. There, nil is JSON false and :null is 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.

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.

Generations and recovery

(checkpoint) requires a clean Git worktree and a passing ./script/check. It saves pending reconstructible mutations and publishes a retained image without stopping the active session.

  • (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-ID

Recovery 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 tries, in order:

  • the selected generation from the current source revision
  • other compatible generations from that revision, newest first
  • a private clean checkout of current committed source

Explicit generation selection may use an older revision.

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")