Skip to content

simstim UX

Status: accepted, 15 October 2026. This is the third design of the client’s screens:

  • the first was one home screen with panes;
  • the second was a light launcher that followed Amp’s CLI (decision 0009);
  • this one keeps that launcher’s flow, with a look and motion of our own (decision 0012).

simstim has two kinds of screen, with opposite rules:

The launcherAn attached session
WhatHosts, sessions, search, the quick start, sheets, the add-host wizard, the guided setupThe agent’s real TUI
Who draws itsimstim, in the alternate screenThe agent, byte for byte
JobStart or join a session in a few keys, then get out of the wayEverything else
LookOur own: a signal. One column, a cyan accent, live traces, sheets that rise from the bottomUntouched. Every row and column is the agent’s.
Keys simstim readsAll of themOnly the detach key, and Ctrl+V when the clipboard holds an image

Amp’s CLI was the baseline. We keep its good habits: colours from the terminal’s palette, faint secondary text, a command palette, one list at a time. The rest is our own.

1. Principles

  1. One job per screen. Pick a host, then pick or start a session. Each screen is one list in one column. There are no sidebars, split panes, permanent previews or dashboards.
  2. The session owns the terminal. Once you attach, every row and column belongs to the agent. The client shows only two things of its own: the reconnect notice while the link is down, and system notifications (OSC 777), which draw nothing on the screen.
  3. A signal, not a box. No frame round the list. The look is a cyan accent, braille traces of each session’s output, rules instead of boxes, and sheets that rise from the bottom. It reads like a console tuned to your sessions.
  4. The terminal’s own colours. Every colour is a palette slot or the terminal’s default, so simstim matches your theme. Fixed RGB is kept for the brand gradient.
  5. Motion with a purpose. Things move when they change, are busy or need you, smoothly and in your theme’s colours. Motion never holds a key back for more than a moment, and one switch turns it off.
  6. Fast paths. The launcher draws at once and opens where you left off, so simstim then Enter takes you back in. A number opens a row, one line starts a session, and / searches every host.
  7. Plain words. Short labels in lower case for keys, sentence case for text, no exclamation marks. Every error says what to try next.

2. Screens

The mockups are 80 columns wide and come from the golden tests in internal/tui/testdata. The column grows with the terminal, up to 116 columns, centred.

2.1 First run

With no hosts, the screen is a centred welcome.

                            ⣀⡠⠤⢄⡀   ⣀⣀⣀    ⢀⠤⠒⠊⠉⠉⠉⠑⠢⠤⡀
                        ⢀⡠⠒⠉    ⠈⢑⢔⠉   ⠑⢄⡠⠒⠁       ⣀⢤⣚⣓⣦⣤⣀
                  ⠶⠶⠶⢶⡒⠪⢅⡀     ⢀⠔⠁ ⠑⢄  ⡠⠊⠑⡄     ⢀⠔⡩⠊⠁   ⠈⠉⠛⠓⠶⠶
                      ⠈⠑⠢⢌⡑⠢⠤⠤⠒⠁    ⢈⠦⡊   ⠈⠢⢄ ⢀⣔⠕⠊
                          ⠈⠒⠢⢄⣀⣀⣀⡠⠤⠒⠁ ⠈⠢⢄⡀ ⣀⡠⠝⠉

                                 s i m s t i m
                              jack in to any host

             enter set up   a add a host   ctrl+o commands   ? keys

The welcome plays as a short sequence:

  1. The mark opens out from its middle. It is three strands of a signal woven into a ribbon that pinches at both ends, drawn in braille, in the brand gradient. Then it flows, a pulse runs along it, and the strands are brighter where they cross.
  2. The name decodes out of braille noise, letter by letter.
  3. The tagline, then the keys, come in under it. Enter opens the guided setup (2.12). a opens the add-host wizard, and says how many hosts your SSH config already has.

2.2 The launcher’s layout

