More
Privacy and security
dotpals runs entirely on your computer. It reads what your agents already write locally, keeps a history in a plain JSON file, and sends nothing anywhere, unless you turn on the one optional cloud feature: double-checking unclear test results with TypeSafe.
Nothing leaves your computer
- No telemetry, no analytics, no account. dotpals makes no network calls of its own, except to TypeSafe if you choose Cloud (Jev) to double-check test results (off by default). The pal, the notch and the dashboard load nothing from the internet.
- The bridge listens only on
127.0.0.1, so other machines on your network can't connect to it. - Usage limits are read from files on your computer (Codex's logs, and what Claude Code gives its status line), never fetched.
- The only downloads are the ones you start: installing dotpals from GitHub with npx, and Electron and the optional TypeSafe SDK from npm during setup. If you click Set up Laya (or run
dotpals laya), pip downloads Laya, PyTorch and their parts from PyPI, and Laya downloads its model from Hugging Face the first time it starts (with Hugging Face's telemetry turned off). Nothing about you or your code is sent to set it up.
This website is different from the app: its home page shows how many people have visited. Each browser is counted once, the first time it visits (remembered in its local storage), by a public counter at abacus.jasoncameron.dev that keeps only the number. No cookies, and nothing about you is sent. The app itself never counts anything.
What dotpals reads
| Source | Why | How to stop it |
|---|---|---|
| Claude Code hook events | The live feed and the pal's state. | Remove the plugin, or switch Claude Code off on the Agents page. |
Claude Code transcripts (~/.claude/projects) | History, sessions without the plugin, and context-window usage. | DOTPALS_CLAUDE_LOGS=0 |
Codex session logs (~/.codex/sessions) | Codex's activity, context window and usage limits. | DOTPALS_CODEX=0, or switch Codex off |
| Hook events from Cursor, Gemini CLI, OpenCode and Copilot CLI | Their activity, once you press Connect. | Disconnect, or switch the agent off |
| What Claude Code passes its status line | Your usage limits and context-window sizes, once you run dotpals statusline. Only those fields are saved. | dotpals statusline --off |
What dotpals stores
Everything is in ~/.dotpals (see Where files live).
history.jsonkeeps the activity feed so it survives restarts: your prompts, the agent's closing messages, tool calls, file paths, commands, diffs and command output, each clipped to a few thousand characters. It keeps 7 days by default (1 to 90 in Settings) and at most 5000 entries.config.jsonholds your settings.claude-limits.jsonholds Claude Code's usage percentages and reset times, the model's name and context-window sizes, and nothing from your conversations.statusline.jsonholds the status line you had before.
History holds what your agents did, including command output and diffs. If an agent printed a secret, it can end up in history.json too. Treat the file like your shell history.
To keep less:
- Keep history for fewer days, or turn it off, in Settings → History. With history off, activity is kept only in memory until dotpals closes.
- Clear removes everything dotpals recorded. Your agents' own logs aren't touched.
DOTPALS_HISTORY=0turns history off whatever the setting says.DOTPALS_HOMEmoves the folder.
What dotpals tells your agents
Nothing, unless you turn on Share with your agents in Settings. Then each Claude Code session gets a short note, as extra context you don't see in the chat, about what your other agents did in the same project in the last two hours: the files they changed, their test results, what they were asked, and whether they're still working. dotpals hands the note only to Claude Code, on your computer. From there it's part of the conversation, so Claude Code sends it to the model it uses, like everything else in its context. Leave the setting off if what one session was asked shouldn't reach another.
Double-checking test results
Double-check unclear test results is off by default. When it's on, it only looks at test runs dotpals couldn't call from their output, and it's shown a small part of them: the facts parsed from the output, the exit status, the command, the end of the output and the lines that look like failures (a few thousand characters at most). Clear results, and runs where no tests ran, are never sent.
- Off (the default): nothing is sent anywhere.
- Local (Laya): sent only to Laya's server on your own computer. The address must be
127.0.0.1,localhostor[::1], so nothing leaves your computer. dotpals still removes passwords, keys, emails and IP addresses first. When dotpals runs Laya for you, it listens only on127.0.0.1(Laya's own default is every network), so other machines can't reach it. - Cloud (Jev): sent to TypeSafe (
api.typesafe.ai) with your API key, through TypeSafe's official SDK. Before anything is sent, dotpals removes anything that looks like a password, key or token (private keys, cloud and API tokens,password=…lines, passwords in URLs, the API key itself), and replaces email addresses, IP addresses and your home folder's path. Patterns can't catch everything, such as a customer's name printed by a test, so leave it off for projects whose test output must not leave your computer. TypeSafe's own terms cover what happens to it there.
The answer (passed, failed or unclear, with its probability) is saved with that test run in history.json. Your API key is saved in config.json (readable by you only on macOS and Linux) and is never shown, logged or sent to the pal, the notch or the dashboard: they only see whether a key is saved and its last 4 characters.
What dotpals changes
dotpals changes other tools' files only when you ask it to, and always carefully:
- Connect on the Agents page adds one command, or a plugin file, to that agent's config. It backs up the original first (as
<file>.dotpals-backup), merges instead of overwriting, writes the file in one go so it's never half-written, and refuses to touch a file it can't read. Disconnect takes out only what dotpals added. dotpals statuslinesets your Claude Code status line, backs up~/.claude/settings.json, keeps your previous status line working, and--offputs it back.- Setup adds the Claude Code plugin through Claude Code's own
claude plugincommands, and turns on Open when I log in (skip them with--no-claudeand--no-login).
dotpals never changes what an agent is allowed to do. With Cursor and GitHub Copilot CLI it uses only hooks that watch, never the ones that can approve or block. The OpenCode plugin is written so it can't throw an error into OpenCode. The hook command always finishes quickly and successfully, whether or not dotpals is running.
How the bridge is protected
The bridge is a small web server, so it's built to be safe even though your browser can reach it:
- Local only. It listens on
127.0.0.1. - It only answers to its own name. Requests must be addressed to
127.0.0.1,localhostor[::1], which stops “DNS rebinding” pages from reading your activity. - Changes need a custom header (
x-dotpals: 1): settings, clearing history, Connect and Disconnect, dismissing sessions, answering approvals and testing the test-result checker. Browsers won't send a custom header to another site without asking it first, and the bridge never says yes, so websites can't change anything. They can't read its answers either. - Only its own files are served: the pages and scripts in
bridge/,src/anddesktop/. - The desktop app runs its pages sandboxed, with only a narrow set of desktop functions exposed, and opens links to websites and your editor outside the app.
Two things to keep in mind. Any program running on your computer can connect to the bridge's port and read the activity feed, just as it could read your agents' own logs. And anything on your computer can post events to /event and /hook, which add to the feed but can't read it, change settings or answer approvals.
Approving from the pal, safely
Approve from the pal lets you answer Claude Code's permission prompts with Allow or Deny. Because it answers on your behalf, it's designed to fail safe:
- Off by default. You turn it on in Settings.
- It only waits when you can answer: when a pal, the notch or the dashboard is connected. Otherwise the bridge steps aside at once.
- It always falls back to Claude Code. If you don't answer within the wait you chose (30 seconds by default, 10 to 120 allowed), or Claude stops waiting, dotpals gives no answer and Claude asks in the terminal as usual. It never allows anything on its own.
- You see exactly what will happen: the tool, the command or diff, and warnings written before the fact, such as “Force-pushes to git (can overwrite others' work)” or “Changes .env, which usually holds secrets”. Risky requests get an amber Allow button.
- Websites can't answer. Answers need the
x-dotpalsheader, which other websites can't send, and each request can be answered only once. - Deny is explained to Claude as “The user said no from dotpals.”
While dotpals waits, Claude Code doesn't show its own permission prompt, so the terminal looks idle until you answer or the wait runs out. Keep the wait short if you often work in the terminal.
Reporting a vulnerability
Please don't open a public issue. Report it privately through GitHub's private vulnerability reporting (the repository's Security tab, then Report a vulnerability), with what you found, how to reproduce it and its impact. Security fixes go into the latest release. See SECURITY.md.