First findings
Start here: lumen-agent status
Before reading a single finding, ask the endpoint what it is doing:
lumen-agent status # exit 0 daemon answered, 3 daemon down, 1 no report
lumen-agent status --json | jq '.daemon.policy, .hooks[].policy_id, .warnings'
One screen answers the questions a security review asks: what policy is in force, is anything actually running, which supervisor would restart the daemon, where the proxy forwards to, which Claude Code guards are registered and what policy each of them enforces, and how deep the spool is.
Four lines are worth knowing about before you need them:
control DISABLEDis printed first, above the daemon block — a switched-off agent looks identical to a healthy one everywhere else.policy … source embeddedwith anENFORCING:line means the daemon is running the policy compiled into the binary, not your file — see Configuration.- A warning that the hook guard and the daemon are running different policies is the one to act on.
spool … queuedcomes from inside the daemon, never from opening the file.
Findings: one JSON object per interaction
Every inspection appends a line to /var/lib/lumen/findings.jsonl. What is
stored is the post-action text: once a rule redacts, the record holds the
placeholder and the span, never the raw value.
tail -f /var/lib/lumen/findings.jsonl | jq -c \
'{ts, stage, action: .action.effective, classes: [.detections[] | select(.matched) | .class], text}'
{"ts":"2026-07-27T16:41:02Z","stage":"input","action":"redact",
"classes":["sensitive_data"],
"text":"deploy fails with key [REDACTED:credentials], what should I check?"}
In monitor mode nothing is redacted, so the record holds the text as it was
seen — secrets included. The file you are collecting to tune thresholds
is itself sensitive. It is created 0600; treat it accordingly, and promote
pr_secrets to redact as soon as its false-positive rate looks acceptable.
Useful one-liners:
# What is being detected, ranked
jq -r '.detections[] | select(.matched) | .class' findings.jsonl | sort | uniq -c | sort -rn
# Everything that was blocked, and why
jq -r 'select(.action.effective=="block") | "\(.ts) \(.action.by_rule) \(.action.reason)"' findings.jsonl
# Which rule is doing the work (tuning before you enforce)
jq -r 'select(.action.effective!="log") | .action.by_rule' findings.jsonl | sort | uniq -c
Is it alive?
lumen-agent status # the whole picture, exit 3 if not
curl -s 127.0.0.1:7645/v1/health | jq # the liveness probe installers use
curl -s 127.0.0.1:7645/v1/policy | jq # which policy version is loaded
Service logs
| Platform | Command |
|---|---|
| Linux | journalctl -u lumen-agent -f |
| macOS | tail -f /var/log/lumen/agent.err.log |
| Windows | Get-EventLog -LogName Application -Source lumen-agent -Newest 20 |
What a healthy first run looks like
health: ok | version: v0.1.0 | policy: pol_packaged_monitor
verdict: log | the key is AKIAIOSFODNN7EXAMPLE
The credential coming back untouched is the expected first result, not a failure: the shipped policy is monitor mode. The agent saw it, classified it, and recorded it. Promote the rule and the same request changes answer within seconds, with no restart — see From monitor to enforce.