writeonce/docs/stories/runtime-v2/02-pty.md
shoney.arickathil 3190b609af docs(rt2): track-wide brainstorm — all five iterations ready, graph remapped
- spec 2026-09-01-runtime-v2-design.md: the one principle (PULL — a
  child is fds, the net verbs drive them; runtime-v2 adds acquisition
  verbs, never transport), the full surface (ids 97+: spawn/spawn_pty/
  wait_dl/signal/resize, signal.on delivering the sig number, term.raw/
  restore with runtime-guaranteed restore, send_fd/recv_fd/connect_unix),
  actor-owned lifecycle, mechanics notes, refusals by name
- push transport rejected with reasons recorded (mailbox-cap collision,
  new delivery machinery); death-notice verb refused (a two-line fiber
  composes wait_dl)
- five stories flip readiness: ready; fork sections rewritten as settled
- graph section 6 remapped: pull broke the 1->2->3 chain — only 1->2
  remains; 3, 4, 5 and the VTE grid startable alone today
- board section + registry follow; linkcheck 0 broken

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
(cherry picked from commit d313cdeebbe53c83b83f31f4480631568d9d0743)
2026-09-15 01:15:30 +02:00

1.9 KiB

track iteration status readiness
runtime-v2 2 pending ready

runtime-v2 2 — PTY: a child that believes it owns a terminal

Part of Story — runtime-v2: the runtime beyond sockets. After 1: a streaming child whose stdio is a pseudo-terminal instead of pipes. A shell run over pipes disables its prompt, its line editing and its job control; a multiplexer is pointless without them.

The problem. Nothing can allocate a PTY pair, place the child on the slave side as its controlling terminal, or resize it. The reference reading is .dev/reference/tmux spawn.c + compat/fdforkpty.c (~450 lines of C covering five platforms; Linux alone is far smaller).

Info — the forks, settled (brainstorm 2026-09-01; spec:

2026-09-01-runtime-v2-design.md)

  1. Separate verb: proc.spawn_pty(cmd, args, cols, rows) -> ?Child — its own builtin id (static arity table stays static), same Child record with in and out both the master fd, err nil.
  2. Resize ships HERE: proc.resize(id, cols, rows) → TIOCSWINSZ on the slot; refusal by name on a pipe child.
  3. Transport settled by iteration 1's pull decision — the master fd is driven by the existing net verbs, nothing new.
  4. Master raw by default, no knobs — until a consumer asks by name. (openpty may need -lutil — the plan verifies the link line before assuming.)

Acceptance sketch

  • A real shell spawned on a PTY prints a PROMPT (it never does over pipes) — asserted on the bytes.
  • Resize: the child (a script reading TIOCGWINSZ) observes the new size.
  • isatty inside the child answers yes on all three fds.
  • Kill/reap/stop legs identical to 1's, PTY edition; fd count flat.

Consumers

wmux 1 (every pane), the alacritty study's stage A (the headless expect-clone is exactly "spawn on a PTY, script it, assert").