giro
Guarded loops for AI coding agents. giro turns a Spec into integrated, verified work through bounded loops that exit exactly two ways — proof, or a hand raised to a human. Nothing silent in between.
Giro — a lap, a loop, a tour in stages. The engine runs the laps; you write the route and take the finish.
Status: pre-alpha (M0). The loop engine, state store, gate runner, and CLI exist and are fully tested against a fake driver. Live agent drivers are the next milestone. Successor to pierg/orchestrion, rebuilt from scratch around a narrower thesis.
The thesis
Most agent frameworks describe what an agent should do and hope it complies. giro inverts that:
Control never crosses an LLM. Content always does.
The giro CLI is a deterministic loop engine. It owns every arrow — state transitions, budgets, gate execution, wave scheduling, escalation. LLM contexts are spawned inside the loop to do the creative work (implement, plan, judge), and each one ends by emitting a JSON envelope. A budget enforced by a while loop cannot be talked out of; an LLM "following instructions" can.
One primitive, two levels
An actor makes an attempt. An independent verifier — a set of gates — judges it. All green: the loop exits with proof. Otherwise the findings feed the next attempt, until the budget runs out and the loop escalates to needs-human. It cannot just stop.
| Loop | Actor | Verifier | On fail |
|---|---|---|---|
| Issue loop | a fresh worker context | [verify] gates |
retry, findings carried forward |
| Spec loop | a wave of Issue loops | [validate] gates |
findings become gap Issues → next wave |
There is no third loop. Validate is the Spec loop's verifier; gap Issues are its feedback. The "lifecycle" is one feedback edge, not a controller.
One verb
giro implement <target>
The router reads the target and picks the level. An Issue runs the Issue loop. A Spec runs the Spec loop — planned into Issues first if it has none. No second entrypoint, no mode flags. When a run ends needs-human, you answer (edit the Issue, decide the question) and run the same command again: re-invoking is the answer, and the budget resets.
Merging giro/<spec> into your main line stays your hand, always.
Gates
A gate is anything that ends in { "verdict": "pass" | "fail", "findings": [...] }.
- command — a shell command; exit 0 is pass. Deterministic and cheap.
- prompt — a rubric applied by a fresh, blind judge context.
- skill — a full SKILL.md procedure, same envelope at the end.
Judges start blind on every attempt; findings feed the next actor, never the next judge. A judge that can't produce the envelope gets one retry, then fails closed. All gates run to completion — the next attempt sees every finding, not just the first.
State
Specs and Issues are markdown with tiny frontmatter, committed beside the code:
docs/specs/<slug>/SPEC.md state: draft | active | done | needs-human
docs/specs/<slug>/issues/NN-slug.md state: ready | in-progress | done | needs-human | wontfix
The store is the durable checkpoint: kill the engine at any point and giro implement resumes from exactly where the markdown says. Every attempt appends its story to the Issue file — the history is readable, not buried in a log.
Quickstart
uv tool install giro # not yet published — for now: uv sync && uv run giro
cd your-project
giro init # writes giro.toml — set your [verify] gates
giro implement <spec> # go
Exit codes are the contract: 0 proof, 2 needs-human, 1 error. CI and chat agents read them the same way.
Layout
docs/design.md— the founding design: vocabulary, state machines, envelopes, loop contracts, decisions.skills/— the LLM touchpoints: what workers, judges, and chat doorways are told.src/giro/— the engine.loops.pyis the heart.
Roadmap
- M0 — engine core (this): guarded loops, gates, store, CLI; proven end-to-end with a fake driver.
- M1 — live driver:
claude -pworker/judge/planner contexts; first real Spec shipped by the machine. - M2 — parallel waves:
concurrency > 1, isolated worktrees, integration branch + re-verify. - M3 — the doorway:
/girochat skill, escalation console, one-shot install (CLI + skills).
MIT — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
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
File details
Details for the file giro-0.0.1.tar.gz.
File metadata
- Download URL: giro-0.0.1.tar.gz
- Upload date:
- Size: 33.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.12.2 {"installer":{"name":"uv","version":"0.12.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
164d52aa2f4b077eb4aa9bc9fbc040af5d29a5e9c674f136967a4ee7885e0363
|
|
| MD5 |
49e8d22b67192dce9a4f5d596bb2a7f7
|
|
| BLAKE2b-256 |
25250f1c8d2ed6b9faa453afd71d178513a905f2924106584687bf45b8d3a7e4
|
File details
Details for the file giro-0.0.1-py3-none-any.whl.
File metadata
- Download URL: giro-0.0.1-py3-none-any.whl
- Upload date:
- Size: 23.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.12.2 {"installer":{"name":"uv","version":"0.12.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
483250d4c615313a4b29974a0f3d8c192634477ccbc9caf20948f0a2758f6fc6
|
|
| MD5 |
bf30ae0fe40b57c019e99233048266a8
|
|
| BLAKE2b-256 |
6bc9d6cb2df4f587dc5c63c12ba0dae19f98968dad72891ecdaecbd0748c522a
|