Skip to content

Add per-connection terminal capability detection#226

Draft
lawik wants to merge 1 commit into
nerves-project:mainfrom
lawik:add-terminal-capability-detection
Draft

Add per-connection terminal capability detection#226
lawik wants to merge 1 commit into
nerves-project:mainfrom
lawik:add-terminal-capability-detection

Conversation

@lawik

@lawik lawik commented Jun 3, 2026

Copy link
Copy Markdown

Lars' notes:

This is an experiment towards supporting modern terminal features over SSH. I'm not sure it is worthwhile since it raises a lot of fun compat concerns.

I was mostly interested in if it was possible to get some of this feature-set over SSH and in Elixir. Perhaps being able to detect support for the kitty image protocol and other fun madness.

Claude:

Detect modern terminal features (Kitty graphics, sixel, Kitty keyboard protocol, synchronized output, terminal name/version) per SSH connection by querying the connecting terminal and reading its responses back over the pty.

Environment-based detection (TERM/KITTY_PID/TERM_PROGRAM) doesn't work on a Nerves device: those variables live on the client and don't survive the hop over SSH. Instead, the IEx shell-startup callback runs a batch of capability queries terminated by a Primary Device Attributes (DA1) request. Reading with echo off routes input through the Erlang group's "dumb" state, where get_chars returns bytes immediately rather than waiting for a newline, so the raw response can be read without a custom ssh_cli. DA1 is answered by essentially every terminal and responses arrive in order, so its reply doubles as a completion sentinel.

Results are stored per session (keyed by group leader, cleaned up on disconnect) and exposed via NervesSSH.TerminalCapabilities.get/0. Controlled by the new :detect_terminal_capabilities option (default on; Elixir 1.17+).

Detect modern terminal features (Kitty graphics, sixel, Kitty keyboard
protocol, synchronized output, terminal name/version) per SSH connection by
querying the connecting terminal and reading its responses back over the pty.

Environment-based detection (TERM/KITTY_PID/TERM_PROGRAM) doesn't work on a
Nerves device: those variables live on the client and don't survive the hop
over SSH. Instead, the IEx shell-startup callback runs a batch of capability
queries terminated by a Primary Device Attributes (DA1) request. Reading with
echo off routes input through the Erlang group's "dumb" state, where get_chars
returns bytes immediately rather than waiting for a newline, so the raw
response can be read without a custom ssh_cli. DA1 is answered by essentially
every terminal and responses arrive in order, so its reply doubles as a
completion sentinel.

Results are stored per session (keyed by group leader, cleaned up on
disconnect) and exposed via NervesSSH.TerminalCapabilities.get/0. Controlled by
the new :detect_terminal_capabilities option (default on; Elixir 1.17+).
@fhunleth

fhunleth commented Jun 3, 2026

Copy link
Copy Markdown
Member

This seems really useful, but my first reaction is shouldn't this be in OTP? Either that or some hook be in OTP? It seems generally useful to everyone and not just Nerves users. I'd also expect it to work in console.

@lawik

lawik commented Jun 3, 2026

Copy link
Copy Markdown
Author

Yeah. I don't know the world of tty, pty and the rest well enough to have a good sense. It does seem like it'd be neat to have in OTP but would also kind of be a bit bloaty? I don't know.

@fhunleth

fhunleth commented Jun 3, 2026

Copy link
Copy Markdown
Member

It does seem like it'd be neat to have in OTP but would also kind of be a bit bloaty?

I feel like Nerves is more susceptible to bloat given its embedded focus than OTP. I kind of wish that it would be easier to make OTP less bloaty. 😢

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants