Skip to content

Widen the repo to monitors - #6

Merged
jackyraimond merged 5 commits into
mainfrom
add-monitors
Aug 13, 2026
Merged

Widen the repo to monitors#6
jackyraimond merged 5 commits into
mainfrom
add-monitors

Conversation

@jackyraimond

Copy link
Copy Markdown
Collaborator

Adds monitors as a second component type alongside hooks.

What a monitor is

A shell command that runs in the background for the whole session. Every line it prints to stdout reaches Claude as a notification.

It is the mirror image of a hook. A hook reacts to something Claude does — it fires on a lifecycle event and can block, format or record. A monitor reacts to something the world does, and tells Claude about it without anyone asking it to look:

[
  { "name": "shopware-log", "command": "tail -F var/log/dev.log",
    "description": "Shopware runtime errors" }
]

You edit a plugin, an exception lands in the log, and Claude knows — instead of you noticing later and pasting it in. Same for a failing Vite build, a container that died, or a deploy that finished.

Why here and not a new repo

Because they share this repository's trust model, which is what CONTRIBUTING is actually written around. Both run unsandboxed, automatically, with your credentials. A monitor arguably deserves more scrutiny than a hook, not less: it runs for the entire session and feeds its output straight into Claude's context.

Grouping by trust rather than by taxonomy also settles where the other components go. Skills and agents only influence what Claude says, with no automatic execution, so they belong in AiOpsCommunity/skills. MCP and LSP are a different thing again — mostly wrapping third-party servers — and are deliberately not addressed here.

Layout

Exactly parallel to hooks, because monitors/monitors.json is a default location Claude Code discovers on its own, just like hooks/hooks.json:

monitors/
├── _template/
└── <monitor-name>/
    ├── .claude-plugin/plugin.json
    ├── monitors/monitors.json     # array of monitor entries
    ├── scripts/<script>
    └── README.md

Tooling

  • validate.sh loops over both kinds, sharing the manifest and README checks. Monitor-specific: array shape, required fields, duplicate names, valid when values, ${user_config.*} in a command (which Claude Code rejects for shell commands), personal paths, path escapes, and bundled script permissions. A monitor with no bundled script — a bare tail -F — is valid and reported as such.
  • pr-policy.sh now enforces one hook or one monitor per PR, and blocks a PR that touches both.
  • review-flags.sh scans monitor scripts too.
  • CI validates monitor manifests with claude plugin validate --strict.

The rule the template leads with

Print only what deserves to interrupt. Every line costs context and pulls Claude's attention. A monitor that forwards a whole log turns a session into noise, and noise is how a useful monitor gets uninstalled. The template script filters in the script, before printing, and the README says to ask of every line: would I tap someone on the shoulder for this?

Constraints, stated up front

Documented in the template README rather than left to be discovered:

  • Monitors run only in interactive CLI sessions.
  • They run unsandboxed, at hook trust level.
  • ${user_config.*} is not substituted into a monitor command, and monitor processes do not receive CLAUDE_PLUGIN_OPTION_<KEY>. A monitor needing configuration reads a file its script owns.
  • Disabling a plugin mid-session does not stop a running monitor.
  • Monitors are an experimental component; the schema may change between releases.

Testing

./scripts/validate.sh, ./scripts/pr-policy.sh and claude plugin validate --strict all pass.

18 validator scenarios, each mutating a real monitor plugin and asserting the build fails with the right message: missing description, missing command, duplicate names, an invalid when, a valid on-skill-invoke: when, ${user_config.*} in a command, a personal path, a path escaping the plugin, a non-executable script, monitors.json that is not an array, an empty array, a missing README, a missing marketplace entry, a mismatched plugin.json name, and a deleted template. Plus two positives: a monitor with no bundled script passes, and hooks still validate.

9 pr-policy scenarios: one hook passes, one monitor passes, a hook and a monitor together fails, two monitors fails, two hooks still fails, an unregistered monitor fails, a monitor with no README row fails, a monitor plus a template change fails, and an infrastructure-only change passes.

Suggested next step

Land this, then a first real monitor as a separate PR to set the example. A log tail for Shopware or Symfony is the obvious candidate, since it demonstrates the filtering discipline better than anything abstract.

🤖 Generated with Claude Code

