Skip to content

Instantly share code, notes, and snippets.

@simoninglis
Created February 3, 2026 00:19
Show Gist options
  • Select an option

  • Save simoninglis/884482b8e808dc588779d4612c6adb90 to your computer and use it in GitHub Desktop.

Select an option

Save simoninglis/884482b8e808dc588779d4612c6adb90 to your computer and use it in GitHub Desktop.
CI status in tmux status bar (GitHub Actions + Gitea Actions)

CI Status in tmux Status Bar

Put your CI build status in your tmux status bar. Know immediately when something breaks.

C:✓ B:✓ D:✓ V:✓ │ 14:32 01-Feb

Why?

When you're doing trunk-based development, you need to know immediately when CI fails. Not 10 minutes later when you context-switch. Not at the end of the day.

The best gate is one you can't forget to check. When it's in your peripheral vision all day, you're not going to forget.

Scripts

Script Platform Requires
ci-status-github.sh GitHub Actions gh CLI
ci-status-gitea.sh Gitea Actions teax

Setup

1. Download the script

# GitHub users
curl -o ~/.local/bin/ci-status.sh \
  https://gist.githubusercontent.com/.../ci-status-github.sh
chmod +x ~/.local/bin/ci-status.sh

# Gitea users
curl -o ~/.local/bin/ci-status.sh \
  https://gist.githubusercontent.com/.../ci-status-gitea.sh
chmod +x ~/.local/bin/ci-status.sh

2. Configure the script

Edit the script and set your repo:

REPO="owner/repo"

For Gitea with self-signed certs, uncomment:

export TEAX_INSECURE=1

3. Add to tmux

In your .tmux.conf or session script:

# Simple - just CI status
set -g status-right '#(~/.local/bin/ci-status.sh) │ %H:%M'

# With refresh interval (default is 15s, this sets 30s)
set -g status-interval 30

4. Per-project scripts

For multiple projects, put the script in each project and reference it:

# In your tmux session setup
set -g status-right '#($PROJECT_DIR/scripts/ci-status.sh) │ %H:%M'

Output

Output Meaning
CI:✓ All workflows passed
CI:✗ Something failed
CI:⏳ Running
CI:- No runs found for this commit
CI:? Error (not in repo, API issue, etc.)
+3 3 unpushed commits (showing remote CI status)

Gitea multi-workflow output

The Gitea script shows individual workflow status:

C:✓ B:✓ D:✓ V:✓

Where:

  • C = ci.yml (lint, test)
  • B = build.yml
  • D = staging-deploy.yml
  • V = staging-verify.yml

Customize the WORKFLOWS variable to match your pipeline.

Unpushed commit indicator

When your local branch is ahead of remote, the scripts show what CI actually ran (remote HEAD) plus how many commits you haven't pushed:

CI:✓ +3

This means: "CI passed for what's on the server, but you have 3 local commits not yet pushed."

Related

License

MIT

#!/bin/bash
# CI status for tmux status bar - Gitea Actions version
# Requires: teax (https://github.com/simoninglis/teax)
#
# Usage: Add to tmux status bar:
# set -g status-right '#(/path/to/ci-status-gitea.sh)'
#
# Output examples:
# C:✓ B:✓ D:✓ V:✓ # All green
# C:✓ B:✗ D:- V:- # Build failed
# C:✓ B:✓ D:✓ V:✓ +3 # Green but 3 unpushed commits
# CI:? # Error or not in git repo
# Configuration - customize these
REPO="owner/repo" # Your Gitea repo
WORKFLOWS="C:ci.yml,B:build.yml,D:staging-deploy.yml,V:staging-verify.yml"
# For self-signed certs, uncomment:
# export TEAX_INSECURE=1
cd "$(git rev-parse --show-toplevel 2>/dev/null)" || { echo "CI:?"; exit 0; }
LOCAL_SHA=$(git rev-parse --short HEAD 2>/dev/null) || { echo "CI:?"; exit 0; }
REMOTE_SHA=$(git rev-parse --short origin/main 2>/dev/null) || { echo "CI:?"; exit 0; }
get_ci_status() {
local sha="$1"
local result
local exit_code
result=$(teax -o tmux runs status -r "$REPO" --sha "$sha" --show "$WORKFLOWS" 2>/dev/null)
exit_code=$?
case $exit_code in
0) echo "$result" ;; # All passed
1) echo "$result" ;; # Some failed (still show status)
2) echo "$result" ;; # Running
3) echo "CI:-" ;; # No runs found
*) echo "CI:?" ;; # Error
esac
}
if [ "$LOCAL_SHA" != "$REMOTE_SHA" ]; then
# Local ahead of remote - show remote status + unpushed count
AHEAD_COUNT=$(git rev-list origin/main..HEAD --count 2>/dev/null || echo "?")
STATUS=$(get_ci_status "$REMOTE_SHA")
echo "${STATUS} +${AHEAD_COUNT}"
else
get_ci_status "$LOCAL_SHA"
fi
#!/bin/bash
# CI status for tmux status bar - GitHub Actions version
# Requires: gh CLI (https://cli.github.com)
#
# Usage: Add to tmux status bar:
# set -g status-right '#(/path/to/ci-status-github.sh)'
#
# Output examples:
# CI:✓ # Latest run passed
# CI:✗ # Latest run failed
# CI:⏳ # Running
# CI:✓ +3 # Passed but 3 unpushed commits
# CI:? # Error or not in git repo
# Configuration - customize these
REPO="owner/repo" # Your GitHub repo (or leave empty to auto-detect)
cd "$(git rev-parse --show-toplevel 2>/dev/null)" || { echo "CI:?"; exit 0; }
# Auto-detect repo from git remote if not set
if [ -z "$REPO" ]; then
REPO=$(gh repo view --json nameWithOwner -q .nameWithOwner 2>/dev/null) || { echo "CI:?"; exit 0; }
fi
LOCAL_SHA=$(git rev-parse --short HEAD 2>/dev/null) || { echo "CI:?"; exit 0; }
REMOTE_SHA=$(git rev-parse --short origin/main 2>/dev/null) || { echo "CI:?"; exit 0; }
get_ci_status() {
local sha="$1"
local status conclusion
# Get the latest workflow run for this commit
read -r status conclusion < <(gh run list --repo "$REPO" --commit "$sha" --limit 1 \
--json status,conclusion -q '.[0] | "\(.status) \(.conclusion)"' 2>/dev/null)
if [ -z "$status" ]; then
echo "CI:-"
return
fi
case "$status" in
completed)
case "$conclusion" in
success) echo "CI:✓" ;;
failure) echo "CI:✗" ;;
cancelled) echo "CI:⊘" ;;
*) echo "CI:?" ;;
esac
;;
in_progress|queued|waiting)
echo "CI:⏳"
;;
*)
echo "CI:?"
;;
esac
}
if [ "$LOCAL_SHA" != "$REMOTE_SHA" ]; then
AHEAD_COUNT=$(git rev-list origin/main..HEAD --count 2>/dev/null || echo "?")
STATUS=$(get_ci_status "$REMOTE_SHA")
echo "${STATUS} +${AHEAD_COUNT}"
else
get_ci_status "$LOCAL_SHA"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment