@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,61 @@
|
|
|
1
|
+
# `zen meta` - the meta agent, on this project
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
zen meta run [project] "<question>" ask it something
|
|
5
|
+
zen meta run [project] /<name> [words] run .github/prompts/<name>.prompt.md
|
|
6
|
+
zen meta prompts [project] list the stored prompts
|
|
7
|
+
zen meta resume [project] [session] carry on a run that stopped
|
|
8
|
+
zen meta model [ref] show or set the model it uses
|
|
9
|
+
zen meta dataset <verb> see dataset.md
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
`zen meta --help` has every option.
|
|
13
|
+
|
|
14
|
+
## `--json`
|
|
15
|
+
|
|
16
|
+
`zen meta run --json` prints ONE object on stdout when the run ends:
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{
|
|
20
|
+
"project": "/path/to/project",
|
|
21
|
+
"provider": "vertex",
|
|
22
|
+
"model": "vertex/gemini-3.8-flash",
|
|
23
|
+
"sessionId": "…",
|
|
24
|
+
"exitCode": 0,
|
|
25
|
+
"resumes": 0,
|
|
26
|
+
"usage": {},
|
|
27
|
+
"tokens": {
|
|
28
|
+
"calls": 12,
|
|
29
|
+
"inputTokens": 0,
|
|
30
|
+
"cachedInputTokens": 0,
|
|
31
|
+
"outputTokens": 0,
|
|
32
|
+
"reasoningTokens": 0
|
|
33
|
+
},
|
|
34
|
+
"answer": "the final answer, as markdown",
|
|
35
|
+
"answerFile": "/path/to/project/.tmp/logs/meta.<when>.md"
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
`tokens` is summed over every model call of the run; `usage` is the meta
|
|
40
|
+
agent's own end-of-session summary, passed through as it came, and may be absent.
|
|
41
|
+
|
|
42
|
+
- Progress goes to stderr as plain lines: no box, no animation, no status row.
|
|
43
|
+
stdout carries the object and nothing else, so redirect it to keep it:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
zen meta run acme /analyze --json > analyze.json
|
|
47
|
+
zen meta run acme /analyze --json > analyze.json 2> analyze.log
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
- Nothing is asked. A `run` with no question, no `/<name>` and nothing piped
|
|
51
|
+
in is a usage error (exit 2) that lists the prompts, not a menu.
|
|
52
|
+
- A run the meta agent ends in failure still prints the object, then exits 1.
|
|
53
|
+
Check `exitCode`; `sessionId` is what `zen meta resume` takes. A run that
|
|
54
|
+
never starts (no key, bad model) prints no object, only the error.
|
|
55
|
+
- `--dry-run --json` gives `{project, provider, model, from, command, env}`,
|
|
56
|
+
secrets masked, and runs nothing.
|
|
57
|
+
- `zen meta prompts --json` gives `[{name, description, path}]`;
|
|
58
|
+
`zen meta model --json` gives `{model, from, sources}`.
|
|
59
|
+
|
|
60
|
+
The answer is also saved as markdown on every run, with or without `--json`;
|
|
61
|
+
`answerFile` is its path.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Models - `zen models`
|
|
2
2
|
|
|
3
3
|
```
|
|
4
|
-
zen models <providers|ls|search|show|test|pick> [ref] [options]
|
|
4
|
+
zen models <providers|ls|search|show|test|pick|browse> [ref] [options]
|
|
5
5
|
```
|
|
6
6
|
|
|
7
7
|
Alias: `model`.
|
|
@@ -21,6 +21,7 @@ but a credential.
|
|
|
21
21
|
| `zen models show <ref>` | One model, every field the vendor gave |
|
|
22
22
|
| `zen models test <ref> …` | One real minimal call per ref, and a verdict |
|
|
23
23
|
| `zen models pick` | The first ref that answers, printed on stdout |
|
|
24
|
+
| `zen models browse` | Interactive TUI for a person; needs a terminal |
|
|
24
25
|
|
|
25
26
|
Filters, on `ls` and `search`: `--chat`, `--embeddings`, `--images`, `--audio`,
|
|
26
27
|
`--tools`, `--vision`, `--free`, `--min-context <n>`, `--provider <name>`,
|
|
@@ -28,6 +29,9 @@ Filters, on `ls` and `search`: `--chat`, `--embeddings`, `--images`, `--audio`,
|
|
|
28
29
|
|
|
29
30
|
`pick` requires `--chat` or `--embedding`, and takes `--provider` and `--limit`.
|
|
30
31
|
|
|
32
|
+
`browse` is for a person at a terminal and refuses without one (exit 2). An
|
|
33
|
+
agent wants `ls --json`, `search` or `pick` instead.
|
|
34
|
+
|
|
31
35
|
## Where the lists come from
|
|
32
36
|
|
|
33
37
|
The providers themselves, cached for a day in `~/.zenera/neo/catalog`. When a
|
|
@@ -71,7 +75,7 @@ This is what the command is for.
|
|
|
71
75
|
```
|
|
72
76
|
$ zen models test vertex:gemini-embedding-001
|
|
73
77
|
vertex:gemini-embedding-001 blocked Vertex AI API has not been used in project my-proj …
|
|
74
|
-
vertex:gemini-embedding-001
|
|
78
|
+
fix vertex:gemini-embedding-001 gcloud services enable aiplatform.googleapis.com --project my-proj
|
|
75
79
|
error 1 of 1 did not answer
|
|
76
80
|
find one that does: zen models pick --embedding
|
|
77
81
|
```
|
|
@@ -81,16 +81,23 @@ the first segment as a **provider name**, not a vendor, so a bare
|
|
|
81
81
|
## `zen list`
|
|
82
82
|
|
|
83
83
|
```
|
|
84
|
-
zen list [--sessions] [--prune]
|
|
84
|
+
zen list [--sessions] [--runs] [--limit <n>] [--prune]
|
|
85
85
|
```
|
|
86
86
|
|
|
87
87
|
Every known project: its sessions, the last run, and whether one is live right
|
|
88
88
|
now.
|
|
89
89
|
|
|
90
|
-
| Flag
|
|
91
|
-
|
|
|
92
|
-
| `--sessions`
|
|
93
|
-
| `--
|
|
90
|
+
| Flag | Meaning |
|
|
91
|
+
| ------------- | -------------------------------------------------------- |
|
|
92
|
+
| `--sessions` | Expand each project into its sessions |
|
|
93
|
+
| `--runs` | The most recent runs, newest first, across every project |
|
|
94
|
+
| `--limit <n>` | Runs to list. Default 20 |
|
|
95
|
+
| `--prune` | Forget entries whose directory has gone away |
|
|
96
|
+
|
|
97
|
+
`--runs` answers "what ran last", which is not a question about one project, so
|
|
98
|
+
on its own it replaces the table rather than following it; each row names the
|
|
99
|
+
project and session it belongs to, and `--json` gives the run directory too —
|
|
100
|
+
which is what `zen inspect --dir` takes.
|
|
94
101
|
|
|
95
102
|
The registry is an index, not the truth. An entry pointing at a directory that
|
|
96
103
|
no longer exists is shown dimmed rather than hidden, because a moved project is
|
|
@@ -558,6 +558,7 @@ ordinary hybrid search and narrow by file or section.
|
|
|
558
558
|
zen rag docs list <files|sections|tables> [-f <pattern>] [-s <section>]
|
|
559
559
|
zen rag docs grep <pattern> [-f <pattern>] [--regex] [--case-sensitive]
|
|
560
560
|
zen rag docs show <file> [--section <name>] [--lines <from-to>]
|
|
561
|
+
zen rag docs show <target>... [--max-lines <n>]
|
|
561
562
|
```
|
|
562
563
|
|
|
563
564
|
`list sections` gives every heading with the lines it spans, which is how a
|
|
@@ -566,6 +567,23 @@ total even when `--limit` cuts the rows, so unlike a search it can answer
|
|
|
566
567
|
whether a string appears at all. `show` prints a document, a named section, or
|
|
567
568
|
a line range, verbatim.
|
|
568
569
|
|
|
570
|
+
### Reading several passages in one call
|
|
571
|
+
|
|
572
|
+
Name every passage you will read or cite in **one** `show`, as
|
|
573
|
+
`<document>:<a>-<b>`, `<document>:<a>` or `<document>#<heading>` - the form a
|
|
574
|
+
citation is written in, so a citation pastes back unchanged:
|
|
575
|
+
|
|
576
|
+
```sh
|
|
577
|
+
zen rag docs show -d <index-dir> "<doc-1>:24-60" "<doc-2>:25-40" "<doc-3>#<heading>"
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
Each target prints under a header that is itself a target, in the order given;
|
|
581
|
+
overlapping ranges in one document print once. A missing document or heading is
|
|
582
|
+
reported in place and the rest still print (exit 1 only when none could be
|
|
583
|
+
read). `--max-lines` (default 400) is shared fairly between targets, and a cut
|
|
584
|
+
block ends with the target that continues it. `--json` returns
|
|
585
|
+
`{results, printed, failed}`. `--section` and `--lines` read one document only.
|
|
586
|
+
|
|
569
587
|
### Reading a complete section or table
|
|
570
588
|
|
|
571
589
|
Search finds relevant passages, not necessarily every row of a table. When the
|
|
@@ -596,12 +614,12 @@ the answer needs every row.
|
|
|
596
614
|
|
|
597
615
|
`@zenera/rag/docs/tools` exports four tools in the group `docs`:
|
|
598
616
|
|
|
599
|
-
| Tool | For
|
|
600
|
-
| ------------- |
|
|
601
|
-
| `search_docs` | The search above, with the same narrowing parameters
|
|
602
|
-
| `list_docs` | The documents, their headings, or their tables - no ranking
|
|
603
|
-
| `grep_docs` | Every matching line, counted in full - the way to prove absence
|
|
604
|
-
| `read_docs` | A section or a line range, verbatim
|
|
617
|
+
| Tool | For |
|
|
618
|
+
| ------------- | ---------------------------------------------------------------- |
|
|
619
|
+
| `search_docs` | The search above, with the same narrowing parameters |
|
|
620
|
+
| `list_docs` | The documents, their headings, or their tables - no ranking |
|
|
621
|
+
| `grep_docs` | Every matching line, counted in full - the way to prove absence |
|
|
622
|
+
| `read_docs` | A section or a line range, verbatim; several at once via `reads` |
|
|
605
623
|
|
|
606
624
|
Only `search_docs` ranks. Every answer carries line numbers and `read_docs`
|
|
607
625
|
takes them, which is the loop the subject exists for: find the passage, read
|
|
@@ -14,14 +14,18 @@ answers once on stdout and exits.
|
|
|
14
14
|
| `--project <name\|dir>` | Which project. Inferred from the directory otherwise |
|
|
15
15
|
| `--session <id>` | Continue a particular session |
|
|
16
16
|
| `--new` | Start a new session rather than continuing one |
|
|
17
|
+
| `--input <file>` | Read the whole request from JSON; `-` is stdin |
|
|
17
18
|
| `--workspace <dir>` | What the agent may read and write |
|
|
18
19
|
| `--memory <dir>` | Where the agents remember into, instead of the project's |
|
|
20
|
+
| `--memory-read-only` | Recall from it; write nothing back |
|
|
19
21
|
| `--model <ref>` | Override the default model for this run |
|
|
20
22
|
| `--image <ref>` | Override the container image commands run in |
|
|
21
23
|
| `--read-only` | Withhold every tool that can write |
|
|
22
24
|
| `--plain` | Never open the TUI; a prompt is then required |
|
|
23
25
|
| `--theme <dark\|light>` | Palette for the TUI; `auto` detects. `$ZENERA_THEME` |
|
|
24
26
|
| `--out <file>` | Put the answer in this file instead of on stdout |
|
|
27
|
+
| `--batch-dir <dir>` | Where a batch's runs live. `<project>/batches/<stamp>` |
|
|
28
|
+
| `--concurrency <n>` | How many of a batch run at once. Default 16, most 32 |
|
|
25
29
|
| `--yes` | Say yes to the workspace and install questions |
|
|
26
30
|
|
|
27
31
|
Flags always beat the file: the repository states intent, the invocation
|
|
@@ -38,6 +42,7 @@ the file is the only place it lands.
|
|
|
38
42
|
zen run "what changed?" > out.md answer in the file, progress on screen
|
|
39
43
|
zen run "what changed?" > out.md 2>/dev/null ... and nothing on screen at all
|
|
40
44
|
zen run --out out.md "what changed?" the same file, stdout left empty
|
|
45
|
+
zen run --json --out run.json "what changed?" the whole envelope, in a file
|
|
41
46
|
```
|
|
42
47
|
|
|
43
48
|
There is no `--quiet`. Narration is on stderr already, so a redirect is enough;
|
|
@@ -46,7 +51,9 @@ There is no `--quiet`. Narration is on stderr already, so a redirect is enough;
|
|
|
46
51
|
`--json` answers with the paths as well as the answer: the session and run
|
|
47
52
|
directories, every file the run left behind, and every tree the agent could see,
|
|
48
53
|
with the path it had on this machine beside the path it had inside the
|
|
49
|
-
container.
|
|
54
|
+
container. `--out` takes that envelope off stdout the same way it takes the
|
|
55
|
+
prose — with `--json` the envelope _is_ the answer, so the file holds all of it
|
|
56
|
+
and stdout is left empty.
|
|
50
57
|
|
|
51
58
|
```json
|
|
52
59
|
{
|
|
@@ -58,7 +65,8 @@ container.
|
|
|
58
65
|
"output": ".../output.md",
|
|
59
66
|
"state": ".../state.json",
|
|
60
67
|
"meta": ".../meta.json",
|
|
61
|
-
"report": ".../report.html"
|
|
68
|
+
"report": ".../report.html",
|
|
69
|
+
"graph": ".../graph.mmd"
|
|
62
70
|
},
|
|
63
71
|
"mounts": [
|
|
64
72
|
{ "host": "...", "at": "/workspace", "readOnly": false },
|
|
@@ -76,11 +84,198 @@ container.
|
|
|
76
84
|
`mounts` also lists the container's `$HOME` and, when keys are forwarded, the
|
|
77
85
|
credential files mounted under `/run/zenera/keys`.
|
|
78
86
|
|
|
87
|
+
## A request in a file
|
|
88
|
+
|
|
89
|
+
`--input <file.json>` is the whole invocation written down. It is the only way
|
|
90
|
+
to ask about a picture - a command line cannot carry one - and it is what makes
|
|
91
|
+
a run reproducible: a case is a file, so it can be checked in, diffed and re-run.
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"project": "acme",
|
|
96
|
+
"input": [{ "text": "what is in this picture?" }, { "image": "./shot.png" }],
|
|
97
|
+
"workspace": "./ws",
|
|
98
|
+
"memory": "./mem"
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Only `input` is required, and it may be a plain string instead of an array. Each
|
|
103
|
+
part is a bare string, `{ "text": "…" }`, one of `{ "image" | "audio" | "video" |
|
|
104
|
+
"file": "…" }`, or the canonical `{ "type", "url", "mimeType" }` - the same shapes
|
|
105
|
+
the library's `Input` accepts, because the file is a JSON projection of it.
|
|
106
|
+
|
|
107
|
+
Three rules, and they are the whole of the format:
|
|
108
|
+
|
|
109
|
+
- **Paths are relative to the file**, not to the directory you ran from, so a
|
|
110
|
+
case travels with the images beside it. With `--input -` there is no file, so
|
|
111
|
+
they are relative to the cwd. A bare `project` is a registered name and is
|
|
112
|
+
left alone; one starting with `.` or `/` is a directory.
|
|
113
|
+
- **The file wins** over the same flag on the command line. A field it leaves
|
|
114
|
+
out falls through to the flag, then to the usual default. This is the one
|
|
115
|
+
place the rule above the options table is reversed - the file _is_ the
|
|
116
|
+
invocation, not a repository's standing intent.
|
|
117
|
+
- **A local media path is inlined** as a `data:` url, so the state a run resumes
|
|
118
|
+
from carries the picture rather than a path that meant something elsewhere.
|
|
119
|
+
`http(s):` and `data:` urls are passed through untouched. The bytes land in
|
|
120
|
+
`state.json` and are rewritten on every later turn of that session, so there
|
|
121
|
+
is a 20 MB ceiling and a warning well before it.
|
|
122
|
+
|
|
123
|
+
A request never opens the TUI and never asks about the workspace, exactly like a
|
|
124
|
+
prompt on the command line. Giving both a prompt and `--input` is an error.
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
zen run --input case.json --json | jq -r .output
|
|
128
|
+
cat case.json | zen run --input - --json
|
|
129
|
+
zen run --input case.json --json --out result.json everything, in a file
|
|
130
|
+
zen run --input case.json --session 20260825-143012-a7f3 continue, don't start
|
|
131
|
+
```
|
|
132
|
+
|
|
79
133
|
`--plain` never opens the TUI. The TUI is the only thing that can ask for a
|
|
80
134
|
prompt, so with `--plain` the prompt has to be there already - in the argument
|
|
81
135
|
or on stdin - and `zen run --plain` with neither is an error instead of a
|
|
82
136
|
window. Say it in a script that must not meet one.
|
|
83
137
|
|
|
138
|
+
## Many at once - `zen run batch`
|
|
139
|
+
|
|
140
|
+
```
|
|
141
|
+
zen run batch --input cases.json [--batch-dir <dir>] [--concurrency 16]
|
|
142
|
+
[--memory <dir>] [--memory-read-only] [--out <file>] [--json]
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
The same file, pluralised. One project, many questions, sixteen at a time by
|
|
146
|
+
default:
|
|
147
|
+
|
|
148
|
+
```json
|
|
149
|
+
{
|
|
150
|
+
"batch": [
|
|
151
|
+
{ "id": "vat", "input": "what is the VAT threshold?" },
|
|
152
|
+
{ "input": [{ "text": "what is this?" }, { "image": "./shot.png" }] },
|
|
153
|
+
{ "id": "ws", "input": "read the notes", "workspace": "./cases/ws" }
|
|
154
|
+
]
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
An item takes `input`, an optional `id` and an optional `workspace`, and nothing
|
|
159
|
+
else. `project` and `memory` belong to the batch rather than to an item, so they
|
|
160
|
+
are flags: a file that names either is refused rather than half-honoured. An
|
|
161
|
+
`id` names a directory, so it has to be one - letters, digits, dot, dash and
|
|
162
|
+
underscore - and it defaults to the item's index. Two items may not share an
|
|
163
|
+
`id` or a `workspace`, because they run at the same time.
|
|
164
|
+
|
|
165
|
+
Everything refusable is refused before the first model call. A batch pays for a
|
|
166
|
+
mistake once per item.
|
|
167
|
+
|
|
168
|
+
### What it leaves behind
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
<batch-dir>/
|
|
172
|
+
README.md a live dashboard, rewritten every second
|
|
173
|
+
batch.json the index: every item, whether it worked, where it is
|
|
174
|
+
<id>/
|
|
175
|
+
workspace/ what that item could read and write
|
|
176
|
+
memory/ its own copy, in the copying mode only
|
|
177
|
+
output.json exactly what `zen run --json` prints for one run
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
`README.md` is where the progress of a batch lives. Sixteen agents narrating at
|
|
181
|
+
once would be noise, so instead the file is rewritten once a second: a
|
|
182
|
+
fixed-height panel showing every worker - what it is running, the tail of what
|
|
183
|
+
it is thinking or writing, its turns and its tokens - over a `Tokens by model`
|
|
184
|
+
table, a table of the finished ones and a list of the ones still waiting. The
|
|
185
|
+
panel keeps its height while there is work left to start, so nothing jumps
|
|
186
|
+
between ticks. Watch it in an editor preview, or `watch -n1 cat "$DIR/README.md"`.
|
|
187
|
+
When the batch ends the same file is the report.
|
|
188
|
+
|
|
189
|
+
Tokens are reported **per model**: agents may each use a different one, so one
|
|
190
|
+
total belongs to none of them. Every model id gets a row with its calls and its
|
|
191
|
+
input, cached, output and thinking tokens, and the rows always add up to the
|
|
192
|
+
batch total. Tokens spent summarising, which no node attributes to a model, are
|
|
193
|
+
shown as `(compaction)`.
|
|
194
|
+
|
|
195
|
+
Each `output.json` is written the moment its item finishes, so a batch stopped
|
|
196
|
+
half way still has every answer it managed to get. `batch.json` is an index, not
|
|
197
|
+
a second copy - it points at the files:
|
|
198
|
+
|
|
199
|
+
```json
|
|
200
|
+
{
|
|
201
|
+
"batch": {
|
|
202
|
+
"dir": "...",
|
|
203
|
+
"items": 3,
|
|
204
|
+
"ok": 2,
|
|
205
|
+
"failed": 1,
|
|
206
|
+
"concurrency": 16,
|
|
207
|
+
"memory": { "source": "...", "mode": "read-only" },
|
|
208
|
+
"usage": {
|
|
209
|
+
"inputTokens": 0,
|
|
210
|
+
"cachedInputTokens": 0,
|
|
211
|
+
"outputTokens": 0,
|
|
212
|
+
"reasoningTokens": 0
|
|
213
|
+
},
|
|
214
|
+
"models": [{ "model": "gemini-3-flash", "calls": 12, "usage": {} }],
|
|
215
|
+
"durationMs": 0
|
|
216
|
+
},
|
|
217
|
+
"batch_results": [
|
|
218
|
+
{ "index": 0, "id": "vat", "ok": true, "input": "…", "output": ".../vat/output.json" },
|
|
219
|
+
{
|
|
220
|
+
"index": 1,
|
|
221
|
+
"id": "1",
|
|
222
|
+
"ok": false,
|
|
223
|
+
"input": "…",
|
|
224
|
+
"output": "...",
|
|
225
|
+
"error": { "message": "…" }
|
|
226
|
+
}
|
|
227
|
+
]
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
A failure is data. One item that cannot be answered costs one answer, not the
|
|
232
|
+
other ninety-nine; the exit code says how many failed, and it is set after
|
|
233
|
+
everything is written.
|
|
234
|
+
|
|
235
|
+
stdout is the batch directory and nothing else, so `ls "$(zen run batch --input
|
|
236
|
+
cases.json)"` works. `--json` prints the index there instead. Progress is in
|
|
237
|
+
`<batch-dir>/README.md` either way. `--out` puts the index in a second file as
|
|
238
|
+
well.
|
|
239
|
+
|
|
240
|
+
### Memory, in two modes
|
|
241
|
+
|
|
242
|
+
A memory is a locked directory, so sixteen runs cannot hold one. Which leaves
|
|
243
|
+
two honest arrangements, and the flag picks between them:
|
|
244
|
+
|
|
245
|
+
| Mode | What happens |
|
|
246
|
+
| -------------------- | ------------------------------------------------------------------ |
|
|
247
|
+
| `--memory-read-only` | Every item recalls from the one graph. Nothing is written, no lock |
|
|
248
|
+
| default | Each item gets a copy under `<batch-dir>/<id>/memory` |
|
|
249
|
+
|
|
250
|
+
In the copying mode the project's own memory is never touched. Fold what the
|
|
251
|
+
items learned back in afterwards, having read it:
|
|
252
|
+
|
|
253
|
+
```
|
|
254
|
+
zen memory merge <batch-dir>/*/memory
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
An item that committed nothing leaves no `memory/` behind, so that line never
|
|
258
|
+
names a directory `merge` would refuse.
|
|
259
|
+
|
|
260
|
+
`--memory <dir>` names the source in both modes; without it the source is the
|
|
261
|
+
project's own memory, and a project with none runs the batch with none. A
|
|
262
|
+
source that does not exist yet is not an error in the copying mode: a project
|
|
263
|
+
declares its memory directory and the first run makes it, so every item simply
|
|
264
|
+
starts from an empty graph. That is how a cold project is warmed, and pointing
|
|
265
|
+
`--memory` at a directory that is not there is how you ask for it deliberately.
|
|
266
|
+
A batch refuses to start while another run holds that memory's lock.
|
|
267
|
+
|
|
268
|
+
`--memory-read-only` works on a single `zen run` too. It is how you ask a
|
|
269
|
+
question of what the agents know without changing what they know.
|
|
270
|
+
|
|
271
|
+
### What means nothing in a batch
|
|
272
|
+
|
|
273
|
+
`--session`, `--new`, `--workspace`, `--plain` and `--theme` are refused by
|
|
274
|
+
name rather than ignored. Every item is a new session of its own, they cannot
|
|
275
|
+
share a workspace, and a batch never draws the TUI.
|
|
276
|
+
|
|
277
|
+
For a project or a prompt actually called "batch", say `--project batch`.
|
|
278
|
+
|
|
84
279
|
## Which word is the project
|
|
85
280
|
|
|
86
281
|
The first positional is read as a project when it names one, and as the first
|
|
@@ -138,7 +333,7 @@ run history. Ids look like `20260825-143012-a7f3`.
|
|
|
138
333
|
```
|
|
139
334
|
<project>/sessions/<id>/
|
|
140
335
|
workspace/ what the agent sees, unless --workspace said otherwise
|
|
141
|
-
runs/<run-id>/ input.md, output.md, state.json, report.html, meta.json
|
|
336
|
+
runs/<run-id>/ input.md, output.md, state.json, report.html, graph.mmd, meta.json
|
|
142
337
|
.data/
|
|
143
338
|
state.json the live, resumable state, rewritten after every run
|
|
144
339
|
session.json when it was made, and the workspace it is rooted at
|
|
@@ -162,4 +357,6 @@ definition and is taken over.
|
|
|
162
357
|
## Afterwards
|
|
163
358
|
|
|
164
359
|
Each run writes a `report.html` next to its state; the run prints a
|
|
165
|
-
`file://` link to it.
|
|
360
|
+
`file://` link to it. It writes a `graph.mmd` beside it too - the same
|
|
361
|
+
trajectory as one Mermaid flowchart, which is what `zen inspect graph` prints.
|
|
362
|
+
See [inspect.md](inspect.md).
|
|
@@ -119,7 +119,16 @@ distinguishes the two cases: a broken Dockerfile is an error, a laptop with no
|
|
|
119
119
|
Podman is a warning.
|
|
120
120
|
|
|
121
121
|
`zen sandbox clean` removes every container this CLI created - the way out of a
|
|
122
|
-
container left on a bad rootfs.
|
|
122
|
+
container left on a bad rootfs. `--idle` removes only what no live run is using:
|
|
123
|
+
stopped containers, and running ones whose run was killed before stopping them
|
|
124
|
+
(`zen sandbox status` marks those `orphaned`).
|
|
125
|
+
|
|
126
|
+
`could not create container … exceeded num_locks (2048)` means the engine is out
|
|
127
|
+
of locks: every container holds one, stopped ones included, and `persist: true`
|
|
128
|
+
leaves one stopped per session. `zen run` and `zen run batch` check this before
|
|
129
|
+
the first model call and exit `5` when the engine cannot hold them (a batch needs
|
|
130
|
+
one per item it runs at once). `zen sandbox status` shows a `locks` row when few
|
|
131
|
+
are left; `zen sandbox clean --idle` frees them.
|
|
123
132
|
|
|
124
133
|
For complete container architecture, the `sandbox:*` tools, mount rules, and
|
|
125
134
|
hardening details, load the `zen-sandbox` skill (`.github/skills/zen-sandbox/SKILL.md`).
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: zen-code-python
|
|
3
|
+
description: Code an agent writes must be a reusable tool that can be remembered and re-run, never a one-off. Holds the coding rules (`references/code_python.md`) and decides where they go in the target project - a section of a dedicated code agent's system prompt, or a coding skill for generic agents that sometimes run code - how to adapt them, and what a prompt or skill for a code-writing agent must never say. Load before writing, editing or reviewing any agent prompt, skill or house rule for an agent that writes or runs code - any agent holding `sandbox:*` or `run_command` - and before shipping a script inside a skill.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Code an agent writes is a tool
|
|
7
|
+
|
|
8
|
+
A script an agent writes is worth more than the answer it printed. Written
|
|
9
|
+
generically - every changing value an argument, a name that says what it does -
|
|
10
|
+
it can be committed to memory as a `file` node and found again by the next
|
|
11
|
+
similar question, which runs it instead of writing it again. Written as a
|
|
12
|
+
one-off - this customer's id, this month, this path, as literals - it can only
|
|
13
|
+
ever answer the question that produced it, and memory fills up with near-copies
|
|
14
|
+
that never fold together.
|
|
15
|
+
|
|
16
|
+
Nothing in the runtime enforces this, and `zen check` does not report it. The
|
|
17
|
+
rules reach an agent only through what you write into the target project.
|
|
18
|
+
|
|
19
|
+
## The reference
|
|
20
|
+
|
|
21
|
+
`references/code_python.md` is the rule set, in wording that has been tested on
|
|
22
|
+
models. It is a source to build from, not a file to copy. Start from its
|
|
23
|
+
sentences - copying and then editing them works; rewriting them from scratch in
|
|
24
|
+
your own words loses the mechanical phrasing that makes them obeyed.
|
|
25
|
+
|
|
26
|
+
**Keep in substance, and never soften:**
|
|
27
|
+
|
|
28
|
+
- every value that would change for the next similar question is a named
|
|
29
|
+
argument, never a literal
|
|
30
|
+
- the file is named for what it does, and describes itself through `--help`
|
|
31
|
+
- the result goes to stdout, a produced file to an `--output` path
|
|
32
|
+
- the script is written to a file and the file is run - no `python -c`, no
|
|
33
|
+
heredoc
|
|
34
|
+
- before using the output, the script is checked against a different question
|
|
35
|
+
of the same kind
|
|
36
|
+
- with memory: search before writing, commit the working script after
|
|
37
|
+
|
|
38
|
+
**Adapt to the project:**
|
|
39
|
+
|
|
40
|
+
- the interpreter and language, if the sandbox image runs something other than
|
|
41
|
+
Python
|
|
42
|
+
- where scripts are written - `/workspace/scripts/` unless the project already
|
|
43
|
+
has a place
|
|
44
|
+
- libraries the image carries and the agent should prefer, and the output
|
|
45
|
+
format the project expects (JSON, CSV, a table)
|
|
46
|
+
- an example invocation from this project's own domain, values passed as
|
|
47
|
+
arguments
|
|
48
|
+
- the memory steps: keep them when the agent holds `memory_search` /
|
|
49
|
+
`memory_commit`, drop them when it never will. In a skill several agents may
|
|
50
|
+
load, keep them gated on the tool, as the reference does
|
|
51
|
+
|
|
52
|
+
## Decide where the rules go
|
|
53
|
+
|
|
54
|
+
List the agents that hold `sandbox:*` or `run_command`, and read each one's
|
|
55
|
+
prompt for what its job is. Then:
|
|
56
|
+
|
|
57
|
+
| The project has | Write |
|
|
58
|
+
| ---------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
59
|
+
| A **dedicated code agent** - a runner, an executor, an analyst whose answers are scripts | A `## Writing code` section in that agent's `agents/prompts/<name>.md` |
|
|
60
|
+
| **No dedicated code agent** - generic agents that sometimes run code | A coding skill, `agents/skills/code_python/SKILL.md` |
|
|
61
|
+
| Both | The prompt section, and the generic agents hand the code work to that agent rather than writing it - see below |
|
|
62
|
+
| No agent that writes or runs code | Nothing |
|
|
63
|
+
|
|
64
|
+
**A dedicated code agent gets the rules in its system prompt.** It writes code
|
|
65
|
+
on nearly every turn, so the rules are part of its job description: a skill
|
|
66
|
+
would cost a load on every case, and preloading one is the same text in the
|
|
67
|
+
prefix with an extra file to keep in step. Put the section after the agent's
|
|
68
|
+
identity and procedure, before its prohibitions.
|
|
69
|
+
|
|
70
|
+
**Generic agents get a skill.** Most of their turns write no code, so the rules
|
|
71
|
+
should cost nothing until one does. The `description` is the routing key - name
|
|
72
|
+
the condition, not the topic:
|
|
73
|
+
|
|
74
|
+
```yaml
|
|
75
|
+
description: Before writing, changing or running any Python script - how to write it as a reusable tool rather than a one-off.
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Leave it in the agent's index; do not preload it. If `allow` is used, add
|
|
79
|
+
`code_python` to it for every agent holding `sandbox:*`.
|
|
80
|
+
|
|
81
|
+
**With both, one copy.** Generic agents that can reach a code agent should
|
|
82
|
+
`fork:` to it for an answer, or hand off to it, rather than writing code
|
|
83
|
+
themselves - then the rules have one home and the scripts one author. Grant
|
|
84
|
+
them no `sandbox:*` for code work. If they must keep a shell of their own, they
|
|
85
|
+
need the skill too, and its rules are the same sentences as the prompt section:
|
|
86
|
+
a second wording is how one copy ends up softer than the other, and the softer
|
|
87
|
+
one is the one obeyed.
|
|
88
|
+
|
|
89
|
+
Run `zen check` after any change to `agents.yaml` or a skill.
|
|
90
|
+
|
|
91
|
+
## Writing anything else around it
|
|
92
|
+
|
|
93
|
+
- **One home per agent.** Once an agent has the rules - in its prompt or in its
|
|
94
|
+
skill - no house rule, other skill or prompt line restates them. A prompt that
|
|
95
|
+
needs to point at the skill names it: _"Follow `code_python` for every
|
|
96
|
+
script."_
|
|
97
|
+
- **Never add an exemption.** _"Hard-coding is fine for a quick one-off check"_
|
|
98
|
+
is a permission: every probe is a one-off by construction, so the exception
|
|
99
|
+
admits exactly what the rule forbids. The same goes for `python -c`.
|
|
100
|
+
- **Never show a one-off as an example.** A prompt or skill that shows
|
|
101
|
+
`python -c "..."`, or a script with a literal id, date or path in its body,
|
|
102
|
+
teaches the shape the rule forbids. Every example invocation passes its values
|
|
103
|
+
as named arguments:
|
|
104
|
+
`python /workspace/scripts/list_overdue_invoices.py --customer-id 42`.
|
|
105
|
+
- **Scripts shipped inside a skill** (`agents/skills/<name>/scripts/`, §3.4.1 of
|
|
106
|
+
the copilot instructions) follow the same rules: named arguments, a `--help`,
|
|
107
|
+
the result on stdout, an `--output` path under `/workspace` for any file,
|
|
108
|
+
since `/skills` is read-only.
|
|
109
|
+
- **Memory is what makes the reuse happen.** A code-writing agent without
|
|
110
|
+
memory still writes reusable scripts, but cannot find them in a later session.
|
|
111
|
+
Say so if the project expects reuse and that agent has no `memory:`.
|
|
112
|
+
|
|
113
|
+
## Review
|
|
114
|
+
|
|
115
|
+
- [ ] Every agent that writes or runs code has the rules - a prompt section for
|
|
116
|
+
a dedicated code agent, the `code_python` skill reachable for the others
|
|
117
|
+
- [ ] Every rule under _Keep in substance_ is there, none softened, and the
|
|
118
|
+
memory steps match whether the agent holds the memory tools
|
|
119
|
+
- [ ] Generic agents beside a dedicated code agent hand code work to it, or
|
|
120
|
+
carry the same wording - not a second paraphrase
|
|
121
|
+
- [ ] No other prompt, skill or house rule restates the rules, adds an
|
|
122
|
+
exemption, or shows `python -c` or a script with literal values
|
|
123
|
+
- [ ] Every script shipped in a skill takes its values as named arguments
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Writing Python scripts
|
|
2
|
+
|
|
3
|
+
Every script you write is a tool for the next question like this one, not an
|
|
4
|
+
answer to this one. Write it once, generically, so it can be remembered and run
|
|
5
|
+
again unchanged.
|
|
6
|
+
|
|
7
|
+
## Before writing
|
|
8
|
+
|
|
9
|
+
If you hold `memory_search`, search for a script that already answers this kind
|
|
10
|
+
of question, and load the best match with `memory_load`. If it fits, run it with
|
|
11
|
+
this question's arguments and write nothing new. If it needs a change, change
|
|
12
|
+
it the way the rest of this skill says - usually by adding an argument - and
|
|
13
|
+
commit the new version as superseding the old one.
|
|
14
|
+
|
|
15
|
+
## Writing
|
|
16
|
+
|
|
17
|
+
1. **Solve the kind of question, not this one.** Anything that would differ the
|
|
18
|
+
next time - inputs, ids, names, paths, urls, dates and date ranges, filters,
|
|
19
|
+
thresholds, limits, the output path - is a named `argparse` argument such as
|
|
20
|
+
`--resource-id`, never a literal in the code. A default is allowed only for a
|
|
21
|
+
value that is the same for every question.
|
|
22
|
+
2. **Name the file for what it does**, verb first: `list_overdue_invoices.py`,
|
|
23
|
+
`compare_quarterly_revenue.py`. Never `script.py`, `test.py`, `tmp.py` or a
|
|
24
|
+
name that only makes sense in this conversation.
|
|
25
|
+
3. **Describe it.** Line one is a docstring saying what question it answers. The
|
|
26
|
+
same sentence is the `argparse` description, and every argument has a
|
|
27
|
+
`help=`, so `--help` is all a later reader needs.
|
|
28
|
+
4. **Print the result to stdout** and anything else to stderr. Exit non-zero
|
|
29
|
+
with a message saying what failed when it cannot answer. A file it produces
|
|
30
|
+
goes to the path given by `--output`.
|
|
31
|
+
5. **Take credentials from environment variables by name.** Never write a key,
|
|
32
|
+
token or password into the code or an argument default.
|
|
33
|
+
6. **Use only what the sandbox image already has.** Do not `pip install` from
|
|
34
|
+
the script or before running it.
|
|
35
|
+
7. **Write it to a file and run the file**:
|
|
36
|
+
`python /workspace/scripts/<name>.py --resource-id 42`. Never run Python
|
|
37
|
+
with `python -c` or a heredoc.
|
|
38
|
+
|
|
39
|
+
## Before using its output
|
|
40
|
+
|
|
41
|
+
- Run it, and fix the script - not the output - when it fails or prints
|
|
42
|
+
something wrong.
|
|
43
|
+
- Read your own code against a different question of the same kind. If
|
|
44
|
+
answering it would mean editing the script rather than passing other
|
|
45
|
+
arguments, a value is still hard-coded: make it an argument and run again.
|
|
46
|
+
- If you hold `memory_commit`, commit the working script as a `file` node. Its
|
|
47
|
+
text says what kind of question it answers and names its arguments, so that a
|
|
48
|
+
later search for a similar question finds it.
|