Every list screen has the same parts, top to bottom:

  ⢄⡠⠊ simstim  › atlas-dev                      9ms · 4 sessions · 1 needs you   ← header
  ────────────────────────────────────────────────────────────────────────────   ← rule

  ▍ 1 ● auth-refact…  claude    ~/src/app         needs input     2m  ⣀⣀⣠⣴⣶⣦⣄⣀   ← the list
    2 ⢼ api-tests     codex     ~/src/api         working        14s  ⣀⣴⣶⣦⣴⣶⣶⣼
    3 ○ notes         shell     ~                 idle            1h  ⣀⣀⣀⣀⣀⣀⣀⣀
    4 ✓ docs-pass     opencode  ~/src/docs        exited 0        3h  ⣀⣀⣀⣀⣀⣀⣀⣀

    ● Do you want to proceed?              ~/src/app · 6.1 of 8 GiB · s4          ← the line under the list

    ✓ Copied: simstim attach atlas-dev/auth-refactor.                            ← notices
  ────────────────────────────────────────────────────────────────────────────   ← bottom rule
    ❯ / search every host   n start a session                                     ← the prompt line
    enter attach   space peek   r rename   esc hosts   ? keys                      ← the keys
  • The header has three parts on the left: the logo (a three-cell braille wave), the name in the brand gradient, and where you are (hosts, › atlas-dev, › search). The facts sit on the right. A host’s name decodes in when you open it.
  • The rule draws itself from the left when the launcher starts. While something is busy, such as a host connecting, a cyan band sweeps along it.
  • Each row has these columns:
    • the marker: a cyan ▍ and a soft cyan tint on the selected row;
    • its number, faint (1–9 open it);
    • the state glyph and the name in bold;
    • details, faint;
    • at the right, the trace.
  • The trace is eight braille cells of the session’s output over the last half minute. A busy agent draws a wave, a quiet one a flat line. It scrolls as time passes. It is coloured like the state: cyan for working, yellow for needs input, faint otherwise.
  • The line under the list is about the selected row.
  • Notices rise above the bottom rule.
  • The prompt line is where search and the quick start happen. When idle, it says how to use them.
  • The keys are in lower case, the key in cyan and its words faint, with wide gaps between them.

2.3 Hosts

  ⢄⡠⠊ simstim  hosts                                     3 hosts · 1 needs you
  ────────────────────────────────────────────────────────────────────────────

  ▍ 1 ● atlas-dev   4 sessions · 1 needs you                     9ms  ⣀⣀⣀⣀⣀⣀⣀⣼
    2 ◌ aws-gpu     offline                                           ⣀⣀⣀⣀⣀⣀⣀⣀
    3 ● gcp-dev     2 sessions                                  41ms  ⣀⣀⣀⣀⣀⣀⣀⣼

    ssh atlas-dev · Debian 13 · 4 CPUs · claude, codex, opencode, shell
  • Each row:
    • The state: ● green online, the spinner while connecting, ◌ faint offline, ✕ red not ready.
    • The name, then a faint summary, in which the count that needs you is yellow.
    • The round trip, then the trace of all the host’s sessions together.
  • The line under the list: how the host is reached, and what it runs.
  • Keys: Enter (or l, →, or its number) opens the host’s sessions. n starts a session there, a adds a host and i shows its details. With exactly one host, the launcher opens on its sessions.

