ari

command module
v0.1.0-rc.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 4, 2026 License: MIT Imports: 2 Imported by: 0

README

ari

ari (アリ, ant) is a coding agent for the terminal, shaped like an ant colony.

One binary carries a headless core and every surface as a client of it: a TUI you live in, ari -p for scripts and CI, and later an HTTP surface. Today it is one excellent ant: six tools, a strict edit gate, a permission pipeline that shows you the real diff or the real command before anything runs, and sessions that resume byte-identical from plain JSONL. The colony (a queen that routes work to specialist ants, shared memory, eval-gated evolution) arrives milestone by milestone on seams that are already in the code.

Status: pre-release, building toward v0.1.0.

Principles

  • Secure by default. ari asks before it edits or runs anything, secrets stay out of the model's sight, and nothing phones home.
  • Honest metering. Every model call lands in a ledger with tokens and dollars, shown in the sidebar.
  • Headless core. The TUI is a client. Anything the TUI can do, ari -p can do in CI.
  • Plain files. Sessions are append-only JSONL under ~/.ari, diffable and crash-safe.

Install

Build from source:

go install github.com/tamnd/ari@latest

Packaged channels land with the first tagged release: Homebrew on macOS, Scoop on Windows, apt and dnf on Linux, and a container image on GHCR.

First run

Open ari in the root of a repo:

ari

On first run a short onboarding explains that ari asks before it edits or runs commands and that its data lives in .ari/, then it writes a small config to ~/.ari/config.toml with only an env reference for your API key, never the key itself. Set the key in your environment first:

export ANTHROPIC_API_KEY=...   # or OPENAI_API_KEY, or an OpenRouter key

Then the chat opens with the editor focused, the sidebar showing the resolved model, an empty context bar, and a zero cost. Nothing has touched the repo, because ari does no work until asked.

The walkthrough

Ask for a small refactor:

Rename Greeting to Greet across the package and update the test, then run go test.

Here is what you see, and it is the same sequence the demo fixture replays in CI:

  1. A dim, collapsed reasoning block with its elapsed time, then assistant text streaming in.
  2. find for Greeting, rendered as a grouped match list.
  3. read on the files it will touch, in one parallel batch, each a file header and a bounded preview. A successful read arms the edit gate for that file.
  4. A first edit that ari rejects because old_string was not unique, shown in the chat as a tool result with the occurrence count and the fix, not an error. The model adds a surrounding line and retries, and it lands.
  5. A permission dialog for the edit, because the default mode is ask. It shows a real syntax-highlighted diff of the change. Approve for the session and the next edit runs without a second prompt.
  6. sh with go test ./.... The pipeline asks once, showing the exact command. Allow it for the session, the tests run, and the turn finishes.

The sidebar meters every model call live, and the cache hit rate stays high because the prompt prefix is stable across the turn.

Resume

Quit with the quit key. Next time, ari --resume (or pick the session from the switcher) replays the transcript from JSONL into a byte-identical chat, and you ask a follow-up in the same session, appended to the same file.

The permission model

Every tool call passes through an ordered pipeline before it runs. Deny beats ask beats allow because deny is the first stage and allow is near the last, so no convenience can undo a stop. In the middle sits a safety floor that no mode can cross: ari will not edit its own binary, the nest, your VCS internals, or your shell startup files, whatever mode you are in.

Four modes set how much ari asks:

  • ask (default): ari asks before any edit or command, and shows you the real diff or the exact command first.
  • auto-edit: in-tree edits run without a prompt; commands still ask.
  • full-auto: ari runs without prompts, for a run you mean to leave unattended. The safety floor still holds.
  • plan: ari plans and reads but makes no changes.

Set the mode for a run with --mode, or as a config default. A grant you give in the chat (allow for session) lasts the session and is never a rule ari wrote for itself.

Config

Config is TOML with a fixed precedence: built-in defaults, then ~/.ari/config.toml, then the project's .ari/config.toml, then the gitignored .ari/local.toml, then flags for the run. A fresh install with only an API key in the environment runs with no config file at all.

An API key is always a reference, never a literal:

[provider.anthropic]
kind = "anthropic"
base_url = "https://api.anthropic.com"
api_key = "${ANTHROPIC_API_KEY}"

[tier.frontier]
chain = [{ provider = "anthropic", model = "claude-opus-4-8" }]

A tier is a failover chain, and an ant names a tier rather than a model, so swapping models is a one-line edit. A key a later milestone does not know about is a warning, not a crash.

