plugins/claude-code-hermit/skills/channel-setup/SKILL.md
Guided channel activation for local/tmux users — installs the plugin, configures the bot token in the project-local state dir, and walks through pairing. Run after hatch or hermit-settings to activate a configured channel.
npx skillsauth add gtapps/claude-code-hermit channel-setupInstall 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.
Activate a channel configured in config.json for local/tmux operation. This mirrors what docker-setup does for Docker users but targets the local environment.
Docker check (first): read .claude-code-hermit/state/runtime.json if it exists.
runtime_mode == "docker": stop and redirect —
This project is running in Docker. Channel token and pairing must happen inside the container, not on the host. Run
/claude-code-hermit:docker-setup— it configures channels container-side. Stop.
runtime.json is missing AND .claude-code-hermit/docker/Dockerfile.hermit exists (Docker scaffolded but not yet booted): same redirect.Read .claude-code-hermit/config.json. Collect all entries under channels that are valid objects.
/claude-code-hermit:hatch or /claude-code-hermit:hermit-settings channels to add one first." Stop.AskUserQuestion (header: "Channel") — list channel names as options plus All — which to set up.Run steps 2–6 for each selected channel.
Run both checks in a single Bash call:
bun --version 2>/dev/null; uname -s
Bun missing (command fails / no output): tell the operator —
Bun is required for channel plugins but is not installed. Install: https://bun.sh Then re-run this skill.
Stop for this channel.
iMessage on non-macOS: if uname -s is not Darwin and the channel is imessage, note it's macOS-only and skip this channel.
Run claude plugin list --json and apply the project-or-local + enabled filter:
enabled == true AND (scope == "project" OR scope == "local") AND projectPath equals the current project root.Resolve the expected marketplace for this channel:
channels.<channel>.marketplace is set in config.json, use that value (third-party channel plugin path).claude-plugins-official (built-in channels: discord, telegram, imessage).Then check whether the surviving set contains an entry where:
id left of @) equals <channel>, ANDid right of @) equals the resolved marketplace.(Both clauses matter — discord@some-other-marketplace is a different plugin from a different source and must not satisfy this gate.)
enabled == true, and *_STATE_DIR (set by hermit-start at boot) points at .claude.local/channels/<channel>/.claude plugin install <channel>@<marketplace> --scope local
claude plugin enable <channel>@<marketplace> --scope local
Explicit enable covers the disabled-but-installed-at-project/local case — the filter excluded such entries (enabled-only), and install is a separate command from enable per the CLI surface, so it may no-op without re-enabling. A user-scope install elsewhere does not satisfy this gate; channel tokens and access policy are project-local.After any install (or if already present): tell the operator to run /reload-plugins in this session to activate the plugin's configure and access commands before pairing.
Token env var names: discord → DISCORD_BOT_TOKEN, telegram → TELEGRAM_BOT_TOKEN.
Resolve state_dir:
channels.<channel>.state_dir from config.json..claude.local/channels/<channel>.Check if the token file already exists: <state_dir>/.env and contains the token var name.
<state_dir>/.env." → proceed to step 5.To create your bot and get a token, follow the official guide: https://code.claude.com/docs/en/channels
questions: [
{
header: "Bot token",
question: "Paste your bot token (or skip to add it later):",
options: [
{ label: "Skip", description: "I'll add the token to <state_dir>/.env manually" }
]
}
]
Operator pastes the token via Other, or selects Skip.
If token provided:
mkdir -p <state_dir><TOKEN_VAR>=<pasted-token> to <state_dir>/.env (overwrite if exists)chmod 600 <state_dir>/.env.claude.local/ is in .gitignore: check if .gitignore exists and contains .claude.local/; if missing, append .claude.local/.channels.<channel>.state_dir was not set in config.json, write it now as a relative path (e.g. .claude.local/channels/<channel>)..claude/settings.local.json in a single read-modify-write (create {} if missing):
*_BOT_TOKEN from the env block (tokens must only live in .env).state_dir. Set env.<CHANNEL_UPPERCASE>_STATE_DIR = <absolute_state_dir> if not already correct. Same naming convention as token vars (step 4) — suffix _STATE_DIR instead of _BOT_TOKEN.<CHANNEL_UPPERCASE>_STATE_DIR → <absolute_state_dir> in .claude/settings.local.json (takes effect on next restart)."If token already configured: also run step 6 before proceeding to step 5.
If Skip: print the manual command:
echo '<TOKEN_VAR>=your-token' > <state_dir>/.env && chmod 600 <state_dir>/.env
Then proceed to step 5 without a token (pairing will be skipped in step 5).
If no token is configured (skipped in step 4): print restart instructions and stop:
Restart Claude Code with channels active once you've added your token:
- With hermit:
hermit-start(passes--channelsautomatically)- Manual:
claude --channels plugin:<channel>@<marketplace>(use the same<marketplace>resolved in step 3 —claude-plugins-officialfor built-in channels, orchannels.<channel>.marketplacefor third-party plugins.)
If token is configured: check whether the channel is already active in the current session by checking if the channel's reply tool is available. If active, skip the restart prompt and go straight to the pairing question batch.
If not active, display:
Token saved. Restart Claude Code to activate the channel:
- With hermit:
hermit-start(passes--channelsautomatically)- Manual:
claude --channels plugin:<channel>@<marketplace>(use the same<marketplace>resolved in step 3.)After restarting, DM your bot — it will reply with a 6-character pairing code.
Then ask:
questions: [
{
header: "Pairing",
question: "Channel state?",
options: [
{ label: "Already paired", description: "Just verify access.json" },
{ label: "Ready to pair", description: "Restarted, DM'd the bot, have the 6-char code" },
{ label: "Skip", description: "I'll pair later" }
]
}
]
/claude-code-hermit:channel-setup again after restarting to complete pairing."Pairing flow:
Ask with AskUserQuestion:
questions: [
{
header: "Pairing code",
question: "Paste the 6-character code your bot replied with:",
options: [
{ label: "Skip", description: "Pair later" }
]
}
]
If code provided (via Other):
/<channel>:access pair <code> — include the state dir hint in the message to the LLM running the tool: "save access.json to <state_dir>/ not ~/.claude"/<channel>:access policy allowlistIf Skip: "DM the bot later, then run /<channel>:access pair <code> and /<channel>:access policy allowlist." Stop.
Check if access.json exists at <state_dir>/access.json.
~/.claude/channels/<channel>/access.json. If found there, move it:
mkdir -p <state_dir>
mv ~/.claude/channels/<channel>/access.json <state_dir>/access.json
Confirm: "Moved access.json to <state_dir>/."/<channel>:access pair <code> after DMing your bot."If access.json is verified, continue to step 6b.
Once access.json is at <state_dir>/access.json (§6), set sensible delivery defaults the operator hasn't customized.
Skip this step if the current channel is imessage. Otherwise:
<state_dir>/access.json. If ackReaction is already a non-empty string, skip — don't overwrite operator customization./<channel>:access set ackReaction 👀 — save access.json to <state_dir>/, not ~/.claude
👀 works on Discord (any unicode emoji accepted) and is in Telegram's fixed reaction whitelist. Operators get an emoji on their inbound DM as soon as the bot receives it — fills the gap after the 5–10s typing indicator times out. Idempotent: re-running channel-setup leaves customized values alone.
Skip this step if the current channel is imessage, or if access.json is not present at <state_dir>/access.json (note: "Pairing didn't complete — skipping group setup.").
AskUserQuestion — label and prompt vary by channel:
discord: header "Server channel" — "Want the hermit to also listen in a Discord server channel? Channel ID: enable Developer Mode in Discord settings → right-click the channel → Copy Channel ID."telegram: header "Group chat" — "Want the hermit to also listen in a Telegram group? Group ID: forward a message from the group to @userinfobot or use @RawDataBot. Group IDs are negative integers (e.g. -1001234567890).""Yes — add a channel" (discord) / "Yes — add a group" (telegram) with ID captured via Other; "Skip — DMs only".Other; each subsequent ID from step 3c's Other — loop until "Done"):
a. Ask with AskUserQuestion (header: "Mention required") for this ID:
"Yes — require @mention" (default — safer for noisy channels)"No — respond to all messages"
b. Run the slash command directly, with the state-dir hint (same pattern as §6b):"Yes — require @mention": /<channel>:access group add <channelId> — save access.json to <state_dir>/, not ~/.claude"No — respond to all messages": /<channel>:access group add <channelId> --no-mention — save access.json to <state_dir>/, not ~/.claude
c. Ask with AskUserQuestion (header: "Add another?") — "Yes — add another" with the next ID via Other; "Done — continue". On "Done — continue": exit the loop.Read after the loop): open <state_dir>/access.json. For each ID added in step 3, confirm groups.<channelId> is present with the expected requireMention value. For any missing: "Group entry didn't land — run /<channel>:access group add <channelId> manually after setup." Do not error. Then proceed to §7.Channel setup complete!
Channel: <channel>
Plugin: installed (--scope local)
Token: configured (<state_dir>/.env)
Paired: yes / skipped
Server channels: <id1> (mention: yes/no), <id2> (mention: no) / skipped
State dir: <state_dir>
hermit-start passes --channels automatically on next boot.
If anything was skipped, list the remaining steps.
data-ai
Initializes or resumes a work session. Loads context from OPERATOR.md and SHELL.md, orients the agent, and establishes what to work on. Use at the beginning of every work session.
tools
Evolves hermit configuration and templates after a plugin update. Detects version gaps, presents new features, walks through new settings. Run after updating the plugin.
testing
Initializes the autonomous agent in the current project. Creates the state directory, templates, OPERATOR.md, and config.json. Appends session discipline to CLAUDE.md. Detects installed hermits. Run once per project, like git init.
tools
Generates Docker scaffolding and walks the operator through the full deployment — token setup, build, start, MCP plugin configuration, workspace trust, and verification. Offers to back up and overwrite existing Docker files. Run after /hatch.