Skip to content
PrismaLens Docs

Commands

The prismalens binary (alias pl) has these subcommands:

prismalens <command> [flags] # alias: pl
investigate Run a read-only root-cause investigation of a firing alert.
listen Serve a token-authed local webhook receiver for Alertmanager.
status List past and running investigations.
report Print a stored report for one run.
serve Run the JSON-RPC 2.0 server over stdio (the live channel for apps).
doctor Preflight-check the investigation environment.
init Scaffold a prismalens.config.yaml in the current directory.

Available on the prismalens binary itself, before any subcommand:

  • --version, -v — print the installed PrismaLens version and exit.
  • --help, -h — print usage (top-level, or for a subcommand: pl investigate --help).

Flags are strict on every command: an option a command doesn’t declare is an error (Unknown option: --my-typo, exit 1), never silently ignored.

Seeds an investigation from a firing alert, rents a Tier-2 harness to gather evidence read-only, and renders the ordered-evidence report once the run resolves.

The seed alert comes from one of:

  • a FiringAlert JSON piped on stdin (also accepts a webhook/Alertmanager-shaped payload — alertname/severity are read from the top level, falling back to labels), or
  • --query — a one-line description the CLI synthesizes into a minimal alert.

If neither is given (no pipe, no --query), the run fails with a hard input error. If the stdin payload is present but isn’t valid JSON, it isn’t a hard error: the malformed input is logged as a warning and ignored, and the run proceeds from --query if one was given (and fails as “no seed alert” if not). Pair a pipe with --query when you can’t be sure the upstream payload is well-formed.

FlagTypeDefaultDescription
--repo <dir>stringcurrent directoryPath to the repository the harness investigates (its cwd).
--query, -q <text>stringSynthesize an alert from this one-line description (alternative to piping a FiringAlert JSON on stdin).
--config <path>stringPath to a prismalens.config.yaml (skips the upward config search; fails closed on missing/invalid files).
--max-turns <number>integeragent.max_turns in configMaximum number of turns (tool calls) the harness is allowed to make before being halted.
--model <id>stringOverride agent.model — a bare model id, e.g. gpt-oss:120b.
--harness <name>enum: deepagents | claude-codeagent.default in config (claude-code)Tier-2 harness backend. (codex is a reserved value but is planned, not yet available — selecting it throws.)
--mode <mode>enum: read-only | supervised | auto | dangerousagent.permissions.mode in config (read-only)Permission posture the harness runs under.
--dangerously-skip-permissionsbooleanfalseAlias for --mode dangerous. Wins over --mode when set.
--sandbox <mode>enum: auto | process | srt | e2bagent.sandbox in config (auto)Isolation boundary the harness runs in. auto uses srt (an enforced OS boundary) when its egress self-check passes, else the cooperative process floor — the degrade is logged, never silent. e2b is an explicit-only cloud/remote boundary that needs E2B_API_KEY.
--service <name>stringSelect the service context by name from services in config (overrides the alert’s service label).
--jsonbooleanfalsePrint the InvestigationReport as JSON to stdout (suppresses the human renderer and implies --quiet).
--output <file>stringAlso write the InvestigationReport JSON to this file.
--quietbooleanfalseSuppress progress and the human renderer (errors still go to stderr).

Both hero harnesses (claude-code and deepagents) run inside the isolation boundary: every investigation gets at least the always-on process floor, and srt/auto apply the enforced boundary when it’s available. See Sandboxing & permissions for what each boundary actually guarantees and how to read a run’s fidelity report.

  • 0 — the run produced a synthesized InvestigationReport.
  • 1 — a hard input error (no alert/query, an unbuilt harness, a sandbox mode a harness can’t honor), a mid-stream failure, or a no-evidence run (the harness branch gathered nothing and errored — the CLI reports the failure rather than fabricating a root cause).

Troubleshooting walks each exit-1 cause — including what a “no-evidence” run means — and the fix.

Terminal window
# Synthesized alert from a one-liner, deepagents harness, investigating ./my-service
prismalens investigate \
--repo ./my-service \
--query "p99 checkout latency tripled after 14:00 UTC" \
--harness deepagents
# Pipe a real FiringAlert (or webhook/Alertmanager-shaped) payload on stdin
cat alert.json | prismalens investigate --repo ./my-service
# Machine-readable report to stdout, a copy on disk, no progress chatter
prismalens investigate -q "OOMKilled in payments pod" --json --output report.json

