# Gh Workflow Monitoring

> `gh run watch` — block until a GitHub Actions run finishes, no polling loop. Use when waiting for CI after a push or following a triggered workflow to completion.

- Skill: `laurigates/gh-workflow-monitoring` (Agent Skill)
- Install (CLI): `npx skillmds@latest add laurigates/gh-workflow-monitoring`
- Raw SKILL.md: https://api.skillmd.com/api/skills/laurigates/gh-workflow-monitoring/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: laurigates (https://skillmd.com/u/laurigates)
- Updated: 2026-09-09
- Page: https://skillmd.com/skills/laurigates/gh-workflow-monitoring

---


# GitHub Workflow Monitoring

## When to Use This Skill

| Use this skill when... | Use the alternative when... |
|---|---|
| Watching a workflow run until it completes via blocking `gh run watch` | Use `gh-cli-agentic` for one-shot JSON queries of run/PR check state |
| Waiting for CI after a push, or triggering a workflow and following progress | Use `git-fix-pr` to diagnose AND auto-correct failing checks on a PR |
| Chaining on a run's outcome with `gh run watch --exit-status` | Use `github-actions-plugin:github-actions-inspection` to read a finished run's logs and stack traces |
| Finding the latest in-progress run for a workflow | Use `gh-cli-agentic` to list completed runs by status filter |

Watch and monitor GitHub Actions workflow runs using `gh run watch` - a blocking command that follows runs until completion without needing timeouts or polling.

## Core Commands

### Watch a Run Until Completion

```bash
# Watch most recent run (interactive selection if multiple)
gh run watch

# Watch specific run ID
gh run watch $RUN_ID

# Compact mode - show only relevant/failed steps (recommended for agents)
gh run watch $RUN_ID --compact

# Exit with non-zero if run fails (useful for chaining)
gh run watch $RUN_ID --exit-status

# Combined: compact output, fail on error
gh run watch $RUN_ID --compact --exit-status
```

**Key Flags**:

| Flag | Description |
|------|-------------|
| `--compact` | Show only relevant/failed steps (less output) |
| `--exit-status` | Exit non-zero if run fails |
| `-i, --interval` | Refresh interval in seconds (default: 3) |

### Find Runs to Monitor

```bash
# List in-progress runs
gh run list --status in_progress --json databaseId,name,status,createdAt

# List runs for specific workflow
gh run list -w "CI" --json databaseId,name,status,conclusion -L 5

# List runs for current branch
gh run list --branch $(git branch --show-current) --json databaseId,name,status

# List runs triggered by specific event
gh run list --event push --json databaseId,name,status -L 10

# List failed runs
gh run list --status failure --json databaseId,name,conclusion,createdAt -L 5
```

**Status Values**: `queued`, `in_progress`, `completed`, `waiting`, `pending`, `requested`

**Conclusion Values** (when completed): `success`, `failure`, `cancelled`, `skipped`, `neutral`, `timed_out`

### View Run Details

```bash
# Get run status with jobs
gh run view $RUN_ID --json status,conclusion,jobs,name,createdAt

# View with step details
gh run view $RUN_ID --verbose

# Get failed logs only (most useful for debugging)
gh run view $RUN_ID --log-failed

# Get full logs
gh run view $RUN_ID --log

# View specific job
gh run view --job $JOB_ID

# Open in browser
gh run view $RUN_ID --web
```

### Extract One Step's Bare Output from `--log`

`gh run view --log` is **tab-delimited**: every line is
`<job>\t<step>\t<timestamp> <log line>`. To scrape one step's stdout back to
its bare form — dropping the job and step columns and the per-line
timestamp — filter to the step name (field-2 substring) and strip the
timestamp, which is the first space-delimited token of field 3:

```bash
# All lines from the step whose name contains "clean warm run", de-columned
gh run view $RUN_ID --log \
  | awk -F'\t' '/clean warm run/ { sub(/^[^ ]* /, "", $3); print $3 }'
```

This is the durable way to read a **succeeded** step's output for structured
markers — `RESULT …`, a `PASS`/`FAIL` line, a JSON blob a job printed — when
`--log-failed` doesn't apply (nothing failed; you just want the output). The
whole job's log is one stream, so narrow to the step first, then grep the
markers:

