GUIDES
  • Claude Code
  • Codex
  • Cursor
  • OpenAI

Claude asked for my API key. Is it safe to paste it?

No, not into the chat. A key you paste there becomes part of the conversation: the model provider gets it with every later request, the transcript keeps it on disk, and the agent can copy it into a file or a commit. Instead, let the agent ask for the key with a tool call. With offprompt, you type the key on a page in your browser, it is written straight to the project's .env.local, and the agent only learns that the key exists.

claude — ~/acme-support
Summarise each new support ticket with OpenAI.
That needs OPENAI_API_KEY, which isn't in .env.local yet. I'll ask you for it with offprompt.
offprompt - collect_secret (MCP)
⎿
file: .env.localkeys: OPENAI_API_KEY Opened http://127.0.0.1:4123 in your browser. Waiting for you to write it…
✻Waiting on offprompt… (esc to interrupt)
offprompt127.0.0.1:4123
Claude Code asks offprompt for the key by name, and offprompt's own page opens in your browser for that request. The page is offprompt's, rendered for this example; you type the key there, never in the terminal.

What happens to a key you paste into the chat

An agent such as Claude Code, Codex or Cursor works by sending the whole conversation to a model on every turn. Once a key is in the conversation, it goes along each time:

  • The model provider receives it, with that request and every later one in the session, and keeps it for as long as its data policy keeps requests.
  • The transcript keeps it. Coding agents save each session on your disk so you can resume it, and a hosted agent keeps it in your account. A summary made when the conversation is compacted can repeat it.
  • The agent can echo it. Asked to make something work, it may write the key into a config file, a test, a script or a log line, and from there into a commit.

None of this can be taken back. A key that has been in a chat is best treated as exposed, and replaced.

claude — ~/acme-support
Summarise each new support ticket with OpenAI.
I need an OpenAI API key for this. Paste it here and I'll add it to .env.local.
sk-proj-EXAMPLE-n0t-a-real-key-Qz4f9Wm2Lx7Rk1Tb
Write(.env.local)
⎿
Wrote 1 lines to .env.local1 OPENAI_API_KEY=sk-proj-EXAMPLE-n0t-a-real-key-Qz4f9Wm2Lx7Rk1Tb
Pasted into Claude Code: the key is in the conversation, and the agent echoes it again when it writes the file. Every request to the model from here on carries both. (The key is made up.)

The fix: the agent asks, and you type the key somewhere else

offprompt is an MCP server, a tool the agent can call. When a task needs a key the project does not have, the agent calls offprompt's collect_secret tool with the key's name, why it needs it, and the file it goes in:

{
  "secrets": [{ "name": "OPENAI_API_KEY", "provider": "openai" }],
  "reason": "Each new support ticket gets a short summary from **OpenAI**, written by `lib/summarise.ts`.",
  "sink": { "kind": "dotenv", "path": ".env.local" }
}
  1. A page opens in your browser, served from 127.0.0.1 on your own machine. It says which agent is asking, what for, and which file it will write.
  2. You paste the key. The page checks it against what offprompt knows of the provider, such as an OpenAI project key starting with sk-proj-, and links to where the key is made.
  3. offprompt writes the key to .env.local, and answers the agent with the key's name and a fingerprint of four emoji, which your page shows too:
claude — ~/acme-support
offprompt - collect_secret (MCP)
⎿
Wrote 1 value to .env.local · fingerprint 🍋 🥝 🌮 🧀
Fingerprint 🍋 🥝 🌮 🧀. OPENAI_API_KEY is in .env.local; lib/summarise.ts reads it as process.env.OPENAI_API_KEY.
What the agent gets back, and what your page shows once it is written. The four emoji match, so the file holds what you typed; the key itself appears nowhere in the session.

From then on the project reads the key by name, as process.env.OPENAI_API_KEY. The agent never had the value, so it cannot repeat it.

When the agent runs in a cloud sandbox, such as Claude Code on the web or Codex cloud, it cannot open a page on your screen. It shows you a link instead, through a Cloudflare quick tunnel. You open it in your own browser, which encrypts the key to one only the sandbox holds before sending it, so the tunnel carries only ciphertext. See Cloud sandboxes.

Set it up in 30 seconds