Headless: ari -p

ari -p runs one turn and exits, using the same core, loop, tools, and ledger the TUI drives:

ari -p "read main.go and summarize it"

The prompt can also come from stdin, so ari composes in a pipeline:

echo "summarize the build failure" | ari -p -

--json streams the raw event schema, a hello first and then the turn, so a downstream step can reconstruct the transcript or resume from a sequence cursor:

ari -p --json --mode full-auto "rename Greeting to Greet, then run go test"

A headless turn that would need a human auto-denies rather than hanging, so a CI run never stalls on a dialog. Widen it deliberately with --mode full-auto for a run you have decided to leave unattended. The exit code is the terminal reason, so a CI step can branch on success without parsing output.

ari doctor

ari doctor audits the nest, the config, and any listening surface for the mistakes that turn a coding agent into someone else's remote shell. It checks credential-directory permissions, a literal secret in config, config health, the permission mode default, whether .ari/local.toml is gitignored, the listening surface, and journal continuity.

ari doctor          # report
ari doctor --fix    # apply the safe repairs, leave the judgment calls
ari doctor --audit  # the deeper integrity checks a reviewer would run

The exit code is a CI contract: 0 clean, 1 warnings only, 2 at least one critical, 3 doctor could not run. Wire it into a pre-merge check to fail on a committed secret or a loose credential file.

License

