Configuration
Options
Section titled “Options”Everything passed to createProblems(options):
| Option | Default | Meaning |
|---|---|---|
slug |
required | Your provider slug: the subdomain your surface lives at. |
endpoint |
https://<slug>.problems.dev/report |
Full URL override, if you’re not on the default host. |
toolName |
- | Identifies the reporting tool, e.g. "acme-cli@2.1.0". |
agentName |
- | Passed through to the report’s agentName. |
runtime |
node/<version> <platform> <arch> |
Runtime string; override if you have a better one. |
enabled |
true |
false disables reporting. The env opt-outs below always win. |
injectAnswers |
true |
MCP: append a matched fix to the failed tool result. |
mapToolError |
— | Opt-in exception-to-message callback for MCP answer injection; return undefined to preserve the throw. |
captureResponseBody |
true |
Capture a bounded prefix of failed HTTP response bodies. |
maxResponseBodyBytes |
4000 |
Maximum captured body bytes. |
responseBodyTimeoutMs |
100 |
Maximum body-read wait in milliseconds. |
captureClientErrors |
false |
wrapFetch: also report 4xx, not just 5xx/network. |
answerWaitMs |
server default: 6000 |
Model-work budget (0–6000ms); shorter waits may omit a known answer. Persistence and transport are separate; enrichment and notifications are queued. |
timeoutMs |
10000 |
Hard cap on a single report’s delivery. |
mode |
"auto" |
MCP reports use server limits; others use CLI limits. Override with "server" or "cli". |
maxReportsPerProcess |
CLI: 5; server: none |
Explicit lifetime cap per client, including server mode. |
maxReportsPerWindow |
5 |
Server attempts per rolling window. |
reportWindowMs |
60000 |
Server rolling window length. |
dedupeTtlMs |
60000 |
Successful report and answer cache lifetime. |
fetch |
globalThis.fetch |
Injection point for tests. |
Endpoint resolution
Section titled “Endpoint resolution”By default the SDK posts to https://<slug>.problems.dev/report. Set
PROBLEMS_HOST to change the host: the endpoint becomes
https://<slug>.<PROBLEMS_HOST>/report. Pass a full endpoint to override the
URL outright.
Opting out
Section titled “Opting out”Either environment variable disables reporting at runtime, overriding the
enabled option:
PROBLEMS_REPORTINGisoff,0, orfalseDO_NOT_TRACKis set to any truthy value (respecting the DNT convention)
Privacy & data
Section titled “Privacy & data”Errors only. No usage telemetry, analytics, or session tracking.
A report contains the error message and stack, the failing tool or command name,
argument names (not directly collected values), the toolName, and the Node version and platform.
It also includes anything you add explicitly (goal, versions, attempted).
Error text and captured HTTP bodies can still contain argument values or other user data. Pattern-based redaction cannot guarantee removal of all sensitive content.
The SDK scrubs recognized secret patterns before sending: bearer tokens, JWTs, sk-/sk-ant- keys,
gh*_ tokens, AWS AKIA…, Slack xox…, and api_key=/secret: assignments
become [REDACTED]. The server re-redacts as a backstop. Run the same scrubber
yourself:
import { redactSecrets } from "@problemsdev/sdk";
// text has matched secrets replaced with [REDACTED]; secretsFlagged is true if any matched.const { text, secretsFlagged } = redactSecrets(untrusted);Delivery limits
Section titled “Delivery limits”CLI reports default to five attempts per client lifetime. MCP reports default to five attempts per rolling minute. Set mode: "server" for long-running tools whose fetch wrappers or process hooks also report. An explicit maxReportsPerProcess adds a lifetime cap in either mode.
A 429 pauses delivery according to Retry-After, with a one-minute fallback for missing or invalid headers. There are no automatic retries; later report calls can attempt delivery again within these limits.
Successful reports are cached for dedupeTtlMs, up to 100 entries. A cached answer returns with cached: true without another submission, even when delivery is capped. Cached reports without answers return duplicate. Concurrent identical reports share delivery; failed deliveries are not cached.
Awaited reporting and answer injection can delay failed calls by up to timeoutMs (ten seconds by default). HTTP error-body capture is limited to maxResponseBodyBytes bytes and responseBodyTimeoutMs milliseconds (defaults: 4,000 bytes and 100ms). Set captureResponseBody: false to skip it. Successful tool calls do not await reporting, and report() never rejects.
Intake latency
Section titled “Intake latency”The server waits for answer matching within a six-second default budget; retries share that budget. It commits the report and background jobs before returning a successful response. Enrichment and provider notifications run through a durable queue, so neither holds the report response open.
Set answerWaitMs to request a shorter matching budget. Zero skips inline model
work, so a newly submitted report returns without a matched answer; queued
enrichment still runs later. Matching that exceeds the budget is not retried in
the background. Shorter waits therefore trade answer availability for latency.
timeoutMs still bounds SDK delivery. Leave room above answerWaitMs for database
writes and network transport. The matching budget does not guarantee total
response latency.
Advanced options
Section titled “Advanced options”Most integrations do not need custom filtering. For application-specific rules, see optional filtering and sanitization.