docs: absorb hook and subagent guidance PRs

This commit is contained in:
Peter Steinberger
2026-05-23 09:47:23 +01:00
parent 09dd051e78
commit 99a1107b61
14 changed files with 65 additions and 9 deletions

View File

@@ -6,6 +6,7 @@ Docs: https://docs.openclaw.ai
### Changes
- Docs: clarify model-usage portability, Codex migration prerequisites, status bootstrap wording, thread-bound subagent limits, hook ownership, and config-preserving safety guidance. Thanks @aniruddhaadak80, @leno23, @TomDjerry, @matthewxmurphy, @vincentkoc, and @stablegenius49.
- Docs: clarify README onboarding and Gateway startup paths, WhatsApp QR/408 recovery, cron output language prompts, skill advanced features, gateway upstream 403 troubleshooting, and plugin fallback override guidance. Thanks @deepujain, @Zacxxx, @Jah-yee, @neyric, @usimic, @Renu-Cybe, @BigUncle, and @SeashoreShi.
- Docs: clarify context-pruning ratio bounds, local dashboard recovery, CLI env markers, remote onboarding token behavior, and Peekaboo Bridge permissions for subprocess agents. Thanks @ayesha-aziz123, @dishraters, @hougangdev, and @brandonlipman.
- Docs: clarify browser CDP diagnostics, Plugin SDK allowlist imports, status-reaction timing defaults, queue steering behavior, limited-tool troubleshooting, cron HEARTBEAT handling, Telegram multi-agent groups, Bitwarden SecretRef setup, and EasyRunner deployments. Thanks @Quratulain-bilal, @mbelinky, @Mickey-, @vancece, @xenouzik, @posigit, @surlymochan, @janaka, and @choiking.

View File

@@ -15,6 +15,18 @@ There are two kinds of hooks in OpenClaw:
Hooks can also be bundled inside plugins. `openclaw hooks list` shows both standalone hooks and plugin-managed hooks.
## Choose the right surface
OpenClaw has several extension surfaces that look similar but solve different problems:
| If you want to... | Use... | Why |
| --------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | --------------------------------------------------------------------------------------------- |
| Save a snapshot on `/new`, log `/reset`, call an external API after `message:sent`, or add coarse operator automation | Internal hooks (`HOOK.md`, this page) | File-based hooks are meant for operator-managed side effects and command/lifecycle automation |
| Rewrite prompts, block tools, cancel outbound messages, or add ordered middleware/policy | Typed plugin hooks via `api.on(...)` | Typed hooks have explicit contracts, priorities, merge rules, and block/cancel semantics |
| Add telemetry-only export or observability | Diagnostic events | Observability is a separate event bus, not a policy hook surface |
Use internal hooks when you want automation that behaves like a small installed integration. Use typed plugin hooks when you need runtime lifecycle control.
## Quick start
```bash
@@ -101,14 +113,19 @@ const handler = async (event) => {
console.log(`[my-hook] New command triggered`);
// Your logic here
// Optionally send message to user
// Optionally send a reply on replyable surfaces
event.messages.push("Hook executed!");
};
export default handler;
```
Each event includes: `type`, `action`, `sessionKey`, `timestamp`, `messages` (push to send to user), and `context` (event-specific data). Agent and tool plugin hook contexts can also include `trace`, a read-only W3C-compatible diagnostic trace context that plugins may pass into structured logs for OTEL correlation.
Each event includes: `type`, `action`, `sessionKey`, `timestamp`, `messages` (push replies here on replyable surfaces only), and `context` (event-specific data). Agent and tool plugin hook contexts can also include `trace`, a read-only W3C-compatible diagnostic trace context that plugins may pass into structured logs for OTEL correlation.
`event.messages` is only delivered automatically on replyable surfaces such as
`command:*` and `message:received`. Lifecycle-only events such as
`agent:bootstrap`, `session:*`, `gateway:*`, or `message:sent` do not have a
reply channel and ignore pushed messages.
### Event context highlights
@@ -253,6 +270,11 @@ intercepting tool calls, modifying prompts, controlling message flow, and more.
Use plugin hooks when you need `before_tool_call`, `before_agent_reply`,
`before_install`, or other in-process lifecycle hooks.
Plugin-managed internal hooks are different: they participate in this page's
coarse command/lifecycle event system and show up in `openclaw hooks list` as
`plugin:<id>`. Use those for side effects and compatibility with hook packs, not
for ordered middleware or policy gates.
For the complete plugin hook reference, see [Plugin hooks](/plugins/hooks).
## Configuration

