Skip to main content

in-lockstep

An agentic SDLC framework, written in Python, for a repository in any language. Your lifecycle is executable code: not a manifest, not a spec, and not something that generates a pipeline. The module you write is the thing that runs.

uv tool install 'in-lockstep[anthropic]'
in-lockstep init
# .lockstep/lockstep.py — the whole configuration
from in_lockstep import Lockstep
from in_lockstep.adapters import PytestTest, RuffValidate, Test, Validate
from in_lockstep.middleware import CostBudget, otel

lockstep = Lockstep.detect()
lockstep.bind(Test, PytestTest(args=["-q"]))
lockstep.bind(Validate, RuffValidate())
lockstep.middleware += [otel(), CostBudget(usd=2.00)]

What ships today

Six core workflows are the goal. This table is what actually runs, kept honest by a test that reads it: a row claiming runs must name a verb that ships, and a planned row must not. So implementing one without flipping its row fails CI, and so does deleting a feature the table still advertises.

Capability Status What that means
Code Review runs review --aspect security, per-lens prompts, cassette-replayable offline
Implement runs oneshot and TDD strategies; /implement on an issue end to end via the three-job trampoline
Bug Fix runs fix verb; a failed run opens an ai-generated issue an agent can pick up, attempts bounded
Triage runs triage from a ticket, $0 on a local model
Detected lifecycle runs Lockstep.detect() reads pyproject, package.json and the Makefile, and detected_bindings serves Test, Validate, Build and Run from what is actually there: pytest and ruff where they exist, then Makefile targets (make test, make lint, make build, make run), then package.json scripts. A repository with no lockstep.py runs on those bindings; init writes the same ones into the module it scaffolds. A target that is not in the file is not guessed
Provisioned environment runs provision builds the repository's own environment from a file that exists (uv sync --locked for a uv.lock, npm ci for a package-lock.json, a requirements.txt into a venv of its own, or the Makefile's own deps target); detected_bindings binds it first and the scaffolded work jobs run it before doctor, with one line that is the same in every repository. A pyproject without a lock binds no Python provisioner, and nothing to provision is not bound, never a success
Harvesting history into cases runs eval harvest turns a recording into cases (real requests, real answers, expectations derived from them); eval run replays and settles them for nothing. Measures everything below the model; re-testing a changed prompt is a real call
Review conversation as context runs what a reviewer said on the pull request (the thread, the verdicts, the notes pinned to a line) reaches the next /fix or /implement as untrusted context, and /fix can be asked for from the pull request: it resolves to the ticket that pull request was opened for
Backport runs deterministic cherry-pick -x staged for apply --base; --resolve lets a model merge conflicts, budget- and approval-gated
RFE runs rfe --idea drafts the ticket; a human reads it, and --create files it through TicketSource
Flaky-test adapter planned roadmap item 26
GitHub runs SCM, issues, chat-ops gate, trampolines
GitLab partial GitLabScm/GitLabIssues and host-aware init ship; no live dogfooded pipeline yet
Keyless CI (federation) runs GitHub OIDC exchanged at Anthropic; no ANTHROPIC_API_KEY in secrets
Org standards as a package runs in_lockstep.standards entry points at Tier.PLUGIN; worked example in examples/acme-standards
Extension packs runs in_lockstep.extensions entry points that offer rather than apply; pack describe derives a receipt, add records what you accepted, pack try measures it for $0
Pack catalog runs a static index.toml in a git repo; market add/search/lint, receipts re-derived locally and refused when they disagree
Spend controls runs per-run predictive budget, rolling daily ceiling, org-limit attestation
Metrics report runs report reads the ledger back: outcomes, effort, spend, turns per strategy, what it keeps finding. --html writes one self-contained page, --scm adds merge and issue timings. Every number carries its denominator, and a field nobody measured is a dash
Ledger + tamper-evidence runs orphan-branch records; report/doctor flag a rewritten history
Shared ledger store planned compare_and_set is declared and refused at LOCAL scope; fan-out barriers need SHARED

Why code rather than configuration

A change to your review policy becomes a diff in a pull request, with blame, history and rollback. You extend a verb by subclassing, override behaviour by rebinding, and compose cross-cutting concerns as middleware. Those are language features, and reinventing them in YAML produces a worse version of each.

The cost is that a container is harder to read than a manifest, which is what in-lockstep ls is for: it prints what will actually run.

Extensions that travel

Config-as-code makes extension ordinary (subclass a prompt, write a strategy, declare a verb), and for a long time it made extension local: what one team wrote could not reach another. An extension pack is that same code as an installable distribution, and the rule it turns on is short.

Installing a pack offers it. A line you wrote is what puts it in force. in_lockstep.standards packages apply themselves, because they can only tighten and the risk is forgetting one. An extension hands a model write and execute tools and spends money, so its arrival is a diff: in-lockstep ls will not mention a pack until lockstep.py names it.

What you can know before you trust one is derived from its code rather than claimed in a file:

in-lockstep pack describe acme-tdd-pro   # capabilities, imports, guardrails, evidence — no key
in-lockstep pack try acme-tdd-pro --corpus ./our-cases   # measured on YOUR cases, replaying, $0
in-lockstep add acme-tdd-pro             # records what you accepted; prints the lines to paste

add never writes .lockstep/lockstep.py and never installs anything. It records the receipt you accepted at .lockstep/packs/<name>.json, and doctor re-derives against it: DOC170 fails when a pack may do more than you agreed to, which is the upgrade that would otherwise arrive quietly.

docs/extending.md is the how; design/extension-packs.md is why each refusal is where it is.

Commands

