同时收敛启动与运维脚本默认行为(含 wiki worker)、更新 Admin 可观测性与相关测试,降低首轮时延并提高运行稳定性。 Made-with: Cursor
4.9 KiB
oclaw/runtime/hooks
Python hooks runtime and bundled hook packages (parity target: OpenClaw src/hooks).
What you get
- In-process hook bus: register on
typeortype:action, sync/async handlers, isolated failures. - Directory discovery:
HOOK.md+ one handler file per hook directory (first match in priority order, seeworkspace._handler_candidates). - Config gating:
hooks.internal.enabledandhooks.internal.entries.<hookKey>.enabled. - Source precedence: bundled / managed / workspace / plugin collision resolution (
policy). - Eligibility: OS / bins / env / config paths; optional remote context from message metadata (
eligibility_from_metadata+config.should_include_hook).
Handler entry priority
First existing file under the hook directory wins:
handler.py → index.py → handler.ts → index.ts → handler.mts → index.mts → handler.cts → index.cts → handler.mjs → index.mjs → handler.cjs → index.cjs → handler.sh → index.sh → handler.bash → index.bash
Hook layout
Put hooks in any of:
- Bundled: shipped with runtime (
runtime_hooks_bundled_root()) - Managed:
~/.oclaw/hooks/<hookName>/ - Workspace:
<workspace>/hooks/<hookName>/ - Plugin:
.openclaw/extensions/<id>/.codex-plugin/plugin.json→hookspaths - Extra dirs:
hooks.internal.load.extraDirsplus skill-side.../hooksdirs merged at runtime init
Each hook directory needs HOOK.md (YAML frontmatter with metadata.oclaw.events) plus one handler file as above.
Remote eligibility on inbound messages
Callers (e.g. gateway) may attach JSON metadata:
{
"hookEligibility": {
"remote": {
"platforms": ["linux"],
"binsPresent": ["git", "node"],
"note": "remote agent capabilities"
}
}
}
Parsed by hook_eligibility_from_message_metadata and passed into initialize_hooks_runtime(..., eligibility=...). Note: hook runtime initializes once per process; the first successful init wins (see hooks_runtime.initialize_hooks_runtime).
TS parity matrix (OpenClaw src/hooks)
Legend: Done / Partial / TODO
| Area | Status |
|---|---|
internal-hooks bus (register / trigger / type + type:action) |
Done |
loader (.py import + TS/JS/shell runners, hookMode / nodeScript) |
Done |
path boundary (handlerPath under baseDir) |
Done |
frontmatter + metadata.oclaw |
Done |
| invocation + config enable gate | Done |
| policy / source precedence | Done |
runtime eligibility (os / requires / env / config) |
Done |
remote eligibility (platforms / hasBin / hasAnyBin) — filter API + gateway metadata wiring |
Done |
package.json openclaw.hooks / oclaw.hooks |
Done |
plugin hook dirs (.codex-plugin + hooks) |
Done |
legacy hooks.internal.handlers |
Done |
hooks list/check/info CLI (python -m oclaw.runtime.operations hooks …) |
Done |
hooks enable / hooks disable (config file patch) |
Done |
install / update hook packs (npm/git; TS install.ts / update.ts) |
Partial (hooks install / hooks update print deprecation + manual/OpenClaw guidance; no npm/git runner) |
| gmail watcher family | Partial (config gates + initialize_hooks_runtime → start_gmail_watcher_with_logs; gog/API loop not ported). Set OCLAW_SKIP_GMAIL_WATCHER=1 (or OPENCLAW_SKIP_GMAIL_WATCHER) to no-op. |
| fire-and-forget / message-hook mappers | TODO |
Minimal self-test
From the repository root (see tests/conftest.py for sys.path layout):
python runtime/hooks/_selftest.py
or run hook discovery / parity tests:
pytest tests/test_oclaw_hooks_bundled_parity.py tests/test_oclaw_hooks_runtime.py -q
Operations CLI (from parent of this repo on sys.path, see tests/conftest.py)
python -m oclaw.runtime.operations hooks list
python -m oclaw.runtime.operations hooks list --eligible --verbose
python -m oclaw.runtime.operations hooks check --json
python -m oclaw.runtime.operations hooks info session-memory --workspace /path/to/workspace
python -m oclaw.runtime.operations hooks enable session-memory --workspace /path/to/workspace
python -m oclaw.runtime.operations hooks disable command-logger --workspace /path/to/workspace
python -m oclaw.runtime.operations hooks install ./path-or-npm-spec # deprecated, exit 2 + hints
python -m oclaw.runtime.operations hooks update --dry-run # deprecated, exit 2 + hints
Uses the same merged config as the agent runtime (including skill hooks/ extra dirs via merge_skill_hook_extra_dirs_into_config).
Enable matches OpenClaw semantics: the hook must satisfy requirements (bins/os/env/config) if its config entry were turned on; plugin hooks cannot be toggled from this CLI. Writes go to OCLAW_CONFIG_PATH (optional, relative paths resolved under PROJECT_ROOT) or oclaw/oclaw.json by default.