Skip to content

fix: align installer hook schema with current Claude Code format - #84

Merged
Tony363 merged 1 commit into
mainfrom
fix/installer-hook-schema
Mar 18, 2026
Merged

fix: align installer hook schema with current Claude Code format#84
Tony363 merged 1 commit into
mainfrom
fix/installer-hook-schema

Conversation

@Tony363

@Tony363 Tony363 commented Mar 18, 2026

Copy link
Copy Markdown
Owner

Summary

  • install-with-sondera.sh: Replace outdated flat-object hook schema (user-prompt-submit with args/blocking/timeout) with current array-based format covering all 14 lifecycle events (PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, etc.)
  • test-sondera-integration.sh: Add schema validation step that verifies CamelCase event keys and array format, catching outdated configurations
  • SONDERA_INTEGRATION.md: Update Production Setup description to reflect full lifecycle event coverage

Context

The installer was generating settings.local.json with a deprecated schema that didn't match the actual Claude Code hook format used in the project's own .claude/settings.local.json. This caused a mismatch between what the installer produces and what Claude Code expects.

Test plan

  • bash -n install-with-sondera.sh — shell syntax valid
  • bash -n test-sondera-integration.sh — shell syntax valid
  • Generated JSON validated through python3 -m json.tool
  • Output structure matches current .claude/settings.local.json format

🤖 Generated with Claude Code

Summary by Sourcery

Align the Sondera installer-generated Claude hook configuration with the current Claude Code lifecycle hook schema and ensure it stays validated.

New Features:

  • Generate a full set of lifecycle hook entries (14 events) in settings.local.json when installing Sondera, using the current array-based schema.

Bug Fixes:

  • Fix mismatch between the installer-generated hook configuration and the actual Claude Code hook schema, avoiding deprecated flat user-prompt-submit hooks.

Enhancements:

  • Add a schema validation step to the Sondera integration test script to enforce the array-based hook format with CamelCase event keys.
  • Clarify production setup documentation to state that policy enforcement now covers all Claude lifecycle events.

Summary by CodeRabbit

  • Documentation

    • Updated production setup documentation to reflect expanded policy-enforced validation scope across 14 lifecycle events.
  • Configuration

    • Updated hook configuration to support event-specific validation triggers replacing the previous single-hook model.
  • Tests

    • Added validation checks for hook configuration format compliance.

The install-with-sondera.sh script generated settings.local.json using an
outdated flat-object schema with kebab-case keys and deprecated properties
(args, blocking, timeout). This updates it to the current array-based
format with CamelCase event keys covering all 14 lifecycle events.

- Update installer to generate correct hook schema (array-of-matcher format)
- Add schema validation step to test-sondera-integration.sh
- Update SONDERA_INTEGRATION.md to reflect full lifecycle coverage

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@sourcery-ai

sourcery-ai Bot commented Mar 18, 2026

Copy link
Copy Markdown

Reviewer's Guide

Aligns the installer-generated Claude Code hook configuration with the current array-based, CamelCase lifecycle hook schema and adds a test-time schema guard plus matching documentation updates.

Sequence diagram for lifecycle event hook execution with new array-based schema

sequenceDiagram
  actor Developer
  participant ClaudeClient
  participant HookDispatcher
  participant SonderaClaudeHook

  Developer->>ClaudeClient: Trigger action that causes UserPromptSubmit
  ClaudeClient->>HookDispatcher: Emit UserPromptSubmit event
  HookDispatcher->>HookDispatcher: Look up hooks[UserPromptSubmit]
  HookDispatcher->>HookDispatcher: Match matcher "*" and select command hook
  HookDispatcher->>SonderaClaudeHook: Execute "$HOOK_PATH --verbose user-prompt-submit"
  SonderaClaudeHook-->>HookDispatcher: Return exit status and output
  HookDispatcher-->>ClaudeClient: Apply policy decision / result
  ClaudeClient-->>Developer: Continue workflow with validated action
Loading

Class diagram for updated Claude Code hook configuration schema

