SSD Nodes Learn Hosting plans →
Руководства Matt ConnorАвтор: Matt Connor · Обновлено 2026-11-09

Как настроить statusline Claude Code на VPS

Параметр statusLine запускает скрипт и выводит его stdout под приглашением. Добавьте имя хоста, каталог, ветку Git и модель, чтобы не перепутать сервер.

Что показывает statusline в Claude Code

statusline в Claude Code — это строка под приглашением командной строки, в которой отображается вывод написанного вами скрипта. Добавьте блок statusLine в settings.json и укажите в нём команду. Claude Code запускает эту команду, передаёт ей состояние сеанса в формате JSON через стандартный ввод и выводит всё, что команда записывает в стандартный вывод.

Это весь контракт. Скрипт читает JSON из стандартного ввода и выводит текст в стандартный вывод. Скрипт выполняется на вашей машине, и его вывод не передаётся модели, поэтому токены не расходуются.

На ноутбуке с одним проектом это просто оформление. На трёх серверах это защитный механизм. Каждый сеанс Claude Code выглядит одинаково в каждом терминале, поэтому четыре окна SSH без подписей могут привести к выполнению миграции не на том сервере. Если statusline начинается с имени хоста, такой риск исчезает.

Где находится параметр statusLine в settings.json

Добавьте его в пользовательские настройки в ~/.claude/settings.json. Они применяются ко всем проектам на этом компьютере. Также можно использовать настройки проекта в .claude/settings.json внутри репозитория. Для этого каталога они имеют приоритет.

{
  "statusLine": {
    "type": "command",
    "command": "~/.claude/statusline.sh"
  }
}

type всегда имеет значение "command". Значение command выполняется через shell, поэтому там можно указать путь к скрипту или обычную команду. Прежде чем писать скрипт, проверьте, что настройка работает:

{
  "statusLine": {
    "type": "command",
    "command": "hostname -s"
  }
}

Запустите Claude Code и отправьте одно сообщение. В строке под приглашением теперь отображается короткое имя хоста сервера. Если строка остаётся пустой, проблема связана с настройкой или диалогом доверия, а не со скриптом. См. раздел «Почему statusline остаётся пустой» ниже.

По состоянию на August 2026 доступны три необязательных ключа. padding добавляет горизонтальный отступ в символах. Значение по умолчанию — 0. refreshInterval повторно запускает команду каждые N секунд в дополнение к обычным триггерам. Минимальное значение — 1. Это нужно только в том случае, если строка отображает часы или другое значение, которое изменяется во время простоя сеанса. hideVimModeIndicator отключает встроенный текст -- INSERT --, если ваш скрипт уже отображает режим vim.

Какие данные получает скрипт statusline?

Не доверяйте списку полей из любого источника, включая эту страницу. Получите реальный объект, который передаёт ваша версия. Напишите временный скрипт, сохраняющий stdin в файл:

cat > ~/.claude/statusline-capture.sh <<'EOF'
#!/bin/bash
cat > /tmp/statusline-input.json
echo "captured"
EOF
chmod +x ~/.claude/statusline-capture.sh

Укажите этот файл в statusLine.command, запустите сессию и отправьте одно сообщение. Панель считывает captured. Теперь проверьте полученные данные:

jq . /tmp/statusline-input.json

Так вы получите точную структуру для своей сборки и сможете повторить проверку после любого обновления, которое изменит схему.

Стабильные части, описанные в августе 2026 года, представлены вложенными объектами, а не плоскими ключами. model содержит id и display_name. workspace содержит current_dir и project_dir: current_dir указывает текущий каталог сессии, project_dir — каталог, из которого она была запущена. Эти значения различаются после изменения рабочего каталога во время сессии. Поле верхнего уровня cwd содержит то же значение, что и workspace.current_dir. context_window содержит количество токенов и предварительно рассчитанное значение used_percentage. cost содержит total_cost_usd и счётчики длительности. session_id не меняется в течение сессии и уникально для каждой сессии, что важно для последующего кэширования.

Три правила помогают сохранить работоспособность скрипта при изменениях схемы.

Некоторые ключи отсутствуют, а не имеют значение null. vim, agent, pr, worktree и effort появляются только при включённой соответствующей функции. Если режим vim отключён, чтение .vim.mode с помощью jq -r выводит буквальную строку null, и панель показывает читателю null. Добавляйте // empty к каждому селектору, чтобы при отсутствии ключа ничего не выводилось.

