@yaag/extension 0.6.2 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,6 +5,16 @@ The yaag pi extension: run Orchestration Programs from a pi session.
5
5
  It is loaded by pi through jiti, in **Node**, and bridges to the `yaag` CLI,
6
6
  which runs on **Bun** (ADR-0005, ADR-0015).
7
7
 
8
+ ## Docs
9
+
10
+ The package ships the user and agent docs in `docs/`:
11
+
12
+ - [`docs/getting-started.md`](docs/getting-started.md) — install, prerequisites, first Run.
13
+ - [`docs/authoring.md`](docs/authoring.md) — how to write an Orchestration Program.
14
+ - [`docs/examples.md`](docs/examples.md) — five example programs, in reading order.
15
+ - [`docs/cli.md`](docs/cli.md) — CLI flags and tool parameters.
16
+ - [`docs/troubleshooting.md`](docs/troubleshooting.md) — the errors you can meet.
17
+
8
18
  ## Prerequisites
9
19
 
10
20
  **Bun is required.** The extension itself runs in pi's Node process, but every
@@ -138,6 +148,8 @@ export default defineRun({
138
148
  run: async (ctx) => {
139
149
  const agent = await ctx.spawn({
140
150
  name: "reviewer",
151
+ model: ["anthropic/claude-opus-4:medium", "anthropic/claude-haiku-4"],
152
+ thinking: (model) => (model.includes("haiku") ? "low" : "high"),
141
153
  tools: ["read", "grep"],
142
154
  disallowedTools: ["yaag_run"],
143
155
  skills: ["review"],
@@ -173,6 +185,14 @@ is recoverable and the Handle can be asked again. `wrapUpPrompt` replaces the
173
185
  default steering message. This is intentionally different from `timeoutMs`, the
174
186
  destructive fallback that rejects with `ASK_TIMEOUT` and closes the Agent.
175
187
 
188
+ `model` takes one pattern, an ordered list, or a function of the failures so
189
+ far; `thinking` takes a level or a function of the settled model. A pattern can
190
+ end with a thinking suffix (`"opus-5:medium"`), and the suffix wins over
191
+ `thinking`. The fallback rules — trigger classes, retry, termination — are
192
+ stated on the types in `<program dir>/.yaag/types/runtime/index.d.ts` and in
193
+ the root [`README.md`](../../README.md#models-and-fallback); the sequences are
194
+ in [`../../docs/architecture.md`](../../docs/architecture.md) §4 and §6.
195
+
176
196
  The tool call:
177
197
 
178
198
  ```json
@@ -231,3 +251,6 @@ Provided commands: `/yaag-status`, `/yaag-setup-workspace [dir]`.
231
251
  - [`../../docs/architecture.md`](../../docs/architecture.md) — the diagrams
232
252
  - [`../../docs/adr/`](../../docs/adr) — why it is built this way
233
253
  - [ADR-0018: foreign workspaces use CLI aliases and vendored types](../../docs/adr/0018-foreign-workspaces-use-cli-aliases-and-vendored-types.md) — workspace setup and foreign-program support
254
+ - [ADR-0037: model resolution triggers are read from pi's stderr diagnostic](../../docs/adr/0037-model-resolution-triggers-are-read-from-pis-stderr-diagnostic.md) — which failures start a fallback
255
+ - [ADR-0038: a mid-Ask model swap is a yaag-side match, then `set_model`](../../docs/adr/0038-a-mid-ask-model-swap-is-a-yaag-side-match-then-set-model.md) — how a live Agent changes model
256
+ - [ADR-0039: replay adopts the recorded resolved model](../../docs/adr/0039-replay-adopts-the-recorded-resolved-model.md) — why a replay skips the resolution loop
@@ -0,0 +1,115 @@
1
+ # Authoring an Orchestration Program
2
+
3
+ A program is a TypeScript module. It default-exports `defineRun(...)`. It can
4
+ import `@yaag/runtime` and `typebox`. A program file can import other modules;
5
+ an inline program cannot.
6
+
7
+ The deep reference is the vendored declaration file:
8
+ `<program dir>/.yaag/types/runtime/index.d.ts`. This page gives the shape and
9
+ the rules. It does not restate the types.
10
+
11
+ ## The Run
12
+
13
+ `defineRun` takes a name, an optional description, an optional argument schema,
14
+ and a `run` body. The body gets a context with `args` and `spawn`. What the body
15
+ returns is the result of the Run.
16
+
17
+ <!-- embed: docs/examples/01-minimal.ts -->
18
+
19
+ ```ts
20
+ export default defineRun({
21
+ name: "minimal",
22
+ description: "Asks one Agent for one short answer.",
23
+ async run(ctx) {
24
+ const agent = await ctx.spawn({ name: "writer" });
25
+ return await agent.ask(prompt`Write one sentence about the sea. Report only that sentence.`);
26
+ },
27
+ });
28
+ ```
29
+
30
+ Keep the module top level side-effect free. `yaag describe` imports the module
31
+ and executes its top level.
32
+
33
+ ## Arguments
34
+
35
+ Declare arguments with a typebox object schema. The Orchestrator validates the
36
+ arguments before it starts any Agent, so a bad call costs nothing. `ctx.args` is
37
+ typed from the schema.
38
+
39
+ <!-- embed: docs/examples/02-args.ts -->
40
+
41
+ ```ts
42
+ args: Type.Object({
43
+ topic: Type.String({ description: "What to write about" }),
44
+ sentences: Type.Optional(Type.Integer({ description: "How many sentences" })),
45
+ }),
46
+ ```
47
+
48
+ ## Agents and spawn restrictions
49
+
50
+ `defineAgent` holds policy that does not change: the prompt, the model, the
51
+ thinking level, the tools, and the skills. A spawn holds topology: the name, the
52
+ working directory, and the worktree request. `ctx.spawn(definition, overrides)`
53
+ puts the two together.
54
+
55
+ `tools`, `disallowedTools`, `skills`, and `disallowedSkills` take **names**, not
56
+ paths. `disallowedTools` and `disallowedSkills` apply last. An unknown skill
57
+ name rejects the spawn.
58
+
59
+ <!-- embed: docs/examples/03-fan-out.ts -->
60
+
61
+ ```ts
62
+ const reviewer = defineAgent({
63
+ name: "reviewer",
64
+ tools: ["read"],
65
+ disallowedTools: ["yaag_run"],
66
+ skills: [],
67
+ });
68
+ ```
69
+
70
+ ## Worktrees
71
+
72
+ `worktree: true` puts the Agent in its own git worktree, on a fresh branch. Two
73
+ Agents that write files then cannot collide. The worktree outlives the Run: yaag
74
+ creates it and never removes it. Merge or delete the branch yourself.
75
+
76
+ ## Asks and limits
77
+
78
+ `handle.ask(prompt, options)` is the only conversational verb. The soft limits
79
+ are `maxTurns`, `maxToolCalls`, and `maxDurationMs`. A soft limit steers the
80
+ Agent with `wrapUpPrompt`, gives it one more turn, then fails the Ask with
81
+ `ASK_LIMIT`. The Handle stays alive, so the program can ask again.
82
+
83
+ `timeoutMs` is different: it kills the Agent and fails with `ASK_TIMEOUT`. Use
84
+ it as the last resort, not as a budget.
85
+
86
+ `outputSchema` makes the Ask return data against a typebox object schema. A
87
+ result that never validates fails with `ASK_INVALID_OUTPUT`.
88
+
89
+ <!-- embed: docs/examples/04-controlled-ask.ts -->
90
+
91
+ ```ts
92
+ const report = await agent.ask(prompt`Read README.md and report your verdict.`, {
93
+ maxTurns: 6,
94
+ maxToolCalls: 12,
95
+ maxDurationMs: 120_000,
96
+ wrapUpPrompt: "Stop the work and report what you have now.",
97
+ outputSchema: Report,
98
+ });
99
+ ```
100
+
101
+ Use the `prompt` tag for prompt text. It removes the indentation that a
102
+ template literal keeps.
103
+
104
+ ## Asking the user
105
+
106
+ An Agent cannot ask the user today. yaag cancels the dialog request of an Agent,
107
+ so the Agent has to decide by itself. Write prompts that state the decision
108
+ rules. ADR-0022 plans the human-in-the-loop verbs; they are not available yet.
109
+
110
+ ## Record and resume
111
+
112
+ `--record <file>` writes a Cassette of every frame. `--resume <file>` runs the
113
+ program again and replays the recorded Asks. A resume needs the program too,
114
+ because a Cassette holds the history of a Run and never the program. See
115
+ [Examples](examples.md#05--record-and-resume).
package/docs/cli.md ADDED
@@ -0,0 +1,102 @@
1
+ # CLI and tool reference
2
+
3
+ The `yaag` CLI and the yaag extension start the same Runs. The CLI is for a
4
+ terminal; the tools are for a pi session.
5
+
6
+ ## Usage
7
+
8
+ <!-- embed: @yaag/cli/src/argv.ts#USAGE -->
9
+
10
+ ```text
11
+ usage:
12
+ yaag run <program.ts> [--quiet] [--args <json>] [--record <file>] [--replay <file>] [--resume <file>] [--events-fd <n>] [--config <file>] [--no-config]
13
+ yaag run --eval <source> [--quiet] [--args <json>] [--record <file>] [--replay <file>] [--resume <file>] [--events-fd <n>] [--config <file>] [--no-config]
14
+ yaag run --eval-fd <n> [--quiet] [--args <json>] [--record <file>] [--replay <file>] [--resume <file>] [--events-fd <n>] [--config <file>] [--no-config]
15
+ yaag describe <program.ts>
16
+ yaag setup-workspace [dir]
17
+
18
+ --eval runs an Orchestration Program that you give as source text. Give a
19
+ program file or --eval, but do not give both. A program that --eval runs can
20
+ import "@yaag/runtime" and "typebox" only. A program that imports other modules
21
+ must be a file.
22
+
23
+ --eval-fd reads the program source from descriptor <n>, and needs the writer to
24
+ close that descriptor. It keeps the source out of the process argument list,
25
+ where every local user can read it. The yaag extension always uses it.
26
+
27
+ --config <file> reads one more config file for this Run. Give it one time only.
28
+ yaag reads it after the global config and after the project config.
29
+
30
+ --no-config tells yaag to ignore the global config and the project config. It
31
+ does not ignore --config.
32
+
33
+ A --resume or --replay Run also needs the program: give the program file,
34
+ --eval <source>, or --eval-fd <n>. A Cassette holds the history of a Run, and never the program
35
+ to run.
36
+
37
+ Warning: describe imports the module and executes its top level. Keep program module top level side-effect free.
38
+ ```
39
+
40
+ A bad invocation prints this usage text on stderr and exits with code 2. Those
41
+ argv errors have no troubleshooting entry: the usage text is the fix.
42
+
43
+ ## Tools
44
+
45
+ ### yaag_run
46
+
47
+ Runs an Orchestration Program. It maps to `yaag run`.
48
+
49
+ | field | maps to | notes |
50
+ |---|---|---|
51
+ | `file` | `yaag run <program.ts>` | Path of the program file. |
52
+ | `script` | `--eval-fd` | Inline source. It can import `@yaag/runtime` and `typebox` only. |
53
+ | `args` | `--args <json>` | A JSON object string. |
54
+ | `background` | none | Extension only. Starts the Run and returns its Run id. |
55
+ | `record` | `--record <file>` | Writes the Cassette here. |
56
+ | `resume` | `--resume <file>` | Replays matching Asks, then continues live. |
57
+ | `config` | `--config <file>` | Reads one more config file for this Run. |
58
+ | `noConfig` | `--no-config` | Ignores the global config and the project config. |
59
+
60
+ ### yaag_status
61
+
62
+ Reports the Runs of the session, or one Run.
63
+
64
+ | field | maps to | notes |
65
+ |---|---|---|
66
+ | `id` | none | Extension only. Omit it for every Run of the session. |
67
+
68
+ ### yaag_stop
69
+
70
+ Stops a background Run and reaps its Agents.
71
+
72
+ | field | maps to | notes |
73
+ |---|---|---|
74
+ | `id` | none | Extension only. The Run id that `yaag_run` returned. |
75
+
76
+ ### yaag_describe
77
+
78
+ Reports the name, description, and argument schema of a program. It maps to
79
+ `yaag describe`.
80
+
81
+ | field | maps to | notes |
82
+ |---|---|---|
83
+ | `file` | `yaag describe <program.ts>` | Describing imports the module and executes its top level. |
84
+
85
+ ### yaag_setup_workspace
86
+
87
+ Creates `.yaag/` with the editor types. It maps to `yaag setup-workspace`.
88
+
89
+ | field | maps to | notes |
90
+ |---|---|---|
91
+ | `dir` | `yaag setup-workspace [dir]` | Defaults to pi's working directory. |
92
+
93
+ ## Background Runs
94
+
95
+ Only the extension has background Runs. Call `yaag_run` with `background: true`.
96
+ It returns a Run id. Poll it with `yaag_status`, and end it with `yaag_stop`.
97
+ A Run record outlives the session, so a later session reaches a Run by its id.
98
+
99
+ ## One side only
100
+
101
+ - CLI only: `--replay` (strict replay, no model calls) and `--quiet`.
102
+ - Extension only: `yaag_status`, `yaag_stop`, and background Runs.
@@ -0,0 +1,14 @@
1
+ /**
2
+ * The smallest Orchestration Program. It starts one Agent, sends one Ask, and
3
+ * returns the text that the Agent reports.
4
+ */
5
+ import { defineRun, prompt } from "@yaag/runtime";
6
+
7
+ export default defineRun({
8
+ name: "minimal",
9
+ description: "Asks one Agent for one short answer.",
10
+ async run(ctx) {
11
+ const agent = await ctx.spawn({ name: "writer" });
12
+ return await agent.ask(prompt`Write one sentence about the sea. Report only that sentence.`);
13
+ },
14
+ });
@@ -0,0 +1,22 @@
1
+ /**
2
+ * A Run with declared arguments. `yaag describe` shows the schema. The
3
+ * Orchestrator rejects invalid arguments before it starts an Agent.
4
+ */
5
+ import { defineRun, prompt } from "@yaag/runtime";
6
+ import { Type } from "typebox";
7
+
8
+ export default defineRun({
9
+ name: "args",
10
+ description: "Writes about a topic, with a sentence budget.",
11
+ args: Type.Object({
12
+ topic: Type.String({ description: "What to write about" }),
13
+ sentences: Type.Optional(Type.Integer({ description: "How many sentences" })),
14
+ }),
15
+ async run(ctx) {
16
+ const sentences = ctx.args.sentences ?? 3;
17
+ const agent = await ctx.spawn({ name: "writer" });
18
+ return await agent.ask(
19
+ prompt`Write ${String(sentences)} sentences about ${ctx.args.topic}. Report only the text.`,
20
+ );
21
+ },
22
+ });
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Parallel Agents from one Agent Definition. Each Agent gets the same spawn
3
+ * restrictions: it can read files, it cannot start a nested Run, and it has no
4
+ * skills.
5
+ */
6
+ import { defineAgent, defineRun, prompt } from "@yaag/runtime";
7
+
8
+ const reviewer = defineAgent({
9
+ name: "reviewer",
10
+ tools: ["read"],
11
+ disallowedTools: ["yaag_run"],
12
+ skills: [],
13
+ });
14
+
15
+ export default defineRun({
16
+ name: "fan-out",
17
+ description: "Reviews one file with three Agents at the same time.",
18
+ async run(ctx) {
19
+ const reviews = await Promise.all(
20
+ ["style", "risk", "tests"].map(async (topic) => {
21
+ const agent = await ctx.spawn(reviewer, { name: `reviewer-${topic}` });
22
+ return await agent.ask(prompt`Read README.md. Report the ${topic} problems you find.`);
23
+ }),
24
+ );
25
+ return reviews.join("\n\n");
26
+ },
27
+ });
@@ -0,0 +1,33 @@
1
+ /**
2
+ * An Ask with limits and a structured result. The limits steer the Agent first,
3
+ * then fail the Ask with `ASK_LIMIT`. The Agent stays alive, so the program can
4
+ * recover.
5
+ */
6
+ import { defineRun, isYaagError, prompt } from "@yaag/runtime";
7
+ import { Type } from "typebox";
8
+
9
+ const Report = Type.Object({
10
+ verdict: Type.String(),
11
+ reasons: Type.Array(Type.String()),
12
+ });
13
+
14
+ export default defineRun({
15
+ name: "controlled-ask",
16
+ description: "Asks for a structured report under explicit limits.",
17
+ async run(ctx) {
18
+ const agent = await ctx.spawn({ name: "auditor", tools: ["read"] });
19
+ try {
20
+ const report = await agent.ask(prompt`Read README.md and report your verdict.`, {
21
+ maxTurns: 6,
22
+ maxToolCalls: 12,
23
+ maxDurationMs: 120_000,
24
+ wrapUpPrompt: "Stop the work and report what you have now.",
25
+ outputSchema: Report,
26
+ });
27
+ return `${report.verdict}: ${report.reasons.join("; ")}`;
28
+ } catch (error) {
29
+ if (isYaagError(error) && error.code === "ASK_LIMIT") return "the audit hit its limit";
30
+ throw error;
31
+ }
32
+ },
33
+ });
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Two Asks in sequence. Run it with `--record` to write a Cassette. If the
3
+ * second Ask fails, run it again with `--resume` on that Cassette: the first
4
+ * Ask replays from the recording and costs nothing.
5
+ */
6
+ import { defineRun, prompt } from "@yaag/runtime";
7
+
8
+ export default defineRun({
9
+ name: "record-resume",
10
+ description: "Drafts a text, then shortens it.",
11
+ async run(ctx) {
12
+ const agent = await ctx.spawn({ name: "writer" });
13
+ const draft = await agent.ask(prompt`Write two sentences about rain. Report only the text.`);
14
+ return await agent.ask(
15
+ prompt`Shorten this text to one sentence: ${draft}. Report only that sentence.`,
16
+ );
17
+ },
18
+ });
@@ -0,0 +1,102 @@
1
+ # Examples
2
+
3
+ Five programs, in reading order. Each file is in `examples/` next to this page.
4
+ Run one with `yaag run <file>`, or with the `yaag_run` tool.
5
+
6
+ ## 01 — one Agent, one Ask
7
+
8
+ The smallest program. It starts one Agent, sends one Ask, and returns the text.
9
+ The return value of `run` is the result of the Run.
10
+
11
+ <!-- embed: docs/examples/01-minimal.ts -->
12
+
13
+ ```ts
14
+ export default defineRun({
15
+ name: "minimal",
16
+ description: "Asks one Agent for one short answer.",
17
+ async run(ctx) {
18
+ const agent = await ctx.spawn({ name: "writer" });
19
+ return await agent.ask(prompt`Write one sentence about the sea. Report only that sentence.`);
20
+ },
21
+ });
22
+ ```
23
+
24
+ Full file: [`examples/01-minimal.ts`](examples/01-minimal.ts). Run it with
25
+ `yaag run examples/01-minimal.ts`.
26
+
27
+ ## 02 — declared arguments
28
+
29
+ A program declares its arguments with a typebox schema. `yaag describe` shows
30
+ that schema, and the Orchestrator rejects invalid arguments before it starts an
31
+ Agent.
32
+
33
+ <!-- embed: docs/examples/02-args.ts -->
34
+
35
+ ```ts
36
+ args: Type.Object({
37
+ topic: Type.String({ description: "What to write about" }),
38
+ sentences: Type.Optional(Type.Integer({ description: "How many sentences" })),
39
+ }),
40
+ ```
41
+
42
+ Full file: [`examples/02-args.ts`](examples/02-args.ts). Run it with
43
+ `yaag run examples/02-args.ts --args '{"topic":"tides"}'`.
44
+
45
+ ## 03 — parallel Agents with restrictions
46
+
47
+ An Agent Definition holds policy: which tools and which skills the Agent gets.
48
+ A spawn holds topology: the name and the working directory. Three Agents run at
49
+ the same time.
50
+
51
+ <!-- embed: docs/examples/03-fan-out.ts -->
52
+
53
+ ```ts
54
+ const reviewer = defineAgent({
55
+ name: "reviewer",
56
+ tools: ["read"],
57
+ disallowedTools: ["yaag_run"],
58
+ skills: [],
59
+ });
60
+ ```
61
+
62
+ Full file: [`examples/03-fan-out.ts`](examples/03-fan-out.ts). Run it with
63
+ `yaag run examples/03-fan-out.ts`.
64
+
65
+ ## 04 — Ask limits and a structured result
66
+
67
+ Soft limits steer the Agent first, then fail the Ask with `ASK_LIMIT`. The
68
+ Agent stays alive, so the program can recover. An `outputSchema` makes the Ask
69
+ return data instead of text.
70
+
71
+ <!-- embed: docs/examples/04-controlled-ask.ts -->
72
+
73
+ ```ts
74
+ const report = await agent.ask(prompt`Read README.md and report your verdict.`, {
75
+ maxTurns: 6,
76
+ maxToolCalls: 12,
77
+ maxDurationMs: 120_000,
78
+ wrapUpPrompt: "Stop the work and report what you have now.",
79
+ outputSchema: Report,
80
+ });
81
+ ```
82
+
83
+ Full file: [`examples/04-controlled-ask.ts`](examples/04-controlled-ask.ts). Run
84
+ it with `yaag run examples/04-controlled-ask.ts`.
85
+
86
+ ## 05 — record and resume
87
+
88
+ A Cassette records every frame of a Run. `--record <file>` writes it. `--resume
89
+ <file>` runs the program again and replays the recorded Asks, so only the new
90
+ work costs money. A resume needs the program too, because a Cassette never
91
+ holds it.
92
+
93
+ <!-- embed: docs/examples/05-record-resume.ts -->
94
+
95
+ ```ts
96
+ const agent = await ctx.spawn({ name: "writer" });
97
+ const draft = await agent.ask(prompt`Write two sentences about rain. Report only the text.`);
98
+ ```
99
+
100
+ Full file: [`examples/05-record-resume.ts`](examples/05-record-resume.ts). Run
101
+ it with `yaag run examples/05-record-resume.ts --record run.json`, then resume
102
+ it with `yaag run examples/05-record-resume.ts --resume run.json`.
@@ -0,0 +1,53 @@
1
+ # Getting started
2
+
3
+ yaag runs Orchestration Programs: TypeScript modules that drive pi Agents.
4
+ Start a Run from the `yaag` CLI, or from a pi session with the yaag extension.
5
+
6
+ ## Install
7
+
8
+ Install the extension into a pi session:
9
+
10
+ - `pi install @yaag/extension` adds it permanently.
11
+ - `pi -e @yaag/extension` loads it for one session.
12
+
13
+ yaag needs Bun on `PATH`. Install it with
14
+ `curl -fsSL https://bun.sh/install | bash`. If the extension reports that Bun is
15
+ missing, read [Bun is missing](troubleshooting.md#bun-is-missing).
16
+
17
+ ## Prepare the workspace
18
+
19
+ Run the `yaag_setup_workspace` tool, or `yaag setup-workspace .` on the command
20
+ line. It creates `.yaag/` in the workspace root. `.yaag/types/` holds the
21
+ `@yaag/runtime` declarations that an editor needs. A folder with `.yaag/` is a
22
+ Program Directory, and the extension tells the model about it.
23
+
24
+ ## Write and run the first program
25
+
26
+ Copy [`examples/01-minimal.ts`](examples/01-minimal.ts) into the Program
27
+ Directory:
28
+
29
+ <!-- embed: docs/examples/01-minimal.ts -->
30
+
31
+ ```ts
32
+ import { defineRun, prompt } from "@yaag/runtime";
33
+
34
+ export default defineRun({
35
+ name: "minimal",
36
+ description: "Asks one Agent for one short answer.",
37
+ async run(ctx) {
38
+ const agent = await ctx.spawn({ name: "writer" });
39
+ return await agent.ask(prompt`Write one sentence about the sea. Report only that sentence.`);
40
+ },
41
+ });
42
+ ```
43
+
44
+ Then run `yaag run 01-minimal.ts`, or ask the model to use the `yaag_run` tool.
45
+ `yaag describe 01-minimal.ts` reports the name, the description, and the
46
+ argument schema of the program.
47
+
48
+ ## Next
49
+
50
+ - [Authoring](authoring.md) — how to write a program.
51
+ - [Examples](examples.md) — five programs, from minimal to record and resume.
52
+ - [CLI reference](cli.md) — every flag and every tool parameter.
53
+ - [Troubleshooting](troubleshooting.md) — the errors you can meet.
@@ -0,0 +1,132 @@
1
+ # Troubleshooting
2
+
3
+ One entry for each failure you can meet. The quote is the message text, or the
4
+ text that yaag matches on. An entry is at most ten lines, blank lines apart.
5
+
6
+ ## Bun is missing
7
+
8
+ <!-- quote: src/process/status.ts -->
9
+
10
+ > yaag needs Bun and could not find it on PATH or in ~/.bun/bin.
11
+
12
+ Cause: the extension bridges to the Bun CLI, and Bun is not on `PATH` and not
13
+ in `~/.bun/bin`.
14
+
15
+ Fix: install Bun with `curl -fsSL https://bun.sh/install | bash`, then restart
16
+ pi. The extension resolves Bun once, at load.
17
+
18
+ ## No API key for a spawned Agent
19
+
20
+ <!-- quote: @yaag/runtime/src/model/model-failure.ts -->
21
+
22
+ > No API key
23
+
24
+ pi says `No API key found for the selected model.`, or `No API key for
25
+ <provider>/<id>`. yaag reads that text and calls the failure `auth`.
26
+
27
+ Cause: a spawned Agent is hermetic, so it loads no pi extension of the session.
28
+ A model that a provider extension registers is out of reach.
29
+
30
+ Fix: name the provider extension in the `extensions` spawn option, or give the
31
+ Agent a model the machine can reach. A `model` list falls back on `auth`.
32
+
33
+ ## failed to publish cassette
34
+
35
+ <!-- quote: @yaag/runtime/src/cassette/cassette-publish.ts -->
36
+
37
+ > failed to publish cassette
38
+
39
+ Cause: yaag could not write the Cassette. Most often the parent directory of
40
+ the `--record` path does not exist, or it is not writable.
41
+
42
+ Fix: create the directory first, then run again. The Run keeps its result; only
43
+ the recording failed.
44
+
45
+ ## Replay or resume mismatch
46
+
47
+ <!-- quote: @yaag/runtime/src/cassette/replay-divergence.ts -->
48
+
49
+ > replay diverged for agent
50
+
51
+ Cause: the program changed since the recording. A spawn option, an Agent
52
+ Definition field, or an Ask prompt no longer hashes to the recorded value.
53
+
54
+ Fix: restore the program to the recorded shape, or record again. A resume
55
+ replays only the Asks that still match, and runs the rest live.
56
+
57
+ ## --resume or --replay needs the program
58
+
59
+ <!-- quote: @yaag/cli/src/argv.ts -->
60
+
61
+ > needs the program too: give <program.ts>, --eval <source>, or --eval-fd <n>.
62
+
63
+ Cause: a Cassette holds the history of a Run. It never holds the program.
64
+
65
+ Fix: name the program as well: `yaag run program.ts --resume run.json`.
66
+
67
+ ## Inline program limits
68
+
69
+ <!-- quote: src/record/run-program-param.ts -->
70
+
71
+ > yaag_run: script is too large
72
+
73
+ Cause: an inline program (`script`, or `--eval`) must be 65536 bytes (64 KiB)
74
+ or smaller, and it can import `@yaag/runtime` and `typebox` only.
75
+
76
+ Fix: write the program to a file and pass `file` or `<program.ts>`. A file may
77
+ import any module.
78
+
79
+ ## An Ask failed with a limit or a timeout
80
+
81
+ <!-- quote: @yaag/runtime/src/errors.ts -->
82
+
83
+ > limit reached at
84
+
85
+ Cause: `ASK_LIMIT` is a tripped soft budget (`maxTurns`, `maxToolCalls`,
86
+ `maxDurationMs`). `ASK_TIMEOUT` is `timeoutMs`, and it kills the Agent.
87
+ `ASK_INVALID_OUTPUT` is a result that never satisfied `outputSchema`.
88
+ `ASK_STALLED` is silence past the watchdog budget.
89
+
90
+ Fix: raise the budget, or add a `wrapUpPrompt`. After `ASK_LIMIT` the Handle is
91
+ alive, so the program can ask again.
92
+
93
+ ## describe executes the module top level
94
+
95
+ <!-- quote: @yaag/cli/src/argv.ts -->
96
+
97
+ > describe imports the module and executes its top level.
98
+
99
+ Cause: `yaag describe` imports the program to read its declaration.
100
+
101
+ Fix: keep the module top level side-effect free. Put every action inside `run`.
102
+
103
+ ## Missing @yaag/runtime editor types
104
+
105
+ The editor says it cannot find the module `@yaag/runtime` in a program file.
106
+
107
+ Cause: the folder is not a Program Directory yet, so `.yaag/types/` is absent.
108
+
109
+ Fix: run the `yaag_setup_workspace` tool, or `yaag setup-workspace .`. It
110
+ reports the written declarations:
111
+
112
+ <!-- quote: @yaag/cli/src/setup-workspace.ts -->
113
+
114
+ > .yaag/types/: written
115
+
116
+ Rerun it after an upgrade to refresh the declarations.
117
+
118
+ ## A config file is missing or invalid
119
+
120
+ <!-- quote: @yaag/runtime/src/config/config-file.ts -->
121
+
122
+ > does not exist
123
+
124
+ Cause: yaag reads the global config, the project config, and the `--config`
125
+ file at the start of a Run. A `--config` file that is not there, or any config
126
+ file that yaag cannot read or parse, stops the Run at the start (exit 1).
127
+
128
+ Fix: correct the path or the file. Give `--no-config` to ignore the global
129
+ config and the project config.
130
+
131
+ Plain usage errors of the CLI exit with code 2 and print the usage text. See
132
+ [the CLI reference](cli.md#usage).