Project-scoping
Ringtail reads one project's .env.example as the manifest — and fans each key out across the environment axis.
Ringtail is project-scoped. You point it at a local project and it reads that project's
.env.example as the manifest — the shopping list of every credential the project needs.
The connection grid is built directly from it: providers × environments.
Only names and paths cross the boundary during selection — never file contents, nothing secret.
The .env.example format
Ringtail groups the keys in your .env.example into one provider row per section. You do
not need any special format — the normal way you already write .env.example works. There are
three ways a key gets grouped, in order:
1. A plain section comment (what most projects already use):
# Database
DATABASE_URL=
## Auth
BETTER_AUTH_SECRET=
# ---- Email ----
RESEND_API_KEY=Each # Header, ## Header, or # ---- Header ---- comment starts a new row. Decorative
dashes/equals/asterisks around the label are ignored, and a prose comment (one containing a
URL, colon, or other sentence punctuation — e.g. # get this from the dashboard →) is left as
a plain comment, not treated as a header.
2. The box-drawing section comment (Ringtail's own repos use this — still supported):
# ── Cloudflare ──
CLOUDFLARE_API_TOKEN=
CLOUDFLARE_ACCOUNT_ID=3. No header at all — Ringtail recognizes the provider from the variable name so a bare
.env.example still splits into real provider rows:
DATABASE_URL= # → neon
BETTER_AUTH_SECRET= # → better-auth
RESEND_API_KEY= # → resend
CLOUDFLARE_API_TOKEN= # → cloudflare
STRIPE_SECRET_KEY= # → creem (billing)Known prefixes: DATABASE_URL / POSTGRES* / PG* / NEON* → neon, RESEND* →
resend, BETTER_AUTH* → better-auth, POSTHOG* / NEXT_PUBLIC_POSTHOG* → posthog,
CLOUDFLARE* / CF_* → cloudflare, CREEM* / STRIPE* / DODO* → creem,
INFISICAL* → infisical. Anything unrecognized and without a header lands in an other
row — still on the grid, just not auto-mapped to a recipe.
As always, only names are read — the right-hand side of .env.example holds no values, so
nothing secret is ever touched.
The environment axis
local · dev · staging · prod.
- local — your machine,
.env.local, localhost. The only environment that touches your disk. - dev · staging · prod — deployed. Secrets go to Infisical only, never your disk. Each environment gets its own scoped keys and resources (e.g. a Neon branch per env).
Sink routing follows the axis: local → .env.local; dev / staging / prod → Infisical.
syncCredential fans one acquired key out per environment so a single consent provisions the
whole row.
Local credential discovery
Before asking you for anything, Ringtail scans known credential stores — .env.local,
~/.ringtail, ~/.aws/credentials, ~/.config/gh, ~/.wrangler / ~/.cloudflared, and the
environment — validates what it finds, reuses complete root grants, and only prompts for real
gaps. Known locations only, local-only, and transparent about what it reused. It never scans
your whole disk.