Statusline theme
Skill dox187/usage-aware-claude-statusline/.claude/skills/statusline-theme
Usage-aware status line for Claude Code: session & weekly rate-limit gauges with reset countdowns and a precise context-window meter, plus tokens, git & weather. Template-driven and extensible — set it up by chatting with Claude or via a TUI. Pure-stdlib Python, no pip install. macOS, Linux & Windows.
npx -y skills add dox187/usage-aware-claude-statusline --skill statusline-themeAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Owns ALL color decisions for the Claude Code statusline. Use when the user wants to "theme my statusline", "apply Catppuccin/Dracula/Nord/Gruvbox/Tokyo Night/One Dark/Solarized/Monokai/Rose Pine/Everforest/Ayu", "change the colors", "use a <palette> color scheme", "make <element> <color>" (e.g. "make branch green", "turn the model name red"), "recolor the branch/path/time", or "snap my colors to <palette>". Three modes: apply a whole palette, recolor named elements, or snap existing colors to the nearest palette color.
SKILL.md
18.8 KB, as published. Nobody here has run it
statusline-theme
Set the colors block of statusline_config.json for the usage-aware Claude
Code statusline. You handle three jobs:
- (A) Apply a palette — map every non-semantic color KEY onto a bundled palette and write the resolved hex values.
- (B) Recolor element(s) — change only the specific keys the user named ("make branch green", "model should be #ff0066").
- (C) Snap to a palette — replace each current color with the nearest color in a chosen palette, measured by CIEDE2000 (perceptual distance).
Hard rules (never violate)
- Never recolor the SEMANTIC band keys —
ctx_bar,ctx_bar_mid,ctx_bar_high,ctx_bar_crit,ctx_bar_max,ctx_bar_track— unless the user explicitly opts in ("also theme the gauge bands", "recolor the severity bands too"). These encode a green to red severity ramp shared by the context gauge AND the usage gauges; recoloring them silently would break the meaning. When in doubt, leave them out and say so. Likewise, never recolor the SEMANTIC status/incident keys —status_investigating,status_identified,status_monitoring,status_maintenance,status_default,status_title,status_count,status_header— unless the user explicitly opts in ("also theme the incident colors", "recolor the status indicator too"). These encode Claude service incident severity and have universally understood meaning; recoloring them silently would make the statusline misleading. - Confirm before writing. Always: resolve the ACTIVE config (Step 0) ->
read it -> compute new colors -> show BEFORE/AFTER swatches + a diff ->
test-render -> get explicit confirmation -> only THEN commit (via the helper's
commit, see "Writing the result"). Never write without a yes. - Only touch the
colorsblock. Preservetemplates,weather,emoji_width,ctx_bar_empty, and every_comment/_-prefixed key exactly as-is. Commit the whole file back, changing onlycolors. Never blind-overwrite the active config; install only via the helper's history-awarecommitso the prior version is snapshotted first. - Valid hex only. Every value must be
#RRGGBB. Invalid values are silently ignored by the renderer, so never emit them. - English only in everything you show and write.
Files in this skill
palettes.json— 15 palettes, each with 9 ROLES (text, muted, red, peach, yellow, green, sky, blue, mauve), verified hex.rolemap.json— the KEY -> ROLE map for "apply palette" mode, plus the optional band opt-in map.colorutil.py— stdlib-only: hex<->rgb, sRGB->XYZ->Lab,ciede2000,nearest_color, andswatch_line/print_swatchesfor truecolor previews.assets/sample_input.json— canonical Claude Code session JSON for test renders.
Read palettes.json and rolemap.json on demand (don't paste them inline
unless needed). Run colorutil.py via the shell for math and swatches.
The shared active-config + history helper lives in the sibling
statusline-config skill (one copy only, stdlib): from this skill it is
../statusline-config/statusline_io.py. You call it as a CLI subprocess; you
never import it.
Step 0 — Resolve the ACTIVE statusline (do this first)
Claude Code runs a specific statusline — usually the deployed copy (e.g.
~/.claude/statusline.py), NOT the repo copy. You MUST theme the config that
the active renderer actually reads, not a hardcoded repo path. Resolve it with
the sibling helper:
python <skills-dir>/statusline-config/statusline_io.py locate
<skills-dir> is the directory containing this skill; from here the helper is
../statusline-config/statusline_io.py. Parse the JSON it prints and read
config_path (the active config you will theme) and statusline_py (the
renderer used for test renders). Handle source:
"pointer"— a saved pointer resolved it. Useconfig_pathdirectly."settings"— derived from the activesettings.json. Useconfig_path, and OFFER to save a pointer so future runs are instant:python <skills-dir>/statusline-config/statusline_io.py save-pointer --statusline-py <statusline_py> --config <config_path> [--settings <settings_json>] [--launcher <launcher>]."none"— nothing resolvable. Ask the user where their statusline is installed (thestatusline.pyand itsstatusline_config.json), then offer to save a pointer viasave-pointerfor next time.
Use the resolved config_path everywhere below as the live config to read and
(after confirmation) commit to. Never assume the repo path. If config_path is
missing or unreadable, fall back to renderer defaults but tell the user and
prefer to confirm the real path.
Config locations
- Live config: the
config_pathreturned by Step 0 — the file the ACTIVE renderer reads (usually the deployedstatusline_config.jsonnext to the deployedstatusline.py, or the path in$STATUSLINE_CONFIGbaked into thestatusLine.command). Do NOT hardcode the repo path; the repo copy is often not the active one. - The full set of non-semantic color KEYS you may set:
time, version, model, effort, peak, offpeak, offpeak_warn, usd, ctx_label, ctx_value, ctx_percent, ctx_icon, model_icon, total_icon, total, bracket, input, separator, output, cached_icon, cached, path, git_icon, branch, git_status, changes, weather, ctx_bracket. - The status/incident color keys (
status_investigating,status_identified,status_monitoring,status_maintenance,status_default,status_title,status_count,status_header) are semantic and excluded from automatic palette application. They may only be set on explicit user opt-in (see Hard rule 1 and Mode A). - The user's config may only define a subset of these. When applying a palette, set the keys the rolemap covers that are already present, plus any the user asks for. Don't invent keys the user never had unless they explicitly want a full palette application across every key.
Listing palettes
When the user asks "what palettes / themes are there?", read palettes.json and
list each id with its _label. Optionally render a one-line swatch per palette
so they can see it (see "Showing swatches"). The ids are:
catppuccin-latte, catppuccin-frappe, catppuccin-macchiato, catppuccin-mocha, dracula, nord, gruvbox-dark, tokyo-night, one-dark, solarized-dark, solarized-light, monokai, rose-pine, everforest-dark, ayu-dark.
Accept fuzzy names: "catppuccin" -> ask which flavor (default mocha); "solarized"
-> ask dark vs light; "tokyonight"/"tokyo" -> tokyo-night; "rose pine" ->
rose-pine; "everforest" -> everforest-dark; "ayu" -> ayu-dark.
The standard loop (every mode)
- Resolve the ACTIVE config first (see "Step 0") and use its
config_pathas the live file for every step below. - Read the active
config_path. Capture the existingcolorsobject (call it BEFORE). If the file is missing/invalid, start from the renderer defaults — but tell the user, and prefer to ask for the real path. - Compute the AFTER
colorsobject per the chosen mode (below). - Preview: print BEFORE vs AFTER truecolor swatches and a key-by-key diff (only the keys that change). Note explicitly that the semantic band keys are left untouched (unless opted in).
- Validate: every AFTER value matches
^#[0-9a-fA-F]{6}$. - Test-render with the canonical sample input against a CANDIDATE config so the live file is untouched (see "Test render").
- Confirm: ask the user to approve. Only on an explicit yes do you commit.
- Commit the full config (only
colorschanged) history-aware via the helper'scommitsubcommand (see "Writing the result").
Mode A — apply a whole palette
- Resolve the palette id (ask to disambiguate flavors if needed). Read its role
hex values from
palettes.json. - Read
rolemap.json->roles. For each KEY inroles, look up its ROLE, then the role's hex in the palette. That hex becomes the new value for that key. - Build AFTER = current
colorswith those keys overwritten. Do not add the band keys. If the user has band keys already set, leave them as they are. - Band opt-in: only if the user explicitly asked to theme the bands, also
apply
rolemap.json->bands_optin(ctx_bar/ctx_bar_mid -> green, ctx_bar_high -> peach, ctx_bar_crit/ctx_bar_max -> red, ctx_bar_track -> muted). Otherwise say "leaving the severity bands at their defaults". - Status opt-in: only if the user explicitly asked to theme the incident/
status colors ("also theme the incident colors", "recolor the status
indicator too"), also apply
rolemap.json->status_optin(status_investigating -> peach, status_identified/status_header -> red, status_monitoring -> blue, status_maintenance -> sky, status_default -> yellow, status_title/status_count -> muted). Otherwise say "leaving the incident severity colors at their defaults". - Preview, validate, test-render, confirm, commit (history-aware, see "Writing the result").
Mapping reference (authoritative copy is rolemap.json):
time->yellow version->muted model->red effort->blue
ctx_label/ctx_value/ctx_icon/model_icon/total_icon->muted
git_icon/bracket/separator/cached_icon->muted
ctx_percent->text ctx_bracket->text
total->green input->red output->blue cached->mauve
path->blue branch/git_status/changes->yellow
weather->sky peak->red offpeak->green offpeak_warn->peach usd->green
Mode B — recolor named element(s)
The user names one or more elements and a color each ("make branch green", "path #88c0d0", "turn the time gold").
- Map each named element to a KEY. Common phrasings:
- "branch" ->
branch(consider alsogit_status/changesif they say "git status colors" — ask if ambiguous). - "path"/"cwd"/"directory" ->
path. - "model"/"model name" ->
model. "time"/"clock" ->time. - "version" ->
version. "weather" ->weather. "effort" ->effort. - "context %"/"ctx percent" ->
ctx_percent. "brackets" ->bracket(and/orctx_bracket— ask). "input/output/cached tokens" ->input/output/cached. "total" ->total. - "status indicator"/"incident indicator"/"investigating color" ->
status_investigating; "identified color" ->status_identified; "monitoring color" ->status_monitoring; "maintenance color" ->status_maintenance; "status default color" ->status_default; "status title color" ->status_title; "status count color" ->status_count; "status banner"/"incident banner"/"status header" ->status_header. When the user says "recolor the status/incident colors" without specifying a severity, ask which states they want to change (or offer to apply the fullstatus_optinpalette mapping). - If the named element is one of the band keys or status/incident keys, STOP and confirm the opt-in first, because that overrides the severity ramp.
- "branch" ->
- Resolve the requested color:
- A hex (
#rrggbbor#rgb): use it (normalize viacolorutil.hex_to_rgb/rgb_to_hex). - A color word ("green", "gold", "sky blue"): pick a sensible hex. If a palette is in play (the config already looks like a known palette, or the user mentions one), prefer that palette's matching role. Otherwise use a reasonable common value and SHOW it so the user can veto.
- A hex (
- AFTER = current
colorswith just those keys changed. Preview only the changed keys, validate, test-render, confirm, commit (history-aware).
Mode C — snap to the nearest palette color
"Snap my colors to Nord", "make my current colors match Gruvbox as closely as possible." This keeps the user's per-key intent but pulls each color onto the chosen palette.
-
Resolve the palette id; read its 9 role hexes as the candidate set.
-
For each NON-SEMANTIC key currently in
colors, compute the nearest palette color by CIEDE2000 and use it as the AFTER value. Usecolorutil:python <skill>/colorutil.py # self-test (<skill> = this skill's directory)For the snapping itself, import the helper or run a tiny inline script. On macOS/Linux a bash heredoc works; on Windows/PowerShell write the snippet to a temp
.pyfile and run it (PowerShell has no heredoc). Use the activeconfig_pathfrom Step 0 for the config you read, and this skill's own directory forcolorutil.py/palettes.json. Bash example (substitute the resolvedconfig_pathfor<config_path>and this skill's dir for<skill>):python3 - <<'PY' import json, sys sys.path.insert(0, "<skill>") import colorutil pal = json.load(open("<skill>/palettes.json")) cur = json.load(open("<config_path>")).get("colors", {}) roles = [v for k, v in pal["nord"].items() if not k.startswith("_")] bands = {"ctx_bar","ctx_bar_mid","ctx_bar_high","ctx_bar_crit","ctx_bar_max","ctx_bar_track"} status = {"status_investigating","status_identified","status_monitoring","status_maintenance","status_default","status_title","status_count","status_header"} for key, hexv in cur.items(): if key.startswith("_") or key in bands or key in status: # never snap band or status keys by default continue try: best, de = colorutil.nearest_color(hexv, roles) except ValueError: continue print(f"{key}: {hexv} -> {best} (dE00={de:.2f})") PYSwap
nordfor the chosen palette id and adjust the paths (the activeconfig_pathand this skill's dir). Skip the band keys (and_-prefixed keys) in the loop unless the user opted in. -
AFTER = current
colorswith each non-semantic key replaced by its nearest palette hex. Preview (show the per-key delta-E so the user sees how far each moved), validate, test-render, confirm, commit (history-aware).
Showing swatches (BEFORE/AFTER preview)
Use colorutil.swatch_line / print_swatches to render truecolor blocks so the
user can actually see the colors in the terminal. Example: build a list of
(label, hex) for the changed keys and print two lines, BEFORE and AFTER. On
Windows/PowerShell write the snippet to a temp .py file and run it (no
heredoc); the bash heredoc below is illustrative for macOS/Linux.
python3 - <<'PY'
import sys
sys.path.insert(0, "<skill>") # this skill's directory
import colorutil
before = [("model","#E06C75"), ("branch","#E5C07B"), ("path","#61AFEF")]
after = [("model","#f38ba8"), ("branch","#f9e2af"), ("path","#89b4fa")]
print("BEFORE:"); colorutil.print_swatches(before)
print("AFTER: "); colorutil.print_swatches(after)
PY
Also show a plain text diff of just the changed keys, e.g.:
model #E06C75 -> #f38ba8
branch #E5C07B -> #f9e2af
path #61AFEF -> #89b4fa
(semantic bands ctx_bar* left unchanged)
Test render (do not touch the live file)
The canonical sample input is bundled as assets/sample_input.json. Write the
candidate config to a temp path, then run the resolved active renderer
(statusline_py from Step 0) with STATUSLINE_CONFIG pointed at the candidate
so the user's live file stays untouched until they confirm. A non-empty colored
line means success.
Use the statusline_py from Step 0 wherever <statusline.py> appears, and this
skill's bundled <skill>/assets/sample_input.json for the sample. Do not
hardcode any particular machine's path.
PowerShell:
$env:STATUSLINE_CONFIG="<candidate.json>"; Get-Content <skill>/assets/sample_input.json | uv run <statusline.py>
# fallback: ... | python <statusline.py>
bash:
STATUSLINE_CONFIG=<candidate.json> uv run <statusline.py> < <skill>/assets/sample_input.json
# fallback: python3 instead of uv run
Writing the result (history-aware commit)
Never blind-overwrite the live config. On explicit confirmation, install the new
config through the sibling helper's commit subcommand, which snapshots the
current config and appends a changelog entry before writing.
-
Build the full new config object in memory: the current config with ONLY the
colorsblock changed. Keep key order stable, keep all_commentkeys and every_-prefixed key, preservetemplates/weather/emoji_width/ctx_bar_emptyexactly, and keep it valid JSON. (This is the same CANDIDATE you test-rendered.) -
Write that new config to a temp file (e.g. in the OS temp dir) so large JSON never goes through argv.
-
Run the helper's
commitagainst the activeconfig_pathfrom Step 0:python <skills-dir>/statusline-config/statusline_io.py commit \ --config <config_path> --new <temp-config> \ --skill statusline-theme \ --summary "<what changed, one line>" \ --why "<the user's intent>" \ --diff "<the changed-key list, e.g. model #E06C75 -> #f38ba8 ...>"The helper validates the temp file is JSON (exits 4 touching nothing if not), snapshots the about-to-be-replaced config into
.statusline-config-history/YYYYMMDD-hhmm.jsonnext to the active config, writes the new bytes toconfig_path, and appends a human entry to.statusline-config-history/YYYYMMDD.md. For--summarykeep it to the color change (e.g. "Applied Catppuccin Mocha palette" or "Recolored branch -> green"); for--diffpass the same per-key BEFORE -> AFTER list you previewed. -
Read the JSON the helper prints (
snapshot,changelog,config_path) and tell the user what changed in one line plus the snapshot + changelog paths, and how to revert (restore the snapshot file, re-run this skill, or restore from git). The snapshot is the easiest undo.
Do NOT write the live config any other way (no direct file write) — always go
through commit so history is recorded.
Notes on specific palettes
A few palettes don't have a distinct color for every role; the closest named
color is reused (this is intentional and documented in palettes.json):
- Monokai: no separate blue — cyan
#66d9efserves bothskyandblue. - Rose Pine: gold
#f6c177servespeachandyellow; foam#9ccfd8servesskyandblue; pine#31748fis thegreenrole. - Solarized dark/light: the accent hues are identical; only
text/muteddiffer between the two variants. - Catppuccin comes in four flavors (latte/frappe/macchiato/mocha); Latte and Solarized Light are light themes — flag that if the user is on a dark terminal.
Gives 0 of the 12 instructions most design systems skills give
Counted across 528 of the 534 authors here whose files we hold, read 2026-08-06
- create a custom theme if neededin 54 of 528, across 10 files
- read the corresponding theme filein 54 of 528, across 10 files
- ask which theme to applyin 53 of 528, across 9 files
- show the theme showcasein 53 of 528, across 9 files
- maintain visual identity across all slidesin 50 of 528, across 6 files
- apply the specified colors and fontsin 47 of 528, across 3 files
- get explicit confirmationin 45 of 528, across 1 file
- Generate a design system before codingin 19 of 528, across 6 files
- Maintain at least 4.5:1 color contrast ratioin 19 of 528, across 8 files
- Describe component shapes, colors, shadows, and interaction statesin 18 of 528, across 4 files
- Check Python installation and install if missingin 17 of 528, across 4 files
- Default to html-tailwind if stack is unspecifiedin 17 of 528, across 4 files
Said here and by no other author read
- resolve the active statusline config first
- change only the colors block
- map keys to palette roles for full themes
- change only specified keys for element recoloring
- replace existing colors with nearest palette match for snapping
- show before and after color swatches
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once.