diagnosis.json. All of this happens in runtime.py and session.py — the CLI layer only routes to these functions; it does not participate in any of the runtime logic.
Session Lifecycle
Every run moves through a strict state machine. States are written into the session record at each transition so you can always inspectruns/<run_id>.json to see exactly where a session stopped.
| State | When it occurs |
|---|---|
| IDLE | The implicit starting state before critiqor monitor openclaw is called. No files exist yet. |
| MONITORING | create_session() has run, the plugin is loaded, OpenClaw is running as a child process, and events are being captured into runs/<run_id>/session.json. |
| FINALIZING | critiqor finalize was called. request_finalize() stamps the session FINALIZING and active_session.json transitions to the same status so nothing else can claim the active slot. Evidence is being assembled and the diagnosis is being generated. |
| COMPLETED | finalize_session() has finished. diagnosis.json has been written, the session record is updated with full diagnosis data, and active_session.json is removed. |
| ABORTED | An error occurred during monitoring (launch failure, unhandled OSError, or explicit call to abort_session()). The session record is stamped ABORTED and active_session.json is removed. |
MONITORING or FINALIZING status are considered active. load_active_session() returns None for any other status, which prevents accidental double-starts.
Session File Structure
create_session() writes the initial session record to runs/<run_id>.json using write_json(), a low-level helper that writes atomically through a .tmp rename. Path resolution for every run artifact goes through paths_for(runs_dir), which returns a SessionPaths object whose methods — run_path(run_id), evidence_summary_path(run_id), and diagnosis_path(run_id) — resolve to runs/<run_id>.json, runs/<run_id>/session.json, and runs/<run_id>/diagnosis.json respectively. At finalize time write_json is called again through evidence_summary_path to update the evidence file and a second time through diagnosis_path to write the completed diagnosis artifact.
The structure below reflects what is present in runs/<run_id>.json at creation time and what gets filled in at finalization:
finalize_session() completes, status becomes "COMPLETED", finalized_at is stamped, event_log contains the merged event stream, and diagnosis, trust_score, causal_graph, failure_analysis, and cost_analysis are all populated from the diagnosis engine output.
How Events Flow Into the Session
Two independent sources are merged at finalize time. Neither source blocks the other — they run in parallel during monitoring and are joined only whencritiqor finalize is called.
Source 1 — Internal lifecycle events
Written directly to runs/<run_id>.json by append_event_to_run() throughout the monitoring session. These include:
state_transition— every status change (MONITORING,FINALIZING,COMPLETED,ABORTED)process_start— recorded immediately aftersubprocess.Popensucceeds, includes the PID and launch commandprocess_end— recorded when the child process exits, includes exit code and PIDerror_event— recorded on non-zero exit, timeout,KeyboardInterrupt, orOSError
runs/<run_id>/session.json by the bundled OpenClaw plugin as the agent runs. These are the structured tool and extension API events described in the OpenClaw Plugin page.
At finalize time, load_session_evidence_events() reads session.json, normalizes each event through normalize_plugin_event() (which maps raw plugin event types to canonical Critiqor types), and merges the result with the internal lifecycle events before passing the combined stream to the diagnosis engine.
Environment Variables Set for OpenClaw
Before spawning the child process, the runtime callsopenclaw_environment() to build an enriched copy of the current environment. The following variables carry run context into the plugin:
| Variable | Purpose |
|---|---|
CRITIQOR_RUN_ID | The current run identifier (e.g. run_001). The plugin uses this to construct the path to session.json. |
CRITIQOR_RUNS_DIR | Absolute path to the runs directory. The plugin resolves all write paths relative to this value. |
CRITIQOR_AGENT_ID | Agent identifier passed from --agent-id. Stored in session metadata. |
CRITIQOR_TENANT_ID | Tenant identifier passed from --tenant-id. Stored in session metadata. |
CRITIQOR_VISIBILITY | Dashboard visibility state (private, public, anonymous, or shared). Applied at ingestion. |
CRITIQOR_EVENT_SOURCE | Always "openclaw" for monitored sessions. Identifies the event origin in the session record. |
OPENCLAW_BUNDLED_PLUGINS_DIR is set to the parent of the critiqor-openclaw plugin directory, which causes OpenClaw to auto-load the plugin without any manual configuration.
Related Pages
- Architecture Overview — The two-layer design and the full session pipeline from CLI to dashboard.
- OpenClaw Plugin — How the plugin captures events and writes them to
session.json.