@agent-compose/cli 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@ import { createRequire } from "node:module";
3
3
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
4
4
 
5
5
  // src/index.ts
6
- import { readFileSync as readFileSync3 } from "node:fs";
6
+ import { readFileSync as readFileSync4 } from "node:fs";
7
7
  import { fileURLToPath as fileURLToPath2 } from "node:url";
8
8
  import { program } from "commander";
9
9
 
@@ -183,7 +183,7 @@ var registerCommand = new Command("register").description("Register a workflow w
183
183
  console.error(`Error: workflow not found at ${workflowPath}`);
184
184
  process.exit(1);
185
185
  }
186
- const { source, networkPolicy, placeholders, snapshot, saveSnapshot } = await bundleWorkflow(workflowPath);
186
+ const { source, manifest, networkPolicy, placeholders, snapshot, saveSnapshot, memory, workflowPlan } = await bundleWorkflow(workflowPath);
187
187
  if (networkPolicy)
188
188
  console.log(`[register] Network policy detected — credentials will be brokered via Vercel firewall`);
189
189
  if (snapshot)
@@ -195,13 +195,16 @@ var registerCommand = new Command("register").description("Register a workflow w
195
195
  const result = await client.register({
196
196
  name,
197
197
  source,
198
+ manifest,
199
+ workflowPlan,
198
200
  factorySlug: opts.factory,
199
201
  ...opts.version ? { version: opts.version } : {},
200
202
  ...opts.schedule ? { schedule: opts.schedule } : {},
201
203
  ...networkPolicy ? { networkPolicy } : {},
202
204
  ...placeholders ? { placeholders } : {},
203
205
  ...snapshot ? { snapshot } : {},
204
- ...saveSnapshot !== undefined ? { saveSnapshot } : {}
206
+ ...saveSnapshot !== undefined ? { saveSnapshot } : {},
207
+ ...memory !== undefined ? { memory } : {}
205
208
  });
206
209
  const scheduleNote = opts.schedule ? ` — schedule: ${opts.schedule}` : "";
207
210
  console.log(`✓ Workflow: ${result.name}@${result.version} (${result.id})${scheduleNote}`);
@@ -246,6 +249,37 @@ function extractToolSnippet(toolInput) {
246
249
  const raw = toolInput ? String(toolInput) : "";
247
250
  return raw.match(/"(?:command|file_path|url|query|pattern)":"([^"]{1,80})/)?.[1] ?? "";
248
251
  }
