Skip to content

Configuration

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.

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.

Either environment variable disables reporting at runtime, overriding the enabled option:

  • PROBLEMS_REPORTING is off, 0, or false
  • DO_NOT_TRACK is set to any truthy value (respecting the DNT convention)

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);

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.

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.

Most integrations do not need custom filtering. For application-specific rules, see optional filtering and sanitization.