Skip to content

ax ssh <task> with no command silently does nothing instead of opening an interactive shell #374

Open

Description

@sharadregoti

`ax ssh ` (no trailing `-- command`) is documented as opening an interactive shell (README, CLI help text), but it doesn't work: it runs immediately and returns to the prompt with no output and no error.

Root cause: `runSSH` in `cmd/ax/main.go` defaults to running `/bin/sh` when no command is given, but `guest.Client.Exec` (`internal/guest/client.go`) never wires up stdin. `ExecOptions` only has `Stdout`/`Stderr`. The shell gets EOF on stdin immediately and exits, same as running `echo | sh` locally.

Repro: apply a task with `spec.debug: true`, wait for it to reach `Running`, run `ax ssh `. Nothing happens.

A real interactive shell needs stdin forwarding end to end: `ExecOptions.Stdin`, the `StartProcessRequest`/streaming RPCs in the guest protocol, and ideally PTY allocation so things like `vim` or job control work. One-off commands (`ax ssh -- ls`) work fine since they don't need stdin.

Activity

  1. anzal1 commented on Oct 16, 2026

    @anzal1
    Contributor

    @mayawang thanks for the pointer in #413. I'd like to build PTY support for ax ssh and want your take before starting.

    The guest protocol in agent-substrate/env has no tty or resize today, so this is two PRs:

    1. env: a tty option on StartProcessRequest (with rows and cols) and a ResizeProcess RPC. The guest allocates the pty and puts the merged output on stdout. Additive, so old clients keep working.
    2. ax: raw mode on the local terminal, initial size, SIGWINCH forwarding, restored on exit. A bare ax ssh <task> on a terminal gets a pty, with -t/-T overrides like ssh.

    Since Ctrl-C becomes a byte in raw mode, the double Ctrl-C escape would become ssh's ~..

    Is this approach OK, and are you fine with the proto change in env? Happy to keep it compatible with #492 if ssh becomes exec.

  2. mayawang commented on Oct 16, 2026

    @mayawang
    Collaborator

    Thanks @anzal1, the two-step plan makes sense. Two things first: #492 renames ax ssh to ax exec and adds ax cp, so the AX half should build on that. And the guest protocol lives in agent-substrate/env, so it's worth opening an issue there with the tty and resize proposal before the PR.

  3. anzal1 commented on Oct 28, 2026

    @anzal1
    Contributor

    @mayawang sorry for the silence since your Oct 16 reply. An update on your two points:

    Env issue: opened agent-substrate/env#104 with the tty + resize proposal on Oct 17, and tomergee implemented it the next day in agent-substrate/env#107, which is in review now.

    Building on #492: agreed. I'll do the ax side on ax exec rather than ax ssh, so I'm holding until the #492 rename and env#107 land. Then I'll send raw mode, the initial size, resize on SIGWINCH and the ~. escape.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions