Runtime overview
OpenClaw is a self-hosted gateway that connects chat apps — Discord, Slack, Signal, Telegram, WhatsApp, iMessage, Matrix, Microsoft Teams and more — to AI coding agents. Beacon supports it through three collection paths. The first two are live collection paths and both are wanted on the same machine; the third is an offline recovery path for historical or missed sessions:--harness openclaw-gateway is also accepted and installs the same thing.
The live paths are not alternatives. The plugin reports what the agent did — sessions, prompts, tool calls, commands, files, MCP activity and token usage. OpenClaw’s own diagnostics-otel export reports what the gateway did, as traces and metrics, and by OpenClaw’s default carries no prompt, tool, or system-prompt content at all unless captureContent is explicitly enabled. The session-file sync reads what OpenClaw already committed to disk and marks every event harness.collection_method=poll, so it can backfill but cannot approve, deny, or delay a tool call.
A gateway is not a single-user CLI, and the telemetry reflects that. One OpenClaw process fans several people’s chat accounts into one or more agents. Every event therefore carries the chat channel, the sender, the OpenClaw agent id and the per-turn run id under
raw, so a command executed on a repository can be traced back to the person who asked for it and the app they asked from.Prerequisites
Before enabling OpenClaw telemetry, make sure:- OpenClaw Gateway is installed and you can edit its config.
beacon endpoint installhas run so shared endpoint config and runtime log paths exist. The plugin path does not need the collector running; the OTLP path does.- The gateway is restarted, or
openclaw plugins reload beacon-endpointis run, after installing or removing the plugin.
Collection path 1: the Beacon-managed plugin
OpenClaw discovers a plugin as a directory, reading each child of its extensions directories and loading the entrypoint that directory’spackage.json declares. So Beacon owns the directory name beacon-endpoint and never reads or writes any other plugin beside it.
$OPENCLAW_STATE_DIR relocates the user-scope location, matching how OpenClaw resolves its own state directory. The workspace path has no override — OpenClaw joins the literal onto the gateway’s workspace.
Three files are written, and all three are required — OpenClaw skips a directory missing either manifest during discovery and reports nothing about it:
beacon endpoint inventory reports both scopes, so an install at either is visible.
Registered hooks
OpenClaw publishes forty-one typed plugin hooks. Beacon registers ten, and the exclusions are covered under What Beacon deliberately does not register.The plugin never makes the gateway wait on a tool call
Every other handler resolves toundefined. OpenClaw reads a returned object on its modify-kind hooks as a request to change behaviour, so returning nothing is what keeps the plugin an observer.
Beacon owns one directory and nothing else
Ifbeacon.js in that directory was not written by Beacon — a beacon-endpoint plugin installed from ClawHub, say — both install and uninstall refuse rather than overwriting or deleting it.
Uninstall removes the three files and the directory, because a directory holding manifests and no entrypoint is a plugin OpenClaw tries to load and reports as broken. A file you put in there stops the directory removal rather than being deleted with Beacon’s.
Collection path 2: OpenClaw’s OpenTelemetry export
OpenClaw ships adiagnostics-otel plugin that exports OTLP logs, traces and metrics. It is configured in OpenClaw, not by beacon endpoint install:
captureContent explicitly enabled it carries no prompt, response, tool-input, tool-output or system-prompt content, and OpenClaw documents that default deliberately.
By default Beacon filters OpenClaw’s operational metrics out of the runtime log as low-signal; beacon endpoint install --include-runtime-metrics keeps them.
Collection path 3: committed session files
OpenClaw also keeps committed session JSONL files under its state directory:$OPENCLAW_STATE_DIR relocates the root, matching the plugin install path. The session sync prefers OpenClaw’s sessions.json index when it exists, then flat-scans *.jsonl session files that are not in the index:
Your gateway config is read, never written
Beacon does not edit~/.openclaw/openclaw.json. This is the one deliberate departure from how every other runtime is handled, and the reason is that OpenClaw’s config is “JSON or JSON5” by its own documentation: JSON5 permits comments, trailing commas and unquoted keys, none of which survive a round trip through a JSON encoder. Rewriting it would silently strip your comments out of the file that configures every chat channel you run.
Instead, the installer reads that config and tells you what is missing. Two keys can matter:
If — and only if — your config already has a plugins.allow allowlist, beacon-endpoint has to be named in it or the plugin will not load at all. Beacon says so when the key is present and stays silent when it is not: introducing an allowlist where none existed would deny every other plugin you run.
A config Beacon cannot parse produces no advice rather than a guess, which is the common case for JSON5.
Discovery and status
Show OpenClaw status on all paths
openclaw_gateway harness on every path, so one gateway is one harness in any query that groups by harness.name. Plugin events carry harness.collection_method=plugin — Beacon ships the plugin source OpenClaw loads, so its coverage is Beacon’s to fix rather than OpenClaw’s to expose — OTLP events carry otlp, and session-file sync events carry poll.
Status checks the manifests as well as the plugin entry, because a directory OpenClaw skipped and a plugin that loaded and saw nothing look identical from the log alone.
Install or configuration support
beacon endpoint install --harness openclaw is not the command — OpenClaw’s OTLP export lives in OpenClaw’s own config, so Beacon prints the settings rather than writing them. Running it says so and names both commands.
Telemetry coverage
Tool taxonomy
MCP calls are identified by their separator, and they have to be. OpenClaw names a tool from an MCP server
<server>__<tool> — no mcp anywhere in the name, no mcp_* argument, and nothing in the result saying where the tool came from. So the usual mcp__server__tool reader finds nothing, and a GitHub server’s github__create_issue would land under tool.completed with no server attribution at all.The Claude-style mcp__server__tool form is still recognized first, because OpenClaw’s own Codex and Claude harness bridges mint it.exec reports status: "running" with a partial tail and no exit code. Beacon records the command line and no outcome for it, rather than presenting a partial tail as the command’s output.
apply_patch, and why it needs both halves of the call
apply_patch takes the whole patch envelope as one opaque string, and OpenClaw derives its destination paths only on before_tool_call. The plugin therefore remembers those paths, keyed by OpenClaw’s own tool call id, and attaches them to the completion — without which a completed patch would be a blob with no file rows, and every file-scoped detection matches on file.path.
Paths from a call the plugin never saw proposed are dropped rather than guessed: a patch event enriched with another call’s paths would read as evidence that those files changed. Such a call is recorded as a completed tool carrying its patch text instead.
Approvals and enforcement
Beacon records no approval decisions for OpenClaw, and does not synthesize any. OpenClaw genuinely does ask operators to approve tool calls, and exposes no hook reporting the answer: there is notool_approval_* event in its catalog, and the only approval surface a plugin has is before_tool_call’s requireApproval result — a plugin requesting a prompt and being told its own outcome. Beacon does not request approvals, so it never sees one. This is the same call already settled for Cline, Pi, goose, OpenHands and Kiro.
Enforcement stays behind the optional, off-by-default policy provider seam (BEACON_POLICY_PROVIDER), which is inert unless it names an executable and fails open on any error.
What Beacon deliberately does not register
Some exclusions are about volume, and some are about what a telemetry plugin is allowed to be. Because registering them would give Beacon power over your agent:before_prompt_build,agent_turn_prepareandheartbeat_prompt_contributionare prompt injection hooks.inbound_claim,before_dispatchandreply_dispatchare claim hooks that can swallow a message before the agent sees it.before_installgates skill and plugin installation.skill_proposal_evaluatemakes its handler a voting evaluator on whether a skill may be created.
llm_inputcarries the full system prompt, the assembled prompt and the entire history array on every model call.message_receivedalready carries what the person actually wrote, which is the prompt an investigation asks about.agent_endcarries the wholemessagesarray for the turn; its unique fields are a success flag and a duration.model_call_startedandmodel_call_endedfire once per provider call — several per turn with a tool loop — and neither carries usage.- The delivery hooks (
message_sending,message_sent,reply_payload_sending) describe chat plumbing rather than agent action.
tool_result_persistandbefore_message_writeare OpenClaw’s two synchronous hooks. Promises are ignored with a warning, so a handler that spawns a process could not wait for it.
Data handling
OpenClaw content is handled like every other runtime. Prompts, tool arguments, command lines, command output, paths and diffs are retained in local or customer-controlled logs, with local secret redaction and per-string limits applied before writing, and a hash and byte count on each content-bearing event. Events over the 64 KiB limit drop raw and retained content, preserve stable metadata, and setfield_truncated.
The whole hook envelope is kept under raw.openclaw, which preserves the fields OpenClaw reports that the event schema has no column for — the channel, the sender, the agent id, the run id and the conversation key. It goes through the same redaction and limits as everything else and is the first thing dropped when an event exceeds the ceiling.
Chat messages are prompts here. On a gateway the prompt is a message someone sent from Discord or WhatsApp, so retained prompt text includes chat content from those apps. That is the point of the integration, and it is worth knowing before you enable it on a shared gateway.
Known gaps
- No approval decisions. OpenClaw exposes no approval event to a plugin, and Beacon does not synthesize one. Approval rules and dashboards show nothing for this runtime.
- No reported cost. OpenClaw computes a per-turn USD figure from an operator-configured cost table rather than from a provider report, and it is not on the
llm_outputhook. Beacon records runtime-reported cost only, sogen_ai.usage.cost_usdstays empty rather than carrying a local estimate. - Token usage needs a config key. See Your gateway config is read, never written. This is the most common reason an otherwise healthy OpenClaw install reports no tokens.
- Tool ordering is not guaranteed.
tool.invokedcan be written after the completion for the same call, because thebefore_tool_callhandler never blocks. Correlate ongen_ai.tool.call.id. - No working directory outside a repository. OpenClaw sets
workspaceDirfor runs that have one and omits it otherwise — a chat turn that never touched a repository genuinely has none. Beacon leaves the field absent rather than falling back to the gateway daemon’s own directory, which would attribute the work to wherever the service manager started it. - No per-call tool result for most tools.
after_tool_callcarries aresult, but onlyexecpublishes a documented structure inside it. Other tools’ results are kept underrawrather than promoted to schema fields. - Gateway lifecycle is not collected.
gateway_startandgateway_stopdescribe the service rather than agent activity, and the event schema has no action for them.
Deployment notes
Plugins are discovered at gateway startup, so an install taken while the gateway is running takes effect after a reload. Restart the gateway, or runopenclaw plugins reload beacon-endpoint.
Confirm status, then generate one event and check the log:
- Confirm the gateway was reloaded after the install.
- Check
$OPENCLAW_STATE_DIR: if it is set, the user-scope plugin is under that directory, not~/.openclaw. - Confirm all three files are present in
~/.openclaw/extensions/beacon-endpoint/. OpenClaw skips a directory missing a manifest without reporting it. - Check
plugins.denyandplugins.entries.beacon-endpoint.enabledin OpenClaw’s config, andplugins.allowif you use one. - Run
openclaw plugins inspect beacon-endpoint --runtime --jsonto see what the gateway thinks of it.
allowConversationAccess is not set. beacon endpoint hooks status --harness openclaw says so.
Related
Supported agent harnesses
Return to the runtime support overview.
OpenClaw commands
Print config, check status, and validate the gateway’s OTLP export.