Fix an AMG Hermes agent that is silent on Slack because its SLACK_BOT_TOKEN/SLACK_APP_TOKEN are missing or wrong in the profile .env — including recovering LOST tokens from old session transcripts without asking Joe to regenerate them at api.slack.com. Use when an agent's service is running but it never answers Slack messages (Autumn case, 2026-07-14).
Install
npx skillscat add joecastelino/jay-skill-pack/hermes-slack-token-recovery Install via the SkillsCat registry.
Hermes Agent Slack Token Recovery
An agent that boots fine but is SILENT specifically on Slack (Telegram works) usually
has NO Slack tokens loaded — not a billing problem (that's hermes-agent-provider-switch)
and not the App-Home-disabled banner (that's hermes-slack-slash-commands).
Step 1 — Confirm the gap (don't trust gateway_state.json)
systemctl --user status hermes-gateway-<profile>.service --no-pager
grep -c "^SLACK_BOT_TOKEN=" /home/itadmin/.hermes/profiles/<profile>/.env
tr '\0' '\n' < /proc/<MainPID>/environ | grep -c SLACK- Journal showing ONLY Telegram warnings and zero "slack" lines = Slack platform never initialized.
- TRAP:
gateway_state.jsoncan showslack: connectedwith a STALEupdated_at
from weeks earlier. Check the timestamp — an old date means it's a leftover, not live. channel_directory.json+platforms/pairing/slack-approved.jsonsurviving with Slack
entries proves Slack WAS configured before → tokens were removed (Autumn's were removed
Jun 4 on Joe's disconnect request), not never-set.
Step 2 — Recover the tokens from session transcripts (no Slack dashboard needed)
Old setup sessions in /home/itadmin/.hermes/sessions/session_*.json contain the raw
tokens from when the app was first wired. Use raw Python IO — read_file/execute_code
stdout MASKS tokens, but you can still test them in-memory:
import re, glob, json, urllib.request
cands = {}
for f in glob.glob("/home/itadmin/.hermes/sessions/session_2026*.json"):
t = open(f, errors="replace").read()
for m in re.finditer(r'(xox[bp]-[A-Za-z0-9-]{50,}|xapp-[A-Za-z0-9-]{60,})', t):
cands.setdefault(m.group(1), set()).add(f)Then identify WHOSE token each is, without printing them:
- xoxb (bot): POST
https://slack.com/api/auth.testwithAuthorization: Bearer <tok>
→{ok, user, team, bot_id}. Theuserfield names the agent (e.g.autumn). - xapp (Socket Mode): POST
https://slack.com/api/apps.connections.open
→ok: true= valid. Match it to the right app by the app ID embedded in the
token itself:xapp-1-A0BXXXXXXXX-.... (Autumn = A0B7YEHJBNX; Jay = A0B8EKPGX0R;
Jeff/amazon-agent = A0BH9AXT1RU; Don = A0B8XBMAD2P.) - Ignore short (<50 char) or doc-example tokens ending in things like
123456— invalid. - Slack tokens don't expire on their own; a token removed from .env months ago still works
unless someone hit Revoke in the Slack dashboard.
Step 3 — Restore and restart
Backup .env first, append (raw Python write, chmod 600):
SLACK_BOT_TOKEN=xoxb-...
SLACK_APP_TOKEN=xapp-1-A0B...-...
SLACK_ALLOWED_USERS=U0B7UBQ8Y3T # Joe; add others from platforms/pairing/slack-approved.jsonsystemctl --user restart hermes-gateway-<profile>.serviceStep 4 — Verify
Wait ~20s, then check gateway_state.json shows slack: connected with a FRESHupdated_at (this is the real readiness signal — the journal may print nothing for
Slack on success). Then have Joe ping the bot.
Step 5 — Home-channel prompt after reconnection (Autumn, 2026-07-15)
A freshly reconnected agent may greet the first message with:
":mailbox_with_mail: No home channel is set for Slack... Type /sethome..."
Don't make Joe run /sethome — set it directly in the profile .env
(home channel var, e.g. SLACK_HOME_CHANNEL=D0B86M092D7 — Joe's DM with that bot;
find the DM channel ID via conversations.list types=im with the bot's xoxb, matching
Joe's user U0B7UBQ8Y3T) and restart the gateway. Autumn's home = D0B86M092D7.
The home channel is where cron results and cross-platform messages get delivered.
Identifying an UNKNOWN Slack user ID (Joe says "fix @U0Bxxxxx", 2026-07-14)
When Joe mentions a broken bot by Slack ID and you don't know which agent it is:
users.infowill FAIL — none of the fleet bot tokens haveusers:readscope
(they only have app_mentions/chat:write/im/channels/groups/files/commands).- Identify by ELIMINATION instead:
- For every profile
.envwith a SLACK_BOT_TOKEN, callauth.test→ each returns
its ownuser_id. Known fleet (2026-07-14): Jay=U0B8ANZEYA2, Don=U0B8XBXUTA7,
Jeff=U0BHD8TK5FT, Autumn=U0B7PC55JDD. If the mystery ID isn't in that list,
it's one of the token-less profiles (Walter/base, Stacey/email-agent, Ralph,
Solo, Arnold, Tink, Dori). - Check which gateways actually have Slack live:
for pid in $(pgrep -f hermes.*gateway); do tr '\0' '\n' </proc/$pid/environ | grep -q SLACK_BOT_TOKEN && echo $pid HAS-SLACK; done
(env var presence in /proc beats gateway_state.json, which can be stale). - Grep the whole box for the ID (
.hermesconfigs, pairing files, channel_directory,
ALL session transcripts). Zero hits = that app was never wired from this machine
→ no tokens exist on disk → recovery Step 2 will find nothing; go straight to
asking Joe which agent it is + regenerating tokens at api.slack.com.
- For every profile
- Report to Joe: list who IS live (verified IDs) and ask which agent the ID maps to —
don't guess the profile; writing tokens into the wrong profile makes it reply as
the wrong bot.
Identifying an UNKNOWN Slack user/bot ID (e.g. Joe pastes <@U0Bxxxxxxxx>)
Our fleet bot tokens do NOT have users:read — users.info returns missing_scope,
so you cannot look the ID up directly. Instead:
- Audit the fleet first: run
auth.testwith every profile's SLACK_BOT_TOKEN
(from/home/itadmin/.hermes/profiles/*/.env) — each returns{user, user_id, bot_id}.
If the mystery ID matches one, that's the agent. Also check which RUNNING gateways
actually have Slack loaded:grep SLACK /proc/<pid>/environ(tr '\0' '\n') — a token
in .env but not in the live process env means restart needed. - If no profile matches, ask Joe for the app's tokens (api.slack.com/apps →
OAuth & Permissions for xoxb).auth.teston the pasted xoxb instantly revealsuser(bot name) +user_id— this is hownumber_5= U0B8EMPBFU4 (app A0B8AT7CJ2W)
was identified 2026-07-14. Validate a pasted xapp viaapps.connections.open. - Known fleet Slack IDs: jay=U0B8ANZEYA2, don_ready=U0B8XBXUTA7, jeff=U0BHD8TK5FT,
autumn=U0B7PC55JDD, number_5=U0B8EMPBFU4 (no profile on this box as of 2026-07-14 —
its "install" was an abandonedhermes authin the secondary WSLUbuntudistro).
Joe = U0B7UBQ8Y3T. - If the agent lived on a "different install", check OTHER WSL distros on this same
computer → skillwsl-cross-distro-hermes-discovery.
Pitfalls
- read_file / patch / printed stdout mask
xox*tokens — do ALL token handling inside
one execute_code block with rawopen()IO; never round-trip a token through a
masked view or you'll write the mask to disk. - Multiple agents' tokens appear in the same transcripts — ALWAYS verify identity via
auth.test(userfield) and theA0B...id inside the xapp token before writing.
Writing another agent's bot token = agent replies as the wrong bot. - If NO valid token is found in transcripts, fall back to regenerating at
api.slack.com/apps/ (OAuth & Permissions for xoxb; Basic Information →
App-Level Tokens for xapp, scopeconnections:write) — needs Joe's browser session. - If tokens are present and valid but the bot still won't take DMs, check the App Home
Messages Tab banner case → skillhermes-slack-slash-commands.