feat(cli): add JSON output to truss train workstation - #2639
Merged
Conversation
Adds `-o/--output-format json` so scripts can read the provisioned node
SSH addresses instead of scraping the rich-formatted text block.
Follows the `@json_command` pattern already used by `truss push`: all
human-facing output (push progress, `--tail` logs) moves to stderr and
stdout carries a single JSON document. Failures land on stdout as
`{"error": {...}}` with exit 1, and the REST client's stdout error print
is suppressed so it can't corrupt the stream.
Hostname construction moves into `workstation_ssh_hostnames()` so the
text and JSON paths render from one list. It now includes the remote
segment for non-default remotes, which the SSH proxy command needs to
resolve the right ~/.trussrc entry when several are configured.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Brian Broll seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account. You have signed the CLA already but the status is still pending? Let us recheck it. |
brollb
marked this pull request as ready for review
September 2, 2026 20:13
ShreyaRavi
approved these changes
Sep 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🚀 What
Adds
-o/--output-format jsontotruss train workstation, so scripts can read the provisioned node SSH addresses programmatically instead of scraping the rich-formatted text block.Text output is unchanged apart from the remote-segment fix noted below.
💻 How
Follows the
@json_commandpattern already used bytruss push(truss/cli/cli.py:748) rather than the read-only commands'cli-table|csv|jsonbranch, because this command mutates state and emits output it doesn't own (truss_train/deployment.pypush progress,--taillog streaming). The flag is spelled-o/--output-formatto match the rest of thetraingroup;json_commandkeys off theoutput_formatdestination, so the two compose.Three details worth review:
suppress_error_print.RestAPIClient._handle_errorprints 4xx messages with a bareprint()to stdout, whichconsole_to_stderr()cannot redirect. Bothupsert_training_projectandcreate_training_jobgo through that client, so JSON mode setssuppress_error_print = Trueand lets the error surface as an exception forjson_commandto render — same astruss pushdoes.JSON is printed before
--tail, with an explicit flush.truss push --watch --output jsonprints its payload after watch mode returns. That ordering doesn't work here: the addresses are the point of the command and tailing may never end. Printing first means the payload can sit in a block-buffered pipe indefinitely, henceflush=True.Hostnames now include the remote segment for non-default remotes. Construction moved into
workstation_ssh_hostnames()so text and JSON render from one list. The old inline string always omitted the remote, so a workstation launched with--remote devprinted an address thatresolve_remote()can only resolve if the user has exactly one remote or has stampeddevas their default — otherwise it errors out. The segment is still omitted for the defaultbasetenremote to keep the common case short.The payload also carries the raw push response under
job, so consumers aren't blocked on us adding fields.Note the nodes are not reachable when the JSON is emitted — the job is queued, not running. Callers still need to poll status before connecting. Happy to add a
--wait-for-runningflag in a follow-up if scripts end up reimplementing that poll.🔬 Testing
uv run pytest truss/tests/cli -q→ 591 passed.New tests in
truss/tests/cli/train/test_workstation.py:workstation_ssh_hostnames()unit tests: default remote omitted, non-default remote included, one hostname per node in rank order.is_leader,orchestratornull for single-node, rawjobpassthrough).suppress_error_printset in JSON mode.{"error": {"message": ...}}on stdout with exit 1.🤖 Generated with Claude Code