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.
Files changed (36) hide show
  1. package/CHANGELOG.md +69 -1
  2. package/README.md +90 -82
  3. package/SECURITY.md +7 -2
  4. package/ai-push-hooks.toml +1 -1
  5. package/docs/configuration.md +339 -0
  6. package/package.json +3 -3
  7. package/pyproject.toml +12 -3
  8. package/src/ai_push_hooks/artifacts.py +19 -6
  9. package/src/ai_push_hooks/cli.py +24 -8
  10. package/src/ai_push_hooks/config.py +220 -49
  11. package/src/ai_push_hooks/engine.py +93 -43
  12. package/src/ai_push_hooks/executors/apply.py +121 -43
  13. package/src/ai_push_hooks/executors/ask.py +30 -13
  14. package/src/ai_push_hooks/executors/exec.py +61 -22
  15. package/src/ai_push_hooks/executors/runner_workflow.py +38 -16
  16. package/src/ai_push_hooks/executors/runners/claude.py +18 -6
  17. package/src/ai_push_hooks/executors/runners/codex.py +9 -3
  18. package/src/ai_push_hooks/executors/runners/command.py +25 -9
  19. package/src/ai_push_hooks/executors/runners/contracts.py +52 -25
  20. package/src/ai_push_hooks/executors/runners/opencode.py +74 -21
  21. package/src/ai_push_hooks/executors/runners/opencode_support.py +15 -5
  22. package/src/ai_push_hooks/executors/runners/process.py +26 -7
  23. package/src/ai_push_hooks/executors/runners/registry.py +14 -5
  24. package/src/ai_push_hooks/executors/step_commands.py +58 -18
  25. package/src/ai_push_hooks/git_utils.py +92 -27
  26. package/src/ai_push_hooks/hook.py +48 -12
  27. package/src/ai_push_hooks/install.py +40 -18
  28. package/src/ai_push_hooks/modules/beads.py +18 -7
  29. package/src/ai_push_hooks/modules/docs.py +17 -7
  30. package/src/ai_push_hooks/modules/pr.py +18 -7
  31. package/src/ai_push_hooks/paths.py +6 -2
  32. package/src/ai_push_hooks/plugin_loader.py +79 -26
  33. package/src/ai_push_hooks/plugins.py +3 -1
  34. package/src/ai_push_hooks/prompts_builtin.py +1 -1
  35. package/src/ai_push_hooks/types.py +47 -27
  36. 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.1...HEAD
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
- **Modular AI checks before `git push`.**
3
+ [![CI](https://github.com/shanebishop1/ai-push-hooks/actions/workflows/ci.yml/badge.svg)](https://github.com/shanebishop1/ai-push-hooks/actions/workflows/ci.yml) [![npm beta](https://img.shields.io/npm/v/ai-push-hooks/beta?label=npm%20beta)](https://www.npmjs.com/package/ai-push-hooks/v/beta)
4
4
 
5
- Use **OpenCode, Codex, or Claude Code** to review outgoing changes, check that code and docs agree, and apply scoped fixes. Combine AI reasoning with your own scripts, tests, and rules in a repo-local Git hook.
5
+ **Agentic linting for the rules your coding agent forgot.**
6
6
 
7
- - **Check alignment:** compare changes with documentation, requirements, or task state.
8
- - **Ask or apply:** get findings without edits, or let AI update explicitly allowed files.
9
- - **Verify before pushing:** run deterministic checks and block when your rules fail.
10
- - **Build your workflow:** choose modules, prompts, and runners per step.
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 --template minimal-docs
34
+ npx --no-install ai-push-hooks init
17
35
  npx --no-install ai-push-hooks install
18
36
  ```
19
37
 
20
- Choose your [runner and model](#choose-your-ai) in `ai-push-hooks.toml`, then push normally. The starter checks docs, applies fixes, and stops for review if anything changed.
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
- ## Modular By Design
42
+ ## Example: Check Your Rules
25
43
 
26
- A workflow is a list of modules. Each module combines the steps it needs:
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
- | Step | Purpose |
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
- Use a review-only module, an apply-only module, or a full collect/ask/apply/verify flow. Add your existing lint and test commands alongside AI checks. No AI runner is needed for deterministic-only workflows.
48
+ ```python
49
+ import json
37
50
 
38
- ## Choose Your AI
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
- ```toml
43
- [llm]
44
- runner = "opencode"
45
-
46
- [runners.opencode]
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
- [runners.claude]
55
- type = "claude"
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
- Each `ask` or `apply` step can override the default with, for example, `runner = "claude"`. You can review with one tool and apply with another.
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
- ## Example: Docs Alignment
68
+ ```toml
69
+ [llm]
70
+ runner = "opencode"
65
71
 
66
- This workflow asks AI to find documentation drift, applies narrow fixes, and requires human review when files change. Use it with the runner settings above:
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 = ["docs"]
78
+ modules = ["rules"]
71
79
 
72
- [[modules.docs.steps]]
80
+ [[modules.rules.steps]]
73
81
  id = "collect"
74
82
  type = "collect"
75
- collector = "docs_context"
83
+ python = "checks/hooks.py:collect_rules"
76
84
 
77
- [[modules.docs.steps]]
85
+ [[modules.rules.steps]]
78
86
  id = "review"
79
87
  type = "ask"
80
- prompt = "Check that the docs match the outgoing code changes. Return a JSON array of factual issues with file and description fields, or [] if aligned."
81
- inputs = ["collect/push.diff", "collect/docs-context.txt"]
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.docs.steps]]
86
- id = "fix"
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
- assertion = "docs_apply_requires_manual_commit"
96
- inputs = ["fix/result.json"]
96
+ python = "checks/hooks.py:assert_rules"
97
+ inputs = ["review/issues.json"]
97
98
  ```
98
99
 
99
- **Want findings only?** Remove the `fix` and `review-required` steps. `ask` saves a response; findings do not block a push unless you add an assertion to evaluate them.
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 test verification too?** Change the workflow list to `modules = ["docs", "verify"]` and append a module using your project's test command:
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
- ```toml
104
- [[modules.verify.steps]]
105
- id = "tests"
106
- type = "exec"
107
- command = ["npm", "test"]
108
- timeout_seconds = 300
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
- A nonzero test exit blocks the push. For requirements or plan alignment, use project access and a prompt such as: "Compare the outgoing diff with docs/requirements.md. Identify unmet acceptance criteria and missing tests." AI review complements verification; it does not replace running the tests.
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
- ## Extend It
122
+ ```toml
123
+ [runners.codex]
124
+ type = "codex"
114
125
 
115
- - **Prompts:** write them inline, load a `prompt_file`, or use a built-in prompt.
116
- - **Custom checks:** use argv commands or repo-local Python callbacks.
117
- - **Task alignment:** use the Beads collector and actions with the optional `bd` CLI.
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
- See the [configuration guide](docs/configuration.md) for settings, callbacks, and built-in handlers.
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. Review and commit any applied edits before retrying.
126
- - `apply` checks file and Git state before and after copying allowlisted changes back. It does not auto-commit.
127
- - Runners, scripts, and callbacks are local programs, not an OS sandbox. Use only trusted configuration.
128
- - Repository content may be sent to your runner's model provider. Review its privacy and billing terms.
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**. This is historical evidence, not a current suite result or proof
121
- for every provider, model, authentication mode, platform, or live `apply` path.
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.
@@ -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-terra"
15
+ model = "openai/gpt-5.6-luna"
16
16
  variant = ""
17
17
  timeout_seconds = 800
18
18
  max_parallel = 2