Independent system-level observation of AI coding agent actions via native hooks. Tool call interception, file change hashing, security block/guidance decisions, actual cost from transcripts, and subagent lifecycle tracking with inline attribution. The execution audit layer — parallel to ai.claude.* self-report. Based on gryph (Apache-2.0).
These events are parallel to foundation.protocols.ai.claude.* — not replacements. Both are emitted into the same Matrix room, linked by session_id and tool_use_id.
| Property | ai.claude.* | ai.gryph.* |
|---|---|---|
| Source | Bridge daemon (API conversation) | System hooks (tool call interception) |
| Trust | Self-report | Independent observation |
| Can block | No | Yes (PreToolUse hook) |
| Sees prompts/responses | Yes | No |
| Sees actual file changes | Via bridge report | Via system hook + SHA-256 hash |
| Token counts | Estimated during session | Actual from transcript at session end |
2 events — hook-observed session boundaries
Hook-observed session start. Includes agent version and gryph version — fields not available in claude.session.start.
| Field | Type | Description |
|---|---|---|
| session_id | string | UUID linking to claude.session.start |
| agent_name | string | Agent identifier (e.g., "claude-code") |
| agent_version | string | Exact agent build (e.g., "2.1.104") |
| model | string | Model at session start |
| working_directory | string | Absolute path to project |
| source | string | How started: "cli", "web", "ide" |
| permission_mode | string | Agent permission mode |
| gryph_version | string | Gryph version performing observation |
| timestamp | string | ISO 8601 UTC |
{
"type": "foundation.protocols.ai.gryph.session.start",
"content": {
"session_id": "3f057459-de35-4b1a-84d7-484a38194b6a",
"agent_name": "claude-code",
"agent_version": "2.1.104",
"model": "claude-opus-4-20250514",
"working_directory": "/path/to/project",
"source": "cli",
"permission_mode": "default",
"gryph_version": "v0.6.0",
"timestamp": "2026-04-12T22:57:49Z"
}
}
Hook-observed session end. Includes actual token counts from the agent's transcript file — ground truth for cost estimation.
| Field | Type | Description |
|---|---|---|
| session_id | string | Session UUID |
| reason | string | "user_closed", "error", "completed" |
| duration_ms | integer | Wall-clock session duration |
| total_actions | integer | Total hook events in session |
| files_read | integer | File read count |
| files_written | integer | File write count |
| commands_executed | integer | Shell command count |
| blocked_actions | integer | Actions blocked by Checks |
| sensitive_actions | integer | Actions flagged as sensitive |
| cost | object | Actual tokens + cost (from transcript) |
{
"type": "foundation.protocols.ai.gryph.session.end",
"content": {
"session_id": "3f057459-...",
"reason": "user_closed",
"duration_ms": 3600000,
"total_actions": 148,
"files_read": 24,
"files_written": 16,
"commands_executed": 45,
"blocked_actions": 2,
"sensitive_actions": 1,
"cost": {
"input_tokens": 150000,
"output_tokens": 25000,
"cache_read_tokens": 80000,
"total_cost_usd": "2.850",
"source": "transcript"
}
}
}
3 events — pre-execution (can block), post-success, post-failure
Observed before tool execution. This is the enforcement point — Checks run here and can block. No ai.claude.* equivalent fires before execution.
| Field | Type | Description |
|---|---|---|
| tool_use_id | string | Links Pre to Post for the same call |
| tool_name | string | "Read", "Write", "Edit", "Bash", "Grep", "Glob", etc. |
| action_type | string | "file_read", "file_write", "command_exec", "tool_use" |
| input_summary | string | Abbreviated input (path or command, truncated) |
| is_sensitive | boolean | Target matches sensitive patterns |
| decision | string | "allow", "blocked", or "guidance" |
| checks_run | array | Checks that fired: [{check, decision, reason}] |
{
"type": "foundation.protocols.ai.gryph.tool.pre",
"content": {
"session_id": "3f057459-...",
"sequence": 42,
"tool_use_id": "tu_abc123",
"tool_name": "Bash",
"action_type": "command_exec",
"input_summary": "docker build -t myimage .",
"is_sensitive": false,
"decision": "blocked",
"checks_run": [
{"check": "gate3-docker-compose", "decision": "block",
"reason": "Use docker compose build, not standalone docker build -t"}
],
"timestamp": "2026-04-12T23:05:00Z"
}
}
Observed after successful tool execution.
| Field | Type | Description |
|---|---|---|
| tool_use_id | string | Links to corresponding tool.pre |
| tool_name | string | Tool name |
| action_type | string | Normalised action type |
| result_status | string | "success" |
| duration_ms | integer | Execution time |
Observed after failed tool execution. Distinct from tool.post to enable filtering.
| Field | Type | Description |
|---|---|---|
| tool_use_id | string | Links to corresponding tool.pre |
| tool_name | string | Tool name |
| error_message | string | Error description |
| duration_ms | integer | Execution time |
2 events — system-observed reads and writes with content hashing
System-observed file read. Covers Read, Grep, Glob, LS tools.
| Field | Type | Description |
|---|---|---|
| tool_use_id | string | Triggering tool call |
| tool_name | string | "Read", "Grep", "Glob", "LS" |
| path | string | Absolute file path |
| is_sensitive | boolean | Matches sensitive patterns |
System-observed file write. Includes SHA-256 content hash for immutable audit.
| Field | Type | Description |
|---|---|---|
| tool_use_id | string | Triggering tool call |
| tool_name | string | "Write", "Edit", "NotebookEdit" |
| path | string | Absolute file path |
| content_hash | string | SHA-256 of file after write |
| lines_added | integer | Lines added |
| lines_removed | integer | Lines removed |
| is_sensitive | boolean | Matches sensitive patterns |
1 event — shell commands with exit codes and timing
System-observed shell command execution.
| Field | Type | Description |
|---|---|---|
| tool_use_id | string | Triggering tool call |
| command | string | Full command string |
| description | string | Agent's description of command purpose |
| exit_code | integer | Process exit code (0 = success) |
| duration_ms | integer | Execution time |
| is_sensitive | boolean | Command accesses sensitive paths |
1 event — permission prompts, warnings, info messages
System-observed notification. Captures permission prompts (maps to ai.claude.approval.request from a different perspective).
| Field | Type | Description |
|---|---|---|
| message | string | Notification text |
| notification_type | string | "permission_prompt", "warning", "info", "error" |
2 events — no ai.claude.* equivalent. Only gryph can block tool calls.
A tool call was blocked by a governance Check before execution.
| Field | Type | Description |
|---|---|---|
| tool_use_id | string | The blocked tool call |
| tool_name | string | Tool that was blocked |
| action_type | string | Normalised action type |
| check_name | string | Which Check blocked it |
| reason | string | Human-readable reason |
| input_summary | string | What was attempted |
{
"type": "foundation.protocols.ai.gryph.security.blocked",
"content": {
"session_id": "3f057459-...",
"sequence": 42,
"tool_use_id": "tu_blocked01",
"tool_name": "Bash",
"action_type": "command_exec",
"check_name": "gate3-docker-compose",
"reason": "Use docker compose build, not standalone docker build -t",
"input_summary": "docker build -t myimage .",
"timestamp": "2026-04-12T23:05:00Z"
}
}
A tool call was allowed but with advisory guidance from a Check.
| Field | Type | Description |
|---|---|---|
| tool_use_id | string | The guided tool call |
| tool_name | string | Tool name |
| check_name | string | Which Check issued guidance |
| guidance | string | Advisory text |
1 event — actual token counts from transcript (ground truth)
Actual token counts from the agent's transcript file. Compare with ai.claude.usage.checkpoint estimates to calibrate cost models.
| Field | Type | Description |
|---|---|---|
| models | array | Per-model breakdown: model, input/output/cache tokens, cost |
| total_input_tokens | integer | Sum across all models |
| total_output_tokens | integer | Sum across all models |
| total_cost_usd | string | Estimated cost (string, not float) |
| source | string | "transcript" |
1 event — sensitive file access logging (content NOT included)
A sensitive file was accessed. Records the fact of access for compliance, not the content.
| Field | Type | Description |
|---|---|---|
| tool_use_id | string | The accessing tool call |
| action_type | string | "file_read", "file_write", "command_exec" |
| path | string | The sensitive path |
| matched_pattern | string | Which pattern matched (e.g., "**/.env") |
| content_redacted | boolean | Always true |
Track agent hierarchy: when subagents spawn and complete (added v1.1, validated 2026-04-14)
agent_id and agent_type
in every subagent tool call. Main-agent calls omit these fields. No bracketing needed —
check for field presence.
A subagent was spawned by the main agent.
| Field | Type | Description |
|---|---|---|
| agent_id | string | Subagent identifier (from Claude Code hook JSON) |
| agent_type | string | Subagent type |
Values: Explore, Plan, general-purpose | ||
A subagent completed or was terminated.
| Field | Type | Description |
|---|---|---|
| agent_id | string | Subagent identifier |
| agent_type | string | Subagent type |
| agent_transcript_path | string | Path to per-subagent JSONL transcript |
| last_assistant_message | string | Final output (truncated to 500 chars) |
How the two observation layers map to each other
| ai.claude.* event | ai.gryph.* event | Relationship |
|---|---|---|
| session.start | session.start | Parallel — same session, different observer |
| session.end | session.end | Parallel — gryph adds actual token counts |
| tool.call | tool.pre | gryph fires BEFORE execution, can block |
| tool.result | tool.post | Parallel — gryph adds duration |
| tool.error | tool.failure | Parallel — different error detail |
| file.change | file.write | Parallel — gryph adds content_hash |
| approval.request | notification | Different framing of same moment |
| usage.checkpoint | cost.observed | gryph has ACTUAL tokens vs estimates |
| — | security.blocked | Gryph-only: enforcement layer |
| — | security.guidance | Gryph-only: advisory layer |
| — | privacy.sensitive | Gryph-only: compliance layer |
| prompt, response, thinking | — | Claude-only: hooks don't see conversation |
| context.truncated | — | Claude-only: internal to runtime |
| agent.spawn | subagent.start | Parallel — gryph observes via SubagentStart hook + inline agent_id |
| agent.result | subagent.stop | Parallel — gryph captures transcript path + last message |