@zenera/cli 1.1.21 → 1.1.22
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 +3 -3
- package/dist/banner.d.ts +33 -24
- package/dist/banner.js +25 -6
- package/dist/commands/check.js +1 -0
- package/dist/commands/init.js +1 -0
- package/dist/commands/inspect.js +1 -0
- package/dist/commands/key.js +1 -0
- package/dist/commands/list.js +1 -0
- package/dist/commands/memory.js +1 -0
- package/dist/commands/open.js +1 -0
- package/dist/commands/run.js +3 -0
- package/dist/commands/sandbox.js +1 -0
- package/dist/commands/version.js +1 -0
- package/dist/lib.d.ts +2 -1
- package/dist/lib.js +2 -1
- package/dist/meta.d.ts +1 -1
- package/dist/meta.js +5 -28
- package/dist/resolve.js +19 -12
- package/dist/sandbox.js +1 -0
- package/dist/scaffold.js +3 -1
- package/dist/term.d.ts +2 -0
- package/dist/term.js +2 -0
- package/dist/tui/markdown.d.ts +16 -0
- package/dist/tui/markdown.js +259 -0
- package/dist/tui/theme.js +1 -1
- package/dist/tui/wrap.d.ts +1 -1
- package/dist/validate.js +82 -3
- package/package.json +2 -2
- package/templates/editor/.github/copilot-instructions.md +62 -33
- package/templates/editor/.github/prompts/spec-sync-project.prompt.md +31 -1
- package/templates/editor/.github/skills/zen-cli/SKILL.md +15 -15
- package/templates/editor/.github/skills/zen-cli/references/projects.md +1 -0
- package/templates/editor/.github/skills/zen-cli/references/rag.md +37 -3
- package/templates/editor/.github/skills/zen-cli/references/sandbox.md +30 -2
- package/templates/editor/.github/skills/zen-instructions/SKILL.md +232 -0
- package/templates/editor/.github/skills/zen-memory-warmup/SKILL.md +554 -0
- package/templates/editor/.github/skills/zen-rag-docs/SKILL.md +56 -23
- package/templates/editor/.github/skills/zen-rag-schema/SKILL.md +55 -28
- package/templates/editor/.github/skills/zen-review/SKILL.md +17 -1
- package/templates/editor/.github/skills/zen-sandbox/SKILL.md +257 -0
- package/templates/editor/.github/skills/zen-spec-sync/SKILL.md +15 -3
- package/templates/editor/.vscode/agents.schema.json +8 -3
- package/templates/project/SPECIFICATION.md.tmpl +2 -1
- package/templates/project/agents/files-instructions.md +86 -0
- package/templates/project/agents/fork-instructions.md +17 -0
- package/templates/project/agents/memory-instructions.md +37 -0
- package/templates/project/agents.yaml.tmpl +3 -3
- package/templates/project/gitignore +12 -1
- package/templates/project/scripts/_setup.sh +19 -4
|
@@ -0,0 +1,554 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: zen-memory-warmup
|
|
3
|
+
description: Pre-populating an agent project's memory graph through warm-up queries before production or deployment — isolating scratch memory and workspaces in timestamped .tmp directories, using stronger reasoning models, validating machine-readable JSON output, categorizing queries with limits, shuffling, and dry-run execution, inspecting the graph with zen memory stats/ls, atomic promotion into the project, and generating automated population scripts in scripts/memory_warmup.sh.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Memory Warmup
|
|
7
|
+
|
|
8
|
+
Memory warmup is the process of pre-populating an agent project's knowledge graph
|
|
9
|
+
before deploying it or exposing it to end users.
|
|
10
|
+
|
|
11
|
+
In Zenera Neo, an agent's memory graph (`memory/`) starts completely empty. A cold
|
|
12
|
+
start means early runs cannot recall prior approaches, domain facts, verified
|
|
13
|
+
plans, or tool schemas. Warming up the memory addresses this by executing a
|
|
14
|
+
curated set of representative domain queries ahead of time, allowing agents to
|
|
15
|
+
synthesize, connect, and commit high-value knowledge nodes.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Why Warm Up Memory?
|
|
20
|
+
|
|
21
|
+
1. **Eliminate Cold Starts**: Instead of failing or struggling through initial
|
|
22
|
+
discovery, the agent recalls established patterns, known schemas, and
|
|
23
|
+
proven plans on its very first user-facing turn.
|
|
24
|
+
2. **Higher-Quality Graph via Stronger Models**: You can run warmup turns using
|
|
25
|
+
a more capable reasoning model (`--model`) than your day-to-day runtime
|
|
26
|
+
model. A smarter model creates cleaner abstractions, links causal relations
|
|
27
|
+
accurately, and produces superior plans.
|
|
28
|
+
3. **Consistency & Alignment**: Foundational conventions, domain boundaries,
|
|
29
|
+
and operational rules are seeded as durable `fact` and `plan` nodes rather
|
|
30
|
+
than rediscovered inconsistently across random user sessions.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Core Architecture & Safety Rules
|
|
35
|
+
|
|
36
|
+
Warmup is an offline staging process. It must adhere to five safety rules:
|
|
37
|
+
|
|
38
|
+
### 1. Never warm up directly into the project's active `memory/`
|
|
39
|
+
|
|
40
|
+
If a warmup query fails, hallucinates, or aborts mid-turn, committing directly
|
|
41
|
+
to the project's memory directory corrupts the knowledge graph. Always point
|
|
42
|
+
`zen run` to a timestamped staging directory in `.tmp/` via `--memory` so that
|
|
43
|
+
repeated or concurrent runs never collide:
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
STAMP="$(date +%Y%m%d-%H%M%S)"
|
|
47
|
+
--memory ".tmp/warmup-$STAMP/memory"
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### 2. Isolate workspaces in `.tmp/` with per-run timestamps
|
|
51
|
+
|
|
52
|
+
Warmup queries often instruct agents to investigate repositories, write test
|
|
53
|
+
scripts, or run commands. Running them in the actual project or repository
|
|
54
|
+
working directory risks modifying tracked files or creating untracked clutter.
|
|
55
|
+
|
|
56
|
+
Always isolate the workspace per run into a fresh, timestamped subdirectory
|
|
57
|
+
under `.tmp/`:
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
--workspace ".tmp/warmup-$STAMP/workspaces/run-01-$(date +%s)"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Using timestamps on both the root staging directory and each individual run
|
|
64
|
+
workspace ensures:
|
|
65
|
+
|
|
66
|
+
- Concurrent or repeated warmup attempts never overwrite each other's state.
|
|
67
|
+
- Stale or corrupted files from an earlier failed run cannot leak into subsequent
|
|
68
|
+
queries.
|
|
69
|
+
- Every turn begins from a completely pristine, deterministic working directory.
|
|
70
|
+
|
|
71
|
+
### 3. Use stronger models during population
|
|
72
|
+
|
|
73
|
+
Day-to-day execution might use a fast, cost-effective model (e.g.
|
|
74
|
+
`google:gemini-2.5-flash` or `anthropic:claude-3-5-haiku`). Warmup runs are
|
|
75
|
+
performed infrequently, so it makes sense to use a flagship reasoning model
|
|
76
|
+
(e.g. `anthropic:claude-sonnet-4-5`, `openai:gpt-5`, or
|
|
77
|
+
`google:gemini-3.5-flash`):
|
|
78
|
+
|
|
79
|
+
```sh
|
|
80
|
+
--model anthropic:claude-sonnet-4-5
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The superior graph structure created by the flagship model is then recalled and
|
|
84
|
+
utilized by the runtime model.
|
|
85
|
+
|
|
86
|
+
### 4. Execute non-interactively with `--json`
|
|
87
|
+
|
|
88
|
+
Using `--json` guarantees:
|
|
89
|
+
|
|
90
|
+
- Interactive TUI and confirmation prompts are disabled (assumes `--yes`).
|
|
91
|
+
- Progress narration on stderr is silenced.
|
|
92
|
+
- Machine-readable JSON output on stdout containing `stopReason`, `usage`,
|
|
93
|
+
`mounts`, run artifact paths (`run.dir`, `run.output`), and the answer.
|
|
94
|
+
- The population script can programmatically verify whether the run finished
|
|
95
|
+
successfully (`stopReason === "final"`).
|
|
96
|
+
|
|
97
|
+
### 5. Validate before promotion
|
|
98
|
+
|
|
99
|
+
Track graph accumulation by inspecting `zen memory stats --dir ...` in between
|
|
100
|
+
warmup queries, and do not overwrite the project's `memory/` until the final
|
|
101
|
+
graph in `.tmp/warmup-<timestamp>/memory` has been verified to contain expected
|
|
102
|
+
nodes and vector embeddings.
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## The Warmup Cycle
|
|
107
|
+
|
|
108
|
+
```mermaid
|
|
109
|
+
flowchart TD
|
|
110
|
+
A[Curated Seed Queries] --> B["Initialize .tmp/warmup-<timestamp>/memory"]
|
|
111
|
+
B --> C["For each query: Create fresh .tmp/warmup-<timestamp>/workspaces/run-N-<timestamp>"]
|
|
112
|
+
C --> D["zen run --memory .tmp/warmup-<timestamp>/memory --workspace .tmp/.../run-N-<timestamp> --model <model> --json"]
|
|
113
|
+
D --> E{Check stopReason & exit code}
|
|
114
|
+
E -- Success --> F[Accumulate nodes in staging graph]
|
|
115
|
+
E -- Failure --> G[Log error & abort or retry]
|
|
116
|
+
F --> T["Log timing: query duration & total elapsed"]
|
|
117
|
+
T --> S["Inspect progress: zen memory stats --dir .tmp/warmup-<timestamp>/memory"]
|
|
118
|
+
S --> H{More queries?}
|
|
119
|
+
H -- Yes --> C
|
|
120
|
+
H -- No --> I["Validate: zen memory stats --dir .tmp/warmup-<timestamp>/memory"]
|
|
121
|
+
I --> J{Graph healthy?}
|
|
122
|
+
J -- Yes --> K["Backup existing memory & promote .tmp/warmup-<timestamp>/memory to memory/"]
|
|
123
|
+
J -- No --> L[Inspect with zen memory ls / export & discard]
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Query Categories, Sampling & Dry-Run Preview
|
|
129
|
+
|
|
130
|
+
Warmup suites should be organized across distinct domain categories rather than
|
|
131
|
+
an unstructured flat list of ad-hoc prompts.
|
|
132
|
+
|
|
133
|
+
### Recommended Categories
|
|
134
|
+
|
|
135
|
+
| Category | Objective | Example Prompt |
|
|
136
|
+
| :------------- | :----------------------------------------------------------- | :------------------------------------------------------------------------- |
|
|
137
|
+
| `architecture` | Map high-level layout, component boundaries, and data flow | "Investigate project architecture and summarize component flow." |
|
|
138
|
+
| `workflows` | Formulate multi-step operational plans for common tasks | "Formulate standard operational plans for triaging common tasks." |
|
|
139
|
+
| `integrations` | Index external services, APIs, and credentials | "Identify external services, APIs, and key credential dependencies." |
|
|
140
|
+
| `errors` | Capture error handling, recovery routines, and failure modes | "Analyze error handling strategies, recovery routines, and failure modes." |
|
|
141
|
+
| `conventions` | Record coding styles, house rules, and constraints | "Document project-specific coding standards and house rules." |
|
|
142
|
+
|
|
143
|
+
### Why Sampling, Shuffling, and Limits Matter
|
|
144
|
+
|
|
145
|
+
1. **Balanced Graph Coverage**: If a warmup suite contains 20+ queries, running
|
|
146
|
+
them sequentially with a limit (e.g. `--limit 4`) would only execute the
|
|
147
|
+
first category (`architecture`), leaving workflows and integrations
|
|
148
|
+
completely cold.
|
|
149
|
+
2. **`--shuffle`**: Randomizes the query sequence before limits are applied,
|
|
150
|
+
ensuring that a limited budget run draws an even cross-section across
|
|
151
|
+
different categories.
|
|
152
|
+
3. **`--category <name>`**: Enables focused warmup on a single subsystem (e.g.
|
|
153
|
+
warming up only `integrations` after adding new API capabilities).
|
|
154
|
+
4. **`--limit <n>`**: Prevents unintended token expenditure by capping the total
|
|
155
|
+
number of queries executed during test or verification passes.
|
|
156
|
+
|
|
157
|
+
### Dry Run Mode (`--dry-run`)
|
|
158
|
+
|
|
159
|
+
Warming up memory with frontier reasoning models (`--model`) can be resource
|
|
160
|
+
intensive. A `--dry-run` flag is essential for:
|
|
161
|
+
|
|
162
|
+
- Verifying resolved staging paths and backup targets.
|
|
163
|
+
- Inspecting which queries and categories were selected after filtering,
|
|
164
|
+
shuffling, and limits.
|
|
165
|
+
- Checking the exact `zen run ...` commands that would be executed.
|
|
166
|
+
- Guaranteeing that zero files are written, zero directories are created, and
|
|
167
|
+
zero model tokens are billed.
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Generating the Warmup Script in `scripts/`
|
|
172
|
+
|
|
173
|
+
A project should maintain a dedicated warmup script located in `scripts/`
|
|
174
|
+
(e.g. `scripts/memory_warmup.sh` or `scripts/memory-warmup.sh`).
|
|
175
|
+
|
|
176
|
+
The script should automate the entire pipeline:
|
|
177
|
+
|
|
178
|
+
1. Accept command-line flags:
|
|
179
|
+
- `--dry-run`: Preview selected queries, categories, and commands without executing.
|
|
180
|
+
- `--limit <n>`: Run at most $n$ queries.
|
|
181
|
+
- `--shuffle`: Randomize query order before applying limits.
|
|
182
|
+
- `--category <name>`: Filter queries to a specific category.
|
|
183
|
+
- `--model <provider:model>`: Override model with a reasoning flagship.
|
|
184
|
+
- `--incremental`: Copy existing project memory into staging before warming up.
|
|
185
|
+
- `-y`, `--yes`: Promote memory without interactive confirmation.
|
|
186
|
+
2. Create timestamped staging paths under `.tmp/` (e.g.
|
|
187
|
+
`.tmp/warmup-$(date +%Y%m%d-%H%M%S)/`) and timestamped per-query workspaces.
|
|
188
|
+
3. Filter, shuffle, and sample from categorized query definitions.
|
|
189
|
+
4. If `--dry-run` is active, print the execution plan and exit 0 before touching disk.
|
|
190
|
+
5. Invoke `zen run` with `--memory`, `--workspace`, `--model`, and `--json`.
|
|
191
|
+
6. Parse each outcome with `jq`, halt if a turn fails, and report per-query execution time and total elapsed time since start.
|
|
192
|
+
7. Print graph statistics via `zen memory stats --dir ...` between queries to track graph growth, followed by a final validation.
|
|
193
|
+
8. Safely backup and replace the project's `memory/` directory with the warmed graph.
|
|
194
|
+
|
|
195
|
+
### Recommended Script Template (`scripts/memory_warmup.sh`)
|
|
196
|
+
|
|
197
|
+
When generating a warmup script for a project, use the following production-ready
|
|
198
|
+
pattern:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
#!/usr/bin/env bash
|
|
202
|
+
#
|
|
203
|
+
# scripts/memory_warmup.sh — Pre-populate project memory using curated seed queries.
|
|
204
|
+
#
|
|
205
|
+
# Usage:
|
|
206
|
+
# ./scripts/memory_warmup.sh [options]
|
|
207
|
+
#
|
|
208
|
+
# Options:
|
|
209
|
+
# --dry-run Preview selected queries and commands without executing
|
|
210
|
+
# --limit <n> Maximum number of queries to run
|
|
211
|
+
# --shuffle Randomize query order before applying limits
|
|
212
|
+
# --category <name> Filter queries to a specific category
|
|
213
|
+
# --model <ref> Override model (e.g. anthropic:claude-sonnet-4-5)
|
|
214
|
+
# --incremental Seed staging memory with current memory/ before runs
|
|
215
|
+
# -y, --yes Assume yes for memory promotion
|
|
216
|
+
# -h, --help Show this help
|
|
217
|
+
#
|
|
218
|
+
# Examples:
|
|
219
|
+
# ./scripts/memory_warmup.sh --dry-run
|
|
220
|
+
# ./scripts/memory_warmup.sh --dry-run --category workflows --limit 2
|
|
221
|
+
# ./scripts/memory_warmup.sh --shuffle --limit 5 --model anthropic:claude-sonnet-4-5
|
|
222
|
+
# ./scripts/memory_warmup.sh --incremental
|
|
223
|
+
#
|
|
224
|
+
|
|
225
|
+
set -euo pipefail
|
|
226
|
+
|
|
227
|
+
# Find project root regardless of invocation directory
|
|
228
|
+
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
229
|
+
cd "$ROOT"
|
|
230
|
+
|
|
231
|
+
# Default configuration
|
|
232
|
+
MODEL="${ZEN_WARMUP_MODEL:-}"
|
|
233
|
+
INCREMENTAL=false
|
|
234
|
+
ASSUME_YES=false
|
|
235
|
+
DRY_RUN=false
|
|
236
|
+
LIMIT=0
|
|
237
|
+
SHUFFLE=false
|
|
238
|
+
CATEGORY_FILTER=""
|
|
239
|
+
|
|
240
|
+
# Helper to format seconds as human-readable duration
|
|
241
|
+
format_duration() {
|
|
242
|
+
local total_sec=$1
|
|
243
|
+
local hours=$((total_sec / 3600))
|
|
244
|
+
local mins=$(((total_sec % 3600) / 60))
|
|
245
|
+
local secs=$((total_sec % 60))
|
|
246
|
+
if [ $hours -gt 0 ]; then
|
|
247
|
+
echo "${hours}h ${mins}m ${secs}s"
|
|
248
|
+
elif [ $mins -gt 0 ]; then
|
|
249
|
+
echo "${mins}m ${secs}s"
|
|
250
|
+
else
|
|
251
|
+
echo "${secs}s"
|
|
252
|
+
fi
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
# Parse arguments
|
|
256
|
+
while [[ $# -gt 0 ]]; do
|
|
257
|
+
case "$1" in
|
|
258
|
+
--dry-run)
|
|
259
|
+
DRY_RUN=true
|
|
260
|
+
shift
|
|
261
|
+
;;
|
|
262
|
+
--limit)
|
|
263
|
+
LIMIT="$2"
|
|
264
|
+
shift 2
|
|
265
|
+
;;
|
|
266
|
+
--shuffle)
|
|
267
|
+
SHUFFLE=true
|
|
268
|
+
shift
|
|
269
|
+
;;
|
|
270
|
+
--category)
|
|
271
|
+
CATEGORY_FILTER="$2"
|
|
272
|
+
shift 2
|
|
273
|
+
;;
|
|
274
|
+
--model)
|
|
275
|
+
MODEL="$2"
|
|
276
|
+
shift 2
|
|
277
|
+
;;
|
|
278
|
+
--incremental)
|
|
279
|
+
INCREMENTAL=true
|
|
280
|
+
shift
|
|
281
|
+
;;
|
|
282
|
+
-y|--yes)
|
|
283
|
+
ASSUME_YES=true
|
|
284
|
+
shift
|
|
285
|
+
;;
|
|
286
|
+
-h|--help)
|
|
287
|
+
echo "Usage: ./scripts/memory_warmup.sh [options]"
|
|
288
|
+
echo ""
|
|
289
|
+
echo "Options:"
|
|
290
|
+
echo " --dry-run Preview selected queries and commands without executing"
|
|
291
|
+
echo " --limit <n> Maximum number of queries to run"
|
|
292
|
+
echo " --shuffle Randomize query order before applying limits"
|
|
293
|
+
echo " --category <name> Filter queries to a specific category"
|
|
294
|
+
echo " --model <ref> Override model (e.g. anthropic:claude-sonnet-4-5)"
|
|
295
|
+
echo " --incremental Seed staging memory with current memory/ before runs"
|
|
296
|
+
echo " -y, --yes Assume yes for memory promotion"
|
|
297
|
+
echo " -h, --help Show this help"
|
|
298
|
+
exit 0
|
|
299
|
+
;;
|
|
300
|
+
*)
|
|
301
|
+
echo "Error: Unknown option $1" >&2
|
|
302
|
+
exit 2
|
|
303
|
+
;;
|
|
304
|
+
esac
|
|
305
|
+
done
|
|
306
|
+
|
|
307
|
+
STAMP="$(date +%Y%m%d-%H%M%S)"
|
|
308
|
+
SCRATCH_DIR=".tmp/warmup-$STAMP"
|
|
309
|
+
STAGING_MEM="$SCRATCH_DIR/memory"
|
|
310
|
+
WORKSPACES_DIR="$SCRATCH_DIR/workspaces"
|
|
311
|
+
PROJECT_MEM="memory"
|
|
312
|
+
|
|
313
|
+
# Define curated seed queries structured by category ("category|prompt")
|
|
314
|
+
ALL_QUERIES=(
|
|
315
|
+
"architecture|Investigate the project architecture and summarize the main components and data flow."
|
|
316
|
+
"architecture|Analyze module boundaries, dependency graphs, and core interfaces."
|
|
317
|
+
"workflows|Formulate standard operational plans for triaging and resolving common domain tasks."
|
|
318
|
+
"workflows|Trace the end-to-end user request lifecycle and hand-off points."
|
|
319
|
+
"integrations|Identify external services, APIs, and key credential dependencies."
|
|
320
|
+
"integrations|Verify database and storage schemas, access patterns, and persistence rules."
|
|
321
|
+
"errors|Analyze error handling strategies, recovery routines, and failure modes."
|
|
322
|
+
"errors|Identify retry policies, rate limits, and fallback behaviors."
|
|
323
|
+
"conventions|Document project-specific coding standards, house rules, and commit policies."
|
|
324
|
+
)
|
|
325
|
+
|
|
326
|
+
# 1. Filter by category if requested
|
|
327
|
+
FILTERED=()
|
|
328
|
+
for item in "${ALL_QUERIES[@]}"; do
|
|
329
|
+
cat="${item%%|*}"
|
|
330
|
+
if [ -z "$CATEGORY_FILTER" ] || [ "$cat" = "$CATEGORY_FILTER" ]; then
|
|
331
|
+
FILTERED+=("$item")
|
|
332
|
+
fi
|
|
333
|
+
done
|
|
334
|
+
|
|
335
|
+
if [ ${#FILTERED[@]} -eq 0 ]; then
|
|
336
|
+
echo "Error: No queries matched category '$CATEGORY_FILTER'." >&2
|
|
337
|
+
exit 1
|
|
338
|
+
fi
|
|
339
|
+
|
|
340
|
+
# 2. Shuffle if requested
|
|
341
|
+
if [ "$SHUFFLE" = true ]; then
|
|
342
|
+
TEMP=()
|
|
343
|
+
if command -v python3 >/dev/null 2>&1; then
|
|
344
|
+
while IFS= read -r line; do
|
|
345
|
+
[ -n "$line" ] && TEMP+=("$line")
|
|
346
|
+
done < <(printf '%s\n' "${FILTERED[@]}" | python3 -c 'import sys, random; lines = [l for l in sys.stdin.read().splitlines() if l]; random.shuffle(lines); print("\n".join(lines))')
|
|
347
|
+
elif command -v shuf >/dev/null 2>&1; then
|
|
348
|
+
while IFS= read -r line; do
|
|
349
|
+
[ -n "$line" ] && TEMP+=("$line")
|
|
350
|
+
done < <(printf '%s\n' "${FILTERED[@]}" | shuf)
|
|
351
|
+
elif sort -R </dev/null >/dev/null 2>&1; then
|
|
352
|
+
while IFS= read -r line; do
|
|
353
|
+
[ -n "$line" ] && TEMP+=("$line")
|
|
354
|
+
done < <(printf '%s\n' "${FILTERED[@]}" | sort -R)
|
|
355
|
+
else
|
|
356
|
+
TEMP=("${FILTERED[@]}")
|
|
357
|
+
fi
|
|
358
|
+
FILTERED=("${TEMP[@]}")
|
|
359
|
+
fi
|
|
360
|
+
|
|
361
|
+
# 3. Apply limit if requested
|
|
362
|
+
SELECTED=()
|
|
363
|
+
if [ "$LIMIT" -gt 0 ] && [ "$LIMIT" -lt "${#FILTERED[@]}" ]; then
|
|
364
|
+
for ((i = 0; i < LIMIT; i++)); do
|
|
365
|
+
SELECTED+=("${FILTERED[i]}")
|
|
366
|
+
done
|
|
367
|
+
else
|
|
368
|
+
SELECTED=("${FILTERED[@]}")
|
|
369
|
+
fi
|
|
370
|
+
|
|
371
|
+
# 4. Handle Dry Run mode
|
|
372
|
+
if [ "$DRY_RUN" = true ]; then
|
|
373
|
+
echo "=== DRY RUN: Previewing Warmup Plan ==="
|
|
374
|
+
echo "Project root: $ROOT"
|
|
375
|
+
echo "Staging memory: $STAGING_MEM"
|
|
376
|
+
echo "Target memory: $PROJECT_MEM"
|
|
377
|
+
echo "Model override: ${MODEL:-<default>}"
|
|
378
|
+
echo "Category filter: ${CATEGORY_FILTER:-<all>}"
|
|
379
|
+
echo "Shuffled: $SHUFFLE"
|
|
380
|
+
echo "Limit: ${LIMIT:-none}"
|
|
381
|
+
echo "Selected queries: ${#SELECTED[@]} of ${#ALL_QUERIES[@]}"
|
|
382
|
+
echo ""
|
|
383
|
+
echo "Planned queries:"
|
|
384
|
+
for item in "${SELECTED[@]}"; do
|
|
385
|
+
cat="${item%%|*}"
|
|
386
|
+
q="${item#*|}"
|
|
387
|
+
printf ' [%-14s] %s\n' "$cat" "$q"
|
|
388
|
+
done
|
|
389
|
+
echo ""
|
|
390
|
+
echo "Sample command that would execute:"
|
|
391
|
+
SAMPLE_Q="${SELECTED[0]#*|}"
|
|
392
|
+
echo " zen run --memory \"$STAGING_MEM\" --workspace \"$WORKSPACES_DIR/run-1-<timestamp>\" ${MODEL:+--model \"$MODEL\" }--json \"$SAMPLE_Q\""
|
|
393
|
+
echo " zen memory stats --dir \"$STAGING_MEM\""
|
|
394
|
+
echo ""
|
|
395
|
+
echo "Post-run validation that would run:"
|
|
396
|
+
echo " zen memory stats --dir \"$STAGING_MEM\""
|
|
397
|
+
echo ""
|
|
398
|
+
echo "Dry run complete. No files created, no commands executed."
|
|
399
|
+
exit 0
|
|
400
|
+
fi
|
|
401
|
+
|
|
402
|
+
WARMUP_START=$(date +%s)
|
|
403
|
+
|
|
404
|
+
echo "=== Zenera Neo Memory Warmup ==="
|
|
405
|
+
echo "Project root: $ROOT"
|
|
406
|
+
echo "Staging directory: $SCRATCH_DIR"
|
|
407
|
+
if [ -n "$MODEL" ]; then
|
|
408
|
+
echo "Model override: $MODEL"
|
|
409
|
+
fi
|
|
410
|
+
echo "Selected queries: ${#SELECTED[@]}"
|
|
411
|
+
echo ""
|
|
412
|
+
|
|
413
|
+
# Cleanup scratch on trap unless preserved for inspection on failure
|
|
414
|
+
cleanup() {
|
|
415
|
+
local rc=$?
|
|
416
|
+
if [ $rc -ne 0 ]; then
|
|
417
|
+
echo "" >&2
|
|
418
|
+
echo "Warmup FAILED (exit code $rc)." >&2
|
|
419
|
+
echo "Staging files preserved for inspection at: $SCRATCH_DIR" >&2
|
|
420
|
+
fi
|
|
421
|
+
}
|
|
422
|
+
trap cleanup EXIT
|
|
423
|
+
|
|
424
|
+
# Prepare staging memory
|
|
425
|
+
mkdir -p "$STAGING_MEM" "$WORKSPACES_DIR"
|
|
426
|
+
|
|
427
|
+
if [ "$INCREMENTAL" = true ] && [ -d "$PROJECT_MEM" ]; then
|
|
428
|
+
echo "Copying existing memory for incremental warmup..."
|
|
429
|
+
cp -R "$PROJECT_MEM/." "$STAGING_MEM/"
|
|
430
|
+
fi
|
|
431
|
+
|
|
432
|
+
echo "Running ${#SELECTED[@]} warmup queries..."
|
|
433
|
+
echo "----------------------------------------"
|
|
434
|
+
|
|
435
|
+
COUNT=0
|
|
436
|
+
for item in "${SELECTED[@]}"; do
|
|
437
|
+
COUNT=$((COUNT + 1))
|
|
438
|
+
CATEGORY="${item%%|*}"
|
|
439
|
+
QUERY="${item#*|}"
|
|
440
|
+
|
|
441
|
+
RUN_STAMP="$(date +%s)"
|
|
442
|
+
RUN_WORKSPACE="$WORKSPACES_DIR/run-$COUNT-$RUN_STAMP"
|
|
443
|
+
mkdir -p "$RUN_WORKSPACE"
|
|
444
|
+
|
|
445
|
+
echo "[$COUNT/${#SELECTED[@]}] [$CATEGORY] \"$QUERY\""
|
|
446
|
+
echo " -> Workspace: $RUN_WORKSPACE"
|
|
447
|
+
|
|
448
|
+
# Assemble arguments
|
|
449
|
+
CMD=(zen run --memory "$STAGING_MEM" --workspace "$RUN_WORKSPACE" --json)
|
|
450
|
+
if [ -n "$MODEL" ]; then
|
|
451
|
+
CMD+=(--model "$MODEL")
|
|
452
|
+
fi
|
|
453
|
+
CMD+=("$QUERY")
|
|
454
|
+
|
|
455
|
+
QUERY_START=$(date +%s)
|
|
456
|
+
|
|
457
|
+
# Run query and capture JSON output
|
|
458
|
+
JSON_OUT="$("${CMD[@]}")"
|
|
459
|
+
EXIT_CODE=$?
|
|
460
|
+
|
|
461
|
+
QUERY_END=$(date +%s)
|
|
462
|
+
QUERY_DURATION=$((QUERY_END - QUERY_START))
|
|
463
|
+
TOTAL_ELAPSED=$((QUERY_END - WARMUP_START))
|
|
464
|
+
|
|
465
|
+
if [ $EXIT_CODE -ne 0 ]; then
|
|
466
|
+
echo " -> Command exited with code $EXIT_CODE (query: $(format_duration $QUERY_DURATION), total elapsed: $(format_duration $TOTAL_ELAPSED))" >&2
|
|
467
|
+
exit $EXIT_CODE
|
|
468
|
+
fi
|
|
469
|
+
|
|
470
|
+
# Parse outcome via jq if available
|
|
471
|
+
if command -v jq >/dev/null 2>&1; then
|
|
472
|
+
STOP_REASON=$(echo "$JSON_OUT" | jq -r '.stopReason // empty')
|
|
473
|
+
AGENT=$(echo "$JSON_OUT" | jq -r '.agent // empty')
|
|
474
|
+
echo " -> Completed: agent=$AGENT stopReason=$STOP_REASON"
|
|
475
|
+
|
|
476
|
+
if [ "$STOP_REASON" != "final" ]; then
|
|
477
|
+
echo " -> Unexpected stop reason: $STOP_REASON" >&2
|
|
478
|
+
exit 1
|
|
479
|
+
fi
|
|
480
|
+
else
|
|
481
|
+
echo " -> Turn completed successfully."
|
|
482
|
+
fi
|
|
483
|
+
|
|
484
|
+
echo " -> Timing: query took $(format_duration $QUERY_DURATION) | elapsed since start: $(format_duration $TOTAL_ELAPSED)"
|
|
485
|
+
|
|
486
|
+
# Print memory stats between queries to track graph growth
|
|
487
|
+
if [ -f "$STAGING_MEM/manifest.json" ]; then
|
|
488
|
+
echo ""
|
|
489
|
+
echo "Memory stats after query $COUNT:"
|
|
490
|
+
zen memory stats --dir "$STAGING_MEM"
|
|
491
|
+
else
|
|
492
|
+
echo " -> Memory stats: No memories committed yet."
|
|
493
|
+
fi
|
|
494
|
+
echo ""
|
|
495
|
+
done
|
|
496
|
+
|
|
497
|
+
echo "----------------------------------------"
|
|
498
|
+
TOTAL_RUN_TIME=$(( $(date +%s) - WARMUP_START ))
|
|
499
|
+
echo "All warmup queries finished successfully in $(format_duration $TOTAL_RUN_TIME)."
|
|
500
|
+
echo ""
|
|
501
|
+
|
|
502
|
+
# Validate staging memory
|
|
503
|
+
echo "Validating staging memory graph:"
|
|
504
|
+
zen memory stats --dir "$STAGING_MEM"
|
|
505
|
+
echo ""
|
|
506
|
+
|
|
507
|
+
# Confirmation and promotion
|
|
508
|
+
if [ "$ASSUME_YES" = false ]; then
|
|
509
|
+
read -r -p "Promote staging memory to '$PROJECT_MEM'? [y/N] " CONFIRM
|
|
510
|
+
if [[ ! "$CONFIRM" =~ ^[Yy]$ ]]; then
|
|
511
|
+
echo "Warmup cancelled. Staging files left in $SCRATCH_DIR."
|
|
512
|
+
exit 0
|
|
513
|
+
fi
|
|
514
|
+
fi
|
|
515
|
+
|
|
516
|
+
# Backup existing project memory if present
|
|
517
|
+
if [ -d "$PROJECT_MEM" ]; then
|
|
518
|
+
BACKUP_MEM="memory.bak.$(date +%Y%m%d-%H%M%S)"
|
|
519
|
+
echo "Backing up current memory to $BACKUP_MEM..."
|
|
520
|
+
mv "$PROJECT_MEM" "$BACKUP_MEM"
|
|
521
|
+
fi
|
|
522
|
+
|
|
523
|
+
# Promote staging memory to project root
|
|
524
|
+
echo "Promoting warmed memory to $PROJECT_MEM..."
|
|
525
|
+
mv "$STAGING_MEM" "$PROJECT_MEM"
|
|
526
|
+
|
|
527
|
+
# Clean up remaining scratch workspaces
|
|
528
|
+
rm -rf "$SCRATCH_DIR"
|
|
529
|
+
|
|
530
|
+
echo "Warmup complete! Project memory is ready."
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
---
|
|
534
|
+
|
|
535
|
+
## Best Practices for Seed Queries
|
|
536
|
+
|
|
537
|
+
When authoring or generating queries for the warmup script:
|
|
538
|
+
|
|
539
|
+
1. **Group by Category**:
|
|
540
|
+
- Organize queries into clear domain categories (`architecture`, `workflows`,
|
|
541
|
+
`integrations`, `errors`, `conventions`) so test runs can be sampled or
|
|
542
|
+
targeted easily.
|
|
543
|
+
2. **Use `--dry-run` First**:
|
|
544
|
+
- Always verify candidate queries, model overrides, and category distribution
|
|
545
|
+
with `--dry-run` before initiating a live warmup.
|
|
546
|
+
3. **Prompts That Induce Plan Formation**:
|
|
547
|
+
- Instruct the agent to "analyze and determine the recommended pattern for..." so
|
|
548
|
+
it stores durable `plan` and `fact` nodes rather than transient output.
|
|
549
|
+
4. **Verify Node Vectorisation**:
|
|
550
|
+
- Confirm in `zen memory stats --dir ...` that vector count equals node count
|
|
551
|
+
(ensuring your embedding model is configured and active).
|
|
552
|
+
5. **Keep Seed Queries Under Version Control**:
|
|
553
|
+
- Store the seed prompts inside the script or an adjacent `scripts/warmup-queries.txt`
|
|
554
|
+
so warmup is reproducible across environments and model upgrades.
|
|
@@ -19,17 +19,19 @@ hits for `limit` are not an answer; the eight lines around one of them are.
|
|
|
19
19
|
## The commands
|
|
20
20
|
|
|
21
21
|
```
|
|
22
|
-
zen rag docs <index|search|list|grep|show|stats> [path...]
|
|
22
|
+
zen rag docs <index|restore|ready|search|list|grep|show|stats> [path...]
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
| Command
|
|
26
|
-
|
|
|
27
|
-
| `index`
|
|
28
|
-
| `
|
|
29
|
-
| `
|
|
30
|
-
| `
|
|
31
|
-
| `
|
|
32
|
-
| `
|
|
25
|
+
| Command | Answers | Embedder? | Typical |
|
|
26
|
+
| --------- | ------------------------------------------ | --------- | ------- |
|
|
27
|
+
| `index` | builds the thing | yes | minutes |
|
|
28
|
+
| `restore` | _put the vectors back_ | **yes** | minutes |
|
|
29
|
+
| `ready` | _can this index answer at all?_ | no | instant |
|
|
30
|
+
| `search` | _where does this corpus talk about X?_ | **yes** | seconds |
|
|
31
|
+
| `list` | _what documents/headings/tables are here?_ | no | instant |
|
|
32
|
+
| `grep` | _does the string X appear anywhere?_ | no | instant |
|
|
33
|
+
| `show` | _print this section, verbatim_ | no | instant |
|
|
34
|
+
| `stats` | _what is in this index?_ | no | instant |
|
|
33
35
|
|
|
34
36
|
Only `search` ranks, and only `search` costs a network round trip - it embeds
|
|
35
37
|
the query before it can compare anything. The other four read `outline.json`
|
|
@@ -80,6 +82,35 @@ the answer.)
|
|
|
80
82
|
`manifest.json` records **which embedder made the vectors**, so a search with a
|
|
81
83
|
different model is refused rather than answered with noise.
|
|
82
84
|
|
|
85
|
+
### What survives a clone
|
|
86
|
+
|
|
87
|
+
`lance/` is binary, large, and rebuildable, so a project commits the index and
|
|
88
|
+
git-ignores the vectors. What a fresh checkout holds is therefore an index that
|
|
89
|
+
**looks built and cannot answer**: the manifest is there, `sources/` is there,
|
|
90
|
+
and the first search fails deep in the store with `holds no searchable table`.
|
|
91
|
+
|
|
92
|
+
Two commands close that gap, and neither needs the original documents:
|
|
93
|
+
|
|
94
|
+
```sh
|
|
95
|
+
zen rag docs ready --dir assets/docs-db # exit 0 searchable, exit 3 not
|
|
96
|
+
zen rag docs restore --dir assets/docs-db # re-embed from sources/
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`ready` answers with its **exit code**, so a setup step branches on it without
|
|
100
|
+
parsing anything; `--json` gives the same answer as `{ ready, state, embedding }`
|
|
101
|
+
for a caller that wants the detail. `restore` reads the documents back out of
|
|
102
|
+
`sources/`, re-embeds them with the model the manifest names, and renames the
|
|
103
|
+
result into place - so a failed restore leaves the old index untouched, at the
|
|
104
|
+
cost of room for both while it runs.
|
|
105
|
+
|
|
106
|
+
> **Never test for a built index with `[ -f .../manifest.json ]`.** The manifest
|
|
107
|
+
> is committed and the vectors are not, so that test is true on exactly the
|
|
108
|
+
> machine where it is wrong. `zen rag docs ready` is the test.
|
|
109
|
+
|
|
110
|
+
`restore` is also how an index **changes embedder**: `--embedding <ref>`
|
|
111
|
+
re-embeds everything and rewrites the manifest, so later searches ask for the
|
|
112
|
+
new model. Same corpus, same names, same chunk ids - only the vectors are new.
|
|
113
|
+
|
|
83
114
|
### How a document is cut up
|
|
84
115
|
|
|
85
116
|
Chunking follows the markdown rather than a character count: a paragraph, a
|
|
@@ -582,17 +613,19 @@ sections down. Cite the document name and the line numbers.
|
|
|
582
613
|
|
|
583
614
|
## When it goes wrong
|
|
584
615
|
|
|
585
|
-
| Symptom | Cause
|
|
586
|
-
| ------------------------------------------------ |
|
|
587
|
-
| "not installed" | `@zenera/rag` is not resolvable - install it, or use the two-`--package` npx form
|
|
588
|
-
| `nothing to index` | No `.md`/`.markdown`/`.txt`/`.text` under those paths, or they are all hidden
|
|
589
|
-
| A document you expected is missing | Hidden directory, `node_modules`, an unlisted extension, or over 16 MB - check stderr
|
|
590
|
-
| Refused for a different embedding | The index records the model that built it;
|
|
591
|
-
| No manifest / not an index | A build that did not finish. `manifest.json` is written last on purpose
|
|
592
|
-
|
|
|
593
|
-
| `
|
|
594
|
-
| A
|
|
595
|
-
| `no
|
|
596
|
-
|
|
|
597
|
-
|
|
|
598
|
-
|
|
|
616
|
+
| Symptom | Cause |
|
|
617
|
+
| ------------------------------------------------ | -------------------------------------------------------------------------------------------------------------- |
|
|
618
|
+
| "not installed" | `@zenera/rag` is not resolvable - install it, or use the two-`--package` npx form |
|
|
619
|
+
| `nothing to index` | No `.md`/`.markdown`/`.txt`/`.text` under those paths, or they are all hidden |
|
|
620
|
+
| A document you expected is missing | Hidden directory, `node_modules`, an unlisted extension, or over 16 MB - check stderr |
|
|
621
|
+
| Refused for a different embedding | The index records the model that built it; pass the right `--embedding`, or move it with `restore --embedding` |
|
|
622
|
+
| No manifest / not an index | A build that did not finish. `manifest.json` is written last on purpose |
|
|
623
|
+
| `holds no searchable table` | A manifest with no vectors - a clone, since `lance/` is git-ignored. `restore` it |
|
|
624
|
+
| A step reported `skipped` but nothing can search | The step tested for `manifest.json` instead of asking `ready` |
|
|
625
|
+
| A build is refused | `.lock` - another build is running. It is taken over when the process is gone |
|
|
626
|
+
| `provider "openai": no api key` | `zen key ls` - the keyring, or a real environment variable |
|
|
627
|
+
| A usage error before any credential is asked for | Deliberate: everything about the invocation is checked first, so a typo is a typo |
|
|
628
|
+
| `no document matched --file` | The pattern is matched against the document **name**; `list files` prints them |
|
|
629
|
+
| Nothing matched | Exit 0 with an empty answer. Try fewer words, or `--mode text` for an exact string |
|
|
630
|
+
| Answers quoting text that is no longer there | Nothing watches the documents. Re-index after they change |
|
|
631
|
+
| A search took ten seconds, using no CPU | One embedding round trip, not the index. `list`/`grep`/`show` make none |
|