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.Global flags
Section titled “Global flags”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.
investigate
Section titled “investigate”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
FiringAlertJSON piped on stdin (also accepts a webhook/Alertmanager-shaped payload —alertname/severityare read from the top level, falling back tolabels), 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.
| Flag | Type | Default | Description |
|---|---|---|---|
--repo <dir> | string | current directory | Path to the repository the harness investigates (its cwd). |
--query, -q <text> | string | — | Synthesize an alert from this one-line description (alternative to piping a FiringAlert JSON on stdin). |
--config <path> | string | — | Path to a prismalens.config.yaml (skips the upward config search; fails closed on missing/invalid files). |
--max-turns <number> | integer | agent.max_turns in config | Maximum number of turns (tool calls) the harness is allowed to make before being halted. |
--model <id> | string | — | Override agent.model — a bare model id, e.g. gpt-oss:120b. |
--harness <name> | enum: deepagents | claude-code | agent.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 | dangerous | agent.permissions.mode in config (read-only) | Permission posture the harness runs under. |
--dangerously-skip-permissions | boolean | false | Alias for --mode dangerous. Wins over --mode when set. |
--sandbox <mode> | enum: auto | process | srt | e2b | agent.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> | string | — | Select the service context by name from services in config (overrides the alert’s service label). |
--json | boolean | false | Print the InvestigationReport as JSON to stdout (suppresses the human renderer and implies --quiet). |
--output <file> | string | — | Also write the InvestigationReport JSON to this file. |
--quiet | boolean | false | Suppress 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.
Exit codes
Section titled “Exit codes”0— the run produced a synthesizedInvestigationReport.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.
Examples
Section titled “Examples”# Synthesized alert from a one-liner, deepagents harness, investigating ./my-serviceprismalens 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 stdincat alert.json | prismalens investigate --repo ./my-service
# Machine-readable report to stdout, a copy on disk, no progress chatterprismalens investigate -q "OOMKilled in payments pod" --json --output report.jsonEvery 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 inRun 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.
Output shape
Section titled “Output shape”--json, --output, and pl report all emit the same
InvestigationReport object. Its fields:
| Field | Type | What it is |
|---|---|---|
summary | string | A one-line synopsis of the investigation. |
rootCause | string | null | The identified root cause, or null when not determined — never fabricated. |
rootCauseCategory | string | null | A coarse category for the root cause, when one was classified. |
hypotheses | array | Ordered most → least plausible (array position is the ranking — no numeric score). Each: { statement, status, evidence[] }. |
ruledOut | array | Candidate causes eliminated: { statement, why, evidence[] }. |
coverage | object | { queried[], notQueried[] } — what was and wasn’t checked. |
nextSteps | array | Recommended follow-ups: { title, detail, priority? }. |
fidelity | object | null | The 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.
listen
Section titled “listen”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.
pl listen| Flag | Type | Default | Description |
|---|---|---|---|
--config <path> | string | — | Path 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:
| Status | Meaning |
|---|---|
202 | Payload accepted; body reports received and accepted (firing) counts. |
400 | Body isn’t valid JSON, or isn’t a well-formed Alertmanager payload (the validation reason is included). |
401 | Missing or wrong bearer token. |
404 | Wrong path — only /webhooks/alertmanager is served. |
413 | Request body over 5 MB. |
503 | Intake queue full — Alertmanager’s durable retry absorbs the backpressure. |
status
Section titled “status”Lists investigation runs — recent grouping/investigation activity plus whatever
is running now — reading straight from prismalens.db.
pl statuspl status --status errored,suppressed| Flag | Type | Default | Description |
|---|---|---|---|
--status <list> | string | — | Comma-separated filter over running, done, errored, suppressed. An unknown value exits 1. |
--base-dir <dir> | string | ~/.prismalens | Workspace 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.
report
Section titled “report”Prints one stored InvestigationReport as JSON, by run id.
pl report <runId>pl report <runId> --events| Flag | Type | Default | Description |
|---|---|---|---|
id (positional) | string | — | The run id, as shown by pl status. Required. |
--events | boolean | false | Also print the run’s canonical event timeline, one JSON event per line, under a --- Timeline Events --- header. |
--base-dir <dir> | string | ~/.prismalens | Workspace 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.
initialize
Section titled “initialize”--> {"jsonrpc":"2.0","id":1,"method":"initialize"}<-- {"jsonrpc":"2.0","id":1,"result":{ "protocolVersion": 1, "serverInfo": { "name": "prismalens", "version": "…" } // the installed prismalens version }}investigate
Section titled “investigate”params:
| Field | Type | Notes |
|---|---|---|
alert | object | A FiringAlert (or webhook-shaped payload), same as stdin for the CLI command. |
query | string | Alternative to alert — synthesizes an alert from a one-line description. |
repo | string | Repository path (defaults to the server’s cwd). |
harness | string | deepagents | claude-code. (codex is planned, not yet available.) |
model | string | Bare model id override. |
config | string | Path to a prismalens.config.yaml. |
service | string | Service name from services in config. |
mode | string | Permission posture: read-only | supervised | auto | dangerous. |
dangerouslySkipPermissions | boolean | Alias 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.
Error codes
Section titled “Error codes”| Code | Meaning |
|---|---|
-32700 | Parse error — invalid JSON on a line. |
-32600 | Invalid request — not a well-formed JSON-RPC 2.0 request. |
-32601 | Method not found. |
-32602 | Invalid params — includes input errors from resolving the investigation (no alert/query, an unknown or unbuilt harness). |
-32603 | Internal error — a mid-stream failure; data carries { runId }. |
-32000 | No 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.
doctor
Section titled “doctor”Preflight checklist that gates a run. Prints pass/fail per check, then exits non-zero iff a hard check fails.
| Flag | Type | Default | Description |
|---|---|---|---|
--no-ping | boolean | false | Skip the live model credential ping (avoids network egress to the provider). |
| Check | Hard/Soft | What it verifies |
|---|---|---|
| Harness binary | Hard | The binary for the configured harness (agent.default) is on PATH: deepagents → deepagents-acp, claude-code → claude. |
| LLM credential | Hard | The 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. |
| Workspace | Soft | workspace.base_dir can be created and is writable. |
| Listen token | Soft | Whether listen.token is set — only pl listen needs it, so an unset token is a notice, not a failure. |
prismalens doctorA 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.
prismalens initNon-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.
Next steps
Section titled “Next steps”- Providers — set up a model provider and harness binary.
- Configuration — the full
prismalens.config.yamlreference and BYO-key environment variables.