Restructure the status line stdin JSON for clarity and accuracy: - Rename model.id → model.display_name, cwd → workspace.current_dir - Replace raw context_window size/count with used_percentage, remaining_percentage, current_usage, context_window_size, and total_input_tokens/total_output_tokens - Add version field from cfg.getCliVersion() - Add git.branch, metrics.models, metrics.files - Remove upstream-only fields: tokens.tool (never populated), session (start_time/elapsed_time not live-updating), streaming_state, approval_mode, terminal, metrics.tools - Rename tokens.candidates → tokens.completion (Qwen API convention) - Fix template string escaping in builtin-agents to avoid templateString() placeholder collision Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
12 KiB
Status Line
Display custom information beneath the footer using a shell command.
The status line lets you run a shell command whose output is displayed as a persistent line below the footer bar. The command receives structured JSON context via stdin, so it can show session-aware information like the current model, token usage, git branch, or anything else you can script.
┌─────────────────────────────────────────────────────────────────┐
│ ? for shortcuts 🔒 docker | Debug | ◼◼◼◻ 67% │
├─────────────────────────────────────────────────────────────────┤
│ user@host ~/project (main) qwen-3-235b ctx:34% │ ← status line
└─────────────────────────────────────────────────────────────────┘
Prerequisites
jqis recommended for parsing the JSON input (install viabrew install jq,apt install jq, etc.)- Simple commands that don't need JSON data (e.g.
git branch --show-current) work withoutjq
Quick setup
The easiest way to configure a status line is the /statusline command. It launches a setup agent that reads your shell PS1 configuration and generates a matching status line:
/statusline
You can also give it specific instructions:
/statusline show model name and context usage percentage
Manual configuration
Add a statusLine object under the ui key in ~/.qwen/settings.json:
{
"ui": {
"statusLine": {
"type": "command",
"command": "input=$(cat); model=$(echo \"$input\" | jq -r '.model.display_name'); pct=$(echo \"$input\" | jq -r '.context_window.used_percentage'); echo \"$model ctx:${pct}%\"",
"padding": 0
}
}
}
| Field | Type | Required | Description |
|---|---|---|---|
type |
"command" |
Yes | Must be "command" |
command |
string | Yes | Shell command to execute. Receives JSON via stdin, first line of stdout is displayed. |
padding |
number | No | Horizontal padding (default: 0) |
JSON input
The command receives a JSON object via stdin with the following fields:
{
"session_id": "abc-123",
"version": "0.14.1",
"model": {
"display_name": "qwen-3-235b"
},
"context_window": {
"context_window_size": 131072,
"used_percentage": 34.3,
"remaining_percentage": 65.7,
"current_usage": 45000,
"total_input_tokens": 30000,
"total_output_tokens": 5000
},
"workspace": {
"current_dir": "/home/user/project"
},
"git": {
"branch": "main"
},
"metrics": {
"models": {
"qwen-3-235b": {
"api": {
"total_requests": 10,
"total_errors": 0,
"total_latency_ms": 5000
},
"tokens": {
"prompt": 30000,
"completion": 5000,
"total": 35000,
"cached": 10000,
"thoughts": 2000
}
}
},
"files": {
"total_lines_added": 120,
"total_lines_removed": 30
}
},
"vim": {
"mode": "INSERT"
}
}
| Field | Type | Description |
|---|---|---|
session_id |
string | Unique session identifier |
version |
string | Qwen Code version |
model.display_name |
string | Current model name |
context_window.context_window_size |
number | Total context window size in tokens |
context_window.used_percentage |
number | Context window usage as percentage (0–100) |
context_window.remaining_percentage |
number | Context window remaining as percentage (0–100) |
context_window.current_usage |
number | Token count from the last API call (current context size) |
context_window.total_input_tokens |
number | Total input tokens consumed this session |
context_window.total_output_tokens |
number | Total output tokens consumed this session |
workspace.current_dir |
string | Current working directory |
git |
object | absent | Present only inside a git repository. |
git.branch |
string | Current branch name |
metrics.models.<id>.api |
object | Per-model API stats: total_requests, total_errors, total_latency_ms |
metrics.models.<id>.tokens |
object | Per-model token usage: prompt, completion, total, cached, thoughts |
metrics.files |
object | File change stats: total_lines_added, total_lines_removed |
vim |
object | absent | Present only when vim mode is enabled. Contains mode ("INSERT" or "NORMAL"). |
Important: stdin can only be read once. Always store it in a variable first:
input=$(cat).
Examples
Model and token usage
{
"ui": {
"statusLine": {
"type": "command",
"command": "input=$(cat); model=$(echo \"$input\" | jq -r '.model.display_name'); pct=$(echo \"$input\" | jq -r '.context_window.used_percentage'); echo \"$model ctx:${pct}%\""
}
}
}
Output: qwen-3-235b ctx:34%
Git branch + directory
{
"ui": {
"statusLine": {
"type": "command",
"command": "input=$(cat); branch=$(echo \"$input\" | jq -r '.git.branch // empty'); dir=$(basename \"$(echo \"$input\" | jq -r '.workspace.current_dir')\"); echo \"$dir${branch:+ ($branch)}\""
}
}
}
Output: my-project (main)
Note: The
git.branchfield is provided directly in the JSON input — no need to shell out togit.
File change stats
{
"ui": {
"statusLine": {
"type": "command",
"command": "input=$(cat); added=$(echo \"$input\" | jq -r '.metrics.files.total_lines_added'); removed=$(echo \"$input\" | jq -r '.metrics.files.total_lines_removed'); echo \"+$added/-$removed lines\""
}
}
}
Output: +120/-30 lines
Script file for complex commands
For longer commands, save a script file at ~/.qwen/statusline-command.sh:
#!/bin/bash
input=$(cat)
model=$(echo "$input" | jq -r '.model.display_name')
pct=$(echo "$input" | jq -r '.context_window.used_percentage')
branch=$(echo "$input" | jq -r '.git.branch // empty')
added=$(echo "$input" | jq -r '.metrics.files.total_lines_added')
removed=$(echo "$input" | jq -r '.metrics.files.total_lines_removed')
parts=()
[ -n "$model" ] && parts+=("$model")
[ -n "$branch" ] && parts+=("($branch)")
[ "$pct" != "0" ] 2>/dev/null && parts+=("ctx:${pct}%")
([ "$added" -gt 0 ] || [ "$removed" -gt 0 ]) 2>/dev/null && parts+=("+${added}/-${removed}")
echo "${parts[*]}"
Then reference it in settings:
{
"ui": {
"statusLine": {
"type": "command",
"command": "bash ~/.qwen/statusline-command.sh"
}
}
}
Behavior
- Update triggers: The status line updates when the model changes, a new message is sent (token count changes), vim mode is toggled, git branch changes, tool calls complete, or file changes occur. Updates are debounced (300ms).
- Timeout: Commands that take longer than 5 seconds are killed. The status line clears on failure.
- Output: Only the first line of stdout is used. The text is rendered with dimmed colors and truncated to terminal width.
- Hot reload: Changes to
ui.statusLinein settings take effect immediately — no restart required. - Shell: Commands run via
/bin/shon macOS/Linux. On Windows,cmd.exeis used by default — wrap POSIX commands withbash -c "..."or point to a bash script (e.g.bash ~/.qwen/statusline-command.sh). - Removal: Delete the
ui.statusLinekey from settings to disable. The status line disappears and the "? for shortcuts" hint returns.
Troubleshooting
| Problem | Cause | Fix |
|---|---|---|
| Status line not showing | Config at wrong path | Must be under ui.statusLine, not root-level statusLine |
| Empty output | Command fails silently | Test manually: echo '{"session_id":"test","version":"0.14.1","model":{"display_name":"test"},"context_window":{"context_window_size":0,"used_percentage":0,"remaining_percentage":100,"current_usage":0,"total_input_tokens":0,"total_output_tokens":0},"workspace":{"current_dir":"/tmp"},"metrics":{"models":{},"files":{"total_lines_added":0,"total_lines_removed":0}}}' | sh -c 'your_command' |
| Stale data | No trigger fired | Send a message or switch models to trigger an update |
| Command too slow | Complex script | Optimize the script or move heavy work to a background cache |