Некоторые значения в начале равны null. context_window.used_percentage и context_window.current_usage имеют значение null до первого ответа API, а current_usage снова получает значение null после /compact, пока следующий вызов не заполнит его. Поэтому для отображения процента использования контекста на панели требуется // 0. Иначе в первые секунды каждой сессии будет отображаться null. Перед добавлением этого числа на панель полезно понять, как фактически заполняется контекстное окно.

Ветка git не входит в JSON. Ни одно поле её не передаёт. Любая ветка на панели появляется потому, что скрипт самостоятельно выполняет git.

Скрипт statusline, который корректно работает при ошибках

Это версия для копирования и вставки. Она выводит имя хоста, текущий рабочий каталог, ветку git и имя модели. Для каждого поля предусмотрено резервное значение, поэтому даже пустой JSON-объект формирует пригодную для использования строку.

#!/bin/bash
# ~/.claude/statusline.sh
input=$(cat)

# Read one field. Prints nothing when the key is missing or null.
field() { printf '%s' "$input" | jq -r "$1 // empty" 2>/dev/null; }

HOST=$(hostname -s 2>/dev/null)
[ -z "$HOST" ] && HOST="host"

DIR=$(field '.workspace.current_dir')
[ -z "$DIR" ] && DIR=$(field '.cwd')
[ -z "$DIR" ] && DIR="$PWD"

MODEL=$(field '.model.display_name')
[ -z "$MODEL" ] && MODEL="claude"