classDiagram

  class HooksConfig {
    Map~LifecycleEvent,LifecycleEventHookList~ hooks
  }

  class LifecycleEventHookList {
    List~LifecycleEventHook~ items
  }

  class LifecycleEventHook {
    string matcher
    List~HookEntry~ hooks
  }

  class HookEntry {
    CommandHook commandHook
  }

  class CommandHook {
    string type
    string command
  }

  class LifecycleEvent {
    PreToolUse
    PermissionRequest
    PostToolUse
    PostToolUseFailure
    UserPromptSubmit
    Notification
    Stop
    SubagentStart
    SubagentStop
    TeammateIdle
    TaskCompleted
    PreCompact
    SessionStart
    SessionEnd
  }

  class OldFlatHookSchema {
    string command
    List~string~ args
    bool blocking
    int timeout
  }

  HooksConfig "1" --> "*" LifecycleEventHookList : contains
  LifecycleEventHookList "1" --> "*" LifecycleEventHook : items
  LifecycleEventHook "1" --> "*" HookEntry : hooks
  HookEntry "1" --> "1" CommandHook : commandHook
  HooksConfig "1" --> "*" LifecycleEvent : keys

  OldFlatHookSchema <.. HooksConfig : replaced_by
Loading

File-Level Changes

Change Details Files
Update installer to emit array-based lifecycle hook schema covering all current Claude Code events.
  • Replace single flat user-prompt-submit hook object with per-event CamelCase keys (e.g., PreToolUse, PostToolUse, UserPromptSubmit, SessionStart) each mapped to an array of matcher/hook definitions.
  • Configure each lifecycle event to call the same sondera hook binary with a --verbose flag and an event-specific subcommand string.
  • Ensure generated .claude/settings.local.json structurally matches the project’s canonical Claude settings format.
install-with-sondera.sh
Add integration test guard that validates the new hook schema shape and key naming.
  • Load the generated .claude/settings.local.json in Python and inspect the hooks object.
  • Fail the test if the legacy kebab-case user-prompt-submit key is present.
  • Assert that PreToolUse exists, uses CamelCase naming, and is configured as an array, not a flat object, with clear error messages and remediation hint.
test-sondera-integration.sh
Document that the production Sondera integration now covers all Claude lifecycle events.
  • Adjust the Production setup description to state that policy-enforced validation applies across all 14 lifecycle events and list representative examples.
SONDERA_INTEGRATION.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Mar 18, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The changes expand Sondera integration from a single user-prompt-submit hook to fourteen event-specific hooks (PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, etc.), with corresponding documentation updates and schema validation logic to enforce the new CamelCase array-based hook format.

Changes

Cohort / File(s) Summary
Sondera Hook Configuration & Validation
install-with-sondera.sh, test-sondera-integration.sh
Replaces single user-prompt-submit hook with 14 event-specific hooks, each invoking Sondera in verbose mode. Adds validation checkpoint to enforce new CamelCase hook schema and reject outdated kebab-case format.
Documentation Update
SONDERA_INTEGRATION.md
Expands Production Setup security line to specify policy-enforced validation across all 14 lifecycle events instead of generic description.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

Poem

🐰 Fourteen hooks now dance in line,
Where once just one did shine,
PreToolUse to SessionEnd's call,
Sondera guards them all! ✨
From kebab-case we flee,
CamelCase harmony! 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description provides a clear summary of changes, context, and test plan, but does not follow the required template structure with sections like Type of Change, Design Principle Compliance, Exceptions & Justifications, and formal Testing checkboxes. Restructure the description to follow the repository's template, including Type of Change selection, SOLID/KISS/Let It Crash compliance sections, and formal Testing checkboxes.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: aligning the installer's hook schema with the current Claude Code format, which is the core objective across all three modified files.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/installer-hook-schema
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • The new hook commands drop the --socket "$SOCKET_PATH" argument that was present in the previous schema, so the Sondera hook may no longer know which socket to use; consider preserving the socket flag in each command invocation.
  • All hook entries repeat the same matcher/hooks structure with only the event-specific suffix changing; consider generating this JSON via a small loop or template to reduce duplication and the risk of inconsistent edits across events.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new hook commands drop the `--socket "$SOCKET_PATH"` argument that was present in the previous schema, so the Sondera hook may no longer know which socket to use; consider preserving the socket flag in each command invocation.
