#10555: feat(hooks): add priority-aware hook registration
stale
size: M
Cluster:
Security Enhancements and Guardrails
## Human View
### Summary
The current hook system calls handlers in registration order. This works until you need execution guarantees — for example, a security sanitization hook **must** run before a logging hook, regardless of which plugin registered first.
This PR adds `src/hooks/priority-hooks.ts` — a standalone module that provides deterministic ordering via numeric priorities:
```
security (1) → core (10) → plugins (50) → logging (100)
```
Lower priority number = runs earlier. Equal priorities preserve insertion order.
#### API
```ts
import {
registerPriorityHook,
triggerPriorityHook,
oncePriorityHook,
} from "./priority-hooks.js";
// Security hook always runs first
registerPriorityHook("command:new", sanitizeInput, { priority: 1, label: "security" });
// Logging always runs last
registerPriorityHook("command:new", logEvent, { priority: 100, label: "logging" });
// Trigger — handlers run in priority order
await triggerPriorityHook(event);
```
Also includes:
- `oncePriorityHook` — auto-remove after first invocation
- `unregisterPriorityHook(eventKey, id)` — remove by stable ID (not function reference)
- `listPriorityHooks` / `getPriorityHookStats` — introspection for debugging
- Error isolation — one handler throwing doesn't block the rest
#### What this does NOT change
- No modifications to existing `internal-hooks.ts`
- No breaking changes — purely additive new file
- Uses the same `InternalHookHandler` / `InternalHookEvent` types
#### Why not modify `internal-hooks.ts` directly?
Backward compatibility. Existing code registers hooks without priorities and expects registration-order execution. This module can be adopted incrementally where ordering matters.
### Test plan
- [x] 14 vitest tests in `priority-hooks.test.ts`
- [x] Priority ordering (security < core < plugin < logging)
- [x] Equal priority preserves insertion order
- [x] Merges general type + specific action handlers with correct sort
- [x] Error in one handler does not stop others
- [x] `once` hooks auto-remove after first call
- [x] Unregister by ID
- [x] Stats tracking
- [x] Clear resets everything
---
## AI View (DCCE Protocol v1.0)
### Metadata
- **Generator**: Claude (Anthropic) via Cursor IDE
- **Methodology**: AI-assisted development with human oversight and review
### AI Contribution Summary
- Solution design and implementation
- Test development (14 test cases)
### Verification Steps Performed
1. Analyzed existing codebase patterns
2. Implemented feature with comprehensive tests
3. Ran test suite (14 tests passing)
### Human Review Guidance
- Core changes are in: `src/hooks/priority-hooks.ts`, `internal-hooks.ts`, `priority-hooks.test.ts`
- Verify test coverage matches the described scenarios
Made with M7 [Cursor](https://cursor.com)
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
- Adds a new standalone hook module (`src/hooks/priority-hooks.ts`) that supports numeric priorities, stable IDs, unregistering by ID, and basic stats/introspection.
- Introduces `triggerPriorityHook()` which merges type-level and specific `type:action` handlers and executes them in priority order with per-handler error isolation.
- Includes a Vitest suite (`src/hooks/priority-hooks.test.ts`) validating ordering, once hooks, unregistering, stats, and clear/reset behavior.
<h3>Confidence Score: 3/5</h3>
- Reasonably safe to merge once deterministic ordering guarantees are enforced.
- Core logic is small and covered by tests, but the module promises insertion-order stability for equal priorities while relying on runtime sort stability; that can break the main advertised guarantee in some environments. Also, duplicate execution can occur if an entry is registered for both the type and specific keys.
- src/hooks/priority-hooks.ts
<!-- greptile_other_comments_section -->
<sub>(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#6405: feat(security): Add HTTP API security hooks for plugin scanning
by masterfung · 2026-02-01
76.6%
#22293: Hooks: add message-filter bundled hook with inbound message pre-filter
by MegaPhoenix92 · 2026-02-21
75.0%
#9914: fix(hooks): resolve bundled hook dist paths and packaging checks
by zimmra · 2026-02-05
75.0%
#15571: feat: infrastructure foundation — hooks, model failover, sessions, ...
by tangcruz · 2026-02-13
74.9%
#11597: feat(hooks): implement message:received hook
by gnufoo · 2026-02-08
74.2%
#7091: feat: add pre-answer hooks system for automatic context injection
by dizhaky · 2026-02-02
73.3%
#16915: fix: await compaction hooks with timeout to prevent cross-session d...
by maximalmargin · 2026-02-15
73.0%
#19565: feat: add agent lifecycle hook events (session, message, error)
by tag-assistant · 2026-02-17
73.0%
#11778: fix(plugins): enforce monotonic hook deny merges
by coygeek · 2026-02-08
72.8%
#19922: feat(hooks): add message:received and message:sent hook events
by NOVA-Openclaw · 2026-02-18
72.3%