Skip to main content
Beekeeper Docs

Audit Log

Query, export, and understand Beekeeper's NDJSON decision log.

Every decision Beekeeper makes (allow, warn, block, quarantine, posture override, and config change) is appended to an NDJSON audit log. Each line is a single JSON object.

A separate, opt-in corpus log records confirmed incidents for the local first-responder loop. It is a different file (corpus/beekeeper-corpus.ndjson), also append-only and owner-only and written through the same redaction step. It carries a richer four-layer record (behavior, decision, outcome, context) in the frozen push-envelope shape rather than the flat decision record described here, and it never leaves the machine. See Security and Configuration.

Location

OSAudit log
Linux / macOS~/.beekeeper/audit/beekeeper.ndjson
Windows%APPDATA%\beekeeper\audit\beekeeper.ndjson

The log is a single beekeeper.ndjson file with owner-only permissions (0600), written append-only. The shipped binary does not rotate or compress the audit log; there are no dated per-day files. Query it with the beekeeper audit subcommands below rather than reading dated files directly.

Reading the log

beekeeper audit tail   # stream live decisions (Ctrl+C to stop)
beekeeper audit tail --no-follow   # dump existing records and exit

To browse the same records interactively, with one color-coded row per decision and an expandable per-record view of the full decision logic (corroboration sources, catalog matches, rules, posture overrides, and Sentry evidence), open the TUI Dashboard and run audit tail from the command palette.

Querying

beekeeper audit query --since 24h --decision block --limit 50
beekeeper audit query --since 2026-06-01T00:00:00Z --agent claude-code --tool Bash
  • --since accepts a Go duration (24h, 168h) or an RFC3339 timestamp
  • --agent, --tool, --decision (allow | warn | block), and --limit filter the results

Exporting

beekeeper audit export --format ndjson
beekeeper audit export --format csv --since 7d
beekeeper audit export --format otlp

--format is required and accepts ndjson, csv, or otlp. The same --since / --agent / --tool / --decision filters apply.

Posture override records

A scoped install-posture override (beekeeper posture allow / enforce, see the CLI Reference) writes a distinct record_type:"posture_override" record with these key fields:

FieldDescription
posture_override_actionallow_once | allow_always | enforce_block | enforce_warn
posture_packagethe package an allow override exempts (empty for an enforce)
posture_ecosystemthe ecosystem the override is scoped to (empty matches any)
posture_rulethe rule scope: release-age, lifecycle, git-remote, or empty (all rules)
reasonthe operator-recorded justification (required for allow_always)

A posture allow is posture-scoped: it silences a posture warn for the package but never downgrades a catalog or corroboration malware block.

The Sentry layer also writes a sentry_install_observed record (SENTRY-009) when a monitored descendant spawns a package-manager install. It is detection-only (severity info); Sentry never blocks or quarantines. See Security.

The nudge record type that earlier versions produced is no longer written as of v1.1.0 (the package-manager nudge was removed). The deprecated nudge_* fields are retained unpopulated for corpus schema compatibility only.

Record types

Each line carries a record_type. The shipped binary writes:

record_typeWritten by
policy_decisionThe beekeeper check hook and the MCP gateway: the allow/warn/block/quarantine decision for a tool call. This is the default record.
tool_resultThe PostToolUse hook (beekeeper audit-record): the outcome of a tool call that ran.
posture_overrideA scoped install-posture override from beekeeper posture allow / enforce (see above).
sentry_install_observedA Sentry install observation (SENTRY-009): a monitored descendant spawned a package-manager install. Detection-only.
sentry_alertA Sentry behavioral rule hit (detection-only).
llmf_alertA LlamaFirewall prompt-injection or unsafe-code scan result.
config_changeA beekeeper config set change.

The nudge and version_drift record types that earlier versions emitted are no longer written as of v1.1.0.

The decision field is one of allow, warn, block, or alert (alert marks a Sentry detection-only record). A quarantine carries quarantine: true alongside its decision.

Record examples

{"record_type":"policy_decision","decision":"block","tool_name":"Bash","reason":"corroborated: 2 sources flag this package","agent_name":"claude-code"}
{"record_type":"posture_override","posture_override_action":"allow_always","posture_package":"left-pad","posture_rule":"release-age","reason":"internal mirror"}
{"record_type":"sentry_install_observed","decision":"alert","severity":"info","reason":"package-manager install observed: npm"}

Remote sinks, rotation, and the redaction caveat

In this release the only active audit sink is the local file. It is owner-only (0600) and append-only.

The internal/audit package also implements remote syslog / OTLP / HTTPS sinks and size-based rotation, and the schema accepts an audit config block (sinks, syslog_address, otlp_endpoint, https_endpoint, max_size_bytes, retention_days). But no shipped code path wires them up: the live writer fans out to no remote sink and does not rotate, so setting those keys has no effect today. Treat shipping audit data off-host as something you do yourself by forwarding the file.

Redaction is field-scoped, not content-scanning. The decision Reason field and raw/rewritten package-manager commands are redacted, but Sentry-derived fields (accessed file paths, network destinations, process exe paths, correlated extension IDs) and catalog coordinates are written verbatim, and the behavioral-watch audit path does not route through RedactRecord at all. A credential embedded in a watched file path or network destination is therefore present in the on-disk log unscrubbed. The file is owner-only (0600); account for this before you forward the audit log off-host.

On this page