@zenera/cli 1.1.23 → 1.1.25
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/README.md +88 -2
- package/dist/ask.d.ts +51 -0
- package/dist/ask.js +166 -0
- package/dist/banner.js +2 -2
- package/dist/batch.d.ts +83 -0
- package/dist/batch.js +413 -0
- package/dist/catalog.d.ts +11 -1
- package/dist/catalog.js +80 -7
- package/dist/command.d.ts +6 -0
- package/dist/commands/inspect.d.ts +57 -0
- package/dist/commands/inspect.js +539 -91
- package/dist/commands/list.js +128 -19
- package/dist/commands/memory.js +461 -32
- package/dist/commands/meta.js +311 -21
- package/dist/commands/models.js +110 -14
- package/dist/commands/open.js +4 -4
- package/dist/commands/run.js +175 -36
- package/dist/commands/sandbox.js +148 -15
- package/dist/engine.d.ts +24 -0
- package/dist/engine.js +61 -8
- package/dist/eventlog.d.ts +59 -0
- package/dist/eventlog.js +146 -0
- package/dist/liveness.d.ts +7 -0
- package/dist/liveness.js +20 -3
- package/dist/main.js +5 -2
- package/dist/meta/editor.d.ts +9 -0
- package/dist/meta/editor.js +60 -0
- package/dist/meta/finetune/children.d.ts +8 -0
- package/dist/meta/finetune/children.js +76 -0
- package/dist/meta/finetune/command.d.ts +30 -0
- package/dist/meta/finetune/command.js +338 -0
- package/dist/meta/finetune/dataset/anchors.d.ts +41 -0
- package/dist/meta/finetune/dataset/anchors.js +239 -0
- package/dist/meta/finetune/dataset/changes.d.ts +36 -0
- package/dist/meta/finetune/dataset/changes.js +319 -0
- package/dist/meta/finetune/dataset/command.d.ts +17 -0
- package/dist/meta/finetune/dataset/command.js +1011 -0
- package/dist/meta/finetune/dataset/drift.d.ts +33 -0
- package/dist/meta/finetune/dataset/drift.js +71 -0
- package/dist/meta/finetune/dataset/export.d.ts +26 -0
- package/dist/meta/finetune/dataset/export.js +51 -0
- package/dist/meta/finetune/dataset/index.d.ts +2 -0
- package/dist/meta/finetune/dataset/index.js +2 -0
- package/dist/meta/finetune/dataset/sample.d.ts +50 -0
- package/dist/meta/finetune/dataset/sample.js +197 -0
- package/dist/meta/finetune/dataset/schema.d.ts +33 -0
- package/dist/meta/finetune/dataset/schema.js +216 -0
- package/dist/meta/finetune/dataset/store.d.ts +35 -0
- package/dist/meta/finetune/dataset/store.js +177 -0
- package/dist/meta/finetune/dataset/types.d.ts +125 -0
- package/dist/meta/finetune/dataset/types.js +39 -0
- package/dist/meta/finetune/failure.d.ts +15 -0
- package/dist/meta/finetune/failure.js +26 -0
- package/dist/meta/finetune/feedback.d.ts +45 -0
- package/dist/meta/finetune/feedback.js +85 -0
- package/dist/meta/finetune/improvements.d.ts +51 -0
- package/dist/meta/finetune/improvements.js +244 -0
- package/dist/meta/finetune/index.d.ts +2 -0
- package/dist/meta/finetune/index.js +2 -0
- package/dist/meta/finetune/journal.d.ts +35 -0
- package/dist/meta/finetune/journal.js +135 -0
- package/dist/meta/finetune/live.d.ts +74 -0
- package/dist/meta/finetune/live.js +226 -0
- package/dist/meta/finetune/loop.d.ts +3 -0
- package/dist/meta/finetune/loop.js +114 -0
- package/dist/meta/finetune/memories.d.ts +47 -0
- package/dist/meta/finetune/memories.js +154 -0
- package/dist/meta/finetune/report.d.ts +33 -0
- package/dist/meta/finetune/report.js +1284 -0
- package/dist/meta/finetune/retry.d.ts +24 -0
- package/dist/meta/finetune/retry.js +96 -0
- package/dist/meta/finetune/sampler.d.ts +18 -0
- package/dist/meta/finetune/sampler.js +41 -0
- package/dist/meta/finetune/system.d.ts +27 -0
- package/dist/meta/finetune/system.js +132 -0
- package/dist/meta/finetune/train.d.ts +39 -0
- package/dist/meta/finetune/train.js +391 -0
- package/dist/meta/finetune/tui.d.ts +16 -0
- package/dist/meta/finetune/tui.js +291 -0
- package/dist/meta/finetune/tuning.d.ts +167 -0
- package/dist/meta/finetune/tuning.js +289 -0
- package/dist/meta/finetune/usage.d.ts +62 -0
- package/dist/meta/finetune/usage.js +225 -0
- package/dist/meta/host.d.ts +14 -0
- package/dist/meta/host.js +20 -0
- package/dist/meta/index.d.ts +11 -0
- package/dist/meta/index.js +11 -0
- package/dist/meta/launch.d.ts +81 -0
- package/dist/meta/launch.js +286 -0
- package/dist/meta/model.d.ts +44 -0
- package/dist/meta/model.js +119 -0
- package/dist/meta/prompts.d.ts +18 -0
- package/dist/meta/prompts.js +61 -0
- package/dist/meta/relay.d.ts +20 -0
- package/dist/meta/relay.js +123 -0
- package/dist/meta/tokens.d.ts +52 -0
- package/dist/meta/tokens.js +226 -0
- package/dist/meta/window.d.ts +61 -0
- package/dist/meta/window.js +198 -0
- package/dist/meta/wire.d.ts +42 -0
- package/dist/meta/wire.js +129 -0
- package/dist/modelref.d.ts +16 -0
- package/dist/modelref.js +41 -0
- package/dist/narrate.js +5 -2
- package/dist/podman.d.ts +42 -0
- package/dist/podman.js +198 -5
- package/dist/progress.d.ts +33 -0
- package/dist/progress.js +402 -0
- package/dist/projects.d.ts +0 -5
- package/dist/projects.js +2 -15
- package/dist/request.d.ts +45 -0
- package/dist/request.js +300 -0
- package/dist/sandbox.d.ts +2 -0
- package/dist/sandbox.js +20 -3
- package/dist/scaffold.d.ts +15 -6
- package/dist/scaffold.js +5 -60
- package/dist/session.d.ts +26 -1
- package/dist/session.js +46 -32
- package/dist/term.d.ts +5 -0
- package/dist/term.js +28 -3
- package/dist/trace.d.ts +84 -0
- package/dist/trace.js +737 -0
- package/dist/tui/models.d.ts +33 -0
- package/dist/tui/models.js +389 -0
- package/dist/tui/wrap.d.ts +5 -0
- package/dist/tui/wrap.js +12 -0
- package/dist/usage.d.ts +78 -0
- package/dist/usage.js +51 -0
- package/dist/validate.js +25 -3
- package/package.json +3 -2
- package/templates/editor/.github/copilot-instructions.md +41 -107
- package/templates/editor/.github/prompts/analyze.prompt.md +31 -0
- package/templates/editor/.github/prompts/dataset.prompt.md +108 -0
- package/templates/editor/.github/prompts/finetune-apply.prompt.md +91 -0
- package/templates/editor/.github/prompts/finetune.prompt.md +744 -0
- package/templates/editor/.github/prompts/new-agent.prompt.md +3 -1
- package/templates/editor/.github/prompts/new-skill.prompt.md +2 -0
- package/templates/editor/.github/prompts/project-review.prompt.md +4 -3
- package/templates/editor/.github/skills/zen-analyze-run/SKILL.md +483 -0
- package/templates/editor/.github/skills/zen-cli/SKILL.md +18 -4
- package/templates/editor/.github/skills/zen-cli/references/check.md +7 -5
- package/templates/editor/.github/skills/zen-cli/references/dataset.md +34 -0
- package/templates/editor/.github/skills/zen-cli/references/finetune.md +77 -0
- package/templates/editor/.github/skills/zen-cli/references/inspect.md +300 -21
- package/templates/editor/.github/skills/zen-cli/references/memory.md +121 -28
- package/templates/editor/.github/skills/zen-cli/references/meta.md +61 -0
- package/templates/editor/.github/skills/zen-cli/references/models.md +6 -2
- package/templates/editor/.github/skills/zen-cli/references/projects.md +12 -5
- package/templates/editor/.github/skills/zen-cli/references/rag.md +24 -6
- package/templates/editor/.github/skills/zen-cli/references/run.md +201 -4
- package/templates/editor/.github/skills/zen-cli/references/sandbox.md +10 -1
- package/templates/editor/.github/skills/zen-code-python/SKILL.md +123 -0
- package/templates/editor/.github/skills/zen-code-python/references/code_python.md +48 -0
- package/templates/editor/.github/skills/zen-dataset/SKILL.md +253 -0
- package/templates/editor/.github/skills/zen-finetune/SKILL.md +1791 -0
- package/templates/editor/.github/skills/zen-finetune/references/readme-template.md +268 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/batch.mjs +390 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/difficult.mjs +243 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/memory.mjs +280 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/next.mjs +398 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/report.mjs +797 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/select.mjs +354 -0
- package/templates/editor/.github/skills/zen-finetune/scripts/usage.mjs +722 -0
- package/templates/editor/.github/skills/zen-inspect/SKILL.md +431 -0
- package/templates/editor/.github/skills/zen-inspect-ask/SKILL.md +270 -0
- package/templates/editor/.github/skills/zen-memory/SKILL.md +78 -29
- package/templates/editor/.github/skills/zen-memory-warmup/SKILL.md +363 -531
- package/templates/editor/.github/skills/zen-rag-docs/SKILL.md +20 -8
- package/templates/editor/.github/skills/zen-review/SKILL.md +5 -3
- package/templates/editor/.github/skills/zen-review/scripts/check-paths.sh +5 -4
- package/templates/editor/.github/skills/zen-sandbox/SKILL.md +25 -2
- package/templates/editor/.github/skills/zen-sandbox-capacity/SKILL.md +334 -0
- package/templates/editor/.github/skills/zen-sandbox-capacity/references/loadtest.md +181 -0
- package/templates/editor/.github/skills/zen-sandbox-capacity/scripts/preflight_sandbox.sh +457 -0
- package/templates/editor/.github/skills/zen-topology/SKILL.md +283 -0
- package/templates/editor/.vscode/agents.schema.json +1 -1
- package/templates/editor/.vscode/settings.json +2 -0
- package/templates/project/agents/files-instructions.md +35 -13
- package/templates/project/agents/fork-instructions.md +27 -0
- package/templates/project/agents/memory-instructions.md +106 -34
- package/templates/project/agents/tools-instructions.md +7 -4
- package/templates/project/gitignore +5 -0
- package/dist/meta.d.ts +0 -221
- package/dist/meta.js +0 -684
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: zen-topology
|
|
3
|
+
description: 'Use when designing, reviewing or auditing how a Zenera project divides work between agents - whether to hand off, fork one branch to delegate, fan out several branches, or keep the work in one conversation; which fork `context` to pick; what each choice costs in tokens, prompt cache and elapsed time; and how to read a recorded run for topology mistakes (missed fan-out, a forked sequence, an early or looping hand-off, a delegation that cost more than it saved). Load before adding or changing `handoffs:` or `fork:` in agents.yaml, before writing a prompt line that says when to delegate, and before grading Delegation or Forking in a run audit.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Agent topology
|
|
7
|
+
|
|
8
|
+
Work moves between agents in exactly two ways, and both are tools the model
|
|
9
|
+
calls: a **hand-off** (`transfer_to_<name>`) gives the conversation away, a
|
|
10
|
+
**fork** (`fork`) sends work out and gets answers back. Everything else is one
|
|
11
|
+
agent working in its own conversation. Both are opt-in per agent in
|
|
12
|
+
`agents.yaml` - `handoffs:` and `fork:`, described key by key in §8.
|
|
13
|
+
|
|
14
|
+
Whether a second agent should exist at all is copilot-instructions §6.1 - this
|
|
15
|
+
skill starts once it does. The rules an agent reads at run time about forking
|
|
16
|
+
are zen's own `agents/fork-instructions.md`; this skill is for whoever designs
|
|
17
|
+
the project or judges a run against it, and never repeats that file's prose.
|
|
18
|
+
|
|
19
|
+
## 1. The four shapes
|
|
20
|
+
|
|
21
|
+
| Shape | Control | The other side sees | Comes back | Use it when |
|
|
22
|
+
| -------------- | ---------------------------- | ---------------------------------------- | ----------------------------- | --------------------------------------------------------------------------- |
|
|
23
|
+
| Keep it here | stays | - | - | steps depend on each other, one call does it, or you want to steer the work |
|
|
24
|
+
| Hand-off | moves, and **stays moved** | the whole transcript | nothing, unless it hands back | another agent should own the conversation from now on |
|
|
25
|
+
| Fork, 1 branch | returns to the forking agent | what `context` gives it + its assignment | that branch's answer only | you want an answer from someone better suited, or to keep noise out |
|
|
26
|
+
| Fork, N | returns to the forking agent | the same, per branch | N answers in one tool result | N independent parts of one task, done at the same time |
|
|
27
|
+
|
|
28
|
+
## 2. What a hand-off carries
|
|
29
|
+
|
|
30
|
+
When the model calls `transfer_to_<name>`, the kernel records a `handoff` node
|
|
31
|
+
(`from`, `to`, the optional `reason` argument), switches the current agent,
|
|
32
|
+
appends a fresh `system_prompt` for the target, and rebuilds the tool list for
|
|
33
|
+
it - its own tools, its hand-offs, its memory and skill tools, its `fork`.
|
|
34
|
+
|
|
35
|
+
- **The target sees the entire transcript**, every tool call and result the
|
|
36
|
+
previous agent made included. The runtime can collapse the outgoing agent's
|
|
37
|
+
turns with a hand-off policy, but `zen` sets none, so nothing is summarised.
|
|
38
|
+
Do not write a prompt that assumes the target starts clean.
|
|
39
|
+
- Only the newest system prompt is sent. The previous agent's role and house
|
|
40
|
+
rules are gone from the request; its words are not.
|
|
41
|
+
- The target's `description:` is the whole of what the caller reads when
|
|
42
|
+
deciding, so it is a routing condition, not a title.
|
|
43
|
+
- **Auto-recall fires again** for the target, with its own memory mask, against
|
|
44
|
+
the last user input - not against the `reason`.
|
|
45
|
+
- Preloaded skills are applied for the target; the outgoing agent's skill tools
|
|
46
|
+
are not the target's.
|
|
47
|
+
- **Nothing hands control back.** The target answers every later turn until it
|
|
48
|
+
hands off itself, which is why `zen check` warns `handoff.one-way` on any edge
|
|
49
|
+
with no path home.
|
|
50
|
+
- A memory commit is due from the agent that did the work, **before** its
|
|
51
|
+
hand-off. The target holds only the transcript of it - see **zen-memory**.
|
|
52
|
+
|
|
53
|
+
## 3. What a fork carries
|
|
54
|
+
|
|
55
|
+
The model calls `fork` with `branches: [{name, instructions, agent?}]` and one
|
|
56
|
+
`context` for the whole call. The agent must declare `fork:`; `fork.agents`
|
|
57
|
+
reaches the model as an `enum`, and `fork.maxBranches` caps the array.
|
|
58
|
+
|
|
59
|
+
**What a branch starts from:**
|
|
60
|
+
|
|
61
|
+
| `context` | The branch begins with |
|
|
62
|
+
| ------------------- | --------------------------------------------------------------------------- |
|
|
63
|
+
| `inherit` (default) | the parent's visible history up to the fork call, then its assignment |
|
|
64
|
+
| `compact` | the same minus every `tool_call`, `tool_result` and `memory_recall` |
|
|
65
|
+
| `none` | nothing: its agent's system prompt, then its instructions as a user message |
|
|
66
|
+
|
|
67
|
+
Under `inherit` and `compact` the assignment arrives as the result of the
|
|
68
|
+
inherited `fork` call, opening `You are branch "<name>" of the fork above`,
|
|
69
|
+
naming its siblings. Skills another agent loaded are dropped from an inherited
|
|
70
|
+
prefix, so a branch never reads instructions for tools it does not hold.
|
|
71
|
+
|
|
72
|
+
**What comes back:** one tool result, holding each branch's final answer and
|
|
73
|
+
status in declared order, never completion order. The branch's own steps are
|
|
74
|
+
kept inside the `join` node for audit and are never shown to the parent. A
|
|
75
|
+
failed branch is a row with `status: error`, not a failed run.
|
|
76
|
+
|
|
77
|
+
**What outlives the branch:** files it wrote (branches share the workspace with
|
|
78
|
+
the parent and each other) and anything it committed to memory. Nothing else.
|
|
79
|
+
|
|
80
|
+
**Depth:** a branch may fork again while under the run's `maxForkDepth` (2 by
|
|
81
|
+
default). At the cap the `fork` tool is withdrawn and so is
|
|
82
|
+
`agents/fork-instructions.md`.
|
|
83
|
+
|
|
84
|
+
## 4. What it costs - tokens, cache, time
|
|
85
|
+
|
|
86
|
+
A provider caches the longest **repeated prefix** of a request - tool schemas,
|
|
87
|
+
system prompt, then messages - and bills a cached token below an uncached one.
|
|
88
|
+
The runtime keeps that prefix still: house rules first, the role file second,
|
|
89
|
+
the tool array fixed for the agent's life, preloads at the head, auto-recall
|
|
90
|
+
only at the start of a turn. So the question for every shape is: **are the
|
|
91
|
+
first bytes the same as a request the provider has already seen?**
|
|
92
|
+
|
|
93
|
+
| Shape | Tokens sent | Prompt cache | Elapsed |
|
|
94
|
+
| ---------------------------- | ------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | -------------------- |
|
|
95
|
+
| Keep it here | the transcript, growing every call | hits on all of it but the newest tail | the sum of the steps |
|
|
96
|
+
| Hand-off | the whole transcript, on every call the target makes | **misses on the target's first call** - new system prompt and tools, so nothing after them matches | serial |
|
|
97
|
+
| Hand-off back | the same | the original agent's prefix up to its hand-off may still hit, within the provider's cache lifetime | serial |
|
|
98
|
+
| Fork, `inherit`, same agent | per branch: the parent's history + brief + its own work | the inherited prefix is byte-identical up to the fork call, so it can hit | the slowest branch |
|
|
99
|
+
| Fork, `inherit`, other agent | the same | misses: a different system prompt, so the whole history is paid uncached, once per branch | the slowest branch |
|
|
100
|
+
| Fork, `compact` | less history: decisions without tool traffic | same agent: hits only up to the first dropped tool call; other agent: misses | the slowest branch |
|
|
101
|
+
| Fork, `none` | its agent's prompt + instructions + its own work | nothing to share with the parent; same-agent branches share the system prompt with each other | the slowest branch |
|
|
102
|
+
| The parent after a join | two messages more: the call and one result | unchanged - declared order makes the join deterministic | - |
|
|
103
|
+
|
|
104
|
+
What follows from the table:
|
|
105
|
+
|
|
106
|
+
- **A fan-out buys time, not tokens.** N branches together usually send more
|
|
107
|
+
than doing the N parts in series, because every branch pays its own start.
|
|
108
|
+
The saving is the elapsed time of all but the slowest branch, and the
|
|
109
|
+
parent's context staying N answers long instead of N transcripts.
|
|
110
|
+
- **A one-branch fork costs a whole conversation's start** to save the caller
|
|
111
|
+
some context. Worth it for a long, noisy job with a short verdict; a loss for
|
|
112
|
+
one read, one search or one command.
|
|
113
|
+
- **Agents passing the conversation back and forth pay a cache miss on every
|
|
114
|
+
switch**, plus a recall each time, on a transcript that only grows.
|
|
115
|
+
- **`inherit` versus `compact` is a trade, not a rule.** `compact` sends less;
|
|
116
|
+
`inherit` on the same agent can be served from cache. When most of the
|
|
117
|
+
history is tool traffic, `compact` wins; when it is mostly decided
|
|
118
|
+
conversation, `inherit` on the same agent can be cheaper. On a different
|
|
119
|
+
agent there is no cache to win, so the smaller prefix wins.
|
|
120
|
+
- **Cached tokens are not shown in the run graph.** `zen inspect`'s `tokens`
|
|
121
|
+
row and each `llm` node's `in` count cached tokens as input. Reason about the
|
|
122
|
+
cache from the structure above; never report a hit or a miss as measured.
|
|
123
|
+
|
|
124
|
+
## 5. Choosing - in this order
|
|
125
|
+
|
|
126
|
+
Ask each question of the piece of work in front of you and stop at the first
|
|
127
|
+
yes.
|
|
128
|
+
|
|
129
|
+
1. **Does any part need another part's result?** Keep that sequence here. A
|
|
130
|
+
branch cannot see its siblings, cannot ask, and cannot be steered.
|
|
131
|
+
2. **Is it one call, or one call that takes a list?** Keep it here. Pass the
|
|
132
|
+
list.
|
|
133
|
+
3. **Should another agent answer the user from now on** - over several turns,
|
|
134
|
+
on its own model or tools? Hand off, and make sure a path leads back.
|
|
135
|
+
4. **Do you want an answer and then carry on?** Fork one branch on the agent
|
|
136
|
+
that suits the job. Never a hand-off: that spends the conversation to get
|
|
137
|
+
the answer.
|
|
138
|
+
5. **Are there N independent parts?** Fork N branches - one per item, or one
|
|
139
|
+
per trade, each on the agent that fits.
|
|
140
|
+
|
|
141
|
+
Then pick `context`, cheapest first:
|
|
142
|
+
|
|
143
|
+
1. `none`, when everything the branch needs can be written into its
|
|
144
|
+
instructions - paths included. Write it in and take `none`.
|
|
145
|
+
2. `compact`, when it needs the plan and the decisions but not how they were
|
|
146
|
+
found, or when the branch runs a **different** agent.
|
|
147
|
+
3. `inherit`, when it must see the work as it stands - reviewing what was just
|
|
148
|
+
written, continuing an investigation - and preferably on the **same** agent.
|
|
149
|
+
|
|
150
|
+
## 6. Where each rule goes
|
|
151
|
+
|
|
152
|
+
| Rule | Goes in |
|
|
153
|
+
| ----------------------------------------------------------------- | ----------------------------------------------------------------- |
|
|
154
|
+
| who may hand off to whom; who may fork, to which agents, how wide | `agents.yaml` - `handoffs:`, `fork: { agents, maxBranches }` (§8) |
|
|
155
|
+
| what a hand-off target is for | `agents.yaml` - the target's `description:`, as a condition |
|
|
156
|
+
| **when** to fork or hand off, in this domain's terms | the deciding agent's prompt |
|
|
157
|
+
| which `context` this work wants | the deciding agent's prompt |
|
|
158
|
+
| what a branch must return, and in which file | the forking agent's prompt, so it writes it into `instructions` |
|
|
159
|
+
| which hand-off ends a specialist's turn | the specialist's prompt |
|
|
160
|
+
| a forking policy for the whole project | `agents/fork-<topic>-instructions.md` - load **zen-instructions** |
|
|
161
|
+
|
|
162
|
+
The domain-terms line is the one most often missing, and without it a weaker
|
|
163
|
+
model works through a list serially and never calls `fork`: _"When the request
|
|
164
|
+
covers more than one region, fork one branch per region with `context: none`,
|
|
165
|
+
and tell each branch to return the region, the total and the top three
|
|
166
|
+
findings."_
|
|
167
|
+
|
|
168
|
+
Never edit `agents/fork-instructions.md` - it is zen's copy, `zen check --fix`
|
|
169
|
+
replaces it, and an edit there is reported as `rules.stale`.
|
|
170
|
+
|
|
171
|
+
## 7. Reading a run for topology
|
|
172
|
+
|
|
173
|
+
Where the topology shows in `zen inspect graph` (load **zen-inspect** for the
|
|
174
|
+
format):
|
|
175
|
+
|
|
176
|
+
- `%% agent <last> · started as <first>` - a hand-off happened.
|
|
177
|
+
- `@<agent>` on a node - the first node that agent owns.
|
|
178
|
+
- `handoff <from> to <to>` - open it for `reason`.
|
|
179
|
+
- `fork (<context> context) <branch>, <branch>` - the mode it chose.
|
|
180
|
+
- the branch subgraphs, one marked `slowest`, and `join <branch>=ok, ...`.
|
|
181
|
+
- `%% branches` - which join waited for which branches, with status.
|
|
182
|
+
- `%% tools` - `fork xN` and how many research calls ran around it.
|
|
183
|
+
|
|
184
|
+
| The graph shows | Finding | Fix goes in | Next run should show |
|
|
185
|
+
| ----------------------------------------------------------------------------------- | ------------------------------------------------- | --------------------------------------------------------- | -------------------------------------------- |
|
|
186
|
+
| research calls in series, none using an earlier result, `fork` in the agent's tools | missed fan-out | the agent's prompt: the domain trigger of §6 | one `fork` with a branch per item |
|
|
187
|
+
| the same, `fork` not in the agent's tools | missed fan-out | `agents.yaml`: `fork:` on that agent | the same |
|
|
188
|
+
| a branch's instructions name a sibling's result, or read a file a sibling writes | a sequence was forked | the forking agent's prompt | those steps in the trunk |
|
|
189
|
+
| a one-branch fork whose branch made one or two calls | delegation that cost more than it saved | the forking agent's prompt | the call made in the trunk |
|
|
190
|
+
| after the join, the parent repeats calls a branch already made | the branch was not told what to return | the forking agent's prompt: what each branch must return | no repeat after the join |
|
|
191
|
+
| a branch not `ok` | an assignment missing a fact it could not ask for | the forking agent's prompt | that branch `ok` |
|
|
192
|
+
| `slowest` far behind its siblings | an uneven division | the forking agent's prompt: split that part | branch durations close together |
|
|
193
|
+
| two branches with the same calls on the same subjects | overlap, paid for twice | the forking agent's prompt: divide by subject | disjoint subjects |
|
|
194
|
+
| a wide fan-out to **another** agent with `inherit` and a long history | the history paid uncached, once per branch | the forking agent's prompt: `compact` or `none` | `fork (compact context)` or `(none context)` |
|
|
195
|
+
| a `handoff` before the agent's own part was done | an early hand-off | the outgoing agent's prompt | its own calls, then the hand-off |
|
|
196
|
+
| `handoff` A to B, then B to A, then A to B | a loop - two prompts claim the same job | both prompts, so one owns it | one hand-off, or none |
|
|
197
|
+
| a hand-off for one question, then the target writes the final answer | wanted an answer, spent the conversation | the outgoing agent's prompt, and `fork:` in `agents.yaml` | a one-branch `fork` to that agent |
|
|
198
|
+
| a specialist exists in `agents.yaml`, and the agent did that job inline | the prompt never said when to delegate | the deciding agent's prompt | a `fork` or `handoff` to the specialist |
|
|
199
|
+
|
|
200
|
+
Price each finding honestly. A missed fan-out costs the elapsed time of every
|
|
201
|
+
branch but the slowest - not tokens, which a fork usually raises. A forked
|
|
202
|
+
sequence or an overlap costs the duplicated calls and their tokens. A
|
|
203
|
+
needless hand-off or one-branch fork costs one conversation's start, uncached.
|
|
204
|
+
|
|
205
|
+
To learn **why** the model chose the shape, ask the `llm` node that carries
|
|
206
|
+
`calls transfer_to_<name>` or `calls fork`, or the first call of a serial run -
|
|
207
|
+
load **zen-inspect-ask** for how to word it. First rule out the cheap causes:
|
|
208
|
+
`fork` not in that call's tools (depth cap, or no `fork:`),
|
|
209
|
+
`fork-instructions.md` not in its `system_prompt`, a specialist not in its
|
|
210
|
+
`enum`.
|
|
211
|
+
|
|
212
|
+
## 8. The keys in `agents.yaml`
|
|
213
|
+
|
|
214
|
+
Both keys are per agent, and both only make a tool available. When the model
|
|
215
|
+
uses it is the prompt's business (§6).
|
|
216
|
+
|
|
217
|
+
### `handoffs:`
|
|
218
|
+
|
|
219
|
+
```yaml
|
|
220
|
+
agents:
|
|
221
|
+
- name: intake
|
|
222
|
+
description: Takes the first message and routes the case to the right desk.
|
|
223
|
+
handoffs: [billing, technical]
|
|
224
|
+
- name: billing
|
|
225
|
+
description: Answers invoice and refund questions from the written policy.
|
|
226
|
+
handoffs: [intake] # the way home
|
|
227
|
+
- name: technical
|
|
228
|
+
description: Diagnoses faults from the logs and says what to do next.
|
|
229
|
+
handoffs: [intake]
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
- A list of bare agent names. There is no object form and no per-edge
|
|
233
|
+
configuration.
|
|
234
|
+
- Each name becomes one tool on this agent, `transfer_to_<name>`, described by
|
|
235
|
+
the **target's** `description:`. With none, the model gets a generic sentence
|
|
236
|
+
and `zen check` warns `agent.no-description`. Write it as a routing
|
|
237
|
+
condition, not a title: _"Applies the written peril policies to a claim and
|
|
238
|
+
explains the outcome"_, never _"The adjuster agent"_.
|
|
239
|
+
- `handoff.unknown` (an agent not declared) and `handoff.self` are load errors.
|
|
240
|
+
- `handoff.one-way` is a warning: an edge `A → B` with no path from B back to
|
|
241
|
+
A. Indirect counts - `B → C → A` is a way home - so every edge must lie on a
|
|
242
|
+
cycle. Without one, the first routed question is the last one routed.
|
|
243
|
+
|
|
244
|
+
### `fork:`
|
|
245
|
+
|
|
246
|
+
```yaml
|
|
247
|
+
agents:
|
|
248
|
+
- name: trunk
|
|
249
|
+
fork: true # any declared agent, any number of branches
|
|
250
|
+
|
|
251
|
+
- name: sweep
|
|
252
|
+
fork:
|
|
253
|
+
agents: [sweep, prober] # who a branch may run - itself included
|
|
254
|
+
maxBranches: 6
|
|
255
|
+
|
|
256
|
+
- name: asker
|
|
257
|
+
fork: { agents: [prober], maxBranches: 1 } # delegation, never a fan-out
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
| Written | Means |
|
|
261
|
+
| ------------------ | -------------------------------------------------------------------------------------------------------------------- |
|
|
262
|
+
| absent, or `false` | no `fork` tool, and `agents/fork-instructions.md` never reaches this agent |
|
|
263
|
+
| `true`, or `{}` | the tool, any declared agent, no cap |
|
|
264
|
+
| `agents: [a, b]` | a branch may run only these. The list is an `enum` on each branch's `agent` field, so another name cannot be decoded |
|
|
265
|
+
| `maxBranches: n` | at most `n` branches per call. `1` allows delegation and refuses fan-out |
|
|
266
|
+
|
|
267
|
+
- `agents` **may name the forking agent itself** - one role fanned out over
|
|
268
|
+
many items is the common shape, and unlike `handoffs:` it is not an error.
|
|
269
|
+
- A branch that leaves `agent` out runs the forking agent - but only when the
|
|
270
|
+
forking agent is in `agents`. When it is not, the model must name one.
|
|
271
|
+
- **A branch runs as its agent**: that agent's prompt, tools, memory binding,
|
|
272
|
+
skills, hand-offs and its own `fork:`. A hand-off inside a branch moves the
|
|
273
|
+
branch's conversation, never the parent's.
|
|
274
|
+
- Depth is not a key here. `maxForkDepth` (2 by default) is a run option; at
|
|
275
|
+
the cap the `fork` tool is withdrawn, and `agents/fork-instructions.md` with
|
|
276
|
+
it.
|
|
277
|
+
- Refused at load: `agents: []`, `maxBranches: 0`, and an `agents` entry not
|
|
278
|
+
declared (`fork.unknown`).
|
|
279
|
+
- `fork.uninstructed` is an error: an agent can fork and
|
|
280
|
+
`agents/fork-instructions.md` is missing or empty. `zen check --fix` writes it
|
|
281
|
+
back. That file is zen's - an edit in it is reported as `rules.stale` and lost
|
|
282
|
+
at the next `--fix`; project policy on forking goes in
|
|
283
|
+
`agents/fork-<topic>-instructions.md` (load **zen-instructions**).
|
|
@@ -16,23 +16,35 @@ Check which tools you actually have:
|
|
|
16
16
|
- If `write_file` and `apply_patch` are available, you may create and edit files
|
|
17
17
|
under `/workspace`.
|
|
18
18
|
|
|
19
|
-
##
|
|
19
|
+
## Finding files
|
|
20
20
|
|
|
21
|
-
Never guess a file's name, location, or contents.
|
|
21
|
+
Never guess a file's name, location, or contents. Pick the tool by what you know:
|
|
22
22
|
|
|
23
|
-
-
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
- **The directory** → `list_dir { path }`. One level, not recursive. Each file shows
|
|
24
|
+
`format`, `bytes` and, for text, `lines`, so you can decide what to read and how much
|
|
25
|
+
without opening it. Omit `path` (or give `/`) to list the mounted trees.
|
|
26
|
+
- **Part of the path** → `find_files { pattern, path? }`. `pattern` is **required**: a
|
|
27
|
+
plain, case-insensitive substring, never a glob or regex (`*.ts` matches nothing; write
|
|
28
|
+
`.ts`). It is matched against the path with its mount name (`/workspace`, `/assets`, …)
|
|
29
|
+
removed: `/workspace/src/a.ts` is matched as `src/a.ts`, so `src/` matches and
|
|
30
|
+
`/workspace/src` does not. To limit the search to one tree, pass it as `path`. Matches
|
|
31
|
+
come back as absolute paths.
|
|
32
|
+
- **Neither** → `list_dir` the root, then descend.
|
|
33
|
+
|
|
34
|
+
`find_files` matches paths, not contents. Both tools stop at 500 results and set
|
|
35
|
+
`truncated`: narrow the `pattern` or `path` rather than repeating the call.
|
|
26
36
|
|
|
27
37
|
## Reading files
|
|
28
38
|
|
|
29
|
-
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
-
|
|
35
|
-
|
|
39
|
+
- `read_file { path, start_line?, end_line? }`; lines are 1-based and inclusive. Read a
|
|
40
|
+
short file whole; for a long one (see `lines` from `list_dir`), read the range you need.
|
|
41
|
+
- The result gives the file's total `lines` and the `start_line`/`end_line` returned.
|
|
42
|
+
`truncated: true` means more follows `end_line` (your range or the 256 KB cap); continue
|
|
43
|
+
from `end_line + 1` only if you need it.
|
|
44
|
+
- A non-text file fails with its `format`. Do not retry; `copy_file` can still copy it.
|
|
45
|
+
- Check whether a target exists before writing to it.
|
|
46
|
+
|
|
47
|
+
When a tool returns `error` with a `hint`, act on the hint instead of repeating the call.
|
|
36
48
|
|
|
37
49
|
## Modifying files
|
|
38
50
|
|
|
@@ -69,6 +81,16 @@ Example patch:
|
|
|
69
81
|
Use `write_file` only to create a **new** file or to overwrite a small file completely.
|
|
70
82
|
Never use `write_file` to update an existing file when only a few lines need to change.
|
|
71
83
|
|
|
84
|
+
### Copying: `copy_file`
|
|
85
|
+
|
|
86
|
+
Use `copy_file` to duplicate a file, never `read_file` + `write_file`. The bytes skip the
|
|
87
|
+
conversation, so there is no size cap and binaries arrive intact.
|
|
88
|
+
|
|
89
|
+
- The source may be in a read-only mount; only the destination must be writable.
|
|
90
|
+
This is how something under `/assets`, `/skills` or `/memory` reaches `/workspace`.
|
|
91
|
+
- Set `overwrite: true` only when intentionally replacing an existing destination.
|
|
92
|
+
- Copying a directory and its contents requires `recursive: true`.
|
|
93
|
+
|
|
72
94
|
### Moving and deleting
|
|
73
95
|
|
|
74
96
|
- Use `move_file` to rename or relocate a file or directory. It creates parent directories
|
|
@@ -83,4 +105,4 @@ All file operations are confined to mounted trees:
|
|
|
83
105
|
(such as `/workspace/src/main.ts`) are where project files reside.
|
|
84
106
|
- `/assets`, `/skills`, `/memory`: Read-only mounts. You may read, list, and search them,
|
|
85
107
|
but you cannot write, move, or delete files inside them.
|
|
86
|
-
- Any attempt to reach outside these mounts fails with
|
|
108
|
+
- Any attempt to reach outside these mounts fails with a containment error.
|
|
@@ -48,6 +48,31 @@ the tool call.
|
|
|
48
48
|
Do not fork a sequence. Branches run at once and can exchange nothing, so a step
|
|
49
49
|
that needs the step before it has to stay in this conversation.
|
|
50
50
|
|
|
51
|
+
## When the assignment is yours
|
|
52
|
+
|
|
53
|
+
These rules reach a branch as well as the agent that forked it, and a branch
|
|
54
|
+
arrives in the middle of someone else's sentence. Your assignment comes to you
|
|
55
|
+
as the result of a `fork` call, because that is how the runtime delivers it —
|
|
56
|
+
and that is indistinguishable, in a transcript, from a fork you made yourself
|
|
57
|
+
coming back with an answer.
|
|
58
|
+
|
|
59
|
+
It is not one. When a message begins "You are branch ... of the fork above", you
|
|
60
|
+
are that branch and that text is your assignment:
|
|
61
|
+
|
|
62
|
+
- **Nothing has run yet.** There is no result in it and nothing to verify. The
|
|
63
|
+
fork it names is above in the conversation you were forked out of, which is
|
|
64
|
+
not the one you are in — yours begins with that message.
|
|
65
|
+
- **Do the work yourself.** Never fork a branch to carry out the assignment you
|
|
66
|
+
were handed: that branch is you one level down holding the same instructions,
|
|
67
|
+
it will read them the same way, and each level spends a whole system prompt to
|
|
68
|
+
arrive back where it started. At the depth cap the tool is withdrawn and the
|
|
69
|
+
work comes back undone.
|
|
70
|
+
- **Do not go looking for proof it was already done.** An empty workspace is
|
|
71
|
+
what an unstarted job looks like, not a sign that something failed upstream.
|
|
72
|
+
|
|
73
|
+
Fork from inside a branch only for work that is genuinely divisible further and
|
|
74
|
+
that you were not handed already divided.
|
|
75
|
+
|
|
51
76
|
## When it is worth it
|
|
52
77
|
|
|
53
78
|
One question decides it: **could this be finished by someone who cannot ask you
|
|
@@ -63,6 +88,8 @@ no, the work stays here.
|
|
|
63
88
|
| Find the config, then change it, then test it | Not a fork. Each step needs the one before it |
|
|
64
89
|
| A change you would want to steer while it happens | Not a fork. A branch cannot be corrected once it starts |
|
|
65
90
|
| One read, one search, one command | Not a fork. A whole conversation to save yourself a line |
|
|
91
|
+
| Twenty items one call already takes as a list | Not a fork. Pass the list |
|
|
92
|
+
| The assignment you were handed, whole | Not a fork. It is yours — see above |
|
|
66
93
|
| Two jobs that would write the same file | Not a fork until they write different files — see below |
|
|
67
94
|
|
|
68
95
|
## Fanning out
|
|
@@ -7,7 +7,8 @@ requires: [memory]
|
|
|
7
7
|
This project has a memory: a graph of what earlier runs worked out, kept with
|
|
8
8
|
the project rather than with the session, and shared with every other agent that
|
|
9
9
|
can see it. It is reached **only** through the `memory_*` tools - `memory_search`
|
|
10
|
-
to find, `memory_load` to
|
|
10
|
+
to find by meaning, `memory_grep` to find an exact string, `memory_load` to
|
|
11
|
+
read.
|
|
11
12
|
|
|
12
13
|
Not every agent may write to it. Read what follows against the tools you
|
|
13
14
|
actually have: if `memory_commit` is not among them, everything under
|
|
@@ -99,8 +100,9 @@ its own source.
|
|
|
99
100
|
## Reading it
|
|
100
101
|
|
|
101
102
|
`memory_search` hands back an outline of a subgraph with each node's text cut to
|
|
102
|
-
160 characters. `
|
|
103
|
-
|
|
103
|
+
160 characters. `memory_grep` hands back the nodes containing an exact string,
|
|
104
|
+
with the lines it matched on. `memory_load` is what reads a node whole, by id -
|
|
105
|
+
load anything you are going to rely on.
|
|
104
106
|
|
|
105
107
|
### The shape of a recollection
|
|
106
108
|
|
|
@@ -133,20 +135,52 @@ at that path through `memory_load`, never by looking around in the directory.
|
|
|
133
135
|
`vectors.json` and `manifest.json` - its internal format. Do not open, list,
|
|
134
136
|
grep, `cat` or `find` them, and do not point a shell command at that directory:
|
|
135
137
|
|
|
136
|
-
- it is ranked by **meaning**, so substring matching misses the hits;
|
|
137
138
|
- `graph.json` is every node ever committed, as one line;
|
|
138
139
|
- a raw read bypasses the audience mask and serves **superseded** nodes -
|
|
139
140
|
corrections that were withdrawn - as if they were current;
|
|
140
141
|
- it records no use, so the ranking that decides what gets recalled next decays;
|
|
141
142
|
- another run may be writing, and the manifest is written last.
|
|
142
143
|
|
|
144
|
+
**`memory_grep` is that search, done properly.** It reads every node exactly -
|
|
145
|
+
the text, the metadata and the bytes of remembered files - and hands back the
|
|
146
|
+
matching lines with the node they belong to. It applies the mask, it leaves out
|
|
147
|
+
what has been superseded unless you ask for it, and it names any file it could
|
|
148
|
+
not read, so a file that went unsearched never passes for one with no match.
|
|
149
|
+
|
|
143
150
|
A memory is a record, not an authority - but checking one is not the same as
|
|
144
|
-
redoing it
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
151
|
+
redoing it, and how you check depends on where its content came from.
|
|
152
|
+
**Pinned** - a released spec, a versioned document: its content cannot have
|
|
153
|
+
moved, so use what the node says and check only that the route still resolves.
|
|
154
|
+
**Living** - code, an API, anything that changes: confirm the named lines still
|
|
155
|
+
say what the node says, the route still resolves, the command still exists.
|
|
156
|
+
Work it out from nothing only when that check fails, or when being wrong is
|
|
157
|
+
expensive. A check that costs what the original investigation cost is not a
|
|
158
|
+
check - it is the investigation again, and the memory bought nothing.
|
|
159
|
+
|
|
160
|
+
### None of it appears in an answer
|
|
161
|
+
|
|
162
|
+
The store is your apparatus, not your subject. An answer says what was found and
|
|
163
|
+
where it can be checked - the sources, the commands, the files the work left
|
|
164
|
+
behind. It never says that a recollection was what put you on to them.
|
|
165
|
+
|
|
166
|
+
Never write `/memory`, a node id, or the words "memory", "recalled" or
|
|
167
|
+
"remembered" into an answer. Read your text before you send it: if it holds
|
|
168
|
+
`/memory` or a node id, cut the sentence around it and say what was done
|
|
169
|
+
instead. "Loaded the script from memory (`/memory/01J….py`) and ran it" is
|
|
170
|
+
"ran `<path>`" with your working left in by mistake.
|
|
171
|
+
|
|
172
|
+
Two reasons, and both hold even where the reader would find it interesting. A
|
|
173
|
+
node id names nothing the reader can open, so it reads as a citation and cannot
|
|
174
|
+
be followed; and it stops being true the moment the node is superseded, while
|
|
175
|
+
the source it was drawn from does not. Cite the source, never the memory of it.
|
|
176
|
+
|
|
177
|
+
This binds on a branch's answer exactly as it binds on the final one. A branch
|
|
178
|
+
rejoins as a single result that the agent above writes its own answer from, so
|
|
179
|
+
an id that survives the join is an id in the reply.
|
|
180
|
+
|
|
181
|
+
The one exception is a question about the store itself - what is known about
|
|
182
|
+
something, whether it was seen before, what to forget. Then it is the subject,
|
|
183
|
+
and ids are what the reader needs.
|
|
150
184
|
|
|
151
185
|
## Searching it
|
|
152
186
|
|
|
@@ -177,8 +211,34 @@ would use - node texts are written to be found that way. Narrow with `kinds`,
|
|
|
177
211
|
`newer_than`, `limit`, `max_hops` and `max_nodes` when a recollection comes back
|
|
178
212
|
broad rather than wrong.
|
|
179
213
|
|
|
214
|
+
### Which of the two
|
|
215
|
+
|
|
216
|
+
`memory_search` ranks, so it returns what is closest and stops. That makes it
|
|
217
|
+
right for a question and wrong for a fact about the store itself - whether one
|
|
218
|
+
exact name, path or command was ever written down. An empty search on a
|
|
219
|
+
question is still the answer to that question: it matched by meaning, so other
|
|
220
|
+
wordings of the same question were covered. Do not follow it with a
|
|
221
|
+
`memory_grep` for words taken from the question.
|
|
222
|
+
|
|
223
|
+
`memory_grep` is exact and complete. Reach for it when the thing you are looking
|
|
224
|
+
for is a **string** rather than a subject, and when the answer has to be all of
|
|
225
|
+
them:
|
|
226
|
+
|
|
227
|
+
| Looking for | Use |
|
|
228
|
+
| --------------------------------------------------------------- | --------------- |
|
|
229
|
+
| what was learned about a subject, however it was phrased | `memory_search` |
|
|
230
|
+
| a name, path, id, host, flag or command, spelled exactly | `memory_grep` |
|
|
231
|
+
| whether an exact name, path or command was written down at all | `memory_grep` |
|
|
232
|
+
| everywhere a thing is mentioned, before changing or retiring it | `memory_grep` |
|
|
233
|
+
| a starting point, when you do not yet know the vocabulary | `memory_search` |
|
|
234
|
+
|
|
235
|
+
Either way, ids from one are ids for the other: grep a name, then `memory_load`
|
|
236
|
+
what it turned up.
|
|
237
|
+
|
|
180
238
|
Recalling nothing is not proof of anything: work it out normally, then commit
|
|
181
|
-
the result so the next run does not repeat it.
|
|
239
|
+
the result so the next run does not repeat it. A `memory_grep` that found
|
|
240
|
+
nothing is stronger - it means the string is not there - but it says nothing
|
|
241
|
+
about the subject under another name.
|
|
182
242
|
|
|
183
243
|
## Updating it
|
|
184
244
|
|
|
@@ -199,6 +259,12 @@ five paths.
|
|
|
199
259
|
| The passage itself, when its source cannot change under you | A passage quoted out of something that can |
|
|
200
260
|
| A proven absence - looked here and here, it is not there | Anything not actually verified |
|
|
201
261
|
|
|
262
|
+
A restatement is not merely wasted space. Recall seeds on text alone, so a run
|
|
263
|
+
that commits its own request as a task, a plan and a result has committed three
|
|
264
|
+
near-copies of one sentence - and on the next similar question those three take
|
|
265
|
+
the seed slots between them. Everything actually learned then ranks below them
|
|
266
|
+
and is never reached.
|
|
267
|
+
|
|
202
268
|
A search over a schema or a documentation index costs a round trip and comes
|
|
203
269
|
back ranked, so it is the thing most worth not paying for twice. Commit what it
|
|
204
270
|
**resolved to** - the operation and its shape, or the document, heading and line
|
|
@@ -210,7 +276,8 @@ When the index is over something pinned - a released spec, a versioned reference
|
|
|
210
276
|
tree - go one further and carry the passage itself in a `file` node, headed with
|
|
211
277
|
the documents and line ranges it was taken from. The pointer says where to look
|
|
212
278
|
and the conclusion says what it meant, but only the passage saves the next run
|
|
213
|
-
from opening the sources to find out what they actually said.
|
|
279
|
+
from opening the sources to find out what they actually said. Say in the node's
|
|
280
|
+
text which kind of source it was, so a later run can see why a copy was allowed.
|
|
214
281
|
|
|
215
282
|
### When to commit
|
|
216
283
|
|
|
@@ -270,6 +337,25 @@ already in memory says is folded into it, and its existing id comes back under
|
|
|
270
337
|
your ref - so the links you asked for still land, on the memory that was already
|
|
271
338
|
there.
|
|
272
339
|
|
|
340
|
+
**Take the task text you were handed.** When your instructions give you the
|
|
341
|
+
task text, commit that text verbatim as your `task` node and look nothing up for
|
|
342
|
+
it. Agents that commit at the same moment cannot see each other; identical
|
|
343
|
+
wording is what folds their nodes into one.
|
|
344
|
+
|
|
345
|
+
**Grep for an entity before minting a node for it.** An endpoint, a command, a
|
|
346
|
+
host, a tool, a file - anything that recurs across runs is one node the rest of
|
|
347
|
+
the graph hangs off, and folding by similarity will not catch a second copy
|
|
348
|
+
worded differently. `memory_grep` the exact string first, and attach your edges
|
|
349
|
+
to what comes back. One grep per entity you are about to mint, for its exact
|
|
350
|
+
string. A sentence describing the subject is not an entity, and neither is a
|
|
351
|
+
task's text: a literal phrase misses every other wording of it, and a
|
|
352
|
+
near-duplicate is folded anyway.
|
|
353
|
+
|
|
354
|
+
A duplicated hub is worse than a missing one. It splits the graph into islands:
|
|
355
|
+
the question reaches one copy, the artifact that answers it hangs off another,
|
|
356
|
+
and the walk out from a seed cannot cross between them - so a memory that is
|
|
357
|
+
present returns nothing, and nothing in the recollection says it happened.
|
|
358
|
+
|
|
273
359
|
**Say where the content came from.** This is what lets an incomplete
|
|
274
360
|
recollection be continued instead of believed:
|
|
275
361
|
|
|
@@ -305,18 +391,11 @@ whole of what you know is one line long.
|
|
|
305
391
|
**The file must exist in the workspace first.** `memory_commit` copies an
|
|
306
392
|
existing file from the workspace; it is not an upload channel and does not
|
|
307
393
|
write file contents from raw arguments. Write the file to the workspace first
|
|
308
|
-
(using `write_file`, `apply_patch`, or a command saving under
|
|
309
|
-
then pass its workspace path (e.g. `"file": "report.py"` or
|
|
310
|
-
`"file": "/workspace/report.py"`).
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
| ---------------------- | -------------------------------------------------------------------------- |
|
|
314
|
-
| Working scripts | A script, query or invocation that can be re-run directly |
|
|
315
|
-
| Configurations & specs | Self-contained config files, schemas or request templates |
|
|
316
|
-
| Rendered findings | A table of findings or structured report produced by an investigation |
|
|
317
|
-
| Pinned reference text | Verbatim passages from released specs or versioned docs that cannot change |
|
|
318
|
-
| Assembled answers | Synthesised conclusions from multiple sources with a provenance header |
|
|
319
|
-
| Specimen responses | An API response shape to reproduce against (never raw secrets) |
|
|
394
|
+
(using `write_file`, `apply_patch`, `copy_file`, or a command saving under
|
|
395
|
+
`/workspace`), then pass its workspace path (e.g. `"file": "report.py"` or
|
|
396
|
+
`"file": "/workspace/report.py"`). Write it with its provenance header (below)
|
|
397
|
+
the first time: adding the header in a second write pays for the whole file
|
|
398
|
+
twice.
|
|
320
399
|
|
|
321
400
|
Do not commit files from the living codebase (use a pointer with file and line
|
|
322
401
|
ranges instead - copies go stale silently), raw ephemeral command logs, or
|
|
@@ -371,16 +450,9 @@ the point; the rows it emitted do not.
|
|
|
371
450
|
|
|
372
451
|
Two things fall outside that. An answer you assembled from several sources is a
|
|
373
452
|
copy of none of them and exists nowhere in the project, so commit it, with a
|
|
374
|
-
pointer node per source `INFORMED`ing it. And a
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
When it is kept whole, keep it as a `file` node rather than as a longer `text`:
|
|
379
|
-
the text says what the passage establishes and names the documents it came from,
|
|
380
|
-
the file carries the whole block behind its provenance header. Say in the text
|
|
381
|
-
which kind of source it was, so a later run can see why a copy was allowed. A
|
|
382
|
-
pointer alone, with nothing of what the source said, makes the next run open all
|
|
383
|
-
of it again - which is the reading the memory was supposed to buy.
|
|
453
|
+
pointer node per source `INFORMED`ing it. And a passage from a pinned source
|
|
454
|
+
does not go stale silently, so it may be kept whole, as described for indexes
|
|
455
|
+
above.
|
|
384
456
|
|
|
385
457
|
A body or a result set may still be worth keeping as a SPECIMEN - a shape to
|
|
386
458
|
write against, a case to reproduce. Commit it as a `file` node whose text says
|