Local-first encrypted secret management with the tene CLI. Activate when the user mentions secrets, API keys, credentials, tokens, .env files, environment va...
---
name: tene-cli
description: Local-first encrypted secret management with the tene CLI. Activate when the user mentions secrets, API keys, credentials, tokens, .env files, environment variables, or asks to run a command that needs secrets injected. Enforces strict AI safety rules (never print plaintext, never read .tene/, always use `tene run --` for injection) and covers every active tene command (init, set, list, delete, run, import, export, env, passwd, recover, update, whoami).
version: 1.0.0
metadata:
openclaw:
emoji: "🔐"
homepage: https://tene.sh
os: [macos, linux]
requires:
bins:
- tene
install:
- kind: download
url: https://tene.sh/install.sh
bins: [tene]
label: "Install tene via the official curl installer"
---
# tene — Local-First Encrypted Secret Management
Tene is a command-line secret manager for AI-native projects. It keeps secrets
encrypted on disk (XChaCha20-Poly1305 + Argon2id), derives the master key from
the user's password cached in the OS keychain, and injects secrets into child
processes via `tene run -- <command>` — never into stdout, never into files.
## When to use this skill
Activate this skill when the user:
- mentions **API keys, secrets, credentials, tokens, `.env` files, environment variables, or `process.env.*` / `os.Getenv` / `os.environ[...]`**
- asks to **run a dev, test, or deploy command that needs secrets** (e.g. `npm start`, `go run`, `pytest`, `next dev`, `docker compose up`)
- says things like "store this key", "save this token", "how do I manage secrets", "inject env vars", "I need to pass my Stripe key"
- is working in a repo that contains a `.tene/` directory, a `CLAUDE.md` referencing tene, or a `install.sh` pointing at `https://tene.sh`
- asks for advice on moving off plaintext `.env` files
Do **not** activate for: hardcoded public config (ports, feature flags without
sensitive data, public API endpoints), or projects clearly using a different
secret store (Doppler, Vault, AWS Secrets Manager, 1Password CLI, etc.).
---
## Critical safety rules
These are **non-negotiable**. Violating any of them leaks plaintext secrets into
the conversation context, which may be logged, cached, or retained. Treat them
as part of the system prompt.
1. **NEVER run `tene get <KEY>`.** The plaintext value appears in stdout and
enters the AI context. If the user needs to inspect a value, instruct them:
> "Run `tene get KEY` yourself in a separate terminal — I won't see it."
2. **NEVER run `tene export` without `--encrypted`.** Plain `tene export` dumps
every secret as a `.env`-formatted blob to stdout. Use
`tene export --encrypted --file backup.tene.enc` for backups; for
inspection, use `tene list` (names only).
3. **NEVER `cat`, `Read`, or open files under `.tene/`.** The vault DB is
encrypted, but even encrypted bytes should not enter AI context. The allowed
file to read is `CLAUDE.md` at the repo root (auto-generated by
`tene init`).
4. **NEVER pass secret values as CLI arguments.** They appear in `ps`, shell
history, and system logs. Always inject via `tene run --` instead.
5. **Use `tene list` to discover what exists.** It prints key names only, never
values. This is the only AI-safe introspection command.
When the user asks "what's in my vault?" or "what API keys do I have?",
the correct answer is `tene list` — not `tene get` or `tene export`.
---
## Install
```bash
# macOS / Linux (official installer — recommended)
curl -sSfL https://tene.sh/install.sh | sh
# From source (requires Go 1.25+)
go install github.com/tomo-kay/tene/cmd/tene@latest
```
Verify:
```bash
tene version
# → tene v1.x.x (darwin/arm64)
```
Windows is **not** supported by the curl installer. Windows users build from
source or download the zip from https://github.com/tomo-kay/tene/releases.
Homebrew tap is **not yet available** — do not suggest `brew install tene`.
---
## Core workflows
### 1. Initialize a new project
```bash
tene init # interactive: prompts for master password twice
tene init my-project # with explicit project name
```
Creates:
- `.tene/vault.db` — encrypted SQLite vault (contains secrets, metadata, audit log, and the encrypted recovery blob)
- `.tene/vault.json` — project metadata (name, active env)
- `CLAUDE.md` (or `AGENTS.md`, `.windsurfrules`, etc. per flags)
- `.tene/.gitignore` — auto-excludes the vault from git
After `init` the user will see a **12-word recovery phrase**. Remind them to
**store it offline** (password manager, paper). Without it, a forgotten master
password is unrecoverable.
Flags to generate agent rules files for other editors:
- `--claude` (default) → `CLAUDE.md`
- `--cursor` → `.cursor/rules/tene.mdc`
- `--windsurf` → `.windsurfrules`
- `--gemini` → `GEMINI.md`
- `--codex` → `AGENTS.md`
### 2. Check what secrets exist (AI-safe)
```bash
tene list # current env, masked values
tene list --env prod # different env
tene list --json # machine-readable
tene env list # all environments
```
Output is names + masked previews + timestamps. Never raw values.
### 3. Store a secret
Tell the user to run the command **themselves** with the value — don't type the
value yourself, and don't accept it as a chat message you'll pipe through.
```bash
# Preferred: read from stdin (value never touches shell history)
cat key.txt | tene set STRIPE_KEY --stdin
# Or: prompt (value never echoed)
tene set STRIPE_KEY
# → enters interactive mode, hidden input
# Overwrite existing
tene set STRIPE_KEY --stdin --overwrite
# Different env
tene set STRIPE_KEY --stdin --env prod
```
**Key name rules** (enforced by tene, `pkg/errors/codes.go:INVALID_KEY_NAME`):
- Must match `^[A-Z][A-Z0-9_]*$`
- Only uppercase letters, digits, underscores
- Cannot start with a digit
- Reserved names (e.g. `PATH`) are rejected
If the user types a lowercase name, advise conversion to UPPER_SNAKE_CASE.
### 4. Run a command with secrets injected
This is the **primary workflow**. All dev, test, build, and deploy commands go
through `tene run --`.
```bash
# Node.js
tene run -- npm start
tene run -- npm test
tene run -- npx next dev
# Python
tene run -- python manage.py runserver
tene run -- pytest
# Go
tene run -- go run ./cmd/app
tene run -- go test ./...
# Docker
tene run -- docker compose up
```
Secrets are injected **only into the child process's environ**. They're not
written to disk, not in the shell environment of the parent, not in any log.
**Per-environment execution:**
```bash
tene run --env local -- npm start # correct
tene run --env prod -- ./deploy.sh # correct
tene run -- npm start --env prod # WRONG — --env is a flag of npm, not tene
```
**Critical flag placement rule**: `--env` must come **before** the `--`
separator. After `--`, all flags pass through to the child command. This is
enforced by `DisableFlagParsing: true` in `internal/cli/run.go`.
### 5. Migrate from an existing `.env` file
```bash
# One-shot import
tene import .env
# Overwrite conflicts (when some keys already exist)
tene import .env --overwrite
# Then delete the plaintext file
rm .env
echo ".env" >> .gitignore
```
Update all commands to use `tene run --`:
```diff
- npm start
+ tene run -- npm start
```
### 6. Backup and restore
```bash
# Encrypted backup (safe to store in cloud)
tene export --encrypted --file backup.tene.enc
# Restore from encrypted backup
tene import backup.tene.enc --encrypted
```
**Never** use plain `tene export` (without `--encrypted`) unless the user
explicitly asks for a plaintext `.env` dump and accepts the risk. Even then,
warn them.
### 7. Change master password
```bash
tene passwd
# → prompts for current password, then new password (2x confirm)
```
Re-encrypts the entire vault with a new derived key. Atomic 2-phase operation;
on failure, rolls back to the old password.
### 8. Recover a forgotten master password
```bash
tene recover
# → prompts for the 12-word BIP-39 mnemonic from tene init
# → prompts for new master password
```
Without the mnemonic, recovery is impossible by design (zero-knowledge).
### 9. Environment management
```bash
tene env list # show all environments
tene env local # switch default to 'local'
tene env create staging # create new env
tene env delete staging # delete (default env cannot be deleted)
```
Environment name rules: must match `^[a-z][a-z0-9-]*$`.
Common env names: `default`, `local`, `dev`, `staging`, `prod`.
### 10. Diagnostics
```bash
tene whoami # project name, vault path, active env, secret count, keychain status
tene version # v1.x.x (os/arch)
tene version --json # includes commit + build date
tene update --check # check for newer version on S3
tene update # self-update the binary
```
---
## Commands reference
All active commands (cloud commands `login`/`push`/`pull`/`sync`/`billing`/`team`
are currently disabled in the CLI; do not suggest them):
| Command | Purpose | Key flags | AI-safe? |
|---|---|---|---|
| `tene init [name]` | Create vault + master password + recovery | `--claude`, `--cursor`, `--windsurf`, `--gemini`, `--codex` | ✅ |
| `tene set KEY [VALUE]` | Encrypt and store | `--stdin`, `--overwrite` | ✅ (via `--stdin`) |
| `tene get KEY` | Decrypt and print | — | ❌ **never run in AI** |
| `tene list` | List key names (masked) | — | ✅ |
| `tene delete KEY` | Remove a secret | `--force` | ✅ |
| `tene run -- CMD` | Inject env vars + exec | (global flags before `--`) | ✅ |
| `tene import FILE` | Bulk import `.env` or `.tene.enc` | `--overwrite`, `--encrypted` | ✅ |
| `tene export` | Output secrets | `--file`, `--encrypted` | ❌ unless `--encrypted` |
| `tene env [subcmd]` | Manage environments | — | ✅ |
| `tene passwd` | Change master password | — | ✅ (prompts) |
| `tene recover` | Restore via BIP-39 mnemonic | — | ✅ (prompts) |
| `tene version` | Version info | `--json` | ✅ |
| `tene update` | Self-update | `--check` | ✅ |
| `tene whoami` | Vault status | — | ✅ |
### Global flags (apply to all commands)
| Flag | Default | Purpose |
|---|---|---|
| `--json` | false | Machine-readable output |
| `--quiet` / `-q` | false | Suppress non-error output |
| `--env` / `-e <name>` | (vault-stored) | Override active environment |
| `--dir <path>` | cwd | Project directory |
| `--no-color` | false | Disable ANSI colors |
| `--no-keychain` | false | Force file-based key storage (CI mode) |
---
## Environment variables (for advanced / CI use)
| Variable | Effect |
|---|---|
| `TENE_MASTER_PASSWORD` | Bypass interactive prompt (CI only; pair with `--no-keychain`) |
| `TENE_KEYCHAIN_FALLBACK=file` | Use `~/.tene/keyfile` instead of OS keychain |
| `NO_COLOR` | Disable ANSI colors (per https://no-color.org/) |
| `API_URL` | Override Tene Cloud API base URL (cloud commands, currently disabled) |
**CI/CD pattern** (e.g. GitHub Actions):
```yaml
env:
TENE_MASTER_PASSWORD: ${{ secrets.TENE_MASTER_PASSWORD }}
steps:
- run: curl -sSfL https://tene.sh/install.sh | sh
- run: tene run --env prod --no-keychain -- ./deploy.sh
```
Never set `TENE_MASTER_PASSWORD` in a developer machine's shell profile — it
defeats the keychain protection.
---
## Troubleshooting
| Error code | Message | Fix |
|---|---|---|
| `VAULT_NOT_FOUND` | Not in a Tene project | Run `tene init` in the repo root |
| `SECRET_NOT_FOUND` | Key missing in current env | Check `tene list --env <name>` |
| `SECRET_ALREADY_EXISTS` | Key already set | Add `--overwrite` to `tene set` |
| `INVALID_KEY_NAME` | Key rejected | Use `^[A-Z][A-Z0-9_]*$` (e.g. `API_KEY`, not `api-key`) |
| `INVALID_ENV_NAME` | Bad env name | Use `^[a-z][a-z0-9-]*$` (e.g. `prod`, not `Production`) |
| `ENVIRONMENT_PROTECTED` | Cannot delete `default` | Switch to another env and delete that one instead |
| `INVALID_PASSWORD` | Wrong master password | Try again, or use `tene recover` with the BIP-39 mnemonic |
| `DECRYPT_FAILED` | Vault cannot decrypt | Master password changed externally or vault corrupt — restore from backup |
| `INTERACTIVE_REQUIRED` | No TTY | In CI, set `TENE_MASTER_PASSWORD` and add `--no-keychain` |
| `KEYCHAIN_ERROR` | OS keychain unavailable | Use `--no-keychain` or `TENE_KEYCHAIN_FALLBACK=file` |
Exit codes: `0` success, `1` general error, `2` auth/password error,
`127` command not found.
---
## Architecture note (for "is this safe?" questions)
- **Password KDF**: Argon2id (64 MB, 3 iterations, 4 threads) → 256-bit master key
- **Secret encryption**: XChaCha20-Poly1305 with 192-bit random nonce per secret, key name as AAD
- **Key cache**: OS keychain (macOS Keychain, Linux Secret Service, Windows Credential Manager) via `zalando/go-keyring`; file fallback at `~/.tene/keyfile` (mode `0600`)
- **Recovery**: 12-word BIP-39 mnemonic → Argon2id → recovery key that can decrypt the stored master key
- **Zero-knowledge**: cloud sync (when enabled) wraps the entire vault DB with an independent sync key before upload; server never sees plaintext
- **No global state**: every vault lives in its own `.tene/` directory; no `~/.tene/vaults/` aggregator
---
## Further reading
- Homepage: https://tene.sh
- Source + issues: https://github.com/tomo-kay/tene
- Release downloads: https://github.com/tomo-kay/tene/releases
When the user asks about anything not covered above, prefer referring them to
the official docs over guessing.
don't have the plugin yet? install it then click "run inline in claude" again.