Skip to content

feat(hooks): implement interceptor hooks system#1253

Merged
chaliy merged 2 commits intomainfrom
feat/issue-1235-hooks-system
Apr 13, 2026
Merged

feat(hooks): implement interceptor hooks system#1253
chaliy merged 2 commits intomainfrom
feat/issue-1235-hooks-system

Conversation

@chaliy
Copy link
Copy Markdown
Contributor

@chaliy chaliy commented Apr 13, 2026

Summary

  • Expand the hooks system from just on_exit to a full interceptor pipeline
  • Add event types: ExecInput, ExecOutput, ToolEvent, ToolResult, ErrorEvent
  • Add hooks: before_exec, after_exec, before_tool, after_tool, on_error
  • Wire before_exec (can rewrite/block scripts), after_exec (observe output), on_error (observe errors) into exec() pipeline
  • Generic fire_hooks() helper for DRY hook chain execution
  • Builder API: .before_exec(), .after_exec(), .before_tool(), .after_tool(), .on_error()
  • Tool hooks defined but not yet wired into builtin pipeline (follow-up)

Test plan

  • before_exec hook modifies script text
  • before_exec hook cancels execution
  • after_exec hook captures output
  • Multiple hooks chain correctly
  • cargo clippy clean

Closes #1235

Add before_exec, after_exec, before_tool, after_tool, on_error hooks
alongside the existing on_exit hook. All hooks use the HookAction
interceptor pattern (Continue/Cancel).

Wired: before_exec (can rewrite/block scripts), after_exec (observe
output), on_error (observe errors). Tool hooks defined but wired in
follow-up (requires builtin pipeline changes).

Builder API: .before_exec(), .after_exec(), .before_tool(),
.after_tool(), .on_error()

Closes #1235
@chaliy chaliy force-pushed the feat/issue-1235-hooks-system branch from d7c80ab to df54cc1 Compare April 13, 2026 11:46
@chaliy chaliy merged commit 351d3f1 into main Apr 13, 2026
27 checks passed
@chaliy chaliy deleted the feat/issue-1235-hooks-system branch April 13, 2026 16:51
chaliy added a commit that referenced this pull request Apr 13, 2026
…ship skills

PR #1253 auto-closed #1235 via `Closes #1235` despite explicitly noting
that tool hooks and HTTP hooks were deferred as follow-up. This left
dead code and missing features hidden behind a closed issue.

Add a rule to both skills: only use closing keywords when every
task/checkbox in the issue is complete. Use `Part of #N` for partial work.
chaliy added a commit that referenced this pull request Apr 13, 2026
…1255)

## Summary

Completes the two main functional gaps from #1235 that PR #1253 deferred
as follow-up:

- **Wire `before_tool`/`after_tool`** into
`execute_registered_builtin()` — hooks can now modify args, cancel tool
invocations, and observe results
- **Add `before_http`/`after_http`** — new
`HttpRequestEvent`/`HttpResponseEvent` event types, interceptor hooks on
`HttpClient` fired around every HTTP request (after allowlist check),
builder API via `BashBuilder::before_http()`/`after_http()`
- **Add "never close half-done issues" rule** to `process-issues` and
`ship` skills to prevent premature issue closure
- **Update `specs/009-implementation-status.md`** with
hooks/interceptors section

### What changed

| File | Change |
|------|--------|
| `hooks.rs` | Add `HttpRequestEvent`/`HttpResponseEvent` types; remove
`#[allow(dead_code)]` |
| `interpreter/mod.rs` | Fire `before_tool`/`after_tool` in builtin
execution; add `fire_after_tool` helper |
| `lib.rs` | Builder fields/methods for HTTP hooks; hook transfer during
build; 6 new tests |
| `network/client.rs` | HTTP hook storage, setters, firing in
`request_with_headers` and `request_with_timeouts` |
| Skills | "never close half-done issues" rule in `process-issues` and
`ship` |
| Spec 009 | Hooks/interceptors status table |

### Security

- `before_http` fires **after** the allowlist check — security boundary
stays in bashkit
- Hooks are registered by the trusted embedder via `BashBuilder` (same
trust model as `HttpHandler`)
- Cancellation messages don't leak internal state

### What remains from #1235

Part of #1235 — the following items from the original issue are still
open:
- Runtime registration API (`bash.hooks().on_exit(...)`)
- Dedicated hooks spec in `specs/`
- Rustdoc guide in `crates/bashkit/docs/`
- `examples/hooks.rs`

## Test plan

- [x] `test_before_tool_hook_modifies_args` — hook rewrites args, output
reflects change
- [x] `test_before_tool_hook_cancels` — hook cancels echo, exit code 1
- [x] `test_after_tool_hook_observes_result` — hook captures tool name,
stdout, exit code
- [x] `test_before_tool_hook_does_not_fire_for_special_builtins` —
declare (special) skipped, echo (registered) fires
- [x] `test_before_http_hook_cancels_request` — hook blocks curl to
blocked.example.com
- [x] `test_after_http_hook_observes_response` — hook wires correctly,
builder accepts it
- [x] 2413 lib tests pass, 123 doctests pass
- [x] `cargo fmt --check` clean
- [x] `cargo clippy --all-targets --all-features -- -D warnings` clean
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: implement interceptor hooks system (before/after exec, tool, http, error)

1 participant