Audit Log JSON Schema
This page is the field-by-field reference for the JSON object produced by runok audit --json (one object per line, JSONL). Use it to write jq queries against audit logs without reading the runok source.
Top-Level Object
Section titled “Top-Level Object”Every line of runok audit --json output is one AuditEntry object with the fields listed below.
Example entry:
{ "timestamp": "2026-03-13T19:31:00.090565+00:00", "command": "git push -f origin main", "action": { "type": "deny", "detail": { "message": "force push is forbidden", "fix_suggestion": "git push origin main" } }, "sandbox_preset": null, "default_action": "ask", "metadata": { "endpoint_type": "hook", "session_id": "abc-123", "cwd": "/home/user/project", "tool_name": "Bash", "hook_event_name": "PreToolUse" }, "command_evaluations": [ { "command": "git push -f origin main", "action": { "type": "deny", "detail": { "message": "force push is forbidden", "fix_suggestion": "git push origin main" } }, "matched_rules": [ { "action_kind": "deny", "pattern": "git push -f|--force *", "matched_tokens": ["origin", "main"] } ], "eval_type": "primary", "argv": ["git", "push", "-f", "origin", "main"] } ]}timestamp
Section titled “timestamp”RFC 3339 timestamp in UTC, with sub-second precision and a +00:00 offset (e.g. 2026-03-13T19:31:00.090565+00:00), recording when the evaluation was performed. Note that the offset is written as +00:00, not Z — jq literal-string comparisons (select(.timestamp >= "...")) need to use the same form.
Type: str
Always present: Yes
command
Section titled “command”The input command string exactly as runok received it, before any shell parsing or compound-command splitting. For compound input this is the whole expression (a && b); for single input this is the same string as command_evaluations[0].command.
Type: str
Always present: Yes
action
Section titled “action”Final evaluation result for the input as a whole. For compound input, this is the aggregated decision across all branches (the strictest result wins: any deny makes the whole input deny, etc.). See Action Object for the shape.
Type: Action
Always present: Yes
sandbox_preset
Section titled “sandbox_preset”Name of the sandbox preset that was applied to this evaluation. null when no sandbox was applied or when multiple presets were merged (compound input where different branches matched different presets — the merged policy has no single canonical preset name). The preset name, when present, corresponds to a key under definitions.sandbox. See Sandbox merging for compound commands.
Type: str | null
Always present: Yes (may be null)
default_action
Section titled “default_action”The configured defaults.action value at the time of evaluation. null when no default was configured. See defaults.action for the possible values.
Type: "allow" | "ask" | "deny" | null
Always present: Yes (may be null)
metadata
Section titled “metadata”Session and context information about the invocation. See Metadata Object.
Type: Metadata
Always present: Yes
command_evaluations
Section titled “command_evaluations”Per-branch evaluation records, in source order. One entry per shell command extracted from command:
- A non-compound input (e.g.
git status) produces exactly one entry witheval_type: "primary". - A compound or pipelined input (e.g.
a && b,a || b,a ; b,a | b) produces one entry per branch, all witheval_type: "compound". - An input with no runnable command (comment-only, parse error) produces an empty array.
Each entry carries the rule-evaluation result (action, matched_rules) and the shell-level parse result (env, argv, redirects, pipe) side by side, so audit consumers can filter on the actual binary in one jq line:
runok audit --json | jq 'select(.command_evaluations[].argv[0] == "helmfile")'See CommandEvaluation Object for the shape of each entry.
Type: list[CommandEvaluation]
Always present: Yes (may be empty)
Action Object
Section titled “Action Object”Represents an evaluation result. The type field is a discriminator; detail is omitted for allow, and present (with type-specific keys) for deny and ask.
// allow{ "type": "allow" }
// deny{ "type": "deny", "detail": { "message": "force push is forbidden", "fix_suggestion": "git push origin main" }}
// ask{ "type": "ask", "detail": { "message": "are you sure?" } }When no rule matches, the configured default_action is applied directly: type is "allow", "deny", or "ask" accordingly. There is no separate "default" discriminator in the audit-log JSON.
The kind of action.
Type: "allow" | "deny" | "ask"
Always present: Yes
| Value | Meaning |
|---|---|
allow | The command is permitted. |
deny | The command is rejected. |
ask | The command requires user confirmation. |
detail.message
Section titled “detail.message”Optional message attached to the rule. For deny actions this is the rule’s message (see Denial Feedback); for ask actions this is the prompt shown to the user.
Type: str | null
Present when: type is deny or ask. The value may be null when the rule did not set message.
detail.fix_suggestion
Section titled “detail.fix_suggestion”Optional fix-suggestion attached to a deny rule. See Denial Feedback.
Type: str | null
Present when: type is deny. The value may be null when the rule did not set fix_suggestion.
Metadata Object
Section titled “Metadata Object”{ "endpoint_type": "hook", "session_id": "abc-123", "cwd": "/home/user/project", "tool_name": "Bash", "hook_event_name": "PreToolUse"}endpoint_type
Section titled “endpoint_type”Which runok subcommand recorded this entry. Audit consumers can use this to distinguish hook invocations from explicit runok exec runs.
Type: "exec" | "hook"
Always present: Yes
| Value | Source |
|---|---|
exec | The user invoked runok exec directly. |
hook | An AI coding agent’s tool-use hook (e.g. Claude Code PreToolUse) invoked runok. |
runok check is a dry-run evaluator and does not write audit log entries, so it never appears here.
session_id
Section titled “session_id”Session identifier supplied by the calling environment, when available. For hook invocations from Claude Code, this is the Claude Code session ID. null when no session ID was provided.
Type: str | null
Always present: Yes (may be null)
Working directory at the time of evaluation. null when the working directory could not be determined.
Type: str | null
Always present: Yes (may be null)
tool_name
Section titled “tool_name”Hook-specific: name of the tool the agent was about to run (e.g. Bash, Read). null when endpoint_type is not hook.
Type: str | null
Always present: Yes (may be null)
hook_event_name
Section titled “hook_event_name”Hook-specific: name of the hook event (e.g. PreToolUse). null when endpoint_type is not hook.
Type: str | null
Always present: Yes (may be null)
CommandEvaluation Object
Section titled “CommandEvaluation Object”One entry per shell command extracted from the input. Higher-level shaping (resolving binary vs subcommand, normalising mise shims, classifying -n as boolean vs value-taking) is intentionally not done here because those rules differ per CLI and belong to the audit consumer.
{ "command": "FOO=x echo hi > /tmp/log", "action": { "type": "allow" }, "eval_type": "compound", "env": [{ "name": "FOO", "value": "x" }], "argv": ["echo", "hi"], "redirects": [ { "redirect_type": "output", "operator": ">", "target": "/tmp/log", "descriptor": null } ], "pipe": { "stdin": false, "stdout": true }}command
Section titled “command”The branch command as runok extracted it, with redirects stripped but the inline env prefix kept. For eval_type: "primary" entries this is identical to the top-level command.
Type: str
Always present: Yes
action
Section titled “action”Rule-evaluation result for this branch. See Action Object.
Type: Action
Always present: Yes
matched_rules
Section titled “matched_rules”Rules that matched for this branch, in match order. See RuleMatch Object.
Type: list[RuleMatch]
Omitted when empty.
eval_type
Section titled “eval_type”How this branch was extracted from the input.
Type: "primary" | "compound"
Always present: Yes
| Value | Meaning |
|---|---|
primary | Non-compound input. The single entry covers the whole input. |
compound | One branch of a compound or pipelined input (a && b, a || b, a ; b, a | b, etc.). |
Inline KEY=VALUE env prefix attached to this branch. See EnvVar Object.
Type: list[EnvVar]
Omitted when empty.
Command name plus arguments, with shell quoting resolved. argv[0] is the binary as written. Empty (and therefore omitted) when shell parsing could not produce an argv (AST leaf-text fallback path).
Type: list[str]
Omitted when empty.
redirects
Section titled “redirects”Redirect operators attached to this branch. See Redirect Object.
Type: list[Redirect]
Omitted when empty.
Pipeline position of this branch. See Pipe Object.
Type: Pipe
Omitted when both stdin and stdout are false (i.e. the branch is not part of a pipeline).
RuleMatch Object
Section titled “RuleMatch Object”{ "action_kind": "deny", "pattern": "git push -f|--force *", "matched_tokens": ["origin", "main"]}action_kind
Section titled “action_kind”The kind of rule that matched.
Type: "allow" | "ask" | "deny"
Always present: Yes
pattern
Section titled “pattern”The rule pattern string as written in runok.yml. See Pattern Syntax.
Type: str
Always present: Yes
matched_tokens
Section titled “matched_tokens”Tokens the wildcard portion of the pattern captured. For example, the pattern git push -f|--force * matched against git push -f origin main yields ["origin", "main"]. Empty for patterns with no wildcards.
Type: list[str]
Always present: Yes (may be empty)
EnvVar Object
Section titled “EnvVar Object”{ "name": "FOO", "value": "x" }Variable name.
Type: str
Always present: Yes
Variable value with shell quotes resolved. null for the bare KEY= cmd form (which clears the variable in the child process’s environment).
Type: str | null
Always present: Yes (may be null)
Redirect Object
Section titled “Redirect Object”Captures redirect operators (> file, 2>&1, <<< here-strings, << here-docs, etc.). The here-doc delimiter and body are not captured — only the operator itself.
{ "redirect_type": "output", "operator": ">", "target": "/tmp/log", "descriptor": null}redirect_type
Section titled “redirect_type”Redirect category.
Type: "input" | "output" | "dup"
Always present: Yes
| Value | Examples |
|---|---|
input | <file, <<EOF, <<-EOF, <<<"string" |
output | >file, >>file, &>file |
dup | 2>&1, >&2 (file-descriptor duplication) |
operator
Section titled “operator”The redirect operator text.
Type: str
Always present: Yes
target
Section titled “target”Redirect target. A filename for file redirects, an fd reference like &1 for dup redirects, or an empty string for << / <<- here-docs (the delimiter is not captured).
Type: str
Always present: Yes (may be empty)
descriptor
Section titled “descriptor”Explicit file descriptor when the redirect specifies one (e.g. 2 in 2>file). null when the redirect uses the default fd (stdin for input, stdout for output).
Type: int | null
Always present: Yes (may be null)
Pipe Object
Section titled “Pipe Object”{ "stdin": true, "stdout": false }true when this branch’s stdin comes from a preceding pipe (i.e. there is a ... | this upstream).
Type: bool
Always present: Yes
stdout
Section titled “stdout”true when this branch’s stdout feeds a following pipe (i.e. there is a this | ... downstream).
Type: bool
Always present: Yes
Related
Section titled “Related”runok audit— The CLI command that produces this JSON.- Configuration Schema —
audit— How to configure audit logging. - Pattern Syntax — Syntax of the
patternstrings insidematched_rules.