Skip to content

Event Schema

Every interceptor writes the same event format, so detection, the dashboards, and your own tools can treat events from Claude Code, Codex, Cowork, and Antigravity the same way.

Every event has these fields:

interface BaseEvent {
schema_version: 1; // Event format version
event_id: string; // Unique event ID
session_id: string; // Session the event belongs to
occurred_at: string; // When it happened (ISO 8601)
recorded_at: string; // When Omnodex recorded it (ISO 8601)
interceptor: Interceptor; // What captured it
event_type: EventType; // What kind of event it is
platform?: string; // Agent runtime, when known (for example "codex")
}
ValueSource
claude-code-hookClaude Code hooks
codex-hookCodex hooks
antigravity-hookAntigravity hooks
mcp-proxyThe Omnodex MCP proxy (Cowork, Codex MCP, Antigravity MCP, and any other MCP client)
analyzerRisk detection
mockomnodex spike test sessions
{
event_type: "session.started";
user: string; // OS user running the agent or proxy
project_path: string; // Working directory of the session
mcp_servers: string[]; // Upstream servers (proxy sessions)
}
{
event_type: "session.ended";
duration_ms: number;
status: "completed" | "errored" | "interrupted";
}

Written when a tool call starts.

{
event_type: "tool.invoked";
tool_call_id: string; // Links to the matching tool.completed
tool_name: string; // For example "Bash", "Edit", or "filesystem__read_file"
mcp_server: string; // Owning MCP server, or "builtin" for the agent's own tools
parameters: Record<string, unknown>; // Values may be "[REDACTED]" if redaction is on
cwd?: string; // Working directory, when the agent reports it
}

Written when a tool call finishes. Tool output is not stored, only its size.

{
event_type: "tool.completed";
tool_call_id: string;
duration_ms: number;
status: "success" | "error";
response_bytes: number;
error_message?: string;
}

Written for file reads and writes the interceptor can identify, currently Claude Code’s file tools.

{
event_type: "file.read" | "file.written";
path: string; // File path, or the search pattern for Grep and Glob
bytes: number;
}

Written by detection when a rule matches.

{
event_type: "risk.detected";
severity: "LOW" | "MEDIUM" | "HIGH" | "CRITICAL";
category: string;
description: string;
related_event_id: string; // tool_call_id of the call that triggered the rule
rule_id: string;
}

Events are stored as JSON Lines under the Omnodex home, one file per session:

$OMNODEX_HOME/event-log/
index.jsonl one line per session: session_id, registered_at, file
sessions/<session_id>.jsonl

Each line is one complete event:

{"schema_version":1,"event_id":"7c4137d2-1d73-44f4-89d6-312c04250883","session_id":"2bf17678-7b08-4f3f-805d-5058426114b5","occurred_at":"2026-09-16T20:20:39.350Z","recorded_at":"2026-09-16T20:20:39.350Z","interceptor":"mcp-proxy","event_type":"tool.invoked","tool_call_id":"f2cc6e27-457a-4b23-9643-77af2a68a534","tool_name":"filesystem__list_directory","mcp_server":"filesystem","parameters":{"path":"/home/case/project"}}

Standard tools can process the files:

Terminal window
# Count events across all sessions
cat ~/.omnodex/event-log/sessions/*.jsonl | wc -l
# Tool calls only
cat ~/.omnodex/event-log/sessions/*.jsonl | jq -c 'select(.event_type == "tool.invoked") | {tool_name, mcp_server}'
# Shell commands
cat ~/.omnodex/event-log/sessions/*.jsonl | jq -c 'select(.event_type == "tool.invoked" and .tool_name == "Bash") | .parameters'