- All hook entries repeat the same `matcher`/`hooks` structure with only the event-specific suffix changing; consider generating this JSON via a small loop or template to reduce duplication and the risk of inconsistent edits across events.

## Individual Comments

### Comment 1
<location path="install-with-sondera.sh" line_range="138" />
<code_context>
-      "timeout": 5000
-    }
+    "PreToolUse": [
+      { "matcher": "*", "hooks": [{ "type": "command", "command": "$HOOK_PATH --verbose pre-tool-use" }] }
+    ],
+    "PermissionRequest": [
</code_context>
<issue_to_address>
**issue (bug_risk):** The new hook commands no longer pass the socket path, which may break integration if the hook expects it.

Previously this hook was called with `--socket "$SOCKET_PATH"`, but the new config runs `$HOOK_PATH --verbose ...` without referencing `SOCKET_PATH`. If the hook still needs the socket flag to talk to Sondera, it will fail at runtime. Please either add the socket argument back (e.g. `"$HOOK_PATH --socket $SOCKET_PATH --verbose pre-tool-use"` or via an `args` array) or confirm that the hook implementation no longer requires it.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread install-with-sondera.sh
"timeout": 5000
}
"PreToolUse": [
{ "matcher": "*", "hooks": [{ "type": "command", "command": "$HOOK_PATH --verbose pre-tool-use" }] }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): The new hook commands no longer pass the socket path, which may break integration if the hook expects it.

Previously this hook was called with --socket "$SOCKET_PATH", but the new config runs $HOOK_PATH --verbose ... without referencing SOCKET_PATH. If the hook still needs the socket flag to talk to Sondera, it will fail at runtime. Please either add the socket argument back (e.g. "$HOOK_PATH --socket $SOCKET_PATH --verbose pre-tool-use" or via an args array) or confirm that the hook implementation no longer requires it.

@github-actions

Copy link
Copy Markdown
Contributor

PAL MCP Consensus Code Review (via AWS Bedrock)

Overview

This PR updates the Sondera integration installer to align with Claude Code's current hook schema format. The changes migrate from the deprecated flat kebab-case hook configuration (user-prompt-submit) to the new array-based CamelCase event system (PreToolUse, PostToolUse, etc.). The PR touches 3 files:

  • SONDERA_INTEGRATION.md - Updated documentation
  • install-with-sondera.sh - Rewrote hook configuration generation
  • test-sondera-integration.sh - Added schema validation

Changed Files: 3 (0 Python files - all shell scripts and markdown)
Lines Changed: +68, -7

Critical Issues

None identified. This is a schema migration fix with proper validation.

High Priority

None identified. The implementation is sound for this migration task.

Medium Priority

1. Hardcoded Socket Path Reference

File: install-with-sondera.sh:140
Issue: The hook commands reference $SOCKET_PATH variable but don't actually pass it via --socket flag like the old schema did.

Old format:

"command": "$HOOK_PATH",
"args": ["--socket", "$SOCKET_PATH"]

New format:

"command": "$HOOK_PATH --verbose pre-tool-use"

Impact: The Sondera hook binary might not know which socket to connect to. Verify that:

  • The hook binary reads socket path from environment variable, or
  • The socket path is hardcoded/discoverable by default, or
  • The --socket flag should be added back to each command

Recommendation: Verify with Sondera documentation or add --socket $SOCKET_PATH to each hook command if needed.

2. Missing Error Handling in Validation Script

File: test-sondera-integration.sh:30-53
Issue: The Python validation uses inline script without proper error context if JSON parsing fails.

Recommendation: Add a try-except block to catch JSON decode errors:

try:
    with open('.claude/settings.local.json') as f:
        data = json.load(f)
except json.JSONDecodeError as e:
    print(f'ERROR: Invalid JSON - {e}', file=sys.stderr)
    sys.exit(1)

3. Incomplete Hook Coverage

