skills/env/SKILL.md
Manage credentials INSIDE the active ~/.claude/.env file — read which token/account to use for a given app (Simplicity vs Dataforce vs Ronan-personal), add or update a secret WITHOUT it passing through the chat (an interactive Terminal window prompts for it), and track secrets that were exposed in a transcript so they get rotated. Sibling to /ro:context (which switches WHICH env file is active). Use when the user wants to add an API key/token/secret, asks "which credential do I use for X", needs the env organized/labelled, or a secret was pasted into the chat and should be rotated.
npx skillsauth add RonanCodes/ronan-skills envInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
/ro:context decides which ~/.claude/.env.<context> file is active. /ro:env manages the credentials inside it: reading the right one, adding new ones safely, keeping it organised, and tracking exposures. Resolve the active file with ro context env (cwd-aware); ~/.claude/.env is a symlink to it.
Every section of the env file is tagged with one of three owners. Never guess — the tag tells you.
| Tag | What | Cloudflare account |
|---|---|---|
| [SIMPLICITY] | Simplicity Labs company infra. Bare names (CLOUDFLARE_API_TOKEN, _ACCOUNT_ID, _ZONE_ID) are the Simplicity defaults, kept bare for skill compatibility; _SIMPLICITY mirrors them. | fcc16bad… ("[email protected]'s Account") |
| [DATAFORCE] | The product (Simplicity × Taskforce). Runs on the Simplicity account; own keys always suffixed _DATAFORCE, or product-scoped (Google Ads, Shopify, Nango, Atlassian DAFO, ChatGPT GPT). | fcc16bad… (same account) |
| [PERSONAL] | Ronan's own side-projects, NOT Simplicity. Suffixes _RONAN, _LEKKERTAAL, _ADHD; also Pushover/Telegram/Neon-"factory"/VAPID. | c421a1b2… (ronanconnolly.dev / [email protected]) |
The file carries a LEGEND + DEPLOY CHEAT-SHEET at the top mirroring this. The dataforce repo's memory reference_dataforce_cf_credentials mirrors it too.
| App | Token | Account |
|---|---|---|
| Dataforce | CLOUDFLARE_API_TOKEN_DATAFORCE | CLOUDFLARE_ACCOUNT_ID_SIMPLICITY |
| Simplicity site | CLOUDFLARE_API_TOKEN (=_SIMPLICITY) | CLOUDFLARE_ACCOUNT_ID |
| lekkertaal / adhd | CLOUDFLARE_API_TOKEN_RONAN | _ADHD | CLOUDFLARE_ACCOUNT_ID_RONAN |
which <app> → just answer from the table above + grep -iE '<app>' "$(ro context env)".
Several services have more than one account in the env file: a Simplicity Labs / Dataforce one and a personal Ronan Connolly one. The trap is that the unsuffixed/default key is usually the Simplicity one (kept bare for skill compatibility), so an agent that grabs the obvious key ships a personal app wired to the wrong account. This actually happened: smartcart.ronanconnolly.dev (a personal 12-in-12 app) was shipped sending OTP emails from [email protected] because the agent used the bare RESEND_API_KEY (the Simplicity account) instead of RESEND_API_KEY_RONAN.
The rule, every time you reach for a service credential:
grep -i resend "$(ro context env)" # → shows RESEND_API_KEY *and* RESEND_API_KEY_RONAN
grep -i cloudflare "$(ro context env)" # → bare token *and* _RONAN token
_RONAN). A personal app is anything on ronanconnolly.dev, a 12-in-12 side project, a hackathon build, or anything under the discopenguin Cloudflare account. Only use the Simplicity Labs / Dataforce / Taskforce account when the app is explicitly one of those ventures (the repo lives under Simplicity-Labs, the project is Dataforce/Taskforce, or the user names it as company work).| Service | Simplicity / Dataforce key | Personal "Ronan Connolly" key | Notes |
|---|---|---|---|
| Resend | RESEND_API_KEY (sends from simplicitylabs.io) | RESEND_API_KEY_RONAN (sends from ronanconnolly.dev) | Bare key is the Simplicity account — the trap |
| Cloudflare | CLOUDFLARE_API_TOKEN (= _SIMPLICITY, account fcc16bad…) | CLOUDFLARE_API_TOKEN_RONAN / CLOUDFLARE_ACCOUNT_TOKEN_RONAN (account c421a1b2688f51a3713d99c3e875ef1d, the discopenguin / [email protected] account where ronanconnolly.dev + nutmeg + smartcart live; per-project tokens like _NUTMEG, _RONANCONNOLLY live on the same account) | Bare token is the Simplicity account |
| Anthropic | ANTHROPIC_API_KEY_DATAFORCE | (none yet) | No generic personal Anthropic key exists yet; add one as _RONAN if needed |
This list will grow. When you add a new key for a service that already has one, always suffix the new one (_RONAN for personal, _DATAFORCE / _SIMPLICITY for company) and add a row here so the next agent does not fall into the same trap. The owner tags in the ownership model above are the deeper source of truth: [PERSONAL] suffixes (_RONAN, _LEKKERTAAL, _ADHD) are never the right pick for a Simplicity/Dataforce app, and the bare/[SIMPLICITY] keys are never the right pick for a personal app.
Default path (agent-driven): launch an interactive Terminal window so the human types the secret there. The value never enters the conversation, never hits a tool result, never lands in argv/ps.
bash "${CLAUDE_PLUGIN_ROOT:-$HOME/Dev/ronan-skills}/skills/env/scripts/add-secret.sh" --launch ANTHROPIC_API_KEY_DATAFORCE DATAFORCE "Workspace key, dataforce chat"
That opens Terminal; the user pastes the value at a hidden read -rs prompt. The script then, on the real env file (symlink resolved):
.bak.<ts> backup first (non-destructive),# [OWNER] … block at the end,If the user is at the keyboard, they can run it themselves: prefix with ! in Claude Code, or run bash …/add-secret.sh --interactive KEY OWNER "comment" in any terminal.
Rule: if a user does paste a secret into the chat anyway, (1) still get it into the env (or wherever it belongs), and (2) immediately log it for rotation (next section) and tell them to rotate it — a value in the transcript is compromised.
When a secret is exposed (pasted in chat, screenshotted, committed), log it:
bash "${CLAUDE_PLUGIN_ROOT:-$HOME/Dev/ronan-skills}/skills/env/scripts/rotate-queue.sh" add CLOUDFLARE_API_TOKEN_DATAFORCE env "re-pasted in chat 2026-05-23"
bash "${CLAUDE_PLUGIN_ROOT:-$HOME/Dev/ronan-skills}/skills/env/scripts/rotate-queue.sh" list # see everything still to rotate
bash "${CLAUDE_PLUGIN_ROOT:-$HOME/Dev/ronan-skills}/skills/env/scripts/rotate-queue.sh" done CLOUDFLARE_API_TOKEN_DATAFORCE
Queue lives at ~/.claude/.secrets-rotate-queue.md (gitignored). list also greps the active env for CHAT-EXPOSED / ROTATE comment markers. At the start of any session that will touch deploys/secrets, run list and nudge the user on anything still OPEN.
Keep it self-documenting:
# --- [OWNER] … --- tag.add-secret.sh so you don't see it and can't typo it). The file is a symlink — edit the resolved target (readlink -f ~/.claude/.env), not the link._DATAFORCE, _RONAN, …), and add them via add-secret.sh with that OWNER tag./ro:context — switches the active profile/file. ro:env operates within whatever it resolves./ro:cf-ship, /ro:fly-deploy, /ro:cloudflare-dns — consume these credentials; point them at the cheat-sheet when they pick a token./ro:setup-wizard — first-run onboarding; ro:env is the ongoing per-secret manager.testing
--- name: linear-pipeline description: The Fable orchestrator for a single dispatched Linear ticket. Holds almost no context itself; it receives `--issue <ID> --detached`, decides the stage sequence, and fans out a sub-agent per stage, passing forward only each stage's artifact (never re-derived, never inlined into its own context). Step zero, before any planning or stage routing, is a boundary triage against `canon/security-boundary.md` (#199): a match tags Ronan Connolly and stops the run, no
development
--- name: in-your-face description: Capture a chat-only answer into a durable artifact (markdown + HTML, PDF when cheap) and launch it automatically so the user cannot miss it. Use when user says "in your face", "don't let me lose this", "save that answer", "make that durable", or right after answering a substantive side question (a recipe, comparison, how-to, or generated prompt) that would otherwise die with the context. category: workflow argument-hint: [--no-open] [--vault <short>] [hint of
tools
One-shot headless OpenAI Codex CLI calls for background/admin AI tasks — summaries, classification, extraction, admin glue. The default engine for anything that runs AI constantly in the background (daemon-driven, per-event), because it bills the flat ChatGPT subscription instead of Claude usage or per-token API spend, and it keeps working while Claude is rate-limited. NEVER for coding — coding stays Claude. Use when a skill or daemon needs a cheap always-on AI call, when the user says "use codex", "ask codex", "codex as backup", or when building a background summarizer/classifier into a listener or loop. Reads auth from ~/.codex/auth.json (ChatGPT account, no API key).
research
Turn a warranty rejection, repair quote, or RMA email into a cited decision brief — legal read (NL/EU consumer law), is the part user-serviceable, live part and new-unit prices, repair-vs-DIY-vs-new economics, before-you-send-it checklist, deadlines. Use when the user pastes or screenshots a repair quote, warranty rejection, "not covered" email, onderzoekskosten fee, or asks "should I repair or replace this".