Clawhip
Event-contract layer that defines the canonical envelope format and normalized event names for OMX hook events.
Clawhip is the event-contract layer that sits between OMX's raw hook pipeline and downstream consumers — OpenClaw gateways, notification brokers, and interop agents. It fixes a canonical envelope shape and a stable set of normalized event names so consumers never need to parse raw OMX event strings directly.
What it is
Clawhip is a schema and routing contract, not a separate process. When OMX fires a hook, the event envelope already conforms to the clawhip contract: a versioned schema, a context block with normalized fields, and a context.normalized_event string.
context.normalized_event maps the internal event names OMX uses — like session-start or session-idle — to a small, stable vocabulary that consumers can depend on without breaking when OMX internals change.
How OMX uses it
- Normalized event routing — Consumers route on
context.normalized_eventrather than the raweventfield. Supported values:started,blocked,finished,failed,retry-needed,pr-created,test-started,test-finished,test-failed,handoff-needed. - Envelope contract — Every event carries
schema_version: "1",event,timestamp,source, and acontextblock. Optional identifiers (session_id,thread_id,turn_id,mode) appear only when available. - Context fields — The
contextblock includesnormalized_event,session_name,repo_path,branch,issue_number,pr_number,pr_url,command,tool_name,status, anderror_summary. - Noise control — Duplicate suppression gates on
thread_id + turn_id + type. Idle events obey the idle cooldown gate. Operational events likeretry-neededandhandoff-neededare handled separately from session lifecycle completions.
Example
A clawhip envelope for a session-end event:
{
"schema_version": "1",
"event": "session-end",
"timestamp": "2025-04-19T10:00:00.000Z",
"source": "omx",
"session_id": "omx-abc123",
"context": {
"normalized_event": "finished",
"session_name": "omx-abc123",
"repo_name": "my-app",
"branch": "feat/new-api",
"status": "success"
}
}Consumer routing on normalized_event:
switch (event.context.normalized_event) {
case "finished": handleSuccess(event); break;
case "failed": handleFailure(event); break;
case "blocked": escalate(event); break;
}The key point is routing on context.normalized_event ("finished") rather than the raw event field ("session-end"). This keeps consumers stable even when OMX changes internal event names.