NVIDIA / NVIDIA/OpenShell

feat(api)!: define lifecycle semantics for bidirectional streams

Open
#3,056 5 comments 0 reactions 1 assignee View on GitHub

@varshaprasad96 is already working on this.

Since Sep 15, 2026.

Dominant language
Rust
Stars
8.7k
Forks
1.3k
Avg merge
2d 11h
Merged PRs (30d)
253

Description

User Story

As a client implementing exec, TCP forwarding, or relay protocols, I want explicit stream lifecycle semantics, so that I can half-close input, drain output, cancel cleanly, and distinguish normal completion from transport failure.

Problem Statement

OpenShell bidirectional frame protocols define initialization and data payloads but do not consistently define explicit half-close or close frames. Cancellation, first-frame validation, cross-direction ordering, backpressure, deadlines, and retry behavior are incomplete or distributed across implementation details.

Impact / Why This Matters

SDKs must infer when closing their send direction should preserve the receive direction, and gateways/supervisors can interpret EOF differently. This creates hangs, truncated output, premature relay teardown, and language-specific behavior. Protocol ambiguity becomes harder to correct after the beta compatibility boundary.

Proposed Design

Specify lifecycle state machines for each public bidirectional RPC. Where transport EOF is insufficient or ambiguous, add explicit close/half-close frames carrying the channel and optional reason. Define:

  • required first frame and rejection behavior;
  • legal frame ordering;
  • input half-close while output continues;
  • normal completion versus cancellation and error;
  • backpressure and maximum frame behavior;
  • idle and operation deadlines; and
  • whether and how a failed stream can be retried.

Expose equivalent semantics through every SDK.

Acceptance Criteria

  • Each bidirectional RPC has a documented lifecycle/state machine.
  • TCP forward and relay protocols support clean half-close where the underlying TCP flow requires it.
  • Invalid first frames and illegal frame ordering return consistent status codes.
  • Client cancellation, server cancellation, idle timeout, and normal EOF are distinguishable.
  • Implementations do not truncate remaining output when the input direction closes normally.
  • Rust, Python, TypeScript, and Go SDK helpers expose consistent lifecycle behavior.
  • Tests cover both half-close directions, simultaneous close, cancellation, timeout, backpressure, and peer failure.
  • Gateway/supervisor version-skew expectations for new frames are documented.

Alternatives Considered

Use gRPC stream EOF as the only close signal. This is simple but cannot always express per-channel closure or preserve the opposite direction consistently. Add close semantics only in SDKs. That leaves raw clients and gateway/supervisor peers with an underspecified wire contract.

Agent Investigation

TcpForwardFrame and RelayFrame currently carry initialization and data without a common explicit close payload, while related control streams define separate relay-close messages. Capability/version-skew handling is related to #2949.

Related: #2565, #2949. Source audit: https://gist.github.com/mrunalp/e80942c1544a0225ee588796a41ab30b.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.