2.4 Sessions

  ⢄⡠⠊ simstim  › atlas-dev                      9ms · 4 sessions · 1 needs you
  ────────────────────────────────────────────────────────────────────────────

    1 ● auth-refact…  claude    ~/src/app         needs input     2m  ⣀⣀⣀⣀⣀⣀⣀⣀
  ▍ 2 ⢼ api-tests     codex     ~/src/api         working        14s  ⣀⣀⣀⣀⣀⣀⣀⣼
    3 ○ notes         shell     ~                 idle            1h  ⣀⣀⣀⣀⣀⣀⣀⣀
    4 ✓ docs-pass     opencode  ~/src/docs        exited 0        3h  ⣀⣀⣀⣀⣀⣀⣀⣀

    ▸ ∴ Working (14s · esc to interrupt)                      ~/src/api · s3
  • Each row: the number, the state glyph, the name, the agent and folder (faint), the state in its colour, the time in that state, and the trace.

    • A working session’s glyph is a tiny Game of Life in one braille cell.
    • The dot of a session that needs you breathes.
  • Order: needs input, working, idle, then ended.

  • The live activity line says what the selected session is doing now:

    • If it waits for you, its question, in yellow.
    • Otherwise, the most telling line of its screen, after a cyan ▸. That line is read from the session about every 1.5 s, and borders, prompts and the hints an agent always shows are skipped. It decodes in when it changes.
    • Its folder, memory and ID sit at the right.
  • Keys:

    • Enter, or the row’s number, attaches. On an empty list, Enter opens the quick start.
    • n opens the quick start, space peeks at the screen, and r renames in place.
    • d deletes after a confirm, y copies the attach command, and alt+e (opt+e on a Mac) hides or shows ended sessions.
    • Esc (or h, ←) goes back to the hosts, on the same host.
  • Before the host answers:

    • The launcher shows the sessions it remembers from the last run at once, quiet (faint), while the rule’s scan says it is connecting.
    • Enter attaches straight away.
    • The line under the list says “last seen before this run” until the live list arrives (decision 0011).
  • Offline: a red ✕ and the message, then a cyan → and the step to try:

      ✕ Cannot reach aws-gpu: ssh: connect to host 198.51.100.4 port 22: Operation
        timed out.
      → ssh aws-gpu   (check that this works first)
      Retrying in the background.
  • Every host: simstim flip, or “All sessions” in the palette, lists every host’s sessions in one list, under each host’s name.

2.5 Search every host

/ from either list opens the prompt line in search mode. The list shows the sessions of every host that match. A result can match its name, agent, folder or ID, or its host’s name. Matched letters are cyan and underlined.

  ⢄⡠⠊ simstim  › search                                             every host
  ────────────────────────────────────────────────────────────────────────────

  ▍ 1 ● auth-refact…  claude    atlas-dev:~/sr…  needs input     2m  ⣀⣀⣀⣀⣀⣀⣀⣀
    2 ⢼ api-tests     codex     atlas-dev:~/sr…  working        14s  ⣀⣀⣀⣀⣀⣀⣀⣼
  …
    search ❯ te
    enter attach   ↑↓ move   esc close

Enter attaches the selected result, and Esc closes the search.

2.6 Quick start

n opens the prompt line for a new session on the host in play. The whole session is one line: claude ~/src/app auth.

    claude  codex  opencode  shell   ~/src/api/  ~/src/app/
  ────────────────────────────────────────────────────────────────────────────
    atlas-dev ❯ claude ~/src/api/
    enter start   tab complete   ctrl+enter detached   ctrl+f form   esc cancel
  • The line: an agent the host has, a folder (any word with a / or ~), and the rest as the name. +wt asks for a new git worktree. Each part is optional: the agent defaults to the one used last on the host, and the folder to ~.
  • Completion: a faint ghost after the cursor shows what Tab would add, either an agent’s name or a folder on the host. The line above the rule lists the host’s agents, with the one the line names lit, then the folders that match.
  • Keys:
    • Enter starts the session and attaches, and ctrl+enter starts it detached.
    • ctrl+f opens the full form (2.7) with the line filled in.
    • While the session starts, the line shimmers “Starting claude on atlas-dev…”. An error appears above the rule.

2.7 Sheets

Every dialog is a sheet. It rises from the bottom of the screen over the dimmed list, full width, with no side borders. Its title is in cyan, set into a rule across its top, its body is indented, and its keys are on its last line. A sheet’s facts sit at the right of its rule.

  ── New session on atlas-dev ───────────────────────────────────────────────

    Agent      claude  codex  opencode  shell  other…   not installed: anti…
    Folder     ~/src/app
    Name       auth
    Worktree   ● this folder   ○ new worktree

    enter start   tab next   ctrl+enter start detached   esc cancel