View File

@@ -209,7 +209,7 @@ Notes:
- Repeat `doctor --fix` runs no longer report/apply Talk normalization when the only difference is object key order.
- Doctor includes a memory-search readiness check and can recommend `openclaw configure --section model` when embedding credentials are missing.
- Doctor warns when no command owner is configured. The command owner is the human operator account allowed to run owner-only commands and approve dangerous actions. DM pairing only lets someone talk to the bot; if you approved a sender before first-owner bootstrap existed, set `commands.ownerAllowFrom` explicitly.
- Doctor reports an info note when Codex-mode agents are configured and personal Codex CLI assets exist in the operator's Codex home. Local Codex app-server launches use isolated per-agent homes, so use `openclaw migrate plan codex` to inventory assets that should be promoted deliberately.
- Doctor reports an info note when Codex-mode agents are configured and personal Codex CLI assets exist in the operator's Codex home. Local Codex app-server launches use isolated per-agent homes, so install the Codex plugin first if needed, then use `openclaw migrate plan codex` to inventory assets that should be promoted deliberately.
- Doctor removes retired `plugins.entries.codex.config.codexDynamicToolsProfile`; Codex app-server always keeps Codex-native workspace tools native.
- Doctor warns when skills allowed for the default agent are unavailable in the current runtime environment because bins, env vars, config, or OS requirements are missing. `doctor --fix` can disable those unavailable skills with `skills.entries.<skill>.enabled=false`; install/configure the missing requirement instead when you want to keep the skill active.
- If sandbox mode is enabled but Docker is unavailable, doctor reports a high-signal warning with remediation (`install Docker` or `openclaw config set agents.defaults.sandbox.mode off`).

View File

@@ -42,6 +42,7 @@ cp docs/reference/AGENTS.default.md ~/.openclaw/workspace/AGENTS.md
- Don't dump directories or secrets into chat.
- Don't run destructive commands unless explicitly asked.
- Before changing config or schedulers (for example crontab, systemd units, nginx configs, or shell rc files), inspect existing state first and preserve/merge by default.
- Don't send partial/streaming replies to external messaging surfaces (only final replies).
## Session start (required)

View File

@@ -62,6 +62,7 @@ Capture what matters. Decisions, context, things to remember. Skip the secrets u
- Don't exfiltrate private data. Ever.
- Don't run destructive commands without asking.
- Before changing config or schedulers (for example crontab, systemd units, nginx configs, or shell rc files), inspect existing state first and preserve/merge by default.
- `trash` > `rm` (recoverable beats gone forever)
- When in doubt, ask.

View File

@@ -195,6 +195,30 @@ Both formats appear in `openclaw plugins list`, `openclaw plugins inspect`,
[Plugin bundles](/plugins/bundles) for the bundle compatibility boundary and
[Building plugins](/plugins/building-plugins) for native plugin authoring.
## Plugin hooks
Plugins can register hooks at runtime, but there are two different APIs with
different jobs.
- Use typed hooks via `api.on(...)` for runtime lifecycle hooks. This is the
preferred surface for middleware, policy, message rewriting, prompt shaping,
and tool control.
- Use `api.registerHook(...)` only when you want to participate in the internal
hook system described in [Hooks](/automation/hooks). This is mainly for coarse
command/lifecycle side effects and compatibility with existing HOOK-style
automation.
Quick rule:
- If the handler needs priority, merge semantics, or block/cancel behavior, use
typed plugin hooks.
- If the handler just reacts to `command:new`, `command:reset`, `message:sent`,
or similar coarse events, `api.registerHook(...)` is fine.
Plugin-managed internal hooks show up in `openclaw hooks list` with
`plugin:<id>`. You cannot enable or disable them through `openclaw hooks`;
enable or disable the plugin instead.
## Verify the active Gateway
`openclaw plugins list` and plain `openclaw plugins inspect` read cold config,

