From claude-code-hermit
Runs background watchers for logs, files, events, or processes via CC Monitor tool, streaming stdout as zero-token-cost conversation notifications. Supports ad-hoc commands, polling, streaming, and config watches.
npx claudepluginhub gtapps/claude-code-hermit --plugin claude-code-homeassistant-hermitThis skill uses the workspace's default tool permissions.
Run background event watchers using the CC Monitor tool. Each stdout line from
Sends dual-channel notifications to Telegram (HTML) and Pushover (plain text) on watchexec file changes or process crashes. Use for monitoring processes and alerting on restarts.
Watches files and directories for changes with event callbacks, pattern filtering, and command execution on changes. Useful for development automation, live reloading, or monitoring needs via /watch.
Enforces protocol for safe terminal command execution: announce intent, read output, detect errors, poll status, stop on failures. Use for any run_command.
Share bugs, ideas, or general feedback.
Run background event watchers using the CC Monitor tool. Each stdout line from the subprocess becomes a conversation notification. Silence costs zero tokens.
Two classes:
tail -f, WebSocket, fswatch). Truly event-driven./claude-code-hermit:watch <instruction> — start ad-hoc (poll, default 5m interval)
/claude-code-hermit:watch <stream-command> — start ad-hoc stream
/claude-code-hermit:watch start — register all enabled config watches
/claude-code-hermit:watch stop [id] — stop by id (or auto if 1 active)
/claude-code-hermit:watch stop --all — stop all watches
/claude-code-hermit:watch status — list active watches from registry
All active watches are tracked in .claude-code-hermit/state/monitors.runtime.json.
This is the sole source of truth — not SHELL.md.
{
"monitors": [
{
"id": "deploy-errors",
"task_id": "bmg9y1le3",
"description": "errors in deploy.log",
"started_at": "2026-04-12T15:00:00Z",
"source": "config",
"class": "stream"
}
],
"last_cleared": "2026-04-12T15:00:00Z"
}
SHELL.md ## Monitoring entries are a journal only — no code path reads
them for decisions. Start/stop decisions read from the runtime registry.
.claude-code-hermit/sessions/SHELL.md must exist).
If none: "No active session. Run /claude-code-hermit:session first."adhoc-<epoch>-<4char-random> (e.g., adhoc-1744460400-a3f2).
Timestamp + random suffix avoids collisions across sessions.while true; do <check-command> && echo "<brief-event-description>"; sleep <interval_secs>; done
description: the operator's instruction text (shown in every notification)command: the constructed commandtimeout_ms: 300000 (ignored when persistent, but always required)persistent: true (runs until stopped or session ends)state/monitors.runtime.json (create if missing: {"monitors": [], "last_cleared": null})monitors[] with source: "adhoc"## Monitoring: - [ACTIVE] <instruction> (started HH:MM)/watch start)Called automatically by session-start (step 11b). Can also be called manually.
config.json → monitors[], filter enabled: truestate/monitors.runtime.jsonid is NOT already in the registry:
a. Resolve command: Replace the literal string ${CLAUDE_PLUGIN_ROOT} with
the actual env var value (available at skill execution time inside CC context;
NOT available in Monitor subprocess). If the var is unset, log a warning and
skip that watch.
b. Invoke Monitor tool:
description: from config entrycommand: the resolved command stringtimeout_ms: config.timeout_ms ?? 300000persistent: config.persistent ?? true
c. Append to registry with source: "config" and the returned task_id## Monitoring:
[HH:MM] Watches registered: <id1>, <id2> (<N> total)--all flag)stop <id>: Look up task_id in registry → TaskStop → remove entry from registry → update SHELL.md [ACTIVE] to [STOPPED]stop (no id):
source: "adhoc")--all)stop --all: For each entry in registry, call TaskStop with its task_id.
Clear all entries from registry. Log to SHELL.md.Note: If TaskStop returns an error for a given task_id (the watch already
died), remove the entry from the registry anyway. A dead watch's entry is stale.
state/monitors.runtime.jsonActive watches:
ID SOURCE CLASS STARTED DESCRIPTION
deploy-errors config stream 15:00 errors in deploy.log
adhoc-... adhoc poll 16:30 check error rate in app metrics
When a Monitor subprocess exits on its own (timeout, script crash, or clean exit), CC sends a completion notification into the conversation. On seeing this:
task_id from the notification against the runtime registry[HH:MM] Watch <id> exitedIf the notification is missed (compaction, context pressure), the stale entry is harmless. The next session start clears the registry unconditionally.
timeout_ms even when
persistent: true (the tool schema requires it; the value is ignored).$CLAUDE_PLUGIN_ROOT is NOT available in Monitor subprocess. Resolve it at
registration time. $PWD is the project root in the subprocess.grep --line-buffered is required in pipes. Without it, pipe buffering can
delay events by minutes.inotifywait (from inotify-tools, included in the hermit base image) instead of fswatch (macOS-only). Example stream command: inotifywait -m -r --format '%w%f %e' -e modify,create,delete src/.config.json monitors only apply at the next session start
or after a manual /watch stop <id> + /watch start./session-close: session-close stops all watches before archiving. The
registry is cleared.