Repository navigation
Stream exec stdin without a TTY #3802
Description
Activity
What's the use case that was encountered that requires this?
The use case is a script controlling a process inside a sandbox: make a request, read its response, change credentials or policy on the host, then make another request without restarting the process.
With the proposed --stream-stdin flag, we'd launch the script using:
openshell sandbox exec --name test-sandbox --stream-stdin --no-tty -- python3 -u /sandbox/worker.pyA controller would use that command through subprocess pipes:
import subprocess child = subprocess.Popen( [ "openshell", "sandbox", "exec", "--name", "test-sandbox", "--stream-stdin", "--no-tty", "--", "python3", "-u", "/sandbox/worker.py", ], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=None, # Diagnostics go to the controller's stderr. ) child.stdin.write(b'{"op":"call"}\n') child.stdin.flush() first = child.stdout.readline() # Read response while stdin stays open. # Rotate credentials or update policy on the host. child.stdin.write(b'{"op":"call"}\n') child.stdin.flush() second = child.stdout.readline() # Response from the same process.Currently, the CLI waits for stdin EOF before starting the remote command, so the first response cannot arrive. We need non-TTY execution to keep requests and responses unchanged and keep stdout separate from stderr.
Without --stream-stdin, that sequence is:
- Python writes {"op":"call"}\n and keeps stdin open.
- OpenShell buffers the input and waits for EOF before starting the worker.
- Python calls stdout.readline() and waits for the worker’s response.
- Both wait indefinitely: OpenShell needs EOF, while Python needs a response before sending the next request.
Tried it on a new sandbox. On CLI
0.1.3-dev.66+g36819f476, sandbox exec --no-tty starts streaming when piped stdin stays open past the 200 ms grace period. That lets a client send requests and get replies from the same remote process without closing stdin.I've narrowed #3803 to report gRPC errors that arrive after the remote command exits and add a warning when streaming exceeds the 4 MiB limit, since the command may already have processed some input.
User Story
As a client running a persistent command in an OpenShell sandbox, I want to send a request and read its response while keeping stdin open, so that I can exchange multiple requests with the same process without allocating a terminal.
Problem Statement
openshell sandbox execreads piped stdin to EOF before starting the remote command. A client that writes one request and waits for a response cannot progress: OpenShell waits for EOF, while the client waits for a process that has not started.Impact / Why This Matters
Finite pipelines can close stdin before reading results. Persistent request/response tools cannot do that without ending their input stream. Using a TTY can change byte handling and combines output that a client needs to read separately. Clients otherwise need a separate SSH or SDK integration for this workflow.
Proposed Design
Add an explicit
openshell sandbox exec --name <sandbox> --stream-stdin -- <command>mode. Start the command before stdin reaches EOF and forward input as it arrives. Run without a TTY, keep stdout and stderr separate, and preserve the command's exit status after receiving the final stream result. Reject--ttywith this mode; allow--no-tty.Closing stdin ends only the command's input. Continue reading its remaining output until completion. Cancellation stops the execution and releases its input resources. Report transport or input-delivery failure even if the process previously reported exit code zero. Do not automatically retry an interrupted execution because the command may already have performed work.
Retain the existing 4 MiB total stdin limit per command. Exceeding it cancels the operation and reports that the command may already have processed earlier input. Cancellation cannot undo that work. The total limit bounds this CLI path even when the command stops reading stdin. Without the new flag, continue buffering finite input and rejecting oversized input before launch.
Acceptance Criteria
--tty.Alternatives Considered
Make every pipe stream automatically. An explicit mode makes the changed execution timing visible and keeps existing finite-input behavior intact. Use a TTY. That changes terminal semantics and does not meet the separate-output requirement. Use an SDK directly. That is suitable for applications already using an SDK, but leaves command-line integrations without this workflow.
Agent Investigation
No response
Checklist