A monitor is the mirror image of a hook. A hook reacts to something
Claude does; a monitor reacts to something the world does. It runs a
command in the background for the whole session, and every line it
prints to stdout reaches Claude as a notification — so Claude learns
about a failing build or an exception in a log without anyone asking it
to look.

They belong in this repository because they share its trust model, not
because they are both plugin components. Both run unsandboxed,
automatically, with the user's credentials, which is what CONTRIBUTING
is written around. Skills and agents only influence what Claude says and
stay in the skills repo.

The layout mirrors hooks exactly: monitors/<name>/monitors/monitors.json
is a default location Claude Code discovers on its own, just like
hooks/hooks.json.

Tooling now covers both kinds:

- validate.sh loops over hooks/ and monitors/ with shared manifest and
  README checks. Monitor-specific checks cover the array shape, required
  fields, duplicate names, valid `when` values, ${user_config.*} in a
  command (which Claude Code rejects for shell commands), personal
  paths, path escapes, and bundled scripts. A monitor with no bundled
  script, such as a bare `tail -F`, is fine and says so.
- pr-policy.sh enforces one hook *or* one monitor per PR, and blocks a
  PR touching both, since a reviewer should have one thing in front of
  them.
- review-flags.sh scans monitor scripts too.
- CI validates monitor manifests with the official validator.

The template carries the contract that matters: stdout is a message to
Claude, so print only what deserves to interrupt. A monitor that
forwards a whole log turns a session into noise, and noise is how a
useful monitor gets uninstalled.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Watches the log files you name and reports only the lines matching the
patterns you chose. A request fails somewhere in the stack, the reason
lands in a log, and Claude is told — instead of you noticing later and
pasting it in.

Stack-agnostic by construction. Paths are relative to the project and
missing files are skipped silently, so one user-level config covers
every project: list the log locations of every framework you use, and in
each project only the ones that exist are watched. Symfony, Laravel and
Rails can sit in the same config without interfering.

The config lives in user scope, not in the project, and that is the
point rather than a detail. A watch list taken from a file inside the
repository would let any repository you clone point the monitor at
~/.ssh/id_rsa with a pattern of "." and read a private key straight into
Claude's context. Monitors receive no CLAUDE_PLUGIN_OPTION_* and cannot
use ${user_config.*}, so a file the script owns under the plugin data
directory is both the documented way to configure one and the safe one.
As a second line of defence the script refuses credential-shaped paths
outright and says so rather than failing quietly.

Most of the script is restraint, because a monitor that floods a session
gets uninstalled: an empty match list is rejected since "print
everything" is the one thing a monitor must not do, consecutive
duplicates are dropped, output is capped at five lines a minute per file
with a single summary when the window clears, long lines are truncated,
and only lines written after startup are considered.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@jackyraimond jackyraimond mentioned this pull request Aug 12, 2026
KainDitmer and others added 3 commits August 13, 2026 08:26
Three conflicts, plus one the merge got wrong on its own:

- marketplace.json: main's four hooks kept, log-watch appended after them, so
  the file reads hooks-then-monitors like the README does. The catalog
  description now names monitors too, since this branch is what adds them.
- README repo layout: both sides edited the same tree lines. main's optional
  skills/ entry belongs to the hooks subtree; the monitors subtree keeps its
  own wording.
- validate.sh: both sides added functions in the same spot; check_monitors,
  check_manifest and check_bundled_skills are all kept.
- git placed main's check_bundled_skills() call inside the orphan loop at the
  bottom, where base and name are leftovers from the loop above. Moved it into
  the per-plugin loop next to check_config().

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The template rule exists so that changing a starting point other people
already build on gets its own review. A template that does not exist at the
base is not that: it is a new kind arriving, and reviewing a starting point
without the first thing built from it is guesswork.

So the check now distinguishes the two. Editing an existing template beside a
component still fails; adding one passes and says so.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@jackyraimond
jackyraimond merged commit 4275f3a into main Aug 13, 2026
5 checks passed
@jackyraimond
jackyraimond deleted the add-monitors branch August 13, 2026 08:35
jackyraimond added a commit that referenced this pull request Aug 13, 2026
PR #6 landed, so the monitors scaffolding this branch carried is now on main
and drops out of the diff; what is left is the ci-watch monitor itself.

Both conflicts were the same shape as everywhere else this week: one entry
added on each side, in marketplace.json and in the README monitors table. All
six plugins kept, hooks before monitors, ci-watch before log-watch.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants