- Not set up yet (local/tmux)? Run
/claude-code-hermit:channel-setup— it installs the plugin, writes the token, and guides pairing. Requires Bun. - Verify Claude Code was started with
--channels. Check boot script output for[hermit] Channels: discord. If hermit-start printed a bun or token warning, that channel was skipped. - Check bot token and bot online status.
- Stale token in settings.local.json: If
.claude/settings.local.jsonhasDISCORD_BOT_TOKENorTELEGRAM_BOT_TOKENin itsenvkey, it overrides the token file at.claude.local/channels/<plugin>/.env. Remove the token from settings.local.json — it should only live in the channel's.envfile.hermit-startcleans these automatically on boot, but if the token was added manually or by a previous channel plugin setup, it may persist. - Verify tmux session:
tmux ls - If Docker
--network=none, channels can't work. - Telegram has no message history — messages sent while your hermit was down are lost.
Hermit uses proactive channel sends for heartbeat alerts, morning briefs, and idle transition notifications. If messages aren't arriving:
- Check
channels.<name>.allowed_usersin config.json: Proactive sends require exactly one allowed user for the active channel. If absent, empty, or multiple users configured, there's no unambiguous outbound target. Add your user ID via/hermit-settings channels. - Check
channels.<name>.dm_channel_id: Outbound Discord DM notifications require the DM channel ID, not the user ID. This is learned automatically from the first inbound message. If it'snull, send any message to the bot to populate it. - Verify the
replytool is available: Channels must be started with--channelsfor the plugin'sreplytool to be accessible. Check boot output. channel-send-unavailablealert: If sends are failing, heartbeat records this as a deduped alert. Check SHELL.md Findings for the unsent message content.- Always-on vs interactive: In interactive mode, channel plugins may not be running. Proactive sends only work when Claude Code is launched with
--channels.
Plugin checks run during idle reflection via reflect. If accepted plugins aren't being invoked:
- Check
plugin_checksin config.json: Must have entries withenabled: true. View with/hermit-settings plugin-checks. - Check reflection cadence: Reflection runs every 4+ hours during idle. If the hermit is always
in_progress, plugin checks won't fire (they're idle-only). - Unavailable suppression: If a plugin skill is missing or uninstalled, the check is suppressed for
interval_days. Checkstate/reflection-state.jsonforlast_unavailable_at. - One per reflect: Only one plugin check runs per reflect invocation. If multiple are due, the oldest fires first.
- Check
AGENT_HOOK_PROFILEinconfig.jsonenv(written to.claude/settings.local.jsonat boot). Core hooks needstandardorstrict. Hermit hooks (e.g., git-push-guard) needstrict. View/change with/hermit-settings env. - Validate hooks.json:
cat hooks/hooks.json | python3 -m json.tool - Test manually:
echo '{}' | node scripts/cost-tracker.js - Hooks may not fire for subagent tool calls — see Architecture.
- Workspace trust: Run
claudeinteractively once first and accept the trust prompt. Then restart headless. - Orphaned SHELL.md: A crash left an active session. Attach to tmux and choose resume/new, or delete
sessions/SHELL.md. - Auth expired: Check with
claude --version. Runclaude /loginif needed.
- Check
CLAUDE_AUTOCOMPACT_PCT_OVERRIDEinconfig.jsonenv(default 50). Adjust with/hermit-settings env. - Check heartbeat interval — 5m with Opus is expensive. Default is 2h; use 15m-30m only if you need faster monitoring.
- Check if watches are running with short intervals (
/claude-code-hermit:watch stop). - Review SHELL.md size — bloated files cost tokens on every read.
- Use
/costto check current session spend.
- Reflection runs at task boundaries, during heartbeat idle checks, and at end of day. If you're closing sessions before finishing work, reflection may not trigger.
- Check that
idle_behavioris set to"discover"in config — without it, idle-time reflection won't fire. - If you just started using Hermit, give it a few sessions to build up memory. Proposals come from patterns, and patterns take repetition.
- Check proposals exist:
ls .claude-code-hermit/proposals/PROP-*.md
- Verify location:
.claude-code-hermit/OPERATOR.md - 50-line rule: The SessionStart hook reads only the first 50 lines. Critical context must be at the top.
- Verify the SessionStart hook is registered in
hooks/hooks.json.
SHELL.md from a crashed session persists. Choose resume or start new (generates a partial report). If this keeps happening, check system stability, rate limits, disk space, and consider Docker for auto-restart.
- Check the
routinesarray in config.json — each routine must haveenabled: true. - Routines are managed by the routine watcher, which runs in its own tmux window. Check it:
tmux select-window -t <session>:routines. - Each routine fires once per matching time slot — check
/tmp/hermit-routines-<session>for dedup state (format:YYYY-MM-DDTHH:MM|routine-id). - Verify your timezone is set correctly:
/claude-code-hermit:hermit-settings timezone. The routine watcher readsconfig.timezoneand setsTZ=. - Check
state/runtime.json(session state) — if stuck onin_progress, routines are queued tostate/routine-queue.json(not skipped) and fire when session returns to idle. Inspect with:cat .claude-code-hermit/state/runtime.json | jq .session_state
- Check
idle_behaviorin config.json — must be"discover"for maintenance tasks."wait"only checks tasks and channels. - Your hermit must be in
idlestate (check SHELL.md status). Idle agency only runs between tasks. - NEXT-TASK.md pickup is gated by escalation level:
conservativeonly alerts,balancedauto-starts,autonomousruns fully unattended. - If no NEXT-TASK.md exists: idle agency picks up
IDLE-TASKS.mditems (first unchecked, capped byidle_budget), then falls back to reflection (every 4+ hours), then priority alignment via OPERATOR.md context.
- See "Routines Not Firing" above — the morning brief is a routine (
claude-code-hermit:brief --morning). - Verify channels work first — send "status" manually from your phone.
Reflect checks dismissed and deferred proposals before creating new ones. If you're still seeing re-suggestions:
- Run
/claude-code-hermit:hermit-evolveto ensure the latest reflect skill is active. - If significantly more evidence has accumulated since the dismissal, Hermit may intentionally revisit — this is by design.
A bloated SHELL.md costs tokens on every read. Keep it lean:
- Use
/compactbetween steps to free context. - The progress log should stay under ~30 entries. If it's growing beyond that, close the session and start a new one.
- The
session-diffhook auto-populates## Changed— don't manually list files. - If SHELL.md is already bloated, run
/claude-code-hermit:session-closeto archive it and start fresh.
Common causes:
- UID mismatch: The Dockerfile matches your host UID. If you're not UID 1000, rebuild after checking
id -u. The generated Dockerfile should handle this, but manual edits may break it. - Network issues during build:
apt-getornpm installfails. Check your network, proxy settings, and Docker DNS config. - npm permission errors: Claude Code installs globally. The Dockerfile sets
NPM_CONFIG_PREFIXfor theclaudeuser — if you modified the Dockerfile, ensure this is preserved. - Ubuntu 24.04 default user conflict: UID 1000 is taken by the default
ubuntuuser. The generated Dockerfile runsuserdel -r ubuntufirst — don't remove this line. - Rebuild after config changes: If you changed
docker.packagesin config.json, rebuild:docker compose -f docker-compose.hermit.yml build --no-cache
- Check plugin version:
cat .claude-plugin/plugin.json | grep version(or check the installed plugin path). - Check config version:
cat .claude-code-hermit/config.json | grep _hermit_versions. - If both match, there's genuinely nothing to upgrade. New features may have landed as skill changes (no config migration needed).
- If the plugin was updated but the marketplace cache is stale:
claude plugin marketplace add gtapps/claude-code-hermitto force refresh, then reinstall.
Check logs first:
.claude-code-hermit/bin/hermit-docker logsCommon causes:
- Auth expired:
hermit-docker loginto re-authenticate, thenhermit-docker restart. - Workspace trust not accepted: Attach once (
hermit-docker attach), accept the trust prompt, then detach (Ctrl+B, D). - Missing
.env: If using API key auth, ensure.envexists withANTHROPIC_API_KEYset.
Usually a UID mismatch between the host and the container user. The generated Dockerfile creates a claude user matching your host UID. If you changed your system user or are running on a different machine:
- Check your host UID:
id -u - Rebuild the image:
docker compose -f docker-compose.hermit.yml build --no-cache
Docker:
- Verify the channel plugin is installed inside the container:
hermit-docker attach, then check withclaude plugin list. - Check bot pairing: send a test message to the bot and watch the logs (
hermit-docker logs). - For Discord: ensure
channels.discord.state_diris set inconfig.json(e.g..claude.local/channels/discord) and the directory is bind-mounted indocker-compose.hermit.yml.hermit-startresolves relative paths and derivesDISCORD_STATE_DIRat boot. - For Telegram: ensure
channels.telegram.state_diris set and the bot token is in the state directory's.envfile.
Local/tmux:
- Run
/claude-code-hermit:channel-setupto verify and repair the full setup (bun, plugin, token, pairing, access.json location). - Check
hermit-startoutput for bun or token warnings — the channel is skipped if either is missing.