@ctrl-spc/cs 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents.js +70 -5
- package/dist/autostart.js +15 -1
- package/dist/browser.js +386 -0
- package/dist/codebases.js +15 -0
- package/dist/codex-home.js +501 -0
- package/dist/companion.js +9 -12
- package/dist/config.js +23 -0
- package/dist/daemon.js +33 -3
- package/dist/env.js +42 -0
- package/dist/failure-reason.js +98 -0
- package/dist/index.js +1 -1
- package/dist/mcp.js +7627 -298
- package/dist/orchestrator.js +6011 -0
- package/dist/panel3/answer.js +166 -0
- package/dist/panel3/checkout.js +29 -0
- package/dist/panel3/cli.js +83 -0
- package/dist/panel3/client.js +181 -0
- package/dist/panel3/coordinator.js +18 -0
- package/dist/panel3/presence.js +162 -0
- package/dist/panel3/prompt.js +677 -0
- package/dist/panel3/run.js +1988 -0
- package/dist/panel3/say.js +262 -0
- package/dist/panel3/secrets.js +98 -0
- package/dist/panel3/show.js +996 -0
- package/dist/panel3/spawn.js +503 -0
- package/dist/panel3/tools.js +1601 -0
- package/dist/presence.js +178 -6
- package/dist/win-shell.js +162 -0
- package/dist/work-context.js +1484 -0
- package/package.json +3 -2
|
@@ -0,0 +1,677 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ═══ AGENT PANEL v3: what an agent is told. ═══
|
|
3
|
+
*
|
|
4
|
+
* THIS FILE BELONGS TO AGENT PANEL v3. Nothing outside `src/panel3/` may
|
|
5
|
+
* import it.
|
|
6
|
+
*
|
|
7
|
+
* ---------------------------------------------------------------------------
|
|
8
|
+
* WHY THE WORDS LIVE HERE AND NOT IN THE DAEMON.
|
|
9
|
+
*
|
|
10
|
+
* `run.ts` is about leases, processes and rows: what may be taken, what is
|
|
11
|
+
* written before a spawn, what happens when a machine dies. This is product
|
|
12
|
+
* copy — it decides the words a person ends up reading — and the rules that
|
|
13
|
+
* govern it are not the rules that govern a lease. Kept in the daemon, the
|
|
14
|
+
* paragraph explaining why a reply may not say "dispatch" would sit three
|
|
15
|
+
* hundred lines from the sentence it is about.
|
|
16
|
+
*
|
|
17
|
+
* ---------------------------------------------------------------------------
|
|
18
|
+
* ═══ THE STRUCTURE IS ONE SENTENCE PLUS THE TOOL DESCRIPTIONS. NOTHING ELSE. ═══
|
|
19
|
+
*
|
|
20
|
+
* ux.md: "The structure v3 provides is exactly two things: a core responsibility
|
|
21
|
+
* per level, and the tools that level can reach. Everything else about how an
|
|
22
|
+
* agent behaves is left loose on purpose. There is no procedure, no required
|
|
23
|
+
* sequence, no router."
|
|
24
|
+
*
|
|
25
|
+
* So there is deliberately NO order of tool calls here, no mapping from a kind
|
|
26
|
+
* of request to the tool that answers it, and no instruction to read before
|
|
27
|
+
* writing. That flexibility is the thing the whole design exists to keep, and a
|
|
28
|
+
* prompt is exactly where it gets quietly spent.
|
|
29
|
+
*
|
|
30
|
+
* WHAT IS HERE BESIDES THE ONE SENTENCE IS NOT PROCEDURE. It is the facts of the
|
|
31
|
+
* situation an agent cannot discover for itself: that a person is reading the
|
|
32
|
+
* reply, that a person is watching while it works, that it cannot see code, and
|
|
33
|
+
* what that person has already said. None of those is a step.
|
|
34
|
+
*
|
|
35
|
+
* AND IT DOES NOT LIST WHAT THE RECORD HOLDS. An earlier draft enumerated
|
|
36
|
+
* projects, work items and artifacts here, which is the job ux.md gives to the
|
|
37
|
+
* tool's own description "because they travel with the tool" — and this is the
|
|
38
|
+
* one place in the file that would silently go stale the first time a tool is
|
|
39
|
+
* added and nobody thinks to look at a prompt.
|
|
40
|
+
*
|
|
41
|
+
* ---------------------------------------------------------------------------
|
|
42
|
+
* ═══ THE HOUSE VOCABULARY IS BANNED IN ANYTHING A PERSON READS. ═══
|
|
43
|
+
*
|
|
44
|
+
* ux.md: "The user perceives one voice, because no agent uses house vocabulary
|
|
45
|
+
* and the brief is the same at every level. Nothing in a reply reveals which
|
|
46
|
+
* level wrote it."
|
|
47
|
+
*
|
|
48
|
+
* The person asked about their own work. Agent, run, dispatch, level, card,
|
|
49
|
+
* turn, coordinator, orchestrator and worker all describe how the product went
|
|
50
|
+
* about answering them, which is not what they asked and not a vocabulary they
|
|
51
|
+
* should have to learn to read their own board. The ban is stated as a ban
|
|
52
|
+
* because it is not obvious: every one of those words is the natural one to
|
|
53
|
+
* reach for from inside, which is exactly why it leaks.
|
|
54
|
+
*
|
|
55
|
+
* ---------------------------------------------------------------------------
|
|
56
|
+
* ═══ WHAT IS MADE GOES IN THE THING. THE REPLY POINTS AT IT. ═══
|
|
57
|
+
*
|
|
58
|
+
* ux.md: "Output goes into the code or into a CTRL+SPC object, never into the
|
|
59
|
+
* chat. The chat carries pointers."
|
|
60
|
+
*
|
|
61
|
+
* THIS IS A FACT ABOUT THE SITUATION, WHICH IS WHY IT IS HERE AND NOT PROCEDURE.
|
|
62
|
+
* An agent writing into a plain chat window has no choice: prose is the only
|
|
63
|
+
* place its work can land, so restating what it produced is the only way the
|
|
64
|
+
* person sees it. Here it is the opposite, and the agent cannot tell from where
|
|
65
|
+
* it sits: every epic, item and document it creates is recorded against the
|
|
66
|
+
* conversation as it is made, and is already in front of the person as something
|
|
67
|
+
* they can open. Nothing about that is discoverable from a tool description,
|
|
68
|
+
* which says what a tool does and not what the screen already shows.
|
|
69
|
+
*
|
|
70
|
+
* SO THE FAILURE IS SPECIFIC, AND IT WAS MEASURED BEFORE THIS PARAGRAPH EXISTED.
|
|
71
|
+
* Asked for an epic with two items under it, level 1 created all three correctly
|
|
72
|
+
* and then wrote a summary of each item's description back into the reply. Both
|
|
73
|
+
* copies were real; only one of them is the one the person can edit, and the
|
|
74
|
+
* other starts going stale the moment they do. The rule is not about length.
|
|
75
|
+
*
|
|
76
|
+
* ---------------------------------------------------------------------------
|
|
77
|
+
* ═══ IT MUST NOT IMPLY A CODE TOOL, AND IT MUST NAME THE HONEST MOVE. ═══
|
|
78
|
+
*
|
|
79
|
+
* ux.md: "level 1 is never granted a code tool, so it cannot become the thing
|
|
80
|
+
* that does the work." That is already true mechanically — `spawn.ts` starts
|
|
81
|
+
* level 1 with `--tools ''` and the tools server serves no code tool at any
|
|
82
|
+
* level — so this file's job is not to enforce it. It is to stop the absence
|
|
83
|
+
* being expensive.
|
|
84
|
+
*
|
|
85
|
+
* THE FAILURE THAT COSTS THE USER IS NOT THE ABSENCE. It is an agent that
|
|
86
|
+
* answers a question about code from what it can infer and writes the answer in
|
|
87
|
+
* the voice of something that looked. The user cannot tell that apart from a
|
|
88
|
+
* real answer, and one of those makes every other answer untrustworthy. So the
|
|
89
|
+
* absence is stated plainly as a fact, and the honest move — send somebody who
|
|
90
|
+
* can look — is named beside it.
|
|
91
|
+
*
|
|
92
|
+
* ---------------------------------------------------------------------------
|
|
93
|
+
* ═══ A DISPATCHED AGENT IS TOLD ITS OWN JOB AND NOTHING ABOUT THE
|
|
94
|
+
* CONVERSATION. ═══
|
|
95
|
+
*
|
|
96
|
+
* ux.md: "a fresh subagent needs its task, the interfaces it touches, and the
|
|
97
|
+
* global constraints. Nothing else", with the measured cost of the alternative —
|
|
98
|
+
* "a real session's dispatch hit 42k chars of which 99% was pasted history."
|
|
99
|
+
*
|
|
100
|
+
* So `workBrief` carries exactly two things written by judgement, the
|
|
101
|
+
* responsibility and the boundary, and the facts the product attaches. It
|
|
102
|
+
* carries NO messages, no earlier replies and no history: what the person said
|
|
103
|
+
* reaches it only insofar as whoever dispatched it put it in the
|
|
104
|
+
* responsibility, which is that agent's job to get right.
|
|
105
|
+
*
|
|
106
|
+
* ═══ AND IT IS THE SAME VOICE, WHICH IS WHY THE OUTBOUND RULES ARE SHARED. ═══
|
|
107
|
+
* ux.md: "the brief is the same at every level. Nothing in a reply reveals which
|
|
108
|
+
* level wrote it." Two copies of the ban on house vocabulary would be two copies
|
|
109
|
+
* that drift, and the drift is invisible: it shows up as one reply in ten
|
|
110
|
+
* mentioning a dispatch, from the level nobody re-read.
|
|
111
|
+
*
|
|
112
|
+
* ---------------------------------------------------------------------------
|
|
113
|
+
* ═══ WHAT SURVIVES A RESPAWN IS HANDED OVER AS THE INPUT, NOT OFFERED AS A
|
|
114
|
+
* TOOL. ═══
|
|
115
|
+
*
|
|
116
|
+
* ux.md: "The brief and the report are in the spawn's prompt, not behind a tool
|
|
117
|
+
* call the agent has to choose to make. An agent cannot fail to read its own
|
|
118
|
+
* input. This is the difference between a guarantee and a hope."
|
|
119
|
+
*
|
|
120
|
+
* `get_my_brief_and_report` still exists, for re-reading mid-run. It is not the
|
|
121
|
+
* delivery mechanism, and this file is: `resumePrompt` puts the brief and the
|
|
122
|
+
* report in front of an agent before it has decided anything.
|
|
123
|
+
*
|
|
124
|
+
* ═══ AND WHAT IT IS TOLD ABOUT WRITING ONE IS A FACT, NOT A PROCEDURE. ═══ The
|
|
125
|
+
* header above bans procedure here, and the ban holds: nothing below says when
|
|
126
|
+
* to write, in what order, or what to do first. What an agent CANNOT discover
|
|
127
|
+
* for itself is that it can be stopped and started again, and that the only
|
|
128
|
+
* thing that comes back with it is what it wrote down. Given that fact, writing
|
|
129
|
+
* it down is the obvious move rather than an instruction to comply with — and
|
|
130
|
+
* how to write it travels with `write_report`'s own description, where ux.md
|
|
131
|
+
* says the how belongs.
|
|
132
|
+
*/
|
|
133
|
+
/**
|
|
134
|
+
* ═══ WHAT EVERY LEVEL IS TOLD ABOUT THE THING IT SENDS BACK. ═══
|
|
135
|
+
*
|
|
136
|
+
* One owner for the rules that decide how a reply reads, because the person is
|
|
137
|
+
* meant to hear one voice however many agents were involved. The one line that
|
|
138
|
+
* differs between levels is what an agent PRODUCED, and it differs for a real
|
|
139
|
+
* reason: level 1 makes objects the person can already open, and a dispatched
|
|
140
|
+
* agent changes code they cannot see from here.
|
|
141
|
+
*/
|
|
142
|
+
const whatYouSendBack = (produced) => [
|
|
143
|
+
'WHAT YOU SEND BACK',
|
|
144
|
+
'Your reply is the whole of what they read, so write it to them, about their own work.',
|
|
145
|
+
'- Be brief. They are looking for the sentence that answers them, not for a report.',
|
|
146
|
+
'- Name the real things: the actual items, projects and people, by the names they have.',
|
|
147
|
+
...produced,
|
|
148
|
+
'- Never name the machinery. Words like agent, run, dispatch, level, card, turn, coordinator,',
|
|
149
|
+
' orchestrator and worker are ours and not theirs, and none of them belongs in something a',
|
|
150
|
+
' person reads. The same goes for the line about what you are doing.',
|
|
151
|
+
'',
|
|
152
|
+
'Reply with the text they should read, and nothing else.',
|
|
153
|
+
];
|
|
154
|
+
/**
|
|
155
|
+
* ═══ WHAT A WORKER SENDS BACK, WHICH DOES NOT GO TO THE PERSON. ═══
|
|
156
|
+
*
|
|
157
|
+
* ux.md: "Each worker writes what it found into the record, and the level 2 agent
|
|
158
|
+
* reads them back", and the reply that reaches the person is written by that
|
|
159
|
+
* agent, once, covering all of them. So a worker's own words go to whoever sent
|
|
160
|
+
* it and nowhere else — `panel3_answer` puts them in its report rather than on
|
|
161
|
+
* the card — and it is TOLD so, because from where it sits the two are
|
|
162
|
+
* indistinguishable and the difference decides how it writes.
|
|
163
|
+
*
|
|
164
|
+
* THE BAN ON HOUSE VOCABULARY STAYS, for a reason it did not have at the other
|
|
165
|
+
* levels: what a worker writes is read by the agent that has to answer the
|
|
166
|
+
* person, and the phrases most likely to be quoted straight through are the ones
|
|
167
|
+
* that summarise. A sentence about dispatching a worker is one paste away from
|
|
168
|
+
* something a person reads.
|
|
169
|
+
*/
|
|
170
|
+
const whatAWorkerSendsBack = () => [
|
|
171
|
+
'WHAT YOU SEND BACK, AND WHO READS IT',
|
|
172
|
+
'What you write at the end goes to whoever sent you, and to nobody else. They asked several',
|
|
173
|
+
'people for several pieces and they put the answer together out of them, so nothing you write',
|
|
174
|
+
'reaches the person except through them.',
|
|
175
|
+
'- Write it to somebody who has not seen any of this. They know what they asked you for and',
|
|
176
|
+
' nothing about what you found, so say what you found or changed and where.',
|
|
177
|
+
'- Be complete about the things they could not know, and brief about everything else. Do not',
|
|
178
|
+
' paste the code back: they can read it.',
|
|
179
|
+
'- If part of what you were given turned out not to be yours, or not to be there, say so plainly',
|
|
180
|
+
' rather than working around it quietly.',
|
|
181
|
+
'- Never name the machinery. Words like agent, run, dispatch, level, card, turn, coordinator,',
|
|
182
|
+
' orchestrator and worker are ours, and what you write may go on to a person word for word.',
|
|
183
|
+
'',
|
|
184
|
+
'Reply with what they need to know, and nothing else.',
|
|
185
|
+
];
|
|
186
|
+
/** The one line about being watched, which is true at every level: the activity
|
|
187
|
+
* line is the only sign a person has that anything is happening. */
|
|
188
|
+
const WHILE_YOU_ARE_WORKING = [
|
|
189
|
+
'WHILE YOU ARE WORKING',
|
|
190
|
+
'One line saying what you are doing is on their screen for as long as you are here, and it is',
|
|
191
|
+
'the only sign that anything is happening at all. Say what you ARE doing, never what you are',
|
|
192
|
+
'about to do: an intention that then falls through leaves them watching a sentence that was',
|
|
193
|
+
'never true.',
|
|
194
|
+
];
|
|
195
|
+
/**
|
|
196
|
+
* ═══ WHAT THE PERSON ATTACHED, AS A FACT AND NOTHING MORE. ═══
|
|
197
|
+
*
|
|
198
|
+
* plan-work-items.md constraint 5: "no agent is asked in prose to go and find
|
|
199
|
+
* what a card is about." So this is one sentence saying it happened and to whom
|
|
200
|
+
* it belongs, and nothing more: not "read these before you answer", not "use
|
|
201
|
+
* get_work_item on each one", nothing that tells the agent what to DO. It
|
|
202
|
+
* already holds `get_work_item` and `list_work_items`; what it cannot discover
|
|
203
|
+
* on its own is that these specific ids are the ones the person meant, and that
|
|
204
|
+
* is the one fact stated here.
|
|
205
|
+
*
|
|
206
|
+
* SHARED between `levelOnePrompt` and `workBrief` for the same reason
|
|
207
|
+
* `whatYouSendBack` is: one wording for "what was attached", never two that
|
|
208
|
+
* drift.
|
|
209
|
+
*/
|
|
210
|
+
const whatWasAttached = (attachments) => {
|
|
211
|
+
const codebases = attachments.filter((attachment) => attachment.startsWith('codebase '));
|
|
212
|
+
const personAttachments = attachments.filter((attachment) => !attachment.startsWith('codebase '));
|
|
213
|
+
const personAttachmentLines = personAttachments.length === 0 ? [] : [
|
|
214
|
+
'',
|
|
215
|
+
'WHAT THE PERSON ATTACHED',
|
|
216
|
+
'They attached these when they sent this, so what is asked belongs against them.',
|
|
217
|
+
...personAttachments,
|
|
218
|
+
/* ═══ THE ONE KIND THAT IS AN INSTRUCTION RATHER THAN A SUBJECT. ═══ A
|
|
219
|
+
work item is what the work is ABOUT, and the paragraph above already
|
|
220
|
+
says so. A skill is not: it is a method a person chose, and an agent
|
|
221
|
+
that read it as one more thing the request belongs against would quote
|
|
222
|
+
it back and carry on doing the work its own way. That is the fact it
|
|
223
|
+
cannot discover from the line above, so it is the one sentence added,
|
|
224
|
+
and the tool's own description carries the rest.
|
|
225
|
+
|
|
226
|
+
═══ SAID WHENEVER ANYTHING IS ATTACHED, WHICH IS A CHOICE AND NOT AN
|
|
227
|
+
ACCIDENT. ═══ Both callers hold the rows, `kind` and all, so narrowing
|
|
228
|
+
this to cards that actually have a skill is available and was not
|
|
229
|
+
taken. The sentence is a DEFINITION of what that word means in the list
|
|
230
|
+
above, not an instruction to go and do something: a card with only a
|
|
231
|
+
work item attached reads past it, exactly as it reads past any other
|
|
232
|
+
word it has no use for. What narrowing would buy is one line on some
|
|
233
|
+
cards, against a second rule to keep true in a second place.
|
|
234
|
+
|
|
235
|
+
AND THE WORST CASE IS CHEAP AND HONEST. An agent that called
|
|
236
|
+
`get_skill` with a work item's id gets a failure through `only`, which
|
|
237
|
+
says there is no such row, rather than somebody else's document. */
|
|
238
|
+
'A `skill` is a document written to be followed. Call `get_skill` with its id, read all of it,',
|
|
239
|
+
'and do what it says for the rest of this work.',
|
|
240
|
+
/* ═══ THE ONE SENTENCE THAT IS TRUE AT EVERY LEVEL, WHICH IS WHY IT IS ONE
|
|
241
|
+
SENTENCE. ═══ `get_credential` is levels 2 and 3 only (Lane, 2026-08-19:
|
|
242
|
+
level 1 reads the NAME, the levels that do the work read the value), and
|
|
243
|
+
this wording is shared by `levelOnePrompt` and `workBrief` both. So it
|
|
244
|
+
says where the name is and who may read the value, rather than telling
|
|
245
|
+
anybody to call a tool: a coordinator reading it learns to write "use the
|
|
246
|
+
Stripe test key" into what it dispatches, and a worker reading it learns
|
|
247
|
+
there is a tool and an id to call it with. A "call get_credential"
|
|
248
|
+
sentence would be an instruction level 1 cannot follow, in level 1's own
|
|
249
|
+
prompt. */
|
|
250
|
+
'A `credential` is a secret the person authorised for this work. Its name is above; the value',
|
|
251
|
+
'is readable only by the agents doing the work, with `get_credential`.',
|
|
252
|
+
];
|
|
253
|
+
return [
|
|
254
|
+
...(codebases.length === 0 ? [] : [
|
|
255
|
+
'',
|
|
256
|
+
'THE CODEBASES THIS CARD TOUCHES',
|
|
257
|
+
...codebases,
|
|
258
|
+
'For a dispatched piece, its one codebase is named separately below. The other selected',
|
|
259
|
+
'codebases are separate work, not missing folders, so do not look for or report on them.',
|
|
260
|
+
]),
|
|
261
|
+
...personAttachmentLines,
|
|
262
|
+
];
|
|
263
|
+
};
|
|
264
|
+
const projectCodebases = (codebases) => {
|
|
265
|
+
if (codebases === null)
|
|
266
|
+
return [];
|
|
267
|
+
return [
|
|
268
|
+
'',
|
|
269
|
+
'THE CODEBASES REGISTERED ON THIS PROJECT',
|
|
270
|
+
...(codebases.length === 0
|
|
271
|
+
? [
|
|
272
|
+
'There are none. If this needs code, ask the person to add a codebase to this project and',
|
|
273
|
+
'stop. Work that does not need code can continue.',
|
|
274
|
+
]
|
|
275
|
+
: [
|
|
276
|
+
...codebases.map((codebase) => (`${codebase.name} — id ${codebase.id} — ${codebase.identity} — `
|
|
277
|
+
+ (codebase.located ? 'located on this machine' : 'not located on this machine'))),
|
|
278
|
+
'Choose the codebase that contains the work and include its id when you send somebody.',
|
|
279
|
+
'If several codebases are needed, send one person per codebase. If the request does not make',
|
|
280
|
+
'the choice clear, call `ask_question` once with `answer_mode` set to `multi_select`, put the',
|
|
281
|
+
'plausible codebase names in `options`, and stop. Do not write a question as your reply.',
|
|
282
|
+
]),
|
|
283
|
+
];
|
|
284
|
+
};
|
|
285
|
+
/**
|
|
286
|
+
* The card's name and the messages waiting on it, as one prompt for a level 1
|
|
287
|
+
* agent. It carries no path, no id and nothing about this machine, so nothing in
|
|
288
|
+
* it can breach the rule that an absolute local path never reaches the database
|
|
289
|
+
* — which matters because the daemon writes it to `panel3_runs.brief`.
|
|
290
|
+
*
|
|
291
|
+
* ═══ `cardTitle` IS A NAME, NOT THE QUESTION, AND ITS LABEL SAYS SO. ═══ `say`
|
|
292
|
+
* fixes it once, as the truncated first line of the FIRST message, and never
|
|
293
|
+
* changes it. Labelled as what is being asked, a second turn would tell the
|
|
294
|
+
* agent the current question is a stale half-sentence and then hand it the real
|
|
295
|
+
* ones underneath — so the label names the conversation, which is all the title
|
|
296
|
+
* has ever been.
|
|
297
|
+
*
|
|
298
|
+
* ═══ `produced` IS LEVEL 1's REPORT, AND IT IS HERE FOR THE SAME REASON THE
|
|
299
|
+
* REPORT IS IN A RESPAWN'S PROMPT. ═══
|
|
300
|
+
*
|
|
301
|
+
* Every turn on a card is answered by a fresh level 1 agent that remembers
|
|
302
|
+
* nothing, and the thing it most needs from the last one is WHAT THAT ONE MADE.
|
|
303
|
+
* Measured before this existed, and it is user-visible: asked to add items to an
|
|
304
|
+
* epic it had created a turn earlier, level 1 could not find the epic — nothing
|
|
305
|
+
* served a card's own receipts and there is no `list_epics` — so it created two
|
|
306
|
+
* items under no epic at all. "Add three more to that epic" simply failed.
|
|
307
|
+
*
|
|
308
|
+
* A run's report and a card's receipts are the same instrument at the two
|
|
309
|
+
* levels: what is already done, carried across a death. So they arrive the same
|
|
310
|
+
* way, in the prompt rather than behind a tool call, and for the same stated
|
|
311
|
+
* reason — an agent cannot fail to read its own input.
|
|
312
|
+
*
|
|
313
|
+
* THE NAMES IN IT ARE READ NOW, NOT WHEN THE RECEIPT WAS WRITTEN, which is
|
|
314
|
+
* `show.ts`'s rule and its bug: a label written at creation and printed after a
|
|
315
|
+
* rename names a different, real object. The caller resolves them.
|
|
316
|
+
*/
|
|
317
|
+
export function levelOnePrompt(cardTitle, messages, produced, attachments = [], codebases = null) {
|
|
318
|
+
return [
|
|
319
|
+
'You are the one place a person talks to in CTRL+SPC. You talk to them, and you coordinate',
|
|
320
|
+
'the work. You do not do the work yourself.',
|
|
321
|
+
'',
|
|
322
|
+
'WHAT YOU CAN SEE',
|
|
323
|
+
'Your tools read the record. Read as much of it as the question needs.',
|
|
324
|
+
'If they ask what is happening, look rather than guess: everything already under way stays exactly',
|
|
325
|
+
'where it is while you read, and nothing about being asked slows it down.',
|
|
326
|
+
'',
|
|
327
|
+
'WHAT YOU CANNOT SEE',
|
|
328
|
+
'You have no way to open a file, search a codebase or run anything. That is deliberate and it',
|
|
329
|
+
'is not a fault to apologise for. NEVER guess at what the code does, and never write as though',
|
|
330
|
+
'you had looked: they cannot tell a real answer from a plausible one, so one invented answer',
|
|
331
|
+
'makes every true one worthless.',
|
|
332
|
+
'',
|
|
333
|
+
'WHAT YOU CAN SEND SOMEBODY TO DO',
|
|
334
|
+
'Anything that means reading or changing code, you send somebody to do. They work in a copy of',
|
|
335
|
+
'the codebase and they write to this person themselves when they are done, in their own words,',
|
|
336
|
+
'which nobody edits on the way. So do not wait for them, do not offer to come back with what',
|
|
337
|
+
'they find, and do not describe what they are going to find. Say what is being looked at, and',
|
|
338
|
+
'let the answer arrive from whoever finds it.',
|
|
339
|
+
...projectCodebases(codebases),
|
|
340
|
+
'',
|
|
341
|
+
...WHILE_YOU_ARE_WORKING,
|
|
342
|
+
'',
|
|
343
|
+
'WHAT THIS CONVERSATION IS CALLED',
|
|
344
|
+
cardTitle,
|
|
345
|
+
'',
|
|
346
|
+
'WHAT HAS ALREADY BEEN MADE HERE',
|
|
347
|
+
'Everything this conversation has produced so far, whatever it was that made it, with the id to',
|
|
348
|
+
'use for each. Anything they call "that epic" or "the item you made" is in this list. Put new',
|
|
349
|
+
'work inside what is already there rather than making a second one that means the same thing.',
|
|
350
|
+
...(produced.length === 0 ? ['Nothing has been made here yet.'] : produced),
|
|
351
|
+
...whatWasAttached(attachments),
|
|
352
|
+
'',
|
|
353
|
+
'WHAT THEY HAVE SAID THAT NOBODY HAS ANSWERED YET, OLDEST FIRST.',
|
|
354
|
+
'They are one sequence, and a later one may correct an earlier one.',
|
|
355
|
+
'',
|
|
356
|
+
...messages.map((body, i) => `${i + 1}. ${body}`),
|
|
357
|
+
'',
|
|
358
|
+
...whatYouSendBack([
|
|
359
|
+
'- What you make goes IN the thing you make, and not in here. Anything you create is already in',
|
|
360
|
+
' front of them as something they can open, so name what you made and stop there. Writing its',
|
|
361
|
+
' contents out again leaves them holding two copies of the same words, and the one they can edit',
|
|
362
|
+
' is not this one.',
|
|
363
|
+
]),
|
|
364
|
+
].join('\n');
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* What an agent sent to do a piece of work is told: its own job, the facts of
|
|
368
|
+
* where it is, and nothing about the conversation it came out of.
|
|
369
|
+
*
|
|
370
|
+
* ═══ THIS IS BOTH THE PROMPT AND THE BRIEF. ═══ It is what the process is
|
|
371
|
+
* started with AND what `panel3_runs.brief` stores, exactly as level 1's prompt
|
|
372
|
+
* is, so what `cs3 show` prints is the thing the agent was actually sent rather
|
|
373
|
+
* than a description of it.
|
|
374
|
+
*
|
|
375
|
+
* ═══ AND IT CARRIES NO PATH, WHICH IS CONSTRAINT 6. ═══ The working copy is
|
|
376
|
+
* the directory the process is started in, so it never has to be named — and
|
|
377
|
+
* because this text is stored, naming it would put an absolute filesystem path
|
|
378
|
+
* in the database. The same rule is passed on to the agent for what it writes,
|
|
379
|
+
* because its report and its reply are stored too.
|
|
380
|
+
*
|
|
381
|
+
* ═══ AND WHAT THE CARD HAS ATTACHED TRAVELS WITH EVERY DISPATCH ON IT, NOT
|
|
382
|
+
* JUST THE FIRST. ═══ `workItemId` is a single item the DISPATCHING agent
|
|
383
|
+
* chose to name for this one piece of work; `attachments` is the set the
|
|
384
|
+
* PERSON pointed the whole card at, and level 1 did not choose it and cannot
|
|
385
|
+
* un-choose it for whoever it sends. Without it, only the coordinator that
|
|
386
|
+
* happened to be spawned first would ever see what the conversation is about.
|
|
387
|
+
* Every child it starts, and every grandchild THEY start, would be working
|
|
388
|
+
* from nothing but a responsibility sentence somebody else wrote down.
|
|
389
|
+
*/
|
|
390
|
+
export function workBrief(level, responsibility, boundary, workItemId, attachments = [], codebase) {
|
|
391
|
+
return [
|
|
392
|
+
...(level === 2
|
|
393
|
+
? [
|
|
394
|
+
'You see one thing a person asked for through to done. You may do the whole of it yourself,',
|
|
395
|
+
'or split it and send others to do the parts.',
|
|
396
|
+
'',
|
|
397
|
+
'WHICH OF THE TWO, DECIDED BEFORE YOU START READING',
|
|
398
|
+
'Name the parts of this job first: pieces that do not need each other\'s answers. More than',
|
|
399
|
+
'one such part means send one person per part, now, rather than working through them',
|
|
400
|
+
'yourself. Several files to read, several places to check, several questions asked at once',
|
|
401
|
+
'are all that case, and reading them one after another leaves the person waiting for the',
|
|
402
|
+
'whole queue when they could have waited for the longest one.',
|
|
403
|
+
'Do it yourself when it is genuinely one thread: one file, one question, or parts that each',
|
|
404
|
+
'need the last one\'s answer.',
|
|
405
|
+
'',
|
|
406
|
+
'READING CANNOT COLLIDE, so a job that is only reading has nothing to be careful about: send',
|
|
407
|
+
'as many as there are parts. The care below is about CHANGING files, and only that.',
|
|
408
|
+
'',
|
|
409
|
+
'IF YOU SPLIT IT',
|
|
410
|
+
'Everybody you send works in the SAME copy of the codebase as everybody else, at the same',
|
|
411
|
+
'time. Nothing keeps them out of each other\'s way, so anybody CHANGING files needs a piece',
|
|
412
|
+
'that touches nobody else\'s files, or has to be sent on their own.',
|
|
413
|
+
'What you have already sent somebody to do is written down, and you are handed that list',
|
|
414
|
+
'rather than having to remember it. Anything on it has been sent. Nothing on it is sent again.',
|
|
415
|
+
'When every one of them has finished you are started again, with what each of them wrote,',
|
|
416
|
+
'to put it together and answer. Nothing any of them writes reaches the person except',
|
|
417
|
+
'through you, so the reply that covers all of it is yours to write and nobody else\'s.',
|
|
418
|
+
'WHICH MEANS THE REPLY YOU WRITE NOW IS NOT THAT ANSWER. If you have sent anybody, you are',
|
|
419
|
+
'stopping in the middle, and what you write as you stop goes to the person as a message from',
|
|
420
|
+
'you. So make it one short sentence at most, or nothing worth reading twice: the real answer',
|
|
421
|
+
'is the one you write when you come back. What is happening meanwhile belongs on the line',
|
|
422
|
+
'below, which is where they are already watching it.',
|
|
423
|
+
]
|
|
424
|
+
: [
|
|
425
|
+
'You change the code. One piece of the work, the one below, and nothing else. Whoever sent',
|
|
426
|
+
'you is doing the rest.',
|
|
427
|
+
'',
|
|
428
|
+
'Somebody else may be working in this same copy of the codebase at the same time as you, on',
|
|
429
|
+
'a different piece. Stay inside what you were given and leave the rest of it alone.',
|
|
430
|
+
]),
|
|
431
|
+
'',
|
|
432
|
+
'WHAT YOU OWN',
|
|
433
|
+
responsibility,
|
|
434
|
+
'',
|
|
435
|
+
'WHAT YOU MUST LEAVE ALONE',
|
|
436
|
+
boundary,
|
|
437
|
+
...(workItemId ? ['', 'THE WORK ITEM THIS IS ABOUT', workItemId] : []),
|
|
438
|
+
...whatWasAttached(attachments),
|
|
439
|
+
...(codebase ? [
|
|
440
|
+
'',
|
|
441
|
+
'THE CODEBASE THIS WORK BELONGS TO',
|
|
442
|
+
`${codebase.name} — id ${codebase.id} — ${codebase.identity}`,
|
|
443
|
+
] : []),
|
|
444
|
+
'',
|
|
445
|
+
'WHERE YOU ARE',
|
|
446
|
+
'The directory you are in is a working copy of the codebase. Read it, run things in it, and',
|
|
447
|
+
'change it where that is what you were asked for. Name a file by its path inside this copy,',
|
|
448
|
+
'never by the full path from the root of this machine: the full one means nothing to the person',
|
|
449
|
+
'reading and is not ours to hand around.',
|
|
450
|
+
'',
|
|
451
|
+
'WHAT YOU WERE AND WERE NOT GIVEN',
|
|
452
|
+
'What is above is the whole of it. You have not seen what anybody said, and you are not meant',
|
|
453
|
+
'to: what matters was written into what you own. If something you genuinely need is missing,',
|
|
454
|
+
'say so plainly in your reply rather than guessing at it.',
|
|
455
|
+
'',
|
|
456
|
+
'WHAT CANNOT BE DECIDED HERE',
|
|
457
|
+
'Some things are not yours to settle, and guessing at one of those quietly is worse than any',
|
|
458
|
+
'delay: the work goes on top of an assumption nobody made and nobody can see. Asking stops you',
|
|
459
|
+
'where you are, and you are started again with the answer when there is one, so nothing you have',
|
|
460
|
+
'done is lost by asking. Questions already asked on this work, and what they were answered with,',
|
|
461
|
+
'are there to be read, and one of them may be yours.',
|
|
462
|
+
'',
|
|
463
|
+
'YOU CAN BE STOPPED, AND WHAT YOU WROTE DOWN IS ALL THAT COMES BACK WITH YOU',
|
|
464
|
+
'This machine can go down and take you with it, mid-sentence, with no warning and no chance to',
|
|
465
|
+
'tidy up. When that happens you are started again with what is above and with the notes you last',
|
|
466
|
+
'wrote down, and with nothing else: not what you had in your head, not what you had just decided,',
|
|
467
|
+
'not what you were halfway through. Notes written at the end of the work are notes that were',
|
|
468
|
+
'never written.',
|
|
469
|
+
'',
|
|
470
|
+
...WHILE_YOU_ARE_WORKING,
|
|
471
|
+
'',
|
|
472
|
+
...(level === 2
|
|
473
|
+
? whatYouSendBack([
|
|
474
|
+
'- Nobody rewrites what you send. It goes to them as you wrote it, so it has to stand on its',
|
|
475
|
+
' own: answer the thing that was asked, and say what you changed and where, without pasting',
|
|
476
|
+
' the code back. They can read the code; they cannot read your reasoning.',
|
|
477
|
+
])
|
|
478
|
+
: whatAWorkerSendsBack()),
|
|
479
|
+
].join('\n');
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* What an agent that was stopped is started again with: the same brief, its own
|
|
483
|
+
* notes, and what it already sent others to do.
|
|
484
|
+
*
|
|
485
|
+
* ═══ THE BRIEF IS CARRIED VERBATIM AND IS THE LAST THING IN IT. ═══ Verbatim
|
|
486
|
+
* because ux.md fixes it at dispatch — "a respawn is given the same instruction
|
|
487
|
+
* the first attempt was" — so this must not summarise, shorten or re-derive it.
|
|
488
|
+
* Last because the brief ENDS with how to write the reply, and that ending is
|
|
489
|
+
* the one an ordinary spawn has: putting the resumption after it would push the
|
|
490
|
+
* outbound rules into the middle of the prompt and leave a note about a dead
|
|
491
|
+
* process as the final word.
|
|
492
|
+
*
|
|
493
|
+
* ═══ THE REPORT IS WHAT THE RUN WROTE, AND NOTHING ELSE. ═══ It is deliberately
|
|
494
|
+
* lossy (ux.md), because the record holds the detail — the receipts, the
|
|
495
|
+
* activity and the commits are all still there to be read. This carries the
|
|
496
|
+
* state to resume from, not an archive.
|
|
497
|
+
*
|
|
498
|
+
* ═══ `children` IS READ LIVE BY THE CALLER, WHICH IS THE RULE THAT DECIDES
|
|
499
|
+
* WHAT GOES IN A REPORT AT ALL. ═══ ux.md: "anything that can change while
|
|
500
|
+
* you are not running is read live and never carried in your report." What was
|
|
501
|
+
* dispatched changes while a run is dead — its children finish — so it is a fact
|
|
502
|
+
* to be read rather than something to be remembered, and the sentence below says
|
|
503
|
+
* so out loud. NULL means this agent cannot have sent anybody: at the deepest
|
|
504
|
+
* level there is no `dispatch` at all, and printing "you sent nobody" would
|
|
505
|
+
* describe an absence as a choice.
|
|
506
|
+
*/
|
|
507
|
+
export function resumePrompt(brief, report, children) {
|
|
508
|
+
return respawnPrompt([
|
|
509
|
+
'YOU WERE ALREADY DOING THIS, AND YOU WERE STOPPED BEFORE YOU FINISHED.',
|
|
510
|
+
'Not by anybody: the machine went down and took you with it. You are the same agent, started',
|
|
511
|
+
'again, and everything below is what survived. Nothing about what you were sent to do has',
|
|
512
|
+
'changed, and nothing you did before you stopped has been undone.',
|
|
513
|
+
], brief, report, children);
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* ═══ WHAT AN AGENT IS STARTED AGAIN WITH WHEN THE PROCESS IT WAS RUNNING IN
|
|
517
|
+
* DIED ON SOMETHING UPSTREAM. ═══
|
|
518
|
+
*
|
|
519
|
+
* recovery-1/ux.md, Slice 3: "the agent's harness fails on something that is
|
|
520
|
+
* nobody's fault: a rate limit, a dropped connection, a provider outage. The
|
|
521
|
+
* product tries again rather than failing the card."
|
|
522
|
+
*
|
|
523
|
+
* ═══ IT EXISTS BECAUSE `resumePrompt`'s OPENING IS FALSE HERE. ═══ That one
|
|
524
|
+
* says "the machine went down and took you with it", and on this path the
|
|
525
|
+
* machine did not go down: it is the same daemon, still running, that watched
|
|
526
|
+
* the harness exit. Telling an agent something untrue about why it is running is
|
|
527
|
+
* what this file exists to prevent, and a fifth opening onto the one respawn
|
|
528
|
+
* body is the shape the other four already established rather than a new idea.
|
|
529
|
+
*
|
|
530
|
+
* ═══ AND IT SAYS THE FAILURE WAS NOT THE AGENT'S, BECAUSE THE ALTERNATIVE IS
|
|
531
|
+
* WORSE. ═══ An agent told only that it stopped has no way to tell a harness
|
|
532
|
+
* that died from work it got wrong, and the cheapest guess from inside is that
|
|
533
|
+
* the last thing it tried was the problem. That is how a resume turns into a
|
|
534
|
+
* rewrite of work that was already right.
|
|
535
|
+
*/
|
|
536
|
+
export function retryPrompt(brief, report, children) {
|
|
537
|
+
return respawnPrompt([
|
|
538
|
+
'YOU WERE ALREADY DOING THIS, AND THE PROCESS YOU WERE RUNNING IN DIED BEFORE YOU FINISHED.',
|
|
539
|
+
'Not because of anything you did, and not because anybody stopped you: the harness itself',
|
|
540
|
+
'failed, which is what a rate limit, a dropped connection or a provider outage looks like from',
|
|
541
|
+
'here. You are the same agent, started again, and everything below is what survived. Nothing',
|
|
542
|
+
'about what you were sent to do has changed, and nothing you did before it died has been undone.',
|
|
543
|
+
], brief, report, children);
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* ═══ WHAT AN AGENT THAT ASKED IS STARTED AGAIN WITH. ═══
|
|
547
|
+
*
|
|
548
|
+
* ux.md: "The run that asked is spawned again, fresh, with the question and the
|
|
549
|
+
* answer in its brief. Not level 1 passing it down through level 2. Not a
|
|
550
|
+
* message. A respawn, which is the same mechanism as redirect." So this is
|
|
551
|
+
* `resumePrompt` with one more thing in it, and the sameness is the point: the
|
|
552
|
+
* agent picks up where the old one left off for the same reason a crash resume
|
|
553
|
+
* does, because the work was never inside the process.
|
|
554
|
+
*
|
|
555
|
+
* ═══ AND IT SAYS OUT LOUD THAT AN ANSWER CAN BE BIGGER THAN THE QUESTION. ═══
|
|
556
|
+
* ux.md: "If the answer turns out to change more than that worker's own piece,
|
|
557
|
+
* it escalates again rather than proceeding. Whether an answer is local or global
|
|
558
|
+
* is judgement, and building a classifier for it would be the product deciding
|
|
559
|
+
* something the agent is better placed to see." So it is named as a judgement
|
|
560
|
+
* the agent makes, in one sentence, rather than a rule about when to ask.
|
|
561
|
+
*/
|
|
562
|
+
export function answerPrompt(brief, report, children, question, answer) {
|
|
563
|
+
return respawnPrompt([
|
|
564
|
+
'YOU STOPPED BECAUSE YOU COULD NOT GO ON WITHOUT KNOWING SOMETHING. HERE IT IS.',
|
|
565
|
+
'You are the same agent, started again, and everything you did before you asked is still there.',
|
|
566
|
+
'',
|
|
567
|
+
'WHAT YOU ASKED',
|
|
568
|
+
question,
|
|
569
|
+
'',
|
|
570
|
+
'WHAT CAME BACK',
|
|
571
|
+
answer,
|
|
572
|
+
'',
|
|
573
|
+
'If this answers less than you asked, or turns out to change more than the piece you were sent',
|
|
574
|
+
'to do, ask again rather than deciding it yourself. Carrying on from a guess about something this',
|
|
575
|
+
'big is how work gets done twice.',
|
|
576
|
+
], brief, report, children);
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* ═══ WHAT AN AGENT IS STARTED AGAIN WITH WHEN EVERYBODY IT SENT HAS FINISHED.
|
|
580
|
+
* ═══
|
|
581
|
+
*
|
|
582
|
+
* ux.md's third re-arm, and the one nothing else could fire: "every child of a
|
|
583
|
+
* run has finished → that run, so it can read them back and carry on."
|
|
584
|
+
*
|
|
585
|
+
* ═══ WHAT THEY FOUND IS IN THE PROMPT, NOT BEHIND A TOOL CALL. ═══ This is the
|
|
586
|
+
* one respawn whose entire purpose is reading them back, and ux.md is explicit
|
|
587
|
+
* about the difference between a guarantee and a hope: "an agent cannot fail to
|
|
588
|
+
* read its own input." `childrenOf` carries each of their reports, so the
|
|
589
|
+
* synthesis starts from what they wrote rather than from remembering to ask.
|
|
590
|
+
*
|
|
591
|
+
* ═══ AND IT SAYS OUT LOUD THAT NOBODY ELSE WILL SAY IT. ═══ A worker's words go
|
|
592
|
+
* into the record and stop there, by `panel3_answer`. From inside, an agent
|
|
593
|
+
* cannot tell whether the person has already read three replies; told wrongly it
|
|
594
|
+
* writes a covering note over answers nobody ever saw. So it is told, as a fact
|
|
595
|
+
* about the situation rather than as an instruction.
|
|
596
|
+
*/
|
|
597
|
+
export function readBackPrompt(brief, report, children) {
|
|
598
|
+
return respawnPrompt([
|
|
599
|
+
'EVERYBODY YOU SENT HAS FINISHED, AND YOU ARE STARTED AGAIN TO READ WHAT THEY FOUND.',
|
|
600
|
+
'You are the same agent, started again, and nothing you did before has been undone. Nothing you',
|
|
601
|
+
'sent anybody to do is still running.',
|
|
602
|
+
'',
|
|
603
|
+
'WHAT THEY WROTE IS BELOW, and it has gone nowhere else. The person has not seen any of it and',
|
|
604
|
+
'will not: what reaches them about this is what you write now. If what came back leaves the',
|
|
605
|
+
'work finished, answer with the whole of it in one piece. If it leaves something undone, that',
|
|
606
|
+
'is still yours, and you may do it or send somebody for it exactly as before.',
|
|
607
|
+
], brief, report, children);
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* ═══ WHAT AN AGENT IS STARTED AGAIN WITH WHEN SOMEBODY IT SENT CANNOT GO ON.
|
|
611
|
+
* ═══
|
|
612
|
+
*
|
|
613
|
+
* ux.md: "the level 2 agent is spawned, sees a child asked something, and either
|
|
614
|
+
* answers it or escalates and exits... Each hop is one cheap spawn that reads and
|
|
615
|
+
* decides. Against a question that waits on a human, three spawns are noise, and
|
|
616
|
+
* each one is a real chance to settle it without interrupting anyone."
|
|
617
|
+
*
|
|
618
|
+
* THE COST OF PASSING IT ON IS STATED, because that is the whole reason the hop
|
|
619
|
+
* exists: an agent that passes everything up is a level that bought nothing.
|
|
620
|
+
*/
|
|
621
|
+
export function escalationPrompt(brief, report, children, questionId, question) {
|
|
622
|
+
return respawnPrompt([
|
|
623
|
+
'SOMEBODY YOU SENT CANNOT GO ON UNTIL SOMETHING IS DECIDED, AND IT CAME TO YOU.',
|
|
624
|
+
'You are the same agent, started again to deal with it. Nothing you did before has been undone.',
|
|
625
|
+
'',
|
|
626
|
+
'WHAT THEY NEED TO KNOW',
|
|
627
|
+
question,
|
|
628
|
+
'',
|
|
629
|
+
`Its id is ${questionId}. That is what you answer it by, and it is also what you name if you`,
|
|
630
|
+
'cannot settle it either and have to send it further up: name it, and it goes up as one question',
|
|
631
|
+
'with your wording. Leave it out and you have asked a second, separate question of your own,',
|
|
632
|
+
'and this one stays here with nobody dealing with it.',
|
|
633
|
+
'',
|
|
634
|
+
'ANSWER IT IF YOU CAN. You know what this work is for and they do not, so most of what reaches',
|
|
635
|
+
'you is yours to settle. Read what you need to first. Only what you genuinely cannot decide goes',
|
|
636
|
+
'further up, and everything that goes up eventually stops a person and asks them instead.',
|
|
637
|
+
'Whichever you do, you stop afterwards: they are started again with the answer, not by you.',
|
|
638
|
+
], brief, report, children);
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* What every respawn shares: what it wrote down, what it already sent others to
|
|
642
|
+
* do, and the brief it was given, verbatim and last.
|
|
643
|
+
*
|
|
644
|
+
* ONE OWNER, because the three reasons a run is started again — the machine went
|
|
645
|
+
* down, its question was answered, somebody it sent needs a decision — differ
|
|
646
|
+
* only in what is NEW. Everything else about resuming is the same fact, and two
|
|
647
|
+
* copies of it would drift in the way ux.md's own note about the brief describes:
|
|
648
|
+
* invisibly, in whichever one nobody re-read.
|
|
649
|
+
*/
|
|
650
|
+
function respawnPrompt(opening, brief, report, children) {
|
|
651
|
+
return [
|
|
652
|
+
...opening,
|
|
653
|
+
'',
|
|
654
|
+
'WHAT YOU WROTE DOWN, THE LAST TIME YOU WROTE ANYTHING DOWN',
|
|
655
|
+
report ?? 'Nothing. You were stopped before you wrote anything down, so what you did before that '
|
|
656
|
+
+ 'is not known here — check the work itself before you assume any of it is undone.',
|
|
657
|
+
'',
|
|
658
|
+
...(children === null ? [] : [
|
|
659
|
+
'WHAT YOU ALREADY SENT SOMEBODY TO DO, AS IT STANDS RIGHT NOW, AND WHAT EACH OF THEM WROTE',
|
|
660
|
+
'Read from the record a moment ago, not from your notes, so it is right even where they are',
|
|
661
|
+
'silent: this is what exists, whatever you meant to do. Do not send somebody to do a piece of',
|
|
662
|
+
'work that is already in this list. Anything of theirs still going is still going, and asking',
|
|
663
|
+
'again for what they are already doing costs the person twice. What is under each one is what',
|
|
664
|
+
'that one wrote down, in its own words.',
|
|
665
|
+
...(children.length === 0 ? ['You have sent nobody.'] : children),
|
|
666
|
+
'',
|
|
667
|
+
]),
|
|
668
|
+
'CARRY ON FROM WHERE THAT LEAVES YOU. What your notes say is done is done and is not to be done',
|
|
669
|
+
'again; what they leave open is what is left. Where they are silent, look at the work itself',
|
|
670
|
+
'rather than starting it over: they are what you had time to write down, not everything that',
|
|
671
|
+
'happened. And write them again as you go, for the same reason.',
|
|
672
|
+
'',
|
|
673
|
+
'WHAT YOU WERE SENT TO DO, WORD FOR WORD AS YOU WERE SENT IT',
|
|
674
|
+
'',
|
|
675
|
+
brief,
|
|
676
|
+
].join('\n');
|
|
677
|
+
}
|