@agent-compose/cli 0.2.1 → 0.3.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.
@@ -0,0 +1,132 @@
1
+ ---
2
+ name: ac:schedule
3
+ description: Create, list, and delete cron schedules attached to registered workflows.
4
+ argument-hint: <create|list|delete> [args]
5
+ allowed-tools: Bash(agentc *)
6
+ ---
7
+
8
+ # Schedules
9
+
10
+ Cron schedules attached to a registered workflow. A workflow can have N
11
+ named schedules with distinct cadences; each tick dispatches a fresh
12
+ run tagged with the schedule's id + name so the dashboard attributes
13
+ the run to its trigger and filters Runs by schedule.
14
+
15
+ > **Mental model.** A schedule is a `(name, workflow, cron)` triple
16
+ > scoped to a factory. Names are unique per factory; ids are stable
17
+ > across re-registers (which makes "show me every run this schedule
18
+ > ever fired" work even when the target template gets new versions).
19
+ > Schedules are independent of workflow lifecycle — deleting a schedule
20
+ > doesn't touch the workflow, deleting a workflow cascades to its
21
+ > schedules.
22
+
23
+ ## Context
24
+
25
+ Registered workflows:
26
+ ```
27
+ !`agentc list 2>/dev/null | awk '{print $1}'`
28
+ ```
29
+
30
+ Existing schedules:
31
+ ```
32
+ !`agentc schedule list 2>/dev/null`
33
+ ```
34
+
35
+ ## Plan
36
+
37
+ Based on `$ARGUMENTS`:
38
+
39
+ | Arguments | Action |
40
+ |---|---|
41
+ | `create <name> --workflow <wf> --cron <expr>` | Create a schedule |
42
+ | `list` | List schedules in the active factory |
43
+ | `delete <id>` | Delete a schedule by id |
44
+ | *(none)* | Ask which subcommand and walk through args |
45
+
46
+ ### Create
47
+
48
+ ```bash
49
+ agentc schedule create <name> --workflow <wf> --cron '<expr>'
50
+ ```
51
+
52
+ - `<name>` — kebab-case, unique per factory (e.g. `nightly-triage`).
53
+ - `--workflow <wf>` — must be a registered workflow in the same factory.
54
+ - `--cron '<expr>'` — UTC, standard 5-field cron. Quote it (shells eat
55
+ the wildcards otherwise). Common patterns:
56
+ - `'0 9 * * *'` — daily at 09:00 UTC
57
+ - `'*/15 * * * *'` — every 15 minutes
58
+ - `'0 * * * 1-5'` — hourly on weekdays
59
+ - `--factory <slug>` — pin to a specific factory (default: active).
60
+
61
+ Read `--cron` aloud back to the user to confirm — the symbol soup
62
+ hides bugs. If unsure, use `cronstrue` (the dashboard renders the
63
+ human form on the Schedules tab).
64
+
65
+ ### List
66
+
67
+ ```bash
68
+ agentc schedule list
69
+ agentc schedule list --factory my-factory
70
+ ```
71
+
72
+ Output is one row per schedule:
73
+
74
+ ```
75
+ <name> <workflow> <cron> next: <ISO> <schedule-id>
76
+ ```
77
+
78
+ The dashboard's `/factories/<slug>/workflows` → **Schedules** tab is
79
+ the richer view: human cadence (cronstrue), next/last fire times,
80
+ delete button, click-through to the Runs view filtered by schedule.
81
+
82
+ ### Delete
83
+
84
+ ```bash
85
+ agentc schedule delete <schedule-id>
86
+ ```
87
+
88
+ Confirm with the user first — "Delete schedule `<name>`? It will stop
89
+ firing immediately; existing runs are unaffected." Schedule ids come
90
+ from `agentc schedule list` or the dashboard.
91
+
92
+ ## Shorthand on register
93
+
94
+ `agentc register <file> --schedule '<cron>'` auto-creates a schedule
95
+ **named after the workflow** at register time. Useful when a workflow
96
+ has exactly one cadence and you don't need a separate name:
97
+
98
+ ```bash
99
+ agentc register pipeline.ts --schedule '0 9 * * *'
100
+ # → registers "pipeline" + creates schedule "pipeline" at 09:00 UTC
101
+ ```
102
+
103
+ Re-registering with the same cron is a no-op; changing the cron
104
+ updates the existing schedule's row. Drop `--schedule` (or pass
105
+ `null`) to clear the auto-shorthand schedule. Schedules created via
106
+ `agentc schedule create` with a different name are left alone.
107
+
108
+ For workflows with multiple cadences (e.g. weekday + weekend), use
109
+ `agentc schedule create` explicitly — the register shorthand only
110
+ manages a single same-name schedule.
111
+
112
+ ## Filtering runs
113
+
114
+ Every run dispatched by a schedule carries `_scheduleId` +
115
+ `_scheduleName` on its metadata. The dashboard's Schedules tab makes
116
+ the schedule name a link straight into a filtered Runs view; the
117
+ chip on each row links back. From the CLI, the metadata is visible
118
+ on `agentc logs <run-id>` and via the SDK's `getRunById`.
119
+
120
+ ## Next Steps
121
+
122
+ - **Schedule created** → "Wait for the first tick (next fire shown in
123
+ `agentc schedule list`); the dispatched run shows up in the dashboard
124
+ Runs view with a `schedule by <name>` link."
125
+ - **`workflow "..." not found`** → Register the target template first
126
+ (`/ac:register <file.ts>`) — schedules can only target workflows
127
+ that already exist.
128
+ - **`schedule "..." already exists`** → Name collision. Either use
129
+ `agentc schedule delete <id>` first or pick a new name.
130
+ - **Schedule never fires** → Check the workflow's `bootFrom`
131
+ (`/ac:snapshots`) — runs against a missing snapshot fail at
132
+ dispatch. The schedule still ticks; only the workflow run fails.
@@ -86,6 +86,9 @@ This lists registered workflows. If it returns without error, setup is complete.
86
86
 
