@morphed/agent-hook
v0.1.3
Published
Morphed pre-tool hook for Claude Code and Codex — gates HubSpot writes through Morphed's decision service before they happen (Build Guide Mechanism C).
Maintainers
Readme
@morphed/agent-hook
Morphed pre-tool hook for Claude Code and Codex — Build Guide Mechanism C. A tiny program the agent runs before any tool call. It asks Morphed's decision service and denies the call if policy says no, before the write happens — even in bypass/yolo mode (the bypass skips prompts, not hooks).
Install (one line)
npx @morphed/agent-hook init --token <MORPHED_API_KEY> --portal <PORTAL_ID>This:
- Detects which agents are installed (
~/.claude/settings.json,~/.codex/config.toml). - Writes the
PreToolUsehook with matchers for HubSpot MCP tools, Claude managed CRM writes, and Bash. - Stores a persistent hook command using
npx --yes --package @morphed/agent-hook morphed-hook, so the hook can still run afterinitexits. - Stores the API key in the OS keychain (via
keytar; falls back to a0600~/.morphed/agent-hook.jsonif the native module isn't available).
Whole-org enforcement
npx @morphed/agent-hook init --token <KEY> --portal <ID> --org--org writes managed settings so individuals can't disable it:
- Claude Code: managed
managed-settings.json(OS-specific path). - Codex:
requirements.tomlwithallow_managed_hooks_only = true.
How the hook works
morphed-hook reads the agent's pre-tool JSON from stdin, pulls tool_name +
tool_input, calls POST /v1/decision (surface: claude_code or codex,
HMAC-signed with the tenant key), and prints the agent's allow/deny JSON:
{ "hookSpecificOutput": { "hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Morphed blocked this write. … STOP — do not retry…" } }- Morphed
approved→allow;blocked/approval_required→deny;modify→ask. - Deny copy is phrased to make the agent stop cleanly and escalate rather than go idle or loop on a block.
- Codex
PermissionRequestevents get thedecision.behaviorshape; both agents'PreToolUseevents get thehookSpecificOutput.permissionDecisionshape. - Fail-open: if Morphed is unreachable or the machine isn't enrolled, the hook allows the call (the backstop, Mechanism F, still catches the write) — a Morphed outage never wedges the agent.
Honest limit
The hook governs the machines it's installed on. It is enrolment, not magic — Morphed can't gate an agent it was never wired into. Anything outside it still falls to the backstop.
Tests
npm test # 16 unit tests: both agent JSON shapes, decision mapping, HMAC, installer