Skip to content
Automation
Skill

/watch

Background watching via the CC Monitor tool. Starts subprocesses that stream events as conversation notifications — zero token cost when quiet. Supports declared config watches (auto-registered on session start) and ad-hoc operator-invoked watches.

From plugin
claude-code-hermit
7488 skills11 agents
Install
$ npx -y skills add gtapps/claude-code-hermit --skill watch --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/watch

Context preview

The summary Claude sees to decide when to auto-load this skill.

Background watching via the CC Monitor tool. Starts subprocesses that stream events as conversation notifications — zero token cost when quiet. Supports declared config watches (auto-registered on session start) and ad-hoc operator-invoked watches.

SKILL.md

watch.SKILL.md
name: watch
description: Background watching via the CC Monitor tool. Starts subprocesses that stream events as conversation notifications — zero token cost when quiet. Supports declared config watches (auto-registered on session start) and ad-hoc operator-invoked watches.

Record notes only inside an open record's turn, using `bun ${CLAUDE_PLUGIN_ROOT}/scripts/task.ts note .claude-code-hermit <id>` with the note on stdin. Otherwise skip record notes. Never edit a task file directly.

Watch

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:

  • **Stream:** Source pushes events (`tail -f`, WebSocket, fswatch). Truly event-driven.
  • **Poll:** Script checks on interval, emits only on change. Same polling model, less noise.

Usage

/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 session <name|glob> [note] — watch local session(s) until their next idle notice
/claude-code-hermit:watch notice <text>              — [internal] handle a watched-session notice
/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

Runtime Registry

All active watches are tracked in `.claude-code-hermit/state/monitors.runtime.json`. This is the **sole source of truth**.

{
  "monitors": [
    {
      "id": "deploy-errors",
      "task_id": "bmg9y1le3",
      "command": "tail -f deploy.log",
      "timeout_ms": 1800000,
      "description": "errors in deploy.log",
      "started_at": "2026-04-12T15:00:00Z",
      "source": "config",
      "class": "stream"
    },
    {
      "id": "session-migration-1775991600-b7c1",
      "description": "database migration",
      "target": "migration",
      "started_at": "2026-04-12T15:00:00Z",
      "source": "adhoc",
      "class": "peer-idle"
    }
  ],
  "last_cleared": "2026-04-12T15:00:00Z"
}

Start/stop decisions read from the runtime registry.

Plan

Starting an ad-hoc watch

1. Parse instruction + optional interval from operator message. Default interval: 5m. 3. Generate id: `adhoc-<epoch>-<4char-random>` (e.g., `adhoc-1744460400-a3f2`). Timestamp + random suffix avoids collisions across sessions. 4. Determine command shape:

  • If instruction is a shell command (contains pipes, flags, or path): use as-is
  • If instruction is a natural language description: wrap in a poll loop:
     while true; do <check-command> && echo "<brief-event-description>"; sleep <interval_secs>; done

5. Invoke Monitor tool with all 3 required params:

  • `description`: the operator's instruction text (shown in every notification)
  • `command`: the constructed command
  • `timeout_ms`: `min(config.timeout_ms ?? 1800000, 1800000)`

6. Read `state/monitors.runtime.json` (create if missing: `{"monitors": [], "last_cleared": null}`) 7. Append entry to `monitors[]` with `source: "adhoc"`, the returned `task_id`, and the exact `command`, `description` and `timeout_ms` used for registration. 8. Write registry back 9. When running inside an open task record, note the watch with its id:

   bun ${CLAUDE_PLUGIN_ROOT}/scripts/task.ts note .claude-code-hermit <id> <<'HERMIT_LINE'
   - [ACTIVE] <instruction> (started HH:MM)
   HERMIT_LINE

Starting a session watch (`/watch session <name|glob> [note]`)

1. If `<name>` contains `*` or `?`, take the **glob branch** below instead of resolving an exact name.

Otherwise resolve `<name>` with `ListAgents`. The row must be a Claude Code session on this machine — `notify_when_idle` covers nothing else, so a cloud/remote agent or an in-process subagent row does not qualify. If no such row matches, answer `No session named <name> is reachable from here.` and do not write the registry.

**Glob branch:** match the glob against the session *name* of every `ListAgents` row that qualifies by the same rule — whole name, case-sensitive, matching only the name that opens the row and not its trailing `[ref]`, kind, status, or tmux address. `ListAgents` omits this session from its own listing, so no self-exclusion is needed. Skip a match that already has a live `peer-idle` entry for that target, and say which ones you skipped. No match: answer `No session matching <name> is reachable from here.` and do not write the registry. One or more matches: show the operator each matched name with the live status its row reports (`idle`, `busy`, `waiting`, `shell`; some rows carry none, so show the name alone there) and wait for confirmation before doing anything else — an already-idle match fires its notice as soon as it is subscribed. On confirmation, run steps 2–5 below once per matched name, each producing its own registry entry; do step 3's relay check on the first match before subscribing to the rest, and if it comes back operator-only, stop there and decline the whole set rather than subscribing the others. 2. Call `SendMessage` with `to: <name>` and `notify_when_idle: true`. Omit `message`: this is a pure subscription, costs the watched session nothing, and fires immediately if it is already idle. 3. Read the tool result: it says whether the notice will be shown to you or only to the operator. When it is operator-only (this session holds peer messages for approval, e.g. under `bypassPermissions`), no relay is possible — say so plainly instead of claiming the watch is live, and do not write the registry. 4. Generate id `session-<name>-<epoch>-<4char-random>` — same time

Read more
Ships withclaude-code-hermit

If you know Claude Tag, the idea will feel familiar: hand Claude work through a channel, such as Discord, Telegram, or your custom integration, and get results back there.

Get the whole plugin

Other skills on claude-code-hermit.