File: install-with-sondera.sh:137-178
Issue: All 14 hooks use identical configuration (just different event names). Consider if:

  • Some events should be non-blocking (e.g., Notification, TeammateIdle)
  • Some events need different timeout values
  • Some events should be disabled by default for performance

Current: All hooks are blocking with default timeout (likely 5000ms based on old config)
Consideration: Review if PreToolUse blocking every tool call could significantly impact performance.

Positive Observations

Schema Modernization ✓

  • Correctly migrates from deprecated flat schema to array-based matcher system
  • Uses proper CamelCase event keys matching Claude Code's current API
  • All 14 documented lifecycle events are now covered (vs just 1 previously)

Comprehensive Testing ✓

  • Added proactive schema validation in test script
  • Validation checks for both old schema presence (regression prevention) and new schema structure
  • Clear error messages guide users to re-run installer if schema is wrong

Documentation Alignment ✓

  • Updated SONDERA_INTEGRATION.md to explicitly mention "14 lifecycle events"
  • Provides examples of event types (PreToolUse, PostToolUse, UserPromptSubmit, SessionStart)
  • Maintains security focus messaging

Clean Implementation ✓

  • No code duplication (uses loop-like structure in JSON generation)
  • Consistent --verbose flag across all hooks for debugging
  • Preserves existing environment variable substitution pattern

Review Summary

Category Rating Notes
Security 4/5 Good - maintains policy enforcement, socket path handling needs verification
Code Quality 4/5 Clean shell scripting, good validation, minor error handling improvements needed
Architecture 5/5 Correct schema migration, properly covers all lifecycle events
Testing 4/5 Good validation added, could use JSON error handling and integration test

Key Strengths

  1. Critical Fix: Addresses breaking change in Claude Code hook system
  2. Complete Coverage: All 14 events vs previous 1 event coverage
  3. Backward Detection: Validates against old schema to prevent regressions
  4. Clear Documentation: Updated docs match implementation

Recommended Actions Before Merge

  1. Verify Socket Path Handling: Confirm Sondera hook binary doesn't require explicit --socket flag
  2. Add JSON Error Handling: Improve test script robustness with try-except
  3. Consider Hook Tuning: Review if all hooks should be blocking with same timeout
  4. Integration Test: Run actual Sondera workflow to verify hooks trigger correctly

Risk Assessment

Low Risk - This is a necessary schema migration. The validation script prevents broken deployments. Main risk is if socket path handling changed (medium severity but likely caught in testing).


Code-Specific Analysis

Shell Script Quality (install-with-sondera.sh)

✓ Proper variable quoting ("$HOOK_PATH", "$SOCKET_PATH")
✓ Heredoc usage for clean JSON generation
✓ Consistent formatting across all 14 hook definitions
⚠️ Consider parameterizing repeated structure to reduce duplication

Test Script Quality (test-sondera-integration.sh)

✓ Clear test output with color-coded results
✓ Logical progression (file exists → schema valid → server running)
✓ Helpful error messages with remediation steps
⚠️ Python inline script could be extracted to helper function
⚠️ Missing JSON parse error handling

Documentation Quality (SONDERA_INTEGRATION.md)

✓ Accurate reflection of implementation
✓ Clear use case differentiation
✓ Specific event examples provided
⚠️ Could link to Claude Code hook documentation for reference


This review was generated by manual comprehensive analysis using Claude Sonnet 4.5.
PAL MCP Consensus Code Review service was unavailable - this represents single-model analysis.
Review is advisory - please use human judgment for final decisions.
Recommended: Run full integration test with Sondera before merge.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
install-with-sondera.sh (1)

137-178: Consider generating the 14 hook entries from a single event list.

