gh-workflow-monitoring

v2026.09.24

`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.

GitHub
Install command
npx skhub add laurigates/gh-workflow-monitoring
Markdown
SKILL.md

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 watchUse 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 progressUse git-fix-pr to diagnose AND auto-correct failing checks on a PR
Chaining on a run's outcome with gh run watch --exit-statusUse github-actions-plugin:github-actions-inspection to read a finished run's logs and stack traces
Finding the latest in-progress run for a workflowUse 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

# 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:

FlagDescription
--compactShow only relevant/failed steps (less output)
--exit-statusExit non-zero if run fails
-i, --intervalRefresh interval in seconds (default: 3)

Find Runs to Monitor

# 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

# 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:

# 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:

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

# 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

# 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

# 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

# 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

# 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

# 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

ContextCommand
Watch until donegh run watch $ID --compact --exit-status
Find in-progressgh run list --status in_progress --json databaseId,name
Latest run IDgh run list -L 1 --json databaseId --jq '.[0].databaseId'
Failed logsgh run view $ID --log-failed
Scrape a succeeded step's stdoutgh run view $ID --log | awk -F'\t' '/STEP/{sub(/^[^ ]* /,"",$3);print $3}'
Trigger + watchgh workflow run "$NAME" && sleep 2 && gh run watch --compact
PR run statusgh pr checks $PR --json name,state,conclusion

Why gh run watch Over Polling

ApproachProblem
sleep + pollWastes time, may miss completion, timeout complexity
WebhookRequires infrastructure, not CLI-friendly
gh run watchBlocks 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

# 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:

- 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
Discovery
Tags

No tags published for this skill.

Version
Latest version metadata

Version

v2026.09.24

Published

Sep 24, 2026

Category

Uncategorized

License

MIT

Source path

git-plugin/skills/gh-workflow-monitoring

Default branch

main

Latest commit

1668324

Tree SHA

b2d4cc3