MIT

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis
Package agent is the engine that turns one awake ant into work: the explicit state-machine loop that drives model turns, schedules tool calls, compacts the context when the window fills, and recovers from provider errors (doc 03).
Package agent is the engine that turns one awake ant into work: the explicit state-machine loop that drives model turns, schedules tool calls, compacts the context when the window fills, and recovers from provider errors (doc 03).
Package ant is the population side of the colony: the card contract, the prompt assembly, and the runner that puts the agent loop behind the core's TurnRunner seam.
Package ant is the population side of the colony: the card contract, the prompt assembly, and the runner that puts the agent loop behind the core's TurnRunner seam.
Package bus is the in-process event broker between the core and its clients.
Package bus is the in-process event broker between the core and its clients.
Package cmd holds the ari command tree.
Package cmd holds the ari command tree.
Package config loads ari's TOML configuration with a fixed precedence: built-in defaults, then the user file (~/.ari/config.toml), then the project file (.ari/config.toml), then the gitignored local file (.ari/local.toml), then flags for the run.
Package config loads ari's TOML configuration with a fixed precedence: built-in defaults, then the user file (~/.ari/config.toml), then the project file (.ari/config.toml), then the gitignored local file (.ari/local.toml), then flags for the run.
Package core is the headless colony: Open, Start, Close, and the SessionAPI every surface drives.
Package core is the headless colony: Open, Start, Close, and the SessionAPI every surface drives.
Package doctor is ari's hardening checker, shipped in the product from day one rather than written after a crisis (doc 14 section 12, D16).
Package doctor is ari's hardening checker, shipped in the product from day one rather than written after a crisis (doc 14 section 12, D16).
Package event is the shared vocabulary between the core and every client.
Package event is the shared vocabulary between the core and every client.
Package journal is the append-only event log of everything the colony does: the durable spine under the D2 event stream and the source for replay (doc 01 section 8).
Package journal is the append-only event log of everything the colony does: the durable spine under the D2 event stream and the source for replay (doc 01 section 8).
kernel
eval
Package eval is the harness the rest of ari is tested with: golden files for every renderer, offline replay sets for the loop, token budgets for the demo tasks, and goleak for every package (D23).
Package eval is the harness the rest of ari is tested with: golden files for every renderer, offline replay sets for the loop, token budgets for the demo tasks, and goleak for every package (D23).
ledger
Package ledger is where token counts become money and budgets.
Package ledger is where token counts become money and budgets.
Package nest owns ari's data directories: the global nest at ~/.ari and the project nest at .ari/ in the repo.
Package nest owns ari's data directories: the global nest at ~/.ari and the project nest at .ari/ in the repo.
Package permission is the ordered decision pipeline every tool call passes through before it runs (doc 05).
Package permission is the ordered decision pipeline every tool call passes through before it runs (doc 05).
Package provider is the only kernel component that opens a socket to a model.
Package provider is the only kernel component that opens a socket to a model.
anthropic
Package anthropic speaks the Messages API natively: fine-grained streaming usage, cache_control breakpoints, parallel tool use.
Package anthropic speaks the Messages API natively: fine-grained streaming usage, cache_control breakpoints, parallel tool use.
openai
Package openai speaks chat completions, the shape every non-Anthropic endpoint understands: hosted gateways, Ollama, LM Studio, llama.cpp, the tailnet box.
Package openai speaks chat completions, the shape every non-Anthropic endpoint understands: hosted gateways, Ollama, LM Studio, llama.cpp, the tailnet box.
scripted
Package scripted is the provider every loop and UI test drives the core with: recorded responses, no network.
Package scripted is the provider every loop and UI test drives the core with: recorded responses, no network.
Package session persists transcripts.
Package session persists transcripts.
jsonl
Package jsonl is the first session.Store: one JSON object per line, one file per session, append-only, under the project's sessions/ directory in the global nest (doc 01 sections 7.3 and 7.5).
Package jsonl is the first session.Store: one JSON object per line, one file per session, append-only, under the project's sessions/ directory in the global nest (doc 01 sections 7.3 and 7.5).
Package tool owns the fail-closed capability surface the model calls.
Package tool owns the fail-closed capability surface the model calls.
ui
Package ui is the root of the terminal client: one tea.Model that coordinates controllers, routes input by scope, and composites every widget onto one cell buffer (doc 02 sections 11 and 18).
Package ui is the root of the terminal client: one tea.Model that coordinates controllers, routes input by scope, and composites every widget onto one cell buffer (doc 02 sections 11 and 18).
bus
Package bus bridges the core's event stream to the UI program (doc 02 section 3).
Package bus bridges the core's event stream to the UI program (doc 02 section 3).
chatlist
Package chatlist is the lazy chat scrollback (doc 02 section 5).
Package chatlist is the lazy chat scrollback (doc 02 section 5).
dialog
Package dialog is the modal layer (doc 02 section 8).
Package dialog is the modal layer (doc 02 section 8).
diff
Package diff renders unified diff text into styled lines, shared by the edit-result chat renderer and the permission prompt (doc 02 section 9).
Package diff renders unified diff text into styled lines, shared by the edit-result chat renderer and the permission prompt (doc 02 section 9).
input
Package input holds the pieces that sit between the terminal and the update loop (doc 02 section 14): a filter that coalesces high-rate mouse traffic so a wheel flick cannot starve the keyboard, and the external editor escape hatch for prompts that outgrow a textarea.
Package input holds the pieces that sit between the terminal and the update loop (doc 02 section 14): a filter that coalesces high-rate mouse traffic so a wheel flick cannot starve the keyboard, and the external editor escape hatch for prompts that outgrow a textarea.
keys
Package keys is the binding registry (doc 02 section 12).
Package keys is the binding registry (doc 02 section 12).
markdown
Package markdown renders assistant prose.
Package markdown renders assistant prose.
parts
Package parts is the render model: the UI draws exactly one data structure, the ordered list of typed parts that make up a session's messages, projected from the core's events with no second schema (doc 02 section 4).
Package parts is the render model: the UI draws exactly one data structure, the ordered list of typed parts that make up a session's messages, projected from the core's events with no second schema (doc 02 section 4).
perm
Package perm is the permission dialog (doc 02 section 9).
Package perm is the permission dialog (doc 02 section 9).
picker
Package picker is the one filterable list dialog: the model picker, the session switcher, and the command palette are all a Dialog with different items and a different ID (doc 02 section 7.1).
Package picker is the one filterable list dialog: the model picker, the session switcher, and the command palette are all a Dialog with different items and a different ID (doc 02 section 7.1).
sidebar
Package sidebar is the live ops panel (doc 02 section 13.1): a fixed width column of stacked sections reading from state the root projects out of core events.
Package sidebar is the live ops panel (doc 02 section 13.1): a fixed width column of stacked sections reading from state the root projects out of core events.
splash
Onboarding: a short sequence of dialogs on the overlay stack (doc 02 section 19.2).
Onboarding: a short sequence of dialogs on the overlay stack (doc 02 section 19.2).
tea
Package tea holds the one rendering contract every widget in the UI implements: paint yourself onto cells within a rectangle (doc 02 section 2.5).
Package tea holds the one rendering contract every widget in the UI implements: paint yourself onto cells within a rectangle (doc 02 section 2.5).
theme
Package theme is the semantic palette layer (doc 02 section 10, D18).
Package theme is the semantic palette layer (doc 02 section 10, D18).
Package version holds the build metadata stamped at link time.
Package version holds the build metadata stamped at link time.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL