It sends counts and names, not content
Per message: token counts, the model, a timestamp, the project folder name and the
git branch — plus the identifiers that let the portal deduplicate and group what it
is given (a message id, a session id, and a one-way salted hash of the project path,
never the path itself), your Claude Code version, which service tier answered, and
whether the turn was a sub-agent's rather than yours.
Once per session it also sends what that session loaded before you typed
anything: how many tools and skills were offered, how many were used, how many times
each block was re-emitted, the size in bytes of each of those blocks, the
names of your MCP servers, and the
names of your skills — each one with where it came from (yours, a
plugin's, or one Claude Code ships) and whether you invoked it in that session. The
counts travel too: how many skills were listed and how many you used, split the same
three ways. That is the whole list.
Those names are what make "you load this one into every session and never call it"
actionable rather than a percentage. If a name is itself confidential — a client's
name, an unannounced project, a skill you wrote called
acme-billing-migration — set TOKREC_UPLOAD_NAMES=0 before
the recorder starts. One setting covers both: no server name and no skill name then
leaves the machine, and neither does the per-server size, which means nothing without
a name to attach it to. Every other count still travels, so the portal can still tell
you how much you load and how little you use; it just cannot tell you which one to
remove.
There is no field in either upload format capable of carrying a prompt, a reply, a
file, or the text of a skill — and tokrec watch --dry-run prints exactly
what would be sent, both kinds, before you send anything.