5 min readby tomo-kay

Cursor + secret management in 2026

How to set up Cursor so API keys stay out of the AI context, using the .cursor/rules/tene.mdc file to teach the agent the safe pattern.

The setup in 5 commands

curl -sSfL https://tene.sh/install.sh | sh
cd your-cursor-project
tene init
tene import .env          # if you have existing secrets
rm .env                   # yes, delete it

That is all the structural work. From now on, launch Cursor normally — the .cursor/rules/tene.mdc file generated by tene init teaches the agent the rest.

What the .cursor/rules/tene.mdc file looks like

tene init creates this file automatically. Abbreviated:

---
description: Secret management with tene
globs:
alwaysApply: true
---

# Secrets Management — tene

This project uses tene for secret management.
Secrets are encrypted locally with XChaCha20-Poly1305.

## Quick Reference

| Task | Command |
|---|---|
| List available secrets | tene list |
| Run with secrets injected | tene run -- <command> |
| Set a new secret | tene set <KEY> <VALUE> |

## Rules

1. Never hardcode secrets in source code.
2. Never create .env files — use tene run -- <command>.
3. Access secrets via process.env.KEY_NAME.
...

Cursor sees the alwaysApply: true front-matter and feeds this file into every new conversation as system context. Whether you are using Composer, Chat, or the inline AI, the agent knows how to handle secrets.

What changes in your Cursor workflow

Before

  1. Open Cursor in a project with an .env.
  2. Ask Composer to scaffold a Stripe webhook.
  3. Composer reads the codebase including .env.
  4. Plaintext sk_test_... enters the context window.

After

  1. Open Cursor in a project where .env has been migrated to tene.
  2. Ask Composer to scaffold a Stripe webhook.
  3. Composer reads .cursor/rules/tene.mdc, sees the rule about process.env.*, and writes the code using process.env.STRIPE_KEY.
  4. Composer does not run tene get STRIPE_KEY because the rules file says not to.
  5. You launch the app in a terminal with tene run -- npm start. process.env.STRIPE_KEY is the real value; Cursor never saw it.
Side-by-side: the same AI-assisted session with plaintext .env versus tene-injected env vars. Same workflow, different safety profile.
The same editor flow, before and after migrating to tene. The agent does the same work; the plaintext just is not there to read.

Running commands inside Cursor

When Composer or Chat asks you to run a terminal command that needs env vars, prefix it with tene run --:

# Cursor suggests:
npm run dev

# You run:
tene run -- npm run dev

If Cursor's embedded terminal is your main shell, consider aliasing:

# ~/.zshrc or equivalent
alias npm-run-with-secrets='tene run -- npm'
alias node-with-secrets='tene run -- node'

When Cursor actually needs a secret value

Sometimes you genuinely need Cursor to see a value — debugging a request that gets signed with a specific key, for example. In that case:

  1. Copy the value yourself from tene get KEY in a separate terminal (not Cursor's).
  2. Paste it into the Cursor chat only for that one reasoning step.
  3. Rotate the key afterward if it was production-grade.

The .cursor/rules/tene.mdc rule discourages this pattern specifically so that "paste a secret into chat" remains a deliberate, friction-loaded action rather than an automatic habit.

Multi-environment with Cursor

# Switch active env for subsequent 'tene run' calls
tene env staging

# Or target a specific env inline
tene run --env prod -- node server.js

Cursor sees the active env name (via the rules file's tene env list reference) but not the values. If you want to test a deploy scenario with real prod credentials and then reset:

tene run --env prod -- node server.js
# Test complete
tene env dev   # back to dev for day-to-day work

Common mistakes

Skipping tene init. Without it, no .cursor/rules/tene.mdc exists, Cursor has no rules, and the agent will happily read .env if you forget to delete it.

Committing the vault file. .tene/vault.db is .gitignored by tene init. Do not override that. The vault belongs on one machine.

Putting credentials in README or CLAUDE.md by hand. Those files are indexed by Cursor. If you are writing a secret anywhere in plaintext, you have reintroduced the problem.

Using tene get inside Cursor's terminal. That prints plaintext to stdout which enters the Cursor context. The rules file explicitly discourages this — but humans sometimes forget. If you need the value, use a separate terminal.

What if I do not want to use tene?

The rules file pattern is the general principle: teach the agent via a rules file, keep secrets out of plaintext, inject at runtime. You can do this with Doppler (.cursor/rules/doppler.mdc), Infisical, or any other secret manager that supports env-var injection. The specific tool matters less than the structural separation between "what the agent knows about the shape of secrets" and "what the agent sees as values."

Summary

  • tene init generates .cursor/rules/tene.mdc so the agent structurally knows how to handle secrets.
  • Your workflow becomes tene run -- <cmd> as a prefix; everything else is the same.
  • .env does not exist on disk, so it cannot be indexed.
  • Related reading: Claude Code + API keys: the safe workflow.