Post #7 in the Claude Code Toolkit series. Earlier posts: nf-agents, nf-dream, nf-git-workflow, nf-memory, nf-cc-sync, nf-ignore. This post is the smallest in the series, the one that fixes a .envrc file most developers paste together once and never revisit.

I keep two GitHub accounts. One for personal projects, one for client work. The gh CLI tracks both and gh auth switch moves between them. The friction shows up when a script wants a GH_TOKEN environment variable per repo.

Two failure modes:

  • Hardcode the token in .envrc. Leak waiting to happen. Even if .envrc is gitignored, the token sits in plaintext on disk, and it stops working the next time you rotate via gh auth refresh.
  • Hardcode the account name. Brittle. Two months later you forget which account this repo uses, run gh auth switch, and now the wrong tokens are loading silently.

nf-direnv sets up the .envrc with the token resolved dynamically at load time, with the correct account picked once and recorded in the file. Plaintext never touches disk; rotation is automatic.

What the skill does

  1. Preflight check: direnv is installed and the cwd is a git repo. Aborts with a clear message otherwise.
  2. Lists gh accounts via gh auth status, asks via AskUserQuestion which to use for this repo.
  3. Reads any existing .envrc and decides between three actions: create, append, or update-in-place. Existing exports unrelated to GH_TOKEN are preserved.
  4. Shows a Before/After/Diff preview, asks for confirmation.
  5. Writes .envrc using $(gh auth token --user <selected>) so the token resolves dynamically on every shell load.
  6. Verifies .envrc is in .gitignore, adds the pattern if missing.
  7. Runs direnv allow so the file actually loads in the current shell.

How to invoke

/nf-direnv

No arguments. The skill asks the questions it needs (which account, which action on .envrc) and reports the result.

A walkthrough

A new repo for client work. gh is authenticated with two accounts: personal-acct and work-acct.

$ cd ~/WORK/some-project
$ /nf-direnv

Preflight:
  direnv:    found (v2.34.0)
  git repo:  yes
  cwd:       ~/WORK/some-project

gh accounts:
  1. personal-acct (active)
  2. work-acct

> Which account for this repo?
> 2

.envrc plan:
  Status:    file does not exist, will create
  Content:
    export GH_TOKEN=$(gh auth token --user work-acct)

.gitignore:
  Status:    .envrc already ignored

Apply? Yes / No
> Yes

Wrote .envrc
Ran: direnv allow
  loading ~/WORK/some-project/.envrc
  export +GH_TOKEN

Two minutes from cd to a working environment. The next time you cd into this repo, direnv reloads .envrc, gh auth token --user work-acct runs, and the right token populates GH_TOKEN. If you have rotated the token in the meantime, the next reload picks up the new value automatically. No edits to .envrc needed.

Decision 1: Dynamic resolution, never a plaintext token

The first version of the skill wrote the token directly:

export GH_TOKEN=gho_AbCdEf...

That worked. It also had three failure modes:

  • The file is plaintext on disk. Even gitignored, a leaked filesystem snapshot is enough.
  • gh auth refresh rotates the token; the file is now stale and writes start failing with Bad credentials.
  • gh auth switch to a different account does nothing for this repo because the value is baked in.

The fix is one syntax change: wrap the value in $(...) and let gh auth token --user <name> resolve it on each shell load.

export GH_TOKEN=$(gh auth token --user work-acct)

gh auth token reads the encrypted credential store (keyring on most systems). The plaintext value never lands on disk. Rotation works without editing the file. Multi-account is explicit (the --user flag pins which account this repo uses).

The general lesson generalizes to any tool with a credential CLI (aws sso login, gcloud auth print-access-token, op read, pass). If the tool can print the secret on demand, wire it through $(...) in .envrc rather than copying the value out by hand.

Decision 2: Account is per-repo, picked once

The brittle alternative is to leave the account global (“use whatever gh auth switch is set to”) and assume the developer is in the right account when they cd in. That fails the first time you forget to switch.

The skill records the account explicitly in .envrc:

export GH_TOKEN=$(gh auth token --user work-acct)

The repo’s .envrc now declares which account it expects. Switching gh globally to another account does not change which token loads for this repo. The repo is self-describing for its credential needs.

This composes with direnv’s per-directory mechanism. Different repos under the same parent (e.g. ~/WORK/personal/repo-a and ~/WORK/client/repo-b) each pick up their own account on cd, with no global state to remember.

Side benefit: the account name in .envrc makes the choice grep-able. If you wonder months later “which account does this repo use”, the answer is one line in the file.

Gotchas

  • .envrc stays gitignored. Even though the file contains no plaintext token, the account name is per-developer. Committing it would push your personal account name to teammates. The skill auto-adds .envrc to .gitignore if missing and never commits .envrc itself.
  • direnv allow is per-machine. The skill runs direnv allow once after writing the file. If you clone the repo on another machine, you have to run direnv allow again there. That is direnv’s security model, not a skill limitation.
  • gh auth token requires login. If gh auth status shows no accounts, the skill stops and tells you to gh auth login first.
  • Existing .envrc content is preserved. The skill never overwrites unrelated exports. If you have NODE_ENV=development already there, it stays.

What you should keep even if you never use this skill

Three patterns generalize:

  1. Never write plaintext tokens to .envrc. Resolve dynamically via the tool’s credential CLI. $(gh auth token --user X) is the pattern for gh; the same shape applies to aws sso login, op read, pass, gcloud auth print-access-token, and anything else with a secret-printing command.
  2. Per-repo account selection. Record the account in the file. Do not rely on global state being correct when someone cds in.
  3. Verify .envrc is gitignored before writing. A two-line check saves a serious incident.

Get the skill

White-labeled in the claude-skills-toolkit repo alongside the rest of this series.

git clone https://github.com/llawliet11/claude-skills-toolkit.git
cp -r claude-skills-toolkit/nf-direnv ~/.claude/skills/

Folder reference: claude-skills-toolkit/nf-direnv (publishes alongside this post).

Verify in a new session: invoke /nf-direnv in any repo. The first run walks you through account selection, file preview, and direnv allow. The next time you cd into the repo, the right token is already loaded.