${ENV_VAR} in skill files: wiring channels without leaking secrets into git
Your agent's definition belongs in git. Its Slack token does not. How rysh skill files keep those two sentences compatible.
Two things I believe about AI agents, which appear to be on a collision course:
- An agent's definition should live in git. Persona, knowledge, channels — reviewable in a PR, diffable, revertible, blame-able. If your bot's behavior isn't versioned, you don't operate a bot; you operate a rumor.
- A Slack bot token must never, ever live in git. Not in the repo, not in the history, not "temporarily." Every security postmortem template has a line for this.
Most bot platforms resolve the collision by giving up on #1 — configuration moves into a dashboard, secrets and logic together, and now your agent is unversioned vendor state. rysh resolves it the other way, with a mechanism old enough to collect a pension: environment variable interpolation.
The file you commit
A rysh humanoid — an agent with external channels — is one markdown skill file. Channels are declared in the frontmatter's contacts section, and every secret is a ${TOKEN} reference, not a value:
---
name: support-bot
description: Support humanoid for Northwind Devtools
contacts:
slack:
enabled: true
bot_token: "${SLACK_BOT_TOKEN}"
app_token: "${SLACK_APP_TOKEN}"
reply_mode: mentions
channels:
- "#support"
email:
enabled: true
address: "support@northwind.dev"
password: "${SUPPORT_EMAIL_PASSWORD}"
---
You are support-bot, the support engineer for Northwind Devtools.
Answer only from the product facts below…
At spawn time — ##humanoid spawn support-bot.md — rysh resolves each ${ENV_VAR} from the environment of the machine doing the spawning. The values exist in the running process; the file never contains them, before or after.
export SLACK_BOT_TOKEN="xoxb-…" # or from your secret manager
export SLACK_APP_TOKEN="xapp-…"
##humanoid spawn support-bot.md
##humanoid channel start support-bot slack
# slack [connected]
That's the entire mechanism. No new vault product, no proprietary secret syntax to learn — the interpolation shape you already know from docker-compose and CI configs, applied to agent definitions.
What this buys you, concretely
git log becomes your bot's changelog — safely. Every persona tweak, every added product fact, every new channel is a commit. You can git revert a bad prompt change at 2 a.m. And because tokens were never in the file, none of that history is radioactive. No git filter-branch archaeology, no rotating every credential because a repo went public.
The file is shareable; the access isn't. Email support-bot.md to a colleague, post it in a gist, use it as a template across three client projects (agencies, this is your workflow) — whoever receives it gets the logic. They can't impersonate your bot, because the file grants nothing. Access comes only from the environment of the machine that spawns it.
Rotation is boring — the way it should be. Slack token compromised? Rotate it at the source, update the env var, restart the channel:
export SLACK_BOT_TOKEN="xoxb-NEW…"
##humanoid channel stop support-bot slack
##humanoid channel start support-bot slack
Zero edits to the skill file. Zero commits. The definition of the agent and the credentials of the agent have separate lifecycles, because they're separate concerns.
Environments come for free. Same file on your laptop with a test-workspace token, on the Mac mini with production credentials. Dev/prod parity for a bot, using nothing fancier than a different .env.
Part of a bigger posture
Keeping secrets out of skill files is one layer of how rysh treats credentials generally — the platform assumes agents will be near secrets and is built to be paranoid about them: output that leaves your session for shared or remote viewing passes through client-side secret redaction, and env access from agent tools goes through a redacting reader. Different layers, same principle: the value stays on your machine; everything else gets a reference or a redaction.
And it composes with the governance story. The skill file in git tells your reviewers what the agent is allowed to say and where. The environment tells the machine what it's allowed to connect to. A PR reviewer can approve a new email channel block without ever being able to see — or needing to see — the mailbox password.
The habit worth forming
If you adopt one convention from this post, make it this: treat agent definitions like application code, and agent credentials like application credentials. Same repos and reviews for the first; same env vars and secret managers for the second. The ${ENV_VAR} syntax is just the seam that lets one file participate in both worlds without contaminating either.
Honest scope, per house rules: live humanoid channels today are Slack, email (IMAP IDLE/SMTP), and website chat — WhatsApp and phone are roadmap, not live. rysh runs on Claude with your own Anthropic key (that key, naturally, is also an env var — never a file). Self-hostable, not open source. Private beta.
Your agent in git, your secrets in the environment, and never the twain shall meet — in a diff, at least.
If your team already reviews infrastructure as code and wants agents to work the same way, you're our kind of people — rysh is onboarding design partners.
More in this series: Your agents live in git · One SKILL.md, three channels