원클릭으로
workflows
Delegate a big or high-stakes job to a fleet of parallel subagents, orchestrated deterministically; runs unattended and reports back
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Delegate a big or high-stakes job to a fleet of parallel subagents, orchestrated deterministically; runs unattended and reports back
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
Spawn external coding agents via the Agent Client Protocol (ACP)
Build and edit small, personal visual tools and artifacts — dashboards, trackers, calculators, data visualizations, charts, simple landing pages, and slide decks the user wants for THEMSELVES. This is the right skill whenever the user asks to "visualize this," "make a chart," or "build an artifact" for their own use, or to edit an app they already built here. Do NOT reach for a ui_show dynamic_page to fake an artifact — build a real persistent app here. NOT for complex, multi-user, or shippable products — those go to a real project folder with a coding agent (see Scope below).
Create images from a text description, or edit photos and graphics the user provides (remove backgrounds or watermarks, retouch, restyle, in-paint). Can produce multiple variants when the user wants options to choose from.
Read, search, send, and manage messages across Gmail, Outlook, Telegram, and other platforms
Trigger-action automation rules for handling incoming messages
Manage assistant voice and system settings
| name | workflows |
| description | Delegate a big or high-stakes job to a fleet of parallel subagents, orchestrated deterministically; runs unattended and reports back |
| compatibility | Designed for Vellum personal assistants |
| metadata | {"emoji":"⚙️","vellum":{"display-name":"Workflows","category":"system","always-candidate":true,"activation-hints":["Batch — apply one operation to each of MANY items (score / rate / rank / classify / extract / summarize each of a large set)","Comprehensive coverage — exhaustively sweep, audit, or find EVERY instance across a large surface","Research & synthesize — gather across many sources or pages and combine into one answer","Confidence — generate several independent attempts and judge them, or adversarially verify findings before trusting the result","Scale — work too large to finish well in one inline pass"],"avoid-when":["A single inline answer, a quick lookup, or a small one-off","Interactive, conversational back-and-forth rather than unattended fan-out"]}} |
A workflow is a short JS/TS script you author that runs in a sandbox and fans work
out across many short-lived leaf agents, orchestrated deterministically. Launch
one with run_workflow (inline script OR saved name, exactly one). It returns a
runId immediately; the run is asynchronous and you are notified in this
conversation when it completes — do NOT poll.
Reach for one when a job is too big, too parallel, or too important for one inline pass. That is more than batch/map-reduce over many items — it also covers exhaustively sweeping or auditing a large surface, researching across many sources and synthesizing, and generating several independent attempts to judge or adversarially verify before trusting the result. For a single task or a quick lookup, do it inline.
These are the load-bearing invariants. Get them wrong and the run misbehaves silently.
awaitHost functions block and return their result directly. Write straight-line code.
const r = agent("Summarize this thread."); // r is the result, right here
Do not write await agent(...), and do not make the script async. An
async script deadlocks on its second host call — the sandbox can suspend the main
evaluation stack but not a promise continuation.
metaThe first statement must be a pure-literal export — no computed values, template strings, or concatenation:
export const meta = {
name: "triage-inbox",
description: "Triage and label inbox messages",
};
meta is extracted statically, without executing the script, so it must be a
plain object literal with string name and description. The name is how a saved
workflow is referenced by workflow(name) and the scheduler.
return the resultThe script body runs as a function. Its result is whatever it returns at the top
level — a bare trailing expression (e.g. result;) is discarded and the run
finishes with no result. Always return the value you want surfaced.
const result = agent(`Write the final summary: ${JSON.stringify(parts)}`);
return result;
Every leaf call is journaled by sequence number and input hash, so a resumed run can
replay the unchanged prefix instead of re-spawning agents. That only holds if the
script is deterministic, so Date.now(), Math.random(), and argless new Date()
throw. Pass any timestamps or random seeds in through args.
All functions are synchronous from the script's perspective.
| Function | Returns | Notes |
|---|---|---|
agent(prompt, opts?) | the leaf's result | Runs ONE leaf. Throws on leaf failure (fails the whole run). |
leaf(prompt, opts?) | a leaf descriptor | Runs nothing on its own; used inside parallel/map/pipeline. |
parallel(specs) | results[] | Runs an array of leaf(...) descriptors concurrently, results in input order. A failed leaf becomes null (never throws). |
map(items, build) | results[] | build(item, i) returns a leaf(...) descriptor per item; runs them like parallel. |
pipeline(items, ...stages) | results[] | Each stage(prev, i) returns a leaf(...) descriptor (run an agent) OR a plain value (pass through unchanged — filter/transform locally, no agent spent). Per-stage barrier: stage N+1 starts only after all of stage N finishes. |
phase(title) | — | Marks a named phase for progress reporting. |
log(msg) | — | Emits a progress log line. |
usage() | { agentsSpawned, inputTokens, outputTokens } | Live snapshot so a script can self-moderate. |
workflow(name, args?) | the child's result | Runs a SAVED workflow inline, depth 1 only (a child may not call workflow()). |
args | the run input | The args object passed to run_workflow. |
Use agent for a single sequential leaf (throws on failure). Use parallel/map/
pipeline for fan-out (a failed leaf is null, so a batch survives a few bad items).
opts for agent / leaf)| Option | Type | Effect |
|---|---|---|
schema | JSON Schema object literal | Forces structured output via a tool. A schema leaf runs with no tools — no file_read/file_list/recall/web_search, so it cannot read files or recall memory (pure judge/extractor). Pass anything it must judge inline in the prompt; a schema leaf told to "read these files" answers from the model's prior, not real data. Use a plain JSON Schema literal, not Zod. |
label | string | Short display/diagnostic label for the leaf. |
profile | string | Overrides the model profile. Must exist in llm.profiles or the leaf throws. See Listing profiles. |
persona | boolean | true makes the leaf speak AS the assistant (identity + memory) — use for output meant to be in the assistant's voice. Default is anonymous — use for impartial judging/extraction. |
persona: true is the costly path (it runs the full memory-injection pipeline). Use
it only for the few leaves whose output must be in the assistant's voice; keep bulk
judging/extraction anonymous.
The capabilities argument to run_workflow declares once, up front, what the
run's leaves may do. There are no per-call permission prompts inside a running
workflow.
{
"tools": ["file_write", "gmail_send"], // side-effecting tools granted to leaves
"hostFunctions": [], // host-function names the run may invoke
"persona": true // grant leaves persona (identity + memory)
}
file_read, file_list, recall, web_search. A schema leaf gets none of these
(it runs as a single forced-tool-choice call) — pass it inline content, never tell it to read.web_fetch is NOT in the baseline — an outbound fetch is side-effecting (its
URL can exfiltrate read data), so a leaf that must fetch a URL has to declare
"web_fetch" in capabilities.tools.web_fetch, …) or
host function makes the LAUNCH prompt the user for approval once — that single
approval covers the whole run. A read-only run (no declared tools) launches with no
prompt. Declare the minimum you need.Runs are autonomous but BOUNDED by a per-run agent cap — spend is structurally capped and you cannot exceed it.
Before choosing a profile for a leaf, look up the valid values rather than guessing
— an unknown profile throws.
manage_workflows with action
list_profiles. It returns the profile names defined in llm.profiles plus the
workspace-wide active profile.GET config/llm/profiles (operationId
llm_profiles_list), which clients use to populate profile dropdowns.Omit profile to use the default: a persona leaf mirrors the main agent (the active
profile floats above the call-site default); an anonymous leaf uses the cost-optimized
workflowLeaf default.
Use manage_workflows to inspect and control runs:
| Action | Requires | Purpose |
|---|---|---|
status | run_id | Status + agent/token counts for one run (NOT the result). |
get_result | run_id | The full result of a finished run. |
list_runs | — | Recent runs, newest first. |
abort | run_id | Signal an in-flight run to abort. |
resume | run_id | Resume an interrupted run (see below). |
list_profiles | — | List defined profiles + the active profile (for leaf profile). |
The completion notification injected when a run finishes carries a truncated
preview of the result (large results are cut off). To read the complete result,
call manage_workflows with action get_result and the run_id — status
deliberately omits the result to stay lightweight.
Resume is not automatic. If the assistant restarts mid-run, the run is reconciled
to status interrupted (the agent/token accounting is preserved so the agent cap
still carries across the restart). It sits there until you explicitly resume it by
run_id via manage_workflows action resume. Resuming re-invokes the engine with
the same runId: the journal replays the completed prefix without re-spawning (or
re-paying for) finished leaves, then continues from the first unfinished leaf under the
run's originally-declared capabilities. Only interrupted runs are resumable; a
completed / failed / aborted run is terminal.
Score each inbox item in parallel (anonymous schema leaves), then write one summary in
the assistant's voice (a single persona leaf). The item list comes in via args —
never fetched inside the script.
export const meta = {
name: "triage-inbox",
description: "Score and summarize inbox items",
};
phase("score");
const scored = map(args.items, (item) =>
leaf(`Rate this message's urgency 0-10 with a one-line reason:\n${item.subject}\n${item.body}`, {
label: `score:${item.id}`,
schema: {
type: "object",
properties: { urgency: { type: "number" }, reason: { type: "string" } },
required: ["urgency", "reason"],
},
}),
);
phase("summarize");
const summary = agent(
`Here are scored inbox items. Write a short triage summary, highlighting anything urgent:\n${JSON.stringify(scored)}`,
{ persona: true },
);
return summary;
A failed scoring leaf shows up as null in scored; the run continues.