Getting started

panto

terminal agentziglua

panto is a small terminal coding agent built on libpanto. A minimal system prompt, a tool set you can swap or switch off, native binaries from Zig, extensions in Lua. This is the operator's reference — flags, configuration, key bindings, and the Lua surface.

Overview

You run panto inside a project directory and talk to a model in a terminal UI. The agent reads and edits files and runs commands through tools — and even the standard tools (read, write, edit, bash) ship as extensions, so any of them can be denied individually.

There are no permission prompts and no hidden machinery: providers are declared in a TOML file, the model is chosen by a provider:alias reference, and anything beyond the core is added as a Lua extension. The rest of these pages document each of those surfaces in turn.

Install

panto builds from source with Zig. Clone the repository and run the Zig build; the result is a single native binary.

shellbash
git clone https://code.tjp.lol/pantograph.git
cd pantograph
zig build            # native binary at zig-out/bin/panto

On first use, run the one-time bootstrap. It stages the embedded Lua runtime and installs panto’s pinned luarocks batteries (just luv, the libuv event loop) under $PANTO_HOME:

shellbash
panto bootstrap        # prepare the rocks tree (idempotent)

Where things live

By default panto keeps its runtime and rocks tree in $PANTO_HOME (falling back to $XDG_DATA_HOME/panto), and reads configuration from a layered set of TOML files. See Configuration → Files & layers.

First run

Run panto with no arguments inside a project to start a fresh conversation. The agent loads your config, selects the default model, and opens the terminal UI. Type a message and press Enter to send it.

panto · first run
$ export ANTHROPIC_API_KEY=sk-ant-…
$ cd ~/code/ledger && panto
 
panto v0.1.0
cwd: ~/code/ledger
 
add a --json flag to the stats command
 
I’ll wire a --json branch into the stats command. Let me read it first.
read src/stats.zig
pub fn run(args: Args) !void { const summary = try compute(args); try printHuman(summary); }
edit src/stats.zig (1 edit)
- try printHuman(summary); + if (args.json) try printJson(summary) else try printHuman(summary);
 
Done — stats --json now prints a machine-readable summary.
 
anthropic:sonnet   18.4k ctx   2.1k tok   $0.03

panto’s UI needs an interactive terminal (a tty). Sessions are saved per directory, so you can pick up where you left off with panto --resume. The full command surface — resuming, listing sessions, auth, the embedded Lua interpreter — is on the Command line page, and every key is listed under Key bindings.

Authenticate

A provider draws its credential from a named auth session. There are two kinds. The simplest is an API key from the environment — the default OpenAI and Anthropic providers read OPENAI_API_KEY and ANTHROPIC_API_KEY directly:

shellbash
export ANTHROPIC_API_KEY=sk-ant-…
panto                  # the anthropic provider is now live

The second is an OAuth device flow, for providers that authenticate interactively. Log in once and panto stores (and refreshes) the token for you:

shellbash
panto auth login github_copilot
panto auth status      # show every session and its login state

If a provider seems missing

An api_key session whose environment variable is empty resolves to nothing, and any provider using it is silently dropped (export the key to bring it back). OAuth providers always survive and resolve at turn time. Auth sessions are declared under [auth] in config.