zti: the Verified Done gate for AI coding agents
Your agent says the work is done. zti proves it. It re-runs the required
checks itself, seals the result in a hash-chained ZTIP
receipt bound to the exact git tree, and blocks the commit or merge when no
passing receipt exists. The agent's claim is never the input.
This repo is the open client layer of ZTI: the CLI, the gate library, and the enforcement hooks. MIT licensed. It reports to a ZTI Core control plane, which stores receipts, verifies them at commit and merge time, and gives you the fleet dashboard and audit trail.
See it work in public: bitscon/zti-verified-done-demo.
PR #2 is a --no-verify bypass caught red in CI and left open on purpose.
Three enforcement tiers, one binding model
A receipt binds to git write-tree: the content address of exactly what would
be committed. Identical at pre-commit and in CI, so nothing can drift between
what was verified and what ships.
| Tier | Where | What it does |
|---|---|---|
| 1. Runtime hook | Claude Code PreToolUse |
Blocks out-of-contract writes and irreversible commands live during the session. Bash is screened for irreversible patterns and forbidden-path tokens; full Bash scoping is on the roadmap |
| 2. Pre-commit gate | .git/hooks/pre-commit |
Blocks the commit unless a passing receipt covers the staged tree |
| 3. CI required check | GitHub Actions | Catches --no-verify at the merge, on the PR head SHA |
Fail-closed on every path: no receipt, a failed receipt, an unreachable plane, and a license-locked plane all block. Agent-neutral: it governs any committer, human or agent, by git content alone.
Install
pip install zti-cli
The package is zti-cli; the command it installs is zti.
Point it at your plane with .zti/config.json in the repo
({"plane_url": "...", "gate_id": "..."}) plus the gate key in
.zti/gate.key, or use the ZTI_PLANE_URL / ZTI_GATE_ID / ZTI_GATE_KEY
environment variables. Keep .zti/gate.key out of version control.
Use
zti receipt # re-run the contract's required checks, mint a receipt,
# ship it to the plane bound to the staged tree
zti verify --staged # exit 0 only if a passing receipt covers the staged content
zti verify <sha> # same check for a commit (what CI runs)
zti install-hooks # drop the Tier-2 pre-commit gate into .git/hooks
Exit codes: 0 pass · 1 receipt exists but not passing · 2 no receipt ·
3 plane unavailable (fail-closed) · 4 usage error.
A contract is a small JSON document. zti receipt re-runs its
required_checks itself and refuses a passing receipt when they fail:
{"work_id": "billing-fix", "allowed_paths": ["src/**"],
"forbidden_paths": ["db/**"], "required_checks": ["pytest -q"]}
For Tier 3, copy zticli/templates/zti-verify.yml into the governed repo's
.github/workflows/ and mark zti-verify as a required status check in
branch protection.
The Claude Code hook (Tier 1)
hooks/claude-code/ holds the pair:
gated.pyruns beside the repo, loads its contract from the plane, and enforces it with the same gate library that mints receipts. If the plane goes down it keeps enforcing on the cached contract. The plane is never in the evaluation path.pretooluse.pyis the Claude CodePreToolUsehook. It asks the local daemon and blocks on anything but an explicit allow. A dead gate can never silently allow.
Start the daemon beside the repo first. At startup it registers with your
plane (set ZTI_ENROLL_TOKEN first if the plane requires an enrollment
token) and loads the contract it will enforce:
python3 hooks/claude-code/gated.py --repo-root . --repo-name myrepo
Then wire the hook in the governed repo's .claude/settings.json:
{"hooks": {"PreToolUse": [{"matcher": "Write|Edit|NotebookEdit|Bash",
"hooks": [{"type": "command", "command": "python3 /path/to/pretooluse.py"}]}]}}
What you need to run it
A ZTI Core plane. ZTI Core is complete and in early access. Every install includes a free 30-day trial with full functionality, and individual use is free on the honor system. Organizations license it per year; pricing is announced at launch. Start at licensing@zerotrustintelligence.io or zerotrustintelligence.io.
The protocol underneath is open: ZTIP, MIT, with its own spec, schemas, and reference runtime.
Development
pip install -e . pytest
pytest -q
Two suites ship here: the gate library and the runtime hook. The full product battery runs in the ZTI Core tree.
License
MIT. Copyright (c) 2026 Chad McCormack.
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 zti_cli-0.1.0.tar.gz.
File metadata
- Download URL: zti_cli-0.1.0.tar.gz
- Upload date:
- Size: 44.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2267061f2e6c23c8f6649dc4220808cf8b279abb99e665847365baf99a02395e
|
|
| MD5 |
c119b0db8be562b37c47c04327cd30c5
|
|
| BLAKE2b-256 |
4ff2f6545c7d729671111dc2c9e12ec90de1680717c1d607e89ce97cc699daa5
|
Provenance
The following attestation bundles were made for zti_cli-0.1.0.tar.gz:
Publisher:
publish.yml on bitscon/zti-cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
zti_cli-0.1.0.tar.gz -
Subject digest:
2267061f2e6c23c8f6649dc4220808cf8b279abb99e665847365baf99a02395e - Sigstore transparency entry: 2555529035
- Sigstore integration time:
-
Permalink:
bitscon/zti-cli@789444d07954d5a32c952b4c79fe8884fcf897e9 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/bitscon
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@789444d07954d5a32c952b4c79fe8884fcf897e9 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file zti_cli-0.1.0-py3-none-any.whl.
File metadata
- Download URL: zti_cli-0.1.0-py3-none-any.whl
- Upload date:
- Size: 24.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3316ba91340476841bd6f6bd20e57f597c1292fe03fe0c6a8b603604f71f3a17
|
|
| MD5 |
7bb347489f44126f3c4e440ad618385a
|
|
| BLAKE2b-256 |
c10e5a1ae399b26c39373b965a1cb5109da8448cbfd015a12e112cb7b86d3e5e
|
Provenance
The following attestation bundles were made for zti_cli-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on bitscon/zti-cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
zti_cli-0.1.0-py3-none-any.whl -
Subject digest:
3316ba91340476841bd6f6bd20e57f597c1292fe03fe0c6a8b603604f71f3a17 - Sigstore transparency entry: 2555529246
- Sigstore integration time:
-
Permalink:
bitscon/zti-cli@789444d07954d5a32c952b4c79fe8884fcf897e9 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/bitscon
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@789444d07954d5a32c952b4c79fe8884fcf897e9 -
Trigger Event:
workflow_dispatch
-
Statement type: