Titles and notifications
The sshc terminal understands the standard escape sequences that programs already send. No dedicated plugin or hook is required. The same mechanism that renames a tab in Terminal.app or iTerm2, and that lets Claude Code and Codex raise notifications, works in sshc's browser terminal.
| Purpose | Sequences | Typical senders |
|---|---|---|
| Rename the pane | OSC 0, OSC 1, OSC 2 | zsh/bash prompt setup, vim, tmux, Claude Code, Codex |
| Raise a notification | OSC 9 (iTerm2 style), OSC 99 (kitty style), OSC 777 (rxvt/tmux style) | Claude Code, Codex, notify commands such as cmux notify |
| Show progress | OSC 9;4 (ConEmu style) | cargo, winget, and other commands that report progress to Windows Terminal or Ghostty |
| Say what a program is doing | OSC 7501 (Program Status Protocol) | Claude Code, other programs that support it, or a shell function |
Pane titles
When a program sets a title with a sequence such as ESC ] 0 ; name BEL, the pane header, the session list, and command search all show that name. Titles sent by a remote shell over SSH are recorded by the engine and applied the same way.
- While you have pinned a pane name, program titles never overwrite it. Choose Use automatic name to show the program title or the connection alias again.
- When a program clears its title, the pane falls back to the connection alias or shell name.
- A reconnect or restart starts a new shell, so the previous title is dropped until the new shell sends one.
- Control characters are removed and titles are limited to 64 characters.
To try it, run this inside a pane:
printf '\e]0;hello\a'The running command
When a command runs for a second or longer in a local shell, sshc puts its name in front of the pane title. While sleep 31 runs, the pane is called sleep · aida@r100: ~, and it goes back when the command ends. No shell setup is needed: the sshc engine asks the operating system for the name of the process the shell runs in the terminal.
| Case | Pane title |
|---|---|
| The shell sends a title (as bash does by default on Debian and Ubuntu) | sleep · aida@r100: ~ |
| The shell sends no title | sleep |
| The running program sent a title itself (Claude Code, vim) | That program's title |
| You pinned the pane name | The pinned name |
- A command that ends within a second (such as
ls) is never named, so the pane title does not flicker. - Only local shells of an sshc engine running on Linux or macOS can be named. Engines on other systems, such as Windows, do not add the command name.
- Names are limited to 15 characters; longer ones are cut.
- Turn off Show the running command in the pane title under the Behaviour tab of Settings → Terminal to leave the name out.
In an SSH session sshc cannot name the command, because SSH does not tell what runs on the remote machine. Set up the remote shell to send a title before each command, and the pane title takes the same form.
For zsh, add this to ~/.zshrc on the remote machine:
preexec() { local words=(${(z)1}); print -rn -- $'\e]2;'"${words[1]} · ${(%):-%n@%m: %~}"$'\a' }
precmd() { print -rn -- $'\e]2;'"${(%):-%n@%m: %~}"$'\a' }For bash 4.4 or later, add this to ~/.bashrc on the remote machine. Back at the prompt, the title is the one the default Debian and Ubuntu ~/.bashrc sends.
PS0='\e]2;$(fc -ln -0 | sed -E "s/^[[:space:]]+//; s/ .*//") · \u@\h: \w\a'When bash keeps commands that start with a space out of the history (HISTCONTROL=ignorespace or ignoreboth; Debian and Ubuntu default to ignoreboth), such a command shows the name of the command before it while it runs.
Notifications
When a program asks for a notification through OSC 9, OSC 99, or OSC 777, sshc marks that pane as unread.
- A notification that arrives while the sshc tab is in the background, while the sshc window does not have the focus (you are working in another app beside it), or while you are looking at another session, marks the session in the session list as unread. Showing that session clears the mark.
- While the tab is in the background or the window does not have the focus, sshc also shows a browser notification (if allowed under Settings → Notifications) and plays the selected sound. The browser notification is titled with the pane name; for SSH the connection alias comes first and the pane name follows in parentheses. A program on the server can change the pane name but not the alias, so these stay distinguishable from sshc's own notifications. The body carries the title and text the program sent.
- The Android app shows an Android notification instead of a browser notification. It arrives while sshc is closed (another app or the home screen is showing), and tapping it opens that pane. The Android notification itself is silent; only the selected sound plays. The text is not shown on the lock screen. Next to the app name, the Android notification says it comes from a terminal program.
- When you show the session that sent a notification, or close that session, sshc also takes the notification back from the system's notification centre or the Android notification shade. Tapping a notification of a session that has been closed does not bring another session forward; sshc says the session is closed instead.
- A notification for the pane you are currently viewing produces neither an unread mark nor a sound.
- A bare BEL (
\a) is not treated as a notification because shells ring it for routine events such as failed completion.
To try it, run one of these inside a pane and then switch to another tab:
printf '\e]9;Task complete\a'
printf '\e]777;notify;Build finished;main.go compiled\a'Long commands finishing
When the shell reports where a command starts and ends through OSC 133 (shell integration), the sshc engine times it. When a command that ran for 30 seconds or more finishes, sshc tells you by the same rules as a program's notification: an unread mark, a browser notification and the sound. The text reads “A command finished after 95 seconds.”, or “A command failed with exit code 2 after 95 seconds.” when the shell reports a nonzero exit code. Because the engine does the timing, commands in a session in another workspace, or outside the split view, are reported too.
To try it, run this in a shell with shell integration and then switch to another session:
sleep 31; falseProgress
When a program reports progress with ESC ] 9 ; 4 ; state ; percent BEL, sshc shows it in two places. The list keeps showing progress while you view another session.
| Where | What you see |
|---|---|
| Pane header | A line along the bottom edge, over a faint track for the whole length |
| Session list row | A ring filled up to the percent, in place of the dot at the start of the row |
- State 1 is normal, 2 is an error (red), 3 is work of unknown length, 4 is paused (yellow), and 0 clears it. Error and paused keep the previous percent when it is omitted.
- Work of unknown length shows as a line moving back and forth in the header, and as a turning ring in the list.
- In the list, while the program status (OSC 7501) is waiting, done or failed, its mark shows in place of the ring. A session that is connecting, reconnecting or has ended shows its connection state.
- Progress also clears when the shell reports through OSC 133 that the command finished, and when the session switches to a new shell.
To try it, run this inside a pane:
printf '\e]9;4;1;40\a'; sleep 3; printf '\e]9;4;0\a'Program status
When a program reports its state (working, waiting for you, done, failed) with OSC 7501, the session list turns the row's dot into a status mark and shows the state and the program's words on the second line, such as "Needs permission · Run rm -rf build?".
- Working and waiting (for permission, an answer or a sign-in) clear when the program returns to the shell prompt (OSC 133 A) or the shell is replaced.
- Done and failed clear once you view the session. As with unread notifications, this browser decides whether you have seen it.
- Idle shows no mark. A session that is connecting, reconnecting or has ended shows its connection state instead.
- In a browser, when a program starts waiting for input while the tab is in the background or the window does not have the focus, sshc shows a browser notification and plays the selected sound. Clicking it opens that session, and sshc takes it back once the program stops waiting. A wait that began while you were on another session is announced once, when you leave sshc. sshc asks for permission once with a notice, the first time a program reports its status; you can also allow it later under Settings → Notifications.
- The Android app raises an Android notification when a program starts waiting for you while sshc is closed. Tapping it opens the session, and it goes away when the program stops waiting. The sound and the pop-up follow the "Programs waiting for you" notification channel in Android's settings. The app asks for the notification permission once, under Notices, the first time it receives a program status. For remote sessions, the notification comes only for the sshc engine selected, and while the app's screen keeps running in the background.
To try it, run this inside a pane, then open another session and wait:
printf '\e]7501;state=working\e\\'; sleep 5; printf '\e]7501;state=done:msg=%s\e\\' "$(printf 'Docs built' | base64)"Claude Code status
Claude Code reports its own state over OSC 7501. Start it, and the session list shows when it is working, needs permission, has a question or is done, with no settings or hooks.
- Needs permission is followed by what it waits for, as in
Needs permission · approve Bash: npm test. - Done is followed by the summary Claude Code sent, and clears once you view the session.
Inside tmux, only needs permission and has a question are shown. See Inside tmux.
Receiving Claude Code notifications
Notifications for needs permission and has a question arrive with no setup (see Program status). To also receive the desktop notifications Claude Code sends itself, set the following.
By default Claude Code sends desktop notifications only when it detects Ghostty, Kitty, or iTerm2. sshc is not part of that detection, so set the channel explicitly in ~/.claude/settings.json. iterm2 sends OSC 9 and kitty sends OSC 99; sshc accepts both.
{
"preferredNotifChannel": "iterm2"
}Task completion and permission prompts then arrive as notifications. When Claude Code sends its task summary as the terminal title, the pane name follows it as well.
Receiving Codex notifications
In Codex's ~/.codex/config.toml, enable TUI notifications and pin the method to osc9. With auto, Codex may not recognise sshc as OSC 9-capable and fall back to BEL.
[tui]
notifications = true
notification_method = "osc9"notifications also accepts a list such as ["agent-turn-complete", "approval-requested"] to limit the kinds of events.
Inside tmux
To let titles and notifications from programs inside tmux reach the outer terminal, add the following to ~/.tmux.conf:
set -g allow-passthrough on
set -g set-titles onClaude Code's permission prompts and questions
tmux does not pass OSC 7501 on, so Claude Code inside tmux cannot report its state. The sshc engine reads the screen instead: while a Claude Code question is visible, the session shows "Needs permission" or "Has a question", as under Program status. The session list, the browser notification and the Android notification work as they do outside tmux. This applies to Open in tmux and to a tmux you typed yourself.
- Only a question visible on the screen can be read. A question in another tmux window cannot: the status goes when you leave that window and returns when you come back. Nothing can be read while you are detached from tmux.
- What is read is the wording and layout of Claude Code 2.1.318. An update of Claude Code that changes the wording may stop this from working.
- The status says only that a program waits and for what kind of answer. Unlike outside tmux, it does not include the command or the text of the question.
- The same characters with nothing below them may be read as a question, for example a copy of one shown with
watch cat, or scrolled to its end inlessoutside tmux. A copy shown withcatorlessinside tmux is not.
If nothing changes
- Confirm that
sshc --versionreports v0.35.0 or later. - Run the
printfexamples above inside a pane. If the pane name or unread mark changes, sshc itself is working. - Start a new Claude Code or Codex session after saving its settings.
- When the agent runs on an SSH host, the settings belong in the home directory of that host.
- When tmux or screen is in between, check its passthrough settings.