@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.
- package/README.md +4 -1
- package/dist/index.js +124 -23
- package/package.json +11 -11
- package/skills/ac:generate-workflow.md +353 -122
- package/skills/ac:invoke.md +31 -9
- package/skills/ac:register-invoke.md +44 -7
- package/skills/ac:register.md +4 -1
- package/skills/ac:schedule.md +132 -0
- package/skills/ac:setup.md +4 -1
- package/skills/ac:snapshots.md +10 -2
- package/skills/ac:tutorial.md +375 -0
- package/skills/ac:demo.md +0 -134
|
@@ -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.
|
package/skills/ac:setup.md
CHANGED
|
@@ -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:
|
|
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)
|
package/skills/ac:snapshots.md
CHANGED
|
@@ -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
|
-
|
|
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).
|