Coding agents¶
A coding agent sends far more than your prompt. Every file it reads, every
command output, and every log line becomes part of a request to the provider:
your .env, a stack trace with a customer's email address, the URL of an
internal git remote. This tutorial runs the agent through Privyx, so those
values are masked on the way out and restored on the way back.
You need: Privyx installed, and Claude Code, Codex, or aider working on its own. Time: ten minutes.
1. Start the tool through Privyx¶
privyx run claude
$ privyx run claude
Privyx proxy → https://api.anthropic.com
Running: claude --settings '{"env": {"ANTHROPIC_BASE_URL": "http://127.0.0.1:38383"}}'
ANTHROPIC_BASE_URL = http://127.0.0.1:38383
Claude Code then starts as it always does. privyx run did three things
first:
- It started a proxy on a free port on
127.0.0.1. - It launched the tool with its base URL pointed at that proxy.
- It will stop the proxy when the tool exits, and exit with the tool's own exit code.
The tool keeps its own login or API key; Privyx relays it to the provider.
Arguments after -- go to the tool:
privyx run claude -- --continue
The other tools it knows:
privyx run codex
$ privyx run codex
Privyx proxy → https://api.openai.com
Running: codex -c 'openai_base_url="http://127.0.0.1:43407/v1"'
OPENAI_BASE_URL = http://127.0.0.1:43407/v1
This covers Codex's built-in openai provider. With a model_provider
of your own in Codex's config, Codex does not go through Privyx; see
Check that it works.
privyx run aider
Privyx sets OPENAI_API_BASE and OPENAI_BASE_URL for it, both ending
in /v1.
Any tool that reads its base URL from an environment variable works. Name the variable and the provider:
privyx run -u https://api.example.com --env-var MY_TOOL_BASE_URL -- my-tool --flag
The variable gets the proxy's URL without a path. privyx run --list
shows the tools Privyx knows by name.
2. Work as usual¶
Ask the agent to do something that touches sensitive text, for example:
Read
.envand tell me which variables are set.
On your screen, nothing looks different: the answer names your real values.
The provider received something else. With this .env:
DB_PASSWORD=hunter2
SMTP_USER=dana@acme.example
the file reached the provider as:
DB_PASSWORD=<PRIVYX_SECRET_26EA7D0A8B8DC4C2>
SMTP_USER=<PRIVYX_EMAIL_4CE2AF0BB2282EF4>
The same happens to tool arguments in the other direction. When the model
decides to write <PRIVYX_EMAIL_4CE2AF0BB2282EF4> into a file, the tool call
your machine receives holds dana@acme.example.
Why these tokens are longer
privyx run creates an anchor secret in ~/.config/privyx/anchor.key
the first time it runs, so a token's id is derived from the value instead
of counted. The same value gets the same token in every turn and after a
restart, which keeps a long conversation, and the provider's prompt
cache, consistent. See Anchors.
3. Check that it works¶
When you leave the tool, look at the audit trail. privyx run keeps it in
your state directory, not in the project:
$ privyx audit stats ~/.local/state/privyx/audit.log
Audit log: /home/dana/.local/state/privyx/audit.log
Period: 2026-10-02T14:34:27 → 2026-10-02T14:34:28
Events: 13
Requests: 3
Responses: 3 (avg 0.04s)
Errors: 0
Sessions: 1 created, 0 deleted
Masked: 117 entities
Restored: 26 pseudonyms
Masked by entity type:
ORGANIZATION 55
EMAIL 31
PERSON 27
IP_ADDRESS 4
The trail holds counts and entity types, never the values. --since 1h
limits it to the last hour, and privyx audit tail FILE follows it live from
a second terminal.
Two things to look for:
-
Requests above zero. If the tool exits without having sent a single request through the proxy,
privyx runsays so:Warning: no request from claude reached Privyx; if it called its provider, it did so directly, without masking.That happens when the tool's own configuration outranks what
privyx runsets: amodel_providerof your own in Codex, or a--settingsof your own after--for Claude Code. If your Claude Code settings pointANTHROPIC_BASE_URLat a router or another proxy, give that URL to Privyx instead, asprivyx run -u URL claude: Privyx then sits in front of it. -
The entity types you expect. Emails, keys, and IP addresses show up without configuration. Names do not; that is the next step.
4. Add your own names and terms¶
The built-in patterns recognize values by their shape. Your name, your employer, and your project's codename have no shape, so Privyx cannot know they matter until you list them. They are also what a coding agent sends most often: they are in your home directory's path, your git branch names, and your commit log.
Put them in a config file:
# ~/.config/privyx/config.yaml
detector:
type: regex # keeps the built-in patterns
terms:
PERSON: [dana, dana whitfield, dwhitfield]
ORGANIZATION: [acme]
PROJECT: [bluebird]
Try it before you rely on it:
$ privyx detect -c ~/.config/privyx/config.yaml --transform "/home/dwhitfield/acme/bluebird on branch feature/dana-login"
6:16 PERSON 'dwhitfield'
17:21 ORGANIZATION 'acme'
22:30 PROJECT 'bluebird'
49:53 PERSON 'dana'
/home/<PRIVYX_PERSON_1>/<PRIVYX_ORGANIZATION_2>/<PRIVYX_PROJECT_3> on branch feature/<PRIVYX_PERSON_4>-login
Then make every run use it:
export PRIVYX_CONFIG=~/.config/privyx/config.yaml # in your shell profile
privyx run claude
or name it once: privyx run -c ~/.config/privyx/config.yaml claude.
Matching ignores case and only hits whole words, so dana does not match
inside danasaur. Your own names and terms goes further:
patterns for IDs, and detectors that find names without a list.
5. Share one proxy between terminals¶
privyx run starts a proxy per tool. To run one proxy for several terminals
or tools instead, start it yourself and point each tool at it:
export PRIVYX_SESSION_STRATEGY=conversation
export PRIVYX_ANCHOR_SECRET=$(openssl rand -hex 32) # keep it; reuse it on every start
privyx proxy --upstream https://api.anthropic.com
ANTHROPIC_BASE_URL=http://localhost:8000 claude
The two variables give this proxy what privyx run sets up by itself: one
session per conversation and stable tokens. A base URL in Claude Code's own
settings.json outranks the environment variable; privyx run handles that
for you, a shared proxy does not.
What Privyx covers for these tools¶
- Masked: the system prompt, your messages, file contents and command output the agent sends back as tool results, tool arguments, and the descriptions of tools (an MCP server writes those). Also what the tool reports about your machine: Claude Code's working directory, home, user name, git branch, and remotes, and Codex's workspace paths and remote URLs. As everywhere, a value is masked only when a detector finds it, so list your user name and organization as shown above.
- Restored: the model's answers, its reasoning, and the arguments of the tool calls it makes.
- Not masked: requests to paths other than the chat endpoints, which are forwarded as the tool sent them; images and other binary content; and anything a tool sends to a host other than its provider's API. Limitations has the details.
Next steps¶
- Your own names and terms: word lists, patterns, Presidio, and the LLM detector.
- Sessions and vault: how sessions are chosen and where they are stored.
- Troubleshooting: a
503from Privyx, a token left in an answer, and other symptoms. privyx runreference: every option, and how each known tool is pointed at the proxy.