Saphan StudioDocs
Getting started

Placing a leg: from an order to a running agent

The operator's walk for starting one leg of work with a single command: print the order template, fill it, commit it, and place it on any free seat.

A leg is one agent's run on one order: one stream, one branch, one seat. You write the order (see Orders), and saphan dispatch place turns that order into a running leg in one act. The order is the only input. The command reads the stream name, repository, base, branch, quote, wall-clock limit and skills from the order itself, chooses a free seat, and starts the run.

Every command below is anchored on your workspace's bridge/ directory, which holds the templates and the role instructions the leg is given.

The walk

1. Print the order template and fill it

saphan dispatch template executor

Use review or tester in place of executor for those roles. The command prints bridge/governance/templates/ORDER_<ROLE>.md from your workspace, read at the moment you run it. It is not a copy built into the program, so your workspace's own edits show up. If the workspace has no template for that role, the command refuses and names the path it read.

Save the output as your order file, fill in every <…> placeholder, and commit the order in its repository. An order that is not committed is refused before any seat is touched.

Then have a person approve it: saphan order sign <path-to-order>. Every order a run receives needs a person's passkey approval of its exact text, given in the browser or, with --cli, with a security key at the terminal. An order nobody approved is refused before any seat is touched, and the refusal names the command to run. For a review, the approval is of the review order the command derives from yours; the refusal names it.

2. Place the leg

saphan dispatch place --order <path-to-order> --role executor

In one act, in this order, the command:

  1. Checks the order and gathers what the leg needs: the role's two instruction pages (the common one and the one for its role) and every skill the order lists under ## SKILLS. All of them must exist, be committed, and land at distinct places.
  2. Checks that the quote and the cap in the order agree, and that the stream has no live run.
  3. Chooses a seat: the first one that fleet dispatchable --role executor admits, on any backend that has a model.
  4. Registers the stream and writes the channel order. For a local seat, it first cuts the git worktree.
  5. Delivers the base to a far seat.
  6. Starts the run detached.
  7. Waits until the run has answered its start-up check, then returns.

It exits 0 when the leg started. Otherwise it exits non-zero and prints the refusal exactly as the engine gave it. Every seat it tried is printed as one line, and the final answer names every seat tried. A run that was admitted is never placed a second time.

3. Place a review

saphan dispatch place --order <path-to-review-order> --role review --reviewed <stream>

This places a courier review of the stream <stream>:

  • The review stream is named <stream>-review, or the next <stream>-review-rN when that name already has a run on this host's record or a local review/<slug> branch exists.
  • The review branch is review/<stream>, cut at <stream>'s tip as this host reads it. If this host has no reading of that tip, the command refuses and names the reading.
  • The reviewer gets the review instructions, and the order's ## Review output manifest is required.
  • --reviewed must name the stream being reviewed, never a review itself. A name like <x>-review or <x>-review-rN is refused, naming <x>.

Without --wait, the command returns when the review starts. It has read no verdict, and a successful exit says nothing about one. Add --wait, for example --wait 30m, and the command holds until the review run closes, then reads the returned _REVIEW_STATUS.md. The review counts as failed (exit non-zero) if the closed run's status has no - verdict: line, or if that line is not one of the allowed verdicts, or if the file is byte-for-byte the one that stood there before the run began. The duration bounds the seat wait and the review hold separately, so the total can be up to twice what you gave.

A review on a far seat has its status filed on your host only by saphan return <courier>. Until you run that, the command says the status was not read. Run it, then read the verdict.

4. Place a tester

saphan dispatch place --order <path-to-tester-order> --role executor

A tester is not a separate --role. An order whose wagon is W<n>-test, or whose ROLE-LOCK names TESTER, is placed with the tester's instruction page and the tester's permission class (the workspace.grant_class.tester setting, or else the bridge's worktree-tester-grant). Use saphan dispatch template tester to start such an order.

5. Waiting and choosing a machine

saphan dispatch place --order <path-to-order> --role executor --wait 30m --host <machine>
  • --wait <duration> turns "no free seat" into a wait. When no admissible seat is left and every refusal met is one the engine says can be retried, it walks the seats again at the interval it prints, until a seat admits or the duration is spent. One line is printed per walk. A refusal that cannot be retried stops the wait at once, because waiting never fixes a defect in the order. The default, 0, does not wait.
  • --host <machine> limits the search to the seats of that one machine, on any backend.
  • A continuation is placed on the host of its newest far run. A stream that already has a far run has its far checkout on that machine, so the leg goes back there. If you name a different host with --host, the engine honours it and prints it as an override.
  • --max-seats <n> stops after trying n seats. The default, 0, tries every admissible seat.

When it refuses

A refusal is printed verbatim, with the next act to take. Read it and do what it says.

  • A refusal that says to try another seat is handled for you: the command moves to the next admissible seat. One that says to wait and ask again is performed once by the command, which then asks the same seat one more time.
  • A terminal refusal is never retried. The command stops. So does a refusal the engine has no entry for. Fix the cause it names, then place again. Do not loop on it.
  • A refusal before a seat is taken costs nothing and touched no seat. These are the ones that need the order or the workspace fixed:
    • the order file is not committed in its repository (the refusal names the path);
    • no person has approved the order's exact text (the refusal names the approval command);
    • a craft page or skill the order needs is missing, uncommitted, or lands on the same destination as another;
    • the order cites a provision-directory path that its provision set does not carry;
    • the quote and the cap disagree (the refusal names both);
    • the stream already has a live run (the refusal names that run);
    • a path listed under ## REVIEW INPUTS is absent or uncommitted;
    • for a review, --reviewed names a review itself, or the reviewed stream's tip is unknown to this host.
  • A seat whose agent program is older than the model requires is skipped without being tried.

Once the command exits 0, the leg is running. Follow it with the commands in Watching the fleet and collect its work as described in Returns and verification.

On this page