The ns command

pip install neural-studio puts an ns executable on your PATH next to the Python SDK. It has three subcommands: two that make ssh, scp, rsync and your editor's remote mode reach a running runtime, and one that delivers metrics recorded while offline. There is no ns login: the command authenticates with a full-access API key from NEURAL_STUDIO_API_KEY or the SDK's config file, resolved exactly as ns.init resolves it. Inside a runtime's terminal the session key is used instead, which is enough for ns sync but not for SSH.

ns ssh-config

ns ssh-config <session-id>             # print the block
ns ssh-config --install <session-id>   # merge it into ~/.ssh/config
ns ssh-config --install --user user <session-id>

Prints, or installs, a Host ns-<session-id> block for one runtime. The <session-id> is the runtime's session id, shown under Connect → SSH Access in the notebook's runtime bar. The block is:

Host ns-<session-id>
    HostName <session-id>
    User user
    ProxyCommand ns ssh --stdio <session-id>
    StrictHostKeyChecking accept-new
    UserKnownHostsFile ~/.ssh/known_hosts.neural-studio
  • --install writes it into ~/.ssh/config (mode 0600) between # >>> neural-studio ns-<session-id> >>> and # <<< ... <<< markers, so running it again replaces the block instead of appending a second one.
  • The login user is the one the API reports for the runtime (user today); --user overrides it. Printing the block works without an API key; the user lookup then falls back to user.
  • ssh runs the ProxyCommand from your login shell, so ns must be on that shell's PATH and the API key visible to it, not only to a virtualenv.
  • Host keys are recorded in ~/.ssh/known_hosts.neural-studio on first connect. Every runtime is a fresh machine with its own session id and its own host key; if ssh ever complains about a changed key, delete the old line from that file.

With the block installed, ssh ns-<session-id>, scp, rsync, VS Code Remote-SSH, Cursor and JetBrains Gateway all work unmodified. The full walkthrough, including key registration, is on SSH into your runtime.

ns ssh

ns ssh <session-id>                    # same as: ssh ns-<session-id>
ns ssh <session-id> -L 6006:localhost:6006

A shortcut that runs ssh ns-<session-id> with any extra arguments passed through. It relies on the block from ns ssh-config --install. The hidden form ns ssh --stdio <session-id> is the ProxyCommand bridge itself: it fetches a single-use SSH ticket from the API, opens the session gateway's relay and pipes your SSH client's bytes through the runtime's outbound tunnel. Key authentication stays end to end between your ssh and the runtime's sshd; the platform only decides which runtime you may reach.

Messages you may see:

  • ns: gateway rejected the SSH relay upgrade: the runtime is not running with a connected tunnel, or the ticket was refused. Check its status in the app and retry.
  • ns: No API key found: set NEURAL_STUDIO_API_KEY or the config file.
  • ns: the session gateway host is not configured: the API you are pointed at has no gateway; check NEURAL_STUDIO_API_URL.
  • A 404 from the API: you are not an editor or owner of the runtime's workspace, or the session id is wrong.

ns sync

ns sync                       # every run-*.db under ./.neural-studio
ns sync /tmp/ns-spill         # another directory
ns sync run-<id>.db           # one file

Replays spill files left behind by mode="offline" runs, by a crash, or by a finish that gave up on a dead network: it creates offline runs on the server, delivers their metric batches, console lines and media, performs any owed finish and compacts the file. Delivery is exactly once, so a second ns sync is a no-op. It prints one summary line, lists files still pending, and exits 0 when nothing is pending and nothing was discarded, 1 otherwise. The same thing from Python is ns.sync(path=None); the mechanics are on the SDK page.