This block is easy to drift over time (especially with the validator script). A loop/template-based emission would be safer to maintain.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@install-with-sondera.sh` around lines 137 - 178, Replace the repeated
hard-coded JSON hook entries with a generator that iterates over a single EVENTS
list and emits each event block; for example, define an array named EVENTS
containing the 14 event names (e.g., "PreToolUse", "PermissionRequest", ...,
"SessionEnd") and loop to print the JSON object using the existing HOOK_PATH
variable so each entry uses "$HOOK_PATH --verbose <event-name>"—update the part
of the script that currently outputs the literal blocks (the section referencing
HOOK_PATH and the event keys) to use this loop/templating approach so the JSON
remains consistent and avoids manual drift.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@install-with-sondera.sh`:
- Around line 137-178: The hook command strings currently embed an unescaped
$HOOK_PATH which will break for paths with spaces/special chars; update each
hook entry (e.g., "PreToolUse", "PermissionRequest", "PostToolUse",
"PostToolUseFailure", "UserPromptSubmit", "Notification", "Stop",
"SubagentStart", "SubagentStop", "TeammateIdle", "TaskCompleted", "PreCompact",
"SessionStart", "SessionEnd") to use an escaped/quoted variable (replace
$HOOK_PATH with a safely-escaped variant such as $HOOK_PATH_ESCAPED or wrap the
variable in quotes) so the command strings correctly handle spaces and
shell-significant characters.

In `@test-sondera-integration.sh`:
- Around line 30-53: The script only validates the 'PreToolUse' key; update the
python check in test-sondera-integration.sh to validate all required lifecycle
event keys by defining a list of the 14 expected CamelCase event names (instead
of just 'PreToolUse'), then iterate over that list and for each ensure it exists
in hooks and is a list; replace the single-key checks for 'PreToolUse' and
'user-prompt-submit' with this loop so any missing or non-array event (e.g.,
hooks[event] not isinstance(list)) causes an error and non-zero exit.

---

Nitpick comments:
In `@install-with-sondera.sh`:
- Around line 137-178: Replace the repeated hard-coded JSON hook entries with a
generator that iterates over a single EVENTS list and emits each event block;
for example, define an array named EVENTS containing the 14 event names (e.g.,
"PreToolUse", "PermissionRequest", ..., "SessionEnd") and loop to print the JSON
object using the existing HOOK_PATH variable so each entry uses "$HOOK_PATH
--verbose <event-name>"—update the part of the script that currently outputs the
literal blocks (the section referencing HOOK_PATH and the event keys) to use
this loop/templating approach so the JSON remains consistent and avoids manual
drift.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 22ff35ee-664f-437c-9950-9d76b4090644

📥 Commits

Reviewing files that changed from the base of the PR and between 70a1512 and 7693af5.

📒 Files selected for processing (3)
  • SONDERA_INTEGRATION.md
  • install-with-sondera.sh
  • test-sondera-integration.sh

Comment thread install-with-sondera.sh
Comment on lines +137 to +178
"PreToolUse": [
{ "matcher": "*", "hooks": [{ "type": "command", "command": "$HOOK_PATH --verbose pre-tool-use" }] }
],
"PermissionRequest": [
{ "matcher": "*", "hooks": [{ "type": "command", "command": "$HOOK_PATH --verbose permission-request" }] }
],
"PostToolUse": [
{ "matcher": "*", "hooks": [{ "type": "command", "command": "$HOOK_PATH --verbose post-tool-use" }] }
],
"PostToolUseFailure": [
{ "matcher": "*", "hooks": [{ "type": "command", "command": "$HOOK_PATH --verbose post-tool-use-failure" }] }
],
"UserPromptSubmit": [
{ "matcher": "*", "hooks": [{ "type": "command", "command": "$HOOK_PATH --verbose user-prompt-submit" }] }
],
"Notification": [
{ "matcher": "*", "hooks": [{ "type": "command", "command": "$HOOK_PATH --verbose notification" }] }
],
"Stop": [
{ "matcher": "*", "hooks": [{ "type": "command", "command": "$HOOK_PATH --verbose stop" }] }
],
"SubagentStart": [
{ "matcher": "*", "hooks": [{ "type": "command", "command": "$HOOK_PATH --verbose subagent-start" }] }
],
"SubagentStop": [
{ "matcher": "*", "hooks": [{ "type": "command", "command": "$HOOK_PATH --verbose subagent-stop" }] }
],
"TeammateIdle": [
{ "matcher": "*", "hooks": [{ "type": "command", "command": "$HOOK_PATH --verbose teammate-idle" }] }
],
"TaskCompleted": [
{ "matcher": "*", "hooks": [{ "type": "command", "command": "$HOOK_PATH --verbose task-completed" }] }
],
"PreCompact": [
{ "matcher": "*", "hooks": [{ "type": "command", "command": "$HOOK_PATH --verbose pre-compact" }] }
],
"SessionStart": [
{ "matcher": "*", "hooks": [{ "type": "command", "command": "$HOOK_PATH --verbose session-start" }] }
],
"SessionEnd": [
{ "matcher": "*", "hooks": [{ "type": "command", "command": "$HOOK_PATH --verbose session-end" }] }
]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether unescaped HOOK_PATH is still used in generated command fields.
rg -n '"command": "\$HOOK_PATH --verbose' install-with-sondera.sh