Every run is persisted under workspace.base_dir (~/.prismalens by default) regardless of how it was invoked:

~/.prismalens/
prismalens.db # record store: runs, alert groups, events, and reports
runs/<runId>/ # per-run workspace dir the harness works in

Run metadata, the canonical event stream, and the synthesized report all live in prismalens.db — a WAL-mode SQLite database backed by Node’s built-in node:sqlite. Read a stored run back with status and report rather than parsing files by hand.

--json, --output, and pl report all emit the same InvestigationReport object. Its fields:

FieldTypeWhat it is
summarystringA one-line synopsis of the investigation.
rootCausestring | nullThe identified root cause, or null when not determined — never fabricated.
rootCauseCategorystring | nullA coarse category for the root cause, when one was classified.
hypothesesarrayOrdered most → least plausible (array position is the ranking — no numeric score). Each: { statement, status, evidence[] }.
ruledOutarrayCandidate causes eliminated: { statement, why, evidence[] }.
coverageobject{ queried[], notQueried[] } — what was and wasn’t checked.
nextStepsarrayRecommended follow-ups: { title, detail, priority? }.
fidelityobject | nullThe honest run-fidelity record — { harness, mode, fidelity, mechanism, sandbox? } — of the boundary that actually applied. See Sandboxing → the fidelity report.

Each evidence entry is { observation, source, direction, status, toolCallId? }source is the exact command or origin that produced the observation, and direction records whether it supports or contradicts the hypothesis. Ordering and the no-numeric-score rule are explained in Ordered evidence.

Starts a token-authed local HTTP receiver that turns firing Alertmanager alerts into investigations, unattended. Each firing alert runs the same seam chain as investigate — config, repo, and sandbox resolved per payload, so config edits apply to the next webhook without a restart.

Terminal window
pl listen
FlagTypeDefaultDescription
--config <path>stringPath to a prismalens.config.yaml (else the global→project search).

listen refuses to start unless listen.token is configured — an open intake is not a mode. It binds 127.0.0.1 only and serves one route, POST /webhooks/alertmanager. Every request must present the shared bearer token or it gets 401. The full setup — the Alertmanager webhook_config, the grouping and budget behavior, and Slack delivery — is in Unattended alerts; every listen.* config key is enumerated in Configuration.

Responses on the wire:

StatusMeaning
202Payload accepted; body reports received and accepted (firing) counts.
400Body isn’t valid JSON, or isn’t a well-formed Alertmanager payload (the validation reason is included).
401Missing or wrong bearer token.
404Wrong path — only /webhooks/alertmanager is served.
413Request body over 5 MB.
503Intake queue full — Alertmanager’s durable retry absorbs the backpressure.

Lists investigation runs — recent grouping/investigation activity plus whatever is running now — reading straight from prismalens.db.

Terminal window
pl status
pl status --status errored,suppressed
FlagTypeDefaultDescription
--status <list>stringComma-separated filter over running, done, errored, suppressed. An unknown value exits 1.
--base-dir <dir>string~/.prismalensWorkspace whose record store to read.

Each run prints one line of key: value fields:

run_id: <id> | status: <state> | created_at: <iso-8601> | alertname: <name> | agent: <harness> | repo: <owner/name>

alertname, agent, and repo appear only when recorded. A suppressed run (one a budget cap turned away) also carries suppressed_by: <cap>. With no runs, status prints No runs found.

Prints one stored InvestigationReport as JSON, by run id.

Terminal window
pl report <runId>
pl report <runId> --events
FlagTypeDefaultDescription
id (positional)stringThe run id, as shown by pl status. Required.
--eventsbooleanfalseAlso print the run’s canonical event timeline, one JSON event per line, under a --- Timeline Events --- header.
--base-dir <dir>string~/.prismalensWorkspace whose record store to read.

report and status are the read side of what a run produces: investigate and listen write runs into prismalens.db; status lists them and report prints one back. If there’s no stored report for the id, report prints an error and exits 1.

