Skip to main content

agent-build-gates

Quality gates for agent-built code. Five of them, all pure standard library, plus an optional sixth.

When an agent writes code at volume, the failure that costs most is not a bug. It is work that looks complete and never touched the service it claims to demonstrate: a class that stands in for a queue, a validator that returns ALLOW because the API was unreachable, a fallback chain whose models never got called. Asking for honesty does not catch that. A script that fails the build does.

pip install agent-build-gates

Zero dependencies. ship-gate needs the [strands] extra, because it drives real agent runs and costs money; the other five are pure standard library.

The gates

no-sim-check

Flags substituted integrations: code that fabricates a success for a call it could have made.

no-sim-check $(git ls-files '*.py')

It looks for substitute-object vocabulary (mock, stub, fake, dummy, hardcoded), returns that fabricate a result, "in production this would" deferrals, and a bare return True straight out of an except. Two scoping rules keep the signal usable, both learned from classifying every hit in a 275-file repo:

  • Identifier-aware boundaries. A plain \b stops at underscores and CamelCase humps, so class MockSQSQueue, mock_client and _simulate_human_response are invisible to it while their docstrings trip it. This uses boundaries that break on both.
  • Prose is exempt. The two vocabulary rules never fire on comments or docstrings, because a comment cannot fake an integration. Only code can. The deferral rule still reads comments, since a deferral comment is the marker for a call that was never made.

Escape a justified line with a trailing # nosim:ok <reason>.

The question the tool cannot answer for you, and the one that separates a real hit from noise: was a real call available and skipped? A helper that genuinely raises to drive a recovery path is fault injection and legitimate. Code that fabricates a success is not.

check-no-aws-ids

Blocks AWS account identifiers from entering any tracked text file (binaries skipped): 12-digit account ids, SSO admin profile strings, sso_account references, and ARNs carrying an account field.

check-no-aws-ids $(git ls-files)                  # explicit files
check-no-aws-ids                                  # every tracked file in the current repo
check-no-aws-ids --frozen-regex REGEX $(git ls-files)   # skip lines REGEX matches (append-only history)

Paths resolve against your working directory, so it behaves the same installed from a wheel or vendored into a repo. Extend the known-safe literals at the call site rather than editing the module: scan(files, allow=ALLOW | {"123456789012"}).

Escape a single line with noaws:ok, matched anywhere on it, so it works as # noaws:ok reason in Python and <!-- noaws:ok reason --> in Markdown. Anything that must legitimately contain account-shaped strings needs this: this gate's own tests, and documentation like the paragraph above. The marker covers only its own line, never the rest of the file.

check-no-local-paths

Blocks local machine paths from files bound for a public repo: absolute home directories (/Users/<name>/, /home/<name>/), home-relative project folders (~/Code, ~/Documents, ~/Desktop, ~/Downloads, ~/Docs), /Volumes/, and macOS per-user temp (/private/var/folders, /private/tmp). Plain /tmp is not flagged.

check-no-local-paths $(git ls-files)
check-no-local-paths --frozen-regex '"id": "obs-(0717|0750)"' log.jsonl

Binary files are skipped. Each hit prints as file:line:text, the text cut to 160 characters. Escape a single line with localpath:ok, as # localpath:ok reason in code or <!-- localpath:ok reason --> in Markdown. For an append-only file whose old lines were public before the check existed and cannot be edited, --frozen-regex skips the lines it matches, so the old lines are named instead of the whole file being skipped and new lines are still checked.

check-denylist

Blocks literal strings that must not reach a public repo, such as another team's project name. Those cannot be built into a published gate without publishing the names being protected, so they live in a file your repo does not track, one term per line (blank lines and # comments ignored).

check-denylist $(git ls-files)                       # reads ./.git-denylist
check-denylist --denylist ~/terms.txt --ignore-case $(git ls-files)

Matching is case-sensitive unless you pass --ignore-case. A hit prints denylist: '<term>' found in <file> and never the surrounding line. A missing denylist file exits 2, not 0: a gate that silently scans nothing is worse than one that fails. A caller that wants "no file, no check" tests for the file first. There is deliberately no per-line escape marker, because one in a tracked file would let a protected name through with a comment.

eval_harness

