Skip to content

feat(hooks): Add hooks feature implementation plan#321

Open
quangdang46 wants to merge 19 commits into
masterfrom
feat/hooks
Open

feat(hooks): Add hooks feature implementation plan#321
quangdang46 wants to merge 19 commits into
masterfrom
feat/hooks

Conversation

@quangdang46
Copy link
Copy Markdown
Owner

Hooks Feature Implementation Plan

This PR adds a comprehensive implementation plan for the hooks feature in jcode, based on research of Claude Code, OpenAI Codex, and anomalyco/opencode.

What this PR includes:

  • Plan document (.omo/plans/hooks-implementation.md) — detailed ~450 line implementation plan covering:
    • 27 hook event types (matching Claude Code)
    • 4 handler types (command, prompt, agent, http)
    • Multi-layer config (env vars > user > project)
    • Matcher patterns (exact, multi-value, regex, wildcard)
    • Integration at Registry::execute() in src/tool/mod.rs
    • CLI hooks command with list/add/remove/enable/disable

Design Decisions:

  1. Config layering: JCODE_HOOKS_* env → ~/.jcode/hooks.toml (user) → .jcode/hooks.toml (project wins)
  2. Sync-only first: No async hooks initially
  3. 4 handler types: command, prompt, agent, http
  4. Future migration: Study anomalyco/opencode's plugin architecture for potential future migration to package/plugin model

Research sources:

  • Claude Code (claude-code-best/claude-code): 27 events, 6 handler types
  • OpenAI Codex (codex-rs): 10 events, 3 handler types
  • anomalyco/opencode: V1/V2 plugin hooks for future reference

Next steps (out of scope for this PR):

  1. Implement the hooks feature per the plan
  2. Add tests
  3. Add documentation to CONFIG_REFERENCE.md

Add .omo/ to gitignore to exclude plan files and agent metadata from version control.
- Add HookResult enum with Continue, Blocked, and Failed variants
- Add HookHandlerConfig enum with Command, Prompt, Agent, and Http variants
- Implement execute_command_hook() async function using tokio::process::Command
  - Serialize HookInput to JSON and write to stdin
  - Use tokio::time::timeout for timeout handling
  - Parse stdout as HookOutput and handle exit codes:
    - Exit 0 = continue, Exit 2 = blocked, other = failed
    - Timeout treated as failed
- Implement execute_hook() dispatch function that routes to appropriate handler
- Add comprehensive tests for command execution, blocked hooks, and timeouts
- Stub out Prompt, Agent, and HTTP handlers for future implementation
- Add SessionStart, SessionEnd, PermissionRequest, PermissionDenied, ToolError to HookEvent enum
- Wire ToolError hook in Registry::execute() error path using fire-and-forget tokio::spawn
- Add parsing for new event names in HookEvent::parse()
- Follow existing PreToolUse/PostToolUse hook pattern
- get_handler_matcher() now returns cmd.matcher.as_ref() / http.matcher.as_ref()
- get_handler_condition() now returns cmd.if_.as_deref() / http.if_.as_deref()
- Reorder HookMatcher derive to Serialize, Deserialize (correct order)
Previously load_hooks_config() only supported 2 layers:
1. User level: ~/.jcode/hooks.toml
2. Project level: .jcode/hooks.toml

This adds a 3rd layer with highest priority:
3. Environment variable: JCODE_HOOKS_CONFIG - points to an absolute path

Layer order (highest to lowest priority):
1. JCODE_HOOKS_CONFIG path (env override)
2. .jcode/hooks.toml (project level)
3. ~/.jcode/hooks.toml (user level)

Each layer merges on top of the previous, so env override takes precedence.
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.

1 participant