|
| 1 | +# Supervise a live REPL phase |
| 2 | + |
| 3 | +Read this when a workflow phase runs inside a retained REPL and its coordinator |
| 4 | +needs progress and completion. Keep one wait open instead of repeatedly reading |
| 5 | +result-file existence, timestamps or log tails. |
| 6 | + |
| 7 | +## Applies to |
| 8 | + |
| 9 | +Coordinators observing an existing live REPL. These commands run outside its |
| 10 | +Sidekick conversation; they submit no work and call no agent. Keep the owning |
| 11 | +parent alive and retain the original child, role conversations and counters. |
| 12 | + |
| 13 | +## Instructions |
| 14 | + |
| 15 | +1. Keep the original ACP invocation pending when it already waits for the work. |
| 16 | + Its acknowledgement supplies the exact message reference needed to reconnect. |
| 17 | +2. If observation must reconnect, use that acknowledged message's existing |
| 18 | + `--follow` command. Preserve its execution, conversation and message identity; |
| 19 | + do not search for whichever message is latest. |
| 20 | +3. Receive the stream's updates while that single command waits. After its |
| 21 | + validated joined ending, use the supervisor below to read the associated |
| 22 | + entry's Journal once and inspect the original canonical phase or Ticket result. |
| 23 | + Retain the launch association between that message, entry and reserved result |
| 24 | + path; a matching entry number alone does not establish that association. |
| 25 | +4. Preserve incomplete or uncertain outcomes. A disconnected owner, missing |
| 26 | + receipt or invalid result calls for reconciliation of the original work, |
| 27 | + never an automatic resend or a new attempt. |
| 28 | + |
| 29 | +An exchange that submits and waits for an entry covers that entry's completion |
| 30 | +and cleanup. An independently running entry can remain active after an unrelated |
| 31 | +exchange ends. Entry reads are snapshots; `entry ... --follow` is unsupported. |
| 32 | + |
| 33 | +## Example |
| 34 | + |
| 35 | +Replace the attachment path and all three reference fields with the original |
| 36 | +acknowledged values. The example identities are illustrative, not live sessions: |
| 37 | + |
| 38 | +```bash |
| 39 | +attachment=/absolute/private/attachment.json |
| 40 | +reference='{"execution":"saved-execution","conversation":"saved-conversation","id":"saved-message"}' |
| 41 | +xmd sidekick read --attach "$attachment" message "$reference" --follow |
| 42 | +``` |
| 43 | + |
| 44 | +The command emits JSON snapshots as the exchange changes and returns its joined |
| 45 | +ending. It does not issue status polls or prompt the agent. Once it finishes, |
| 46 | +inspect the entry recorded for that submission, replacing `14` with its actual |
| 47 | +number: |
| 48 | + |
| 49 | +```bash |
| 50 | +xmd sidekick read --attach "$attachment" entry 14 journal |
| 51 | +``` |
| 52 | + |
| 53 | +A completed exchange can contain a failed or cancelled entry. A completed entry |
| 54 | +can return a Ticket on hold. Neither process exit nor exchange completion |
| 55 | +replaces the workflow's own verdict or delivery checks. |
| 56 | + |
| 57 | +### Format a received snapshot with Query |
| 58 | + |
| 59 | +Use built-in `<Query>` to select progress from a snapshot already received. This |
| 60 | +complete document accepts one snapshot through the aggregate `--props` JSON |
| 61 | +argument and renders a compact summary without copying provisional reply text: |
| 62 | + |
| 63 | +```xmd |
| 64 | +--- |
| 65 | +props: |
| 66 | + type: object |
| 67 | + properties: |
| 68 | + snapshot: {type: object} |
| 69 | + required: [snapshot] |
| 70 | + additionalProperties: false |
| 71 | +--- |
| 72 | +
|
| 73 | +<Query value={props.snapshot} |
| 74 | + yq='{"phase": (.activity.phase // "waiting"), "response": .activity.response, "replies": (.outputs | length), "ending": .ending}' |
| 75 | + as="progress" /> |
| 76 | +<Output><Json value={progress} /></Output> |
| 77 | +``` |
| 78 | + |
| 79 | +Query selects from the supplied value; it does not subscribe, read another |
| 80 | +snapshot or wait for completion. For live formatted progress, keep one passive |
| 81 | +reader feeding received snapshots into the rendering document. Emit a summary |
| 82 | +when it changes and retain the exact terminal receipt separately. This avoids |
| 83 | +starting another XMD process for every token update. The standalone Query |
| 84 | +example above formats one value; it is not itself a streaming command. |
| 85 | + |
| 86 | +### Run the supervisor example |
| 87 | + |
| 88 | +[supervise.md](supervise.md) composes the existing follow command with |
| 89 | +[progress.md](progress.md) and its [persistent reader](progress-reader.node.ts). |
| 90 | +Query selects the progress fields. The reader feeds snapshots to that document, |
| 91 | +prints a changed summary on stderr and forwards the original terminal receipt |
| 92 | +once on stdout. After validating that receipt, the supervisor copies the original |
| 93 | +attachment once into an invocation-private directory with a mode-0600 file. It |
| 94 | +checks that copy's execution and conversation against the acknowledged message, |
| 95 | +then uses the unchanged copy for the one Journal connection. The live handshake |
| 96 | +validates the whole descriptor; copied bytes alone prove no live owner. Replacing |
| 97 | +the original filename after copying cannot retarget that read. The directory is |
| 98 | +removed when the supervisor ends, including failure or cancellation. |
| 99 | + |
| 100 | +The current Journal response is `{value,next,prev,last}`. The supervisor selects |
| 101 | +`{"entry": .entry, "status": .status, "failure": .failure}` with `--yq`, validates those |
| 102 | +facts under `value`, and requires null navigation so a partial failure diagnostic |
| 103 | +cannot stand in for a complete result. The Journal body supplies no execution or |
| 104 | +conversation identity; that association comes from the validated descriptor and |
| 105 | +its successful handshake on the same connection. It owns no agent or REPL. |
| 106 | + |
| 107 | +```text |
| 108 | +Exact message follow -> one persistent Query renderer -> compact live stderr |
| 109 | + -> validated joined receipt |
| 110 | + -> private descriptor copy + live authenticated Journal read |
| 111 | + -> completed entry permits one canonical-result read -> JSON |
| 112 | +``` |
| 113 | + |
| 114 | +Save this input under a new private coordination filename. Replace paths and |
| 115 | +identities with the original launch values; the examples are illustrative: |
| 116 | + |
| 117 | +```json |
| 118 | +{ |
| 119 | + "step": { |
| 120 | + "xmd": ["deno", "run", "--quiet", "--allow-all", "/absolute/workflow/packages/cli/src/deno.ts"], |
| 121 | + "progress": [ |
| 122 | + "deno", "run", "--quiet", "--allow-all", |
| 123 | + "/absolute/workflow/examples/adversarial-implementation/progress-reader.node.ts", |
| 124 | + "/absolute/workflow/examples/adversarial-implementation/progress.md" |
| 125 | + ], |
| 126 | + "attachment": "/absolute/private/attachment.json", |
| 127 | + "message": {"execution": "saved-execution", "conversation": "saved-conversation", "id": "saved-message"}, |
| 128 | + "entry": 14, |
| 129 | + "resultFile": "/absolute/work/attempt/result.json", |
| 130 | + "resultSchema": {"type": "object"} |
| 131 | + } |
| 132 | +} |
| 133 | +``` |
| 134 | + |
| 135 | +Use the selected CLI command in `xmd` and the existing runtime launcher in |
| 136 | +`progress`. The reader also runs with Node/tsx or Bun; it uses their Node stream |
| 137 | +interfaces. Pass the canonical result's existing schema when available. The |
| 138 | +default object schema establishes JSON readability, not workflow acceptance. |
| 139 | +Then keep this invocation pending until it returns: |
| 140 | + |
| 141 | +```bash |
| 142 | +xmd run /absolute/workflow/examples/adversarial-implementation/supervise.md \ |
| 143 | + --props "$(cat -- /absolute/private/supervision-input.json)" --raw |
| 144 | +``` |
| 145 | + |
| 146 | +The root `step` object uses aggregate `--props`, not `--props-step`. The result |
| 147 | +keeps `status` for the entry and `exchangeOutcome` for its exchange. A readable |
| 148 | +canonical artifact appears unchanged under `result`, with `resultStatus=readable`. |
| 149 | +Without `resultFile`, it reports `not-requested`. A missing or invalid requested |
| 150 | +result reports `unavailable`, preserving `entryStatus` separately. |
| 151 | + |
| 152 | +Copy, tuple-validation, read or connection failure leaves entry evidence |
| 153 | +unavailable and skips the canonical-result read. A previously validated joined |
| 154 | +receipt still reports `joinedExchange=true`; it does not establish entry |
| 155 | +completion. A mismatched tuple is rejected before Journal, while owner loss or |
| 156 | +conversation change fails the live handshake. An oversized selected diagnostic |
| 157 | +may refuse under the Journal bound and remains unavailable evidence. The |
| 158 | +supervisor does not follow pages, poll, resend work or convert a canonical hold |
| 159 | +into a passing verdict. |
| 160 | + |
| 161 | +An enclosing `<Let as="receipt">` can capture a foreground command's stdout |
| 162 | +while stderr forwards live progress. A bound `exec as="receipt"` captures both |
| 163 | +channels and displays neither. Keep the final structured result on stdout and |
| 164 | +compact progress on stderr when composing such a supervisor. A missing or |
| 165 | +invalid terminal receipt remains incomplete evidence even if the process exits. |
| 166 | + |
| 167 | +## Common mistake |
| 168 | + |
| 169 | +Resending an assignment because its observer disconnected can duplicate effects. |
| 170 | +Detaching a passive follow releases observation and leaves the producer running; |
| 171 | +explicit ACP cancellation is a different operation. Reconnect to the original |
| 172 | +acknowledged exchange and reconcile its result without changing session identity, |
| 173 | +consumed correction limits or reserved attempts. |
| 174 | + |
| 175 | +## Read next |
| 176 | + |
| 177 | +Read [Run a separate phase or continue a saved ticket](README.md#run-a-separate-phase-or-continue-a-saved-ticket) |
| 178 | +for `<Phase.Run>` and `<Ticket.Continue>`. The language specification defines |
| 179 | +[Query](../../specs/executable-mdx-spec.md#622-selecting-part-of-a-value-query) |
| 180 | +and [foreground command channels](../../specs/executable-mdx-spec.md#36-foreground-execution-capture-and-retention). |
0 commit comments