in-lockstep run <workflow>       # run it; --recover resumes an interrupted run
in-lockstep review --base ...    # review a change, one lens at a time
in-lockstep implement --ticket X # read a ticket, stage a change; writes nothing itself
in-lockstep backport --target .. # replay merged commits onto a release line; model only on conflict
in-lockstep triage --ticket X    # classify a ticket; cheap enough for a local model
in-lockstep rfe --idea "..."     # draft a ticket from a rough idea; --create files it
in-lockstep show-prompt <lens>   # what the model is told, offline, no key
in-lockstep ls                   # the resolved container, middleware, standards and policy
in-lockstep provision            # the repository's own environment, from its lockfile; CI runs it first
in-lockstep pack ls              # installed extension packs — offered, not yet in force
in-lockstep market add <url>     # register a catalog; https only, and committed
in-lockstep search <query>       # packs across the catalogs this repository reads
in-lockstep add <pack>           # accept one: re-derive, record, print the lines to paste
in-lockstep pack try <pack>      # measure it on your cases, replaying a cassette, for $0
in-lockstep pack describe        # the receipt: what is bound, what it may do, what proves it
in-lockstep doctor               # are the controls actually in place?
in-lockstep report --by model    # what the ledger adds up to — and whether it was rewritten
in-lockstep history --explain X  # one run's record, every field, in words
in-lockstep egress-manifest      # the hosts a run may dial, for the proxy that enforces it
in-lockstep gate --actor ...     # is this person allowed to fire a chat-ops trigger
in-lockstep eval harvest --from  # turn a recording into cases you can measure against
in-lockstep eval run             # replay them and settle them, for nothing
in-lockstep apply --from-artifact # the privileged half of the two-job trampoline

Working without keys or spend

--dry-run proves the wiring. in-lockstep review --offline works on a clean install with no key, no module and no recording of your own: a cassette ships, recorded from a real model call against a real merged pull request. Replays are deterministic and free, and neither needs a budget. A run that cannot spend states a ceiling of zero rather than being asked for one.

Cassettes sit at the LLMInput/LLMOutput seam, so one recorded against a provider replays against a different one, and they capture tool IO as well as model IO. This is the debugging story, the testing story and the eval story at once.

Two things worth knowing before running it unattended

Model invocation happens in your process. That is what makes the framework a library rather than a service, and it removes an execution substrate that was also an egress firewall, an out-of-process spend ceiling and a privilege split between the process holding a key and the process able to write. docs/controls-crosswalk.md accounts for every one of those: what replaced it, what is weaker, and the one that was lost rather than replaced. in-lockstep doctor checks the same list.

Configuration is loaded from a trusted ref. .lockstep/lockstep.py defines every binding, policy and protected path. Under review, loading it from the branch being reviewed would let a change rewrite the constraints that apply to reviewing it, so it comes from the base ref instead.

Documentation

Evaluating? The matrix above says what runs; getting started shows every command with the output it actually prints, and costs nothing to follow. --offline and --dry-run need no key.

Adopting? The cookbook is ten recipes of twenty lines or fewer: keyless CI, org standards as a package, the daily ceiling, chat-ops TDD. Then extending for adapters, prompts, strategies and packs, and the trampoline contract for what a CI file owes the framework on any host.

Distributing an extension? design/extension-packs.md is the whole mechanism and the argument for each refusal in it; the worked examples are a prompt pack (examples/acme-review-prompts) and a catalog (examples/lockstep-index).

Auditing? The controls crosswalk is the honest accounting of what in-process invocation costs (what replaced each substrate control, what is weaker, what was lost), and exit gates tracks every claimed control against the test that holds it, including the ones that are unit only or unmet.

Why is it like this? The essays: design and ADR 0001. Long, and deliberately below the fold rather than deleted. They are where the decisions above stop being assertions.

Contributions: CONTRIBUTING.md ends with a wanted list.

Installing

One distribution. Provider SDKs are extras: in-lockstep[anthropic], [openai], [google], [bedrock], [all]. A bare install pulls none of them, because cold start matters in CI.

History

Through 0.1.x this project was a compiler that lowered a markdown spec into GitHub Agentic Workflows. From 0.2.0 it is a different product under the same name: the framework this page describes. It ships below 1.0 because the API is still moving. The compiler line is archived on the compiler-v0.1.x branch. ADR 0001 records why, and what the change cost.

Development

make check     # format, lint, typecheck, test

Metadata

Release files for in-lockstep 0.2.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for in-lockstep 0.2.2
File Size Uploaded
in_lockstep-0.2.2.tar.gz 937.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for in-lockstep 0.2.2
File Interpreter ABI Platform
in_lockstep-0.2.2-py3-none-any.whl Python 3 none any Details

Total release size: 1.5 MB

Release files / in_lockstep-0.2.2.tar.gz

Download URL in_lockstep-0.2.2.tar.gz
Size 937.8 kB
Tags Source
SHA-256 checksum
How to use checksums
6f982623cabf78664d695acd015bb344bbdc5575d98a9e3c8e5b6986b0094437
BLAKE2b-256 checksum
How to use checksums
a14351ef85eaf543ff5e6a38fd7e8782d5e75d41e9e080a748227288695173ab
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 Sep 3, 2026.

Transparency log

Release files / in_lockstep-0.2.2-py3-none-any.whl

Download URL in_lockstep-0.2.2-py3-none-any.whl
Size 514.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
753d6e0c78597ee610116c9e50997fba020ae3c5b09c68107106ece2add48783
BLAKE2b-256 checksum
How to use checksums
01b9437810144006aa2b2cd661641e22c32b596ea02905ef22709b55f9adb5b7
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 Sep 3, 2026.

Transparency log

Release history Release notifications | RSS feed

0.3.1

2 release files

0.3.0

2 release files

This release

0.2.2 This release

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page