SheetOpens onWhat it holds
New sessionctrl+f in the quick start, or the paletteAgent (the chosen one lit while the row has focus), folder with completion from the host, name, and worktree. “other…” runs any command you type.
DeletedRed rule and title: “Delete api-tests?”, what stops and what stays
PeekspaceThe session’s last screen, refreshed while open; ↑↓ move to the next session, Enter attaches
Commandsctrl+oThe palette: a filter, then every command as plain words (“New session”, “Peek at the screen”) with its key in cyan. A command that cannot run says why, faint.
Keys?Every key that works here, in two columns, built from the live registry
Host detailsiRoute, system, helper, agents, limits; t test, s shell, r reconnect, x remove
Add a hostaThe wizard (2.10)
Set upEnter on the first-run screen, sThe guided setup (2.12)

A click outside the palette, the peek, the host details or a confirm closes it.

2.8 Notices and quitting

  • Notices are short lines that slide in from the left above the bottom rule, and fade:

    • success is a green ✓ and the text;
    • information is a cyan •;
    • an error is a red ✕, then a cyan → and the step to try.

    They last 4 s, or 8 s for an error, and two lines show at once.

  • Quitting: ctrl+c turns the keys line into “ctrl+c again to quit, sessions keep running esc stay”. A second ctrl+c quits, and any other key stays. q quits at once. Quitting never stops a session.

2.9 Attached

The agent owns the whole terminal: every row and every column. There is no border, status bar, sidebar or session list.

  • Jack in: with motion on, an attach starts with a 0.17 s sweep. The other rows fade, and a cyan line runs down from the chosen row. Then the terminal is the agent’s.
  • Size: the agent’s PTY is the terminal’s size, and follows every resize.
  • Window title: the agent’s own. simstim saves the title before attaching and puts it back on detach.
  • Detach: Ctrl+\ goes back to the launcher, on the same session, and the rows fade back in. Press it twice quickly to send it to the agent.
  • Lost connection is the only thing the client draws on the screen:
    • At once, the title shows ⧗ reconnecting · atlas-dev/s4, and an OSC 9;4 progress mark appears.
    • After 3 s, one faint line is drawn on the bottom row: simstim · connection lost · reconnecting · keys are not sent · ctrl+\ to leave.
    • On reconnect, a replay or a snapshot redraws the agent’s screen over the line, and the title comes back. A notice follows in the launcher.
  • System notifications (OSC 777) tell you when another session needs you or ends, and when an image upload fails. They draw nothing on the screen.

2.10 Add a host

a, from any screen: a sheet with one step per screen, the step count at the right of its rule. Esc goes back one step.

  1. Where. A target from ~/.ssh/config (↑↓ pick, and typing filters), a name, and an optional extra SSH config file.

  2. Test. Each check shows the spinner, then ✓ or ✕ with the time it took. A failure shows the error and its next step.

  3. Install the helper. This is the consent screen. It says what is installed and where, what else changes (linger, terminfo), and that nothing listens on the network.

  4. Ready. The agents found, the system, and the memory cap per session. The host’s sessions are now open behind the sheet. When a first-class or supported agent is missing or not logged in, Enter goes on to the agents; otherwise it starts a session.

  5. Agents. The checklist: every agent with an installer, first-class and supported ones first. An installed agent has a green ✓, a ticked one a cyan ●, the rest a faint ○, each with its state. The best-effort agents wait under a fold, ▸ 5 more agents, best effort, which Enter or Space opens. Space ticks, and Enter installs what is ticked.

      ── Agents on pi ───────────────────────────────────────────── step 5 of 6 ──
    
        Tick the agents to install on pi. Each one installs with its vendor's
        own installer, in a session you watch.
    
          ✓ Claude Code       installed, logged in
        ▍ ● Codex             not installed
          ○ opencode          not installed
          ○ Antigravity CLI   not installed
          ▸ 5 more agents, best effort
    
        space tick   enter install 1 agent   esc back
  6. Install, then log in. One sheet for each install, then one for each agent that is installed but not logged in. Each shows the command, where it comes from, and the session it runs in (install-codex, login-codex). Enter starts the session and attaches; the user answers the installer or the login there. When they detach, or the session ends, the sheet checks the host again, and the next sheet shows how it went. s skips one, and Esc stops the rest.

  7. Done. Each agent with its mark (✓ ready, ! not logged in, ? login unknown, ✕ missing) and the step to try, then the command for the first session. Enter opens the new-session form with that agent chosen.