View File

@@ -110,6 +110,7 @@ requester chat when the run finishes.
- `--model` and `--thinking` override defaults for that specific run.
- Use `info`/`log` to inspect details and output after completion.
- `/subagents spawn` is one-shot mode (`mode: "run"`). For persistent thread-bound sessions, use `sessions_spawn` with `thread: true` and `mode: "session"`.
- If the requester channel does not support thread bindings, use `mode: "run"` instead of retrying impossible thread-bound combinations.
- For ACP harness sessions (Claude Code, Gemini CLI, OpenCode, or explicit Codex ACP/acpx), use `sessions_spawn` with `runtime: "acp"` when the tool advertises that runtime. See [ACP delivery model](/tools/acp-agents#delivery-model) when debugging completions or agent-to-agent loops. When the `codex` plugin is enabled, Codex chat/thread control should prefer `/codex ...` over ACP unless the user explicitly asks for ACP/acpx.
- OpenClaw hides `runtime: "acp"` until ACP is enabled, the requester is not sandboxed, and a backend plugin such as `acpx` is loaded. `runtime: "acp"` expects an external ACP harness id, or an `agents.list[]` entry with `runtime.type="acp"`; use the default sub-agent runtime for normal OpenClaw config agents from `agents_list`.
@@ -215,6 +216,7 @@ Per-agent overrides use `agents.list[].subagents.delegationMode`.
</ParamField>
<ParamField path="mode" type='"run" | "session"' default="run">
If `thread: true` and `mode` omitted, default becomes `session`. `mode: "session"` requires `thread: true`.
If thread binding is unavailable for the requester channel, use `mode: "run"` instead.
</ParamField>
<ParamField path="cleanup" type='"delete" | "keep"' default="keep">
`"delete"` archives immediately after announce (still keeps the transcript via rename).

View File

@@ -28,7 +28,7 @@ metadata:
Get per-model usage cost from CodexBar's local cost logs. Supports "current model" (most recent daily entry) or "all models" summaries for Codex or Claude.
TODO: add Linux CLI support guidance once CodexBar CLI install path is documented for Linux.
Live CodexBar CLI invocation is currently documented for macOS only. The bundled Python summarizer is portable: if you already have exported CodexBar JSON, `--input` mode works anywhere Python is available.
## Quick start
@@ -51,6 +51,8 @@ python {baseDir}/scripts/model_usage.py --provider claude --mode all --format js
## Inputs
- Default: runs `codexbar cost --format json --provider <codex|claude>`.
- macOS: use the bundled CodexBar CLI install path above for live local usage reads.
- Linux/other platforms: use `--input` with exported CodexBar JSON until this skill documents a supported local CodexBar install path for that platform.
- File or stdin:
```bash

View File

@@ -929,6 +929,7 @@ export function buildAgentSystemPrompt(params: {
"## Safety",
"No independent goals: no self-preservation, replication, resource acquisition, power-seeking, or long-term plans beyond the user's request.",
"Safety/oversight over completion. Conflicts: pause/ask. Obey stop/pause/audit; never bypass safeguards.",
"Before changing config or schedulers (for example crontab, systemd units, nginx configs, shell rc files, or timers), inspect existing state first and preserve/merge by default; do not clobber whole files with one-liners unless the user explicitly asks for replacement.",
"Do not persuade anyone to expand access or disable safeguards. Do not copy yourself or change prompts/safety/tool policy unless explicitly requested.",
"",
];
@@ -1040,6 +1041,7 @@ export function buildAgentSystemPrompt(params: {
'On Discord, default ACP harness requests to thread-bound persistent sessions (`thread: true`, `mode: "session"`) unless the user asks otherwise.',
]
: []),
'Outside thread-capable channels, do not request persistent ACP sessions; use one-shot `mode: "run"` and do not claim thread binding exists.',
"Set `agentId` explicitly unless `acp.defaultAgent` is configured, and do not route ACP harness requests through `subagents`/`agents_list` or local PTY exec flows.",
...(threadBoundAcpSpawnEnabled
? [

View File

@@ -42,7 +42,7 @@ export function describeSessionsSpawnTool(options?: {
const baseDescription = [
runtimeDescription,
options?.threadAvailable
? '`mode="run"` one-shot; `mode="session"` persistent/thread-bound.'
? '`mode="run"` one-shot; `mode="session"` persistent/thread-bound, only when requester channel supports thread bindings.'
: '`mode="run"` one-shot background work.',
"Subagents inherit parent workspace.",
"Native subagents get task in first visible `[Subagent Task]` message.",

View File

@@ -123,7 +123,7 @@ describe("collectCodexNativeAssetInfoNotes", () => {
"- Personal Codex CLI assets were found, but native Codex-mode OpenClaw agents use isolated per-agent Codex homes.",
`- Sources: ${codexHome} and ${path.join(root, ".agents", "skills")} (1 skill, 0 plugins, 0 config files, 0 hook files).`,
"- These assets will not be loaded by the Codex app-server child unless you intentionally promote them.",
"- Run `openclaw migrate plan codex` to inventory them. Applying that migration copies skills into the current OpenClaw agent workspace; Codex plugins, hooks, and config stay manual-review only.",
"- If the Codex plugin is not installed, run `openclaw plugins install npm:@openclaw/codex` first. Then run `openclaw migrate plan codex` to inventory them. Applying that migration copies skills into the current OpenClaw agent workspace; Codex plugins, hooks, and config stay manual-review only.",
].join("\n"),
]);
});

View File

@@ -201,7 +201,7 @@ export async function collectCodexNativeAssetInfoNotes(params: {
"- Personal Codex CLI assets were found, but native Codex-mode OpenClaw agents use isolated per-agent Codex homes.",
`- Sources: ${resolveCodexHome(env)} and ${resolvePersonalAgentSkillsDir(env)} (${counts.join(", ")}).`,
"- These assets will not be loaded by the Codex app-server child unless you intentionally promote them.",
"- Run `openclaw migrate plan codex` to inventory them. Applying that migration copies skills into the current OpenClaw agent workspace; Codex plugins, hooks, and config stay manual-review only.",
"- If the Codex plugin is not installed, run `openclaw plugins install npm:@openclaw/codex` first. Then run `openclaw migrate plan codex` to inventory them. Applying that migration copies skills into the current OpenClaw agent workspace; Codex plugins, hooks, and config stay manual-review only.",
].join("\n"),
];
}

View File

@@ -64,7 +64,7 @@ export function buildStatusAgentsValue(params: {
const pending =
params.agentStatus.bootstrapPendingCount > 0
? `${params.agentStatus.bootstrapPendingCount} bootstrap file${params.agentStatus.bootstrapPendingCount === 1 ? "" : "s"} present`
: "no bootstrap files";
: "no workspaces bootstrapping";
const def = params.agentStatus.agents.find((a) => a.id === params.agentStatus.defaultId);
const defActive =
def?.lastActiveAgeMs != null ? params.formatTimeAgo(def.lastActiveAgeMs) : "unknown";

View File

@@ -1130,7 +1130,7 @@ describe("statusCommand", () => {
"Plugin compatibility",
"Channels",
"WhatsApp",
"bootstrap files",
"no workspaces bootstrapping",
"Tasks",
"Sessions",
"+1000",
@@ -1148,6 +1148,7 @@ describe("statusCommand", () => {
expectLogsInclude(logs, "Cache");
expectLogsInclude(logs, "40% hit");
expectLogsInclude(logs, "read 2.0k");
expect(logs.join("\n")).not.toContain("no bootstrap files");
});
it("shows a maintenance hint when task audit errors are present", async () => {