Environment
- OpenClaw: 2026.6.8 (gateway + CLI)
- Channel provider: bundled Slack provider (
@openclaw/slack external as of 2026.5.x)
- Channel surface: socket-mode bot in a workspace, registered to a single channel
- Host: single-VPS Linux deployment, no container
TL;DR
The OpenClaw Slack provider does not emit an INFO-level log line on receipt of an app_mention event. The Telegram provider does:
[telegram] Inbound message telegram:group:<chat>:topic:<id> -> @<bot> (group, 42 chars)
The Slack equivalent log line does not exist. The only journal evidence that a Slack app_mention arrived is downstream side-effects:
[plugins] [<plugin>] usage surface=tool_mention sender=llm ... — fires only when a plugin tool actually executes.
[agent/cli-backend] cli exec ... trigger=user reuse=invalidated:auth-profile — fires when the LLM router is invoked. Closest proxy, but indirect.
When the LLM router consumes a mention but produces no tool call (e.g., a systemPrompt routing gap silently drops the request), there is zero journal evidence that the inbound ever arrived. The bot's response to the user is missing, but journalctl ... | grep '\[slack\]' returns empty between socket-connect time and now.
The reaction lifecycle in Slack (👀 → 🧠 → ⏳ via the channel-feedback controller in dist/channel-feedback-2_QV4FKD.js) is the only diagnostic signal — and it's only visible in the Slack UI itself, not in the server journal.
Why this matters (concrete failure I just triaged)
A user typed @<bot> refresh in a target channel. The reactions cycled 👀 → 🧠 → ⏳ but no text response landed. My initial triage:
grep '\[slack\]' journal --since "1 hour ago" → zero matches.
- I concluded "Slack socket-mode silently disconnected" because the bundled provider also doesn't log heartbeat / disconnect events at INFO level.
- The user pushed back: "if it never reached the gateway, where did the eye-reaction come from?"
- I re-read the source (
dist/channel-feedback-2_QV4FKD.js DEFAULT_EMOJIS), recognized that 👀/🧠/⏳ is the gateway's status-reaction lifecycle, then traced the cli-session metadata at the right timestamp and found cli exec promptChars=13495 trigger=user reuse=invalidated:auth-profile — which IS the Slack inbound, just unlabelled.
- Root cause turned out to be a systemPrompt routing gap (orthogonal to the observability problem). But the observability gap delayed root cause by ~15 minutes and two wrong-turn hypotheses.
A single [slack] app_mention received log line at INFO would have made step 1 the conclusive answer.
Proposed change
Add an INFO-level log emit in the Slack provider on inbound app_mention (and ideally message events that pass the channel filter), mirroring the Telegram pattern:
[slack] Inbound app_mention slack:<workspace>:channel:<channel-id> -> @<bot> (channel, 42 chars)
Optional finer-grained variants:
[slack] Inbound app_mention channel=<channel-id> user=<user-id> body_chars=<N> bot=@<bot> ts=<message-ts> thread_ts=<thread-ts-or-none>
The Telegram provider's log emits at info from the [telegram] log category (matches op[<pid>]: ... [telegram] Inbound message ...). Mirroring that level + category for [slack] keeps existing journal-grep workflows uniform across channels.
Why INFO (not DEBUG)
- Telegram inbound is INFO. Channel-level parity matters for cross-channel triage — operators learn one pattern, not two.
- INFO is the lowest level that survives the default systemd journal capture in a single-VPS deployment. DEBUG-level entries are routinely filtered out at the host level.
- Volume is small: one log line per
app_mention. A busy bot processing 200 mentions/hour adds ~200 INFO lines/hour — negligible.
Suggested log message format
To match the Telegram format already in use, propose:
log.info(
"[slack] Inbound app_mention slack:%s:channel:%s -> @%s (channel, %d chars)",
workspaceId,
channelId,
botUsername,
bodyChars,
);
If the provider already constructs a from/to semantic pair (as the Telegram provider does — search for Inbound message ${params.from} -> ${params.to} in dist/bot-<hash>.js:7302), the obvious symmetric API is:
log.info(
"[slack] Inbound app_mention %s -> @%s (channel, %d chars)",
`slack:${workspaceId}:channel:${channelId}`,
botUsername,
bodyChars,
);
Adjacent observability gap (could fix here or separately)
The same Slack provider also does not log:
- Socket-mode connect / disconnect / reconnect events at INFO. There IS an emit on initial connect (
[slack] socket mode connected) but no corresponding disconnect/reconnect emit. A silent socket-mode WebSocket disconnect — which I have seen mentioned in other forum posts — would be undetectable without enabling DEBUG.
slack-sdk disconnected event passthrough. Wiring this into a re-connect attempt + log emit would make the bundled provider self-healing and visible.
If maintainers prefer, these are scope-separable into their own issues; I can file a follow-up.
Acceptance criteria suggestions
- Every Slack
app_mention event received by the provider produces a single INFO-level log line with channel, sender, body length, and bot identity.
- The log category is
[slack] to align with the Telegram convention.
- The line is emitted before the event is dispatched to
inbound_claim / LLM router, so it survives downstream silent failures.
- (Optional) Same for
message events that pass the channel filter, behind a config knob if volume becomes a concern.
Sanitization notes
This draft replaces deployment-specific values with placeholders:
<channel-id> for the target channel
<workspace> for the Slack workspace id
<chat> / <id> / <user> for Telegram analogues
@<bot> for the bot username
<plugin> for the relevant plugin id
- Specific tool names, business names, and PII redacted entirely
Environment
@openclaw/slackexternal as of 2026.5.x)TL;DR
The OpenClaw Slack provider does not emit an INFO-level log line on receipt of an
app_mentionevent. The Telegram provider does:The Slack equivalent log line does not exist. The only journal evidence that a Slack
app_mentionarrived is downstream side-effects:[plugins] [<plugin>] usage surface=tool_mention sender=llm ...— fires only when a plugin tool actually executes.[agent/cli-backend] cli exec ... trigger=user reuse=invalidated:auth-profile— fires when the LLM router is invoked. Closest proxy, but indirect.When the LLM router consumes a mention but produces no tool call (e.g., a systemPrompt routing gap silently drops the request), there is zero journal evidence that the inbound ever arrived. The bot's response to the user is missing, but
journalctl ... | grep '\[slack\]'returns empty between socket-connect time and now.The reaction lifecycle in Slack (👀 → 🧠 → ⏳ via the
channel-feedbackcontroller indist/channel-feedback-2_QV4FKD.js) is the only diagnostic signal — and it's only visible in the Slack UI itself, not in the server journal.Why this matters (concrete failure I just triaged)
A user typed
@<bot> refreshin a target channel. The reactions cycled 👀 → 🧠 → ⏳ but no text response landed. My initial triage:grep '\[slack\]' journal --since "1 hour ago"→ zero matches.dist/channel-feedback-2_QV4FKD.js DEFAULT_EMOJIS), recognized that 👀/🧠/⏳ is the gateway's status-reaction lifecycle, then traced the cli-session metadata at the right timestamp and foundcli exec promptChars=13495 trigger=user reuse=invalidated:auth-profile— which IS the Slack inbound, just unlabelled.A single
[slack] app_mention receivedlog line at INFO would have made step 1 the conclusive answer.Proposed change
Add an INFO-level log emit in the Slack provider on inbound
app_mention(and ideallymessageevents that pass the channel filter), mirroring the Telegram pattern:Optional finer-grained variants:
The Telegram provider's log emits at
infofrom the[telegram]log category (matchesop[<pid>]: ... [telegram] Inbound message ...). Mirroring that level + category for[slack]keeps existing journal-grep workflows uniform across channels.Why INFO (not DEBUG)
app_mention. A busy bot processing 200 mentions/hour adds ~200 INFO lines/hour — negligible.Suggested log message format
To match the Telegram format already in use, propose:
If the provider already constructs a
from/tosemantic pair (as the Telegram provider does — search forInbound message ${params.from} -> ${params.to}indist/bot-<hash>.js:7302), the obvious symmetric API is:Adjacent observability gap (could fix here or separately)
The same Slack provider also does not log:
[slack] socket mode connected) but no corresponding disconnect/reconnect emit. A silent socket-mode WebSocket disconnect — which I have seen mentioned in other forum posts — would be undetectable without enabling DEBUG.slack-sdkdisconnectedevent passthrough. Wiring this into a re-connect attempt + log emit would make the bundled provider self-healing and visible.If maintainers prefer, these are scope-separable into their own issues; I can file a follow-up.
Acceptance criteria suggestions
app_mentionevent received by the provider produces a single INFO-level log line with channel, sender, body length, and bot identity.[slack]to align with the Telegram convention.inbound_claim/ LLM router, so it survives downstream silent failures.messageevents that pass the channel filter, behind a config knob if volume becomes a concern.Sanitization notes
This draft replaces deployment-specific values with placeholders:
<channel-id>for the target channel<workspace>for the Slack workspace id<chat>/<id>/<user>for Telegram analogues@<bot>for the bot username<plugin>for the relevant plugin id