harness/step.shOpens one leg: delivers the stage, writes the first message, and
launches the analyst continuing the last close's conversation (a fork of
its session; fresh only for the run's first leg or with
--fresh).
step.sh LEG [--prepare] [--fresh] [--from-cut LABEL] [--force-order] [--reopen] [--api-ok].
--fresh opens a fresh session and --reopen a
leg the analyst already closed, each logged as a departure. It checks
the leg id and the arm; refuses an API key or a gateway route in the
shell; renders the settings; at a stage's first leg copies
DROPS/NN/ into the analyst's folder, refusing if the
previous stage is unfinished unless forced; holds a check leg until the
dispatch has left DONE; clears .pause; writes
.stage and .leg; writes the first message (the
reading order, and lines for a failed last close, an interview reply,
the readers' files); records the session; calls launch.sh.
With --prepare it stops before the launch: the leg handler
(legs.py) then runs the turn headless. At stage E2a it
copies every interview listed in CONTROL/interviews.tsv
into the analyst's handling/interviews/.
The handler, once per leg.
Since v40 (2026-10-02) every ordinary leg forks the last committed
close's session, as the OpenAI copy does; --fresh opens a
fresh session and is logged in RUN.json as a departure. With
--from-cut the leg opens as a fork of a named cut's
checkpoint, and only from the last close: once a later leg has closed,
the live folder is no longer the cut's, and that state is talked to
through interview.sh, in a copy of its own.
step.sh also writes .stagefile, the one stage
file DROPS/ORDER.tsv names, which validate.py
and the compaction hook read.
Checked against: harness/step.sh, harness/lib.sh, harness/protocol_guard.py, harness/READ-ME-FIRST.md.