Crash Reporting
Companion Intelligence apps can send crash reports to Sentry so the team can find and fix bugs. This page describes exactly what is sent, what is stripped before sending, and how to turn it off.
The short version
| Default | How to turn it off | |
|---|---|---|
| First-party apps (Companion Memory, Planning, Hermes, OpenClaw, Spellbook, and the WebXR apps) | On | The Share crash reports switch in the app’s install or settings form in the app store |
| Companion Hub itself | On | Allow anonymous error monitoring in Settings → General settings, or see Companion Hub below |
Crash reporting is opt-out: it is on unless you turn it off.
One thing worth understanding, because it is easy to misread: an app only reports if it was built with a reporting address (a Sentry DSN). Release images are. If you build an app yourself from source without one, it initialises no reporting code at all and makes no outbound connection — but that is the absence of configuration, not a privacy setting you have chosen.
What is sent
Only errors — an exception, where it happened, and a short trail of recent activity. No usage analytics, no page views, no metrics, no session recording.
The whole path, from an exception in a first-party app to the Sentry project only the team can read:
flowchart TD
Q{"Error in a first-party app.<br/>Reporting on?<br/>DSN built in, switch on,<br/>not CI_TELEMETRY=off,<br/>not CI_LOCAL_ONLY=true"}
Q -->|"no"| N["Nothing leaves your machine"]
Q -->|"yes"| S["Scrubber removes credentials, username,<br/>email, hostname, home paths, URL queries,<br/>request bodies, cookies, captured variables"]
S -->|"over 8 KB: truncated"| T["Report: exception, file and function name,<br/>recent activity, app version, OS, browser, timezone"]
T --> Y["Sentry, companion-intelligence org — team only"]Before anything leaves your machine it passes through a scrubber that removes:
- Credentials — API keys, passwords, bearer tokens, session cookies, Tailscale keys, and usernames and passwords embedded in database connection strings
- Your identity — your username, email address, and the identity headers the appliance passes between its own services. Your machine’s hostname is removed too, since it usually contains your name
- File paths — your home directory is collapsed to
~, so/Users/yourname/…never leaves the machine - Search terms and URLs — the query part of every web address is stripped. On Companion Memory a search URL contains what you searched your own memories for, so this matters more here than in most software
- Request bodies and cookies — dropped entirely
- Captured variables and source lines around the error, which can contain the content being processed at the time
Anything longer than 8 KB is truncated, so a large document cannot be smuggled out inside an error message.
What is not stripped
Being straight about the limits:
- The name of the file and function where the error happened. This is our code, not your data, and Sentry needs it to group reports.
- Your timezone, which the Sentry SDK attaches by default.
- The app version, operating system and browser.
- Free text you typed that ends up inside an error message can survive if it looks like ordinary prose — no automated filter reliably recognises a sentence as private. The scrubber removes the categories above by pattern, not by meaning.
Turning it off
Three controls apply to first-party apps, in order of precedence. Companion Hub has its own switch, described in Companion Hub.
1. The app-store switch
Each first-party app has a Share crash reports switch in its settings. Turning it off stops that app reporting, immediately and permanently, even though the app image ships with a reporting address built in.
2. CI_TELEMETRY=off
If you run apps yourself, set CI_TELEMETRY to off (or false, 0, no, disabled) in
the app’s environment. This is what the switch above sets, and it overrides a reporting
address baked into the image — you never need to rebuild anything to stop reporting.
3. CI_LOCAL_ONLY=true
Local-only mode means zero phone-home and beats every other setting, crash reporting included.
# Either of these stops reporting for a self-hosted app
CI_TELEMETRY=off
CI_LOCAL_ONLY=trueA limitation on the browser apps
Some apps are static web pages with no server of their own — the WebXR apps and Spellbook. When these run inside Companion Hub, the switch reaches them normally. When one is deployed straight to a static host such as Cloudflare Pages, there is no server to ask, so the in-browser opt-out is stored in your browser’s local storage instead. Clearing site data resets it.
Companion Hub
Hub reports crashes to Sentry in the published builds: the reporting address is compiled into the Hub image and the desktop app. A Hub you build yourself without one reports nothing. The cihub CLI never reports.
Hub checks its switches at the moment it sends each report, not only when it starts, so a change takes effect on the next error without a restart. Highest precedence first:
| Switch | Where | Effect |
|---|---|---|
| CI_LOCAL_ONLY=true | Hub's env file | Nothing leaves this machine, for any reason |
| CI_TELEMETRY=off | Hub's env file | No error reporting; other features unaffected |
| Allow anonymous error monitoring | Settings → General settings (allowErrorMonitoring in state/settings.json) | Turns reporting on or off for this Hub |
| No reporting address | The build | Nothing to send to |
The two environment variables override the Settings switch, so a machine owner’s choice cannot be undone from the dashboard. Hub answers GET /api/config/telemetry with { "enabled": ..., "reason": ... } so you can check what is in force. The route needs no sign-in and never returns the reporting address.
Reads fail closed. If Hub cannot read or parse state/settings.json, it stops reporting instead of guessing. A missing file is different: on a fresh Hub that has never been configured, reporting takes its default of on.
The desktop app reads the same state/settings.json, so the Settings switch and the environment variables apply to it as well.
What Hub sends
Hub runs its own scrubber on every event. It removes credentials, home-directory paths, cookies, request bodies, identity headers, and the host name before anything is sent. Hub also switches off the optional data collection in Sentry’s SDK (user information, cookies, request headers and bodies, and URL query strings), so visitors’ IP addresses are not stored.
What a Hub crash report contains:
- The exception type, message, and stack trace
- Your device ID, organization ID, and device slug
- The CI Cloud address, the Hub image tag, and the release
- Browser errors and performance traces from the dashboard
- When an app fails: the app’s URN and its recent container logs
What it leaves out:
- Cookies and request bodies
- Identity headers and session tokens
- The machine’s host name and the visitor’s IP address
- The data your apps hold
Container logs are the sharpest edge. Hub scrubs them for known secret shapes, but a log line that prints a bare credential in an unrecognized format can survive. If your apps log secrets, turn error reporting off.
The dashboard can also record masked session replays: all text is masked and all media is blocked. Hub starts the recorder only after consent, and it stops the recorder mid-session if you withdraw consent.
Local history that never leaves
Separately from crash reports, Hub samples CPU, memory, and disk every five seconds and keeps 48 hours of history in its own database to draw the dashboard’s graphs. It has no network egress, so none of the switches above apply to it. The history includes the host machine’s Docker name, and Settings → Logs can bundle it into a support download, so check a bundle before you attach it to a public issue.
The SENTRY_DSN variables are listed under Error monitoring (Sentry) on the environment variables page.
Where reports go
Reports go to the companion-intelligence organisation on Sentry, which only the Companion
Intelligence team can read. They are not shared with third parties or used for advertising,
profiling, or any purpose other than diagnosing faults.