Vibe Coding5 min readby agent-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 the whole structural setup. From now on, open Cursor as usual. The .cursor/rules/tene.mdc file from tene init teaches the agent the rest.

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

tene init writes this file for you. Shortened:

---
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 reads alwaysApply: true and feeds this file into every new chat as system context. Composer, Chat, or 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_... lands in the context window.

After

  1. Open Cursor in a project where .env was moved into tene.
  2. Ask Composer to scaffold a Stripe webhook.
  3. Composer reads .cursor/rules/tene.mdc, sees the rule about process.env.*, and writes code that uses process.env.STRIPE_KEY.
  4. Composer does not run tene get STRIPE_KEY because the rules say not to.
  5. You start 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 tells you to run a 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 built-in terminal is your main shell, set up an alias:

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

When Cursor really needs a secret value

Sometimes you do need Cursor to see a value — say, debugging a request signed with a specific key. In that case:

  1. Copy the value yourself with tene get KEY in a separate terminal. Not Cursor's.
  2. Paste it into Cursor's chat for that one reasoning step.
  3. Rotate the key after, if it was a production key.

The .cursor/rules/tene.mdc rule discourages this on purpose. "Paste a secret into chat" should stay a careful, deliberate action. Not a habit.

Multi-environment with Cursor

# Switch active env for later '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 (through the rules file's tene env list note) but not the values. To test a deploy 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. With no .cursor/rules/tene.mdc, Cursor has no rules. 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 write a secret in plaintext anywhere, you have brought the problem back.

Using tene get inside Cursor's terminal. That prints plaintext to stdout, which then enters Cursor's context. The rules file says no — but people 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 idea. Teach the agent through a rules file. Keep secrets out of plaintext. Inject them 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 splitting "what the agent knows about secrets" from "what the agent sees as values."

Summary

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

FAQ

Does Cursor read .env by default?

Yes. Cursor's Composer and Chat features index project files to build context. .env at the project root is included unless explicitly excluded via .cursorignore or similar.

What does .cursor/rules/tene.mdc do?

It is a Cursor rules file with front-matter alwaysApply: true. It tells the Cursor agent how to think about secrets: use 'tene run --' to inject env vars, use 'tene list' to check what exists, never 'tene get KEY' in chat since that prints plaintext.

Can I use both Cursor and Claude Code on the same project?

Yes. tene init generates rules files for both agents at the same time (.cursor/rules/tene.mdc and CLAUDE.md). Each agent picks up its own rules automatically.