harnesses/acp-runner.js:711
ACP Command Payload Flow
This shows the exact sequence for one ACP shell command. Each row answers one question: what object exists now, who receives it, and what changed from the previous row.
Clean HEAD behavior
harnesses/harness-runtime-event-dispatcher.js:75, 366
conversation/build-agent-io-hooks.js:280
whatsapp/outbound/send-content.js:702, 714, 1841
whatsapp/message-payloads.js:10
1
ACP creates a runtime event
The runner does not emit a bare command object. It emits a harness runtime event.
Source: harnesses/acp-runner.js:711
Object at this point
{
type: "command.started",
provider: "acp",
command: {
command: "pnpm test",
status: "started"
},
raw: { message }
}
What changed?
- This is the first object.
providerstarts as"acp".
2
The dispatcher chooses the ACP route
Because it is ACP and a command runtime event, it stays on the runtime-event path.
Source: harnesses/harness-runtime-event-dispatcher.js:75, 366
Routing decision
if (
event.provider === "acp" &&
event.type === "command.started"
) {
hooks.onRuntimeEvent(event);
return;
}
What changed?
- The object is not reformatted yet.
hooks.onCommand(...)is skipped.
3
Agent IO wraps it for outbound delivery
The original ACP event is placed inside an app-level outbound event.
Source: conversation/build-agent-io-hooks.js:280 and outbound-events.js:92
New wrapper object
{
kind: "runtime_event",
event: {
type: "command.started",
provider: "acp",
command: {
command: "pnpm test",
status: "started"
},
raw: { message }
}
}
What changed?
kind: "runtime_event"is added.provider: "acp"is still unchanged.- Clean HEAD adds no
compactand nocwdhere.
4
WhatsApp turn IO sends or queues it
The outbound event crosses the transport boundary before rendering to a WhatsApp payload.
Source: execute-action-context.js:22, whatsapp/inbound/chat-turn.js:394, whatsapp/outbound/persistent-queue.js:108
Call chain
context.send(outboundEvent)
// same as
turn.io.send(outboundEvent)
sendOrQueueWhatsAppEvent({
event: outboundEvent,
chatId,
getSocket
})
What changed?
- The object is still the same outbound event.
- The transport may send now or persist for replay.
5
The runtime command renderer creates text
Only now does the command become the visible WhatsApp text string.
Source: whatsapp/outbound/send-content.js:702, 714
String transformation
command = "pnpm test"
summary = "*Shell* `pnpm test`"
icon = "🔧"
text = "🔧 *Shell* `pnpm test`"
What changed?
- The runtime event is rendered into a string.
*Shell*is the exact payload text, not_Shell_.
6
Baileys receives the final message payload
The text string is wrapped with URL previews disabled.
Source: whatsapp/outbound/send-content.js:1841 and whatsapp/message-payloads.js:10
Final payload
{
text: "🔧 *Shell* `pnpm test`",
linkPreview: null
}
🔧 Shell
pnpm test
What changed?
makeTextMessage(text)addslinkPreview: null.- This object is passed to
sock.sendMessage(...).
ACP Path
Starts as
{ type: "command.started", provider: "acp", ... }Hook used
hooks.onRuntimeEvent(event)Wrapper
{ kind: "runtime_event", event }ProviderPreserved as
"acp".Direct onCommand Path
Starts as
{ command: "pnpm test", status: "started" }Hook used
hooks.onCommand(commandEvent)Wrapper
runtimeEvent({ type: "command.started", provider: "codex", ... })ProviderSet to
"codex".onRuntimeEvent. The direct command hook is a separate path that manufactures a Codex runtime event from a bare command object.