ai-push-hooks 0.3.1 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +69 -1
- package/README.md +90 -82
- package/SECURITY.md +7 -2
- package/ai-push-hooks.toml +1 -1
- package/docs/configuration.md +339 -0
- package/package.json +3 -3
- package/pyproject.toml +12 -3
- package/src/ai_push_hooks/artifacts.py +19 -6
- package/src/ai_push_hooks/cli.py +24 -8
- package/src/ai_push_hooks/config.py +220 -49
- package/src/ai_push_hooks/engine.py +93 -43
- package/src/ai_push_hooks/executors/apply.py +121 -43
- package/src/ai_push_hooks/executors/ask.py +30 -13
- package/src/ai_push_hooks/executors/exec.py +61 -22
- package/src/ai_push_hooks/executors/runner_workflow.py +38 -16
- package/src/ai_push_hooks/executors/runners/claude.py +18 -6
- package/src/ai_push_hooks/executors/runners/codex.py +9 -3
- package/src/ai_push_hooks/executors/runners/command.py +25 -9
- package/src/ai_push_hooks/executors/runners/contracts.py +52 -25
- package/src/ai_push_hooks/executors/runners/opencode.py +74 -21
- package/src/ai_push_hooks/executors/runners/opencode_support.py +15 -5
- package/src/ai_push_hooks/executors/runners/process.py +26 -7
- package/src/ai_push_hooks/executors/runners/registry.py +14 -5
- package/src/ai_push_hooks/executors/step_commands.py +58 -18
- package/src/ai_push_hooks/git_utils.py +92 -27
- package/src/ai_push_hooks/hook.py +48 -12
- package/src/ai_push_hooks/install.py +40 -18
- package/src/ai_push_hooks/modules/beads.py +18 -7
- package/src/ai_push_hooks/modules/docs.py +17 -7
- package/src/ai_push_hooks/modules/pr.py +18 -7
- package/src/ai_push_hooks/paths.py +6 -2
- package/src/ai_push_hooks/plugin_loader.py +79 -26
- package/src/ai_push_hooks/plugins.py +3 -1
- package/src/ai_push_hooks/prompts_builtin.py +1 -1
- package/src/ai_push_hooks/types.py +47 -27
- package/run.sh +0 -29
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,72 @@ All notable changes to this project are documented here. The format is based on
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.3.3] - 2026-09-14
|
|
8
|
+
|
|
9
|
+
This is a beta patch release. Python and npm both use `0.3.3`, the canonical
|
|
10
|
+
Git tag is `v0.3.3`, npm uses the `beta` dist-tag, and GitHub marks the release
|
|
11
|
+
as a prerelease. PyPI does not provide a separate beta channel, so Python users
|
|
12
|
+
must select the exact `0.3.3` version.
|
|
13
|
+
|
|
14
|
+
This is a documentation and validation patch only; it adds no runtime features.
|
|
15
|
+
|
|
16
|
+
### Documentation
|
|
17
|
+
|
|
18
|
+
- Added a tested deterministic postcondition recipe that distinguishes successful
|
|
19
|
+
runner execution from a verified fix, while preserving legitimate no-op applies.
|
|
20
|
+
- Recorded live runner validation results for OpenCode, Claude Code, and Codex.
|
|
21
|
+
- Clarified the focused pre-push use case and how the tool complements hook
|
|
22
|
+
managers, background reviewers, and broader agent workflow frameworks.
|
|
23
|
+
- Documented custom-agent CLI support through the custom command runner.
|
|
24
|
+
- Updated the Codex conformance check to 0.152.0 and verified live project reads
|
|
25
|
+
and allowlisted edits with `gpt-5.6-luna`.
|
|
26
|
+
|
|
27
|
+
## [0.3.2] - 2026-09-12
|
|
28
|
+
|
|
29
|
+
This is a beta patch release. Python and npm both use `0.3.2`, the canonical
|
|
30
|
+
Git tag is `v0.3.2`, npm uses the `beta` dist-tag, and GitHub marks the release
|
|
31
|
+
as a prerelease. PyPI does not provide a separate beta channel, so Python users
|
|
32
|
+
must select the exact `0.3.2` version.
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- Added a pinned Ruff 0.13.3 formatting policy for Python sources, tests, and scripts.
|
|
37
|
+
- Updated the default OpenCode model and README positioning to
|
|
38
|
+
`openai/gpt-5.6-luna`.
|
|
39
|
+
- Clarified that built-in mutating steps are serialized, while trusted custom
|
|
40
|
+
command runners, including project-access `ask` commands, are not enforced
|
|
41
|
+
read-only.
|
|
42
|
+
- Removed the unused secondary shell launcher in favor of the canonical Python
|
|
43
|
+
console script and npm wrapper.
|
|
44
|
+
|
|
45
|
+
### Fixed
|
|
46
|
+
|
|
47
|
+
- Review initial publication of the configured base branch against the empty
|
|
48
|
+
tree, while retaining configured-base comparison for new feature branches.
|
|
49
|
+
- Persist bounded diffs as valid UTF-8, truncating at character boundaries and
|
|
50
|
+
representing malformed bytes with replacement characters within the budget.
|
|
51
|
+
- Hardened pull-request creation by validating generated payload types,
|
|
52
|
+
reconciling failed `gh` calls against GitHub, and keeping remote credentials
|
|
53
|
+
out of diagnostics.
|
|
54
|
+
- Bounded config, prompt, and callback source reads and rejected unsafe config
|
|
55
|
+
file types.
|
|
56
|
+
- Rejected duplicate workflow identifiers and simplified workflow step result
|
|
57
|
+
handling.
|
|
58
|
+
- Made source distributions complete and added validation of their unpacked
|
|
59
|
+
test suite and wheel builds with the minimum supported setuptools 77 backend.
|
|
60
|
+
- Standardized development and release validation on the isolated project
|
|
61
|
+
`.[dev]` extra instead of repeating tool lists.
|
|
62
|
+
- Restored the PyPI release job's checkout permission and pinned the OpenCode
|
|
63
|
+
contract test's base container image.
|
|
64
|
+
|
|
65
|
+
### Documentation
|
|
66
|
+
|
|
67
|
+
- Added an agent setup skill and CI/npm beta badges.
|
|
68
|
+
- Explained the manual-commit assertion and why applied edits are not part of
|
|
69
|
+
the commit already being pushed.
|
|
70
|
+
- Included the configuration guide in the npm package and removed its link to
|
|
71
|
+
the local-only runner verification report.
|
|
72
|
+
|
|
7
73
|
## [0.3.1] - 2026-09-10
|
|
8
74
|
|
|
9
75
|
### Changed
|
|
@@ -149,7 +215,9 @@ the exact `0.2.0` version rather than a PyPI beta channel.
|
|
|
149
215
|
- Preserved Git porcelain paths and protected pre-existing dirty allowlisted files during apply steps.
|
|
150
216
|
- Clarified module-local artifact references and standardized the repository hook integration.
|
|
151
217
|
|
|
152
|
-
[Unreleased]: https://github.com/shanebishop1/ai-push-hooks/compare/v0.3.
|
|
218
|
+
[Unreleased]: https://github.com/shanebishop1/ai-push-hooks/compare/v0.3.3...HEAD
|
|
219
|
+
[0.3.3]: https://github.com/shanebishop1/ai-push-hooks/compare/v0.3.2...v0.3.3
|
|
220
|
+
[0.3.2]: https://github.com/shanebishop1/ai-push-hooks/compare/v0.3.1...v0.3.2
|
|
153
221
|
[0.3.1]: https://github.com/shanebishop1/ai-push-hooks/compare/v0.3.0...v0.3.1
|
|
154
222
|
[0.3.0]: https://github.com/shanebishop1/ai-push-hooks/compare/v0.2.1...v0.3.0
|
|
155
223
|
[0.2.1]: https://github.com/shanebishop1/ai-push-hooks/compare/v0.2.0...v0.2.1
|
package/README.md
CHANGED
|
@@ -1,134 +1,142 @@
|
|
|
1
1
|
# ai-push-hooks
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://github.com/shanebishop1/ai-push-hooks/actions/workflows/ci.yml) [](https://www.npmjs.com/package/ai-push-hooks/v/beta)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**Agentic linting for the rules your coding agent forgot.**
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
`AGENTS.md` tells an agent how to work. **ai-push-hooks checks whether it followed through.** Think of it as the inverse of `AGENTS.md`: a second pass over outgoing changes before `git push`, catching guidelines the agent forgot or neglected.
|
|
8
|
+
|
|
9
|
+
Use **OpenCode, Codex, Claude Code, or your own agentic CLI** to check rules that need judgment, not just a regex. Report violations, apply scoped fixes, and block pushes with explicit checks. It's a hedge against missed instructions, not a guarantee that AI catches everything.
|
|
10
|
+
|
|
11
|
+
## Rules Worth Checking
|
|
12
|
+
|
|
13
|
+
| Your rule | What the check looks for |
|
|
14
|
+
| --- | --- |
|
|
15
|
+
| No empty marketing speak. | Vague claims and filler in changed pages. |
|
|
16
|
+
| Use our typed API client. | Components making direct backend requests. |
|
|
17
|
+
| Test behavior, including failures. | Changed behavior without meaningful test coverage. |
|
|
18
|
+
| Keep migrations backward-compatible. | Destructive changes that break a rolling deployment. |
|
|
19
|
+
|
|
20
|
+
Write your own rules in prompts or supply a rules file as context. These are examples of checks you configure, not built-in guarantees.
|
|
21
|
+
|
|
22
|
+
## Why This Tool?
|
|
23
|
+
|
|
24
|
+
Keep your coding workflow; add a check before Git sends the commits. ai-push-hooks combines repository-specific AI checks, scripts, and explicit pass/fail gates around the outgoing diff, using your existing coding CLIs. No daemon or hosted review service is required.
|
|
25
|
+
|
|
26
|
+
Use it alongside [Lefthook](https://github.com/evilmartians/lefthook) for hook management and [roborev](https://github.com/kenn-io/roborev) for background reviews. [Archon](https://github.com/coleam00/Archon) and [TAKT](https://github.com/nrslib/takt) orchestrate development tasks; this tool deliberately stays narrower. Its job is to check your rules before a push, not take over how you build the project.
|
|
11
27
|
|
|
12
28
|
## Quick Start
|
|
13
29
|
|
|
30
|
+
Install the [ai-push-hooks skill](https://github.com/shanebishop1/ai-push-hooks/blob/main/skills/ai-push-hooks/SKILL.md), tell your agent what intelligent checks you want before pushes, and let it set up the modules for you.
|
|
31
|
+
|
|
14
32
|
```bash
|
|
15
33
|
npm install --save-dev ai-push-hooks@beta
|
|
16
|
-
npx --no-install ai-push-hooks init
|
|
34
|
+
npx --no-install ai-push-hooks init
|
|
17
35
|
npx --no-install ai-push-hooks install
|
|
18
36
|
```
|
|
19
37
|
|
|
20
|
-
|
|
38
|
+
Install and authenticate your chosen AI CLI. The current `init` starter checks documentation; replace its configuration with the rules-checking example below to check `AGENTS.md` instead. Then push normally.
|
|
21
39
|
|
|
22
40
|
[Other installation options](docs/configuration.md#installation) | [Existing hook managers](docs/configuration.md#hook-managers)
|
|
23
41
|
|
|
24
|
-
##
|
|
42
|
+
## Example: Check Your Rules
|
|
25
43
|
|
|
26
|
-
|
|
44
|
+
This workflow supplies the outgoing diff and your root `AGENTS.md` explicitly, asks for violations, and blocks if any are reported. It does not rely on the runner automatically loading agent instructions.
|
|
27
45
|
|
|
28
|
-
|
|
29
|
-
| --- | --- |
|
|
30
|
-
| `collect` | Gather the outgoing diff and relevant context. |
|
|
31
|
-
| `ask` | Ask AI for plain text or schema-validated JSON. |
|
|
32
|
-
| `apply` | Let AI edit a temporary workspace; copy back only allowlisted changes. |
|
|
33
|
-
| `exec` | Run a command, Python callback, or built-in action. |
|
|
34
|
-
| `assert` | Enforce a rule and block the push if it fails. |
|
|
46
|
+
In `checks/hooks.py`:
|
|
35
47
|
|
|
36
|
-
|
|
48
|
+
```python
|
|
49
|
+
import json
|
|
37
50
|
|
|
38
|
-
|
|
51
|
+
from ai_push_hooks.plugins import CollectorResult, PluginContext
|
|
39
52
|
|
|
40
|
-
Set the default runner in `ai-push-hooks.toml`. Change it to `codex` or `claude` to switch tools:
|
|
41
53
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
type = "opencode"
|
|
48
|
-
model = "provider/model-id" # Replace with an available OpenCode model.
|
|
49
|
-
project_access = "artifacts"
|
|
54
|
+
def collect_rules(context: PluginContext) -> CollectorResult:
|
|
55
|
+
return CollectorResult(artifacts={
|
|
56
|
+
"push.diff": context.push.diff_text,
|
|
57
|
+
"rules.txt": (context.repo_root / "AGENTS.md").read_text(encoding="utf-8"),
|
|
58
|
+
})
|
|
50
59
|
|
|
51
|
-
[runners.codex]
|
|
52
|
-
type = "codex"
|
|
53
60
|
|
|
54
|
-
|
|
55
|
-
|
|
61
|
+
def assert_rules(context: PluginContext) -> dict:
|
|
62
|
+
issues = json.loads(context.inputs["review/issues.json"].read_text(encoding="utf-8"))
|
|
63
|
+
return {"ok": issues == [], "message": "Review findings in review/issues.json."}
|
|
56
64
|
```
|
|
57
65
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
OpenCode defaults to collected artifacts only. Set `project_access = "project"` for repository reads; Codex and Claude default to project access. Each runner uses its own authentication and model identifiers.
|
|
61
|
-
|
|
62
|
-
Other tools, including Pi, can use a [custom command runner](docs/configuration.md#custom-runners).
|
|
66
|
+
In `ai-push-hooks.toml`:
|
|
63
67
|
|
|
64
|
-
|
|
68
|
+
```toml
|
|
69
|
+
[llm]
|
|
70
|
+
runner = "opencode"
|
|
65
71
|
|
|
66
|
-
|
|
72
|
+
[runners.opencode]
|
|
73
|
+
type = "opencode"
|
|
74
|
+
model = "openai/gpt-5.6-luna"
|
|
75
|
+
project_access = "project"
|
|
67
76
|
|
|
68
|
-
```toml
|
|
69
77
|
[workflow]
|
|
70
|
-
modules = ["
|
|
78
|
+
modules = ["rules"]
|
|
71
79
|
|
|
72
|
-
[[modules.
|
|
80
|
+
[[modules.rules.steps]]
|
|
73
81
|
id = "collect"
|
|
74
82
|
type = "collect"
|
|
75
|
-
|
|
83
|
+
python = "checks/hooks.py:collect_rules"
|
|
76
84
|
|
|
77
|
-
[[modules.
|
|
85
|
+
[[modules.rules.steps]]
|
|
78
86
|
id = "review"
|
|
79
87
|
type = "ask"
|
|
80
|
-
prompt = "Check
|
|
81
|
-
inputs = ["collect/push.diff", "collect/
|
|
88
|
+
prompt = "Check the outgoing diff against rules.txt. Inspect repository context as needed. Report only concrete violations introduced by these changes, with file and description fields. Return a JSON array, or [] if none. Do not edit files."
|
|
89
|
+
inputs = ["collect/push.diff", "collect/rules.txt"]
|
|
82
90
|
output = "issues.json"
|
|
83
91
|
schema = "docs_issue_array"
|
|
84
92
|
|
|
85
|
-
[[modules.
|
|
86
|
-
id = "
|
|
87
|
-
type = "apply"
|
|
88
|
-
prompt = "Fix only the reported documentation drift. Keep edits minimal."
|
|
89
|
-
inputs = ["collect/push.diff", "review/issues.json"]
|
|
90
|
-
allow_paths = ["README.md", "docs/**/*.md"]
|
|
91
|
-
|
|
92
|
-
[[modules.docs.steps]]
|
|
93
|
-
id = "review-required"
|
|
93
|
+
[[modules.rules.steps]]
|
|
94
|
+
id = "gate"
|
|
94
95
|
type = "assert"
|
|
95
|
-
|
|
96
|
-
inputs = ["
|
|
96
|
+
python = "checks/hooks.py:assert_rules"
|
|
97
|
+
inputs = ["review/issues.json"]
|
|
97
98
|
```
|
|
98
99
|
|
|
99
|
-
|
|
100
|
+
`docs_issue_array` is the existing schema name for `{file, description}` findings; it works for code rules too. A missing rules file or a failed check blocks the push by default. Findings live in the run artifacts under `.git/ai-push-hooks/`.
|
|
100
101
|
|
|
101
|
-
**Want
|
|
102
|
+
**Want fixes too?** Add an `apply` step with the findings, your rules, and an explicit `allow_paths` list, then recheck and run tests. [Runner completion is not proof that a fix landed](docs/configuration.md#deterministic-postconditions-after-apply): verify the result. Applied edits are not auto-committed: review the diff, commit approved changes, and retry the push.
|
|
102
103
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
104
|
+
## Build Your Workflow
|
|
105
|
+
|
|
106
|
+
Each module combines the steps it needs:
|
|
107
|
+
|
|
108
|
+
| Step | Purpose |
|
|
109
|
+
| --- | --- |
|
|
110
|
+
| `collect` | Gather the outgoing diff and relevant context. |
|
|
111
|
+
| `ask` | Ask AI for findings or another response. |
|
|
112
|
+
| `apply` | Edit a temporary workspace; propagate only allowlisted changes. |
|
|
113
|
+
| `exec` | Run scripts, tests, or other actions. |
|
|
114
|
+
| `assert` | Evaluate a verdict and block the push if it fails. |
|
|
115
|
+
|
|
116
|
+
`ask` alone does not block on findings; add an `assert` gate. Combine AI review with your existing linters and tests, not instead of them. Independent analysis can run concurrently; built-in `exec`, `assert`, and `apply` steps are serialized. Trusted custom command runners, including project-access `ask` commands, are not enforced read-only.
|
|
110
117
|
|
|
111
|
-
|
|
118
|
+
## Choose Your AI
|
|
119
|
+
|
|
120
|
+
OpenCode, Codex, and Claude Code have first-class adapters. OpenCode defaults to **`openai/gpt-5.6-luna`**. Explicit runner profiles use their own model settings. To use Codex or Claude Code, add its profile and change `[llm].runner`:
|
|
112
121
|
|
|
113
|
-
|
|
122
|
+
```toml
|
|
123
|
+
[runners.codex]
|
|
124
|
+
type = "codex"
|
|
114
125
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
- **Pull requests:** compose a PR with AI and create it with the optional `gh` CLI.
|
|
119
|
-
- **Opt-in steps:** gate a step with `when_env`.
|
|
126
|
+
[runners.claude]
|
|
127
|
+
type = "claude"
|
|
128
|
+
```
|
|
120
129
|
|
|
121
|
-
|
|
130
|
+
Each `ask` or `apply` step can override the runner, so one tool can review and another can fix. **Any other agentic CLI, including Pi, can integrate through a [custom command runner](docs/configuration.md#custom-runners)**: supply a noninteractive command or a thin wrapper. Use model identifiers available to your provider.
|
|
122
131
|
|
|
123
132
|
## Control And Safety
|
|
124
133
|
|
|
125
|
-
- Errors block pushes by default.
|
|
126
|
-
- `apply`
|
|
127
|
-
- Runners, scripts, and callbacks are local programs, not an OS sandbox.
|
|
128
|
-
-
|
|
129
|
-
|
|
130
|
-
Logs and run summaries live under `.git/ai-push-hooks/`. OpenCode transcripts are captured there by default. See [Security](SECURITY.md) for access and data-handling details.
|
|
134
|
+
- Errors block pushes by default. AI judgments can still miss violations or report false positives.
|
|
135
|
+
- `apply` validates file and Git state and limits propagated edits to `allow_paths`. It does not auto-commit.
|
|
136
|
+
- Runners, scripts, and callbacks are trusted local programs, not an OS sandbox.
|
|
137
|
+
- Local hooks can be bypassed; retain CI for required enforcement.
|
|
138
|
+
- Repository content may be sent to your model provider. Review its privacy and billing terms.
|
|
131
139
|
|
|
132
|
-
To intentionally skip one push: `AI_PUSH_HOOKS_SKIP=1 git push`.
|
|
140
|
+
Logs and run summaries live under `.git/ai-push-hooks/`. OpenCode transcripts are captured there by default. To intentionally skip one push: `AI_PUSH_HOOKS_SKIP=1 git push`.
|
|
133
141
|
|
|
134
|
-
[Configuration](docs/configuration.md) | [Contributing](CONTRIBUTING.md) | [Changelog](CHANGELOG.md) | [MIT License](LICENSE)
|
|
142
|
+
[Configuration](docs/configuration.md) | [Security](SECURITY.md) | [Contributing](CONTRIBUTING.md) | [Changelog](CHANGELOG.md) | [MIT License](LICENSE)
|
package/SECURITY.md
CHANGED
|
@@ -117,7 +117,12 @@ The [0.3.0 release record](CHANGELOG.md#030---2026-09-09) documented a pinned
|
|
|
117
117
|
Lefthook suite reporting **407 tests with no skips**, an OpenCode **1.18.29**
|
|
118
118
|
contract smoke test with an in-process loopback mock provider and no external
|
|
119
119
|
model call, and version/help-only checks for Codex **0.148.0** and Claude
|
|
120
|
-
**2.1.220**.
|
|
121
|
-
|
|
120
|
+
**2.1.220**. The bounded validation snapshot also records Codex **0.152.0** on
|
|
121
|
+
2026-09-14: its synthetic fixture verified a nonce read and an allowlisted marker
|
|
122
|
+
apply followed by a deterministic postcondition. See the [runner validation
|
|
123
|
+
snapshot](docs/configuration.md#live-validation-snapshot). Together, these records
|
|
124
|
+
are historical or bounded evidence, not a current suite result or proof for every
|
|
125
|
+
provider, model, authentication mode, platform, live `apply` path, or a general
|
|
126
|
+
security guarantee.
|
|
122
127
|
Treat generated-hook path checks and the Lefthook runner as integration
|
|
123
128
|
safeguards, not isolation boundaries.
|
package/ai-push-hooks.toml
CHANGED
|
@@ -12,7 +12,7 @@ base_branch = "main"
|
|
|
12
12
|
# Repository callbacks use python = "path/to/file.py:callable" and command
|
|
13
13
|
# steps use a direct argv array; both are trusted local code.
|
|
14
14
|
runner = "opencode"
|
|
15
|
-
model = "openai/gpt-5.6-
|
|
15
|
+
model = "openai/gpt-5.6-luna"
|
|
16
16
|
variant = ""
|
|
17
17
|
timeout_seconds = 800
|
|
18
18
|
max_parallel = 2
|