1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
//! Per-step on-disk landings (ARCH §2.3 / §2.10).
//!
//! Step records live at `<conv-repo>/steps/<conv-id>/<NNN>/`,
//! outside every worktree (§2.2). The harness writes them as
//! diagnostic / audit artifacts and does not read them back at
//! runtime (§2.3 Diagnostic-only contract).
//!
//! Step 1's dispatch commit lays `goal.md` and `soul.md` at the
//! worktree root and commits — that single commit's tree is the
//! model-read state for step 1 (§2.10). Step ≥2 takes no pre-call
//! commit; the branch tip already represents what the model reads.
//! The `commit` field on each step's `meta.json` records that tip
//! sha so replay can re-run context assembly against the right
//! tree (§2.10) without consulting `request.json`.
//!
//! `request.json`, `response.json`, and `meta.json` land outside
//! the worktree and are not git-tracked (§2.3 — "Step records are
//! not committed to git").
pub use ;
use crateDeps;
use crateError;
use crate;
use Value;
use Path;
/// Worktree-relative path where the conversation's goal is committed
/// at dispatch time (ARCH §2.8). Lives at the worktree root so the
/// manifest's `pinned: [goal.md]` rule (§5.2) sees it.
pub const GOAL_FILE: &str = "goal.md";
/// Worktree-relative path where the role's system prompt is committed
/// at dispatch time (ARCH §4.3 / §2.8). Lives at the worktree root for
/// the same reason `goal.md` does.
pub const SOUL_FILE: &str = "soul.md";
/// `git worktree add -b agents/<id> <worktree_path> <fork-point>`, run
/// against the workspace's bare `repo.git` (§2.2): fork the fresh root
/// agent off the ref the start named — a config lineage's head, or any
/// ref at all (§2.3 *Any ref is a legal fork point*, §7.2
/// fork-from-history). The fork is the freeze (§2.2), and what it
/// freezes is the *governing config commit* of that ref, which
/// `resolved` already carries — so this call is the same operation with
/// a different argument, never a second kind of start. Root id
/// uniqueness per workspace is structural: the `-b` creation fails if
/// the ref already exists.
pub
/// Compose the system slot: the branch's goal, the agent's identity when
/// it has a name, then the role's soul. The system slot *is* the
/// pinned-head wire home for `goal.md`, `name` and `soul.md` (§2.3 "Goal
/// and soul are pinned files", §5.2 structural wire homes): assembly
/// composes all three through here, never as body text.
///
/// The goal leads, so it stays pinned at the head of every model call on
/// the branch (§2.8). The identity line is **derived here from the name
/// fact, never stored a second time** (§2.3 — the `name` file is the one
/// home; `docs/PRINCIPLES.md` single source of truth), and it states the
/// name and nothing else: no instruction rides an identity (§2.8 — the
/// name is who the agent is, not what it is to do). An unnamed agent
/// states nothing, and its slot is byte-identical to what a nameless
/// harness composed — the general path with empty inputs, not a second
/// shape.
pub
/// Step 1: write `goal.md` + `soul.md` to the worktree root, plus any
/// caller-supplied pinned documents at their validated destinations
/// ([`crate::prompt::pinned_doc`], §2.5). Step ≥2 has no dispatch
/// artifact (the branch tip already reflects the model-read state per
/// §2.10).
pub
/// Step 1's dispatch commit (§2.3 step 2): remove the harness-facing
/// control files from the agent's tree (§2.2 — control is read from the
/// governing config commit; the worktree holds only context) and settle
/// the agent's `name` (§2.3), `git add goal.md soul.md`, then commit on
/// the agent branch. The removal is
/// total, not conditional: `--ignore-unmatch` makes it a no-op when the
/// fork point was not a config commit (a child forked off a parent's
/// tip, whose tree already lost them). This is the only commit the
/// harness emits for a step; §2.10 keeps step ≥2 commit-free, so the
/// branch tip after a dispatch commit *is* step 1's read state.
pub
/// Stage the trim that makes the forked tree exactly this agent's
/// context (§2.2, §5.1) — one act with four parts, each a no-op when
/// the fork point carried nothing to change, so the primitive is total
/// whatever ref it forked off:
///
/// 1. **Control leaves.** `manifest.yaml`, `workflow.yaml`,
/// `providers.yaml`, `version`, `souls/` — control is read from the
/// governing config commit, never from a worktree file (§2.2).
/// 2. **Descriptors are derived to the grant.** `descriptions/**` is
/// snapshotted whole into the governing config commit (one config
/// commit serves every role), and the agent's tree is the view of it
/// this role's `tools:` grants — checked out from that commit, not
/// inherited from whatever the fork point carried, so a child's
/// descriptors are never capped by its dispatcher's grant.
/// [`descriptors::derive`] does it, and declines a grant the commit
/// does not describe; see that module for the failures it closes.
/// 3. **The unsettled tool step leaves.** A tool-call dispatch forks
/// *during* the parent's tool step (§2.5), so the inherited transcript
/// can end in a `tool_use` block no `tool_result` entry answers — a
/// tail that settles on the parent's branch and never on the child's,
/// and that every provider refuses (§2.5 pairing).
/// [`unsettled::prune_unsettled`] removes exactly it; see that module
/// for the reproduced 400 it closes.
/// 4. **The name is settled.** `name` (ARCH §2.3, §2.11) is this agent's
/// display fact, and a fork inherits its fork point's — so the commit
/// overwrites it with the agent's own, or with nothing when the agent
/// is unnamed. Always a rewrite, never a deletion, for the reasons
/// [`crate::workspace::agent_name`] gives.
///
/// The parts are staged in this order because the later ones read the
/// worktree: control files are neither descriptors nor transcript
/// entries nor the name, so none sees another's writes.
pub
/// Resolve the branch tip's sha at step-start. Recorded in
/// `meta.json` so replay can re-run context assembly against the
/// right tree without reading `request.json` (§2.10 Diagnostic-only
/// contract).
pub
/// Land `request.json` under `<conv-repo>/steps/<conv-id>/<NNN>/`.
/// Outside every worktree (§2.2) so context assembly cannot pick it
/// up; not git-tracked (§2.3).
pub
/// Land `meta.json` under the conv-repo step dir. The `commit` field
/// is the load-bearing piece (§2.10 — replay reproduces the wire
/// input by re-running context assembly against this sha).
pub