TRIAGE · trg · Rust + Ratatui
Triage
trg is a terminal client for Triage, a routing service that turns plain requests (“file a receipt review task”, “what's the status of that build?”) into actions on other systems. The service decides and acts; trg records exactly what you asked, what was accepted and what happened, including when a reply is lost on the network.
trg # the rich terminal; dry-run by default
trg send 'File a receipt review task' --json
trg send 'An explicitly authorised request' --live
trg turn approve PREVIEW_TURN_ID # a new live action from a frozen preview
trg turn cancel SERVER_TURN_ID # a fence, with proof, not a rollback
trg resume SESSION_ID
The journal
The dangerous moment in any client is the one after it sends a request and before it hears back. trg closes it from both sides: before posting anything, it records a caller UUID, the session and the exact request in a private local journal, and the router uses that UUID to recognise a repeat. A reply that never arrives leaves the turn unknown and held, never quietly retried and never resubmitted with a fresh ID.
turn retry rereads the saved request; resume reconciles by reading, never by posting again.The journal is bound to the router's complete base URL. Pointing the same state directory at a different server fails before a credential is read or a request is sent, so requests can never drift into another endpoint's history.
Outcomes and exit codes
A receipt says what happened, and a finished turn can still mean the action was blocked, rejected or left indeterminate. trg keeps those apart, and its exit codes do too, so a script can tell "the command worked" from "the action worked".
| 0 | the command, admission or read succeeded (not necessarily the action) |
|---|---|
| 1 | an operational failure, or a rejected or unsent admission |
| 2 | invalid input or configuration |
| 3 | acceptance unknown, or a watch deadline reached |
Dry run is the default. Routing and its mode freeze when a turn is submitted, so changing your mind afterwards changes new work, not old. --live, or a persistent live mode, routes for real; the server still owns authorisation for every action.
Approval is a new action. /approve turns a dry-run preview into one live turn pinned to the preview's current proposal revision, without resending your text. Cancellation is a fence. It succeeds only when the router proves no action command started; it never promises a rollback.
The terminal
The composer is always available: type the next request while earlier turns are still pending, each tracked on its own. An inspector shows a selected turn's real events and receipt, and the conversation can carry on: the router can ask which project you meant, hold the task while you answer, and refine an unconsumed preview with “make it P1”, which comes back as a separate dry proposal.
--plain gives a line REPL for screen readers, and every operation is also a subcommand with versioned JSON for scripts.
With native server-sent events, the terminal keeps one observer for the active session rather than polling every turn, and refreshes receipts only when events say something changed. Events never submit, approve or cancel anything. Watch commands stream JSONL with consumed cursors, so a script resumes from the last complete line.
Replies from agents that a request reached can be observed with trg turn replies; they are shown as the agent's assertion, never as proof of execution and never routed as a new command.