Local-first autonomous coding CLI — plans, builds, verifies, and validates against a spec, entirely on your own hardware.

spiral
MIT
Python 3.11+
Ollama
macOS · Linux

An autonomous coding agent that runs on local models. It turns a goal into a requirements checklist, implements each requirement against your project's real build or test command, and verifies the result before reporting done.

Install · Quickstart · Example run · How it works · Commands · Configuration · Principles

spiral is a command-line coding agent that runs entirely on local models through Ollama. Given a goal, it extracts a list of requirements, plans the work, and implements each task against your project's actual build or test command. Changes that pass are committed to git; changes that fail are reverted. When the plan is finished, the code is checked against each requirement — by running the requirement's acceptance check where one exists, and by a separate model where none does — and spiral keeps working until all are met or it reports which ones remain. No API keys and no network calls to a model provider.

Either way you get a global spiral command. From a clone, pip install -e . installs it in editable mode.

Requires Python 3.11+, Ollama, and at least one local model. Apple Silicon with 32 GB+ of unified memory is recommended for the default model set; smaller machines can run a smaller crew (see spiral setup).

spiral runs on a dedicated git branch (spiral/run-*), leaving your working branch untouched. It commits each verified step and prints a summary when the run ends:

a recorded run: gate detection, run branch, spec, plan, approval, first task

A recorded run: gate detection, the run branch, the spec, the milestone plan, approval, and the first task under the live plan panel. Model waits are time-lapsed.

If the project does not build at the start, spiral repairs it first. Each attempt that reduces the number of errors is committed, so progress is kept even if a later attempt fails or the run is stopped:

After the plan finishes, the code is checked against each requirement. Requirements with an executable check are judged by exit code; the rest by a separate model. Unmet requirements become new tasks:

Verification. A task is complete only when it passes every check that applies: the build or test gate (compiles, tests pass), a footgun lint welded into that gate (patterns that compile but crash at runtime), an artifact check (the files the task declared exist), a behavior audit (the task actually changed something relevant), and the final spec validation (the requirement is implemented). You can append your own check with extra_gate.

Acceptance checks. At spec time each requirement can get one shell command that exits 0 exactly when the requirement is met — run a test, invoke the CLI, execute the program. A lint drops presence-style commands (grep, ls, test -f) and anything on the denylist. Validation runs these checks first and only asks a model about requirements that have none; a failed check becomes a remediation task gated on the check itself.

Diversity round. When the worker exhausts its attempts on a red gate, spiral samples N fresh candidates (default 3) at spread temperatures and runs the gate on each. A green candidate is committed; during bootstrap the best red candidate is banked if it resolved errors. The round never runs on a green gate, so a no-op candidate cannot pass as done.

Context acquisition. Local models reference identifiers they have not been shown, and do not reliably notice something is missing. spiral supplies context in stages rather than relying on the model to ask:

Learning across runs. Every attempt is logged to .spiral/ledger.jsonl with the error signature it faced (normalized, so line numbers don't split them) and whether it cleared it. When escalation solves something the worker could not, the fix is appended to learned-fixes.md for later runs. A signature the worker has repeatedly failed and only escalation has solved is routed straight to escalation next time. spiral distill prints the table and writes .spiral/route.json.

Safety. Work happens on a spiral/run-* branch; you merge. The model's shell blocks destructive commands even in full-auto — rm -rf, sudo, mkfs, dd, git push, git reset --hard — and blocks curl/wget, so the worker has no network access. The only door to the web is the research module: GET-only, size-capped, fetched content treated as data, never as instructions. Ctrl-C stops cleanly; committed work is kept and --resume continues.

Models. Each role can be set to any Ollama model:

⇧ Tab — switch between auto and step mode; the current mode is shown in the status line.

step mode — pause at each task: enter to run it, s to skip, a to return to auto, q to stop.

Ctrl-C — stops cleanly. Committed work is kept and --resume continues from there.

Models can be set per shell or persistently.

~/.config/spiral/config.json is written by spiral setup and spiral tune, and can be edited directly:

extra_gate — a command appended to every task's gate. If it exits non-zero, the task is not complete.

diversity_samples — candidates in the best-of-N round at the worker lane's exit (default 3, max 5, 0 disables).

providers — OpenAI-compatible endpoints, keyed by model id. Any role set to one of these ids is served by that endpoint instead of Ollama. The API key is read from the environment variable named in api_key_env and never written to disk. --boost and --api remap roles onto the first provider; without them everything runs local.

hooks — commands run on the events task_green, blocked, run_complete, and spec_green. $SPIRAL_EVENT and $SPIRAL_INFO are set in the environment.

spiral takes project-specific guidance from four sources:

Skills — markdown files loaded per task when they match. Included: android-kotlin, dark-ui-design, design-principles, dependency-medic. Add your own in <project>/.spiral/skills/.

Notes — spiral note "text" appends to a file that is included in every worker prompt.

Reused fixes — when the escalation model solves something the worker could not, the error and the fix are appended to .spiral/skills/learned-fixes.md so the worker can reuse it on later runs.

Signature routing — error signatures the worker has never beaten skip its lane on later runs (see spiral distill).

For UI work (Android, iOS, web, desktop — detected from the repo and goal), a design brief with concrete values (color tokens, type sizes, spacing, motion, sample copy) is generated once per project, or written by hand at .spiral/design.md, and included in every prompt. The brief is distilled into .spiral/design_tokens.json, and for an Android app spiral draws a launcher icon from those tokens and wires the manifest before feature work.

Everything a run decides or learns is written to .spiral/ in the target repo:

Completion is verified, not claimed. It is decided by exit codes, file existence, and the spec check. A passing build is not the same as an implemented feature.

Progress is committed incrementally. During repair, each reduction in error count is a commit, so an interrupted or failed run resumes from the last improvement.

Lanes stop on lack of progress. A task stops after three attempts that resolve no new error, rather than repeating the same failure to a fixed limit.

The control loop is deterministic. Models generate edits and plans; ordering, verification, retries, and git are handled in code. This is what lets small models complete large tasks.

Missing output is surfaced. Unjudged requirements are marked, truncated JSON is repaired, and empty commits are rejected.

Language-server diagnostics as a fast gate between builds; spec-time dry runs for acceptance checks (a check that passes before the work exists proves nothing); interrupting a single attempt without stopping the run; parallel tasks via git worktrees; an emulator launch gate for Android; a JSON event stream and a CI action.

MIT · Built by Edis Devin Tireli · Ph.D. Fellow, University of Copenhagen

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Filter files by name, interpreter, ABI, and platform.

If you're not sure about the file name format, learn more about wheel file names.

Copy a direct link to the current filters

Details for the file spiral_coder-0.1.1.tar.gz.

Details for the file spiral_coder-0.1.1-py3-none-any.whl.