Skip to main content

babysit

Use when a user asks to babysit, monitor, keep checking, keep an eye on, or report when a pull request, CI run, ticket, deployment, or other changing target reaches an outcome.

Source facts

Repository
kirodotdev/KiroCrew
Last source activity
October 7, 2026 at 21:25
Detected SKILL.md language
English
Stars
4,452
Forks
820

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
babysit
description
Use when a user asks to babysit, monitor, keep checking, keep an eye on, or report when a pull request, CI run, ticket, deployment, or other changing target reaches an outcome.
inject_on_trigger
false
triggers
babysit, keep checking, keep an eye on, let me know when, monitor pull request, monitor pr, watch pull request, watch pr
tags
["skill","kirocrew","monitor","babysit"]
# Babysit General-purpose monitoring: this skill works without a Kiro Crew checkout or kirocrew-prepare-pr installed. It owns loop mechanics, not a repository's repair policy. For Kiro Crew PR CI AI comments ONLY, MUST load [kirocrew-prepare-pr: Review repair routing](../kirocrew-prepare-pr/SKILL.md#review-repair-routing) before any fix. That procedure requires model-pinned repair subagents; parent self-fixing does not satisfy it. Prepare-pr owns that repo's local reviewers, PR gates, dispositions and publication rules. Do not require it for other work. ## Choose one driver Use a structured monitor only when its typed provider observes every fact needed to decide the objective. Use the finite legacy path for evidence it cannot see. Structured watches support dashboard, Slack, and Discord sessions. On Webex, use the finite legacy path even for a supported pull request. | Work | Driver | |---|---| | User is waiting, total work under 30 minutes | Bounded in-turn `wait` + poll | | One supported pull request, readiness decided by typed provider facts | `monitor_watch` | | Generic comments/advisory findings, or a required final report or notification | Finite `monitor_start` with `gate=false` | | Act on a schedule, multiple subjects, unsupported ticket or deployment | Finite `monitor_start` | | Fresh-session work needing no approval-bound tools | `cron_add` | | Post-merge cleanup after verified merge | Script cron, roughly every 5 minutes | | External system calls back | `register_hook` | Never use an agent cron or `HEARTBEAT.md` to fix and push review findings. Cron has no owning chat slot's trust and can time out at tool approval while still recording `last_status: ok`; heartbeat's allowlist has no shell or push. Use one session-owned driver, not two watchers. A gated `monitor_start` hands its whole pull-request reading, comment and review bodies included, to the wake judge, so `wake_when` may name prose. No judge lane: only an unchanged subject is free. An installation can set how firmly this table's facts-decided row points at the structured path. With `monitoring.prefer_structured_arming` on, `monitor_watch` is this gateway's default for a supported pull request and the prompt loop is the exception; off (the default) the table reads as written. The setting changes what the two tool descriptions say and refuses neither tool, so the row that matters never moves: evidence the typed provider cannot see -- generic comments, advisory findings, a required final report -- is `monitor_start` with `gate=false` in either position. Read the descriptions you were given rather than assuming a position. ### Structured pull-request watch Use this only for pull-request lifecycle, mergeability, review decision, canonical review facts and check conclusions. Choose the kind from the canonical URL; do not translate one provider's URL into another provider's shape. | URL | `kind` | |---|---| | `https://github.com/OWNER/REPO/pull/NUMBER` | `github_pull_request` | | `https://gitlab.com/GROUP/REPO/-/merge_requests/NUMBER` | `gitlab_merge_request` | | `https://GITLAB_HOST/GROUP/REPO/-/merge_requests/NUMBER` | `gitlab_merge_request` when that exact self-managed host is configured | | `https://dev.azure.com/ORG/PROJECT/_git/REPO/pullrequest/NUMBER` | `azure_devops_pull_request` | | `https://bitbucket.org/WORKSPACE/REPO/pull-requests/NUMBER` | `bitbucket_pull_request` | Call once with the selected kind and unchanged canonical URL: ``` monitor_watch(kind=<kind>, target=<full PR URL>, objective="review_ready", interval_secs=300, max_runtime_secs=14400, wake_instructions=<actions and exit>) ``` Inspect the schema: positive `max_tokens`/`max_provider_errors`, and `max_agent_turns` where 0 = no wake cap. Ordinary unchanged/pending/retry/terminal probes spend no agent turn; a new actionable fingerprint wakes the owning session at most once with a bounded summary. Fetch logs, comments or diffs only when needed on that wake. The token cap applies only when usage is reported; `token_usage_known` exposes that gap; runtime always caps, turns only if set positive. Provider errors are bounded too. GitLab uses installed `glab` credentials, Azure DevOps uses `az login` or the protected `AZURE_DEVOPS_EXT_PAT`, and Bitbucket may use the protected `BITBUCKET_EMAIL` plus `BITBUCKET_API_TOKEN`. A setup or authentication refusal is authoritative; do not replace it with a legacy full-turn loop. The reply is a pending application request, not proof that the monitor armed. END THE TURN so the owning session can apply it. The operator can confirm it in the dashboard; call `monitor_inspect()` at the start of a later user/wake turn, not after arming in the same turn. It takes no monitor id, target or session key. Its retained session-bound state is authoritative. A terminal success uses zero model turns, so a structured watch does not create a final reporting turn. If the user requires a final report or notification even when no action is needed, use the finite legacy path. Typed providers do not observe generic issue/pull-request comments or advisory review findings outside their canonical review and check facts. When readiness depends on those, call the finite legacy path directly with `gate=false`; a typed fingerprint cannot stand in for missing evidence. Use `monitor_update` without an id for cadence, positive budgets or `wake_instructions`: these preserve the comparison baseline. Changing `target` or `objective` starts a new baseline. Terminal records are read-only; restarting requires an explicit new watch. Stop with `monitor_stop(reason=...)`, retaining `user_stop`; `autonudge_stop` is a compatibility alias, not the preferred path. A retained user stop cannot be replaced by rearming: ask its owner to use **Clear stopped monitor** (legacy **Clear stopped goal**) or the dashboard's explicit restart action. Never erase that evidence or retry the refusal. ## Example: legacy comment-aware recipe ```text monitor_start({ "message": "Watch https://github.com/kirodotdev/KiroCrew/pull/123. On each injected cycle, inspect current review comments and checks. Act only on a real change. Kiro Crew AI repairs MUST follow kirocrew-prepare-pr Review repair routing with model-pinned subagents and parent verification; commit and push only if authorized. If ready, terminal, blocked, stopped by the user or out of budget, report the outcome and any open findings, then call autonudge_stop with a reason.", "interval_secs": 300, "max_cycles": 24, "max_runtime_secs": 14400, "gate": false }) ``` Replace the example URL with the real target. Keep `gate: false`: provider-fact gating cannot observe generic comments or advisory findings and could suppress a cycle while that evidence waits. All three limits must be positive and finite; never use `0` for unlimited work. Every delivered legacy cycle is a full model turn even if nothing changed. Name the readiness conditions below by reference rather than copying their text into the message: a copy inside the instruction drifts from the list it duplicates while still reading as authoritative. Follow the execution steps below. ### Same-session timer The legacy timer binds to THIS session. Slot-less subagents, cron, webhook and task-runner turns cannot arm it; use bounded in-turn wait/poll instead. Loops persist in the data home's `autonudge.json`. User turns defer a due fire until their end but do not restart its countdown. Each delivered cycle's next countdown starts after its own work, so cadence includes turn time. Busy cycles can be skipped, not queued, and skips do not spend `max_cycles`. Gateway restarts preserve state. Keep Slack/Discord unattended turns small; they have a 30-minute bound and no blanket grant: normal PreToolUse governance and approvals apply. A rejected or timed-out approval is a stall, not success or permission to loosen security. Fix, commit and push only within the user's authorization. - Name ONE public GitHub PR by full URL in `message` to select gating. A bare `PR <n>` gates only if this session already named its URL. - `gate=true` is the default. Quiet subjects avoid turns, with eventual delivery after enough quiet intervals. Use `gate=false` for generic comments/advisory scans and duties that act despite silence, such as chasing a missing reviewer or tracking a moving base. `max_cycles` counts DELIVERED turns, including quiet-floor deliveries and fallbacks, not just useful changes. - A short `banner` keeps a long instruction out of stored transcript rows while the model receives it whole. Dashboard only; channel loops refuse it with 400. `monitor_update(banner="")` clears it. - `monitor_update(message?, interval_secs?, max_cycles?, max_runtime_secs?, banner?)` preserves the count and omitted fields. Do not mix these with structured-only `target`, `objective`, `max_agent_turns`, `max_tokens`, `max_provider_errors` or `wake_instructions`. On Webex, stop and create a new finite loop instead. - One automation occupies a session. `monitor_start` is create-only; update an active loop rather than replacing it. A new arm replaces a cap/budget-stopped legacy loop, only with user authorization. Manual pauses and user stops stay preserved; retained evidence needs the owner action above. Do not rearm merged/closed work as if it still needed repairs. ## Execute the legacy loop 1. Write a self-contained instruction naming subject, allowed actions, success, blocker/stall conditions and stop tool. Include worktree/branch and whether pushes are authorized. Pass positive cycle and runtime bounds. For Kiro Crew preparation use kirocrew-prepare-pr's budget; never raise its cap yourself. 2. Load the MCP tool by exact `tool_search` ID before calling it. Report only that monitoring was REQUESTED and END YOUR TURN immediately. Application happens when the turn's result is processed, not synchronously with the call. 3. On a later turn, verify the applied transcript notice and session-bound state through `monitor_inspect()` where supported, the dashboard monitor/goal-loop surface or `GET /api/autonudge`. Prepare-pr's `monitor_armed.py` is an optional legacy helper. Check `cycle_count` advances on later cycles; never claim an acknowledgement alone proves active monitoring. 4. A create-only refusal means a loop may already be active: inspect state, never add wait/poll beside it. Missing hosting context permits bounded in-turn wait/poll. A retained-stop refusal needs the owner, not a retry or another driver. Read an absent/frozen loop's reason and report the blocker; do not silently substitute an unbounded poll or retry arming before the pending request applies. 5. Each wake reads durable state, checks the subject and acts only on real changes. Report real signals only; update stale instructions in place. 6. Persist the progress key AND streak below. Keep cycle output small; the same conversation grows each turn and compaction can erase an in-memory counter. 7. On success, terminal state, user stop, external blocker or spent budget, report the real outcome and any open findings, then call `autonudge_stop` with a reason. A cap is a backstop, never successful completion. Do not rearm automatically after a user stop or spent budget. ## Read state from the host Read lifecycle every cycle: merged, closed or declined means report that outcome and stop, regardless of check colors. Ask the host for its aggregate verdict; never hand-roll a green result by filtering only check conclusions. Unknown or unmapped states fail closed. Mergeability can be asynchronous: `unknown`, `checking` or `unchecked` means wait, never pass; a closed object may never settle. Collapse superseded attempts to the newest per workflow/check identity when you read the rollup yourself, ordering by the RUN ID, which increases monotonically -- never a job's start time, which waits on a runner queue, nor the run's creation time, which is second-granular and often tied. Keep every row you cannot strictly order. A typed provider collapses the same way, keyed on the workflow DEFINITION's id plus the check name rather than the display name, since two files may share one `name:`, and on the run's triggering event, since one file on `push` and `pull_request` dispatches twice for one commit. Highest RUN ID wins, but recency alone licenses nothing: the rollup has no lineage edge. Drop a row only when its own RUN concluded CANCELLED, the row itself is COMPLETED+CANCELLED, and a newer run of its identity exists. Read that cancellation from the RUN, never the row: `fail-fast`, a failed `needs`, or an operator cancelling one job all leave a CANCELLED row inside a run that concluded FAILURE and is live. Conversely, a cancelled NEWEST run is never droppable; that revives the verdict it superseded. Two rows of ONE run are not a retry and both stay, because a workflow can publish a check run under its own job's display name. Finally, any completed row of a replaced round still reads as live, not only a cancelled one. The bundled `pr_status.py` applies this rule. Green checks do not answer review threads or advisory findings. Establish once per repo what its reviewer check means, and repeat when its fleet changes: red may mean successful review with findings; green may carry findings; a job log may hold a verdict that never posted; identical trees may receive different verdicts; duplicate dispatch can inflate failure counts. If conclusions are not trustworthy, use the current-head marker/comment body and needed job logs. Record that finding in the repo's own tracker, not this general skill. On GitHub, read the repo's aggregate commit status when present, otherwise the full `statusCheckRollup` (`gh pr view <n> --json state,mergeable,mergeStateStatus,reviewDecision,statusCheckRollup`), and read review threads plus comments/reviews for the current head separately. The rollup is a `CheckRun | StatusContext` union: classify `.conclusion` AND `.state`, respecting the repo's named aggregate status. A same-named CheckRun is not that commit status. Other-host guidance is not live-verified here. On another host (GitLab, Bitbucket, an enterprise forge) derive the same two answers, lifecycle plus aggregate merge verdict and a separate review-thread axis, from that host's own verdict fields, using its CLI or API help rather than field names remembered from elsewhere. Wait states, hidden allowed-failure jobs and "no single merge verdict" hosts all fail closed until you have confirmed the mapping on the actual host. Conflict, `BEHIND`, or `green_age.py` exit 30 requires an authorized sync, not another unchanged poll: GitHub cannot build a conflicted merge ref, so `pull_request` checks may never start while old checks look green. `BEHIND` is the weakest of the three and on some repositories never appears at all: `mergeStateStatus` reports it only under strict up-to-date protection, so where that is off, a base that moved underneath a green head is visible only through the green-age reading below. Rebase unambiguous conflicts under the repo's history rules, re-verify and push only with authorization; escalate ambiguous conflicts. A draft or `CHANGES_REQUESTED` also survives waiting. Read the reviewer: a product hold needs a human decision, not repeated patches. Report it once and stop with the blocking review quoted. ### Optional GitHub helper If kirocrew-prepare-pr is installed, run its complete script bundle from the TARGET repo, not the skill directory. Resolve an absolute `SKILL_DIR` first from the active installation; never use an unresolved default expansion as a path argument. ```bash python3 "$SKILL_DIR/scripts/pr_status.py" <pr#> --json --reviewers <known-lanes> python3 "$SKILL_DIR/scripts/pr_findings.py" <pr#> python3 "$SKILL_DIR/scripts/green_age.py" --pr <pr#> ``` Pin a known fleet with `--reviewers` / `PREPARE_PR_REVIEWERS`; discovery mode only checks stamps it finds and cannot detect an absent lane. Set the repo's aggregate via `--readiness-context` / `PREPARE_PR_READINESS_CONTEXT` where needed. The scripts require sibling `_review_contract.py`; missing scripts are not permission to pretend the helper ran. Use the host interfaces above for general monitoring. - `0`: checks clean, but still apply the readiness conditions below. - `10`: genuinely running. End the cycle silently, without rereading bot bodies, logs or diffs; it neither counts nor resets the stall streak. - `20`: use findings and the reason before acting. Terminal PR state means stop; stale reviewer stamps can mean a comment-triggered bot has not posted yet, not a code defect. `?`/JSON `null` threads mean unknown, never zero. - `2`: environment error, escalate rather than loop on it. `green_age.py` answers the separate question of whether a clean rollup still describes today's base: `0` fresh, `30` the base moved in files this PR also touches since the commit this head's CI ran on (an authorized sync, per the conflict rule above), `2` could not measure — which is neither fresh nor stale. `pr_status.py --json` carries the same reading in `advisory.green_age`, so a cycle that already polled does not need a second call. Keep it out of the stall key: on a busy repository the base moves constantly, and a commit count in the key would reset the streak forever. `--json` appends a last-line object without changing the exit code. Compare ONLY `progress_key` for stalls. Its `advisory` fields include unresolved threads, findings, stale/blocking reviewers and `elided_stamp_reviewers`. Report an elided stamp once per head as a lane-quality note, not a new blocker; the script already checks whether that shortened stamp matches the current head. Always use the target checkout even for a full PR URL: thread lookup also uses cwd, so a foreign checkout can mix two repositories. An unreadable/discarded CI rollup is an environment blocker, not a bug count or a passing empty list. ### Readiness and handoff For comment-aware legacy monitoring, declare review-ready only when all hold: - The host aggregate (or optional `pr_status.py`) is clean for the current SHA. - Threads are confirmed resolved; an unknown count needs inspection, not a guess. - Every bot/human concern has an individual answer, including advisory comments on passing checks. The current head has every required reviewer's fresh verdict and no blocking marker. Do not wait for zero findings: a rebutted or deferred finding can remain visible after it is answered. - Before rebutting a finding a lane has raised a third time, re-run that lane on the unchanged head and re-derive the claim. A third raise is either a rebuttal that did not answer the finding or a lane whose verdict is not reproducible on an identical tree, and only the re-run separates those. - No conflict, behind-base state, draft or changes-requested hold remains, and where the optional helper is installed, `green_age.py` is not reporting exit 30. - No current-head finding lacks a disposition. For Kiro Crew, use kirocrew-prepare-pr's disposition contract rather than inventing a second ledger format. Never stop silently with an unanswered finding. A blocker, budget or user stop requires an open-findings handoff, not a success claim. Structured success proves only the provider facts above; it does not satisfy this comment-aware contract. ## Stall tripwire For legacy cycles, persist a JSON progress key AND an integer streak count, read before each settled cycle. Use a durable file in the active data home's `workspace/` beside loop state, e.g. `.babysit-key-<loop-id>`, NOT scratch/TMPDIR or conversation memory. Resolve the home first; a tilde inside a shell default does not expand. The engine does not track this streak for you. For GitHub the optional helper emits these key fields; otherwise derive equivalent fields from the host verdict above. GitLab and Bitbucket need their own equivalent key before applying this rule: | Field | Meaning | |---|---| | `head_sha` | Exact revision | | `failing_checks` | Sorted workflow-qualified identities, not just names | | `checks_failing` | Failure count | | `readiness_kind` | Running, failing or unpublished | | `exit_code` | Verdict | | `status` | Verdict reason, so changed blockers count as progress | On a settled cycle (`0` or `20`), matching key increments the streak; a new key sets it to 1. Three byte-identical settled keys with no push means stop and escalate when nothing can be changed without a human. Apply a diagnosed fix within authorization instead of waiting for this tripwire. Running (`10`) cycles are skipped, not counted AND not reset; environment (`2`) escalates. The wall-clock budget bounds a wait that never settles. Exclude finding counts (rewording/rebuttals keep changing them) and thread counts (unknown API results are not progress). Preserve both key and count through compaction. A deliberate stop reason names success, the blocker or the terminal state; merely exhausting a cap is never success. With an active loop do not also wait/poll. On a deliberate early end of `wait`, read its end reason; do not reissue a wait the user stopped. Kill switches: the driver's stop tool, dashboard automation popover, cycle/turn cap and runtime budget. A STOP sentinel exists only if explicitly configured through `stop_sentinel_path` on the HTTP arming path; `monitor_start` creates none. Treat `[auto-nudge cycle N]` as your scheduled wake, not a new human request.
View on GitHub