/ci-monitor
Watch GitLab CI and investigate pipeline failures. Use when a pipeline or job is failing or red, when watching MR CI, branch builds, or a specific pipeline, when waiting for CI to go green, or when authoring or validating .gitlab-ci.yml.
$ npx -y skills add bendrucker/claude --skill ci-monitor --agent claude-codeHow 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.
- You can call itInvoke it directly when you want it.
- Slash command
/ci-monitor
Context preview
The summary Claude sees to decide when to auto-load this skill.
Watch GitLab CI and investigate pipeline failures. Use when a pipeline or job is failing or red, when watching MR CI, branch builds, or a specific pipeline, when waiting for CI to go green, or when authoring or validating .gitlab-ci.yml.
SKILL.md
ci-monitor.SKILL.mdname: gitlab:ci-monitor
description: Watch GitLab CI and investigate pipeline failures. Use when a pipeline or job is failing or red, when watching MR CI, branch builds, or a specific pipeline, when waiting for CI to go green, or when authoring or validating .gitlab-ci.yml.
argument-hint: "[mr-url | branch | pipeline-id] [--max-minutes N] [--project group/project]"
effort: low
allowed-tools:
- Monitor
- TaskStop
- Agent
- Bash(bun:*)
- Bash(glab ci:*)
- Bash(glab api:*)
- Bash(glab mr view:*)
- Bash(git remote:*)
- Bash(jq:*)
CI Monitor
Watch a GitLab pipeline (for an MR, a branch, or a specific pipeline ID), reacting to failures by dispatching the `gitlab:logs` agent for diagnostics. Exits cleanly when the pipeline is green, the MR is closed, a pipeline-id target reaches a terminal status, or the wall-clock cap is hit.
Target
$ARGUMENTS
Accepts an MR URL, a branch name, a pipeline ID, or derives one from the current branch:
- MR mode: pass a URL like `https://gitlab.com/group/project/-/merge_requests/123`.
- Branch mode: pass a branch name (e.g. `main`, a release branch). Project path `group/project` is inferred from `git remote get-url origin` in the current directory; pass `--project <group/project>` to override.
- Pipeline-id mode: pass a pipeline ID (e.g. from a manually-triggered pipeline or a re-run). Project is inferred from the git remote; override with `--project <group/project>`.
- No argument: derive an MR URL from the current branch: `glab mr view --output json | jq -r '.web_url'`.
Workflow
Start the monitor
Launch the watch script via the `Monitor` tool with `persistent: true`:
- MR mode: `bun ${CLAUDE_SKILL_DIR}/scripts/watch.ts --mr <mr-url>`
- Branch mode: `bun ${CLAUDE_SKILL_DIR}/scripts/watch.ts --branch <name> [--project <group/project>]`
- Pipeline-id mode: `bun ${CLAUDE_SKILL_DIR}/scripts/watch.ts --pipeline-id <id> [--project <group/project>]`
- Optional flags: `--interval <seconds>`, `--max-minutes <N>`, `--queued-timeout <minutes>`, `--api-error-threshold <N>`.
Exactly one of `--mr`, `--branch`, or `--pipeline-id` is required. In branch and pipeline-id modes, `--project` is inferred from the current git remote when omitted. Pipeline-id mode queries `glab api projects/:id/pipelines/:pid` directly; if the pipeline does not exist the watcher exits non-zero on the first call.
MR mode resolves the pipeline from `projects/:id/merge_requests/:iid/pipelines` and branch mode from `projects/:id/pipelines?ref=<branch>`. Both ignore `external` pipelines (commit statuses posted by other tools, which carry no CI jobs) and `parent_pipeline` pipelines (children the parent already aggregates), and each prefers its own kind: `merge_request_event` in MR mode, branch pipelines in branch mode.
The script emits one JSON object per line on stdout. When the first probe is already green, it emits a single `status: success` event and exits, so there is no separate initial-green path. In pipeline-id mode it also exits after emitting `status: failing`, because a specific pipeline has a finite lifetime and will not restart on its own.
Event schema
Each line is one of:
- `{"type":"status","state":"running|failing|success","sha":"...","run_id":"..."}`: `run_id` is the GitLab pipeline ID. A `success` is confirmed against the pipeline's jobs before it is emitted, so a pipeline reporting `success` while a required job failed is reported as `failing`.
- `{"type":"conflicts","sha":"..."}`: MR reports merge conflicts against the target branch. MR mode only.
- `{"type":"mergeable-unknown","sha":"..."}`: GitLab could not settle merge status after bounded re-polling. MR mode only.
- `{"type":"queued-timeout","minutes":N}`: pipeline has been queued longer than the threshold.
- `{"type":"api-error","consecutive":N}`: consecutive `glab` failures crossed the threshold.
- `{"type":"rate-limited","retry_after":"..."}`: emitted only when `glab` surfaces structured rate-limit data.
- `{"type":"pr-closed"}`: MR closed without merging, or the source branch was deleted. MR mode only. The script exits after emitting.
- `{"type":"merged"}`: MR merged. MR mode only. The script exits after emitting.
- `{"type":"max-time-reached","minutes":60}`: wall-clock cap hit. The script exits after emitting.
In branch and pipeline-id modes, `conflicts`, `mergeable-unknown`, `pr-closed`, and `merged` are never emitted (there is no MR metadata to derive them from). `merged` and `pr-closed` are distinct terminal events: `merged` means the MR landed, `pr-closed` means it closed without merging.
The script exits on `status: success` in every mode, but only once that success survives the job-level confirmation above. A pipeline whose jobs cannot be read keeps the watcher polling rather than exiting green, surfacing as `api-error` if it persists. In pipeline-id mode it also exits on `status: failing` (the pipeline is terminal).
React to events
On `status: failing`, invoke the `gitlab:logs` agent via the `Agent` tool with the pipeline ID from `run_id`. This applies to all three modes; the logs agent accepts a pipeline ID, so pipeline-id mode fits:
Agent(
subagent_type="gitlab:logs",
model="haiku",
prompt="Fetch failing-job logs for pipeline <run_id>. Return the JSON summary described in the logs agent definition."
)
Surface the summary to the parent conversation. Do not attempt fixes; `pull-request:babysit` owns that decision.
On `conflicts`, report the SHA with conflicts and stop watching; conflict resolution belongs to the caller.
On `mergeable-unknown`, report the SHA; the caller decides whether to run an authoritative local check.
On `queued-timeout`, `api-error`, or `rate-limited`, surface the event once and keep the monitor running. Consecutive rate-limit or api-error events mean the monitor should be stopped manually.
On `merged`, `pr-closed`, or `max-time-reached`, the monitor has already exited. Report and finish.
Stopping
The monito
Read more
name: gitlab:ci-monitor description: Watch GitLab CI and investigate pipeline failures. Use when a pipeline or job is failing or red, when watching MR CI, branch builds, or a specific pipeline, when waiting for CI to go green, or when authoring or validating .gitlab-ci.yml. argument-hint: "[mr-url | branch | pipeline-id] [--max-minutes N] [--project group/project]" effort: low allowed-tools: - Monitor - TaskStop - Agent - Bash(bun:*) - Bash(glab ci:*) - Bash(glab api:*) - Bash(glab mr view:*) - Bash(git remote:*) - Bash(jq:*)
CI Monitor
Watch a GitLab pipeline (for an MR, a branch, or a specific pipeline ID), reacting to failures by dispatching the `gitlab:logs` agent for diagnostics. Exits cleanly when the pipeline is green, the MR is closed, a pipeline-id target reaches a terminal status, or the wall-clock cap is hit.
Target
$ARGUMENTS
Accepts an MR URL, a branch name, a pipeline ID, or derives one from the current branch:
- MR mode: pass a URL like `https://gitlab.com/group/project/-/merge_requests/123`.
- Branch mode: pass a branch name (e.g. `main`, a release branch). Project path `group/project` is inferred from `git remote get-url origin` in the current directory; pass `--project <group/project>` to override.
- Pipeline-id mode: pass a pipeline ID (e.g. from a manually-triggered pipeline or a re-run). Project is inferred from the git remote; override with `--project <group/project>`.
- No argument: derive an MR URL from the current branch: `glab mr view --output json | jq -r '.web_url'`.
Workflow
Start the monitor
Launch the watch script via the `Monitor` tool with `persistent: true`:
- MR mode: `bun ${CLAUDE_SKILL_DIR}/scripts/watch.ts --mr <mr-url>`
- Branch mode: `bun ${CLAUDE_SKILL_DIR}/scripts/watch.ts --branch <name> [--project <group/project>]`
- Pipeline-id mode: `bun ${CLAUDE_SKILL_DIR}/scripts/watch.ts --pipeline-id <id> [--project <group/project>]`
- Optional flags: `--interval <seconds>`, `--max-minutes <N>`, `--queued-timeout <minutes>`, `--api-error-threshold <N>`.
Exactly one of `--mr`, `--branch`, or `--pipeline-id` is required. In branch and pipeline-id modes, `--project` is inferred from the current git remote when omitted. Pipeline-id mode queries `glab api projects/:id/pipelines/:pid` directly; if the pipeline does not exist the watcher exits non-zero on the first call.
MR mode resolves the pipeline from `projects/:id/merge_requests/:iid/pipelines` and branch mode from `projects/:id/pipelines?ref=<branch>`. Both ignore `external` pipelines (commit statuses posted by other tools, which carry no CI jobs) and `parent_pipeline` pipelines (children the parent already aggregates), and each prefers its own kind: `merge_request_event` in MR mode, branch pipelines in branch mode.
The script emits one JSON object per line on stdout. When the first probe is already green, it emits a single `status: success` event and exits, so there is no separate initial-green path. In pipeline-id mode it also exits after emitting `status: failing`, because a specific pipeline has a finite lifetime and will not restart on its own.
Event schema
Each line is one of:
- `{"type":"status","state":"running|failing|success","sha":"...","run_id":"..."}`: `run_id` is the GitLab pipeline ID. A `success` is confirmed against the pipeline's jobs before it is emitted, so a pipeline reporting `success` while a required job failed is reported as `failing`.
- `{"type":"conflicts","sha":"..."}`: MR reports merge conflicts against the target branch. MR mode only.
- `{"type":"mergeable-unknown","sha":"..."}`: GitLab could not settle merge status after bounded re-polling. MR mode only.
- `{"type":"queued-timeout","minutes":N}`: pipeline has been queued longer than the threshold.
- `{"type":"api-error","consecutive":N}`: consecutive `glab` failures crossed the threshold.
- `{"type":"rate-limited","retry_after":"..."}`: emitted only when `glab` surfaces structured rate-limit data.
- `{"type":"pr-closed"}`: MR closed without merging, or the source branch was deleted. MR mode only. The script exits after emitting.
- `{"type":"merged"}`: MR merged. MR mode only. The script exits after emitting.
- `{"type":"max-time-reached","minutes":60}`: wall-clock cap hit. The script exits after emitting.
In branch and pipeline-id modes, `conflicts`, `mergeable-unknown`, `pr-closed`, and `merged` are never emitted (there is no MR metadata to derive them from). `merged` and `pr-closed` are distinct terminal events: `merged` means the MR landed, `pr-closed` means it closed without merging.
The script exits on `status: success` in every mode, but only once that success survives the job-level confirmation above. A pipeline whose jobs cannot be read keeps the watcher polling rather than exiting green, surfacing as `api-error` if it persists. In pipeline-id mode it also exits on `status: failing` (the pipeline is terminal).
React to events
On `status: failing`, invoke the `gitlab:logs` agent via the `Agent` tool with the pipeline ID from `run_id`. This applies to all three modes; the logs agent accepts a pipeline ID, so pipeline-id mode fits:
Agent( subagent_type="gitlab:logs", model="haiku", prompt="Fetch failing-job logs for pipeline <run_id>. Return the JSON summary described in the logs agent definition." )
Surface the summary to the parent conversation. Do not attempt fixes; `pull-request:babysit` owns that decision.
On `conflicts`, report the SHA with conflicts and stop watching; conflict resolution belongs to the caller.
On `mergeable-unknown`, report the SHA; the caller decides whether to run an authoritative local check.
On `queued-timeout`, `api-error`, or `rate-limited`, surface the event once and keep the monitor running. Consecutive rate-limit or api-error events mean the monitor should be stopped manually.
On `merged`, `pr-closed`, or `max-time-reached`, the monitor has already exited. Report and finish.
Stopping
The monito
Showing the first part of this file.
My personal plugin marketplace for Claude Code, Anthropic's AI coding assistant.
Repo: bendrucker/claude
Other skills on bendrucker-claude.
- /agent-ideas
Harvest agent-tooling ideas from prominent developers.
Open skill - /cleye
Type-safe CLI argument parsing with cleye, the standard parser for this repo's Bun scripts. Use when writing or editing any script that takes arguments (flags, positional parameters, subcommands, --help) instead of reading existing scripts for the pattern.
Open skill - /coverage
Measure Bun test coverage and close gaps on a specific file. Use when adding or editing tests, when asked about coverage, or when the PostToolUse coverage hook reports uncovered lines.
Open skill - /activity
Report real device usage from ActivityWatch. Covers per-app time, window titles, and active vs idle spans. Use when asked "what apps did I use", "how long was I in X", "what did I work on today", "how much was I active vs idle", or to mine usage patterns for automation.
Open skill - /history
Report shell history from atuin's local capture. Covers what commands ran, when, where, and how they exited. Use when asked "what commands did I run", "what was I working on in the terminal", "have I ever run X", "how do I usually invoke X", or about recent shell activity,
Open skill - /bun
Bun runtime patterns. Use when running bun commands, working with package.json/bun.lock, writing TypeScript scripts under Bun, or developing Claude Code plugins.
Open skill