87
87
  > "You're all set. Here's what you can do now:"
88
88
  >
89
- > - `/ac:demo` — watch AI agents build a browser game end-to-end
89
+ > - `/ac:tutorial` — hands-on walkthrough of register, invoke, schedule, events, and snapshots (~10 min)
90
90
  > - `agentc invoke <workflow> --follow` — run any registered workflow
91
91
  > - `/ac:generate-workflow` — build your own workflow from a description
92
+ > - `/ac:schedule create <name> --workflow <wf> --cron '<expr>'` — fire
93
+ > a workflow on a cron schedule (each tick shows up in the Runs view
94
+ > with a `schedule by <name>` link)
@@ -107,8 +107,16 @@ export default defineWorkflow({
107
107
  // On every successful run — captures the sandbox VM after the last step:
108
108
  defineWorkflow({ snapshots: { saveLatest: true }, run: ... });
109
109
 
110
- // Retain one per step (storage scales with step count):
111
- defineWorkflow({ snapshots: { saveLatest: true, retainSteps: true }, run: ... });
110
+ // Retain one snapshot per step (storage scales linearly with step count).
111
+ // Most useful with step-form workflows where each `.step(definedStep)`
112
+ // is a distinct engine step; a run-form workflow has only one outer
113
+ // "run" step, so `retainSteps: true` there behaves the same as
114
+ // `saveLatest: true` alone.
115
+ defineWorkflow({ id: "pipeline", input, output, snapshots: { saveLatest: true, retainSteps: true } })
116
+ .step(fetchStep)
117
+ .step(scoreStep)
118
+ .step(pickTopStep)
119
+ .build();
112
120
  ```
113
121
 
114
122
  Per-invocation override:
@@ -0,0 +1,375 @@
1
+ ---
2
+ name: ac:tutorial
3
+ description: Hands-on tutorial — register, invoke, schedule, emit events, capture snapshots. ~10 minutes against a running stack.
4
+ effort: high
5
+ allowed-tools: Bash(agentc *) Bash(git *) Bash(open *) Read Write Edit
6
+ ---
7
+
8
+ # Tutorial — agent-compose
9
+
10
+ A hands-on walkthrough of every surface that matters. Builds one tiny
11
+ workflow and uses it to demonstrate the five things you'll actually
12
+ care about in production:
13
+
14
+ 1. **Author + register** a workflow.
15
+ 2. **Invoke** it and watch the run live.
16
+ 3. **Schedule** it to fire on a cron.
17
+ 4. **Emit events** from inside the workflow + inspect them.
18
+ 5. **Snapshot** the sandbox state + boot another workflow from it.
19
+
20
+ Should take ~10 minutes against the hosted server (a bit longer
21
+ locally — the runner sandbox boots fresh each time).
22
+
23
+ ## Pre-flight
24
+
25
+ ```
26
+ !`agentc auth status`
27
+ ```
28
+
29
+ If the line above shows no API key, run `/ac:setup` first.
30
+
31
+ ## Mental model
32
+
33
+ Three primitives. Read once, refer back when something doesn't make
34
+ sense:
35
+
36
+ > **Workflow** — the unit of work you author. Two shapes:
37
+ > `async (ctx, sandbox) => T` (run-form, single body) or
38
+ > `defineWorkflow({...}).step(s1).step(s2).build()` (step-form, typed
39
+ > pipeline). This tutorial uses run-form because it's the smaller
40
+ > mental load; step-form is the right shape when the work decomposes
41
+ > into typed phases.
42
+
43
+ > **Agent loop** — `agent({ runtime, prompt, ... })`. Lives inside the
44
+ > workflow body. Drives one iteration of an LLM agent against the
45
+ > runner sandbox until the model emits `exit_signal: true` or hits
46
+ > the budget.
47
+
48
+ > **Runtime** — `claudeRuntime` (built-in, wraps the Claude CLI).
49
+ > `openAIDesktopRuntime` (computer-use). Write your own with
50
+ > `defineRuntime`.
51
+
52
+ Everything else — schedules, events, snapshots, secrets — wraps these
53
+ three.
54
+
55
+ ## Step 1 — Scaffold
56
+
57
+ Create `hello-agent.ts` next to where the user wants to work. Walk
58
+ them through the file before writing — point at `ctx`, `sandbox`,
59
+ `agent`, the prompt, the tool allowlist, the budget, and the
60
+ `ctx.reportEvent` call (we'll use that in step 4). Confirm before
61
+ saving.
62
+
63
+ ```ts
64
+ // hello-agent.ts
65
+ import { defineWorkflow, agent, claudeRuntime } from "@agent-compose/sdk";
66
+
67
+ const PROMPT = `
68
+ You're verifying agent-compose is wired up correctly.
69
+
70
+ Run \`echo "hello from sandbox $(hostname)"\` once, then emit a
71
+ <status> block with a summary describing what you observed and
72
+ exit_signal: true.
73
+ `;
74
+
75
+ export default defineWorkflow({
76
+ async run(ctx, sandbox) {
77
+ const result = await agent({
78
+ sandbox,
79
+ runtime: claudeRuntime,
80
+ prompt: PROMPT,
81
+ tools: ["Bash"],
82
+ budget: { turnsPerIteration: 6, maxIterations: 1 },
83
+ });
84
+
85
+ // Emit a custom event so step 4 has something to inspect.
86
+ await ctx.reportEvent("tutorial.verified", {
87
+ summary: result.status?.summary ?? "(no summary)",
88
+ attributes: { completed: !!result.status?.completed },
89
+ });
90
+
91
+ return { ok: !!result.status?.completed, summary: result.status?.summary };
92
+ },
93
+ });
94
+ ```
95
+
96
+ ## Step 2 — Register and invoke
97
+
98
+ ```bash
99
+ agentc register hello-agent.ts
100
+ agentc invoke hello-agent --follow
101
+ ```
102
+
103
+ > "The CLI bundles the workflow source + the runtime source via
104
+ > `bundleWorkflow`, then POSTs to `/api/v1/factories/<slug>/templates`.
105
+ > The server creates a runner sandbox, drops the bundle in, and starts
106
+ > Node. Inside, our workflow runs `agent` once — Claude spawns, runs
107
+ > the bash command, emits its `<status>`, and exits. Server marks the
108
+ > run complete; the CLI prints elapsed time and the final outcome."
109
+
110
+ Watch the SSE-streamed events live — point out:
111
+ - `step_started` / `step_completed` (timeline phases).
112
+ - `agent_event` lines (model output streaming live).
113
+ - `event_reported` for the `tutorial.verified` event we emitted (step 4
114
+ picks this up).
115
+ - `run_complete` with elapsed time.
116
+
117
+ Copy the run id from the final output — needed for step 4.
118
+
119
+ ## Step 3 — Schedule it
120
+
121
+ Schedules fire your workflow on a cron. Names are unique per factory
122
+ and stable across re-registers, so historical runs stay attributed
123
+ even when the target template gets new versions.
124
+
125
+ ```bash
126
+ agentc schedule create hello-every-2min \
127
+ --workflow hello-agent \
128
+ --cron '*/2 * * * *'
129
+ ```
130
+
131
+ Wait two minutes, then list runs (or open the dashboard's Runs view):
132
+
133
+ ```bash
134
+ agentc list # registered templates
135
+ # In the dashboard, /factories/<slug>/workflows → Schedules tab shows
136
+ # `hello-every-2min` with the cadence in plain English and the next
137
+ # fire time. Clicking the name filters Runs to just this schedule.
138
+ ```
139
+
140
+ When you're done, clean up:
141
+
142
+ ```bash
143
+ agentc schedule list # find the id
144
+ agentc schedule delete <schedule-id>
145
+ ```
146
+
147
+ > "Schedules are independent of the workflow — deleting a schedule
148
+ > doesn't touch the template, deleting the template cascades to its
149
+ > schedules. A workflow can have N named schedules for different
150
+ > cadences (weekday vs weekend, hourly vs daily, etc)."
151
+
152
+ ## Step 4 — Inspect events
153
+
154
+ `ctx.reportEvent(...)` inside the workflow body emits structured
155
+ events the dashboard timeline renders, downstream workflows subscribe
156
+ to, and analytics queries scan. List the events on the run we did in
157
+ step 2:
158
+
159
+ ```bash
160
+ agentc events list <run-id>
161
+ ```
162
+
163
+ You should see `tutorial.verified` with the summary we emitted.
164
+
165
+ Send a synthetic event from the CLI to verify the write path (useful
166
+ for testing downstream subscribers without re-running the workflow):
167
+
168
+ ```bash
169
+ agentc events send <run-id> tutorial.poke \
170
+ --body '{"source":"tutorial"}' \
171
+ --summary "manual poke from /ac:tutorial"
172
+ ```
173
+
174
+ List again — `tutorial.poke` is now there too.
175
+
176
+ > "Events are idempotent on `(run, name, idempotency-key)`, propagate
177
+ > to subscribers, and live in the same timeline as lifecycle events.
178
+ > Production workflows emit them via `ctx.reportEvent` — the CLI form
179
+ > is for testing + verification."
180
+
181
+ ## Step 5 — Snapshots
182
+
183
+ A snapshot is the on-disk state of a runner VM at the end of a
184
+ successful step. Other workflows boot from it instead of running
185
+ their own setup. Useful for:
186
+
187
+ - Pre-baked sandbox environments (Claude CLI installed, deps fetched,
188
+ caches warm).
189
+ - Re-running a workflow with the same starting state every time.
190
+
191
+ For the tutorial, capture one from the next `hello-agent` run by
192
+ adding `snapshots: { saveLatest: true }` to the workflow:
193
+
194
+ ```ts
195
+ export default defineWorkflow({
196
+ snapshots: { saveLatest: true }, // ← add this
197
+ async run(ctx, sandbox) { /* unchanged */ },
198
+ });
199
+ ```
200
+
201
+ Re-register and invoke:
202
+
203
+ ```bash
204
+ agentc register hello-agent.ts
205
+ agentc invoke hello-agent --follow
206
+ ```
207
+
208
+ After the run completes, list captured snapshots:
209
+
210
+ ```bash
211
+ agentc snapshot list --workflow hello-agent
212
+ ```
213
+
214
+ Copy the `snap_…` id. Now author a *second* workflow that boots from
215
+ it instead of starting from a blank sandbox:
216
+
217
+ ```ts
218
+ // hello-consumer.ts
219
+ import { defineWorkflow } from "@agent-compose/sdk";
220
+
221
+ export default defineWorkflow({
222
+ snapshots: { bootFrom: { snapshotId: "snap_PASTE_ID_HERE" } },
223
+ async run(ctx, sandbox) {
224
+ const result = await sandbox.commands.run("ls -la /home/user");
225
+ return { listing: result.stdout };
226
+ },
227
+ });
228
+ ```
229
+
230
+ ```bash
231
+ agentc register hello-consumer.ts
232
+ agentc invoke hello-consumer --follow
233
+ ```
234
+
235
+ `hello-consumer` starts in the exact state `hello-agent` left the
236
+ sandbox in — same files, same processes, same env. No setup re-runs.
237
+
238
+ > "Snapshot ids are the unit of identity. There's no 'latest of
239
+ > workflow X' resolution at dispatch time — operators pick an id from
240
+ > `agentc snapshot list` (or the dashboard's snapshots page) and
241
+ > paste it. Deleting a snapshot makes any workflow referencing it 503
242
+ > at dispatch; the consuming workflow needs to be re-registered with
243
+ > a different id."
244
+
245
+ ## Step 6 — From your own code (SDK)
246
+
247
+ Everything you just did with the CLI is also available programmatically
248
+ via `@agent-compose/sdk`. The CLI is a thin wrapper around the same
249
+ `AgentComposeClient` — what you see in `agentc <verb>` is what your
250
+ backend code does. Useful for:
251
+
252
+ - Triggering workflows from another service (webhook handlers, queue
253
+ consumers, internal dashboards).
254
+ - Listing runs / schedules from your own admin UI.
255
+ - Wiring agent-compose into a CI pipeline without shelling out to
256
+ `agentc`.
257
+
258
+ Install it as a dependency of the calling project (it's a public npm
259
+ package):
260
+
261
+ ```bash
262
+ npm install @agent-compose/sdk # or bun add @agent-compose/sdk
263
+ ```
264
+
265
+ Construct a client with an API key (mint one in the dashboard's
266
+ Settings → API Keys; the CLI uses the same shape):
267
+
268
+ ```ts
269
+ import { AgentComposeClient } from "@agent-compose/sdk";
270
+
271
+ const client = new AgentComposeClient({
272
+ baseURL: process.env.AGENTC_URL ?? "http://localhost:8080",
273
+ apiKey: process.env.AGENTC_API_KEY!, // ac_…
274
+ });
275
+ ```
276
+
277
+ > "The SDK is Bearer-authed (Authorization: ac_…). It's the same
278
+ > entry point the CLI uses — `agentc invoke foo` is literally
279
+ > `client.invoke('foo', …)`. Browser code talks to the server via a
280
+ > cookie-bound dashboard-internal fetch wrapper instead, but that's
281
+ > a dashboard-only seam; server-to-server is the SDK."
282
+
283
+ ### Invoke a workflow + wait for the result
284
+
285
+ ```ts
286
+ // Fire-and-forget — returns a runId you can stream later.
287
+ const { runId } = await client.invoke("hello-agent", { input: {} });
288
+
289
+ // Block until the run settles, return the typed output:
290
+ const result = await client.invokeAndWait<{ ok: boolean; summary?: string }>(
291
+ "hello-agent",
292
+ { input: {}, timeoutMs: 120_000 },
293
+ );
294
+ console.log(result.outcome, result.output?.summary);
295
+ ```
296
+
297
+ ### Schedules (matches `agentc schedule …`)
298
+
299
+ ```ts
300
+ const schedules = await client.listSchedules(); // → ScheduleRow[]
301
+ await client.createSchedule({
302
+ name: "nightly",
303
+ workflow: "hello-agent",
304
+ cron: "0 9 * * *", // UTC
305
+ });
306
+ await client.deleteSchedule(scheduleId);
307
+ ```
308
+
309
+ ### Events (matches `ctx.reportEvent` inside the workflow + `agentc events`)
310
+
311
+ ```ts
312
+ // Read what a run emitted:
313
+ const events = await client.listRunEvents(runId);
314
+
315
+ // Or factory-wide (audit / cross-workflow analytics):
316
+ const recent = await client.listFactoryEvents({ limit: 200 });
317
+
318
+ // Send a synthetic event into a run from outside:
319
+ await client.reportEvent(runId, {
320
+ name: "deploy.completed",
321
+ summary: "deploy to prod succeeded",
322
+ body: { sha: "abc123" },
323
+ });
324
+ ```
325
+
326
+ ### Snapshots (matches `agentc snapshot list`)
327
+
328
+ ```ts
329
+ const captured = await client.listSnapshots({ workflowName: "hello-agent" });
330
+ const perRun = await client.listRunSnapshots(runId);
331
+ ```
332
+
333
+ To boot another workflow from a captured snapshot, set
334
+ `snapshots: { bootFrom: { snapshotId: "snap_…" } }` in
335
+ `defineWorkflow(...)` — same shape the CLI's register step writes.
336
+
337
+ ### Stream a run's logs
338
+
339
+ ```ts
340
+ for await (const line of client.streamRunLogs(runId)) {
341
+ console.log(`[${line.stream}] ${line.line}`);
342
+ }
343
+ ```
344
+
345
+ The full set of methods is on `AgentComposeClient` — the same surface
346
+ the dashboard playground and `/ac:logs` skill use. See the SDK's
347
+ [`README`](../../sdk/README.md) for the type-checked reference.
348
+
349
+ ## Step 7 — Where to go next
350
+
351
+ > "You've now used every primitive. To go further:"
352
+ >
353
+ > - `/ac:generate-workflow` — describe a multi-phase workflow in
354
+ > plain English; Claude scaffolds the file with `agent` blocks per
355
+ > phase and the right input/output schemas.
356
+ > - `/ac:generate-agent` — scaffold one agent loop's prompt + snippet
357
+ > to slot into an existing workflow.
358
+ > - `/ac:secrets` — wire up brokered network secrets (GCP Secret
359
+ > Manager → injected at the Vercel firewall).
360
+ > - `/ac:schedule` — the dedicated schedules walkthrough.
361
+ > - `/ac:snapshots` — list, inspect, delete captured snapshots.
362
+ > - `/ac:events` — full events reference.
363
+ > - Read [`docs/how-it-works.md`](../../docs/how-it-works.md) for the
364
+ > multi-agent example (plan + parallel implementers).
365
+
366
+ ## Cleanup
367
+
368
+ ```bash
369
+ agentc schedule delete <hello-every-2min-id> # if you created one
370
+ agentc snapshot delete <run-id> <snap-id> # if you captured one
371
+ rm hello-agent.ts hello-consumer.ts # local files
372
+ ```
373
+
374
+ Or keep them as references — registered templates stay in the team
375
+ factory until you `agentc factory ...` them out.
package/skills/ac:demo.md DELETED
@@ -1,134 +0,0 @@
1
- ---
2
- name: ac:demo
3
- description: First-run walkthrough — verify auth, scaffold a sample workflow, register it, invoke, and watch the agent run live.
4
- effort: high
5
- allowed-tools: Bash(agentc *) Bash(git *) Bash(open *) Read Write Edit
6
- ---
7
-
8
- # Demo — agent-compose
9
-
10
- A guided first-run walkthrough. Verify auth, generate a tiny sample
11
- workflow, register it, dispatch it, and watch a single agent loop run
12
- end-to-end. Should take ~5 minutes against the hosted server (a bit
13
- longer locally — the runner sandbox boots fresh).
14
-
15
- ## Context
16
-
17
- ```
18
- !`agentc auth status`
19
- ```
20
-
21
- If the line above shows no API key, run `/ac:setup` first (sign in to
22
- the dashboard, mint an `ac_…` key, `agentc auth login <key>`). That
23
- skill walks the full bootstrap.
24
-
25
- ## Steps
26
-
27
- ### 1. Briefly explain the model
28
-
29
- Make sure the user understands the three primitives before you start
30
- typing. Keep it brief — they can read [`docs/how-it-works.md`](../../docs/how-it-works.md)
31
- for the full version.
32
-
33
- > **Workflow** — `async (ctx, sandbox) => T`. The function you author.
34
- > Owns the run end-to-end: orchestrates phases, kicks off agent loops,
35
- > writes metadata, returns a structured result.
36
-
37
- > **Agent loop** — `agent({ runtime, prompt, ... })`. Embedded inside
38
- > the workflow body. Drives one iteration cycle of an LLM agent against
39
- > the runner sandbox until the model emits `exit_signal: true` (or
40
- > hits the iteration budget).
41
-
42
- > **Runtime** — `claudeRuntime` (built-in) wraps the Claude CLI.
43
- > `openAIDesktopRuntime` wraps OpenAI computer-use. You can write your
44
- > own with `defineRuntime`.
45
-
46
- ### 2. Scaffold a sample workflow
47
-
48
- Create a temporary `hello-agent.ts` next to where the user wants to
49
- work. Keep it minimal — one phase, no fancy plumbing:
50
-
51
- ```ts
52
- // hello-agent.ts
53
- import { defineWorkflow, agent, claudeRuntime } from "@agent-compose/sdk";
54
-
55
- const PROMPT = `
56
- You're verifying agent-compose is wired up correctly.
57
-
58
- Run \`echo "hello from sandbox $(hostname)"\` once, then emit a
59
- <status> block with summary describing what you observed and
60
- exit_signal: true.
61
- `;
62
-
63
- export default defineWorkflow({
64
- async run(ctx, sandbox) {
65
- const result = await agent({
66
- sandbox,
67
- runtime: claudeRuntime,
68
- prompt: PROMPT,
69
- tools: ["Bash"],
70
- budget: { turnsPerIteration: 6, maxIterations: 1 },
71
- });
72
- await ctx.setMetadata({ summary: result.status?.summary });
73
- return { ok: !!result.status?.completed, summary: result.status?.summary };
74
- },
75
- });
76
- ```
77
-
78
- Walk the user through the file — point at `ctx`, `sandbox`,
79
- `agent`, the prompt, the tool allowlist, the budget. Confirm before
80
- writing.
81
-
82
- ### 3. Register
83
-
84
- ```bash
85
- agentc register hello-agent.ts
86
- ```
87
-
88
- > "The CLI bundles the workflow source + the runtime source via
89
- > `bundleWorkflow`, then POSTs to `/api/v1/templates`. Once registered,
90
- > anyone with an `invoke`-scoped API key can call it."
91
-
92
- ### 4. Invoke and watch live
93
-
94
- ```bash
95
- agentc invoke hello-agent --follow
96
- ```
97
-
98
- > "The server creates a runner sandbox, drops the bundle in, and starts
99
- > Node. Inside the sandbox, our workflow runs `agent` once — Claude
100
- > spawns, runs the bash command, emits its `<status>`, and exits.
101
- > Server marks the run complete; the CLI prints the final outcome and
102
- > elapsed time."
103
-
104
- Watch the SSE-streamed events together — point out:
105
- - `step_started` / `step_completed` (timeline phases).
106
- - `agent_event` lines (model output streaming live).
107
- - `run_complete` with elapsed time.
108
-
109
- ### 5. Browse the run in the dashboard
110
-
111
- Once the run finishes, open the run detail page:
112
-
113
- ```bash
114
- # pull the dashboard URL from auth status; substitute the run id
115
- open "$(agentc auth status | awk '/^Dashboard:/ {print $2}')/workflows/<run-id>"
116
- ```
117
-
118
- The dashboard shows the same lifecycle events plus the captured
119
- artifacts (logs, metadata) the workflow emitted.
120
-
121
- ### 6. What to build next
122
-
123
- > "That was the simplest possible workflow. To go further:"
124
- >
125
- > - `/ac:generate-workflow` — describe a multi-phase workflow in plain
126
- > English; Claude scaffolds the full file with `agent` blocks per phase.
127
- > - `/ac:generate-agent` — scaffold one phase's prompt + `agent` snippet
128
- > to slot into an existing workflow.
129
- > - `/ac:generate-runtime` — write a custom runtime for a model the SDK
130
- > doesn't ship.
131
- > - Read [`docs/how-it-works.md`](../../docs/how-it-works.md) for the
132
- > multi-agent example (plan + parallel implementers).
133
-
134
- Clean up: `rm hello-agent.ts` (or keep it as a reference).