252
+ function printAgentMessage(data) {
253
+ const message = data.message;
254
+ if (!message)
255
+ return;
256
+ switch (message.type) {
257
+ case "text": {
258
+ const text = String(message.text ?? "").replace(/<status>[\s\S]*?<\/status>/g, "").trim();
259
+ if (text)
260
+ process.stdout.write(` ${pc.dim("text")} ${text.slice(0, 160)}
261
+ `);
262
+ break;
263
+ }
264
+ case "thinking": {
265
+ const text = String(message.text ?? "").trim();
266
+ if (text)
267
+ process.stdout.write(` ${pc.dim("thinking")} ${text.slice(0, 160)}
268
+ `);
269
+ break;
270
+ }
271
+ case "tool_use": {
272
+ const detail = extractToolSnippet(message.toolInputPreview);
273
+ process.stdout.write(` ${pc.cyan("→")} ${pc.bold(String(message.toolName ?? "tool"))}${detail ? ` ${pc.dim(detail)}` : ""}
274
+ `);
275
+ break;
276
+ }
277
+ case "tool_result":
278
+ process.stdout.write(` ${message.isError ? pc.red("tool error") : pc.dim("tool result")} ${String(message.output ?? "").slice(0, 160)}
279
+ `);
280
+ break;
281
+ }
282
+ }
249
283
  function printEvent(event, data, state) {
250
284
  switch (event) {
251
285
  case "step_started":
@@ -263,6 +297,7 @@ ${pc.dim(`● ${data.step}`)}
263
297
  process.stdout.write(` ${pc.red("✗")} ${data.step}: ${pc.dim(String(data.reason ?? ""))}
264
298
  `);
265
299
  break;
300
+ case "agent.spawned":
266
301
  case "agent_spawned": {
267
302
  const name = String(data.agentName ?? data.label ?? "agent");
268
303
  const id = String(data.agentId ?? "");
@@ -275,6 +310,7 @@ ${pc.bold(pc.magenta(`▶ ${name}`))}${tag}
275
310
  `);
276
311
  break;
277
312
  }
313
+ case "agent.settled":
278
314
  case "agent_settled": {
279
315
  const ok = data.outcome === "success" || data.outcome === "done";
280
316
  const id = String(data.agentId ?? "");
@@ -292,6 +328,16 @@ ${pc.bold(pc.magenta(`▶ ${name}`))}${tag}
292
328
  }
293
329
  break;
294
330
  }
331
+ case "agent.iteration": {
332
+ const name = String(data.label ?? "agent");
333
+ const iteration = data.iteration ? ` ${data.iteration}` : "";
334
+ process.stdout.write(` ${pc.dim(`${name} iteration${iteration}`)}
335
+ `);
336
+ break;
337
+ }
338
+ case "agent.message":
339
+ printAgentMessage(data);
340
+ break;
295
341
  case "agent_event": {
296
342
  const { toolName } = data;
297
343
  if (toolName) {
@@ -600,7 +646,7 @@ function requireAdminKey(adminKey) {
600
646
  process.exit(1);
601
647
  }
602
648
  var keysCommand = new Command6("keys").description("Manage API keys");
603
- keysCommand.command("create <name>").description("Create a new API key (requires admin-scoped ac_… key)").option("--url <url>", "Server URL", parseUrlFlag, defaultUrl).option("--admin-key <key>", "Admin-scoped ac_… key (or AGENT_COMPOSE_ADMIN_KEY env var)", process.env.AGENT_COMPOSE_ADMIN_KEY ?? "").option("--scopes <list>", "Comma-separated scope list: read, invoke, admin. Default (empty) = full team access.").option("--expires-in <duration>", `Expire the key after this duration — e.g. "30d", "2h", "7d12h", "1w", "90m". Default: never.`).option("--factory <slug>", "Restrict the key to a single factory (slug). Default: team-wide.").action(async (name, opts) => {
649
+ keysCommand.command("create <name>").description("Create a new API key (requires admin-scoped ac_… key)").option("--url <url>", "Server URL", parseUrlFlag, defaultUrl).option("--admin-key <key>", "Admin-scoped ac_… key (or AGENT_COMPOSE_ADMIN_KEY env var)", process.env.AGENT_COMPOSE_ADMIN_KEY ?? "").option("--scopes <list>", "Comma-separated scope list: read, invoke, admin, events:read, events:write. Default (empty) = full team access.").option("--expires-in <duration>", `Expire the key after this duration — e.g. "30d", "2h", "7d12h", "1w", "90m". Default: never.`).option("--factory <slug>", "Restrict the key to a single factory (slug). Default: team-wide.").action(async (name, opts) => {
604
650
  requireAdminKey(opts.adminKey);
605
651
  const scopes = opts.scopes ? opts.scopes.split(",").map((s) => s.trim()).filter(Boolean) : undefined;
606
652
  let expiresAt;
@@ -964,8 +1010,122 @@ var cancelCommand = new Command12("cancel").description("Cancel an in-progress r
964
1010
  await streamLogs(runId, opts);
965
1011
  });
966
1012
 
1013
+ // src/commands/events.ts
1014
+ import { Command as Command13 } from "commander";
1015
+ import { readFileSync as readFileSync3 } from "node:fs";
1016
+ import pc3 from "picocolors";
1017
+ function parseBody(raw) {
1018
+ if (raw === undefined || raw === "")
1019
+ return {};
1020
+ const src = raw.startsWith("@") ? readFileSync3(raw.slice(1), "utf8") : raw;
1021
+ try {
1022
+ return JSON.parse(src);
1023
+ } catch (err) {
1024
+ throw new Error(`--body is not valid JSON: ${err instanceof Error ? err.message : String(err)}`);
1025
+ }
1026
+ }
1027
+ function parseAttribute(raw, prev = {}) {
1028
+ const idx = raw.indexOf("=");
1029
+ if (idx < 0)
1030
+ throw new Error(`--attribute must be key=value, got "${raw}"`);
1031
+ const key = raw.slice(0, idx);
1032
+ const val = raw.slice(idx + 1);
1033
+ if (!key)
1034
+ throw new Error(`--attribute key is empty in "${raw}"`);
1035
+ let parsed;
1036
+ try {
1037
+ parsed = JSON.parse(val);
1038
+ } catch {
1039
+ parsed = val;
1040
+ }
1041
+ return { ...prev, [key]: parsed };
1042
+ }
1043
+ function parseConfidence(raw) {
1044
+ const n = Number(raw);
1045
+ if (!Number.isFinite(n) || n < 0 || n > 1) {
1046
+ throw new Error(`--confidence must be a number in [0, 1], got "${raw}"`);
1047
+ }
1048
+ return n;
1049
+ }
1050
+ function parseLimit(raw) {
1051
+ const n = parseInt(raw, 10);
1052
+ if (!Number.isFinite(n) || n < 1)
1053
+ throw new Error(`--limit must be a positive integer, got "${raw}"`);
1054
+ return n;
1055
+ }
1056
+ function fmtBodyPreview(body) {
1057
+ if (body === null || body === undefined)
1058
+ return pc3.dim("—");
1059
+ if (typeof body === "string")
1060
+ return body.length > 60 ? body.slice(0, 57) + "…" : body;
1061
+ try {
1062
+ const s = JSON.stringify(body);
1063
+ return s.length > 60 ? s.slice(0, 57) + "…" : s;
1064
+ } catch {
1065
+ return String(body);
1066
+ }
1067
+ }
1068
+ var sendCommand = new Command13("send").description("Send an event to an existing run (requires events:write or invoke scope)").argument("<run-id>", "Target run id (uuid)").argument("<name>", "Event name (e.g. quality.accepted, deploy.completed)").option("--url <url>", "Server URL", parseUrlFlag, defaultUrl).option("--api-key <key>", "API key", defaultApiKey).option("--body <json>", "Event body — inline JSON or @file (default: {})").option("--summary <s>", "One-line summary (≤2000 chars)").option("--confidence <0..1>", "Confidence score, [0, 1]", parseConfidence).option("-a, --attribute <key=value>", "Attribute (repeatable; value parsed as JSON if possible)", parseAttribute, {}).option("--idempotency-key <k>", "Replay-safe key: identical (run, name, key) returns the original event").option("--no-propagate", "Mark event as non-propagating").option("--timestamp <iso>", "Event timestamp (ISO 8601, defaults to server-now)").option("--json", "Output the raw event JSON instead of the one-line summary").action(async (runId, name, opts) => {
1069
+ let body;
1070
+ try {
1071
+ body = parseBody(opts.body);
1072
+ } catch (err) {
1073
+ console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
1074
+ process.exit(1);
1075
+ }
1076
+ const client = makeClient(opts);
1077
+ const event = await client.reportEvent(runId, {
1078
+ name,
1079
+ body,
1080
+ ...opts.summary ? { summary: opts.summary } : {},
1081
+ ...opts.confidence !== undefined ? { confidence: opts.confidence } : {},
1082
+ ...opts.timestamp ? { timestamp: opts.timestamp } : {},
1083
+ ...Object.keys(opts.attribute).length ? { attributes: opts.attribute } : {},
1084
+ ...opts.idempotencyKey ? { idempotencyKey: opts.idempotencyKey } : {},
1085
+ ...opts.propagate === false ? { propagate: false } : {}
1086
+ }).catch(reportSdkError);
1087
+ if (opts.json) {
1088
+ console.log(JSON.stringify(event, null, 2));
1089
+ return;
1090
+ }
1091
+ console.log(`${pc3.green("✓")} event ${pc3.bold(event.id.slice(0, 8))} ${event.name} ${pc3.dim(`run ${runId.slice(0, 8)}`)}`);
1092
+ });
1093
+ var listCommand2 = new Command13("list").description("List events for a run, or factory-wide with --factory <slug>").argument("[run-id]", "Run id (uuid). If omitted, requires --factory.").option("--url <url>", "Server URL", parseUrlFlag, defaultUrl).option("--api-key <key>", "API key", defaultApiKey).option("--factory <slug>", "List events across a factory instead of a single run").option("--limit <n>", "Max rows (factory mode only; server clamps)", parseLimit).option("--name <pattern>", "Filter by event name (factory mode only)").option("--json", "Output raw JSON instead of the columnar view").action(async (runId, opts) => {
1094
+ if (!runId && !opts.factory) {
1095
+ console.error("Error: provide either <run-id> or --factory <slug>");
1096
+ process.exit(1);
1097
+ }
1098
+ if (runId && opts.factory) {
1099
+ console.error("Error: <run-id> and --factory are mutually exclusive");
1100
+ process.exit(1);
1101
+ }
1102
+ const client = makeClient(opts);
1103
+ const events = runId ? await client.listRunEvents(runId).catch(reportSdkError) : (await client.listFactoryEvents({
1104
+ factorySlug: opts.factory,
1105
+ ...opts.limit !== undefined ? { limit: opts.limit } : {},
1106
+ ...opts.name ? { name: opts.name } : {}
1107
+ }).catch(reportSdkError)).events;
1108
+ if (opts.json) {
1109
+ console.log(JSON.stringify(events, null, 2));
1110
+ return;
1111
+ }
1112
+ if (events.length === 0) {
1113
+ const scope = runId ? `run ${runId.slice(0, 8)}` : `factory "${opts.factory}"`;
1114
+ console.log(`No events for ${scope}.`);
1115
+ return;
1116
+ }
1117
+ const sorted = [...events].sort((a, b) => b.timestamp.localeCompare(a.timestamp));
1118
+ for (const ev of sorted) {
1119
+ const ts = ev.timestamp.replace(/\.\d+Z$/, "Z");
1120
+ const detail = ev.summary ?? fmtBodyPreview(ev.body);
1121
+ const runHint = runId ? "" : pc3.dim(` run ${(ev.runId ?? "—").slice(0, 8)}`);
1122
+ console.log(`${pc3.dim(ts)} ${pc3.bold(ev.name.padEnd(28))} ${detail}${runHint}`);
1123
+ }
1124
+ });
1125
+ var eventsCommand = new Command13("events").description("Send or list run events (Events API)").addCommand(sendCommand).addCommand(listCommand2);
1126
+
967
1127
  // src/index.ts
968
- var pkg = JSON.parse(readFileSync3(fileURLToPath2(new URL("../package.json", import.meta.url)), "utf8"));
1128
+ var pkg = JSON.parse(readFileSync4(fileURLToPath2(new URL("../package.json", import.meta.url)), "utf8"));
969
1129
  program.name("agentc").description("CLI for agent-compose — register, invoke, and monitor workflows").version(pkg.version);
970
1130
  program.addCommand(registerCommand);
971
1131
  program.addCommand(invokeCommand);
@@ -979,4 +1139,5 @@ program.addCommand(usageCommand);
979
1139
  program.addCommand(snapshotCommand);
980
1140
  program.addCommand(factoryCommand);
981
1141
  program.addCommand(cancelCommand);
1142
+ program.addCommand(eventsCommand);
982
1143
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-compose/cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Command-line interface for agent-compose — register, invoke, and monitor workflows from your terminal.",
5
5
  "license": "MIT",
6
6
  "repository": {
package/skills/ac:demo.md CHANGED
@@ -34,7 +34,7 @@ for the full version.
34
34
  > Owns the run end-to-end: orchestrates phases, kicks off agent loops,
35
35
  > writes metadata, returns a structured result.
36
36
 
37
- > **Agent loop** — `runAgent({ runtime, prompt, ... })`. Embedded inside
37
+ > **Agent loop** — `agent({ runtime, prompt, ... })`. Embedded inside
38
38
  > the workflow body. Drives one iteration cycle of an LLM agent against
39
39
  > the runner sandbox until the model emits `exit_signal: true` (or
40
40
  > hits the iteration budget).
@@ -50,7 +50,7 @@ work. Keep it minimal — one phase, no fancy plumbing:
50
50
 
51
51
  ```ts
52
52
  // hello-agent.ts
53
- import { defineWorkflow, runAgent, claudeRuntime } from "@agent-compose/sdk";
53
+ import { defineWorkflow, agent, claudeRuntime } from "@agent-compose/sdk";
54
54
 
55
55
  const PROMPT = `
56
56
  You're verifying agent-compose is wired up correctly.
@@ -62,7 +62,7 @@ exit_signal: true.
62
62
 
63
63
  export default defineWorkflow({
64
64
  async run(ctx, sandbox) {
65
- const result = await runAgent({
65
+ const result = await agent({
66
66
  sandbox,
67
67
  runtime: claudeRuntime,
68
68
  prompt: PROMPT,
@@ -76,7 +76,7 @@ export default defineWorkflow({
76
76
  ```
77
77
 
78
78
  Walk the user through the file — point at `ctx`, `sandbox`,
79
- `runAgent`, the prompt, the tool allowlist, the budget. Confirm before
79
+ `agent`, the prompt, the tool allowlist, the budget. Confirm before
80
80
  writing.
81
81
 
82
82
  ### 3. Register
@@ -96,7 +96,7 @@ agentc invoke hello-agent --follow
96
96
  ```
97
97
 
98
98
  > "The server creates a runner sandbox, drops the bundle in, and starts
99
- > Node. Inside the sandbox, our workflow runs `runAgent` once — Claude
99
+ > Node. Inside the sandbox, our workflow runs `agent` once — Claude
100
100
  > spawns, runs the bash command, emits its `<status>`, and exits.
101
101
  > Server marks the run complete; the CLI prints the final outcome and
102
102
  > elapsed time."
@@ -123,8 +123,8 @@ artifacts (logs, metadata) the workflow emitted.
123
123
  > "That was the simplest possible workflow. To go further:"
124
124
  >
125
125
  > - `/ac:generate-workflow` — describe a multi-phase workflow in plain
126
- > English; Claude scaffolds the full file with `runAgent` blocks per phase.
127
- > - `/ac:generate-agent` — scaffold one phase's prompt + `runAgent` snippet
126
+ > English; Claude scaffolds the full file with `agent` blocks per phase.
127
+ > - `/ac:generate-agent` — scaffold one phase's prompt + `agent` snippet
128
128
  > to slot into an existing workflow.
129
129
  > - `/ac:generate-runtime` — write a custom runtime for a model the SDK
130
130
  > doesn't ship.
@@ -1,19 +1,19 @@
1
1
  ---
2
2
  name: ac:generate-agent
3
- description: Scaffold a `runAgent` block + prompt for one agent loop inside a workflow.
3
+ description: Scaffold an `agent` block + prompt for one agent loop inside a workflow.
4
4
  allowed-tools: Read Write Edit Bash(bunx *) Bash(bun *)
5
5
  effort: high
6
6
  ---
7
7
 
8
8
  # Generate Agent
9
9
 
10
- Interactively scaffold a single agent loop — a `runAgent({ ... })` call
10
+ Interactively scaffold a single agent loop — an `agent({ ... })` call
11
11
  plus its `prompt.md` — to drop into an existing workflow.
12
12
 
13
13
  > **Mental model.** There is no standalone "agent" resource. Agents live
14
- > *inside* workflows via `runAgent`. Each `runAgent` call drives one
14
+ > *inside* workflows via `agent`. Each `agent` call drives one
15
15
  > iteration loop with a runtime, prompt, tool allowlist, and budget.
16
- > Multiple `runAgent` calls compose by sequencing (`await`) or by
16
+ > Multiple `agent` calls compose by sequencing (`await`) or by
17
17
  > fanning out (`Promise.all`).
18
18
 
19
19
  ## Steps
@@ -24,12 +24,12 @@ plus its `prompt.md` — to drop into an existing workflow.
24
24
  - Runtime? (default: `claudeRuntime`. Use `openAIDesktopRuntime` for desktop / computer-use.)
25
25
  - Tools? (e.g. `Read`, `Write`, `Edit`, `Bash`, `Glob`, `Grep`, `WebFetch`)
26
26
  - Budget? Suggest `{ turnsPerIteration: 30-60, maxIterations: 4-8 }` based on complexity.
27
- - Typed response? If yes, sketch a zod schema — `runAgent({ responseSchema })`
27
+ - Typed response? If yes, sketch a zod schema — `agent({ responseSchema })`
28
28
  makes the loop demand a `<response>` block that validates against it.
29
29
  - Prompt directory? (default: alongside the workflow file)
30
30
 
31
- 2. If the user has an existing workflow with a `runAgent` block, read it
32
- to match their conventions — prompt template structure, `promptVars`,
31
+ 2. If the user has an existing workflow with an `agent` block, read it
32
+ to match their conventions — prompt structure,
33
33
  tool sets, error handling. Otherwise follow the patterns in
34
34
  `sdk/src/runtimes/claude.ts` and the SDK's [README](../../sdk/README.md).
35
35
 
@@ -40,19 +40,18 @@ plus its `prompt.md` — to drop into an existing workflow.
40
40
  - Available tools + when to use each.
41
41
  - Step-by-step instructions for the phase.
42
42
  - The `<status>` protocol is auto-appended; don't include it manually.
43
- - Use `{{VAR}}` placeholders for runtime substitution (`WORKING_DIR`,
44
- `DIFF_BASE`, plus any `promptVars` the workflow passes in).
43
+ - Put runtime values directly in the workflow's prompt string; there is no
44
+ separate templating layer.
45
45
 
46
46
  **Snippet to paste into the workflow body:**
47
47
 
48
48
  ```ts
49
49
  import PROMPT from "./<phase>.md" with { type: "text" };
50
50
  // …in the workflow's run():
51
- const result = await runAgent({
51
+ const result = await agent({
52
52
  sandbox,
53
53
  runtime: claudeRuntime,
54
- prompt: PROMPT,
55
- promptVars: { /* … */ },
54
+ prompt: `${PROMPT}\n\nContext: ${JSON.stringify(ctx.input ?? {})}`,
56
55
  tools: [/* … */],
57
56
  budget: { turnsPerIteration: 40, maxIterations: 6 },
58
57
  // responseSchema: MySchema, // when typed handoff is needed
@@ -12,9 +12,9 @@ Interactively scaffold a new workflow from a plain-English description.
12
12
  > **Mental model.** A workflow is `async (ctx, sandbox) => T`. The `ctx`
13
13
  > exposes `run`, `input?`, `setMetadata`, and `step` (for named timeline
14
14
  > phases). The `sandbox` is the runner's own VM — pass it to
15
- > `runAgent({ sandbox, ... })` and to any helper that takes a
15
+ > `agent({ sandbox, ... })` and to any helper that takes a
16
16
  > `SandboxProvider`. Agent loops live *inside* the workflow body via
17
- > `runAgent`. There's no `defineAgent` / `spawnAgent` model anymore.
17
+ > `agent`. There's no `defineAgent` / `spawnAgent` model anymore.
18
18
 
19
19
  ## Steps
20
20
 
@@ -29,7 +29,7 @@ Interactively scaffold a new workflow from a plain-English description.
29
29
  workflows whose end-state other workflows boot from)
30
30
 
31
31
  2. If the user has a reference workflow in their project, read it to
32
- match their conventions (prompt structure, `promptVars` shape,
32
+ match their conventions (prompt structure,
33
33
  error handling). Otherwise follow the patterns in
34
34
  [`sdk/README.md`](../../sdk/README.md) and the example in
35
35
  [`docs/how-it-works.md`](../../docs/how-it-works.md).
@@ -37,7 +37,7 @@ Interactively scaffold a new workflow from a plain-English description.
37
37
  3. Generate a complete, real implementation:
38
38
 
39
39
  ```ts
40
- import { defineWorkflow, runAgent, claudeRuntime } from "@agent-compose/sdk";
40
+ import { defineWorkflow, agent, claudeRuntime } from "@agent-compose/sdk";
41
41
  import PROMPT from "./prompt.md" with { type: "text" };
42
42
 
43
43
  export default defineWorkflow({
@@ -48,13 +48,12 @@ Interactively scaffold a new workflow from a plain-English description.
48
48
  // pure-server work, fetches, etc.
49
49
  });
50
50
 
51
- // Phase 2 — agent loop. Each `runAgent` is one iteration cycle
51
+ // Phase 2 — agent loop. Each `agent` is one iteration cycle
52
52
  // with its own prompt + tool allowlist + budget.
53
- const result = await runAgent({
53
+ const result = await agent({
54
54
  sandbox,
55
55
  runtime: claudeRuntime,
56
- prompt: PROMPT,
57
- promptVars: { /* {{VAR}} substitutions */ },
56
+ prompt: `${PROMPT}\n\nContext: ${JSON.stringify(data)}`,
58
57
  tools: ["Read", "Write", "Edit", "Bash", "Grep", "Glob"],
59
58
  budget: { turnsPerIteration: 40, maxIterations: 6 },
60
59
  // responseSchema: MyZodSchema, // for typed handoffs
@@ -72,7 +71,7 @@ Interactively scaffold a new workflow from a plain-English description.
72
71
  ```
73
72
 
74
73
  - Always declare the return type (or let TS infer + show it on hover).
75
- - Use `Promise.all` to fan out independent `runAgent` calls.
74
+ - Use `Promise.all` to fan out independent `agent` calls.
76
75
  - Use `ctx.step("phase-name", () => …)` for any named non-agent phase.
77
76
 
78
77
  4. Show the complete file plus a separate `prompt.md` (or per-phase