Modular AI push-hook workflow runner
Project description
ai-push-hooks
ai-push-hooks is a configurable pre-push workflow runner for local Git repositories.
It runs module-based steps (collect, LLM, apply, exec, assert) before push so you can automate checks and optional repo maintenance tasks.
Install
Python
uv tool install ai-push-hooks
# or
pipx install ai-push-hooks
Node (wrapper around Python package)
npm install --save-dev ai-push-hooks
# or
pnpm add -D ai-push-hooks
Requirements:
- Python 3.10+ (
python3orpython) is required, including npm installs. opencode-cli(oropencode) is required forllmandapplysteps.ghis required only if you use PR creation viagh_pr_create.
Quick start
-
Install the CLI.
-
Generate a starter config:
ai-push-hooks init --template minimal-docs
-
Wire it into Lefthook:
pre-push: commands: ai-push-hooks: run: ai-push-hooks hook {1} {2}
-
Push as usual. The workflow runs automatically before push completes.
Commands
| Command | What it does |
|---|---|
ai-push-hooks hook <remote-name> <remote-url> |
Runs the configured pre-push workflow. |
ai-push-hooks init --template minimal-docs |
Writes ai-push-hooks.toml starter config. |
ai-push-hooks init --template minimal-docs --force |
Overwrites an existing config file. |
Configuration overview
- Config file lookup order:
ai-push-hooks.toml, then.ai-push-hooks.toml(legacy). - If no config file is present, built-in defaults are used.
- File values are deep-merged over defaults.
- Prompt resolution precedence for
llmandapplysteps:promptprompt_filefallback_prompt_id
Configuration reference
Top-level keys
| Key | Type | Required | Default |
|---|---|---|---|
general |
table | no | built-in values |
llm |
table | no | built-in values |
logging |
table | no | built-in values |
workflow |
table | yes | { modules = ["docs"] } |
modules |
table | yes | { docs = ... } |
[general]
| Key | Type | Default | Description |
|---|---|---|---|
enabled |
bool | true |
Enables or disables the hook globally. |
allow_push_on_error |
bool | false |
If true, push continues even when workflow fails. |
require_clean_worktree |
bool | false |
If true, aborts when local changes exist. |
skip_on_sync_branch |
bool | true |
If true, skips on sync branch/worktree context. |
[llm]
| Key | Type | Default | Description |
|---|---|---|---|
runner |
string | "opencode" |
LLM runner label (currently OpenCode flow). |
model |
string | "openai/gpt-5.3-codex" |
Model passed to OpenCode. |
variant |
string | "" |
Optional OpenCode variant. |
timeout_seconds |
int | 800 |
Timeout per LLM invocation and related OpenCode calls. |
max_parallel |
int | 2 |
Max concurrent read-only steps (collect, llm). |
json_max_retries |
int | 2 |
Retry count for invalid JSON responses. |
invalid_json_feedback_max_chars |
int | 6000 |
Max invalid output included in retry feedback. |
json_retry_new_session |
bool | true |
Starts a new OpenCode session on JSON retry. |
delete_session_after_run |
bool | true |
Deletes OpenCode sessions after completion. |
max_diff_bytes |
int | 180000 |
Max bytes of git diff sent into workflow artifacts. |
session_title_prefix |
string | "ai-push-hooks" |
Prefix for OpenCode session titles. |
[logging]
| Key | Type | Default | Description |
|---|---|---|---|
level |
string | "status" |
Console verbosity (status, info, debug). |
jsonl |
bool | true |
Enables JSONL event logging. |
dir |
string | ".git/ai-push-hooks/logs" |
Directory for hook.jsonl. |
capture_llm_transcript |
bool | true |
Exports OpenCode session transcripts. |
transcript_dir |
string | ".git/ai-push-hooks/transcripts" |
Transcript export directory. |
summary_dir |
string | ".git/ai-push-hooks/summaries" |
Per-run summary JSON directory. |
print_llm_output |
bool | false |
Mirrors raw OpenCode JSON stream to stdout. |
[workflow]
| Key | Type | Required | Description |
|---|---|---|---|
modules |
array of strings | yes | Ordered module IDs to run. Must contain at least one module and each ID must exist under [modules]. |
[modules.<module_id>]
| Key | Type | Required | Description |
|---|---|---|---|
enabled |
bool | no | Enables or disables that module. Default true. |
steps |
array of step tables | yes | Ordered workflow steps for the module. Must be non-empty. |
[[modules.<module_id>.steps]]
| Key | Type | Required | Applies to | Description |
|---|---|---|---|---|
id |
string | yes | all step types | Unique step identifier inside the module. |
type |
string | yes | all step types | One of: collect, llm, apply, exec, assert. |
inputs |
array of strings | no | non-collect steps |
Artifact references from earlier steps. |
output |
string | yes | llm |
Output artifact filename (often .json). |
schema |
string | no | llm |
Validates parsed model output shape. |
prompt |
string | conditional | llm, apply |
Highest-priority prompt source. |
prompt_file |
string | conditional | llm, apply |
Repo-relative or absolute prompt file path. |
fallback_prompt_id |
string | conditional | llm, apply |
Built-in prompt ID used when no higher source resolves. |
collector |
string | yes | collect |
Collector handler ID. |
allow_paths |
array of strings | yes | apply |
File glob allowlist for edits. |
executor |
string | yes | exec |
Exec handler ID. |
assertion |
string | yes | assert |
Assertion handler ID. |
when_env |
string | no | any step | Runs step only when env var parses as true. |
llm and apply are promptable step types: at least one of prompt, prompt_file, or fallback_prompt_id must be set.
Supported handler and schema values
Collectors
| Value | Purpose |
|---|---|
docs_context |
Collects docs-related context and diff artifacts. |
beads_status_context |
Collects branch/beads alignment context. |
pr_context |
Collects PR composition context. |
LLM schemas
| Value | Expected payload |
|---|---|
string_array |
JSON array of strings. |
docs_issue_array |
JSON array of issue objects with at least file and description. |
beads_alignment_result |
JSON object, optionally with commands string array. |
pr_create_payload |
JSON object for PR creation fields. |
Exec handlers
| Value | Purpose |
|---|---|
beads_alignment |
Runs non-interactive Beads commands and writes action report when needed. |
gh_pr_create |
Creates (or reuses) a GitHub PR via gh. |
Assertion handlers
| Value | Purpose |
|---|---|
docs_apply_requires_manual_commit |
Fails when docs were auto-edited and still need user review/commit. |
beads_alignment_clean |
Fails when Beads alignment reports unresolved work. |
Built-in fallback prompt IDs
| Value | Purpose |
|---|---|
docs-query-basic |
Generate doc search queries from diff. |
docs-analysis-basic |
Identify factual documentation drift. |
docs-apply-basic |
Apply minimal doc fixes within allowlist. |
beads-plan-basic |
Build Beads alignment command/report payload. |
pr-compose-basic |
Draft PR title/body/base/head payload. |
Environment variable overrides
Boolean env parsing accepts: 1, true, yes, y, on and 0, false, no, n, off.
| Env var | Effect |
|---|---|
AI_PUSH_HOOKS_SKIP |
If true, sets general.enabled = false. |
AI_PUSH_HOOKS_ALLOW_PUSH_ON_ERROR |
Overrides general.allow_push_on_error. |
AI_PUSH_HOOKS_REQUIRE_CLEAN |
Overrides general.require_clean_worktree. |
AI_PUSH_HOOKS_ALLOW_DIRTY |
If true, forces general.require_clean_worktree = false. |
AI_PUSH_HOOKS_LOG_LEVEL |
Overrides logging.level. |
AI_PUSH_HOOKS_PRINT_LLM_OUTPUT |
Overrides logging.print_llm_output. |
AI_PUSH_HOOKS_MODEL |
Overrides llm.model. |
AI_PUSH_HOOKS_VARIANT |
Overrides llm.variant. |
AI_PUSH_HOOKS_TIMEOUT_SECONDS |
Overrides llm.timeout_seconds (integer). |
when_env is step-level and can point to any env var. A common example is AI_PUSH_HOOKS_CREATE_PR to gate PR creation steps.
Example: docs + PR with opt-in creation
[workflow]
modules = ["docs", "pr"]
[modules.docs]
enabled = true
[[modules.docs.steps]]
id = "collect"
type = "collect"
collector = "docs_context"
[[modules.docs.steps]]
id = "query"
type = "llm"
fallback_prompt_id = "docs-query-basic"
inputs = ["collect/push.diff", "collect/changed-files.txt"]
output = "queries.json"
schema = "string_array"
[[modules.docs.steps]]
id = "analyze"
type = "llm"
fallback_prompt_id = "docs-analysis-basic"
inputs = ["collect/push.diff", "collect/docs-context.txt", "query/queries.json", "collect/recent-commits.txt"]
output = "issues.json"
schema = "docs_issue_array"
[[modules.docs.steps]]
id = "apply"
type = "apply"
fallback_prompt_id = "docs-apply-basic"
inputs = ["collect/push.diff", "collect/docs-context.txt", "analyze/issues.json"]
allow_paths = ["README.md", "docs/**/*.md"]
[[modules.docs.steps]]
id = "assert"
type = "assert"
assertion = "docs_apply_requires_manual_commit"
inputs = ["apply/result.json"]
[modules.pr]
enabled = true
[[modules.pr.steps]]
id = "collect"
type = "collect"
collector = "pr_context"
[[modules.pr.steps]]
id = "compose"
type = "llm"
fallback_prompt_id = "pr-compose-basic"
inputs = ["collect/pr-context.txt", "collect/changed-files.txt", "collect/push.diff", "collect/commits.txt"]
output = "pr-draft.json"
schema = "pr_create_payload"
[[modules.pr.steps]]
id = "create"
type = "exec"
executor = "gh_pr_create"
when_env = "AI_PUSH_HOOKS_CREATE_PR"
inputs = ["compose/pr-draft.json"]
Project details
Release history Release notifications | RSS feed
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 ai_push_hooks-0.1.14.tar.gz.
File metadata
- Download URL: ai_push_hooks-0.1.14.tar.gz
- Upload date:
- Size: 32.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9004ebc98eaab8a9f95dd9405e0655cf0c65c4de1db2041854d5309f04a5470a
|
|
| MD5 |
5b2007cba2aa110cb47100fb4cfa91a8
|
|
| BLAKE2b-256 |
2d3b479913f202d0a475ccac39d521a05acd79c2c5b7db12225b42c7cbbaa402
|
Provenance
The following attestation bundles were made for ai_push_hooks-0.1.14.tar.gz:
Publisher:
release.yml on shanebishop1/ai-push-hooks
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ai_push_hooks-0.1.14.tar.gz -
Subject digest:
9004ebc98eaab8a9f95dd9405e0655cf0c65c4de1db2041854d5309f04a5470a - Sigstore transparency entry: 1171813438
- Sigstore integration time:
-
Permalink:
shanebishop1/ai-push-hooks@ea8bd3f2b1d75cfb4e7277930bcffda580378f0b -
Branch / Tag:
refs/tags/v0.1.14 - Owner: https://github.com/shanebishop1
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ea8bd3f2b1d75cfb4e7277930bcffda580378f0b -
Trigger Event:
push
-
Statement type:
File details
Details for the file ai_push_hooks-0.1.14-py3-none-any.whl.
File metadata
- Download URL: ai_push_hooks-0.1.14-py3-none-any.whl
- Upload date:
- Size: 33.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8978ec0a7cf17accd3c69365d2a4ebff279eadcb5c3a49b920c7ec9c24bccf25
|
|
| MD5 |
a33e04f42c24b04939b21ca5c8072027
|
|
| BLAKE2b-256 |
f41faf9c3dd493146d3efbc57eaddfe397bbbe1947728f111f1a0512ec9a8c00
|
Provenance
The following attestation bundles were made for ai_push_hooks-0.1.14-py3-none-any.whl:
Publisher:
release.yml on shanebishop1/ai-push-hooks
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ai_push_hooks-0.1.14-py3-none-any.whl -
Subject digest:
8978ec0a7cf17accd3c69365d2a4ebff279eadcb5c3a49b920c7ec9c24bccf25 - Sigstore transparency entry: 1171813488
- Sigstore integration time:
-
Permalink:
shanebishop1/ai-push-hooks@ea8bd3f2b1d75cfb4e7277930bcffda580378f0b -
Branch / Tag:
refs/tags/v0.1.14 - Owner: https://github.com/shanebishop1
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@ea8bd3f2b1d75cfb4e7277930bcffda580378f0b -
Trigger Event:
push
-
Statement type: