Build your first workflow — tutorial
Audience: a tenant employee or external Claude session that wants to ship a custom recipe in 30 minutes. Prerequisites: an Amdahl API key with
artifact:writescope; the Amdahl MCP server connected to your client. End state: a working workflow forked fromcontent-calendar, customized to your team's pillars and pacing, ready to read and walk from MCP.
Workflows run two ways. (a) Interactive — an LLM reads the recipe (agent_blueprint://<id>) and walks the steps itself; that's the MCP path this tutorial's audience uses. (b) Headless — the platform runs the workflow for you (how a workflow runs). Over MCP the blueprints coarse tool covers authoring + discovery; it also carries schedule actions, but they need the workflows:delegate scope that standard customer keys don't carry, so Run now / scheduling / backtests run over REST + the Anthropic tool surface (Workflows over the API). To run a workflow on demand from an MCP client, walk the recipe yourself. Workflows are written in a typed DSL (reference) and stored as agent_blueprint artifacts. The platform ships several forkable starters; this tutorial walks through forking the content-calendar starter, customizing it for your team, and walking the customized recipe yourself.
Step 1 — Look at the starter
The Amdahl-shipped starters are public. Read the calendar starter to see what you're starting from:
read_resource artifact://<content-calendar-blueprint-id>If you don't know the id off-hand, list public agent_blueprint artifacts:
read_resource agent_blueprint://list?slug=content-calendarYou'll see the validated DSL. Pay attention to:
identity.slug+version— you'll bump these when you fork.inputs— the surface customers fill in to run the workflow.policy.tool_allowlist— the operations the workflow'stoolsteps will call.steps— the recipe body. The steps run in order; the planning workflow emits placeholdercontent_piecerows, thenplan_and_draft_window(the composition starter) fans outdraft_pieceper planned piece in parallel.
Step 2 — Decide what to change
Common forks for plan_and_draft_window:
- Lock the channel — your team only publishes to LinkedIn; remove the
channelinput + hardcode'linkedin'everywhere. - Pin the audience lens — your ICP is fixed; remove the input + hardcode the audience filter.
- Tighten the cadence — replace
prompt://content_writer/cadence_rhythmwith your own fragment if your audience has unusual posting times. - Pillar-locked — bake the team's pillar set into the workflow and remove the optional input for fixed-pillar teams.
For this tutorial we'll do #1 — lock to LinkedIn.
Step 3 — Fork the starter
Forking is a single op: agents.fork_blueprint reads the starter, creates a tenant-owned copy, and returns the new artifact id. The fork starts at version 1.0.0, status draft, visibility private — you customize from there.
agents.fork_blueprint
source: 'content-calendar' # starter slug, OR a starter UUID, OR a tenant blueprint UUID
new_slug: 'team-x-linkedin-calendar' # optional; auto-generates `<source>-fork` when omitted
new_name: 'Team X LinkedIn Calendar' # optional; defaults to `Copy of <source name>`Returns:
{
"artifact_id": "<new-uuid>",
"slug": "team-x-linkedin-calendar",
"name": "Team X LinkedIn Calendar",
"source_kind": "starter",
}Once the fork lands, customize it via artifacts.update with the patches you want — drop the channel input, hardcode 'linkedin' in the steps that referenced $inputs.channel, etc. The fork's content_json is a full copy of the starter; you patch only the fields you care about.
artifacts.update
id: '<new-uuid>'
content_json:
inputs:
# Drop the `channel` input entirely; keep the rest.
- { name: 'voice_profile_id', type: 'artifact_ref', required: true, validate: { artifact_type: 'voice_profile' } }
- { name: 'period_start', type: 'date', required: true }
- { name: 'period_days', type: 'integer', default: 7, validate: { min: 3, max: 14 } }
- { name: 'piece_count', type: 'integer', default: 5 }
- { name: 'audience', type: 'string' }
- { name: 'pillar_ids', type: 'artifact_ref_list', validate: { artifact_type: 'content_pillar' } }
steps:
# Replace `$inputs.channel` with the literal `'linkedin'`
# everywhere the starter referenced it.
# ... (omitted for brevity; copy from the starter and edit)The fork now reflects your customization. Promote when ready via another artifacts.update with status: 'published'.
Step 4 — Walk your fork
You walk the fork yourself (the interactive path). Read the recipe back:
read_resource agent_blueprint://<your-fork-id>You get the inputs, the policy, and the step tree. Gather the inputs you'd supply:
voice_profile_id: '<your voice profile uuid>'
period_start: '2026-04-29'
period_days: 7
piece_count: 5
audience: 'B2B operators at Series B+ companies'
pillar_ids: ['<pillar-1>', '<pillar-2>', '<pillar-3>']Then perform each step in order with your own primitive tools — substituting $inputs.* with the values above and each $step_id with the output of the step you already ran. A tool step names the operation to call (data.cluster_search, artifacts.create, etc.); an llm step is reasoning you do yourself; loop / branch / parallel steps tell you how to fan out. (Headless runs — Run now, scheduling, backtest — execute on the platform, set up over REST + the Anthropic tool surface, not from your MCP session; see Workflows over the API.)
Step 5 — You're done when the steps are done
When you walk a workflow yourself there's no run row to close — when you've walked every step and written the artifacts the recipe produces (the calendar, the pieces, the drafts), the work is complete. (A headless platform run does record a row; see Run history.) Capture the artifact ids you created as you go; the recipe's outputs_mapping tells you which step output maps to which named output.
Step 6 — Iterate
Once you've walked it once and the output matches your taste, you're done. Common iteration patterns:
- Bump version to 1.1.0 when you tweak the prompt language or add a step. The version is authoring metadata on
identity.version; the next agent that reads the recipe picks up the new body. - Re-read the recipe (
read_resource agent_blueprint://<your-fork-id>) any time to confirm a change landed before walking it again. - Note on unattended use — the
trigger.schedulefield declares cron intent in the DSL, and the platform runs scheduled workflows for you headlessly. You set that up over REST + the Anthropic tool surface (blueprint_schedule.*; see Workflows over the API) — not from a standard MCP customer key, whose schedule actions need theworkflows:delegatescope it doesn't carry. From an MCP session, for ad-hoc recurring use just walk the recipe yourself (or wrap it in your own scheduled job that does).
What this recipe does and doesn't constrain
The recipe's policy.tool_allowlist is GUIDANCE you should respect, not a server-enforced contract. The API key's scope grammar is the real safety boundary. You may adapt mid-walk when an unanticipated case calls for a different tool.
This means: if a workflow declares a tight allowlist, follow it; if the API key has broader scope, you have the headroom to adapt. The workflow declares intent; the API key enforces it. The headless runner does not enforce the allowlist for you either — it runs against a least-privilege scoped token, so the API key's scope grammar, not the allowlist, is the real boundary on every surface.
What's next
- DSL reference — every field, every type, every kind.
- bootstrap_workspace reference, draft_piece reference, plan_and_draft_window reference, research_report reference — per-starter usage docs.