Repository: Tony363/SuperClaude

Length of output: 1635


Escape $HOOK_PATH in all generated hook command strings to handle paths with spaces or special characters.

The unescaped $HOOK_PATH variable (lines 138, 141, 144, 147, 150, 153, 156, 159, 162, 165, 168, 171, 174, 177) will fail when the path contains spaces or shell-significant characters. This affects all 14 hook event handlers.

🔧 Proposed fix
 HOOK_PATH="$SONDERA_DIR/apps/claude/target/release/sondera-claude-hook"
+HOOK_PATH_ESCAPED=$(printf '%q' "$HOOK_PATH")
 
 cat > .claude/settings.local.json <<EOF
 {
   "hooks": {
     "PreToolUse": [
-      { "matcher": "*", "hooks": [{ "type": "command", "command": "$HOOK_PATH --verbose pre-tool-use" }] }
+      { "matcher": "*", "hooks": [{ "type": "command", "command": "$HOOK_PATH_ESCAPED --verbose pre-tool-use" }] }
     ],

Replace $HOOK_PATH with $HOOK_PATH_ESCAPED for each of the 14 event command entries.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@install-with-sondera.sh` around lines 137 - 178, The hook command strings
currently embed an unescaped $HOOK_PATH which will break for paths with
spaces/special chars; update each hook entry (e.g., "PreToolUse",
"PermissionRequest", "PostToolUse", "PostToolUseFailure", "UserPromptSubmit",
"Notification", "Stop", "SubagentStart", "SubagentStop", "TeammateIdle",
"TaskCompleted", "PreCompact", "SessionStart", "SessionEnd") to use an
escaped/quoted variable (replace $HOOK_PATH with a safely-escaped variant such
as $HOOK_PATH_ESCAPED or wrap the variable in quotes) so the command strings
correctly handle spaces and shell-significant characters.

Comment on lines +30 to +53
# 1b. Validate hook schema format (array-based with CamelCase event keys)
echo -n "Validating hook schema format... "
if python3 -c "
import json, sys
with open('.claude/settings.local.json') as f:
data = json.load(f)
hooks = data.get('hooks', {})
if 'user-prompt-submit' in hooks:
print('ERROR: Outdated flat schema detected (kebab-case key)', file=sys.stderr)
sys.exit(1)
if 'PreToolUse' not in hooks:
print('ERROR: Missing PreToolUse key - expected CamelCase event keys', file=sys.stderr)
sys.exit(1)
if not isinstance(hooks['PreToolUse'], list):
print('ERROR: PreToolUse should be an array, not flat object', file=sys.stderr)
sys.exit(1)
" 2>&1; then
echo -e "${GREEN}✓${NC}"
else
echo -e "${RED}✗ Invalid hook schema${NC}"
echo " Expected array-based format with CamelCase event keys (e.g., PreToolUse, PostToolUse)"
echo " Re-run install-with-sondera.sh to regenerate"
exit 1
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify generated hook schema has full 14-event coverage and array values.
python3 - <<'PY'
import json, sys
p = ".claude/settings.local.json"
with open(p) as f:
    data = json.load(f)
hooks = data.get("hooks", {})
expected = {
    "PreToolUse","PermissionRequest","PostToolUse","PostToolUseFailure",
    "UserPromptSubmit","Notification","Stop","SubagentStart","SubagentStop",
    "TeammateIdle","TaskCompleted","PreCompact","SessionStart","SessionEnd"
}
missing = sorted(expected - set(hooks))
wrong_type = sorted(k for k in expected if not isinstance(hooks.get(k), list))
legacy = "user-prompt-submit" in hooks
print("missing:", missing)
print("wrong_type:", wrong_type)
print("legacy_key_present:", legacy)
sys.exit(1 if missing or wrong_type or legacy else 0)
PY

Repository: Tony363/SuperClaude

Length of output: 221


🏁 Script executed:

# First, find and examine the test-sondera-integration.sh file
find . -name "test-sondera-integration.sh" -o -name "*sondera*" | head -20

Repository: Tony363/SuperClaude

Length of output: 118


🏁 Script executed:

# Look for documentation about lifecycle events/hooks
find . -type f \( -name "*.md" -o -name "*.json" -o -name "*.sh" \) | xargs grep -l "PreToolUse\|PostToolUse\|SessionStart" 2>/dev/null | head -20

Repository: Tony363/SuperClaude

Length of output: 301


🏁 Script executed:

# Search for references to "14.*event" or similar hook documentation
rg "lifecycle|event.*hook|hook.*event" -t md -t json -t sh --max-count=30 2>/dev/null | head -50

Repository: Tony363/SuperClaude

Length of output: 5923


🏁 Script executed:

# Read the test-sondera-integration.sh file, focusing on lines 30-53
cat -n test-sondera-integration.sh | sed -n '25,60p'

Repository: Tony363/SuperClaude

Length of output: 1492


🏁 Script executed:

# Read SONDERA_INTEGRATION.md to find the 14 lifecycle events
cat SONDERA_INTEGRATION.md | head -100

Repository: Tony363/SuperClaude

Length of output: 3065


🏁 Script executed:

# Check HOOKS_MODULE.md for the complete list of hook events
cat crates/superclaude-runtime/docs/HOOKS_MODULE.md

Repository: Tony363/SuperClaude

Length of output: 13373


🏁 Script executed:

# Search for references to all the proposed event names
rg "PermissionRequest|PostToolUseFailure|Notification|SubagentStart|TeammateIdle|TaskCompleted|PreCompact|SessionStart|SessionEnd" --max-count=50

Repository: Tony363/SuperClaude

Length of output: 1877


🏁 Script executed:

# Check the install-with-sondera.sh script to see what it sets up
cat install-with-sondera.sh | head -200

Repository: Tony363/SuperClaude

Length of output: 6603


🏁 Script executed:

# Search for documentation about the complete hook schema
rg "14.*event|event.*14|lifecycle.*event|event.*schema" -t md --max-count=20

Repository: Tony363/SuperClaude

Length of output: 223


🏁 Script executed:

# Check what the current test actually validates by examining the full script
cat -n test-sondera-integration.sh | sed -n '1,100p'

Repository: Tony363/SuperClaude

Length of output: 3619


🏁 Script executed:

# Search for any other validations of hook events in the codebase
rg "hooks.*get\|hooks\[" --max-count=20

Repository: Tony363/SuperClaude

Length of output: 45


Validate all 14 lifecycle events, not just PreToolUse.

The current check passes if only PreToolUse exists with array value, leaving validation of 13 other required events unverified. This allows weak/partial hook coverage to pass undetected.

Proposed fix
 if python3 -c "
 import json, sys
 with open('.claude/settings.local.json') as f:
     data = json.load(f)
 hooks = data.get('hooks', {})
 if 'user-prompt-submit' in hooks:
     print('ERROR: Outdated flat schema detected (kebab-case key)', file=sys.stderr)
     sys.exit(1)
-if 'PreToolUse' not in hooks:
-    print('ERROR: Missing PreToolUse key - expected CamelCase event keys', file=sys.stderr)
-    sys.exit(1)
-if not isinstance(hooks['PreToolUse'], list):
-    print('ERROR: PreToolUse should be an array, not flat object', file=sys.stderr)
-    sys.exit(1)
+expected = {
+    'PreToolUse', 'PermissionRequest', 'PostToolUse', 'PostToolUseFailure',
+    'UserPromptSubmit', 'Notification', 'Stop', 'SubagentStart', 'SubagentStop',
+    'TeammateIdle', 'TaskCompleted', 'PreCompact', 'SessionStart', 'SessionEnd'
+}
+missing = sorted(expected - set(hooks.keys()))
+if missing:
+    print(f'ERROR: Missing hook events: {", ".join(missing)}', file=sys.stderr)
+    sys.exit(1)
+bad = sorted(k for k in expected if not isinstance(hooks.get(k), list))
+if bad:
+    print(f'ERROR: Hook events must be arrays: {", ".join(bad)}', file=sys.stderr)
+    sys.exit(1)
 " 2>&1; then
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# 1b. Validate hook schema format (array-based with CamelCase event keys)
echo -n "Validating hook schema format... "
if python3 -c "
import json, sys
with open('.claude/settings.local.json') as f:
data = json.load(f)
hooks = data.get('hooks', {})
if 'user-prompt-submit' in hooks:
print('ERROR: Outdated flat schema detected (kebab-case key)', file=sys.stderr)
sys.exit(1)
if 'PreToolUse' not in hooks:
print('ERROR: Missing PreToolUse key - expected CamelCase event keys', file=sys.stderr)
sys.exit(1)
if not isinstance(hooks['PreToolUse'], list):
print('ERROR: PreToolUse should be an array, not flat object', file=sys.stderr)
sys.exit(1)
" 2>&1; then
echo -e "${GREEN}${NC}"
else
echo -e "${RED}✗ Invalid hook schema${NC}"
echo " Expected array-based format with CamelCase event keys (e.g., PreToolUse, PostToolUse)"
echo " Re-run install-with-sondera.sh to regenerate"
exit 1
fi
# 1b. Validate hook schema format (array-based with CamelCase event keys)
echo -n "Validating hook schema format... "
if python3 -c "
import json, sys
with open('.claude/settings.local.json') as f:
data = json.load(f)
hooks = data.get('hooks', {})
if 'user-prompt-submit' in hooks:
print('ERROR: Outdated flat schema detected (kebab-case key)', file=sys.stderr)
sys.exit(1)
expected = {
'PreToolUse', 'PermissionRequest', 'PostToolUse', 'PostToolUseFailure',
'UserPromptSubmit', 'Notification', 'Stop', 'SubagentStart', 'SubagentStop',
'TeammateIdle', 'TaskCompleted', 'PreCompact', 'SessionStart', 'SessionEnd'
}
missing = sorted(expected - set(hooks.keys()))
if missing:
print(f'ERROR: Missing hook events: {", ".join(missing)}', file=sys.stderr)
sys.exit(1)
bad = sorted(k for k in expected if not isinstance(hooks.get(k), list))
if bad:
print(f'ERROR: Hook events must be arrays: {", ".join(bad)}', file=sys.stderr)
sys.exit(1)
" 2>&1; then
echo -e "${GREEN}${NC}"
else
echo -e "${RED}✗ Invalid hook schema${NC}"
echo " Expected array-based format with CamelCase event keys (e.g., PreToolUse, PostToolUse)"
echo " Re-run install-with-sondera.sh to regenerate"
exit 1
fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test-sondera-integration.sh` around lines 30 - 53, The script only validates
the 'PreToolUse' key; update the python check in test-sondera-integration.sh to
validate all required lifecycle event keys by defining a list of the 14 expected
CamelCase event names (instead of just 'PreToolUse'), then iterate over that
list and for each ensure it exists in hooks and is a list; replace the
single-key checks for 'PreToolUse' and 'user-prompt-submit' with this loop so
any missing or non-array event (e.g., hooks[event] not isinstance(list)) causes
an error and non-zero exit.

@Tony363 Tony363 self-assigned this Mar 18, 2026
@Tony363
Tony363 merged commit aec6bf8 into main Mar 18, 2026
40 of 42 checks passed
@Tony363
Tony363 deleted the fix/installer-hook-schema branch March 18, 2026 20:18
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