Status line
The footer under the prompt box can carry one line of your own. You point Syntic Code at a script, it hands the script a JSON snapshot of the session, and whatever the script prints shows up in the footer. Use it for the git branch, the active model, how full the context is, how much of your plan window is left, a clock, or anything else a shell command can work out.
Two ways to set it up
Let the agent write it
/statuslineWith no instructions, /statusline reads your shell start-up files (~/.zshrc, ~/.bashrc, ~/.bash_profile, ~/.profile, in that order), finds your prompt, and turns it into a status line command. You can also describe what you want:
/statusline show the branch, the model and how much context is usedA small built-in helper agent does the work. It may only read files and edit your settings, and it saves the result to ~/.syntic/settings.json, merging with what is already there. /statusline only works in an interactive session.
Write it yourself
Add a statusLine object to a settings file:
{
"statusLine": {
"command": "~/.syntic/statusline.sh",
"refreshInterval": 30
}
}| Field | Meaning |
|---|---|
command | The shell command to run. It is run through bash -c (cmd on Windows), so pipes and arguments work. Blank means no status line. |
refreshInterval | Optional. Also re-run the command every this many seconds even when nothing in the session changed. Useful for clocks or CI badges. |
A "type": "command" field, which /statusline writes, is accepted and has no further effect.
Changes to the file are picked up while you work, so you can edit the script and the setting and watch the footer update.
Build one step by step
Write a script that reads standard input
#!/usr/bin/env bash
# ~/.syntic/statusline.sh
input=$(cat)
model=$(printf '%s' "$input" | jq -r '.model')
echo "$model"Make it executable
chmod +x ~/.syntic/statusline.shTry it by hand
Feed it a sample snapshot to check the output before Syntic Code runs it:
echo '{"model":"Syntic Code","cwd":"/tmp","total_cost_usd":0.12,"context_used_pct":0.4}' \
| ~/.syntic/statusline.shPoint the setting at it
{ "statusLine": { "command": "~/.syntic/statusline.sh" } }How it runs
| Rule | Detail |
|---|---|
| Where it shows | In the footer, after the hint text, separated by a dot. |
| What is kept | The first line of standard output only. Tabs become spaces and other control characters are removed. |
| Colors | Plain SGR color codes (\e[32m, \e[1;34m, 256-color and 24-bit forms) are kept and drawn. Other escape sequences, including OSC hyperlinks and cursor movement, are dropped. |
| Output size | Only the first 16 KB of output is read. |
| Time limit | One second per run. A slower run is stopped and nothing is shown for it. |
| Exit status | A non-zero exit shows nothing. So does a line that is empty once colors are removed. |
| How often | At most every 300 ms, and only when the snapshot changed. While nothing changes it re-runs every 5 seconds, or every refreshInterval seconds if you set one. Only one run is active at a time. |
| Working folder | The session’s current folder. |
| Terminal size | COLUMNS and LINES are set, so you can shorten the line on narrow windows. |
| Environment | The command is started from a cleaned PATH, and your Syntic credentials are removed from its environment. |
| Folder trust | It does not run until you have trusted the folder (see Folder trust). |
To remove the status line, delete the statusLine key or set command to an empty string.
The JSON your command receives
One JSON object arrives on standard input each run. Fields with no value yet are left out.
| Field | Type | Value |
|---|---|---|
model | string | The model the session is using. |
cwd | string | The working folder. |
workspace_dirs | list of strings | Extra folders added with /add-dir or --add-dir. Left out when there are none. |
session_id | string | The session’s id. |
session_name | string | The session’s title, once it has one. |
version | string | The syntic version. |
permission_mode | string | default, acceptEdits, auto, plan, bypass or dontAsk. |
effort | string | Reasoning effort: low, medium, high, xhigh or max. |
fast_mode | boolean | Fast mode is on. |
thinking_shown | boolean | Reasoning is shown in full. |
vim_mode | boolean | Vim keys are on in the prompt. |
total_cost_usd | number | Estimated cost of the session so far, at list price. |
context_used_pct | number | Share of the context window in use, from 0 to 1. |
context_window | object | used_tokens, window_tokens, and used_percentage (0 to 100, one decimal). Present once the window size is known. |
rate_limits | object | Plan usage, described below. |
Plan usage fields
rate_limits always has five_hour and seven_day, each a fraction from 0 to 1 (0 until usage is known). Once Syntic Code has fetched your plan’s usage, it also carries:
| Field | Value |
|---|---|
windows | One entry per window your plan has (session, weekly, monthly), each with used_percentage (0 to 100) and resets_at (ISO 8601 time, when known). |
unlimited | No limits apply to your organization. |
credits_enabled | Usage credits take over when a window runs out. |
five_hour follows the session window and seven_day follows the weekly window.
Plan usage is fetched in the background every five minutes, and only while a status line is set, you are signed in, and your privacy level allows optional traffic. Headless runs never fetch it.
A full example:
{
"model": "Syntic Code",
"cwd": "/home/dev/shop",
"session_id": "5f1c…",
"session_name": "Fix checkout rounding",
"version": "0.4.2",
"permission_mode": "acceptEdits",
"effort": "medium",
"fast_mode": false,
"thinking_shown": false,
"vim_mode": false,
"total_cost_usd": 0.84,
"context_used_pct": 0.31,
"context_window": { "used_tokens": 81000, "window_tokens": 262144, "used_percentage": 30.9 },
"rate_limits": {
"five_hour": 0.42,
"seven_day": 0.18,
"windows": {
"session": { "used_percentage": 42.0, "resets_at": "2026-10-13T17:00:00Z" },
"weekly": { "used_percentage": 18.0, "resets_at": "2026-10-19T00:00:00Z" }
},
"unlimited": false,
"credits_enabled": false
}
}Examples
Context use with a color warning
#!/usr/bin/env bash
input=$(cat)
pct=$(printf '%s' "$input" | jq -r '.context_window.used_percentage // 0')
model=$(printf '%s' "$input" | jq -r '.model')
if [ "${pct%.*}" -ge 80 ]; then color='\033[31m'; else color='\033[32m'; fi
printf "%s · ${color}%s%% context\033[0m\n" "$model" "$pct"Branch and changed files
#!/usr/bin/env bash
input=$(cat)
dir=$(printf '%s' "$input" | jq -r '.cwd')
cd "$dir" 2>/dev/null || exit 0
branch=$(git branch --show-current 2>/dev/null) || exit 0
dirty=$(git status --porcelain 2>/dev/null | wc -l | tr -d ' ')
echo "⎇ ${branch:-detached} · ${dirty} changed"Git can be slow in very large repositories. Remember the one-second limit; if your command is often cut off, cache the result in a file and refresh it less often.
Plan usage in Python
#!/usr/bin/env python3
import json, sys
data = json.load(sys.stdin)
limits = data.get("rate_limits", {})
session = limits.get("windows", {}).get("session")
cost = data.get("total_cost_usd", 0)
if limits.get("unlimited"):
usage = "no limit"
elif session:
usage = f"{session['used_percentage']:.0f}% of session window"
else:
usage = "usage pending"
print(f"{data.get('model', '?')} · ${cost:.2f} · {usage}")Shorter on narrow windows
#!/usr/bin/env bash
input=$(cat)
model=$(printf '%s' "$input" | jq -r '.model')
cwd=$(printf '%s' "$input" | jq -r '.cwd')
if [ "${COLUMNS:-80}" -lt 100 ]; then echo "$model"; else echo "$model · $cwd"; fiA clock
{ "statusLine": { "command": "date +%H:%M", "refreshInterval": 30 } }Subagent rows
While subagents run, each one has a row of its own. subagentStatusLine lets a script replace the task text on each row:
{ "subagentStatusLine": { "command": "~/.syntic/agent-line.sh" } }The command runs once per running subagent, with the same timing rules as the main status line, and only after the folder is trusted. Its first line of output replaces that row’s task text. It is read from your own user settings file.
Each run receives:
| Field | Value |
|---|---|
agent_id | The subagent’s id. |
agent_type | Its agent type, for example Explore. |
task | The task it was given. |
activity | What it is doing right now (a tool name), when known. |
elapsed_secs | Seconds since it started. |
tokens | Tokens used so far, when known. |
effort | The session’s reasoning effort. |
#!/usr/bin/env bash
input=$(cat)
printf '%s' "$input" | jq -r '"\(.agent_type): \(.activity // "thinking") · \(.elapsed_secs)s"'More about subagents is on Subagents.
When it goes wrong
| Symptom | What to check |
|---|---|
| Nothing appears | Run the command by hand with sample JSON on standard input. Make sure it exits with status 0 and prints a non-empty first line. Check that the folder is trusted. |
| It appears, then vanishes | The script is sometimes slower than one second, or sometimes exits non-zero. Cache slow parts. |
Fields come out as null | Some fields are only sent once known (session_name, context_window, plan usage). Use defaults such as jq -r '.field // "…"'. |
The model shows as [object] or blank | model is a plain string. Read it with .model, not .model.name. |
| Plan usage stays at 0 | You are not signed in, your privacy level blocks optional traffic, or the first fetch has not finished yet. |
| A link or cursor code does not work | Only color codes are kept; other escape sequences are removed on purpose. |
| A command found in your shell is “not found” | The command runs from a cleaned PATH. Use full paths to tools in unusual places. |
Colors and the rest of the footer follow your theme; see Themes. Other footer options (pull request badge, branch links) are on that page too.