¡Hola developer 👋🏻! GitHub Copilot CLI cada vez se está volviendo más personalizable y hoy quiero enseñarte cómo he creado un status line personalizado que muestra las métricas del sistema de mi Mac, el tiempo en mi zona y qué estoy escuchando en Spotify directamente en la interfaz del CLI 🤓.
¡Ah! y también lo he creado para Windows, ¡ver más abajo!
Si quieres saber más sobre el CLI de este asistente aquí te dejo un vídeo de mi canal de YouTube donde repaso sus características principales:
Como puedes ver, en la parte inferior estoy mostrando varias métricas que me dicen: si estoy conectada por cable o no, cómo va la CPU, la memoria RAM, espacio en disco y por último el tiempo en mi zona y lo que estoy escuchando en Spotify 😃.
En tu caso podría ser esto o cualquier otra cosa que consideres útil. Lo importante en este punto es que sepas qué es lo que espera GitHub Copilot CLI. como prepararlo todo.
¿Cómo funciona el statusline de Copilot CLI?
GitHub Copilot CLI tiene una funcionalidad experimental que permite ejecutar un script externo y mostrar su salida como statusline. En cada render tick, o lo que es lo mismo cada vez que refresca el terminal:
- Ejecuta tu script como un subproceso
- Le envía un JSON payload por stdin (con info de la sesión, modelo, tokens…)
- Renderiza lo que tu script imprima por stdout
Esto nos da total libertad para mostrar lo que queramos: el tiempo, música, métricas del sistema… ¡lo que se te ocurra! Lo que si que es importante en este punto es que si no tienes activadas las funcionalidades experimentales debes entrar en una sesión y escribir:
/experimental onEl script: ~/.copilot/statusline.sh
Como al final el script se me ha quedado un poco largo… no mucho… solo 295 líneas ¡pero con muchos comentarios! lo he dejado en este gist. Así que lo único que tienes que hacer es copiarlo o descargarlo y con él crea el archivo ~/.copilot/statusline.sh con el contenido y darle permisos de ejecución (chmod +x):
chmod +x ~/.copilot/statusline.shSi te interesa saber cómo se ha conseguido cada métrica puedes seguir por aquí abajo 👇🏻 sino puedes saltar al final para ver cómo es el pegamento entre GitHub Copilot CLI y este nuevo archivo.
¿Cómo se monta cada métrica?
Cada sección del statusline recoge una información diferentes de mi máquina:
🔌 / 🔋 Batería
Detecta si estás en un Mac de sobremesa (muestra «🔌 AC») o en un portátil (muestra el porcentaje con icono de carga ⚡ si está enchufado)
# ── Batería ──────────────────────────────────────────────
# Usa pmset para leer el estado de energía.
# En un Mac de sobremesa (sin batería) muestra "🔌 AC".
# En un portátil muestra el porcentaje + icono de carga.
get_battery() {
local raw
raw=$(pmset -g batt 2>/dev/null) || { safe; return; }
local pct
pct=$(echo "$raw" | grep -oE '[0-9]+%' | head -1 | tr -d '%')
# Mac de sobremesa o sin información de batería
if [[ -z "$pct" ]]; then
if echo "$raw" | grep -qi "AC Power"; then
echo "🔌 AC"
else
safe
fi
return
fi
# Icono según nivel de batería
local icon state_icon
if (( pct >= 50 )); then icon="🔋"
elif (( pct >= 20 )); then icon="🪫"
else icon="🪫"
fi
# ⚡ si está cargando o conectado a corriente
if echo "$raw" | grep -qi "charging\|AC Power"; then
state_icon="⚡"
else
state_icon=""
fi
echo "${icon} ${pct}%${state_icon:+ ${state_icon}}"
}⚙️ CPU
Porcentaje de uso con indicador de color — 🟢 normal, 🟡 medio, 🔴 alto
# ── Uso de CPU ───────────────────────────────────────────
# `top` en macOS da una primera muestra poco fiable: suele representar
# el uso acumulado desde que arrancó el sistema. Por eso pedimos dos
# muestras (`-l 2`) y nos quedamos con la segunda, que refleja mejor el
# uso actual de CPU.
#
# Tomamos el porcentaje idle y calculamos: uso = 100 - idle.
# Así evitamos depender del formato exacto de user/sys.
#
# Color: 🟢 menos de 50% │ 🟡 50-79% │ 🔴 80% o más
get_cpu() {
local cpu_line
cpu_line=$(top -l 2 -n 0 2>/dev/null | grep "CPU usage" | tail -1) || { safe; return; }
# Extraer el % idle (siempre es el último valor antes de "idle")
local idle total
idle=$(echo "$cpu_line" | awk '{for(i=1;i<=NF;i++) if($i=="idle") print $(i-1)}' | tr -d '%')
[[ -z "$idle" ]] && { safe; return; }
total=$(awk "BEGIN { t=100-${idle}; if(t<0) t=0; if(t>100) t=100; printf \"%.0f\", t }")
local icon
if (( total >= 80 )); then icon="🔴"
elif (( total >= 50 )); then icon="🟡"
else icon="🟢"
fi
# Ancho fijo (3 caracteres) en el porcentaje: " 9%", " 19%", "100%".
# Mantiene constante el número de dígitos para que al pasar de "100%"
# a "19%" no queden dígitos residuales del render anterior.
printf '⚙️ %3d%% %s' "$total" "$icon"
}🧠 RAM
Memoria RAM en uso
# ── RAM ──────────────────────────────────────────────────
# vm_stat devuelve páginas de memoria (no bytes directamente).
# Multiplicamos por el tamaño de página (4096 bytes en macOS)
# y sumamos: activa + wired + comprimida = RAM "en uso real".
get_ram() {
local total_bytes vm page_size stats active wired compressed
total_bytes=$(sysctl -n hw.memsize 2>/dev/null) || { safe; return; }
vm=$(vm_stat 2>/dev/null) || { safe; return; }
page_size=$(echo "$vm" | awk '/page size of/ { for (i=1; i<=NF; i++) if ($i == "of") { print $(i+1); exit } }')
[[ -z "$page_size" ]] && { safe; return; }
stats=$(echo "$vm" | awk '
/Pages active/ { gsub(/\./, "", $NF); active=$NF }
/Pages wired/ { gsub(/\./, "", $NF); wired=$NF }
/Pages occupied by compressor/ { gsub(/\./, "", $NF); compressed=$NF }
END {
if (active == "") exit 1
printf "%d %d %d\n", active, wired, compressed
}
') || { safe; return; }
read -r active wired compressed <<< "$stats"
[[ -z "$active" ]] && { safe; return; }
wired=${wired:-0}
compressed=${compressed:-0}
# Convertir páginas a GB: (páginas * tamaño_página) / 1024^3
local used_gb total_gb
used_gb=$(awk "BEGIN { printf \"%.1f\", (${active} + ${wired} + ${compressed}) * ${page_size} / 1073741824 }")
total_gb=$(awk "BEGIN { printf \"%.0f\", ${total_bytes} / 1073741824 }")
echo "🧠 ${used_gb}/${total_gb}GB"
}💽 Disco
Espacio libre en el disco principal
# ── Disco ────────────────────────────────────────────────
# Espacio libre en el disco principal (/)
get_disk() {
local avail
avail=$(df -h / 2>/dev/null | awk 'NR==2 { print $4 }') || { safe; return; }
[[ -z "$avail" ]] && { safe; return; }
echo "💽 ${avail} free"
}
☀️ El tiempo meteorológico
Según tu IP el servicio de wttr.in detecta tu ubicación y te devuelve el resultado el cual puedes modelar.
# ── Tiempo meteorológico ─────────────────────────────────
# Usa wttr.in para obtener la temperatura de tu ciudad.
# No necesita API keys ni instalar nada — se auto-detecta por IP.
# Se cachea 10 minutos porque el tiempo no cambia tan rápido
# y la petición HTTP es más lenta que leer sensores locales.
get_weather() {
# Comprobar si hay cache válido del tiempo
if cache_is_fresh "$WEATHER_CACHE_FILE" "$WEATHER_CACHE_TTL"; then
cat "$WEATHER_CACHE_FILE"
return
fi
# Consultar wttr.in en una sola petición (más rápido)
# %c = emoji del tiempo (wttr.in lo elige según condición + día/noche)
# %t = temperatura, %l = localización
local raw
raw=$(curl -s --max-time 3 "wttr.in/?format=%c|%t|%l" 2>/dev/null)
[[ -z "$raw" ]] && { echo "🌡️ —"; return; }
local icon temp city
icon=$(echo "$raw" | cut -d'|' -f1 | tr -d ' ')
temp=$(echo "$raw" | cut -d'|' -f2)
city=$(echo "$raw" | cut -d'|' -f3 | sed 's/,.*//' | awk '{print toupper(substr($0,1,1)) tolower(substr($0,2))}')
[[ -z "$temp" ]] && { echo "🌡️ —"; return; }
local result="${icon} ${temp} ${city}"
# Guardar en cache del tiempo
mkdir -p "$(dirname "$WEATHER_CACHE_FILE")"
echo "$result" > "$WEATHER_CACHE_FILE"
echo "$result"
}🎵 Qué estoy escuchando en Spotify
Usando AppleScript te olvidas de tener que usar la API de Spotify.
# ── Spotify ──────────────────────────────────────────────
# Definida al principio del script porque se usa en dos sitios:
# 1) En el path cacheado (para mostrar la canción actual en vivo)
# 2) En el path fresco (cuando se recalculan todas las métricas)
# Usa AppleScript (osascript) para consultar Spotify — no necesita
# API keys ni tokens, funciona nativamente en macOS.
get_spotify() {
# Primero comprobamos si Spotify está corriendo, para no lanzarlo
# accidentalmente (osascript abriría la app si no hacemos esta comprobación)
local running
running=$(osascript -e 'tell application "System Events" to (name of processes) contains "Spotify"' 2>/dev/null)
[[ "$running" != "true" ]] && return 1
local info state track artist rest
info=$(osascript <<'APPLESCRIPT' 2>/dev/null
tell application "Spotify"
set playbackState to player state as string
if playbackState is not "playing" and playbackState is not "paused" then return ""
return playbackState & linefeed & (name of current track) & linefeed & (artist of current track)
end tell
APPLESCRIPT
) || return 1
[[ -z "$info" ]] && return 1
state=${info%%$'\n'*}
rest=${info#*$'\n'}
track=${rest%%$'\n'*}
artist=${rest#*$'\n'}
[[ "$state" != "playing" && "$state" != "paused" ]] && return 1
[[ -z "$track" ]] && return 1
# Truncar nombres largos para que el statusline quepa en pantalla
(( ${#track} > 25 )) && track="${track:0:22}..."
(( ${#artist} > 20 )) && artist="${artist:0:17}..."
# 🎵 si está sonando, ⏸️ si está en pausa
local icon="🎵"
[[ "$state" == "paused" ]] && icon="⏸️"
echo "${icon} ${track} – ${artist}"
}
add_live_spotify() {
local line="$1" spotify
spotify=$(get_spotify 2>/dev/null)
[[ -n "$spotify" ]] && line="${line} │ ${spotify}"
echo "$line"
}El truco del cache
Copilot CLI ejecuta el script en cada render tick. Si cada ejecución tardara 10-15 segundos la experiencia sería horrible. Por eso el script implementa un sistema de cache:
- Guarda el resultado en
~/.copilot/.system-statusline.cache - Si el cache tiene menos de 30 segundos, devuelve el valor cacheado en lugar de recalcular
- El TTL es configurable con la variable de entorno
SYSTEM_CACHE_TTL
Configurar GitHub Copilot CLI
Con el script ya en su sitio lo último que te queda por hacer es editar tu archivo ~/.copilot/settings.json y añade la configuración del statusline. Desde aquí también puedes habilitar el modo experimental:
{
"experimental": true,
"statusLine": {
"type": "command",
"command": "~/.copilot/statusline.sh",
"padding": 1
},
"footer": {
"showCustom": true
}
}Después, reinicia Copilot CLI con /restart o abre una nueva sesión. ¡Y listo! Verás las métricas de tu sistema, el tiempo y tu música directamente en la barra inferior.
Lo mismo pero para Windows
Si tu sistema operativo es Windows, te dejo también este gist donde puedes ver la versión compatible para PowerShell. Y así es como se ve:

¡Nos vemos 👋🏻!


