Agent Session Audit Log — Operations Guide

Table: dev_r_agent_sessions in Supabase project mwkqmgadqnkkihjdeqsi Migration: monitoring/supabase/migrations/20260618170113_723_agent_sessions.sql

What it tracks

Every Claude Code session that runs in the p24-infra ecosystem writes a row to dev_r_agent_sessions. This gives a complete audit trail: which worker ran, when, what skill was invoked, which issues were touched, and how sessions relate to each other in a parent → subagent hierarchy.

Type hierarchy

typeparent_session_idDescription
workerNULLTop-level session: hourly triage, issues-review, manual dev work
subagentparent’s session_idSpawned via the Agent tool by a worker session

The parent_session_id column is a self-referencing foreign key:

worker session (IO1, issues-review)
  └── subagent (worker-issue #721)
  └── subagent (worker-issue #722)
        └── subagent (nested subagent, if any)

Required environment variables

VariableSourceExample values
CLAUDE_SESSION_IDSet by Claude Code automaticallysess_01XYZ...
P24_WORKER_LABELServer startup env (systemd unit file or /etc/environment)IO1, HS1, BMS4-1, local
P24_ENVIRONMENTServer startup env (systemd unit file or /etc/environment)vps-i1, vps-h1, bms-4, local
SUPABASE_URLSOPS → .env on serverhttps://mwkqmgadqnkkihjdeqsi.supabase.co
SUPABASE_ANON_KEYSOPS → .env on servereyJ...

Why server startup env for P24_WORKER_LABEL / P24_ENVIRONMENT? These are identity labels, not secrets — safe to set as system env vars. Claude Code inherits the parent process environment, so any var set in the systemd unit or /etc/environment is automatically available in every session. Do NOT put them in .claude/settings.json — that file is committed and shared across all environments.

Optional:

VariableWhen to setNotes
P24_PARENT_SESSION_IDSubagent sessionsInject in subagent prompt preamble (see below)
P24_SKILL_INVOKEDWhen a skill triggers the sessione.g. hourly-devops-triage
P24_BRANCHSession-end scriptCurrent git branch
P24_ISSUES_WORKEDSession-end scriptComma-separated issue numbers, e.g. 721,722
P24_PR_CREATEDSession-end scriptPR number if one was opened

Per-VPS setup — server startup environment

P24_WORKER_LABEL and P24_ENVIRONMENT are set in the server’s startup environment, not in .claude/settings.json. Add them to the systemd unit file or /etc/environment on each host:

HostWhere to addP24_WORKER_LABELP24_ENVIRONMENT
vps-i1 (IONOS)/etc/environment or claude-runner unitIO1vps-i1
vps-h1 (Hostinger)/etc/environment or claude-runner unitHS1vps-h1
bms-4/etc/environment or claude-runner unitBMS4-1bms-4
local (dev)shell profile (~/.bashrc or PowerShell $PROFILE)locallocal

Example for /etc/environment (applies to all processes on the host):

P24_WORKER_LABEL=IO1
P24_ENVIRONMENT=vps-i1

Example for a systemd unit (/etc/systemd/system/claude-runner.service):

[Service]
Environment=P24_WORKER_LABEL=IO1
Environment=P24_ENVIRONMENT=vps-i1

Passing P24_PARENT_SESSION_ID to subagents

When a worker spawns a subagent via the Agent tool, include this preamble at the top of the subagent prompt:

## Session context
P24_PARENT_SESSION_ID=<current CLAUDE_SESSION_ID>

Set this env var before running agent-session-start.py so your row links
to the parent session in dev_r_agent_sessions.

The subagent reads P24_PARENT_SESSION_ID from its environment (injected via env in the Agent tool call or written to the shell before the script runs), sets type = 'subagent', and writes parent_session_id automatically.

Write points

Session start

Run at the beginning of each session (e.g. via a hook or skill init):

python scripts/agent-session-start.py

Upserts a row with status = 'in_progress'. Safe to call multiple times (uses Prefer: resolution=merge-duplicates).

Session end

Run at session close (e.g. /commit skill, Stop hook):

# Normal completion
P24_BRANCH=$(git branch --show-current) \
P24_ISSUES_WORKED="721,722" \
P24_PR_CREATED="789" \
python scripts/agent-session-end.py --status completed --summary "Implemented #721 and #722, opened PR #789"
 
# On failure
python scripts/agent-session-end.py --status failed --summary "Blocked on missing NEXT_PUBLIC_SUPABASE_ANON_KEY"

Example Grafana queries

Timeline — sessions by worker, last 24 h

SELECT
  started_at,
  ended_at,
  worker,
  environment,
  status,
  skill_invoked,
  EXTRACT(EPOCH FROM (COALESCE(ended_at, NOW()) - started_at)) / 60 AS duration_min
FROM dev_r_agent_sessions
WHERE started_at > NOW() - INTERVAL '24 hours'
ORDER BY started_at DESC;

Subagent tree — children of a given session

SELECT
  s.session_id,
  s.type,
  s.worker,
  s.skill_invoked,
  s.status,
  s.started_at,
  s.summary
FROM dev_r_agent_sessions s
WHERE s.parent_session_id = '<parent_session_id>'
ORDER BY s.started_at;

Summary table — recent worker sessions

SELECT
  session_id,
  worker,
  environment,
  skill_invoked,
  status,
  issues_worked,
  pr_created,
  EXTRACT(EPOCH FROM (COALESCE(ended_at, NOW()) - started_at)) / 60 AS duration_min,
  summary,
  started_at
FROM dev_r_agent_sessions
WHERE type = 'worker'
ORDER BY started_at DESC
LIMIT 50;

Notes

  • CLAUDE_SESSION_ID availability: this env var is set by Claude Code when the --session-id flag is used or when the harness injects it. If not available, both scripts exit silently with a stderr message — no crash, no data loss.
  • No secrets are stored in this table — only session metadata.
  • RLS is enabled with the standard anon all policy (same pattern as dev_r_services, dev_r_projects).
  • grafana_readonly has SELECT access for dashboard queries.