2.11 Fast paths

  • Where you left off. The launcher opens on the sessions of the host you last attached to, with that session selected. simstim then Enter takes you back in.
  • At once. It draws the sessions it remembers before any host answers.
  • Numbers. 1–9 open the row with that number.
  • Search and quick start. / finds a session on any host; n starts one from a single line.
  • The mouse. Click a row to select it, and click the selected row to open it. The wheel moves the selection, and a click on a palette row runs it.
  • The tab title counts the sessions that need you: ● 1 · simstim · homelab.
  • When nobody is looking. If a session starts to need you while the terminal is in the background, the launcher sends a desktop notification.
  • From the shell. simstim attach - attaches to the last session.

2.12 Guided setup

Enter on the first-run screen, or s from any screen: a sheet that asks where agents will run, then hands the host to the add-host wizard (2.10), which ends with the agents and their logins. The engine behind it is shared with simstim setup (decision 0020).

  1. Where. The places, numbered. A green ● marks one this computer can use now, a faint ○ one it cannot, with what is missing. The selected place that is not ready shows its steps under the list, with each command in cyan; Enter checks again.

      ── Set up ──────────────────────────────────────────────────────────────────
    
        Where will agents run?
    
          1 ● A host in your SSH config           3 found: atlas-dev, gcp-dev, …
        ▍ 2 ○ A local VM, with Lima               limactl is not on your PATH
          3 ● A container, for testing (Docker)   no systemd, so no memory caps
          4 ○ A cloud sandbox, with E2B           no E2B API key found
          5 ● A server I will rent                step by step, with checks
    
        To make it ready:
        On macOS, with Homebrew:
          brew install lima
        or with MacPorts:
          sudo port install lima
        Other ways, such as the release archive, are in Lima's guide:
        https://lima-vm.io/docs/installation/
    
        enter check again   ↑↓ move   esc close
  2. A host in the SSH config opens the wizard’s first step, with the hosts listed. Esc there comes back.

  3. Lima, Docker or E2B asks for a name, then makes the machine. The spinner shows the provider’s last line of progress. Esc stops it, and a half-made Lima VM or container is deleted. The wizard then installs the helper without its consent screen, since making the host was the user’s yes, and turns on idle stop for a VM.

  4. A server I will rent has one screen for each step, with the step count at the right of the rule:

    1. An SSH key. The key it found, or how to make one. k runs ssh-keygen in the terminal.
    2. A server. What to rent, and the command that prints the key to paste. Then its address.
    3. A user for your agents. The commands to run as root, with the address and user filled in. Enter checks that ssh user@address works, and the error shows when it does not.
    4. A name for the server. Then the lines for ~/.ssh/config, in full. y adds them, n leaves them to the user; Enter checks that ssh <name> works. Then the wizard tests the host.

The sheets keep the field and its error in view on a short screen; long steps give way first, ending in ….

3. Keymap

These keys work in the launcher. You can rebind any key in config.toml, and simstim config keymap prints the effective map. On screen, keys are written in lower case, as you type them: enter, esc, ctrl+o, space, opt+e on a Mac.

