The first real deployment surfaced everything a header comment
couldn't hold: SDL's Linux build dependencies (and the XTEST error a
partial set produces), the stale-CMake-cache gotcha after a failed
configure (cargo clean -p sdl3-sys), what sdl-static-headless actually
builds and its --tty-only caveat, the install paths the units expect,
how to watch sessions (systemctl list-units / journalctl), operating
knobs (machine, port, limits, banner), the security posture, and a
troubleshooting section written from the actual failures.
The guide lives next to the units as scripts/systemd/README.md; the
socket header shrinks to a pointer (one source of truth), and the main
README's Experimental bullet and notes/APPLE1.md link to it.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Deploying the telnet Apple 1 hit two gaps. First, the default build
links SDL3 dynamically and sdl-static compiles SDL with full video —
which demands X11 dev packages (XTEST et al) that a headless server
neither has nor needs. The new sdl-static-headless feature stacks
sdl3's build-from-source-unix-console on sdl-static: a static SDL
console build with no X11/Wayland at all. Only --tty runs on such a
binary (documented); it builds in a fraction of the time and links no
dynamic SDL.
Second, ewm-one.socket's header said "install both units" without
saying how much more there is: it now carries the full checklist —
the headless build command, binary/banner/unit installs,
daemon-reload, enable, and where the per-instance logs live.
Verified: the headless binary builds, serves a banner + monitor
session over a pipe, and carries no dynamic SDL reference.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Phase T3 of plans/20260719-04-apple1-telnet.md (added after T2): a
--tty-banner <path> text file prints to the session before the machine
says anything — where the operator puts the instructions a bare Woz
Monitor prompt doesn't offer. Line endings are CRLF-normalized for raw
terminals; a missing file fails loud at startup (a systemd misconfig
should be visible in the journal, not silently banner-less).
The flag is tty-session tooling, not machine description — it lives
with --tty, outside the config document, like the debug flags do.
scripts/systemd/banner.txt ships as the example (monitor and BASIC
starters, the reset chord, how to leave telnet) and the service unit
mounts it from /usr/local/share/ewm — readable under
ProtectSystem=strict.
Test: the banner precedes the machine's prompt, CRLF-normalized, and
the flag without a value falls into usage. Verified live: piped
session shows banner then prompt; a bad path exits 1 with the error.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Phase T2, closing plans/20260719-04-apple1-telnet.md.
The tty session gains a hand-rolled RFC 854 subset: a state-machine
filter that stays dormant until the first inbound IAC — nc and local
terminals never see a protocol byte — then announces WILL ECHO + WILL
SGA (character-at-a-time, remote echo), refuses every other
negotiation, swallows subnegotiations, drops IAC IAC (a literal 0xFF
is not an Apple 1 key), and maps BRK/IP — telnet's `send brk`, the
serial-terminal attention — to the RESET button: immediate, flushing
typed-ahead, like the real thing.
scripts/systemd/ carries the inetd-style units: ewm-one.socket
(ListenStream=6502, Accept=yes, MaxConnectionsPerSource) and
ewm-one@.service (StandardInput=socket, DynamicUser, ProtectSystem=
strict, MemoryMax, RuntimeMaxSec) — the sandbox is tight because the
binary needs no filesystem; configs and ROMs are embedded. README's
Experimental section gains the entry; notes/APPLE1.md records the
tty/telnet design as built; the plan is complete.
Tests: the filter unit-tested byte for byte (activation volley, the
no-reply-to-DO-ECHO loop guard, WONT/DONT refusals, subnegotiation
swallowing, BRK, IAC IAC); a session-level test where a staged reader
delivers the volley, enters BASIC, then BREAKs back to the monitor —
staged because BREAK is deliberately out-of-band. Verified live:
piping an IAC volley plus a command through `ewm one --tty` yields
prompt, WILLs, echo, and the dump in one stream.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>