You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Two related improvements to make the CLI a better citizen in orchestrated environments (the Tessera dossier agent, but also any other downstream consumer that wants to validate setup before invoking the CLI for real).
Part 1 — --health subcommand
Problem
Today, the only way to verify the CLI is correctly configured (binary present + valid *_API_KEY exported + provider reachable) is to issue a real query. That:
Burns budget on the operator's account.
Returns a result-shaped envelope, so callers have to special-case "this was a probe, not a real search."
Doesn't give a binary go/no-go signal — the caller must inspect content to infer whether auth worked.
Proposal
Add a perplexity --health (or perplexity health) subcommand whose contract is:
Make the smallest possible authenticated call against the provider's API. For most providers, this is a GET /me / GET /v1/models / equivalent ping that returns a tiny, billing-free response. If the provider has no free probe, use the cheapest possible search with n=1 against a fixed canary query.
Exit 0 if and only if the call returned a successful response (i.e. the API accepted the key and returned valid output).
Exit non-zero on any failure: missing env var, HTTP 401/403, network unreachable, malformed response. Stderr should give a one-line diagnosis (missing $XXX_API_KEY / HTTP 401: invalid_api_key / connection refused / etc.).
Stdout: optionally a tiny JSON envelope {"schema_version":"1","provider":"...","command":"health","status":"ok","elapsed_ms":N} so machine-readable consumers don't have to parse stderr. Empty stdout is also acceptable; the exit code is the contract.
Why it matters
The Tessera dossier agent's /tools pre-flight panel (sapihav/tessera#38) currently shows three states per CLI: ok (binary present + env var set), missing_key (binary present, env var unset), not_installed. There's a fourth state — key_invalid (binary present, env var set, but value is wrong/expired/rate-limited) — that today silently degrades to ok and the operator only finds out by running a dossier and seeing a 401. With --health, the panel can show key_invalid truthfully.
It's also useful for the dossier skill itself (sapihav/osint-dossier Phase 0) to validate before fanning out — see sapihav/osint-dossier#3.
Done when
perplexity --health exists and follows the contract above.
README documents the subcommand and its exit codes.
The probe call's billing impact is documented (e.g. "uses GET /v1/models, no usage charge" or "uses 1 cheapest-tier search").
Part 2 — Exit non-zero on auth failure
Problem (concrete)
A direct shell probe in the Tessera production container, against a host where perplexity_API_KEY is set to an empty string (operator never bought provider credits, so the env var was set to ""):
$ perplexity search "test query"
error: perplexity API returned HTTP 401: {"error":{"message":"Invalid API key provided. ...",
"type":"invalid_api_key","code":401}}
$ echo $?
0
The CLI prints the HTTP 401 to stdout and exits 0. Downstream code reading $? cannot distinguish a 401-failed call from a successful call. This is the immediate cause of two real downstream bugs in our stack:
Cost mis-attribution. Tessera's cost_tracking.py:tool_complete_handler falls through to the price-table fallback when no _cost envelope is found, and bills the per-call USD rate. So a 401 that never actually charged the provider's account gets attributed as a real cost in our portal. The operator sees fictional spend.
Both downstream bugs would still need their own fixes (Tessera should also gate on output shape, the skill should also validate envelope schema), but the cleanest place to detect auth failure is in the CLI itself — it's the layer that holds the HTTP response and knows what 401 means.
3 for network errors (connection refused, DNS, timeout)
4 for malformed response (provider returned non-JSON when JSON expected)
Error message goes to stderr, not stdout. Stdout stays reserved for the success envelope.
README documents the exit-code mapping next to the command list.
Why it matters
Same as Part 1 — orchestrators (the dossier skill, Tessera's cost tracker, anyone wrapping these CLIs) need a deterministic signal of success/failure that doesn't require parsing prose stderr. Exit code is the standard answer.
Done when
Auth failures (401, 403) exit non-zero.
Network failures exit non-zero.
Missing env var exits non-zero (don't even hit the API).
Error text goes to stderr, not stdout.
Success output (JSON envelope) goes to stdout, exit 0.
README has a "Exit codes" section.
Severity / scope
Medium — both parts. Currently masked because operators notice eventually (when a dossier turns up empty seed data or a fictional cost row), but the fix is small and gives every downstream consumer a clean, deterministic interface.
Environment of repro
CLI version: latest from install.sh as of 2026-05-04
Host: Tessera production container (Debian trixie-slim, Python 3.13, Node 22)
Trigger: perplexity_API_KEY="" (empty string) — common when an operator removes credits or never had any.
Add
--healthsubcommand + return non-zero exit code on auth failureTwo related improvements to make the CLI a better citizen in orchestrated environments (the Tessera dossier agent, but also any other downstream consumer that wants to validate setup before invoking the CLI for real).
Part 1 —
--healthsubcommandProblem
Today, the only way to verify the CLI is correctly configured (binary present + valid
*_API_KEYexported + provider reachable) is to issue a real query. That:Proposal
Add a
perplexity --health(orperplexity health) subcommand whose contract is:GET /me/GET /v1/models/ equivalent ping that returns a tiny, billing-free response. If the provider has no free probe, use the cheapest possible search withn=1against a fixed canary query.missing $XXX_API_KEY/HTTP 401: invalid_api_key/connection refused/ etc.).{"schema_version":"1","provider":"...","command":"health","status":"ok","elapsed_ms":N}so machine-readable consumers don't have to parse stderr. Empty stdout is also acceptable; the exit code is the contract.Why it matters
The Tessera dossier agent's
/toolspre-flight panel (sapihav/tessera#38) currently shows three states per CLI:ok(binary present + env var set),missing_key(binary present, env var unset),not_installed. There's a fourth state —key_invalid(binary present, env var set, but value is wrong/expired/rate-limited) — that today silently degrades tookand the operator only finds out by running a dossier and seeing a 401. With--health, the panel can showkey_invalidtruthfully.It's also useful for the dossier skill itself (sapihav/osint-dossier
Phase 0) to validate before fanning out — see sapihav/osint-dossier#3.Done when
perplexity --healthexists and follows the contract above.GET /v1/models, no usage charge" or "uses 1 cheapest-tier search").Part 2 — Exit non-zero on auth failure
Problem (concrete)
A direct shell probe in the Tessera production container, against a host where
perplexity_API_KEYis set to an empty string (operator never bought provider credits, so the env var was set to""):The CLI prints the HTTP 401 to stdout and exits 0. Downstream code reading
$?cannot distinguish a 401-failed call from a successful call. This is the immediate cause of two real downstream bugs in our stack:cost_tracking.py:tool_complete_handlerfalls through to the price-table fallback when no_costenvelope is found, and bills the per-call USD rate. So a 401 that never actually charged the provider's account gets attributed as a real cost in our portal. The operator sees fictional spend.first-volley.shmay treat exit-0 as "this CLI contributed seed data," then drop the unparseable error text downstream — see Phase 1 fan-out silently drops valid exa + tavily results — only jina reaches merged_from osint-dossier#3 for the full story.Both downstream bugs would still need their own fixes (Tessera should also gate on output shape, the skill should also validate envelope schema), but the cleanest place to detect auth failure is in the CLI itself — it's the layer that holds the HTTP response and knows what 401 means.
Proposal
1for any HTTP error (4xx, 5xx)2for missing/empty*_API_KEY3for network errors (connection refused, DNS, timeout)4for malformed response (provider returned non-JSON when JSON expected)Why it matters
Same as Part 1 — orchestrators (the dossier skill, Tessera's cost tracker, anyone wrapping these CLIs) need a deterministic signal of success/failure that doesn't require parsing prose stderr. Exit code is the standard answer.
Done when
Severity / scope
Medium — both parts. Currently masked because operators notice eventually (when a dossier turns up empty seed data or a fictional cost row), but the fix is small and gives every downstream consumer a clean, deterministic interface.
Environment of repro
install.shas of 2026-05-04perplexity_API_KEY=""(empty string) — common when an operator removes credits or never had any.