- Case ID
- #5226
- Severity
- INFO
- Decision
- LOG
- Agent
- All Agents
- Category
- Governance
Correction note (2026-10-13). An earlier version of this article described Ed25519-signed records, a signed export bundle, a
verify-bundlecommand, gap detection, and an append-only log. Current ssg builds do not ship those features. This version describes what ssg ships today. The per-call timings and latency figures that appeared in this article had no benchmark behind them and were removed. Sample output in this article is illustrative, not a recorded run. The only published measurement is p50 0.39 ms and p99 1.91 ms (sigmashake-bench daemon-socket run, 2026-06-10, ssg 0.29.156, n=500). Sub-2 ms evaluation is a design target. The local audit log records decisions on a best-effort basis: entries can be dropped if the daemon queue is full, and old rows are deleted at the row caps. It is local, not append-only, and not immutable. The init adapter ids are claude-code and copilot, not claude or vscode.
The question audit solves
After an AI coding agent session, you can usually tell what changed: git diff shows the file edits, shell history shows some of the commands. But shell history is truncated, rewritten, and missing every tool call the agent made that did not go through a shell. File reads, MCP tool calls, web searches -- none of these appear in history. And no standard tool links a file edit to the agent decision that caused it.
The question "what exactly did the agent do during that session, and in what order?" turns out to be surprisingly hard to answer without a purpose-built audit log.
SSG keeps one. Tool calls from governed agents are evaluated before they execute, and SSG records the decision, the matched rule, and the input in the audit log on a best-effort basis. Entries can be dropped if the daemon queue is full, and old rows are deleted at the row caps.
What the audit log records
For each tool call it records, SSG writes a record containing:
- Timestamp
- Tool name (bash, read_file, write_file, mcp:server/tool, etc.)
- Input (the command string, file path, or structured arguments; stored input is capped at 8 KB)
- Decision: ALLOW, DENY, ASK, FORCE, LOG, SHADOW
- Matched rule ID (empty for ALLOW when no rule matched)
- Session ID linking the call to a specific agent process
- Source and client name
The log is a local SQLite database stored at ~/.sigmashake/rules.db. It stays on your
machine. Cloud audit logs are available on the Enterprise plan only.
Reading the log
Search from the command line with ssg audit search:
# Everything from the last 24 hours
ssg audit search --since 24h
# All blocked (DENY) decisions in the last 7 days
ssg audit search --since 7d --decision block
# Every file read in the last 7 days
ssg audit search --since 7d --tool read_file
# Everything that mentions .env
ssg audit search --query ".env"
# A specific rule's history
ssg audit search --rule-id no-secret-read
# JSON output for downstream processing (200 results maximum per call)
ssg audit search --since 30d --limit 200 --json > agent-activity.json
The valid --decision values are allow, block, log, shadow, ask, and force.
You can also filter with --capability, --source, --client, and --until.
The dashboard (ssg serve) shows the same data in a browser with filterable columns.
A sample audit record
A session where the agent read source files, was blocked from reading a secret file, ran tests, and attempted a deployment that required approval:
# illustrative sample output
2026-06-16T14:20:01Z ALLOW read_file src/auth/middleware.ts
2026-06-16T14:20:04Z ALLOW read_file src/auth/session.ts
2026-06-16T14:20:09Z DENY read_file .env
rule: no-secret-read
2026-06-16T14:20:09Z ALLOW bash npm test
2026-06-16T14:20:41Z ALLOW write_file src/auth/middleware.ts
2026-06-16T14:21:03Z ALLOW bash npm test
2026-06-16T14:21:44Z ASK bash kubectl apply -f k8s/prod.yaml
rule: ask-before-deploy
This record answers several questions you might face later: Did the agent read any secret files? (Yes, it tried; SSG blocked it.) Did the deployment run automatically? (No, the rule asked for a decision first.) What files were modified? (src/auth/middleware.ts.)
Signatures and integrity
The audit table has a signature column, and ssg audit verify checks the Ed25519
signature of each row that has one. Current ssg builds write audit rows without a
signature, so ssg audit verify reports them as unsigned. Unsigned rows are not a
verify failure. Do not treat the local audit log as tamper-evident: anyone with write
access to the database file can change it.
ssg audit verify prints a report with the number of total rows, signed rows that verify,
signed rows that fail, and unsigned rows, then one result line. It exits with code 1 if any
signed row has an invalid signature. It cannot detect a removed row: there is no hash chain
and no gap or sequence check. It also reports a count of entries in a separate deletion log
at ~/.sigmashake/audit-deletions.log; that log tracks deletions and does not prevent them.
Questions a review can answer
The audit log can help a security review or a team audit find answers to questions such as:
- "Did any agent read production secrets during development?" --
ssg audit search --tool read_file --query ".env" - "Which tool calls did a rule block or ask about?" --
ssg audit search --rule-id ask-before-deploy - "What did the agent do during the incident window?" --
ssg audit search --since 2026-06-14T02:00:00Z --until 2026-06-14T04:00:00Z
The log records only tool calls that ssg governed. It has no record of commands that ran outside a governed session.
Exporting records for review
For internal security reviews, vendor assessments, and team audits, export the records for a specific period as JSON Lines (the default) or CSV. Export needs a paid license (see plans):
# Export the last 30 days as JSON Lines
ssg audit export --since 30d --out audit-2026-06.jsonl
# Export one session's denied calls as CSV
ssg audit export --session sess-123 --decision deny --format csv --out denies.csv
--since and --until accept an RFC 3339 time, a date, or a duration back from now
(90m, 24h, 7d). Secrets in the stored input are masked again on export, and with --out
the file is written with mode 0600. Signed export bundles are not available: an export
is a plain record of the log, not a signed bundle, so it does not carry a signature or
manifest hash that a reviewer can verify on its own.
Retention
The local audit log is limited by row count, not by days. A hard ceiling of 500,000 rows deletes the oldest rows first. A soft cap of 50,000 rows also deletes the oldest rows, but it never deletes a row that is less than 24 hours old.
Because the log deletes old rows, it is not append-only. To keep records, export the period you need with ssg audit export (plain JSON Lines or CSV files, not signed bundles) or copy the database file ~/.sigmashake/rules.db before the log reaches these limits. You can also write search results to a file with --json. Each search call returns 200 results at most.
Cloud audit logs are available on the Enterprise plan only. Pro and free plans do not sync audit rows to SigmaShake servers; their audit log stays on the local device.
What the audit log does not replace
The SSG audit log records what the agent attempted and what SSG decided. It does not replace your version control history (which records what actually changed in tracked files) or your shell history (which records commands you ran directly). The three together give a complete picture.
Get started
# macOS / Linux — free installer
curl -fsSL https://install.sigmashake.com | sh
# Windows (PowerShell)
# iwr -useb https://install.sigmashake.com/install.ps1 | iex
# Initialize in your project
ssg init --client=claude-code
# Start the daemon (the audit log is written by the daemon)
ssg daemon &
# After your first session, search the log
ssg audit search --since 24h
# Open the dashboard to browse the log visually
ssg serve
Links: Download · Docs · Playground · Hub