Files
oh-my-claudecode/docs/OPENCLAW-ROUTING.md
Codex Review cc78ba3f45 Collapse duplicate native lifecycle bursts for attached tmux sessions
Attached multi-pane dev sessions were waking OpenClaw multiple times for
what operators experience as one session-start, prompt-submit, or stop
burst. The bridge now keeps a short-lived per-worktree dedupe ledger keyed
by tmux session (and normalized prompt for submit bursts) so the first
signal still ships while repeated pane/client echoes are collapsed before
reaching downstream native gateways.

Constraint: Duplicate bursts can come from separate panes or clients that share one tmux session
Constraint: Preserve the first lifecycle alert and avoid adding dependencies
Rejected: Deduplicate on sessionId alone | pane-local Claude sessions do not share a stable session id
Rejected: Fix only downstream Clawhip routing | duplicate traffic should be suppressed before gateway dispatch
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Keep prompt-submit collapse keyed on tmux session plus normalized prompt unless the UserPromptSubmit bridge contract changes
Tested: npx vitest run src/openclaw/__tests__/*.test.ts
Tested: npx vitest run src/hooks/__tests__/bridge-openclaw.test.ts
Tested: npx tsc --noEmit
Not-tested: Live OpenClaw delivery against a real attached multi-pane dev tmux session
2026-04-10 17:37:42 +00:00

3.6 KiB

OpenClaw / Clawhip Routing Contract

This document defines the normalized event contract OMC emits through the OpenClaw bridge for native Clawhip-style consumers.

Goals

  • Keep the raw hook event (event) for backward compatibility.
  • Add a normalized signal object for routing and dedupe-friendly filtering.
  • Make command/native gateways receive the same logical payload shape as HTTP gateways.

Payload shape

HTTP gateways receive JSON with this structure:

{
  "event": "post-tool-use",
  "instruction": "...",
  "timestamp": "2026-03-09T00:00:00.000Z",
  "sessionId": "...",
  "projectPath": "...",
  "projectName": "...",
  "tmuxSession": "...",
  "tmuxTail": "...",
  "signal": {
    "kind": "test",
    "name": "test-run",
    "phase": "failed",
    "routeKey": "test.failed",
    "priority": "high",
    "toolName": "Bash",
    "command": "pnpm test",
    "testRunner": "package-test",
    "summary": "FAIL src/example.test.ts | ..."
  },
  "context": {
    "sessionId": "...",
    "projectPath": "...",
    "toolName": "Bash"
  }
}

signal contract

Field Meaning
kind Routing family: session, tool, test, pull-request, question, keyword
name Stable logical signal name
phase Lifecycle phase: started, finished, failed, idle, detected, requested
routeKey Canonical routing key for downstream consumers
priority high for operational signals, low for generic tool noise

Additional fields may appear when applicable:

  • toolName
  • command
  • testRunner
  • prUrl
  • summary

Native command gateway contract

Command gateways now get the same normalized payload through both:

  • template variable: {{payloadJson}}
  • env var: OPENCLAW_PAYLOAD_JSON

They also receive convenience env vars:

  • OPENCLAW_SIGNAL_ROUTE_KEY
  • OPENCLAW_SIGNAL_PHASE
  • OPENCLAW_SIGNAL_KIND

That lets native Clawhip routing consume one contract whether the transport is HTTP or shell-command based.

Current high-priority route keys

  • session.started
  • session.finished
  • session.idle
  • question.requested
  • test.started
  • test.finished
  • test.failed
  • pull-request.started
  • pull-request.created
  • pull-request.failed
  • tool.failed

Generic tool.started / tool.finished remain available as low-priority fallback signals.

Noise reduction

  • AskUserQuestion now emits only the dedicated question.requested signal instead of also emitting generic tool lifecycle events.
  • OpenClaw now collapses repeated attached-tmux lifecycle bursts before dispatching them to downstream native gateways.
    • session-start collapses on {projectPath, tmuxSession} for a short burst window.
    • keyword-detector (the UserPromptSubmit bridge surface) collapses prompt-submitted bursts on {projectPath, tmuxSession, normalized prompt}.
    • stop / session-end collapse on {projectPath, tmuxSession} for a short burst window.
  • Consumers should prefer signal.priority === "high" or explicit signal.routeKey filters instead of routing directly on raw hook names.

Stability notes

  • Raw event names are preserved for backward compatibility.
  • signal is the preferred routing surface for new native Clawhip integrations.
  • context remains a whitelisted subset; internal raw tool input/output are used only to derive normalized signals and are not forwarded in payload.context.