```bash
gh run view $RUN_ID --log \
  | awk -F'\t' '/bench \(clean warm/ { sub(/^[^ ]* /, "", $3); print $3 }' \
  | grep -E 'RESULT|SANITY'
```

Notes: match the step name as it appears in the workflow's `name:` (the awk
`/pattern/` is a plain regex over the whole tab-joined line — anchor with a
distinctive substring to avoid matching the same text inside a log line);
`[^ ]*` matches the timestamp because it never contains a space, so a
mangled first token can't over-strip the line.

## Workflow Patterns

### Trigger and Watch

```bash
# Trigger workflow and immediately watch it
gh workflow run "CI" && sleep 2 && gh run watch --compact --exit-status

# Trigger with inputs
gh workflow run "Deploy" -f environment=staging -f version=1.2.3
```

### Wait for PR Checks

```bash
# Get the latest run for a PR's head commit
RUN_ID=$(gh run list --branch $(gh pr view $PR --json headRefName --jq '.headRefName') -L 1 --json databaseId --jq '.[0].databaseId')
gh run watch $RUN_ID --compact --exit-status
```

### Monitor Multiple Runs

```bash
# List all in-progress runs and watch the first one
gh run list --status in_progress --json databaseId,name --jq '.[0]'

# Get all active run IDs
gh run list --status in_progress --json databaseId --jq '.[].databaseId'
```

## Agentic Patterns

### Find and Watch Latest Run

```bash
# 1. Find the run
RUN_ID=$(gh run list -L 1 --json databaseId --jq '.[0].databaseId')

# 2. Watch it (blocking - waits until complete)
gh run watch $RUN_ID --compact --exit-status
```

### Diagnose Failures

```bash
# 1. Find failed run
gh run list --status failure -L 1 --json databaseId,name,conclusion

# 2. Get failed logs
gh run view $RUN_ID --log-failed
```

### CI Integration Flow

```bash
# After pushing, find and watch the triggered run
git push origin HEAD
sleep 5  # Wait for GitHub to register the run
RUN_ID=$(gh run list --branch $(git branch --show-current) -L 1 --json databaseId --jq '.[0].databaseId')
gh run watch $RUN_ID --compact --exit-status
```

## Agentic Optimizations

| Context | Command |
|---------|---------|
| Watch until done | `gh run watch $ID --compact --exit-status` |
| Find in-progress | `gh run list --status in_progress --json databaseId,name` |
| Latest run ID | `gh run list -L 1 --json databaseId --jq '.[0].databaseId'` |
| Failed logs | `gh run view $ID --log-failed` |
| Scrape a succeeded step's stdout | `gh run view $ID --log \| awk -F'\t' '/STEP/{sub(/^[^ ]* /,"",$3);print $3}'` |
| Trigger + watch | `gh workflow run "$NAME" && sleep 2 && gh run watch --compact` |
| PR run status | `gh pr checks $PR --json name,state,conclusion` |

## Why `gh run watch` Over Polling

| Approach | Problem |
|----------|---------|
| `sleep` + poll | Wastes time, may miss completion, timeout complexity |
| Webhook | Requires infrastructure, not CLI-friendly |
| `gh run watch` | Blocks until complete, shows progress, returns exit code |

**Benefits of `gh run watch`**:
- **Blocking**: Waits until run completes - no timeout management needed
- **Live updates**: Shows progress during execution
- **Exit codes**: Returns 0 on success, non-zero on failure
- **Compact mode**: `--compact` reduces output to relevant steps only
- **Chain-friendly**: Use with `&&` for conditional next steps

## Error Handling

```bash
# Watch with error handling
gh run watch $RUN_ID --compact --exit-status && echo "Success" || echo "Failed"

# Check if run exists before watching
gh run view $RUN_ID --json status 2>/dev/null && gh run watch $RUN_ID --compact
```

## Context Expressions

Use in command frontmatter:

```markdown
- In-progress runs: !`gh run list --status in_progress --json databaseId,name --jq '.[0]'`
- Latest run: !`gh run list -L 1 --json databaseId,name,status,conclusion`
```

## See Also

- **gh-cli-agentic** - General GitHub CLI patterns
- **git-branch-pr-workflow** - PR and branch workflows

