Skip to content

Route agent hooks through project service - #274

Merged
TraderSamwise merged 5 commits into
masterfrom
feat/core-hooks-sidecar
Jul 3, 2026
Merged

Route agent hooks through project service#274
TraderSamwise merged 5 commits into
masterfrom
feat/core-hooks-sidecar

Conversation

@TraderSamwise

@TraderSamwise TraderSamwise commented Jul 3, 2026

Copy link
Copy Markdown
Owner

Summary

  • route generated Claude/Codex hooks directly to the per-project service /hooks endpoints
  • move hook lifecycle, permission interaction, transcript, and backend-session handling into metadata-server
  • delete the old aimux claude-hook/codex-hook CLI adapters from the one-shot path

Verification

  • yarn typecheck
  • yarn lint
  • yarn build
  • yarn vitest run src/claude-hooks.test.ts src/codex-hooks.test.ts src/metadata-server.interaction.test.ts src/multiplexer/session-launch.test.ts src/one-shot-node-inventory.test.ts src/cli-launcher.test.ts src/runtime-coherence.test.ts src/runtime-restart.test.ts
  • yarn vitest run
  • pre-push gate: yarn typecheck && yarn lint && yarn test

Summary by CodeRabbit

  • New Features
    • Added new project-service hook endpoints for Claude and Codex, including session-aware interaction resolution (Claude) and telemetry-only permission handling (Codex).
    • Managed tool launches now consistently set the project metadata endpoint file (metadata-api.txt).
  • Bug Fixes
    • Updated hook command generation to use project-based curl requests with action-appropriate timeouts.
    • Improved robustness: permission requests safely return empty results when aborted, and hook handling continues even if backend session recording fails.
  • Tests
    • Expanded/strengthened command-generation, ownership-detection, merging, and integration coverage for both Claude and Codex hooks.

@vercel

vercel Bot commented Jul 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
app Ready Ready Preview, Comment Jul 3, 2026 12:00pm

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 18 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 765645f5-937c-4052-8bf8-38f4cc544749

📥 Commits

Reviewing files that changed from the base of the PR and between dde7d6d and 9cdc4bc.

📒 Files selected for processing (4)
  • src/codex-hooks.test.ts
  • src/metadata-server.interaction.test.ts
  • src/metadata-server.ts
  • src/project-hook-command.ts
📝 Walkthrough

Walkthrough

Claude and Codex hook commands now use project HTTP endpoints instead of CLI hook strings. The metadata server adds /hooks/claude and /hooks/codex, session launch exports the metadata endpoint file, and main.ts removes obsolete hook helpers.

Changes

Project hook command migration

Layer / File(s) Summary
Project hook command builder
src/project-hook-command.ts, src/project-api-contract.ts
Adds a shared curl-based hook command builder and registers the new Claude/Codex hook routes.
Claude/Codex hook command construction
src/claude-hooks.ts, src/codex-hooks.ts, src/claude-hooks.test.ts, src/codex-hooks.test.ts, src/cli-launcher.test.ts, src/one-shot-node-inventory.test.ts
Switches Claude and Codex hook commands to the shared project hook builder, updates ownership matching, and adjusts related command and inventory tests.
Session launch environment wiring
src/multiplexer/session-launch.ts, src/multiplexer/session-launch.test.ts
Sets AIMUX_METADATA_ENDPOINT_FILE for Claude and Codex wrappers and updates launch expectations.
Metadata server hook endpoints and handlers
src/metadata-server.ts, src/metadata-server.interaction.test.ts
Adds hook handlers, session/backend-session resolution, alert and interaction behavior, and route-level integration tests.
Removal of obsolete CLI hook logic
src/main.ts
Removes local hook helpers and the old claude-hook / codex-hook adapter block.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant MetadataServer
  participant InteractionRegistry

  Client->>MetadataServer: POST /hooks/claude?action=permission-request&sessionId=...
  MetadataServer->>InteractionRegistry: register interaction and wait
  InteractionRegistry-->>MetadataServer: decision resolved
  MetadataServer-->>Client: hookSpecificOutput decision
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: routing Claude/Codex agent hooks through project service endpoints.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/core-hooks-sidecar

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

@TraderSamwise

Copy link
Copy Markdown
Owner Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@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: 1

🧹 Nitpick comments (3)
src/project-hook-command.ts (1)

19-26: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Session id is not URL-encoded while action is.

action is passed through encodeURIComponent (Line 16), but session (from $AIMUX_SESSION_ID or the shell-quoted fallback) is inserted raw into the query string at Line 26. A session id containing &, =, %, or spaces would corrupt the URL or smuggle extra query parameters into the request.

