jq— required at runtime byack.shpolyhook— the underlying hook transport- An AI coding tool that fires hooks (Claude Code, Cursor, Windsurf, Cline, Amp, or any polyhook-compatible tool)
Install jq if missing:
# macOS
brew install jq
# Debian/Ubuntu
apt-get install jq
# Windows (via Chocolatey)
choco install jqDownload the latest release for your platform from GitHub Releases and place it on your PATH:
# macOS/Linux — example, adjust version and platform
curl -L https://github.com/polyhook/steplock/releases/latest/download/steplock-$(uname -s)-$(uname -m).tar.gz | tar -xz
mv steplock /usr/local/bin/Verify:
steplock --versionRequires Rust (stable).
git clone https://github.com/polyhook/steplock.git
cd steplock
cargo build --release
mv target/release/steplock /usr/local/bin/# Cargo
cargo install steplockRun inside your repo root. Creates the .steplock/checklists/ directory tree:
steplock initOr create manually:
mkdir -p .steplock/checklistsAdd to .gitignore — commit checklists, ignore runtime state:
.steplock/sessions/
.steplock/audit.log
Each checklist lives in its own subdirectory. The directory name is the checklist identifier.
.steplock/
└── checklists/
└── git-push-quality-gate/
├── config.toml
└── flow.mmd
config.toml — trigger and behaviour:
#:schema https://raw.githubusercontent.com/polyhook/steplock/refs/heads/main/schemas/checklist-config.schema.json
on_event = "tool:before"
on_tool = "bash"
match_input = "input.command.contains('git push')"
reset = "session"
allow_preview_request = trueflow.mmd — checklist items as a Mermaid state diagram:
stateDiagram-v2
[*] --> clean_code
clean_code --> test_coverage
test_coverage --> documentation
documentation --> no_secrets
no_secrets --> [*]
clean_code : Did you write clean, readable code?
test_coverage: Did you increase test coverage by at least a little?
documentation: Did you update relevant documentation?
no_secrets : Did you check for hardcoded secrets or credentials?
See examples/git-push-quality-gate/ for a working reference.
Tell your AI tool to invoke steplock on hook events. Configuration varies by tool.
In your project's .claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "steplock" }
]
}
]
}
}Follow your tool's hook registration docs and point the hook command at steplock. polyhook normalises the event format — no per-tool changes needed.
Trigger a matched action from your AI tool (e.g. ask it to run git push). Expected output in the hook response:
Did you write clean, readable code?
When finished, run: sh /path/to/repo/.steplock/sessions/<session-id>/git-push-quality-gate/ack.sh
Then retry your original command.
Check the audit log for a machine-readable record:
cat .steplock/audit.logsteplock validate # check every config.toml / flow.mmd under .steplock/checklists/ for errors
steplock clean # remove all session state under .steplock/sessions/ (checklists restart fresh)Add the schema hint to config.toml (already shown above) for Taplo autocomplete and inline validation via the Even Better TOML VS Code extension.
For flow.mmd, install Mermaid Preview to get syntax highlighting and diagram preview.
Both extensions are listed in .vscode/extensions.json — VS Code prompts to install them on repo open.