A TypeScript statusline for Claude CLI that displays project info, git status, model, and context usage with color-coded indicators.
- Ensure you have Bun installed
- Add to your Claude config (
~/.claude/settings.jsonor your project's.claude/settings.local.json):
{
"statusLine": {
"type": "command",
"command": "bunx claude-cli-statusline"
}
}You can optionally install it globally with Bun to avoid bunx downloading it:
bun add -g claude-cli-statusline- Clone or copy this repo to your home directory (e.g.,
~/claude-cli-statusline) - Add to your Claude config (
~/.claude/settings.jsonor your project's.claude/settings.local.json):
{
"statusLine": {
"type": "command",
"command": "bun ~/claude-cli-statusline/index.ts"
}
}Or with a custom config file:
{
"statusLine": {
"type": "command",
"command": "bun ~/claude-cli-statusline/index.ts --config=my-config.json"
}
}Note: Adjust the path if you installed it elsewhere.
Default ("extend" layout - single line):
π¦ project-name π relative/dir ππ β branch π§ Model β¬ 89%β¦67%β‘οΈ200K π Explore π΅ $0.05 β±οΈ 1h23m
Without sub-agent active:
π¦ project-name π relative/dir ππ β branch π§ Model β¬ 89%β¦67%β‘οΈ200K π΅ $0.05 β±οΈ 1h23m
With "render-layout": "normal" (basic info only):
π¦ project-name π relative/dir ππ β branch π§ Model β¬ 89%β¦67%β‘οΈ200K π Explore
With "render-layout": "layout-2-line" (two lines):
π¦ project-name π relative/dir
ππ β branch π§ Model β¬ 89%β¦67%β‘οΈ200K π Explore
Icons:
- π¦ Project root directory (basename only by default)
- With
show-project-full-dir: truein config: shows full path like~/path/to/project
- With
- π Current relative directory
- π Git repo (octopus icon only by default)
- π Clean working tree (π’ green) - no uncommitted changes
- π οΈ Dirty working tree (π‘ yellow) - has uncommitted changes
- π€ Staged changes (π΅ light blue) - changes ready to commit
- With
show-git-repo-name: truein config:ππ π¦when repo name matches directory nameππ repo-namewhen repo name differs from directory name
- Git repo name is extracted from remote URL (e.g.,
git@github.com:user/my-repo.gitβmy-repo)
- β Git branch (π’ green if in repo, π‘ yellow if no repo)
- β No git repository
- π§ Model name
- β¬ Context display:
89%β¦67%β‘οΈ200K- First percentage (89%): Total remaining context
- β¦ separator
- Second percentage (67%): Remaining before auto-compact (calculated as percentage of usable space after buffer)
- β‘οΈ Not compacted or π« if context was compacted (auto or manual)
- Max context window (200K, 1M, etc.) with cyan-colored K/M suffix
Context Colors:
- π’ Green: >65% remaining
- π‘ Yellow: 45-65% remaining
- π Orange: 20-45% remaining
- π΄ Red: <20% remaining
Layout:
The statusline uses a single-line layout by default. You can customize the layout using the render-layout config option or the --layout CLI flag. See the render-layout section for details.
The statusline supports an optional animated spinner with multiple style choices:
Available spinner styles:
transportation(default): π π π π π π π πweather: βοΈ π€οΈ β π₯οΈ βοΈ π¦οΈ π§οΈ βοΈhearts: β€οΈ π§‘ π π π π π€ π€fruit: π π π π π« π π πplanets: π πͺ π π π π π πcircles: π΄ π π‘ π’ π΅ π£ π€ β«sports: β½ π π βΎ πΎ π π π±flowers: πΉ πΊ π» πΌ π· πΈ π π΅οΈhands: β π€ ποΈ π π€ π€arrows: β‘οΈβοΈ β¬οΈβοΈ β¬ οΈβοΈ β¬οΈβοΈ moon: π π π π π π π πclock: π π π π π π π π π π π πcircular: β β΄ β β· β βΆ β β΅braille: β β β Ή β Έ β Ό β ΄ β ¦ β § β β dots: β β β β‘ β’ β β β blocks: β β β β
Example with animations (transportation):
π 75%β¦52%β‘οΈ200Kπ
Enable animations in config:
{
"animations": {
"enabled": true,
"spinner": "transportation"
}
}Or use CLI:
bun ~/claude-cli-statusline/index.ts --spinner=heartsNote: When animations are enabled, the spinner appears after the max context window.
Note: Animations are disabled by default to maintain a clean, static statusline.
You can pass options to customize the statusline behavior:
Specify a custom config file. If the path is relative, it searches in order:
- Project
.claude/directory - User
~/.claude/directory - Script directory
Default: statusline-config.json
Examples:
# Use absolute path
bun ~/claude-cli-statusline/index.ts --config=/path/to/my-config.json
# Use relative path (searches in .claude dirs)
bun ~/claude-cli-statusline/index.ts --config=my-config.jsonCustomize the color thresholds for context usage display. Values must be integers between 0-100 and in descending order.
Default: --context-levels=65,45,20
Example:
{
"statusLine": {
"type": "command",
"command": "bun ~/claude-cli-statusline/index.ts --context-levels=75,50,25"
}
}This sets:
- Green: >75% remaining
- Yellow: 50-75% remaining
- Orange: 25-50% remaining
- Red: <25% remaining
Save the input JSON to a file for debugging purposes.
Default filename: sample-input.json
Example:
{
"statusLine": {
"type": "command",
"command": "bun ~/claude-cli-statusline/index.ts --save-sample"
}
}Or with custom filename:
{
"statusLine": {
"type": "command",
"command": "bun ~/claude-cli-statusline/index.ts --save-sample=debug.json"
}
}Specify the statusline layout. Can be a predefined layout name or a custom layout name you've defined.
Predefined layouts:
normal- Basic info onlyextend- Adds cost & duration (default)full- Everything including lineslayout-1-line- Legacy alias fornormallayout-2-line- Two lines
Example:
{
"statusLine": {
"type": "command",
"command": "bun ~/claude-cli-statusline/index.ts --layout=extend"
}
}Note: This CLI flag overrides the render-layout setting in the config file.
Specify the animated spinner style. Choose from 16 different styles.
Available styles:
transportation, weather, hearts, fruit, planets, circles, sports, flowers, hands, arrows, moon, clock, circular, braille, dots, blocks
Example:
{
"statusLine": {
"type": "command",
"command": "bun ~/claude-cli-statusline/index.ts --spinner=hearts"
}
}Note: This CLI flag overrides the animations.spinner setting in the config file. Animations must be enabled separately with animations.enabled: true in your config.
The statusline displays information through widgets that can be arranged using layouts. Each widget shows a specific metric:
| Widget | Icon | Description |
|---|---|---|
project |
π¦ | Project directory name (workspace root) |
cwd |
π | Current working directory relative to project root |
git |
π | Git repository status (clean/dirty/staged) and branch name |
model |
π§ | AI model name (e.g., "Sonnet 4.5") |
context |
β¬ | Context usage (remaining % before full/compact, max tokens) |
subagent |
π | Currently active sub-agent (e.g., "Code-Reviewer", "Explore") |
cost |
π΅ | Total session cost in USD (cumulative across context resets) |
lines |
π | Lines added/removed during session (vanity metric, doesn't reset with context) |
duration |
β±οΈ | Total session duration in hours/minutes (cumulative across context resets) |
Note on metrics:
- Actionable:
gitstatus tells you if you need to commit changes,subagentshows which specialist is handling the task - Informational:
contextshows when compaction will occur - Vanity metrics:
cost,lines, anddurationare cumulative session stats that don't reset with/clear
The config is reloaded on every statusline update, so you can modify it while Claude CLI is running.
See statusline-config.json for the default configuration file with all available options and their default values.
When using relative paths (default or via --config), files are searched in:
- Project:
.claude/<filename>in workspace project directory - User:
~/.claude/<filename>in home directory - Script:
<filename>in statusline script directory
The number of tokens to reserve as a buffer before auto-compact. Claude CLI automatically compacts the conversation when remaining tokens reach this threshold.
Default: 45000 tokens
This setting affects the second percentage in the display (e.g., 89%β¦67%):
- First percentage: Total remaining context (89% = 178K tokens remaining out of 200K)
- Second percentage: Remaining before auto-compact (67% = percentage of usable space remaining)
- Calculation:
(usableSpace - used) / usableSpace * 100 - Where
usableSpace = maxTokens - compactBuffer - This matches Claude CLI's buffer calculation method
- Calculation:
When the second percentage reaches 0%, Claude CLI will auto-compact the conversation, which resets the context and may cause the percentages to jump back up.
An array of three descending integers [green, yellow, orange] that define the thresholds for context remaining percentage:
- First value: minimum % for green (default: 65)
- Second value: minimum % for yellow (default: 45)
- Third value: minimum % for orange (default: 20)
- Below third value: red
Note: CLI flag --context-levels overrides these config values.
A mapping of model IDs to their context window sizes in tokens. This is used to calculate the remaining context percentage from the transcript usage data.
Add entries here if you need to support additional models or if Claude releases models with different context windows.
Default: 200,000 tokens for unknown models
A mapping of model display names to their context window sizes. Used as a fallback when model ID is not found.
Example:
{
"display-name-model-context-windows": {
"Sonnet 4.5": 200000,
"Opus 4": 200000,
"Haiku 4": 200000
}
}When a context window is found via display name, it shows with a π·οΈ indicator: β¬ 60%β¦15%π«200Kπ·οΈ
The default context window size to use when neither model ID nor display name is found in the config.
Default: 200000 tokens
When using the default, it shows with a βοΈ indicator: β¬ 60%β¦15%π«200KβοΈ
You can place configuration files at different levels:
Project-level (.claude/statusline-config.json):
cd /path/to/your/project
mkdir -p .claude
cat > .claude/statusline-config.json << 'EOF'
{
"context-color-levels": [70, 50, 25],
"save-sample": {
"enable": true,
"filename": "debug-input.json"
}
}
EOFUser-level (~/.claude/statusline-config.json):
mkdir -p ~/.claude
cat > ~/.claude/statusline-config.json << 'EOF'
{
"context-color-levels": [65, 45, 20],
"model-context-windows": {
"claude-sonnet-4-5-20250929": 200000
}
}
EOFThis allows you to have different settings per project while maintaining user-wide defaults.
An object to control saving the input JSON on every statusline update. Useful for debugging or analyzing the data structure Claude CLI provides.
Properties:
enable(boolean): Enable/disable sample savingfilename(string): The filename to use when saving
Default:
{
"enable": false,
"filename": "sample-input.json"
}Note: You can change enable to true while Claude CLI is running, and the next statusline update will start saving samples. The CLI flag --save-sample[=filename] overrides these config values.
Controls whether to show the git repository name in the statusline.
Default: false (disabled)
When false (default):
- Shows only:
π β branch(octopus icon + branch)
When true:
- Shows
π π¦ β branchif repo name matches directory name - Shows
π repo-name β branchif repo name differs from directory name
Git repo name detection:
- First tries to extract from remote URL:
git remote get-url origin - For example:
git@github.com:user/my-repo.gitβmy-repo - Falls back to directory basename if no remote is configured
Example:
{
"show-git-repo-name": true
}Why disabled by default: This keeps the statusline shorter and cleaner, as the repository name is often redundant with the project directory name. Enable it if you work in directories where the folder name differs from the actual git repository name (e.g., cloned with a different name, renamed directory, or forked repos).
Controls whether to show the full project directory path or just the basename.
Default: false (disabled - shows basename only)
When false (default):
- Shows only basename:
π¦ project-name
When true:
- Shows full path with home shortening:
π¦ ~/path/to/project-name
Example:
{
"show-project-full-dir": true
}Why disabled by default: The basename is usually sufficient and keeps the statusline more concise. Enable it if you need to distinguish between multiple projects with the same name in different locations.
Customize the icons used to indicate git repository status (staged/clean/dirty).
Default:
{
"clean": "π",
"dirty": "π οΈ",
"staged": "π€"
}Status combinations:
- Clean (no changes):
ππ(octopus + gem in green) - Unstaged changes:
ππ οΈ(octopus + tools in yellow) - Staged changes:
ππ€(octopus + outbox in light blue) - Staged + unstaged:
ππ€π οΈ(staged with additional unstaged changes)
Example (using different icons):
{
"git-status-icons": {
"clean": "β",
"dirty": "β",
"staged": "β"
}
}Note: The icons are displayed directly adjacent to the octopus git icon (π) with no space between them. When there are staged changes, only the staged icon (π€) is shown. The dirty icon (π οΈ) is only shown if there are unstaged changes. The clean icon (π) is only shown when there are no changes at all (no staged, no unstaged).
Controls the layout and ordering of statusline components. You can use predefined layouts or create custom layouts.
Default: "extend" (single line with cost and duration)
Predefined Layouts:
"normal"- Basic info only:["project cwd git model context subagent"]"extend"- Adds cost & duration:["project cwd git model context subagent cost duration"](default)"full"- Everything including lines:["project cwd git model context subagent cost lines duration"]"layout-1-line"- Legacy alias fornormal"layout-2-line"- Two lines:["project cwd", "git model context subagent"]
Available widgets for custom layouts:
You can use any combination of: project, cwd, git, model, context, subagent, cost, lines, duration
See the Available Widgets section for details on what each widget displays.
Examples:
Using predefined layouts:
{
"render-layout": "normal" // Basic info only
}{
"render-layout": "extend" // Adds cost & duration (default)
}{
"render-layout": "full" // Everything including lines
}{
"render-layout": "layout-1-line" // Legacy alias for "normal"
}Custom single line:
{
"render-layout": ["project cwd git model context"]
}Custom two lines:
{
"render-layout": [
"project cwd",
"git model context"
]
}Custom order (context first):
{
"render-layout": [
"context model",
"project cwd git"
]
}Minimal (git and context only):
{
"render-layout": ["git context"]
}Problem: Claude CLI updates the user-level settings (~/.claude/settings.json) whenever you change models. This causes all other CLI sessions to immediately pick up the model change, which is often unexpected behavior.
Solution: The statusline automatically isolates model selections per project by moving them from user-level to project-level settings.
When you change models in Claude CLI:
-
User picks a specific model (e.g., Sonnet, Opus):
- Statusline detects the user settings file was recently modified (within 5 seconds)
- Moves
modelfrom~/.claude/settings.jsonto.claude/settings.local.jsonin your project - Clears it from user settings so other projects aren't affected
- Result: This model choice only affects the current project
-
User picks "Default":
- Statusline detects user settings was recently modified with no model set
- Removes
modelfrom project-local settings if it was set before user settings - Result: Project returns to using whatever default is configured
- β Model selections are project-specific
- β Multiple Claude CLI sessions can use different models without interfering
- β Other projects maintain their own model preferences
- β Completely automatic - no manual file editing needed
This feature is enabled by default via the clear-model config option:
{
"clear-model": true
}To disable (not recommended):
{
"clear-model": false
}Why enabled by default: This fixes unexpected behavior where changing models in one terminal session affects all other sessions. Most users want project-specific model selections.
Run the test suite:
bun testRun with coverage:
bun coverageThe project uses Bun as the runtime and doesn't require compilation. All TypeScript files are executed directly.
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
If the context usage shows "β" instead of a percentage, use the debug script to see what data is available:
Edit your Claude config to use the debug script:
{
"statusLine": {
"type": "command",
"command": "bun ~/claude-cli-statusline/tools/debug.ts"
}
}Start a Claude CLI session and observe the debug output. It will show:
- The complete JSON structure passed to the statusline
- Whether a
budgetfield exists - The transcript file path
If a transcript path is shown, you can manually inspect it:
cat /path/to/transcript.json | jq .Look for fields like:
usagemetadatabudgetmessages[].usage- Any fields containing "token", "context", or "budget"
If you find token usage data in a different location, update index.ts to include those field names in the appropriate arrays:
maxKeys- for maximum token limitsusedKeys- for tokens usedremainingKeys- for tokens remainingremainingPctKeys- for direct percentage values
{
"statusLine": {
"type": "command",
"command": "bun ~/claude-cli-statusline/index.ts"
}
}