Sembl
A deterministic accountability gate for AI coding agents.
Sembl checks what an AI coding agent actually changed against the bounds the change was supposed to stay in — which files it may touch, which it must not, how big the diff may get — and whether it lied about what it touched or what it tested. It runs after the agent and before a human approves, and returns a single verdict: PASS / WARN / BLOCK.
declared bounds + the agent's real diff -> sembl verify -> PASS / WARN / BLOCK
The check is deterministic (no LLM in the loop), executor-neutral (Cursor, Claude Code, Codex, Aider, OpenCode — Sembl never sees the agent), and free to run in CI. Same inputs, same verdict, every time.
Sembl is the gate. If you want the whole pipeline — spec → bounds → executor → gate → merge, with every stage swappable and every artifact recorded — that's sembl-stack (site), which runs this gate at its core.
Why
AI agents are strong executors. The gap is no longer writing the code — it is trusting what the agent did without reading every line. As agents get more autonomous and humans review less, you need a repeatable, mechanical check that the change stayed inside its declared bounds and didn't fabricate its results.
What Sembl does: deterministically catch objective, checkable problems in a diff — out-of-scope edits, edits in forbidden areas, files the agent claimed to change but didn't, and "tests passed" claims with no evidence.
What Sembl does not do: it does not make the agent smarter, and it does not judge code quality or maintainability. That's a reviewer's job, and an LLM reviewer does it about as well — so it isn't Sembl's claim. Sembl's edge is narrow and honest: determinism, zero cost, and auditability — a gate you can put in CI that gives the same answer every time and that nobody can argue with.
How it works
- Declare the bounds of the change — the files it may edit, areas it must not touch, and (optionally) a size budget. Produce this with whatever you already use (see Declaring bounds).
- Your agent does the work.
sembl verifycompares the real git diff against the bounds and returns PASS / WARN / BLOCK. With--report, it also cross-checks the agent's own success report and flags fabricated file claims and unevidenced test passes.
pip install sembl
# after your agent has edited the repo:
sembl verify --wo-file bounds.json --report agent-report.json
sembl verify — BLOCK
Files changed 7
Scope (out of scope) infra/deploy.yaml
Forbidden hits none
Fabricated claims src/payments/refund.ts
Validation evidenced missing: pytest
Churn vs budget 7 files > 6
Reasons • fabricated claims (reported but unchanged): src/payments/refund.ts
• out-of-scope edits: infra/deploy.yaml
Exit codes: PASS=0, WARN=0 (or 1 with --strict), BLOCK=1. Add --json
for machine-readable output in CI.
Declaring bounds (bring your own)
verify reads a small, portable contract. Only four fields matter — anything
that can emit them can drive the gate:
{
"editable_paths": ["src/auth/"],
"forbidden_areas": ["migrations/", "infra/"],
"churn_budget": { "max_files": 6, "max_lines": 200 }
}
Produce it however you like:
- From a planning tool (recommended).
sembl boundsturns what an upstream tool already wrote into a bounds file:sembl bounds --spec-kit specs/001-feature --out bounds.json # GitHub Spec Kit sembl bounds --from kiro|tessl|agents-md|cursor-rules # other presets sembl bounds --config adapter.json # custom (declarative)
Spec Kit'stasks.md(and the other tools' artifacts) already name the exact file paths for each task — those map straight ontoeditable_paths. Use the planner to decide what to build; use Sembl to verify the agent stayed in those lines. Adding a new tool is a config entry, not code — seedocs/integrations.md. - By hand. Write the four fields yourself. It's a normal JSON file.
sembl generate(beta, optional). Sembl can also produce a fuller Work Order JSON thatverifyreads directly — see Beta: Work Order generation. This is optional and interchangeable with the tools above.
What verify checks (all deterministic)
| Check | Signal | Verdict |
|---|---|---|
| Scope | a changed file is outside editable_paths |
out-of-scope (BLOCK in strict, else WARN) |
| Forbidden | a changed file is inside forbidden_areas |
BLOCK |
| Fabrication | the report claims a file changed, but the diff doesn't show it | BLOCK |
| Validation evidence | the report says a test/check passed, with no exit code or output to back it | WARN |
| Churn | the diff exceeds max_files / max_lines |
WARN |
Tests are always allowed alongside in-scope edits. The verdict rolls up to BLOCK
(hard contract breach), WARN (soft signal), or PASS (clean). --strict makes
WARN a failing exit code for CI gating.
The executor report (the --report file) is JSON the agent or your harness
emits; Sembl never trusts it — it only uses it to catch contradictions with the
real diff. Common shapes are recognized (files_modified, changes[],
tests_passed, a checks[] list, …).
Gate it in CI
verify can score a PR's diff directly — no working-tree checkout needed — so it
drops into CI as a hard gate. Feed it a patch with --diff (or --diff - for
stdin):
git diff origin/main...HEAD | sembl verify --wo-file bounds.json --diff - --strict
Or use the GitHub Action on every pull request (see
examples/github-workflow.yml):
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
- uses: speedvibecode/sembl@v0.2.0
with:
bounds: bounds.json
strict: "false" # advisory by default; true for a hard scope gate
Integrations
verify auto-discovers a bounds.json (then .sembl/bounds.json) at the repo
root, so most integrations run zero-arg. Every one is just a trigger for the same
command. Full recipes: docs/integrations.md.
- GitHub Action — gate every PR (above).
- pre-commit — gate local commits. The hook runs
verify --staged, so it scores exactly the commit being made — unstaged worktree noise never leaks into the verdict:- repo: https://github.com/speedvibecode/sembl rev: v0.2.0 hooks: [{ id: sembl-verify }]
- Agent harnesses — run verify the moment the agent stops editing. Claude Code
(
Stophook), Aider (--test-cmd), OpenCode (post-edit hook), or any harness that can run a shell command. Seeexamples/. - MCP — let an agent (or an orchestrator supervising a sub-agent) call the gate
with no shell: it hands over a diff + what it declared, and gets back the
PASS/WARN/BLOCK verdict. The general case for main-agent-verifies-sub-agent.
Zero-install — paste into your MCP client (
.mcp.json, Cursor, Windsurf, …):{ "mcpServers": { "sembl": { "command": "uvx", "args": ["--from", "sembl[mcp]", "sembl-mcp"] } } }
Orpip install "sembl[mcp]"and runsembl-mcp. Tools:gate_pr(one call — picks the base ref, diffs the branch, discovers bounds, returns the verdict),verify_change,bounds_from_spec,list_presets,doctor, plus betaclarify_task/generate_work_order(the full CLI surface). IDE setup indocs/ide-quickstart.md; example config inexamples/mcp/; recipes indocs/integrations.md. - Agent Skills — drop-in skills in
skills/(copy to.claude/skills/):sembl-verify-subagent(main-agent-verifies-sub-agent),sembl-setup-bounds, andsembl-gate-pr.
Install
pip install sembl
# As an isolated tool
uv tool install sembl
From source:
git clone https://github.com/speedvibecode/sembl
cd sembl
uv pip install -e .
Status & honesty
Sembl went through a long generation-first phase. We tested its central premise — that compiling a rich up-front contract makes the agent produce better outcomes — and our own results did not support it: a one-line task did as well as an eight-part Work Order for a capable agent. So we stopped claiming it.
What survived testing, and what Sembl now is:
verify— the accountability gate. This is the product. Deterministic checks over a real diff; covered by the test suite.generate/clarify/ graph context — beta, optional, unproven as an outcome-improver. Kept because they're a convenient way to produce a bounds file, but if you already use GitHub Spec Kit / Tessl / Kiro, use that instead and feed its output toverify.
We make no claim that Sembl improves what an agent produces. Its claim is narrow and true: a repeatable, executor-neutral, free check that a change stayed in declared bounds and didn't fabricate its results.
Beta: Work Order generation (optional)
Optional and unproven as an outcome-improver (see Status & honesty above) — the
older generation half of Sembl. sembl generate --task "..." --provider openai
(needs one provider key: openai/anthropic/gemini/nvidia/openrouter/
tokenrouter/local ollama/claude-cli) drafts a "Work Order" — a scoped
contract + executor prompt + work-order.json that verify --wo-file reads
directly — plus clarify/doctor/show/list and optional graph context
(--graph-mode). It's interchangeable with GitHub Spec Kit and similar tools;
reach for it only if you don't already have a spec/planning step. Full command
reference and setup: sembl.vercel.app/docs.html#generate.
Local test
.venv\Scripts\python.exe -m pytest tests\ -q
python -m compileall -q sembl tests
Releasing
Publishing uses GitHub Actions and Trusted Publishing (OIDC); no API tokens are
stored. .github/workflows/release.yml publishes to PyPI when you publish a
GitHub Release whose tag (v<version>) matches pyproject.toml and
sembl/__init__.py. See VERSIONING.md.
Models write code. Sembl makes the change accountable.
Release files for sembl 0.3.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 | |
|---|---|---|---|
| sembl-0.3.0.tar.gz | 117.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sembl-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 206.3 kB
Release files / sembl-0.3.0.tar.gz
| Download URL | sembl-0.3.0.tar.gz |
|---|---|
| Size | 117.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
53ee52c9c204623ec61e90693e02a629cd24c8cb8313e58c1ced6a7028b20fe7
|
|
BLAKE2b-256 checksum How to use checksums |
858d447f962d1b25489b6a239dfa077a844fcd43b3ad3acbfcfe31ad15f71547
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Jul 13, 2026.
Transparency logRelease files / sembl-0.3.0-py3-none-any.whl
| Download URL | sembl-0.3.0-py3-none-any.whl |
|---|---|
| Size | 89.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6ee7e5a34fcfe3a26fbec742d37f67044cdcb18f22acf11006a4edd326124304
|
|
BLAKE2b-256 checksum How to use checksums |
d32c4bbc5a44ccd2da8199999e45b02ba5ba36cda480cc49fed635b883dcda01
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
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 Jul 13, 2026.
Transparency log