Skip to content

Session replay: OpenClaw mapper — ACP replay stream + subagent_runs + flow_runs + approvals audit #4816

Description

@vivekchand

Context

OpenClaw has the richest on-disk trace of any runtime we support — a purpose-built acp_replay_events stream (ACP = Agent Client Protocol), plus normalized subagent_runs + flow_runs + task_runs + command_log_entries tables. We ignore all of it and render the flat JSONL.

Substrate

  • State DB (orchestration truth): ~/.openclaw/state/openclaw.sqlite
  • Transcripts: ~/.openclaw/agents/<alias>/sessions/*.jsonl — v3 envelope {"type":"message","message":{...},"id","parentId","timestamp"}parentId is a chain, not a tree (reference_openclaw_v3_parentid_is_chain.md)

Sub-agent model

First-class. Table subagent_runs with run_id, child_session_key, controller_session_key, requester_session_key, task, task_name, model, workspace_dir, spawn_mode, outcome_json. This is a REAL parent→child graph — the chain-not-tree warning only applies to the transcript, not to spawn relationships.

Workflow model

Table flow_runsflow_id, shape, sync_mode, controller_id, status, goal, current_step, blocked_task_id, state_json, wait_json. Steps land in task_runs with parent_flow_id, parent_task_id, agent_id, requester_agent_id, delivery_status, notify_policy. A genuine DAG with a controller.

Replay-native stream: acp_replay_events(session_id, seq, at, update_json) + acp_replay_sessions — literally designed for step-by-step replay. Use it directly instead of reconstructing from the JSONL.

Mode + approvals

  • Mode config: exec_approvals_config(default_security, default_ask, default_ask_fallback, auto_allow_skills). default_ask=never + auto_allow_skills=1 = auto. Per-agent overrides in agent_count / allowlist_count.
  • Approval audit trail: command_log_entries(action, session_key, sender_id, entry_json) — the exec-side decisions. Plugin capability approvals in plugin_binding_approvals (per-plugin per-channel).
  • User reply: in command_log_entries.entry_json and in the ACP replay update stream. NeMo Guardrails approval queue writes its own rows (project_runtime_scoped_alerts_approvals.md).

Deliverable

Implement iter_replay_events(session_id) → Iterator[ReplayEvent] for OpenClaw. Read the SQLite in mode=ro immutable=0 (daemon may be writing).

Output per the canonical schema (OSS-01):

  • Primary source: acp_replay_events.update_json — this is the pre-normalized event stream. Map its update_type values to canonical kind.
  • Enrich with joins to subagent_runs (for agent.spawn / agent.return), flow_runs + task_runs (for workflow.*), command_log_entries (for approval.decided), exec_approvals_config (for mode.changed — session-scoped, one at start).
  • Fall back to JSONL parse if acp_replay_sessions has no row for a session_id (older sessions).

Acceptance

  • 3 fixtures replay:
    1. A session with a subagent_runs fanout ≥3 children (delegations render inline)
    2. A flow_runs session with ≥5 task_runs steps (workflow swimlane renders with controller + step status)
    3. A session with an exec_approvals_config that denied ≥1 tool call (approvals rail shows the denied entries with command_log_entries.entry_json as decision_reason)
  • Mode chip shows correct value from exec_approvals_config + per-agent override count in tooltip
  • plugin_binding_approvals rows render as approvals with resolver=policy

Depends on

  • OSS-01 (schema)
  • OSS-02 (mode + approvals ingest + UI wiring)

Gotchas

  • Do not treat transcript parentId as a tree. Use subagent_runs for delegation, parentId only for message ordering within a session.
  • Two approvals systems (reference_approvals_architecture.md) — exec (command_log_entries) and plugin capability (plugin_binding_approvals). Both must land in the approvals rail with different resolver values so the UI can distinguish.
  • Daemon writes to openclaw.sqlite continuously — every read opens mode=ro, never grab a writer lock.

References

  • OSS substrate: clawmetry/sync.py OpenClaw ingest branch (grep ~/.openclaw in sync.py)
  • ACP replay is currently unused — grep acp_replay in this repo returns zero — this issue lights it up
  • Approvals arch memory: reference_approvals_architecture.md

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions