agentmonitors-setup
/agentmonitors-setup
Konfiguruje lokalny system monitorowania agentów Agent Monitors: instaluje CLI, tworzy monitor z zamiaru i sprawdza dostarczanie alertów.
- Autor
- mike-north ↗
- Repozytorium
- agentmonitors ↗
- Licencja
- MIT
- Ostatnia zmiana repozytorium
- 29.08.2026
Ocena i bezpieczeństwo
- Pliki w paczce
- 1
- Skrypty
- 0
- Komentarze HTML
- 0
- Adresy URL w SKILL.md
- 1
Brak sygnałów. Repozytorium zmienione 29.08.2026, bez odwołań do wycofanych modeli i API.
MIT, otwarta: można używać i zmieniać, z zachowaniem informacji o autorze.
Co robi i kiedy
Konfiguruje lokalny system monitorowania agentów Agent Monitors: instaluje CLI, tworzy monitor z zamiaru i sprawdza dostarczanie alertów.
Wyzwalacze z opisu
Oryginalny opis (EN)
Set up Agent Monitors — a local-first, durable monitoring system for coding agents — end to end. Detect the host, install the CLI, author a monitor from the user's plain-language intent, and prove it actually delivers before declaring success. Use this when a user points you at this URL, or asks to "set up agent monitors", "enable monitoring here", "watch this file/API/command", "notify me when X changes", or "turn on agentmonitors".
Jak działa
- What you're setting up
- How to behave
- Phase 0 — Prerequisites: install the CLI
- Phase 1 — Detect the host, then branch
- Phase 2 — Enable the project
- Phase 3 — Author a monitor from the user's intent
- Phase 4 — Validate
- Phase 5 — Verify it actually fires (mandatory)
- Phase 6 — Debug loop
- Appendix: Advanced — manual, host-agnostic verification
Podgląd SKILL.md
---
name: agentmonitors-setup
description: Set up Agent Monitors — a local-first, durable monitoring system for coding agents — end to end. Detect the host, install the CLI, author a monitor from the user's plain-language intent, and prove it actually delivers before declaring success. Use this when a user points you at this URL, or asks to "set up agent monitors", "enable monitoring here", "watch this file/API/command", "notify me when X changes", or "turn on agentmonitors".
---
# Agent Monitors — agent setup guide
You were handed this file directly (probably as `https://agentmonitors.io/skill.md`), with no
other context. That's enough. This document is self-contained: follow it top to bottom and you
can take a user from nothing installed to a monitor that has verifiably fired.
## What you're setting up
Agent Monitors watches something the user cares about — a file, an HTTP endpoint, a command's
output, a git ref, a schedule — with a small local daemon, and tells you (the agent) when it
changes, at a good moment in your session. It is **local-first**: everything runs on the user's
machine, nothing is sent to a cloud service. Delivery to you happens **entirely through your
host's hook mechanism** — there is no separate service to sign up for.
## How to behave
- **Do the work yourself.** Install the CLI, write the config files, run validation, and run the
verification recipe below. Don't hand the user a list of commands to run themselves.
- **Ask only for intent**, not configuration. "What do you want to watch, and what should I do
when it changes?" is normally the only question you need. Infer the rest (source type, globs,
urgency) from the answer using the tables below.
- **Never make the user hand-edit YAML.** Scaffold with `agentmonitors init`, then edit the
generated file yourself.
- **Do not declare the monitor "set up" until you have demonstrated a delivered event.** A
monitor that only parses and validates is unverified. Phase 5 below is not optional — it is
the difference between "I wrote a config file" and "I proved your agent gets told."
---
## Phase 0 — Prerequisites: install the CLI
Check whether the CLI is already on the user's `PATH`:
```bash
agentmonitors --help
```
If that fails, install it:
```bash
npm install -g agentmonitors
```
This installs the `agentmonitors` binary (a thin launcher over the published `@agentmonitors/cli`
package — both resolve to the same CLI; `agentmonitors` is just the short name). Verify with
`agentmonitors --help` again, or `npx agentmonitors --help` to try it without a global install.
---
## Phase 1 — Detect the host, then branch
Figure out which of these three situations you're in before doing anything else.
### 1a. Claude Code, plugin install available (the common case)
If you can run Claude Code slash commands, add the plugin marketplace and install the plugin:
```text
/plugin marketplace add mike-north/AgentMonitors
/plugin install agentmonitors@agentmonitors
```
This wires Claude Code's `SessionStart` / `UserPromptSubmit` / `SessionEnd` lifecycle hooks to the
CLI automatically. Once a project is enabled (Phase 2), monitors just show up in sessions — you
never run delivery commands by hand in normal use. Continue to Phase 2.
### 1b. Claude Code, hooks-only (MCP blocked / restricted-corporate)
The plugin also ships an optional MCP "channel" for push-style delivery. If your organization
blocks MCP servers or third-party plugin marketplaces by policy, that's fine —
**delivery semantics are identical without it.** The channel is a second, additive transport for
the same durable events; the hook-based transport below is the default for every environment and
never depends on channels.
If you can install the plugin (1a) but MCP is blocked, do that — the hooks still work; you only
lose the optional real-time push, not delivery itself.
If you cannot install any plugin at all, wire the hooks by hand in `.claude/settings.json` (or
`.claude/settings.local.json` for a personal-only, gitignored setup) at the project root:
```json
{
"hooks": {
"SessionStart": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "command -v agentmonitors >/dev/null 2>&1 && agentmonitors session start || true"
}
]
}
],
"UserPromptSubmit": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "command -v agentmonitors >/dev/null 2>&1 && agentmonitors hook deliver || true"
}
]
}
],
"SessionEnd": [
{
"matcher": "",
"hooks": [
{
"type": "command",
"command": "command -v agentmonitors >/dev/null 2>&1 && agentmonitors session end || true"
}
]
}
]
}
}
```
Each command is guarded (`command -v … && … || true`) so the host hook never reports a failure
when the CLI is missing from `PATH` or exits non-zero — an unguarded failing hook would disrupt
the user's session. This mirrors the guard the official plugin's own hook wiring uses.
- `SessionStart` runs `agentmonitors session start`, which lazy-boots the per-project daemon and
registers the session (and prints a recap of anything already pending).
- `UserPromptSubmit` runs `agentmonitors hook deliver`, which claims and injects pending monitor
context at each turn boundary.
- `SessionEnd` runs `agentmonitors session end`, which deregisters the session so the idle daemon
can reap itself.
All three read the hook's JSON payload from **stdin** (Claude Code's standard hook input contract)
— no extra flags needed. Continue to Phase 2.
### 1c. Codex or another host
**Honest current state:** Agent Monitors' automatic in-session delivery is Claude-Code-specific
today — there is no Codex (or other host) hook wiring shipped yet. What *does* work today,
host-independently, is everything upstream of delivery: install the CLI, author and validate
monitors, and run the daemon to observe changes and materialize durable events. You can still
prove the underlying mechanism fires correctly using the CLI-only verification recipe in Phase 5
(it doesn't depend on any host-specific hook — it drives the same daemon/session/events surface
directly). Say this plainly to the user rather than implying full parity with the Claude Code
path: monitor authoring and CLI-level verification work today; automatic delivery into a live
Codex/other session does not yet.
---
## Phase 2 — Enable the project
Monitoring is off by default per project. Check whether your CLI has the one-shot bootstrap flag
first — it's the newer, preferred path, but some installs predate it:
```bash
agentmonitors init --help
```
**If `--enable-only` is listed**, use it. It creates the gitignored opt-in file and updates
`.gitignore` for you, with no monitor and no prompts:
```bash
agentmonitors init --enable-only
```
This creates `.claude/agentmonitors.local.md` (the per-developer opt-in file) and adds both
`.claude/*.local.*` and `/.agentmonitors/` to `.gitignore` — no manual file-editing needed. Skip
straight to Phase 3.
**If `--enable-only` is not listed** (older CLI version), create an equivalent enable file by hand:
```bash
mkdir -p .claude
cat > .claude/agentmonitors.local.md <<'EOF'
---
enabled: true
---
> Local AgentMon coordination state. Gitignored; safe to delete (it is regenerated).
EOF
```
Make sure `.gitignore` contains:
```gitignore
.claude/*.local.*
/.agentmonitors/
```
Either way: this file is per-developer, not committed. Without it, `agentmonitors session start`
quick-exits and no automated monitoring runs during a session (a one-shot `agentmonitors daemon
once` still works without it — the opt-in only gates the session-lifecycle hooks).
`.agentmonitors/` is a separate runtime-state directory (per-session hook state) the daemon
creates the moment a session opens — it's regenerated on every run, so it's always safe to
delete.
Only add `.claude/monitors/*` to `.gitignore` if the user wants monitors to stay personal;
otherwise commit monitor definitions so the team shares them.
---
## Phase 3 — Author a monitor from the user's intent
1. Restate the user's intent as an outcome: *what* changed, and *what should you do about it*?
2. Scaffold with `agentmonitors init` — don't hand-write `MONITOR.md` frontmatter, it's easy to
get subtly wrong:
```bash
agentmonitors init <name> --type <source> --dir .claude/monitors
# Examples:
agentmonitors init watch-ts --type file-fingerprint --dir .claude/monitors
agentmonitors init api-health --type api-poll --dir .claude/monitors
```
(The flag is `--type`, not `--source`.)
3. Pick the smallest source that matches the intent:
| Intent | `--type` | Ask for |
| --- | --- | --- |
| Local files changed, created, deleted | `file-fingerprint` | `globs`; optional `cwd` |
| HTTP response/status changed | `api-poll` | `url`; optional `method`, `headers`, `auth`, `change-detection`, `interval` |
| Output of a command/script changed (e.g. `git status`, a health-check script) | `command-poll` | `command` (argv array, not a shell string); optional `interval`, `change-detection`, `cwd`, `env`, `timeout` |
| Time-based reminder or recurring check | `schedule` | `cron`; optional `timezone`, `label` |
| Local git ref advances touching given paths | `incoming-changes` | `paths`; optional `cwd`, `branch`, `interval` |
If none of these fit, say so — it isn't monitorable yet.
Minimal `command-poll` shape:
```yaml
watch:
type: command-poll
command:
- git
- status
- --porcelain
```
`command` is an argv array. Default `change-detection.strategy` is `text-diff`; use
`json-diff` when the command's output is JSON.
4. **Choose urgency by intent — this controls when you're notified:**
| Intent | `urgency` | When delivered |
| --- | --- | --- |
| Interrupt mid-turn the moment it happens ("stop me if the build breaks") | `high` | At the next prompt/tool boundary, after the change has settled for ~15s |
| Surface at the next natural pause; don't interrupt an in-progress turn | `normal` (default) | A brief reminder at turn boundaries; full detail at session recap |
| Only worth mentioning when idle or at session start | `low` | Session recap only |
**For "notify me when it changes," use `urgency: high`.** A `normal`-urgency monitor produces
only a short reminder mid-turn, not the full body — the details arrive at the next
`SessionStart` recap instead. If the user wants to be interrupted, `high` is correct.
Detection latency is **at least 30–45s** in the default configuration — see the fast-test
setup in Phase 5 for shortening this while you verify.
5. Ask only for the fields the chosen source requires; default everything else. Add `notify:`
only if the user wants specific batching/throttling behavior.
6. Edit `.claude/monitors/<id>/MONITOR.md` (or a flat `.claude/monitors/<id>.md`). The body is
your handling instruction — what to do when it fires — not facts already in `watch:`.
```markdown
When this fires, inspect the change and decide whether implementation or docs need follow-up.
```
---
## Phase 4 — Validate
Run this after every edit and fix everything it reports:
```bash
agentmonitors validate .claude/monitors
```
---
## Phase 5 — Verify it actually fires (mandatory)
Validation proves the file parses. It does **not** prove you'll be notified. Those are different
claims — `monitor explain` can show a materialized event that was never delivered to a session.
**The monitor is not done until you've proven a delivered event, end to end.**
### Run `agentmonitors verify`
```bash
agentmonitors verify <monitor-id>
```
This is the whole proof in one command, and it's host-agnostic (Phase 1c hosts can use it too,
minus the automatic hook wiring): it boots an isolated daemon on a throwaway socket and database,
registers a throwaway session, triggers a real change, waits for the event to materialize, and
claims it through the same delivery path a live hook uses — then tears everything down. Check the
exit code: `0` means PASS, non-zero means FAIL with the failing stage named directly. Prefer
`--format json` if you want to branch on the result programmatically instead of parsing text (spec
005 §16 documents the stable JSON shape: `ok`, `monitorId`, `stages`, `failure`, `additionalContext`,
`daemonStderr`, `elapsedMs`).
**Auto-trigger only covers `file-fingerprint`.** For a literal single-file glob (e.g.
`docs/notes.md`), it edits the watched file itself and restores it on exit. For a pattern glob, it
writes a scratch sibling that reuses the glob's static directory prefix and extension — but that
placement can't fabricate a match for a glob whose filename segment is itself a wildcard (e.g.
`file-?.md`) or whose only variability is a wildcard directory with a literal filename (e.g.
`data-*/report.md`); those have no derivable sibling. For every other source — `api-poll`,
`command-poll`, `schedule`, `incoming-changes` — and those un-fabricatable file-fingerprint globs,
have `verify` run the change itself with `--trigger-cmd`:
```bash
agentmonitors verify <monitor-id> --trigger-cmd '<shell command that causes the change>'
```
`--trigger-cmd` is the **decoupled trigger**: after baseline, `verify` runs your shell command
(from the workspace directory) to cause the watched change, then observes and delivers — one
self-contained, non-interactive command. **This is the mode to use as an agent**, because
`--manual` (below) blocks and does not read stdin, so a call-and-return harness (one shell command
per tool call) cannot make the change while it waits. For a `command-poll` watching
`git status --porcelain`, that's e.g. `--trigger-cmd 'touch new-file.txt'`; **you still have to know
what change actually registers for that source** — see "Per-source trigger recipes" in the appendix
(e.g. `file-fingerprint` needs a content change, not just a `touch`; `command-poll` diffs command
output between ticks; `schedule` needs a cron that fires soon). The command's effects are not
reverted, and a non-zero exit is a `setup` failure (fix the command, not the monitor).
`--manual` is the alternative when you'd rather make the change out-of-band yourself:
```bash
agentmonitors verify <monitor-id> --manual
```
It **blocks** for the detect budget and watches for a change you make in a _separate_ step — it is
_not_ an interactive stdin prompt. With a persistent shell you can background the run
(`verify … --manual --timeout-ms <generous> &`), make the change, then read the result; a
call-and-return harness can't, and should use `--trigger-cmd` instead. `--manual` and
`--trigger-cmd` are mutually exclusive.
**If the user wants a stakeholder-presentable proof**, or you want the real workspace daemon left
running afterward so a follow-up `agentmonitors doctor` also goes green, add
`--use-workspace-daemon`. This requires the project to already be enabled (Phase 2) — it runs
`verify` against the real workspace daemon/database instead of a throwaway one and leaves it
running rather than tearing it down. Because that daemon persists, `verify` cleans up after itself
by retracting its scratch file's create event and leaving a short-lived **suppression** so the
daemon erases the scratch file's later deletion event on its own — so the scratch change never
reaches a real session and the run finishes in about the same time as a plain `verify`. An
interrupted run (e.g. a command timeout) leaves no permanent stray session or event behind. Note
that `verify`'s own synthetic trigger is a scratch probe: its PASS is not persisted as a durable
event, so it will **not** show up in `agentmonitors events list` or `agentmonitors doctor`'s event
counts. The PASS proves delivery end-to-end; if the user also wants a durable, queryable artifact to
inspect after the run, have them make one real edit to a watched file and deliver it (a live
session, or `agentmonitors hook deliver`), then inspect `agentmonitors events list --session <id>`.
**Success looks like** a `PASS` line, with a `deliver` stage reporting
`claimed at turn-interruptible` (for `urgency: high`) or `claimed at post-compact`
(`normal`/`low`), followed by the delivered `additionalContext` — that's exactly what a live hook
would inject into the
agent's next turn:
```json
{
"continue": true,
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": "AgentMon: monitored changes are pending — consider handling them before continuing.\n\n### <your-monitor-id> (high)\n..."
}
}
```
(That's the shape a live `UserPromptSubmit` hook receives; `verify`'s own PASS output prints the
raw `additionalContext` text, not this wrapper.)
If `verify` fails, the `FAIL` line names the stage and reason directly — don't guess from empty
output the way the fully-manual recipe below forces you to:
- `no-change` / `no-files-matched` means the trigger didn't do anything the source could detect
(e.g. a `touch` on a file whose content didn't change) — fix the trigger, don't retry hoping it
resolves itself.
- `budget-exceeded` means the change was never detected within the derived wait budget —
`--timeout-ms` to extend it, or run `agentmonitors monitor explain <id>` to see where the
pipeline actually stalled.
- `daemon-died` prints the daemon's own captured stderr — that's the real crash reason, not an
ambiguous timeout.
For debugging an individual pipeline stage by hand, or a host without `agentmonitors verify`
available, see "Appendix: Advanced — manual, host-agnostic verification" at the end of this
document.
---
## Phase 6 — Debug loop
If `agentmonitors verify` failed, its `FAIL` line and `--format json` output already name the
stage and reason — that's usually enough. Its daemon and database are temporary and deleted on
exit (unless you passed `--use-workspace-daemon`, in which case they're the real workspace ones
and `monitor explain`/`doctor` already see them with no extra flags), so there's no state to
inspect after a plain `verify` run beyond what it already printed. If you ran the appendix's fully
manual recipe instead (which pins `AGENTMONITORS_DB` by hand), see that appendix's own debug notes
for reading back its persisted state.
### First: is anything still listening?
`verify` proves delivery works **once**, at setup time. It does not stay true. Before digging into
a specific monitor, check whether a delivery transport is still listening for this workspace at all:
```bash
agentmonitors doctor
```
Read the **Delivery transports** section and its verdict line
(`delivery to active sessions in this workspace → via {hook | channel | both | none}`). It names the listening method
and, when delivery is currently blocked, which of these it is — each with its own fix:
- **`daemon-unreachable`** — there is no daemon for this workspace (it was reaped, or never
started). Nothing can deliver. Run `agentmonitors daemon run`, or open a session in this
workspace.
- **`workspace-mismatch`** — the transport is bound to a *different workspace* than the monitors
you're waiting on. Usually means the session was launched from somewhere other than the repo.
Start a session from the repo directory.
- **`reminders-suppressed`** — everything is up, but reminders are **muted**: an earlier unread
event is already claimed, so new ones won't surface (`coalesced-until-ack`). `doctor`'s own
`remediation[]` names the exact fix — `agentmonitors events ack --session <id> --event-ids
<ids> --socket <socket>`, scoped to precisely the claimed events holding the reminder back and
the daemon `doctor` diagnosed. Don't run a bare `--session <id>` yourself: with no `--event-ids`
it acknowledges *every* unread event for that session, including work never claimed or surfaced.
This one is worth knowing about, because nothing looks broken while it is happening.
- **`heartbeat-stale`** — a channel server registered but stopped reporting; reconnect the MCP
server or start a new session.
`agentmonitors doctor --format json` exposes the same thing as `transports[]`,
`deliveryWillReachThisSession`, `deliverable`, and `remediation[]`.
### Then: why didn't this monitor fire?
When the user says "it didn't fire" and the transports are healthy, don't guess — run:
```bash
agentmonitors monitor explain <id> --dir .claude/monitors
```
This reads persisted runtime state (recent observations, materialized events, session state)
**directly from disk — no live daemon required.** It prints a status per pipeline stage, then a
**Verdict** naming where the signal stopped:
- `definition` — parse/schema/source config problem; edit `MONITOR.md`, then re-run `validate`.
- `scheduling` — the daemon isn't running or the monitor isn't due yet; enable the project, start
a session, or check the interval/cron.
- `observation` — the source ran but errored, rebaselined, or saw no change; inspect the
source-specific config and state.
- `notify` — a debounce/throttle hold is in effect; wait, or adjust `notify:`.
- `materialization` — the source observed a change but no event was written; inspect the
runtime error details in the output.
- `delivery` — an event exists but no lead session is available, or it's already
unread/claimed/acknowledged.
If `monitor explain`'s delivery verdict disagrees with what you expect, the authoritative check is
`events list` — but note that **`events list` needs a reachable daemon** (unlike `monitor
explain`, it has no offline fallback and errors if none is running):
```bash
agentmonitors session list # find the AgentMon session id
agentmonitors events list --session <agentmon-session-id> --unread # requires a live daemon
```
Non-empty output confirms the event reached the session and is pending delivery — the `monitor
explain` delivery verdict may simply be stale. If `events list` is also empty (once the daemon is
confirmed running), the event never reached the session; work backward through the Verdict stages
above.
**`--unread` means unacknowledged, not "never seen."** It matches every event this session hasn't
run `events ack` on yet — including one already surfaced once at a delivery lifecycle. Each row's
`deliveryState` field (`unread`, `claimed`, or `acknowledged`) tells you which: `claimed` means the
event already reached a hook delivery and is waiting on `events ack`, not stuck undelivered.
---
## Appendix: Advanced — manual, host-agnostic verification
`agentmonitors verify` above covers the common case. This appendix drives the exact same
daemon → session → event → delivery pipeline **by hand, one step at a time** — useful for
debugging an individual pipeline stage, or a host without `agentmonitors verify` available. It
works even outside a live Claude Code session.
### Why not just use `agentmonitors session start`?
`session start` is designed for the real `SessionStart` hook: it lazy-boots a daemon with
automatic idle reaping (5 minutes by default), which is fine in a live session where hooks keep
the daemon alive, but can reap mid-way through a slower manual verification. Use the explicit
recipe below instead, which pins everything to one daemon on one socket that never reaps.
### Speed it up for the test
`agentmonitors verify` derives its own poll budget automatically — this shortening step is only
useful for the manual recipe below, which needs its poll loops sized by hand. Default poll
interval is 30s (`file-fingerprint`, `command-poll`) or 5min (`api-poll`). For a
verification pass only, shorten it in the `MONITOR.md` frontmatter, and restore the real value
afterward. `file-fingerprint` takes the same `watch.interval` knob as `command-poll` — it isn't
command-poll-only:
```yaml
watch:
type: file-fingerprint
globs:
- '**/*.ts'
interval: 5s # shorten for testing only
notify:
strategy: debounce
settle-for: 5s # shorten for testing only
urgency: high
```
```yaml
watch:
type: command-poll
command: [cat, tracked/state.txt]
interval: 5s # shorten for testing only
notify:
strategy: debounce
settle-for: 5s # shorten for testing only
urgency: high
```
You can also pass `--poll-ms <ms>` to `daemon run` (default 30000) to shorten the daemon's own
tick rate — but that only controls the daemon's tick granularity, not any individual monitor's due
time; `watch.interval` above (or the `api-poll`/`schedule` equivalents) is what actually governs
when a specific monitor comes due. Budget step 4's poll loop below (event materialization) the same
way step 5 budgets `hook deliver`: roughly `interval + settle-for`, before assuming nothing
happened.
### The recipe
Use an explicit socket so every step talks to the same daemon, independent of whether the project
has an enabled `.claude/agentmonitors.local.md`:
```bash
CWD=$(pwd)
HOST_ID="verify-$(date +%s)"
SOCKET="/tmp/agentmon-verify-$$.sock"
# Isolate this recipe's own runtime state from any other daemon on the
# machine (and from a previous run of this same recipe in the same
# directory). Without this, a rerun can reuse a prior baseline and skew the
# tick-count assumptions in the per-source recipes below (issue #338).
export AGENTMONITORS_DB="/tmp/agentmon-verify-$$.db"
# 1. Start a daemon that never idle-reaps, on an explicit socket every later
# step will also target.
agentmonitors daemon run .claude/monitors --socket "$SOCKET" --reap-after-ms 0 --poll-ms 5000 &
DAEMON_PID=$!
sleep 1
# 2. Open a lead session on the same socket, capturing the AgentMon session
# id (it is NOT the same as $HOST_ID) via --format id — prints just the
# bare id, no JSON parsing needed.
AGENTMON_SESSION_ID=$(agentmonitors session open --socket "$SOCKET" --host-session-id "$HOST_ID" --role lead --workspace "$CWD" --format id)
echo "AgentMon session: $AGENTMON_SESSION_ID"
# 2b. Wait a full poll interval (matching --poll-ms above) before triggering
# anything. A monitor with no prior observation is always "due," so the
# daemon's first tick for it runs immediately at startup — before waiting
# --poll-ms, and independent of step 2's session-open, which only
# registers a delivery recipient and does not affect tick timing — and
# every bundled source except `schedule` treats that first tick as a
# silent baseline for *change* observations (see "Per-source trigger
# recipes" below; `command-poll` is a partial exception — a first-ever
# command that fails still surfaces a health observation on that tick).
# This wait guarantees the baseline tick has already completed before
# step 3.
sleep 5
# 3. Trigger the monitored condition (per-source recipes below).
# 4. Poll `events list` until the materialized event shows up. --unread always
# talks to the live daemon over the socket (it errors if the daemon isn't
# reachable — start it first, as above). This loop's 20 x 2s = 40s budget
# assumes the shortened `interval` + `settle-for` from "Speed it up for the
# test" above (5s + 5s here); at default/unshortened values (e.g.
# file-fingerprint's 30s default interval with no override), widen the
# retry count to cover `interval + settle-for` — the same formula step 5
# budgets for `hook deliver`, one stage later.
for i in $(seq 1 20); do
OUT=$(agentmonitors events list --socket "$SOCKET" --session "$AGENTMON_SESSION_ID" --unread --format json)
[ "$(node -e "console.log(JSON.parse(process.argv[1]).length)" "$OUT")" -ge 1 ] && break
sleep 2
done
echo "$OUT"
# 5. Simulate the UserPromptSubmit hook: claim any pending deliveries and
# confirm the agent would actually be notified. Empty stdout usually means
# nothing was claimable yet — poll the same way step 4 does. But empty
# stdout is also how several misconfigurations look (workspace not
# enabled, daemon unreachable, ...), so if the loop never returns content,
# run `agentmonitors hook deliver --debug` (writes a step-by-step
# diagnosis to stderr) to tell the two apart.
for i in $(seq 1 20); do
OUT5=$(echo "{\"session_id\":\"$HOST_ID\",\"cwd\":\"$CWD\",\"hook_event_name\":\"UserPromptSubmit\"}" \
| agentmonitors hook deliver --socket "$SOCKET")
[ -n "$OUT5" ] && break
echo "(hook deliver: nothing claimable yet, retrying...)" >&2
sleep 2
done
echo "$OUT5"
# 6. Clean up.
kill "$DAEMON_PID"
```
**Success signal:** step 4 prints at least one event row (monitor id, urgency, title). Step 5
(`hook deliver`) returning a non-empty JSON object with a populated
`hookSpecificOutput.additionalContext` confirms the delivery hook would actually notify the agent:
```json
{
"continue": true,
"hookSpecificOutput": {
"hookEventName": "UserPromptSubmit",
"additionalContext": "AgentMon: monitored changes are pending — consider handling them before continuing.\n\n### <your-monitor-id> (high)\n..."
}
}
```
**If step 4 or step 5's loop keeps retrying, don't assume it's just a settle window — check what
the daemon actually recorded first:**
```bash
agentmonitors monitor history <id> --socket "$SOCKET"
```
A row whose result column shows `no-change` means the trigger in step 3 didn't actually alter
anything the source could detect (e.g. a `touch` on a file whose content didn't change under
`file-fingerprint`'s content-hash comparison) — fix the trigger, don't keep waiting.
A row showing `suppressed` means the opposite: the source detected a real change (the trigger
worked), but a debounce/throttle hold in `notify:` is delaying it from becoming an event this tick
— expected mid-settle, not a broken trigger. Wait for the next tick, or check `monitor explain`'s
notify stage.
Only once the result column shows `triggered` — or step 4 has already printed an event row — is a
still-empty step 5 loop for a `high`-urgency monitor expected, not a bug. `events list` (step 4)
surfaces an event as soon as it materializes. `hook deliver` at the `turn-interruptible` lifecycle
applies a *separate*, fixed ~15s "claim settle" window measured from the event's own creation time
before it will surface the event's body — independent of your monitor's `notify.settle-for`. So for
`high` urgency, budget roughly `interval + settle-for + 15s` before step 5's loop returns content —
the 20 × 2s retry window above comfortably covers that. **Do not** change any files or re-open the
session while you wait for step 5 once the event already exists — that resets the condition you're
trying to observe. A `normal`-urgency monitor doesn't have this extra wait: `hook deliver` surfaces
a reminder (not the full body) as soon as the event is unread (002 §9.2). `low` urgency is delivered
only at the `turn-idle` lifecycle (002 §9.3, §13.2) — this recipe's step 5 sends
`UserPromptSubmit`, which maps to `turn-interruptible` only, so it never exercises low-urgency
delivery; expect step 5 to keep returning empty for a `low`-urgency monitor regardless of how long
you wait.
**This recipe's daemon is invisible to `doctor`.** Everything above runs against the explicit
`$SOCKET` / `$AGENTMONITORS_DB`. `agentmonitors doctor` and `monitor explain` auto-discover the
*workspace's own* socket — falling back to the shared global default only when the workspace isn't
enabled — so neither ever resolves this recipe's throwaway `$SOCKET` (both still honor
`AGENTMONITORS_DB` if it's set in their environment). Running plain `agentmonitors doctor` right
after a successful run of this recipe is expected to still report the monitor "never observed" or
the daemon unreachable — that's a different daemon than the one `doctor` resolved, not a
regression. To check the setup a real agent session would actually use, start a daemon on the
workspace's own socket (`agentmonitors daemon run` — no `--socket`) or open a live session, then
re-run `doctor`.
**For a stakeholder-presentable proof** (e.g. showing a security reviewer that monitoring is
actually wired up), don't screenshot the isolated-socket recipe's output — it's throwaway and
proves the mechanism, not the live setup. Instead, start the workspace's own daemon
(`agentmonitors daemon run`, no `--socket`) and screenshot `doctor`'s all-green summary alongside
the `hook deliver` JSON from step 5 above.
### Per-source trigger recipes (step 3)
A monitor with no prior observation is always "due," so the daemon's very first tick for it runs
immediately at startup — before waiting `--poll-ms` at all. `file-fingerprint`, `api-poll`,
`command-poll`, and `incoming-changes` all treat that first tick as a **silent baseline**: whatever
state exists at that moment becomes the reference point, and no *change* observation is ever
emitted for it. A change that lands *before* this first tick finishes is folded straight into the
baseline and is never detected — not on that tick, not on any later one, because later ticks diff
against the state the *previous* tick captured, not against "what changed since the daemon
started." The one exception is `command-poll`'s health tracking: if the command's first-ever
execution *fails*, that failure isn't folded into a silent baseline — it still surfaces a
`Command failing: …` health observation on tick 1, because there is no prior "ok" state for the
failure to be silently reconciled against. `schedule` has no baseline: it emits an observation on
any tick where its cron matches, from the first eligible tick onward. Step 2b's wait exists
precisely to dodge this race — by the time you reach step 3, the baselining first tick has already
completed, so whatever you trigger next is guaranteed to be detected on a subsequent tick.
**`file-fingerprint`** — change the *content* of a file matched by `watch.globs`. This source
detects changes by content hash, not mtime or existence, so a bare `touch` on an existing file
leaves the hash unchanged and is silently ignored — append real content instead:
```bash
echo "// verify $(date)" >> path/to/monitored/file.txt
```
**`command-poll`** — change the command's output between two ticks. Example, watching
`cat tracked/state.txt`:
```bash
echo "changed" >> tracked/state.txt
```
Each tick after the baseline diffs against the *previous* tick's captured output (a rolling
comparison), so once the baseline tick has run, whichever tick executes after you make the change
will detect it. This assumes a fresh baseline, which is why the recipe isolates
`$AGENTMONITORS_DB` above — reusing a database from a prior run of this same recipe means the
daemon's first tick already has a baseline from that earlier run.
**Gotcha, `git status --porcelain` monitors specifically:** this is `command-poll`'s analog of the
`file-fingerprint` `touch` no-op above. `git status --porcelain` reports an already-untracked file
as `?? path` regardless of its content — appending to it again doesn't change that line, so
re-touching an existing untracked file is a silent no-op trigger here too. The trigger must add,
remove, or modify a *tracked* file, or introduce a genuinely *new* untracked path — not write again
to a file that's already untracked.
**`api-poll`** — the response from `watch.url` must change between two ticks. Point it at a
controllable local server, or a source that changes every poll. Without a controllable endpoint,
`agentmonitors monitor test .claude/monitors/<id>/MONITOR.md` confirms the source is configured
and reachable, but an actual fire needs the remote resource to change on its own.
**`schedule`** — set a cron that fires within the next minute while testing (e.g. `'* * * * *'`),
then restore the real cron afterward. `agentmonitors monitor test <path>` confirms the cron
parses. No baseline race here — just make sure the cron is set *before* starting the daemon, so
its first eligible tick can catch the matching minute.
**`incoming-changes`** — advance the tracked ref by committing to a watched path, then trigger a
fetch/merge that advances it (or simulate with `git pull`):
```bash
touch docs/scratch-verify.txt
git add docs/scratch-verify.txt
git commit -m "verify incoming-changes monitor" --no-gpg-sign
```
---
### Reading back the manual recipe's state
This recipe's daemon is dead once its step 6 (`kill "$DAEMON_PID"`) runs, and its socket is
invisible to `doctor`/`monitor explain` even while it's alive — those auto-discover the
*workspace's own* socket (falling back to the shared global default only when the workspace isn't
enabled), never this recipe's throwaway `$SOCKET`. What does survive is the SQLite file
`AGENTMONITORS_DB` pointed at (`/tmp/agentmon-verify-<pid>.db`): `monitor explain` and `monitor
history` both resolve their database via the `AGENTMONITORS_DB` environment variable, so pointing
it at that same file — e.g. `AGENTMONITORS_DB=/tmp/agentmon-verify-<pid>.db agentmonitors monitor
explain <id> --dir .claude/monitors` — reads the persisted state from that run **in-process, no
live daemon required.** (`agentmonitors verify`'s own isolated daemon, by contrast, deletes its
temp database on exit — there's nothing to read back after a plain `verify` run; its own PASS/FAIL
output is the full record. See Phase 6 above for the general debug loop.)
Wersje
W bazie nie ma innych skilli o nazwie agentmonitors-setup.
Migawka bazy z 28.10.2026 · wersja paczki 73d4e1699684 (skrót SHA-256 całej paczki)
Pobrania w ostatnich 30 dniach: 0 · ranking
Zgłoś problem z tym skillem: szkodliwa treść, błędny opis albo prośba autora o usunięcie.
Podobne skille
- 100setup-monitors
Włącza monitorowanie AgentMon w repozytorium i tworzy monitory zdarzeń, np. zmian w pliku, wywołań API lub harmonogramu. - 100monitor
Konfiguruje monitoring kondycji demona SiftCoder, magazynu pamięci i zewnętrznych zależności, takich jak Ollama i Anthropic API. - 100checkly
Konfiguruje, tworzy, testuje i zarządza sprawdzeniami monitoringu w Checkly CLI: API Checks, Browser Checks, monitory URL i ICMP, Playwright, Heartbeat, kanały alertów, dashboardy i status pages. - 95checkly
Tworzy, testuje i zarządza monitoringiem w Checkly CLI: checki API i przeglądarkowe, monitory, alerty, dashboardy i status page. - 100pilot-fleet-health-monitor-setup
Wdraża system monitoringu kondycji floty serwerów z trzema agentami: monitoring, alerty i zbieranie metryk. - 100axiom-alerting
Tworzy i zarządza monitorami oraz notyfikatorami Axiom przez publiczne API v2: budowa alertów, routing powiadomień, walidacja i utrzymanie konfiguracji.