SHORT="$DIR"
if [ -n "$HOME" ]; then
  case "$DIR" in
    "$HOME") SHORT="~" ;;
    "$HOME"/*) SHORT="~/${DIR#"$HOME"/}" ;;
  esac
fi

BRANCH=""
if git -C "$DIR" rev-parse --git-dir >/dev/null 2>&1; then
  BRANCH=$(git -C "$DIR" branch --show-current 2>/dev/null)
  [ -z "$BRANCH" ] && BRANCH="detached"
fi

CYAN=$'\033[36m'
YELLOW=$'\033[33m'
DIM=$'\033[2m'
RESET=$'\033[0m'

LINE="${CYAN}${HOST}${RESET} ${SHORT}"
[ -n "$BRANCH" ] && LINE="${LINE} ${YELLOW}${BRANCH}${RESET}"
LINE="${LINE} ${DIM}${MODEL}${RESET}"

printf '%s\n' "$LINE"

Каждое чтение выполняется через field. Эта команда добавляет // empty, поэтому при переименовании или удалении ключа возвращается пустая строка, а следующая команда подставляет значение по умолчанию. Для каталога предусмотрена последовательная подстановка: workspace.current_dir, затем cwd и $PWD. Ветка определяется через git -C "$DIR", а не через простой git. Поэтому ветка всегда соответствует каталогу, который отображается в statusline.

Сохраните файл и сделайте его исполняемым:

chmod +x ~/.claude/statusline.sh

Бит исполнения обязателен. Claude Code запускает команду через shell, поэтому скрипт без +x завершается с ошибкой Permission denied, не выводит данные в stdout, и строка остаётся пустой без видимой ошибки.

jq разбирает JSON в командной строке и не установлен на чистом сервере Ubuntu:

sudo apt update && sudo apt install -y jq

Затем укажите этот скрипт в настройке, используя первый блок settings.json выше.

Проверьте скрипт до того, как начнёте ему доверять

Запустите его вручную дважды. Сначала с обычным объектом сеанса:

echo '{"model":{"display_name":"Opus"},"workspace":{"current_dir":"/srv/api"},"session_id":"t1"}' | ~/.claude/statusline.sh

Сначала выводится имя хоста, затем /srv/api, а потом Opus. Ветка не выполняется, потому что /srv/api на вашем компьютере, скорее всего, не является репозиторием git.

Затем выполните тест деградации. Именно его часто пропускают:

echo '{}' | ~/.claude/statusline.sh

Пустой объект — худший случай, который может возникнуть после изменения схемы. Строка всё равно выводит имя хоста, текущий каталог из $PWD и слово claude вместо имени модели. Сбой не происходит, и null не выводится. Скрипт, который проходит этот тест, продолжает работать после переименования поля, потому что для скрипта переименованное и отсутствующее поле — одно и то же событие.

Что вы должны увидеть

Статусная строка отображается в отдельной строке над встроенными индикаторами в нижней части экрана и не заменяет их. В рабочей конфигурации она состоит из одной строки: короткое имя хоста голубого цвета, затем рабочий каталог, в котором домашний каталог сокращён до ~, затем имя ветки жёлтого цвета, если каталог является Git-репозиторием, и затем приглушённое имя модели. Примерно так: web-01 ~/api main Opus, при этом все четыре элемента выделены цветом.

Строка повторно запускает ваш скрипт при начале сеанса, в том числе при возобновлении сеанса, при появлении нового сообщения ассистента, после завершения /compact, при изменении режима разрешений, при переключении Vim-режима и при каждом тике refreshInterval, если вы его настроили. Обновления объединяются с задержкой 300 ms, поэтому при серии изменений скрипт запускается один раз. Во время автодополнения, открытия меню справки и отображения запросов разрешений строка скрывается, а затем снова появляется.

Почему имя хоста должно отображаться первым

Если агенты работают более чем на одном сервере, терминал остаётся единственным источником информации о вашем местоположении, но терминалы могут вводить в заблуждение. Откройте второе соединение ssh из панели tmux. Заголовок окна часто сохраняет старое имя, потому что его устанавливает shell, который не узнал о переходе в новое окружение. Оставьте Claude Code работающим в отдельной сессии tmux на VPS и подключитесь к ней через день. На экране ничто не отличит build-сервер от production-сервера.

Статусная строка устроена иначе. Claude Code формирует её самостоятельно для каждой сессии на основе данных этой сессии. Она не может унаследоваться от неправильной панели или остаться устаревшей из-за приглашения shell, которое не обновилось. В ней отображается сервер, на котором агент записывает файлы.

Назначьте каждому серверу свой цвет, чтобы распознавать его ещё до чтения имени. Добавьте две строки перед присваиванием LINE=:

CODE=$(printf '%s' "$HOST" | cksum | cut -d' ' -f1)
HOST_COLOR=$(printf '\033[%dm' "$((31 + CODE % 6))")

Затем используйте ${HOST_COLOR} вместо ${CYAN}. Команда cksum вычисляет контрольную сумму имени хоста. Поэтому одно и то же имя всегда получает один и тот же цвет в диапазоне от 31 до 36: от красного до cyan. Скопируйте этот скрипт на каждый сервер, и каждый сервер будет обозначать себя сам.

Каталог отображается по той же причине. /srv/api и /srv/api-staging находятся на расстоянии одного нажатия клавиши в команде ssh, но последствия ошибки между ними могут отличаться на весь инцидент. Модель и ветка — ещё два значения, которым стоит выделить место. Модель показывает, какую сессию вы возобновили, а ветка — собирается ли агент выполнить commit в main.

На небольшом экране всё это ещё важнее, поскольку заголовок окна недоступен как дополнительный ориентир. Если вы работаете в таком режиме, см. управление Claude Code с телефона.

Ускорьте выполнение скрипта

Скрипт запускается при каждом сообщении ассистента, а Claude Code отменяет выполняющийся процесс, когда появляется новое обновление. Поэтому медленный скрипт выводит устаревший текст или не выводит ничего.

Каждый вызов jq занимает несколько миллисекунд. Медленной является операция git: git status в большом репозитории при холодном кэше занимает сотни миллисекунд. Приведённый выше скрипт намеренно не использует git status и вызывает git branch --show-current, которая читает .git/HEAD и сразу возвращает результат.

Если вы добавляете более ресурсоёмкую операцию, сохраните результат в файле и обновляйте его каждые несколько секунд. Свяжите файл с сессией:

CACHE="/tmp/statusline-$(field '.session_id')"

Используйте session_id, а не $$. $$ — это идентификатор процесса вашего скрипта. Он меняется при каждом запуске, поэтому кэш с таким ключом никогда не используется повторно, и при каждом запуске приходится выполнять операцию полностью. session_id сохраняется в течение всей сессии и отличается в разных сессиях. Поэтому две сессии Claude Code в разных репозиториях не смогут прочитать закэшированное имя ветки друг друга. Сессии намеренно изолированы таким образом. Поэтому передача работы из одной сессии в другую требует отдельного действия. Для этого предназначена операция отправка сообщения из одной сессии Claude Code в другую.

Есть ещё одно ограничение: tput cols не работает внутри скрипта statusline. Claude Code перехватывает вывод вместо подключения скрипта к терминалу, поэтому скрипту нечего измерять для определения ширины. В версиях v2.1.153 и более поздних Claude Code устанавливает переменные окружения COLUMNS и LINES перед запуском команды. Поэтому при необходимости определить объём выводимых данных читайте $COLUMNS.

Почему statusline остаётся пустой

На экране вообще ничего нет. Проверьте бит выполнения с помощью ls -l ~/.claude/statusline.sh, затем вручную запустите скрипт с указанными выше тестовыми входными данными. Если в shell он выводит строку, но в Claude Code она не появляется, начните с claude --debug. Эта команда записывает код завершения и stderr первого запуска statusline в текущем сеансе.

В журнале отладки указано Status line command skipped: workspace trust not accepted. statusline выполняет shell-команду, поэтому на неё распространяется та же проверка доверия к рабочему каталогу, что и на hooks. Пока вы не подтвердите доверие к этому каталогу в диалоговом окне, команда не запускается. Это часто происходит на VPS, где каждый новый clone выполняется в каталоге, который Claude Code ещё не видел. Перезапустите Claude Code в этом каталоге и подтвердите доверие.

Всё пусто, а disableAllHooks задан. "disableAllHooks": true в settings.json также отключает statusline, поскольку это тот же шлюз выполнения shell-команд. Удалите этот параметр или задайте ему значение false.

Строка выводит null. Селектор jq обратился к отсутствующему ключу или ключу со значением null, а jq -r выводит null как четыре символа null. Добавьте // empty для текста и // 0 для чисел.

Строка становится пустой сразу после изменения скрипта. Команда с ненулевым кодом завершения или команда без вывода очищает строку. Обычно причина — последняя строка вида [ -n "$BRANCH" ] && LINE="...". Если ветвь не выполняется, она завершается с кодом 1, и весь скрипт получает этот код завершения. Оставьте printf последней строкой или добавьте exit 0.

Коды escape отображаются как обычный текст, например \e]8;; на панели. Используйте printf '%b' вместо echo -e. Для кликабельных ссылок OSC 8 также требуется терминал с их поддержкой. Кроме того, tmux или SSH могут удалять эти последовательности, поэтому на удалённом сервере безопаснее использовать обычный цвет.

Правая часть строки обрезается. Системные уведомления и счётчик токенов в verbose mode используют эту строку справа, поэтому в узком терминале они перекрывают друг друга. Сократите вывод. Чтобы получить точный учёт использования, а не число на панели, см. как Claude Code подсчитывает токены.

FAQ

Где находится настройка statusline в Claude Code?

Она находится в settings.json в виде блока statusLine, где для type задано значение "command", а для command указан путь к скрипту или shell-команда. Пользовательские настройки находятся в ~/.claude/settings.json и применяются ко всем проектам на этой машине. Настройки проекта находятся в .claude/settings.json внутри репозитория и имеют приоритет для этого каталога. Настройки перезагружаются автоматически, но изменение становится видимым только при следующем триггере обновления, например после следующего сообщения.

Почему statusline в Claude Code пустая?

Почти все случаи объясняются четырьмя причинами. У скрипта отсутствует право на выполнение, поэтому shell возвращает Permission denied, и в stdout ничего не поступает. Диалог подтверждения доверия к workspace не был принят, поэтому claude --debug записывает в журнал Status line command skipped: workspace trust not accepted. Значение disableAllHooks равно true, что отключает statusline при том же условии. Либо скрипт завершается с ненулевым кодом, из-за чего строка остаётся пустой. Сначала проверьте скрипт вручную: echo '{}' | ~/.claude/statusline.sh должен что-либо вывести.

Содержит ли JSON statusline ветку git?

Нет. JSON содержит состояние сессии: модель, каталоги workspace, значения окна контекста и стоимость. Данные о git в нём отсутствуют. Ветка в statusline появляется благодаря вызову git branch --show-current из вашего скрипта. Передайте каталог из JSON с помощью git -C "$DIR", чтобы ветка всегда соответствовала каталогу, который отображается в statusline.

Расходует ли statusline токены или замедляет сессию?

Токены не расходуются, поскольку скрипт выполняется локально, а его вывод не отправляется модели. За скорость отвечает ваш скрипт. Команда запускается после каждого сообщения ассистента с задержкой 300 ms, а Claude Code отменяет выполняемый процесс при поступлении нового обновления. Поэтому скрипт, выполнение которого занимает целую секунду, показывает устаревший текст. Не используйте git status в больших репозиториях. Медленные результаты кэшируйте в файле с ключом session_id.

Как показывать разную statusline на каждом сервере?

Используйте один скрипт и позвольте ему определить машину. Приведённый выше скрипт выводит $HOSTNAME, используя hostname -s как резервное значение. Поэтому один и тот же файл, скопированный на каждый сервер, правильно подписывает каждый из них, а приём с цветом на основе контрольной суммы назначает каждому hostname собственный цвет. Если для одного сервера нужен другой вид statusline, добавьте блок statusLine в настройки проекта соответствующего репозитория на этом сервере. Настройки проекта имеют приоритет над пользовательскими настройками для этого каталога.

Была ли эта статья полезной?