Skip to main content

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 DISABLED is printed first, above the daemon block — a switched-off agent looks identical to a healthy one everywhere else.
  • policy … source embedded with an ENFORCING: 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 … queued comes 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?"}
Monitor mode records what it sees

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

PlatformCommand
Linuxjournalctl -u lumen-agent -f
macOStail -f /var/log/lumen/agent.err.log
WindowsGet-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.