KeyWhereAction
↑ ↓ or j kListsMove
1–9ListsOpen the row with that number: a host’s sessions, or attach
Click, wheelLists, paletteSelect, open the selected row, move; run a palette command
enter, l, →HostsOpen the host’s sessions
esc, h, ←SessionsBack to the hosts
enterSessionsAttach, or open the quick start on an empty list
nAnywhereQuick start on the host in play
/AnywhereSearch every host
spaceSessionsPeek at the screen
r, f2SessionsRename
dSessionsDelete, with a confirm
ySessionsCopy the attach command
wAnywhereGo to the next session that needs you, on any host; press again for the one after
alt+e (opt+e)SessionsHide or show ended sessions
aAnywhereAdd a host
s, or enter on the first-run screenAnywhereThe guided setup
iAnywhereHost details
tab, ctrl+enter, ctrl+fQuick startComplete; start detached; open the form
ctrl+oAnywhereCommands
?AnywhereKeys
escSheets, promptBack or cancel
q, or ctrl+c ctrl+cAnywhereQuit. Sessions keep running.
ctrl+\AttachedDetach. Press it twice to send it to the agent.
ctrl+vAttachedPaste an image if the clipboard holds one; otherwise the key passes through

4. Visual language

4.1 Palette

Every token is a terminal palette slot, the terminal’s default colour, or the faint attribute. So the launcher looks the same in 256- and 16-colour terminals as in truecolour: your theme decides the colours. The truecolour column gives the colours in the reference theme, the owner’s Ghostty theme, which the README images use.

TokenSent asTruecolour (reference theme)256 colours16 coloursNo colourUsed for
textdefault foreground#BFBDB6defaultdefaultdefaultNames, body text
backgrounddefault background#0B0E14defaultdefaultdefaultNever painted, except the tint
faintSGR 2 on the text#656565 (half way to the background)SGR 2SGR 2SGR 2Details, words in the keys, rules, the dimmed backdrop
accentslot 6#90E1C66cyandefaultKeys, sheet titles, the marker, working, the prompt, links, the scan
tintthe accent mixed 13 % into the background#1C292BnonenonenoneThe selected row (truecolour only: elsewhere the marker shows it)
successslot 2#7FD9622greendefault✓, an online host
warningslot 3#F9AF4F3yellowdefaultNeeds input, its question, its trace
dangerslot 1#EA6C731reddefault✕, failed states, the delete sheet
cursorreverse video#BFBDB6 blockreversereversereverseText fields

No colour. With NO_COLOR set, or TERM=dumb, the terminal gets no colour at all, only bold, faint, underline and reverse, and motion is off. Nothing depends on colour alone: the marker ▍ shows the selection, and each state has its own glyph (●, ⠶, ○, ✓, ✕, ◌).

Tested. internal/tui/theme_test.go renders the screens through each colour profile (truecolour, 256, 16, no colour, no terminal) and checks what each one sends. It also checks that every fixed colour keeps a contrast of 3:1 or more on dark and light backgrounds. The golden screens cover 60×20, 80×24 and 120×36.

4.2 The brand

One fixed gradient, from deep teal to electric cyan, colours the welcome mark, the name in the header and on the welcome screen, and the logo. On a light background the teal is deeper, so it keeps its contrast.

