This release has been yanked by its maintainers, and will be ignored by installers, except when explicitly specified.
Consider using release 1.0.0a4 instead.
agentic-dev-loop
An opinionated library for building stage-gated autonomous dev pipelines. A pipeline is a YAML file of steps; each step runs an OpenHands agent (with a file-artifact verdict protocol), a deterministic Python action, or a mechanical shell command (exit code = verdict); LangGraph drives routing, retries, checkpoints and resume. The fixed policies — artifact hygiene, attempt-bounded retries, fail-fast on empty context, a single gated commit point — are the product.
Publicly depends on OpenHands SDK
for agent execution and LangGraph
(+ langgraph-checkpoint-sqlite) for the state graph.
Install & test
pip install agentic-dev-loop # published release
pip install -e . # from this repo (development)
python -m pytest tests/ -q
Requires Python ≥ 3.12.
Quick start
export OPENAI_API_KEY=... # whatever env var your pipeline's api_key_env names
agentic-dev-loop agentic-dev-loop/pipeline.yaml --plan plan.md
agentic-dev-loop agentic-dev-loop/pipeline.yaml --ai-dlc-unit U2
agentic-dev-loop agentic-dev-loop/pipeline.yaml --resume <thread-id> --max-attempts 5
./trigger-agentic-dev-loop.sh --plan plan.md # same thing, from the repo root
Exit code is 0 on pipeline success, 1 otherwise. Each run prints its
thread id; --resume continues the latest checkpoint of a previous thread
(crash, Ctrl-C, exhaustion) with all accumulated notes intact. A live graph
view is served on localhost by default (browser auto-opens; --viz-port
sets a preferred port, default 8321) — pass --no-viz to suppress it. A
stale viz server from a crashed run of the same repo is swept automatically
at startup; if another repo's run holds the port, the engine prints a notice
and serves on a free port. The sidebar
nests each stage's console output (ANSI colours preserved) under a
collapsible section: completed stages auto-collapse, the running stage stays
expanded and live-tails its console. To eyeball the viz page without
running a pipeline, .venv/bin/python viz_demo.py serves the real topology
and replays a scripted run (every node state, verdict badges, retry cycle).
--ai-dlc-unit accepts any unambiguous spelling of a unit number — U2,
2, U002, 002 — or the full unit slug (U002-custom-configuration).
If multiple unit directories match one id, the run fails loudly naming
every candidate; pass the full slug to disambiguate.
What a run looks like
The shipped self-loop example (agentic-dev-loop/, launched from the repo root
so the pipeline constructs this library itself) is:
dev ──▶ test ──▶ review ──▶ qa ──▶ commit
▲ │ │ │
└──────────┴─────────┴─────────┘ fail verdicts / a failing test gate
retry to dev (attempt-bounded)
- dev runs the
devagent with full context (selected docs +additional_files:+ auto-generated expected-output paths). Its writes are untracked; the pipeline only cares about declaredproduces:files. - test is a mechanical command step: it runs the suite
(
.venv/bin/python -m pytest tests/ -q) in the workspace shell. Exit 0 passes and moves on; anything else (including no exit bytimeout) fails and rewinds todevwith the failing output in the retry note. - review / qa are verdict agents: each must write its declared
artifact (e.g.
.pr/qa-report.md) whose lastVERDICT: <word>line decides routing.passfollowson_pass,failfollowson_fail— here{goto: dev, retry: true}, which consumes an attempt and feeds the artifact back to the dev agent as a retry note. - commit is the single commit point:
git add -A+ templated message, but only when the worktree was clean at run start (your in-progress edits are never swept into a loop commit). - Attempts are bounded by
max_attempts(YAML or--max-attempts). Exhaustion or afailureroute ends the run;successcommits and exits.
Every stage boundary is checkpointed to <state_dir>/loop-checkpoints.sqlite
— resume loses nothing but the in-flight stage.
pipeline.yaml reference
Verbatim from agentic-dev-loop/pipeline.yaml (comments added):
name: agentic-dev-loop-construction
extensions:
- agentic_dev_loop.extensions.aidlc:AidlcExtension
additional_files:
- ../README.md # shared context for every agent step
llm:
model: openai/deepseek-v4-pro
base_url: https://api.deepseek.com
api_key_env: OPENAI_API_KEY # missing env var → run fails fast, naming it
# timeout: null # default = no client timeout (long agent runs)
state_dir: .pr # artifacts + checkpoints live here
max_attempts: 10 # retries across the whole graph
agents_dir: sdk_agents # consumer-owned <name>.agent.md files
steps:
- name: dev
agent: dev # → sdk_agents/dev.agent.md
produces: implementation-summary.md # written under state_dir (str or list)
on_pass: test # explicit; omitted → next step in order
- name: test
command: .venv/bin/python -m pytest tests/ -q # mechanical: exit code is the verdict
timeout: 600 # seconds; SIGKILLs the process group
on_pass: review
on_fail: {goto: dev, retry: true}
- name: review
agent: review
artifact: review-findings.md
verdicts: {pass: APPROVED, fail: NEEDS CHANGES}
on_pass: qa
on_fail: {goto: dev, retry: true}
- name: qa
agent: qa
artifact: qa-report.md
max_iterations: 200 # per-run agent iteration cap
verdicts: {pass: PASS, fail: FAIL}
on_pass: commit
on_fail: {goto: dev, retry: true}
- name: commit
action: commit # built-in action
on_pass: success # terminal (also the default for the last step)
params:
message: "feat: construct {subject} (agent dev loop)" # {subject} templated
Step types
How a step behaves is determined solely by which of three mutually-exclusive
keys it carries — exactly one of agent:, command:, or action: is
required, an empty value does not count, and zero or several keys fail to
load. Graph-building dispatches on this kind (see StepConfig.kind in
config.py).
-
agent: <name>— an agent step: loadssdk_agents/<name>.agent.mdand runs it via the OpenHands SDK against the accumulated context. May declareproduces:(hygiene-tracked outputs, no verdict parsing) orartifact:+verdicts:(verdict-parsed routing).max_iterationscaps the agent's own loop. -
command: <shell>— a command step: mechanical, never an LLM call. The command runs in the workspace shell; exit 0 passes, anything else (including no exit bytimeout) fails.timeout:is its only extra field. -
action: <name>— an action step: invokes a registered node-shaped function(state, params) -> state updatewith the step'sparams:. The built-in iscommit; extensions register more viaregistry.add_action. Unknown action names fail at graph build time, not mid-run. -
agent,action, andcommandare mutually exclusive; exactly one is required — an empty value does not count.
Step semantics
- A
commandstep is mechanical — the command runs in the workspace shell; exit 0 passes, anything else (including no exit bytimeout, default 600s) fails and followson_failwith the output tail in the retry note. The kind is thecommand:key, never the step's name. artifact+verdictsmark a verdict step.on_pass/on_failmay be a step name, the terminalsuccess/failure, or{goto: X, retry: true}.on_passomitted → next step in list order.on_failomitted →failure. No loops happen unless you write them.- A verdict agent that writes nothing, or writes an artifact with no
parseable verdict, triggers an attempt-bounded retry with a note — verdicts
are never silently routable, and the last verdict line wins (markdown
decoration like
**VERDICT: PASS**is tolerated). produces:/artifactfiles are deleted at every attempt start, so a retry can never re-read a stale artifact from the previous attempt.paramson thecommitaction support{subject}templating (e.g."feat: {subject} (agent dev loop)").
Extension points
Extensions are plain Python classes referenced by extensions: entries as
module:Class (the module must be importable — e.g. on PYTHONPATH):
class MyExtension:
name = "mine"
def register(self, registry) -> None:
registry.add_action("run_conformance", run_conformance) # step actions
registry.add_tool("figma", FigmaTool) # OpenHands tools
registry.add_document_loader(MyLoader()) # context sources
Working samples of all three kinds ship as the test fixture
tests/sample_ext.py (actions, tools, a document loader — plus constructor-
failure coverage).
Actions receive (state, params); returning continues the pipeline,
raising fails the run. Actions have no verdict channel — for retry-driven
fixing, prefer a verdict agent step.
Document loaders decide which docs enter the run context:
class MyLoader:
name = "wiki"
defaultable = False # may autodetect when no flag is given?
def add_cli_args(self, parser): # flag defaults MUST be None
parser.add_argument("--wiki-page", default=None)
def resolve(self, args): # -> (docs: dict[str, str], subject: str)
return fetch_docs(args.wiki_page), f"wiki {args.wiki_page}"
Loader-selection flow: a loader's flag in argv selects it; flags from two
loaders in one invocation error out; with no flag, the sole defaultable
loader autoruns (the bundled ai-dlc loader autodetects the current unit
from aidlc-docs/aidlc-state.md), otherwise the run proceeds with no
injected docs and the pipeline name: as subject. Unit ids resolve by
exact directory name or by numeric prefix (unit-004-preset-management
answers to 4, 004, U4, U004, or its full slug); ambiguous ids fail
loud listing all matches. A selected loader that
yields zero docs fails fast — context is never silently degraded.
Duplicate CLI option strings across loaders are a load-time error naming both.
Fixed policies (intentionally not configurable)
- Fail fast on missing config/secrets — no silent fallbacks.
- Verdicts are file artifacts under
state_dir; the last decoration-tolerantVERDICT: Xline wins. - Attempt-bounded retries with full retry-note accumulation.
- Per-attempt artifact hygiene — stale artifacts are deleted, never re-parsed.
- Single commit point, gated on a clean-at-start worktree; the commit action no-ops rather than sweep up your unrelated edits.
- Unclear verdicts are never routable — always an attempt-bounded retry.
- Command steps are mechanical — never an LLM call; the exit code is the verdict; a timeout kills the process group.
- Port sweeps are explicit actions with required
port, optionalmatchsubstring filter — the startup sweep of the engine's own viz server (cwd-scoped, best-effort) is the one built-in exception. - No client-side LLM timeout by default (
timeout: null) — agent runs are long; settimeoutif your provider needs one. - Crash-safe resume — every stage boundary is a checkpoint.
The example consumer
agentic-dev-loop/ is a complete, runnable consumer that turns the library on
its own repo: the pipeline above, its three agent definitions (sdk_agents/),
and this README wired in as shared context. Run it from the repo root with
./trigger-agentic-dev-loop.sh --plan plan.md. The e2e suite
(tests/test_e2e_fixtures.py) replays historical failure fixtures against
it — markdown-decorated verdicts, stale-artifact hygiene, verdict-first
truncation, unclear-verdict retry, dirty-worktree commit skip, and
empty-context fail-fast.
AI-DLC
The development lifecycle workflow lives in
.aidlc/aidlc-rules/aws-aidlc-rules/core-workflow.md (the entry point;
phase details under aws-aidlc-rule-details/). Working docs — plans, user
stories, units of work, state — live in aidlc-docs/, created as the
workflow runs. The bundled ai-dlc document loader (see Extension points)
wires the pipeline's --ai-dlc-unit flag to those docs.
OpenCode commands over the workflow: /epic-status, /ticket-details,
/unit-status, /update-subtask (ticket boards over aidlc-docs/),
/apply-aidlc-patches (numbered .patch files under .aidlc/aidlc-patches/,
applied by apply-patches.sh), /load-backend-rules
(coding-standards-ddd.yaml), /software-selection, /postmortem,
/figma, and /export-opencode-tools-to-claude (syncs commands and skills
into .claude-local/ for the Claude CLI).
Skills: brainstorming, hypothesis-generation, writing-plans.
Metadata
Release files for agentic-dev-loop 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| agentic_dev_loop-0.2.0.tar.gz | 99.1 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| agentic_dev_loop-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 153.5 kB
Release files / agentic_dev_loop-0.2.0.tar.gz
| Download URL | agentic_dev_loop-0.2.0.tar.gz |
|---|---|
| Size | 99.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
6997b9a786ee426d5eac4e011fbd4473be2eb2229a2fbdec03d1897297718b0c
|
|
BLAKE2b-256 checksum How to use checksums |
4015f1b5fbd43b411c534601ee991ec5350c53d26389fe3522a0e21450e4e21c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.
Transparency logRelease files / agentic_dev_loop-0.2.0-py3-none-any.whl
| Download URL | agentic_dev_loop-0.2.0-py3-none-any.whl |
|---|---|
| Size | 54.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
52f1b8a5e0da89788751a611b0fd0d641d3af9a76ac2107978b75f1877a5fa55
|
|
BLAKE2b-256 checksum How to use checksums |
cf60bc2f90c603a266d014cd9c026db7a287be9f9ea3c8bbca326d1454d9189a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.
Transparency logSecurity for agentic-dev-loop 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for agentic_dev_loop-0.2.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 19, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.