Expand description
The frozen v1 wire protocol between a local NoMoreIDE daemon and the hosted remote-control relay.
Nothing here talks to a socket, a service or an agent. It is the shape of what may be said and the rules for refusing everything else.
Why this is its own package. Two independently deployed programs speak
this protocol — the daemon on a developer’s machine and the platform’s API
container, which live in different repositories and different Cargo
workspaces. Writing it twice would make it two implementations of one
meaning, which is the mistake the desktop app already made and is still
paying 150 duplicated commands for. So it is one implementation, in a
package light enough for both: serde, serde_json, chrono, and nothing
else. The daemon reaches it through nomoreide_core::remote::protocol.
The daemon always dials out over TLS. Nothing in this protocol opens a port, asks for a port forward, or accepts an inbound connection — a machine running NoMoreIDE is not reachable from the internet because of this feature, and that is the property the whole design is arranged around.
Where to look:
envelope— the invariant frame, and the order a frame is checked in.device_bound— every command the platform may send. This union is the remote attack surface.platform_bound— every event a daemon may send.snapshotandagent_event— the sanitized shapes those carry.limits— every number either side is allowed to assume.errors— the refusal codes, and which of them may ever be retried.version— negotiation, capabilities, and what a phone does against a machine that has not been updated.idempotency— why a mutation is never automatically re-sent.fixtures— one sample of every frame, and the golden files an independent implementation checks itself against.
Three properties hold across all of it, and each has a test that fails if it stops holding:
- Unknown is refused, not ignored. A
typeoutside the union iserrors::ErrorCode::UnknownCommandin either direction, whatever its payload looks like. - No frame can carry what the allowlist excludes. There is no variant for a shell command, a path, an environment, a terminal, a database query, a git mutation or a process id — so no payload can smuggle one.
- Ambiguity never retries. A mutation whose outcome is unknown is a question for a human, not a frame to send again.
The contract in prose, including the threat model, is
docs/remote-protocol-v1.md in the repository.
Re-exports§
pub use device_bound::DeviceBound;pub use envelope::Envelope;pub use errors::ErrorCode;pub use errors::ProtocolError;pub use platform_bound::PlatformBound;pub use terminal_bytes::TerminalBytes;pub use version::Capability;pub use version::CapabilitySet;pub use version::SessionMode;pub use version::PROTOCOL_VERSION;
Modules§
- agent_
event - What one agent turn emits, in order.
- device_
bound - Everything the platform may send to a daemon — the frozen v1 command union.
- envelope
- The frame every relay message travels in, and the order it is checked in.
- errors
- The frozen error codes, and the one thing a caller is allowed to conclude from each: whether retrying is safe.
- fixtures
- One sample of every frame the protocol defines, and the golden files generated from them.
- idempotency
- What happens when the same request id arrives twice.
- limits
- The frozen limits. Every number a v1 peer is allowed to assume about the other side lives here, and nowhere else.
- linear
- Linear operations shared by local and remote clients. Credentials never enter this protocol.
- platform_
bound - Everything a daemon may send to the platform — the frozen v1 event union.
- snapshot
- The sanitized shapes a daemon is allowed to describe itself with.
- terminal_
bytes - Raw PTY bytes on a JSON wire.
- version
- Version negotiation, capabilities, and what a phone does when the machine at the other end is out of date.