Multi-run evaluation with confidence intervals and significance testing, so a single lucky run cannot be reported as a result.

from agent_build_gates import Case, run_suite, gate, label_match, wilson, case_means

cases = [Case("input text", expected="positive")]  # at least 6 cases to compare to a baseline

result = run_suite(cases, my_run_fn, {"correct": label_match}, n=5)
passed, reasons = gate(result, baseline=previous, min_quality=0.8, metric="correct")
print(wilson(case_means(result, "correct")))

run_fn(input) -> (output, tokens) is yours, so the harness never assumes a framework. gate combines a quality floor, a cost ceiling and a paired sign-flip test against a frozen baseline, and returns every reason it failed rather than the first.

The case is the unit of evidence, not the run. The n runs of each case are averaged into one score before any interval or test, because repeats of one prompt are not independent samples. A paired test on k cases cannot return p below 2 * 0.5**k, so with fewer than 6 cases the baseline comparison cannot detect a regression; gate then fails with "regression undetectable" rather than passing. label_match scores an answer correct only when the whole normalised output is the expected label, so "positive, not negative" does not count for both. wilson gives the interval on the rate; pass it case_means, not the flat run scores.

Each result carries cases_sha256, a fingerprint of its case set, and whatever you pass as run_suite(..., meta={...}) (model, temperature, a prompt hash). Both are saved with a baseline, and gate refuses to compare against a baseline measured on a different case set.

ship-gate, behind an extra

ship_gate composes the harness into one auditable GO or NO-GO verdict over real agent runs, and writes the verdict plus the underlying runs to JSON so the decision can be re-examined. It drives a framework and it spends money, so it is optional:

pip install 'agent-build-gates[strands]'

Importing agent_build_gates never pulls that in. Import agent_build_gates.ship_gate directly when you want it; without the extra it raises an ImportError naming the install command.

Testing your gates

These gates are themselves tested, which is the point. A tripwire with no test proving it fires is an unverified claim about the thing that verifies everything else. When this package's own anti-simulation gate was finally given paired positive and negative controls, it turned out to be wrong in both directions at once: it fired on comments describing deliberate fault injection, and it missed the substituted classes it existed to catch. Fixing it took one repo from 133 reported hits to 0 and surfaced nine real substituted integrations that had been invisible.

Measure the precision and recall of your own gates before you trust a green run.

Changes

  • 0.3.0 (2026-10-19): added check-no-local-paths and check-denylist.

License

MIT.

Metadata

Release files for agent-build-gates 0.3.1

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

Source distribution (sdist)

Source distribution for agent-build-gates 0.3.1
File Size Uploaded Provenance Actions
agent_build_gates-0.3.1.tar.gz 34.3 kB With provenance Details for agent_build_gates-0.3.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for agent-build-gates 0.3.1
File Interpreter ABI Platform Actions
agent_build_gates-0.3.1-py3-none-any.whl Python 3 none any Details for agent_build_gates-0.3.1-py3-none-any.whl

Total release size: 57.9 kB

Release files / agent_build_gates-0.3.1.tar.gz

Download URL agent_build_gates-0.3.1.tar.gz
Size 34.3 kB
Tags Source
SHA-256 checksum
How to use checksums
368d6f199fb2edcd2eff93404bdb1d24718710988c54073d27161e7b081b2c0b
BLAKE2b-256 checksum
How to use checksums
052866a603e41e6854624c9cc5fce5fe62086ce84ee76bb0300c0c709caabede
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","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}

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 20, 2026.

Transparency log

Release files / agent_build_gates-0.3.1-py3-none-any.whl

Download URL agent_build_gates-0.3.1-py3-none-any.whl
Size 23.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1c670f6a4d19c8c9c83c05f01c5525e51c43605e8a388b6bca17d492dcb2a3d3
BLAKE2b-256 checksum
How to use checksums
57d5750a34f79258dd4d9249e529b54274d5db978fadbe8c059d2ae75ae1154d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.0 {"installer":{"name":"uv","version":"0.13.0","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}

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 20, 2026.

Transparency log

Security for agent-build-gates 0.3.1

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.

Select from 2 files

Attestation for agent_build_gates-0.3.1.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 20, 2026.

Transparency log

A 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.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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