rst is a fast terminal reset for macOS and Linux. When your terminals "breaks", you run reset, but it takes a second. rst takes 2 milliseconds.
It repairs the kernel TTY state and emits the terminal's terminfo reset strings, without the 1s sleep that reset inherits from 3BSD's tset(1), meant for mechanical printer-and-ink terminals to 'settle down'.
- Fast: ~2ms vs ~1 second for
/usr/bin/reset. - Tiny: 162 KB, smaller than the system
reset(164 KB) it replaces. - Self-contained: parses the terminfo database itself; links only libc, no ncurses.
- Compatible: emits the same reset strings as ncurses
tput reset, and falls back to VT escapes when no terminfo entry exists (e.g. SSH to an older host).
- Kernel TTY state. Restores canonical/cooked input, echo, signals, CR/NL mapping, and output processing. Only repairs disabled control characters, preserving user customizations such as an erase key set to
^H(matching ncurses). UsesTCSAFLUSHto discard stale typeahead a crashed raw-mode program may have left in the input queue. Undoes a stuck^S/TCOOFFviatcflow(TCOON)before touching termios, so reset itself can't hang behind stopped output. Refuses to run as a background job (checkstcgetpgrp) so it never writes to another job's terminal. - Terminal emulator state. Reads the terminal's compiled terminfo entry directly (no ncurses dependency) and emits the terminal's reset strings in the same order ncurses
tput resetuses —rs1,rs2,clear_margins,rs3, with eachrsNfalling back to the correspondingisNwhen absent. For known VT-compatible terminals it first sends a small hard-coded cleanup sequence (synchronized output, mouse, focus, paste off), and only when no terminfo entry is found does it use a hard-coded VT fallback. That makes it recover even when a terminfo entry is absent (e.g. SSHing from a newer terminal to an older host).
It locates a TTY on stderr, stdout, stdin (reopened read-write), or /dev/tty.
Common ways to break your terminal — and how rst recovers them. Type rst blind (you won't see it, but it will execute) and hit Enter to recover.
| Break command | What it does | rst fixes |
|---|---|---|
cat /dev/urandom |
Binary garbage leaves random escape sequences and alternate charset active | ✓ |
printf '\e[?1049h' |
Enters alternate screen; scrollback vanishes | ✓ |
printf '\e[?25l' |
Hides the cursor | ✓ |
printf '\e[8m' |
Invisible (concealed) text | ✓ |
printf '\e(0' |
DEC line-drawing charset; text becomes garbage symbols | ✓ |
printf '\e[4h' |
Insert mode; typing pushes text right | ✓ |
printf '\e[?5h' |
Reverse video | ✓ |
stty raw |
Raw mode; line editing dies (use Ctrl-J to submit) | ✓ |
printf '\e[3;10;20t' |
Resizes the terminal window (on supporting terminals) | ✓ |
printf '\e[r\e[H' |
Resets scroll region and moves cursor home | ✓ |
stty -opost -onlcr |
Disables output processing; ls columns stairstep |
✓ |
printf '\e[?1003h\e[?1006h' |
Enables mouse reporting; clicking/dragging spews escape garbage into your prompt | ✓ |
stty -icanon min 1; stty -isig |
Disables canonical mode and signals; Ctrl-C and line editing stop working | ✓ |
Requires Zig 0.16.0. No ncurses or other external libraries — rst parses the terminfo database itself and links only libc:
zig build --releaseThe binary is installed to zig-out/bin/rst. It links only the system C library (libSystem on macOS, libc on Linux) — no shared-library dependency on ncurses.
zig build --release
install -m 0755 zig-out/bin/rst /usr/local/bin/rstOr put it anywhere earlier on PATH than /usr/bin to shadow the system reset.
A portable PTY test builds the binary, puts a TTY into a deliberately broken raw/no-echo state, runs rst, and verifies that canonical mode and echo were restored:
zig build test
python3 scripts/pty-test.py zig-out/bin/rstThe unit suite includes a seed corpus for the terminfo parser. On architectures supported by Zig's native fuzzer (including CI's x86_64 Linux runner), run 100,000 fuzz iterations with zig build test -Drelease --fuzz=100K.
The mechanism is established prior art; rst is a polished, cross-platform Zig package, not the first fast reset.
- BusyBox
reset— a ~676-byte applet that emits fixed reset escapes, runsstty sane, and performs no settling sleep. (console-tools/reset.c) - Toybox
reset— the closest philosophical match. Its source says: "In 1979 3BSD's tset had a sleep(1) to let mechanical printer-and-ink terminals 'settle down'. We're not doing that." (toys/other/reset.c, 2015 introduction, 2023 cooked-mode fix) - ncurses
tput reset— upstream ncurses moved the terminal-mode part ofresetintotput resetin 2016 and refined it in 2017, withouttset's hardware-settling wait. (tput(1))
A no-code fast alternative on any system with ncurses is:
reset -I && tput resetrst packages the same idea into a single dependency-free standalone binary — it reads the terminfo database itself rather than linking ncurses.
The reset work rst performs is the same mechanism as ncurses reset / tput reset (both funnel into ncurses' progs/reset_cmd.c), minus the legacy sleep. For completeness, the exact, deliberate differences — verified against the ncurses source — are:
- The settling sleep is removed.
/usr/bin/resetcallsnapms(1000)after emitting the reset strings (tset.c), a hardware-settling delay retained from 3BSD for mechanical terminals.tput resetnever had it.rstmatchestput reset: no sleep. - No tabstop reprogramming. Between
rs2andrs3, ncurses'reset_tabstopsclears and re-sets hardware tab stops using theinit_tabs,clear_all_tabs, andset_tabcapabilities.rstomits this; terminal emulators do not use hardware tabs, so it is dead work there. This matters only for a real terminal with non-default tab stops. - No
reset_file/init_file. ncurses cancata per-terminal initialization file named by therf/ifcapability.rstdoes not read or emit arbitrary files during reset. - No alternate margin fallback. If
clear_margins(mgc) is absent, ncurses falls back toset_lr_margin/set_left_margin+set_right_margin(and a space-fill when only the latter pair exists).rstsendsmgconly; on a terminal lackingmgcit clears no margins. - VT cleanup prelude is extra. For known VT-compatible terminals
rstfirst sends a short sequence to disable synchronized output, mouse reporting, focus events, and bracketed paste. ncurses does not do this; it relies on the terminfo strings alone. - Missing-entry fallback is extra. When no terminfo entry exists, ncurses aborts;
rstinstead emits a fixed VT reset sequence so a terminal emulator can still be recovered (common when SSHing to an older host). - Simpler padding handling.
rstremoves terminfo$<delay>markers instead of sleeping or emitting pad bytes scaled to baud rate the waytputsdoes. Terminal emulators process output instantly; this only affects physical serial terminals.
The one behavioral difference that matters for the common case is the removed settling delay. For a real serial or physical terminal where the delay, tabstops, or margin fallbacks matter, use /usr/bin/reset.
Measured on macOS 26.6 / arm64 (Apple Silicon) in a pseudo-TTY harness. Absolute numbers vary by machine and harness overhead; the intentional one-second delay dominates the conclusion.
/usr/bin/reset: 1012 ms (napms(1000) settling sleep)
/usr/bin/reset -I: 2.7 ms (TTY repair only, skips the sleep)
/usr/bin/tput reset: 3.2 ms
rst: 1.9 ms
rst is the fastest of the variants — dropping the ncurses dependency eliminates library initialization overhead — and ~530× faster than /usr/bin/reset for the common terminal-emulator case.
CI builds and runs the PTY test on macOS arm64 and Linux x86_64. Tagged releases publish binaries for macOS and Linux on arm64 and x86_64; Linux binaries are statically linked, while macOS binaries link only the system libSystem.
Apache-2.0. See LICENSE.