In the project's folder, with Node 22 or later, run npx offprompt init. It finds Claude Code, Codex, Cursor and Pi on your machine and declares offprompt in each one's project config. Commit what it adds, and everyone on the project gets it.

To add it by hand instead, start it from npm in each agent's config:

.mcp.json (Claude Code)
{
  "mcpServers": {
    "offprompt": {
      "command": "npx",
      "args": ["-y", "offprompt", "mcp"],
      "timeout": 330000
    }
  }
}
.cursor/mcp.json (Cursor)
{
  "mcpServers": {
    "offprompt": {
      "command": "npx",
      "args": ["-y", "offprompt", "mcp"]
    }
  }
}
.codex/config.toml (Codex)
[mcp_servers.offprompt]
command = "npx"
args = ["-y", "offprompt", "mcp"]
tool_timeout_sec = 330

Claude Code asks once before it starts a server a project declares, and Codex reads a project's config only in a project you trust. The timeouts give you time to type: Codex otherwise ends a tool call after 60 seconds. On Linux, init also passes Codex the variables offprompt needs to open your browser. Other agents, such as Cline, are in Agents.

Then ask for the task, not the key: “Send a welcome email with Resend when someone signs up.” The agent calls offprompt when it reaches the step that needs the key.

Keep the agent out of the file afterwards

offprompt keeps the key out of the conversation, but the file is on disk and the agent could still open it. Every result offprompt returns tells the agent not to and lists the keys the file holds, so it has no reason to. To make sure, close its file tools to the file:

.claude/settings.json (Claude Code)
{
  "permissions": {
    "deny": ["Read(./.env)", "Read(./.env.local)"]
  }
}

In Cursor, list .env* in .cursorignore. Neither covers every shell command, so a script that prints the environment can still show the value. How to keep secrets out of your AI agent's context goes through each way in.

If you already pasted one: rotate it

  1. Make a new key at the provider, with no more access than the task needs.
  2. Ask the agent to use the new key with offprompt, so it is written without entering the chat.
  3. Delete or expire the old key, and check the provider's logs for requests you did not make.
  4. Search the project, and its git history, for the old value, in case the agent wrote it anywhere.

Guides for one provider at a time

Each sets up a key with only the access it needs, has the agent ask for it, and uses it in working code.

FAQ

Does the model provider see my key when the agent uses offprompt?

No. The value goes from your browser to offprompt, running on your machine, and into the file. It is never in a prompt, a tool call's arguments or its result, so nothing sent to the model provider carries it. The provider sees the key's name, the file and a four-emoji fingerprint. If the agent later opens the file, the value enters its context after all: every result tells it not to, and a deny rule in Claude Code or .cursorignore in Cursor closes its file tools to the file.

Does it work when the agent runs in a cloud sandbox?

Yes. From Claude Code on the web, a Cursor Cloud Agent, Codex cloud, a codespace or an SSH session, the agent shows you a link to offprompt's page through a Cloudflare quick tunnel. Your browser encrypts the values to a key made in the sandbox for that one request before they leave it, so the tunnel carries only ciphertext. The link is good for 30 minutes and one write; open it yourself and don't pass it on.

I already pasted a key into the chat. What should I do?

Rotate it. Make a new key at the provider, let the agent ask for it with offprompt, then delete or expire the old one. Deleting the conversation does not reach the copies already sent to the model provider or written into files by the agent. The provider guides below say where each key is rotated.

Does offprompt keep my keys or send them anywhere?

No. offprompt runs on your machine as a process your agent starts. It writes the values to the file the agent named, keeps none of them once they are written, collects no telemetry and has no server of ours to send anything to. It is open source under the MIT license.

Which agents does it work with?

npx offprompt init sets it up for Claude Code, Codex, Cursor and Pi. Any other agent that speaks MCP, such as Cline, Windsurf, Gemini CLI or VS Code, can start it with npx -y offprompt mcp; Cline also needs the project as its cwd.

Will the key end up in git?

Not unless the file is tracked. offprompt's page says whether the file is gitignored, and when the file is tracked by git it holds back the write until you tick an override. Most frameworks keep .env.local out of git by default; check that your .gitignore lists it.

Try it

In a project's folder, run the command below, then ask the agent for something that needs a key.

npx offprompt init

More guides