Runs a JSON-RPC 2.0 server over stdio, newline-delimited in both directions — one JSON value per line, requests on stdin, responses and notifications on stdout. This is the live channel a driving app (the desktop app, the web API) uses instead of shelling out to investigate per run. No flags.

The ~/.prismalens/runs/<runId>/ workspace is still written for every run, exactly as the investigate command writes it.

--> {"jsonrpc":"2.0","id":1,"method":"initialize"}
<-- {"jsonrpc":"2.0","id":1,"result":{
"protocolVersion": 1,
"serverInfo": { "name": "prismalens", "version": "" } // the installed prismalens version
}}

params:

FieldTypeNotes
alertobjectA FiringAlert (or webhook-shaped payload), same as stdin for the CLI command.
querystringAlternative to alert — synthesizes an alert from a one-line description.
repostringRepository path (defaults to the server’s cwd).
harnessstringdeepagents | claude-code. (codex is planned, not yet available.)
modelstringBare model id override.
configstringPath to a prismalens.config.yaml.
servicestringService name from services in config.
modestringPermission posture: read-only | supervised | auto | dangerous.
dangerouslySkipPermissionsbooleanAlias for mode: "dangerous". Wins over mode.

Streams a notification per canonical event (including the terminal report event), then resolves the request with { runId, report }:

--> {"jsonrpc":"2.0","id":2,"method":"investigate",
"params":{"query":"checkout latency spike","repo":"./my-service","harness":"deepagents"}}
// zero or more notifications, in order, as the supervisor streams:
<-- {"jsonrpc":"2.0","method":"investigate/event",
"params":{"runId":"<uuid>","event":{ /* CanonicalEvent */ }}}
// ... agent_step, tool_result, branch_done, (error), then the terminal report event ...
// finally, the request resolves:
<-- {"jsonrpc":"2.0","id":2,"result":{"runId":"<uuid>","report":{ /* InvestigationReport */ }}}

CanonicalEvent.kind is one of agent_step | tool_result | branch_done | error | report. Requests are fire-and-forget on the wire — multiple can run concurrently and interleave their notifications; each notification carries its runId so a driver can demultiplex.

CodeMeaning
-32700Parse error — invalid JSON on a line.
-32600Invalid request — not a well-formed JSON-RPC 2.0 request.
-32601Method not found.
-32602Invalid params — includes input errors from resolving the investigation (no alert/query, an unknown or unbuilt harness).
-32603Internal error — a mid-stream failure; data carries { runId }.
-32000No evidence — the harness branch failed and produced no report; data carries { runId }.

A malformed or failed request always becomes a JSON-RPC error response — the server never crashes on bad input.

Preflight checklist that gates a run. Prints pass/fail per check, then exits non-zero iff a hard check fails.

FlagTypeDefaultDescription
--no-pingbooleanfalseSkip the live model credential ping (avoids network egress to the provider).
CheckHard/SoftWhat it verifies
Harness binaryHardThe binary for the configured harness (agent.default) is on PATH: deepagentsdeepagents-acp, claude-codeclaude.
LLM credentialHardThe resolved synthesis provider and credential source (env vs _FILE). Live-pings the model (~1 token, creating network egress to the provider) unless --no-ping is set. A broken credential or missing file causes a hard, red failure naming the source. The canonical list of credentials lives in Providers & API keys.
WorkspaceSoftworkspace.base_dir can be created and is writable.
Listen tokenSoftWhether listen.token is set — only pl listen needs it, so an unset token is a notice, not a failure.
Terminal window
prismalens doctor

A hard failure prints as an error, a soft failure as a warning, and the process exits 1 only when at least one hard check failed — so doctor is also a reasonable CI smoke check.

Scaffolds a commented prismalens.config.yaml in the current directory, sourced directly from the config schema’s defaults so it can’t drift from what the engine actually uses. No flags.

Terminal window
prismalens init

Non-interactive: if prismalens.config.yaml already exists in the current directory, init prints a notice and leaves it untouched — it never overwrites.

The scaffold includes commented sections for agent (harness + model), telemetry (Prometheus/Alertmanager/API URLs), and workspace.base_dir, with live defaults filled in and everything else left commented as a hint.

  • Providers — set up a model provider and harness binary.
  • Configuration — the full prismalens.config.yaml reference and BYO-key environment variables.