You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
pty-rust proves that Rust, portable-pty, and libghostty can implement the current PTY wire protocol. It does not yet define the compatibility target for replacing the Node CLI and server, or expose the full embedded-client surface that a Rust compositor such as Fractal needs.
The target is behavioral compatibility with the Node PTY, not identical source code or an identical internal architecture. Language and terminal-engine differences are allowed. Each observable difference must be recorded as a decision.
Target
Make pty-rust:
A 99.9%-compatible implementation of the current Node PTY behavior.
A first-class Rust library for embedded terminal clients, similar in purpose to the Node PtyHandle.
A shared conformance implementation that the Rust CLI and embedded clients use. The CLI must not keep a separate terminal model or protocol path.
Keep the current protocol as the baseline. Add protocol features only when a measured use case cannot be expressed safely by the existing frames.
Attach identity follows current Node PTY behavior. Declared PTY root plus session ID means the current session at that address. A replacement under the same ID is the target of a new attach. Generation is optional diagnostic data, not attach eligibility. Embedded clients use a local AttemptId or epoch to reject late events from an older attempt.
Current assessment
Already present:
Current byte-framed protocol and unknown-message preservation.
Local registry and socket connection.
Attach, detach, input, resize, exit, replay, peek, and status.
A libghostty terminal model.
Screen capture and scrollback retention.
Mode and query handling in the daemon.
A PTY test kit and CLI end-to-end tests.
Missing or not yet suitable as an embedding contract:
One long-lived embedded session handle with an event stream.
Direct, typed cell-grid reads with style and width data.
Wrapped-line flags for correct text selection.
Cursor position and visibility.
Active alternate-screen state.
Mouse tracking mode.
Kitty keyboard flag stack.
Bracketed-paste mode.
Scrollback length, live base position, and viewport reads by relative offset.
Explicit attach readiness instead of a fixed delay.
Reconnect and lifecycle semantics suitable for an embedded client.
A stable owner and thread boundary for libghostty Terminal, which is not Send.
Compatibility tests that run the same fixtures against Node and Rust.
Node features such as tags, remote and fabric, gc, events, and higher-level CLI commands remain separate compatibility work. They must not be hidden inside the terminal embedding API.
Proposed crate boundaries
Use the smallest split that gives the CLI and Fractal the same implementation:
pty-protocol: wire types and framing for the current protocol.
pty-client: registry and socket connection, attach lifecycle, reconnect, and typed client events.
pty-terminal: the single-owner libghostty terminal actor and read-only terminal snapshots.
pty-testkit: process-driven test helpers built on the same terminal core.
pty: the CLI, as a consumer of these crates.
This split is a proposal. A smaller workspace is preferred if the same ownership boundaries can remain clear.
Compatibility decisions
Add a short decision record when Rust differs from Node. Each record must state:
the Node behavior;
the Rust behavior;
why they differ;
the observable effect for clients;
how the behavior is tested;
whether migration or protocol negotiation is required.
Known first decision to document: Node converts inbound DATA payloads to UTF-8 text before node-pty.write. Rust currently writes the payload bytes directly through portable-pty. The wire frame itself is already byte-safe.
schickling/dotfiles#1378 migrates Fractal's attached-session and terminal core to the shared handle.
schickling/dotfiles#1375 adds ephemeral tool panes after the shared spawn boundary exists.
Acceptance
README states the compatibility and embedding direction without claiming current parity.
A checked compatibility matrix covers CLI, daemon, protocol, metadata, terminal state, remote transport, and embedding APIs.
Attach parity proves root-plus-session-ID current-session behavior, replacement under the same ID, and stale-event rejection by local attempt identity.
No attach implementation requires generation discovery or generation-fenced admission.
Node and Rust run the same attach, input, resize, replay, and exit fixtures.
The embedded handle exposes terminal snapshots and mode state needed by Fractal without parsing serialized ANSI output.
One actor owns the non-Send libghostty terminal. Consumers receive typed events and snapshots.
The Rust CLI uses the same client and terminal crates as embedded consumers.
Every intentional observable difference has a decision record and a conformance test.
A real byte-round-trip fixture decides whether binary input is a supported cross-implementation feature or a documented Rust-only difference.
No new protocol mode is added without a failing use case and a Node and Rust rollout plan.
Why
pty-rust proves that Rust, portable-pty, and libghostty can implement the current PTY wire protocol. It does not yet define the compatibility target for replacing the Node CLI and server, or expose the full embedded-client surface that a Rust compositor such as Fractal needs.
The target is behavioral compatibility with the Node PTY, not identical source code or an identical internal architecture. Language and terminal-engine differences are allowed. Each observable difference must be recorded as a decision.
Target
Make pty-rust:
Keep the current protocol as the baseline. Add protocol features only when a measured use case cannot be expressed safely by the existing frames.
Attach identity follows current Node PTY behavior. Declared PTY root plus session ID means the current session at that address. A replacement under the same ID is the target of a new attach. Generation is optional diagnostic data, not attach eligibility. Embedded clients use a local AttemptId or epoch to reject late events from an older attempt.
Current assessment
Already present:
Missing or not yet suitable as an embedding contract:
Node features such as tags, remote and fabric, gc, events, and higher-level CLI commands remain separate compatibility work. They must not be hidden inside the terminal embedding API.
Proposed crate boundaries
Use the smallest split that gives the CLI and Fractal the same implementation:
This split is a proposal. A smaller workspace is preferred if the same ownership boundaries can remain clear.
Compatibility decisions
Add a short decision record when Rust differs from Node. Each record must state:
Known first decision to document: Node converts inbound DATA payloads to UTF-8 text before node-pty.write. Rust currently writes the payload bytes directly through portable-pty. The wire frame itself is already byte-safe.
Child work
Acceptance