🛡️ Proposed fix: URL-encode session server-side or switch to curl's `--data-urlencode`
-    `url="$endpoint${route}?action=${action}&sessionId=$session"`,
-    `printf "%s" "$payload" | curl --silent --show-error --fail --max-time ${timeoutSeconds} -H 'content-type: application/json' --data-binary `@-` "$url" || printf '{}\\n'`,
+    `url="$endpoint${route}"`,
+    `printf "%s" "$payload" | curl -G --silent --show-error --fail --max-time ${timeoutSeconds} -H 'content-type: application/json' --data-binary `@-` --data-urlencode "action=${opts.action}" --data-urlencode "sessionId=$session" "$url" || printf '{}\\n'`,

Note: -G with --data-binary together needs verification against the curl version in use; validate this combination still posts the body while appending encoded query params.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/project-hook-command.ts` around lines 19 - 26, The query string in
project-hook-command is building `url` with a raw `sessionId`, while `action` is
already encoded, so update the `session` handling in this shell snippet to
URL-encode it before concatenating into `url`. Keep the fix localized around the
`session`, `endpoint_file`, and `url` construction logic, and preserve the
existing `encodeURIComponent` treatment for `action`; if you change the curl
invocation, make sure the `curl` flags still append encoded query params
correctly with the request body behavior intact.
src/metadata-server.ts (1)

1638-1727: 🔒 Security & Privacy | 🔵 Trivial

Hook endpoints trust any local caller with no additional authentication.

The new /hooks/claude and /hooks/codex POST routes accept sessionId/session_id/backendSessionId/tool-input payloads from any process able to reach 127.0.0.1 on this port, with no token/secret check beyond knowing/guessing a sessionId. resolveHookSessionId will even remap events to a different session if the payload's session_id happens to match another session's backendSessionId. This is a comparable trust model to the prior CLI adapter (which also accepted unauthenticated stdin JSON), so it's not a strictly new class of risk, but centralizing this on an always-listening HTTP server (which also sets Access-Control-Allow-Origin: * elsewhere in this router) widens the blast radius for a malicious local process or browser-based localhost CSRF to spoof permission decisions or fake completion/backend-session data. Worth a deliberate design review now that hooks are network-reachable rather than argv/stdin-scoped.

Also applies to: 2978-3004

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/metadata-server.ts` around lines 1638 - 1727, The hook routes currently
accept unauthenticated localhost POSTs and trust session identifiers/tool
payloads, which allows spoofed events and session remapping. Add an explicit
verification step in the hook request flow before `handleClaudeHook` and
`handleCodexHook` process payloads, and make `resolveHookSessionId` only remap
after the sender is authenticated or the session binding is validated. Update
the hook auth model so these endpoints are no longer blindly accepted from any
local caller, while preserving the existing event handling paths.
src/codex-hooks.ts (1)

50-56: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low value

Trim the Codex permission-request timeout. This hook only emits telemetry and returns immediately, so the 120s --max-time looks unnecessary here; a shorter timeout would fail faster on network issues.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/codex-hooks.ts` around lines 50 - 56, The buildCodexHookCommand function
currently gives the "permission-request" action a much longer timeout than
needed. Update the timeoutSeconds logic in buildCodexHookCommand so the Codex
permission-request path uses a shorter max-time value instead of 120, while
keeping the normal timeout for other actions unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/project-hook-command.ts`:
- Around line 23-27: The hook command currently swallows every failure path in
the curl request and setup checks, making
SessionStart/Stop/Notification/PermissionRequest diagnostics invisible. Update
the shell snippet in project-hook-command.ts to emit a brief error message to
stderr before returning the fallback JSON when curl is missing, the endpoint
file is unavailable/empty, or the curl call fails. Keep the existing `{}`
fallback behavior, but add failure context around the existing
endpoint/session/url handling and the curl invocation so logs can identify the
broken stage.

---

Nitpick comments:
In `@src/codex-hooks.ts`:
- Around line 50-56: The buildCodexHookCommand function currently gives the
"permission-request" action a much longer timeout than needed. Update the
timeoutSeconds logic in buildCodexHookCommand so the Codex permission-request
path uses a shorter max-time value instead of 120, while keeping the normal
timeout for other actions unchanged.

In `@src/metadata-server.ts`:
- Around line 1638-1727: The hook routes currently accept unauthenticated
localhost POSTs and trust session identifiers/tool payloads, which allows
spoofed events and session remapping. Add an explicit verification step in the
hook request flow before `handleClaudeHook` and `handleCodexHook` process
payloads, and make `resolveHookSessionId` only remap after the sender is
authenticated or the session binding is validated. Update the hook auth model so
these endpoints are no longer blindly accepted from any local caller, while
preserving the existing event handling paths.

