agentleFS
amirhosseinNouriamirhosseinNouri/skills/macos-keychain-creds/SKILL.md

macos-keychain-creds

Skill1 starsChanged 2 months agoMITView on GitHub

General-purpose credential storage and retrieval backed by the macOS Keychain. Use this skill whenever a task needs a secret — an API token, personal access token, API key, password, webhook secret, or client secret — for any service (GitHub, GitLab, OpenAI, Slack, Stripe, an internal API, anything). It stores a secret the user pastes (`pbpaste | store_cred.sh SERVICE`), verifies it is still valid, lists what is stored, hands it to a command through the environment without ever printing it (`use_cred.sh SERVICE -- curl ...`), and deletes it. Use it proactively when a command fails with 401/403/"missing token"/"not authenticated", or when about to ask the user to paste a token into the chat — store it in the Keychain instead. Also use it to set up credentials that other skills or scripts will read later.

  • Reads credentials

The file

We split this skill into the rules it gives an agent

9 rules. About 0 are common, 3 are distinctive, and 6 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈3

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 6

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Never ask the user to type or paste a secret into the chat: Ask them to copy it to the clipboard, then run pbpaste | store_cred.sh.

    line 44
  2. Very specific:

    Never print a secret: Not with echo, not in a debug line, not in an error message.

    line 47
  3. Distinctive:

    Ask the user to copy the secret to the clipboard, then:

    line 58
  4. Very specific:

    Use a short lowercase name.

    line 67
  5. Very specific:

    Run check_cred.sh before a task that depends on a credential, and after any 401/403.

    line 132
  6. Distinctive:

    When a task needs a credential:

    line 146
  7. Very specific:

    If missing or invalid, tell the user exactly where to get the secret (see references/recipes.md for the common ones and the scopes each …

    line 150
  8. Very specific:

    Do the work through use_cred.sh.

    line 153
  9. Distinctive:

    If the user pastes a secret into the chat anyway, store it, then tell them plainly that the value is in the transcript and should be …

    line 155

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

macOS Keychain Credentials

Store secrets in the macOS Keychain, then use them without ever seeing them.

The Keychain is the system secret store: entries are encrypted at rest, unlocked with the login password, and readable only by the logged-in user. This skill wraps it so a secret has exactly one safe path in (the user's clipboard) and one safe path out (the environment of a child process).

ConcernHow this skill handles it
Where secrets livemacOS Keychain, one generic-password entry per service
Path instdin only (pbpaste | store_cred.sh) — never argv, never a file
Path outexported into a child process by use_cred.sh — never stdout
Which secrets exist~/.config/macos-keychain-creds/registry.tsv (non-secret metadata only)
NamingSERVICE is any label the user picks, e.g. github-token

scripts/keychain.sh and scripts/registry.sh hold the shared helpers, so nothing else has to be installed.

Throughout, skill_dir means the directory containing this SKILL.md:

skill_dir="<directory containing this SKILL.md>"

The rules that matter

  1. Never ask the user to type or paste a secret into the chat. Ask them to copy it to the clipboard, then run pbpaste | store_cred.sh. A secret pasted into the conversation is in the transcript forever.
  2. Never print a secret. Not with echo, not in a debug line, not in an error message. Use use_cred.sh so the value goes straight into the child process's environment.
  3. Never put a secret in argv. curl -H "Authorization: Bearer sk-..." puts the token in the process list, where any process on the machine can read it. Reference the exported variable inside single quotes instead, so the calling shell never expands it.
  4. Never write a secret to a file — not .env, not a config file, not a scratch file, and never into the repository.
  5. Never enable shell tracing (set -x) around a command holding a secret.

Storing a credential

Ask the user to copy the secret to the clipboard, then:

pbpaste | "$skill_dir/scripts/store_cred.sh" github-token \
  --description "GitHub PAT, repo + read:org" \
  --validate 'curl -sf -o /dev/null -H "Authorization: Bearer $CRED" https://api.github.com/user'
  • SERVICE (github-token here) is the Keychain service name and the handle used everywhere else. Use a short lowercase name; <service>-token or <service>-key reads well.
  • --validate is a shell command that must succeed before the secret is stored. It runs with the secret exported as $CRED, so a bad token can never overwrite a working one. It is saved in the registry, so check_cred.sh can re-run it later. Always supply one when the service has a cheap "who am I" endpoint — see references/recipes.md for ready-made ones.
  • --env-var NAME overrides the exported variable name, which otherwise comes from the service name (github-token → GITHUB_TOKEN).
  • --account ACCOUNT stores a second credential for the same service, e.g. a work and a personal account. It defaults to the macOS username.

Re-running the same command replaces the value and keeps the registered metadata: that is how a token is rotated.

Using a credential

use_cred.sh reads the Keychain and execs the command with the secret in its environment, as both $CRED and the registered variable name:

"$skill_dir/scripts/use_cred.sh" github-token -- \
  bash -c 'curl -sS -H "Authorization: Bearer $GITHUB_TOKEN" https://api.github.com/user' | jq .login

Single quotes around the inner command are load-bearing. With double quotes, the calling shell expands $GITHUB_TOKEN before curl starts — putting the secret into argv and into the agent's transcript.

Define a helper once per shell session for repeated calls against one API:

gh_api() {
  "$skill_dir/scripts/use_cred.sh" github-token -- \
    bash -c 'curl -sS -H "Authorization: Bearer $GITHUB_TOKEN" \
                  -H "Accept: application/vnd.github+json" \
                  "$@"' _ "$@"
}

gh_api https://api.github.com/user/repos?per_page=5 | jq -r '.[].full_name'

Two credentials at once: nest the calls.

"$skill_dir/scripts/use_cred.sh" github-token -- \
  "$skill_dir/scripts/use_cred.sh" openai-key -- ./deploy.sh

A CLI that reads a secret from stdin can take it straight from the pipe:

"$skill_dir/scripts/get_cred.sh" github-token --unsafe-print | gh auth login --with-token

get_cred.sh writes the raw secret to stdout, which is why it demands --unsafe-print. Only ever use it on the left side of a pipe into a program that consumes it. Never run it as a bare command, never capture it into a shell variable that later gets echoed, and never use it to "check" a value.

Checking and listing

"$skill_dir/scripts/check_cred.sh" github-token   # exit 0 valid, 1 missing, 3 present but invalid
"$skill_dir/scripts/list_creds.sh"                # every registered credential and its status
"$skill_dir/scripts/list_creds.sh" --validate     # also re-runs each validation command

Run check_cred.sh before a task that depends on a credential, and after any 401/403. Exit 3 means the secret is expired or revoked — ask the user for a fresh one and store it the same way.

Deleting a credential

Deleting is unrecoverable: the secret cannot be read back afterwards. Confirm the exact service with the user first, then:

"$skill_dir/scripts/delete_cred.sh" github-token --yes

Workflow

When a task needs a credential:

  1. list_creds.sh — is something already stored for this service?
  2. check_cred.sh SERVICE — is it still valid?
  3. If missing or invalid, tell the user exactly where to get the secret (see references/recipes.md for the common ones and the scopes each needs), ask them to copy it to the clipboard, then run pbpaste | store_cred.sh SERVICE --validate '...'.
  4. Do the work through use_cred.sh.

If the user pastes a secret into the chat anyway, store it, then tell them plainly that the value is in the transcript and should be rotated.

Troubleshooting

SymptomLikely causeAction
no Keychain entry for serviceNever stored, or stored under a different accountlist_creds.sh, then store it
check_cred.sh exits 3Token expired, revoked, or missing a scopeStore a fresh token
401 from an API that just workedToken rotated on the provider's sideStore a fresh token
403 with a valid tokenToken lacks the scope or the resource is not sharedRe-issue with the scopes in references/recipes.md
multiline secrets are not supportedClipboard holds a PEM key or a whole config blockStore the key as a file with correct permissions and keep only its passphrase here
empty secret on stdinClipboard is empty or held an imageAsk the user to copy the secret again
did not store the expected valueThe secret contains characters the Keychain CLI manglesReport it; do not retry with the secret in argv
Registry shows a credential as missingKeychain entry deleted outside this skillStore it again, or delete_cred.sh --yes to drop the stale row

Registry

~/.config/macos-keychain-creds/registry.tsv (override with MACOS_KEYCHAIN_CREDS_HOME or MACOS_KEYCHAIN_CREDS_REGISTRY) records service, account, env var, description, and validation command — no secrets. It exists because the Keychain cannot be listed by prefix without an interactive security dump-keychain prompt. It is safe to read, and safe to back up.

References

  • references/recipes.md — copy-paste setup and usage for GitHub, GitLab, OpenAI, Anthropic, Slack, Stripe, npm, Docker registries, and generic Bearer/Basic/header APIs.
  • references/agent-integration.md — reading these credentials from another skill, a script, or a hook, and choosing between use_cred.sh and get_cred.sh.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.