Files
wehub-resource-sync adc62957a7
CI / Multi-repo Path Gate (AST-grep) (windows-latest) (push) Has been cancelled
CI / Version Consistency Check (push) Has been cancelled
CI / npm pack + install test (push) Has been cancelled
CI / Lint & Type Check (push) Has been cancelled
CI / Test (push) Has been cancelled
CI / Test (Windows path suite) (push) Has been cancelled
CI / Build (push) Has been cancelled
CI / No Committed Build Artifacts (push) Has been cancelled
CI / Multi-repo Path Gate (AST-grep) (ubuntu-latest) (push) Has been cancelled
Upgrade Test / omc update + session-start hook (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:36:54 +08:00

107 lines
3.6 KiB
Markdown

# 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:
```json
{
"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`.