In `@src/project-hook-command.ts`:
- Around line 19-26: The query string in project-hook-command is building `url`
with a raw `sessionId`, while `action` is already encoded, so update the
`session` handling in this shell snippet to URL-encode it before concatenating
into `url`. Keep the fix localized around the `session`, `endpoint_file`, and
`url` construction logic, and preserve the existing `encodeURIComponent`
treatment for `action`; if you change the curl invocation, make sure the `curl`
flags still append encoded query params correctly with the request body behavior
intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0b788514-d87e-45fe-982d-233d7e83c268

📥 Commits

Reviewing files that changed from the base of the PR and between 9ef379f and e440cee.

📒 Files selected for processing (13)
  • src/claude-hooks.test.ts
  • src/claude-hooks.ts
  • src/cli-launcher.test.ts
  • src/codex-hooks.test.ts
  • src/codex-hooks.ts
  • src/main.ts
  • src/metadata-server.interaction.test.ts
  • src/metadata-server.ts
  • src/multiplexer/session-launch.test.ts
  • src/multiplexer/session-launch.ts
  • src/one-shot-node-inventory.test.ts
  • src/project-api-contract.ts
  • src/project-hook-command.ts
💤 Files with no reviewable changes (1)
  • src/main.ts

Comment thread src/project-hook-command.ts Outdated

@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: 1

🧹 Nitpick comments (1)
src/codex-hooks.test.ts (1)

19-30: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Stale test description.

Test title says "falls back to empty JSON" but the assertions (lines 21-29) no longer verify any fallback behavior — only that the command ends with a trailing quote, per the line-range summary noting || echo '{}' fallback was removed. Consider updating the it description to match what's actually being asserted (curl-based POST with expected env vars/action, excluding legacy patterns).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/codex-hooks.test.ts` around lines 19 - 30, The test name is stale because
it still mentions falling back to empty JSON even though the
`buildCodexHookCommand` assertions now only verify the curl-based project
service POST and legacy string exclusions. Update the `it(...)` description in
`codex-hooks.test.ts` to match the actual behavior being checked, using the
`buildCodexHookCommand`-focused assertions and removing any fallback wording
that is no longer covered.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/metadata-server.interaction.test.ts`:
- Around line 277-289: The assertion in the Codex permission hook test is too
weak because optional chaining lets it pass even if the session or derived state
was never recorded. Update the test around loadMetadataState(),
sessions["codex-1"], and derived.attention to first assert the session/derived
object exists, then verify attention is not "needs_response" so the test באמת
confirms telemetry-only behavior without stranded response state.

---

Nitpick comments:
In `@src/codex-hooks.test.ts`:
- Around line 19-30: The test name is stale because it still mentions falling
back to empty JSON even though the `buildCodexHookCommand` assertions now only
verify the curl-based project service POST and legacy string exclusions. Update
the `it(...)` description in `codex-hooks.test.ts` to match the actual behavior
being checked, using the `buildCodexHookCommand`-focused assertions and removing
any fallback wording that is no longer covered.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 38120d35-f1d8-47f3-ae55-d0be342f5e12

📥 Commits

Reviewing files that changed from the base of the PR and between e440cee and de271e8.

📒 Files selected for processing (4)
  • src/codex-hooks.test.ts
  • src/codex-hooks.ts
  • src/metadata-server.interaction.test.ts
  • src/metadata-server.ts
💤 Files with no reviewable changes (1)
  • src/metadata-server.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/codex-hooks.ts

Comment thread src/metadata-server.interaction.test.ts

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/project-hook-command.ts`:
- Line 30: The curl hook command uses --url-query in the project-hook-command
path, which breaks on older curl versions and causes the post to fail. Update
the command construction in the hook execution logic to avoid --url-query unless
curl 7.87+ is guaranteed; instead, build the query string into the URL or switch
to --data-urlencode while keeping the existing fail handling and session/action
parameters intact.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 387ddd74-156d-4e0d-856c-7fe74edeb78b

📥 Commits

Reviewing files that changed from the base of the PR and between de271e8 and dde7d6d.

📒 Files selected for processing (3)
  • src/codex-hooks.test.ts
  • src/codex-hooks.ts
  • src/project-hook-command.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/codex-hooks.test.ts

Comment thread src/project-hook-command.ts Outdated
@TraderSamwise
TraderSamwise merged commit ace1f7f into master Jul 3, 2026
3 checks passed
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