Widen the repo to monitors - #6
Merged
Merged
Conversation
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>
Merged
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>
Merged
Add `log-watch` monitor
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
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.jsonis a default location Claude Code discovers on its own, just likehooks/hooks.json:Tooling
validate.shloops over both kinds, sharing the manifest and README checks. Monitor-specific: array shape, required fields, duplicate names, validwhenvalues,${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 baretail -F— is valid and reported as such.pr-policy.shnow enforces one hook or one monitor per PR, and blocks a PR that touches both.review-flags.shscans monitor scripts too.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:
${user_config.*}is not substituted into a monitor command, and monitor processes do not receiveCLAUDE_PLUGIN_OPTION_<KEY>. A monitor needing configuration reads a file its script owns.Testing
./scripts/validate.sh,./scripts/pr-policy.shandclaude plugin validate --strictall pass.18 validator scenarios, each mutating a real monitor plugin and asserting the build fails with the right message: missing
description, missingcommand, duplicate names, an invalidwhen, a validon-skill-invoke:when,${user_config.*}in a command, a personal path, a path escaping the plugin, a non-executable script,monitors.jsonthat is not an array, an empty array, a missing README, a missing marketplace entry, a mismatchedplugin.jsonname, 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