Skip to content

Hook-driven face_say safety net for Claude/Codex/Gemini (v1.16.0)#50

Merged
amariichi merged 2 commits into
mainfrom
feat/hook-bridge-multi-runtime
May 10, 2026
Merged

Hook-driven face_say safety net for Claude/Codex/Gemini (v1.16.0)#50
amariichi merged 2 commits into
mainfrom
feat/hook-bridge-multi-runtime

Conversation

@amariichi
Copy link
Copy Markdown
Owner

Summary

  • Adds a runtime-agnostic hook bridge so the 3D face speaks even when an agent forgets to call face_say voluntarily. Wires Claude Code's Notification+Stop, Codex's PermissionRequest+Stop, and Gemini CLI's Notification+AfterAgent into a single wrapper that emits face_say + face_event and (for helpers) an owner-inbox entry tagged source=mh_hook.
  • New: face.hook MCP tool, face-app/dist/hook_bridge.js orchestrator (per-agent CJK language detection, variant-rotation template selection, owner-inbox routing), scripts/mh-hook.mjs wrapper, scripts/grant-codex-hook-trust.sh for Codex's one-time trust grant.
  • Templates default to ja+en built-in, overridable via ~/.minimum-headroom/face-templates.json.
  • 22 new unit tests; full suite stays green at 325/325.
  • Version bump 1.15.1 → 1.16.0 (package.json, mcp-server SERVER_VERSION, tts-worker / asr-worker pyproject.toml).

Design notes and end-to-end verification log: .agent/PLANS_47_HOOK_DRIVEN_FACE_SAY.md (gitignored, lives only in the local clone).

Per-runtime status (verified 2026-05-10)

Runtime Hook fires Voluntary face_say Notes
Claude Code inconsistent hook is the safety net
Codex 0.130.0 ✓ after one-time trust grant very reliable per CLAUDE.md use scripts/grant-codex-hook-trust.sh after editing config
Gemini CLI 0.41.2 none hook is mandatory; verified payload shapes match google-gemini docs

Codex trust grant

Codex silently filters user-defined hooks until trusted at user level (in [hooks.state.*]). Grant is once-per-edit, user-wide, inherited by every helper spawned afterward. Two paths:

  • Automated: ./scripts/grant-codex-hook-trust.sh (private tmux server, walks /hooks browser, exits)
  • Manual: codex interactively → /hooks → per-event Enter → t → Esc → /quit

mh-hook.mjs is hard-wired to write nothing to stdout and exit 0 always — required because Gemini's AfterAgent treats exit 2 as "retry this turn with stderr as feedback prompt" and Gemini parses stdout as JSON.

Test plan

  • npm test passes locally (325/325, includes the 22 new mh-hook + hook_bridge tests).
  • Merge doc/hook-bridge/{claude-settings.json.example, codex-config.toml.example, gemini-settings.json.example} into your local ~/.claude/settings.json, ~/.codex/config.toml, ~/.gemini/settings.json (substitute /ABS/PATH/).
  • For Codex: run scripts/grant-codex-hook-trust.sh once. Confirm ~/.codex/config.toml grows two [hooks.state.*] tables.
  • Restart the operator stack so the operator pane picks up MH_FACE_AGENT_ID.
  • Spawn a helper (agent.spawn with agent_cmd=claude|codex|gemini), assign a mission that triggers a permission prompt, observe: (a) the face speaks "Approval needed." (or a Japanese variant), (b) owner.inbox.list shows a source=mh_hook entry tagged with the helper's id and runtime.
  • After the helper turn ends without final report, confirm an idle_after_response source=mh_hook done entry appears (Claude Stop / Codex Stop / Gemini AfterAgent).

🤖 Generated with Claude Code

amariichi and others added 2 commits May 10, 2026 17:18
Adds a runtime-agnostic hook bridge so the 3D face speaks even when an
agent forgets to call face_say voluntarily. Wires Claude Code's
Notification + Stop, Codex's PermissionRequest + Stop, and Gemini CLI's
Notification + AfterAgent into a single wrapper script that emits
face_say + face_event and (for helpers) an owner-inbox entry tagged
source=mh_hook. End-to-end verified across all three runtimes; design
notes in .agent/PLANS_47_HOOK_DRIVEN_FACE_SAY.md.

- Adds `face.hook` MCP tool and the face-app `hook_bridge` orchestrator
  with per-agent CJK-heuristic language detection, variant-rotation
  template selection, and owner-inbox routing via existing assignment
  state.
- Adds `scripts/mh-hook.mjs` (the wrapper invoked by each runtime's
  hook config) with strict "stdout silent / exit 0 always" discipline
  required by Gemini AfterAgent's retry-on-exit-2 semantics.
- Adds `scripts/grant-codex-hook-trust.sh` to automate Codex's one-time
  /hooks browser trust grant via a private tmux server.
- Forwards MH_FACE_AUTH_TOKEN as ?auth_token query param from mh-hook
  so it works against face-app instances that require auth.
- Templates default to ja+en built-in, overridable via
  ~/.minimum-headroom/face-templates.json.
- Adds 22 unit tests (mh-hook + hook_bridge); full suite 325 passing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@amariichi amariichi merged commit 4f93eed into main May 10, 2026
1 check passed
@amariichi amariichi deleted the feat/hook-bridge-multi-runtime branch May 10, 2026 08:23
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