Dark backgroundLight background
Truecolour#0E7C7B to #00E5FF#045A5A to #0098B8
256 colours (nearest index)30 (#008787) to 45 (#00D7FF)23 (#005F5F) to 31 (#0087AF)
16 colourscyan (slot 6), no gradientcyan (slot 6), no gradient

4.3 Type and layout

  • Bold: names, the selected command, the brand. Faint: everything secondary. Underline: matched letters in search.
  • No boxes. Rules (──) divide the screen, and a sheet’s title sits in its rule. The list has no frame.
  • Spacing:
    • A two-cell gutter holds the marker.
    • The number and the glyph each take one cell, with one space after each.
    • Columns are two spaces apart, and hints three.
  • Narrow terminals: the column keeps a two-cell margin down to 60 cells. Below 70 cells the folder column of a session list goes; the line under the list still shows the folder, and in search the host too.
  • Truncation: …. Paths keep whole folders, /home/dev/…/auth; names are cut at the end.
  • Sheets rise over the list, which is dimmed with the faint attribute, so the effect works with any theme. One sheet shows at a time.

4.4 Glyphs

GlyphMeaning
▍ cyanThe selected row
⢄⡠⠊The logo: a small braille wave
● green / yellowAn online host / a session that needs input (it breathes)
⢼ braille, cyanA working session: a tiny Game of Life on the cell’s eight dots
⠁⠂⠄⡀⢀⠠⠐⠈The spinner: one dot running round a braille cell
⣀⣀⣴⣶⣦⣀A trace: output over the last half minute
○Idle
✓ greenDone, exited 0, a check passed
✕ redFailed, an error, a host that is not ready
→ cyanThe step to try next
▸ cyanWhat the selected session is doing now
◌Offline, lost
❯The prompt

4.5 Motion and sequences

Motion is there to show change, work in progress and things that need you. Keys act at once, whatever is moving. The one exception is the jack-in, which holds them for 0.17 s.

SequenceWhenWhat happens
BootThe launcher opensThe header rule draws from the left (0.26 s); the rows fade in one after another (22 ms apart, 140 ms each), then the line under them
SlideInto a host’s sessions, or backThe list slides in, from the right going deeper and from the left coming back (0.18 s), and fades in; the host’s name decodes in the header
GlideThe selection movesThe marker moves at once; the row’s tint fades over from the old row (0.11 s)
DecodeA host’s name, the welcome’s name, a new activity lineEach letter settles out of braille noise (0.42 s)
RiseA sheet opensIt slides up from the bottom edge (0.16 s) over the dimming list
ScanA host connecting, a session starting, the wizard at workA cyan band sweeps along the header rule, once every 1.6 s
Jack inAn attachThe other rows fade and a cyan line runs down from the chosen row (0.17 s), then the agent takes over
NoticesWhen they come and goSlide in from the left over 150 ms and fade; fade out over the last 300 ms
Shimmer“Connecting…”, “Starting…”A brighter band sweeps across the faint text
BreathA session needs youIts dot breathes, once every 1.6 s
LifeA session worksIts braille glyph runs a tiny Game of Life
TraceOutputEach row’s trace scrolls with time
WelcomeThe first-run screenThe ribbon opens out, flows and pulses (30 fps); the name decodes; the tagline and keys arrive

Colour. To blend smoothly, the launcher asks the terminal for its real colours: the default foreground and background (OSC 10 and 11) and the 16 palette slots (OSC 4). Fades, the tint and the scan then mix those colours in truecolour, so they match your theme. Without truecolour, or before the terminal answers, the same motion uses steps of faint, normal and bold, and the marker alone shows the selection.

Cost. One frame tick runs only while something moves: 30 fps for sequences, the scan and the welcome, and 10 fps for spinners, breathing dots, working glyphs and scrolling traces. When nothing moves, nothing repaints.

One switch. ui.motion = auto | on | off. auto turns motion off inside SSH sessions, in Emacs and JetBrains terminals, and when NO_COLOR or TERM=dumb is set. With motion off, every sequence is its last frame. Traces still show what happened, but they move only when the list refreshes.

4.6 Capability probe

simstim doctor terminal sends one batch of queries, with DA1 as the end marker. It covers:

  • the kitty keyboard protocol, synchronized output and OSC 52;
  • XTVERSION;
  • the OSC 10, 11 and 12 colours;
  • modes 2027 and 2031.

It shows what the agent will get through the pass-through.

5. Feedback

Notices (2.8):

  • “Detached. auth-refactor keeps running on atlas-dev.”
  • “Reconnected to atlas-dev.”
  • “Copied: simstim attach atlas-dev/auth-refactor.”

A repeat extends the notice instead of adding a line.

Errors:

  • Every error has a message and one next step.

  • In the launcher and in sheets, an error is a red ✕ and the message, then a cyan → and the step.

  • On the command line it prints as a bold red Error: and the message, a blank line, then the step:

    Error: cannot reach atlas-dev through the jump host bastion.
    
    Try: simstim host test atlas-dev --verbose

Empty states: a faint statement, a blank row, then a hint whose key is cyan. “No sessions on gcp-dev yet.” / “n start one from a single line, like: claude ~/src/app”. “Nothing matches ‘xyz’.”

Copy rules:

  • Use sentence case and plain words, with no exclamation marks.
  • Say what keeps running: “Quit. Sessions keep running.”
  • Name the host and the session in every message.

6. CLI

The launcher is the home, and every action also has a command, for scripts and terminal keybindings.

CommandDoes
simstimOpens the launcher
simstim setup [--host h | --create lima|docker|e2b] [--name n] [--agents a,b] [--yes] [--no-login]The guided setup: where agents run, the host, the agent checklist, the installs and the logins, then the first session’s command
simstim host add <name> [target] [--ssh-config f] [--provider-script s --wake] [--yes]Connects a host: probe, consent, install, setup, doctor; in a terminal, the agent checklist when an agent is missing
simstim host ls, test, doctor, rmHost management
simstim host restore <name> [--all]Starts again the sessions that a host restart stopped (or, with --all, a crash)
simstim host start|stop|status <name>Runs the host’s provider script
simstim new <host> [--agent claude] [--dir ~/src/app] [--name x] [--worktree [--base ref]] [--detach] [-- cmd…]Starts a session, and attaches unless --detach
simstim ls [--host h] [--json]Lists sessions, with their state and where the state came from
simstim attach <host>/<session>, attach -Attaches directly; - is the last session. Good for a Ghostty keybinding.
simstim flip [<host>/<session>]A quick switch: the sessions of every host in one list, then attach
simstim send <host>/<session> <text> [--no-enter]Types text into a session without attaching
simstim rename <host>/<session> <name>, kill <host>/<session>Renames; stops and removes (keeping a worktree that has work)
simstim ports <host>/<session>, forward <host>/<session> [port…]Lists the ports a session listens on; forwards them to localhost
simstim demo [--empty]The launcher on sample data; nothing connects anywhere
simstim doctor keysPrints each key event as the terminal sends it, and marks the client’s own keys
simstim doctor terminalAsks the terminal what it supports: kitty keys, synchronized output, colours, and more
simstim version, completion zsh|bash|fishHousekeeping

Exit codes: 0 for success, 1 for a user error, 2 for a host or network error, 3 for a session or host that is not found.

7. Config

# ~/.config/simstim/config.toml
[ui]
motion = "auto"          # auto | on | off

[attach]
detach_key = "ctrl+\\"
image_paste_key = "ctrl+v"
scrollback = "keep"      # keep | clear: what to do with local scrollback on a fresh attach

[sessions]
memory_max = "auto"      # auto = min(8 GiB, 40 % of host RAM)

[keymap]
"session: delete" = "d"
"session: rename" = ["r", "f2"]
# ~/.config/simstim/hosts.toml
[[host]]
name = "atlas-dev"
ssh = "atlas-dev"           # a Host from ~/.ssh/config, used as is
labels = { provider = "homelab" }
# provider = { script = "~/.config/simstim/providers/gcp.sh" }

8. Not built yet

These parts of the spec are planned, and are not in the current build:

  • using the capability probe for the launcher’s own drawing (the probe itself is doctor terminal);
  • live light and dark refresh through mode 2031 (the launcher reads OSC 11 once, at start);
  • the ⧗ mark for hosts with a time limit (GCP IAP, AWS EICE);
  • the disk check in the add-host wizard’s test step;
  • editing a host from host details.