Imported from clode-labs/aramb-skills (
update-workflow/SKILL.md). Install upstream withnpx skills add clode-labs/aramb-skills --skill update-workflow. Copyright stays with the author.
Update Workflow
Produce a fresh, full replacement node + edge set for an existing workflow,
taking the existing definition into account as a hint about what worked. The
workflow ALREADY exists — the platform atomically swaps the new definition in when you
call aramb_mcp.workflows_update. The old definition stays live until that call
succeeds; in-flight runs continue against their snapshot.
If asked to CREATE a workflow from scratch, use
create-workflow. If polishing a template-import draft, useimport-workflow. This skill is update-only.
Which dispatch mode am I in? — read this first
The task_id / workflow_id referred to here are the platform's ids from the
dispatch block — NOT Claude's built-in TaskCreate.
- A) Task dispatch (you are master, dispatched as a system task). Your "Your
task id" block gives you
application_id,project_id,workflow_id, andtask_id. Regenerate from the application's user tasks — ALL statuses, read for intent (+ any user-supplied change request in the task description). Report progress on the task description; close witharamb_mcp.tasks_update. → Go to Path A below. - B) Chat dispatch, team mode (you have
aramb_mcp.tasks_*tools but NOtask_id). You are master launched directly from chat. Do not design the update inline. Look up the workflow and dispatch a proper system task, then exit — the dispatched task re-enters this skill via Path A. → Go to Path B below. - C) Chat dispatch, solo (no
task_id, and noaramb_mcp.tasks_*tools at all). You are solo. Author the update directly from chat — an explicit change request or the work done so far in this conversation. Close by replying in chat. → Go to Path C below.
Paths A and C share all the authoring rules (analyze the delta, setting-change
intent recognition, closing template, pre-flight, the aramb_mcp.workflows_update
call, side-effects). They differ only in where the change spec comes from,
assigned_agent handling, and how you report progress / close out. Path B is a
short hand-off that does no authoring.
MUST rules — read before anything else
- Every node in
aramb_mcp.workflows_updateMUST carryrequired_toolkits. Copy the slugs from each source task'srequired_toolkits(task dispatch) or the matching node inaramb_mcp.workflows_get/ the action it performs (chat dispatch). Use[](not omitted) when the node touches no third-party service. Omitting silently kills the Evaluate missing-connection warnings. Ground slugs viaaramb_mcp.toolkits_list_toolkits— don't trust a slug you can't see in the catalog. Never invent a toolkit binding, and never bind a platform-internal/hidden toolkit (composio,composio_search,browser_tool,slackbot,discord,discordbot,microsoft_teams) —aramb_mcp.workflows_updaterejects those; for Slack/Discord/Teams messaging deliver via the chat service'schat.send_dm(no toolkit). See thearamb-workflowsskill. - Every node that touches a third-party service MUST carry a singular
toolkit— its primary toolkit slug, used for trigger-binding. Invariant the platform enforces:toolkit ∈ required_toolkits. Omit (ornull) only whenrequired_toolkitsis[]. If the existing node had notoolkit(pre-v2 definition), add it now. - No placeholder syntax in any node
prompt. No{{env.KEY}}, no{{input.KEY}}. There is no substitution layer; the platform rejects any prompt matching{{ env.… }}. If a node you carry forward fromaramb_mcp.workflows_getstill contains legacy{{env.…}}placeholders, rewrite that prompt now to read its per-run values from<run_input>(see "Run input & slug grounding — v2 contract" below). - Do NOT declare
env_variables. Omit the field from thearamb_mcp.workflows_updatecall (leaving it out keeps nothing — there's no runtime path). If the existing definition declaredenv_variables, drop them: the schema rejects a non-empty map and the values were never read. - Every node's
promptMUST end with the workflow-step closing instruction so the executing agent callsaramb_mcp.workflows_update_step(with the explicitstep_idrendered into its dispatch) at the end of its run. See "Closing instruction per node" below.- Failure mode: Without it, the agent finishes its LLM session, the platform's safety net auto-closes the step, but
outputsstays NULL. The downstream step's## Upstream contextpreamble shows "(no summary)" instead of the real hand-off.
- Failure mode: Without it, the agent finishes its LLM session, the platform's safety net auto-closes the step, but
- Call
aramb_mcp.workflows_updateexactly once. Success or failure — never retry. - Close out cleanly. Task dispatch: always
aramb_mcp.tasks_update(status=doneon success,status=failedon any error) — never leavein_progress. Chat dispatch: confirm in your reply text. There is no task to close in chat dispatch. - Speak to the user in plain product language — never leak internals. No MCP tool names (
aramb_mcp.workflows_update), raw upstream errors (502from the integrations proxy), CLI names, or "the tool isn't in my surface." You have these tools — call them. Report real failures in human terms and stop.
Run input & slug grounding — v2 contract
These rules apply to every node you author or carry forward — same contract as
create-workflow:
-
Per-run context arrives in
<run_input>, not declared variables. The platform renders the user's instruction (manual run) or the trigger payload JSON (trigger run) into the first step's prompt as a<run_input>block. There are no input variables, no typed form, no{{env.KEY}}substitution. Write node prompts that tell the agent to read what it needs from the context it's given. -
<run_input>is first-step-only. Downstream steps see only their parent'soutputs.summary+outputs.files. So step 1's prompt MUST instruct the agent to distill the relevant input into its summary for propagation. If you're adding a new entry node or changing which node is first, make sure that node funnels the input forward. -
Empty input fails late, gracefully. A step that gets an empty
<run_input>should report "I don't have anything to work on" — no pre-flight gate. -
Ground slugs before drafting. Confirm toolkit slugs with
aramb_mcp.toolkits_list_toolkits(and trigger slugs witharamb_mcp.toolkits_list_triggers("<TOOLKIT>")when relevant). Slugs are uppercase, verbatim from the catalog — never inferred from prose.npx mcporter call aramb_mcp.toolkits_list_toolkits npx mcporter call aramb_mcp.toolkits_list_triggers toolkit="GITHUB" -
Migrating a legacy definition. If
aramb_mcp.workflows_getreturns nodes with{{env.…}}placeholders or a non-emptyenv_variablesmap, treat that as debt to clear in this update: rewrite the placeholder prompts to read from<run_input>, dropenv_variables, and add the per-nodetoolkitfield. The update will be rejected otherwise.
Path B — master, chat dispatch (no task_id): dispatch and exit
You were launched directly from chat instead of via the system-task dispatch, and
you have the aramb_mcp.tasks_* toolkit (team mode). Do not design the workflow
inline. Instead:
- Look up the project's workflows and pick the one to update:
(A project can hold several workflows — appless is the norm; don't assume one per application. If more than one matches the user's intent, ask which.)npx mcporter call aramb_mcp.workflows_list project_id="<PROJECT_ID>" - If a workflow exists — dispatch a proper system task and exit:
Then write a one-line confirmation in your reply text (e.g. "Starting workflow update, task <id>.") and STOP. (The platform saves your final assistant text as the chat row.) The dispatched system task arrives separately and reloads this skill with the correctnpx mcporter call aramb_mcp.workflows_update_from_tasks workflow_id="<WORKFLOW_ID_FROM_STEP_1>"workflow_id+task_id(Path A). - If no workflow exists — tell the user there is no workflow to update yet and
that they need to create one first (suggest the
create-workflowskill). Do NOT design or create one in this turn.
Do not continue past this section — there is no task_id to close in Path B.
Path A & C — author the update
Step 1. Fetch the existing definition
npx mcporter call aramb_mcp.workflows_get workflow_id="<workflow_id>"
Chat dispatch (Path C): if you don't have a workflow_id, find the project's
workflows and pick the one the user means (a project can hold several — appless
is the norm; if more than one matches, ask which):
npx mcporter call aramb_mcp.workflows_list project_id="<project_id>"
If no workflow exists (Path C), tell the user there's nothing to update and suggest
they describe the workflow they want — you'll use create-workflow to build it.
Stop here.
The response is the full canvas: name, description, env_variables, nodes,
edges, default_node_settings, stateful, status, plus schedule if one is
configured. Read it carefully — it's your starting point. Don't throw it away
unless you have a reason.
Step 2. Gather the change spec
Path A (task dispatch) — fetch the user tasks (ALL statuses):
npx mcporter call aramb_mcp.tasks_list \
application_id="<application_id>" \
limit="200"
Same shape as create-workflow, including limit="200" (the max — the default page
is 50, and total in the response tells you whether there are more to page with
offset): do NOT filter by status="done" — read intent
from the whole user-task corpus regardless of success. Ignore
task_kind == "system", read task_kind == "user" only.
Then check the dispatched task description for a User-supplied change request:
section. If present, that text is the user's verbatim instruction (e.g. "add a
Slack DM step after the standup comment", "remove the email triage step"). Treat
it as a first-class authoring signal — apply it directly to the relevant
node(s), in addition to whatever the task corpus diff suggests. Without acting on
it, the user's ask vanishes silently. If no such section exists, you're in plain
regeneration mode (FE-button or "refresh the workflow" intent).
Path C (chat dispatch, solo) — classify the user's message:
- Explicit change ("add a Slack DM step", "remove the email triage", "change the synth step to also include the calendar"): use the user's message as the change spec verbatim. Skip ahead to step 4.
- History-derived (canned button message: "update the existing workflow based on the work done in this chat", or any phrasing pointing at the conversation as evidence): treat your conversation since the workflow was last saved as the evidence. Walk back and produce, in your reasoning: (a) new ordered steps you ran, (b) data hand-offs between them, (c) toolkits actually called, (d) one-off specifics vs the recurring shape. Generalize, don't transcribe — strip one-off dates / values; the workflow is a recipe.
Step 3. Reject firing-condition change requests (schedule or trigger)
A workflow's definition and its firing conditions live in different storage
and different skills. If the change request is solely about when/why the
workflow fires, DO NOT call aramb_mcp.workflows_update — route it:
- Cron / wall-clock timing ("change the schedule to weekly", "stop the cron",
"move it to UTC", "run it every Monday at 9am instead of Tuesday", "pause the
schedule", "stagger the fire time / don't run at exactly 9:00") →
schedule-workflow. Cron fields — including the optionalrandom_delay_enabled/random_delay_max_minutesjitter — live in flat columns on the workflow row. - Event trigger ("fire it on a new GitHub issue too", "stop firing on pushes",
"trigger when I get a Slack DM instead") →
configure-trigger. Event triggers live inworkflow_triggersrows. - Run-status callback ("POST run status to my endpoint", "add/change the
callback URL", "stop sending run webhooks") → set
callback_urldirectly viaaramb_mcp.workflows_set_callback(workflow-level config; see thearamb-workflowsskill). This is NOT a definition change — do NOT callaramb_mcp.workflows_updatefor it. Path C: callset_callbackyourself; Path A: close with a hint so master handles it.
Touching either through aramb_mcp.workflows_update regenerates the definition for
nothing and ignores the actual ask. Reject and route (the examples below use the
cron case; for an event condition, substitute configure-trigger for
schedule-workflow).
- Path A (task dispatch): close the task as failed so master routes correctly:
npx mcporter call aramb_mcp.tasks_update \ task_id="<your task_id>" \ status="failed" \ rejection_reason="schedule-shaped change request — dispatch schedule-workflow skill instead with workflow_id=<id> and the user's exact phrase" - Path C (chat dispatch, solo): use the
schedule-workflowskill (cron) or theconfigure-triggerskill (event) from your loadout directly. Send a one-line confirmation. Do not callaramb_mcp.workflows_updateat all.
If the request is mixed (definition change + firing-condition change in one
sentence), apply the definition change per the rest of this skill, then: Path A —
add a schedule_hint (cron) or trigger_hint (event) to your closing outputs
so master dispatches the right skill next; Path C — call
aramb_mcp.workflows_set_schedule (cron) yourself, or use configure-trigger (event),
right after aramb_mcp.workflows_update succeeds.
Step 4. Analyze the delta
Update progress: "Designing updated workflow — N nodes, M levels" (Path A: append a
## Progress bullet to the task description; Path C: narrate in your reply text).
Intent recognition for setting changes
Many change requests don't change the graph — they change a setting. Recognize the intent and apply at the right level. The defaults block is default_node_settings on the workflow; per-node deviations live in each node's settings. Workflow defaults inherit down; per-node values override.
| User phrase | Where to apply |
|---|---|
| "all steps should use Opus" / "switch the model to Opus" | default_node_settings.model = "claude-opus-4-7" (workflow) |
| "the synth step should use Opus" | that one node's settings.model = "claude-opus-4-7" (override) |
| "use Sonnet everywhere except the writer step, which should be Opus" | workflow default_node_settings.model = "claude-sonnet-4-6" AND that one node's settings.model = "claude-opus-4-7" |
| "give it a $50 budget" / "raise the budget to $50" | workflow-level budget_usd = 50.0. Cumulative cap across the whole run (passed to the agent runtime as maxSessionCostUsd). |
| "cap the synth step at $5" / per-step budget | Reject. Budget caps are workflow-level only. Reply: "Budget caps apply to the whole workflow run, not individual steps. I'll set the workflow budget to $5 if that's what you meant." |
| "this step shouldn't auto-approve" / "make me approve the email step" | that one node's settings.approval_mode = "manual" |
| "auto-approve everything" | workflow default_node_settings.approval_mode = "auto" AND clear approval_mode from any per-node settings overrides |
| "always respond in IST" / "use markdown for replies" / "cite sources" | default_node_settings.instructions = "<phrase>" (workflow) |
| "for this step, prefer concise bullets" | that one node's settings.instructions = "<phrase>" (appends to workflow-level) |
| "give it more turns" / "let each step go up to 80 turns" | default_node_settings.max_turns = 80 (workflow) |
| "let the synth step take longer" | that one node's settings.max_turns = 80 (override) |
| "turn extended thinking off" | default_node_settings.thinking = "off" (workflow) |
| "turn admin on" | default_node_settings.admin = true — only when the user explicitly asks. Off by default. |
Inheritance model — be explicit in the user reply. When you change a workflow default, mention what it implies for nodes that had overrides ("Set the workflow default to Opus and cleared the node override on the synth step so it inherits."). When you set a node override, name the node ("Switched the synth step to Opus; other steps still use the workflow default of Sonnet.").
Don't touch settings the user didn't ask about. Carry the existing
default_node_settings and per-node settings through unchanged from
aramb_mcp.workflows_get (step 1). Edit only the fields the user named.
Graph delta
Compare the existing definition against the change spec (task corpus + change request, or the user's explicit change / chat work):
- New steps the change reflects that the existing graph doesn't have? Add nodes.
- Existing nodes obsolete now (user said remove, or new work supersedes them)? Drop them.
- Reworded step / changed logic? Update that node's
prompt. - Agent assignments changed? Update
assigned_agentper node (see below). - Toolkits changed? Update
required_toolkitsand the singulartoolkitper node (grounded viaaramb_mcp.toolkits_list_toolkits). - Legacy
{{env.…}}placeholders or declaredenv_variablescarried over from the old definition? Clear them — rewrite the prompts to read from<run_input>and drop theenv_variablesmap.
Lean on the existing definition. Resist rewriting from scratch. If 80% of the graph is unchanged, keep 80% unchanged. The user already saw and accepted the existing version; the change spec tells you which 20% to actually touch.
assigned_agent handling — one dedicated agent per node by its role, decided IDENTICALLY in solo and team (same model as create-workflow; mode never enters the decision):
- Existing nodes you keep (both paths): read the existing
assigned_agentverbatim fromaramb_mcp.workflows_getand carry it forward. Workflows can be multi-persona (developer,aramb-deployer, a bespoke agent name, …) even in a solo chat — do NOT blindly stamp"solo"across the graph. - Freshly authored nodes: exactly as create-workflow does. For each node, reuse a fitting existing agent (a persona already in the graph, a roster persona, or one you created in this update), otherwise provision a bespoke agent via
create-agentnamed for its role, to the template-grade bar. This is the same in solo and team. Bare"solo"only for a trivial glue node.
Same authoring rules as create-workflow:
- Concrete prompts with real business context baked in. No generic templates. No
{{env.…}}/{{input.…}}placeholders — per-run values arrive in<run_input>(step 1 only). - Each node
promptends with the closing-instruction template (below). If you carry an old node forward unchanged, verify it still has the template; if it pre-dates this rule, append it now. - The entry (first) node's prompt distills
<run_input>into itsoutputs.summary— if your delta changes which node runs first, make sure the new entry node funnels the input forward. - Each node carries
required_toolkits— never omit;[]for orchestration / file-only nodes. Ground slugs viaaramb_mcp.toolkits_list_toolkits. - Each node that uses toolkits carries a singular
toolkit— its primary slug, a member ofrequired_toolkits; omit (ornull) whenrequired_toolkitsis[]. - Each node carries
settings— usually{}. Carry forward existing per-node overrides fromaramb_mcp.workflows_get, plus or minus what the user is changing. Don't drop overrides the user didn't mention. - Carry forward
default_node_settingsfrom the existing workflow, edited only where the user asked. If the existing block is empty / missing (older definitions), seed the same sensible defaults create-workflow uses (model=claude-sonnet-4-6,effort=medium,thinking=adaptive,max_turns=35,admin=false,budget_usd=25.0,approval_mode=auto,instructions=""). - Sequential
unique_idintegers starting at 1 (numbering can differ from the existing version — uniqueness is what matters). - Dependencies via the top-level
edgesarray, never on nodes. - Do NOT declare
env_variables— omit the field; drop any the old definition carried.
Closing instruction per node — MANDATORY
Every node's prompt MUST end with this exact block, with <summary> and <files> substituted to match what the node will actually produce. Non-negotiable, baked into every prompt at authoring time.
When done — record your output for the next step:
npx mcporter call aramb_mcp.workflows_update_step \
project_id="<your Project ID from User Message>" \
step_id="<your Workflow Run Step ID from User Message>" \
status="done" \
outputs='{"summary":"<one-paragraph hand-off, under 500 chars>","files":["relative/path/to/output.json"]}'
If you can't complete the step:
npx mcporter call aramb_mcp.workflows_update_step \
project_id="<your Project ID from User Message>" \
step_id="<your Workflow Run Step ID from User Message>" \
status="failed" \
error="<concise reason + any partial progress>"
Why both summary and files:
summaryis a paragraph the next agent reads as preamble — the hand-off vocabulary that makes the chain coherent. Keep it under 500 chars; focus on what's useful downstream.filesis a list of paths (relative to the workspace working directory) the next agent reads to dig deeper. Empty array[]is correct when the node only sends a message / posts to an external service and produces no files.
Notes:
- The agent reads
project_idandstep_idfrom the User Message under "## Current Context" (Project ID:andWorkflow Run Step ID:lines). The platform rejects cross-step writes (context_drift), so the agent must copy these verbatim into the close call — never re-use a stale UUID. - Do NOT instruct the agent to call
aramb_mcp.tasks_updatefrom a workflow-step prompt — that targets the tasks domain (different DB rows) and the run will stall on the safety net. Onlyaramb_mcp.workflows_update_stepcloses a workflow run step. - When carrying over node prompts from the existing definition, re-verify the closing template is present and uses
update_stepwith explicit IDs. If the existing version pre-dates this rule (still referencesupdate_my_step), rewrite it now.
Step 4.5. Browser-login pre-check — scoped to changed/added nodes
Same hard gate as create-workflow, but only over the nodes this update adds or changes (an untouched node's login was already gated when it was created):
- For each added/changed node whose
required_toolkitsincludesaramb-browserAND whosepromptnames a known-login site (linkedin.com,github.com,twitter.com/x.com,gmail.com/mail.google.com,reddit.com,notion.so,slack.com,discord.com,instagram.com), infer the<site>-logincontext name and check it withnpx mcporter call aramb-browser.browser_context_list. - Slot present → proceed; mention "I'll use your existing
<site>login." - Slot missing → do NOT call
aramb_mcp.workflows_update. Surface the canonical aramb-browser login flow (browser_context_create→ log in →browser_save_context, context_name=<site>-login) and STOP until the slot exists. No bypass. - If the update removes the last browser-login node for a site, no check is needed — the dependency is gone.
Step 4.6. Trigger review when the entry toolkit changes
Unlike create, aramb_mcp.workflows_update does NOT take a trigger_choice — the
firing condition is managed separately (Step 3 routes explicit schedule/trigger
change requests to schedule-workflow / configure-trigger). But one delta
silently breaks an existing trigger: changing the entry node's toolkit (the
slug an event trigger binds against). If this update changes which toolkit the
entry node uses:
- Check whether a trigger exists (
aramb_mcp.workflows_getsurfaces the schedule; for event triggers, the workflow's trigger rows). If atoolkit_eventtrigger is bound to the old toolkit, it no longer matches the new entry toolkit. - Tell the user via
aramb_mcp.chat_ask_questionthat the trigger needs to change, and run the same picker shape create-workflow uses (list_triggers for the new toolkit → recommend → cron/manual options). On their answer, re-wire viaconfigure-trigger(event) orset_schedule(cron) after the update saves.
If the entry toolkit is unchanged, leave the trigger alone — don't reconfigure a working trigger the user didn't ask to touch.
Step 5. Call aramb_mcp.workflows_update
Update progress: "Saving updated workflow".
Pre-flight checklist — verify before calling aramb_mcp.workflows_update. For every node:
unique_id— sequential integer starting at 1name— short labelprompt— concrete instruction with business context baked in, no{{env.…}}/{{input.…}}placeholders, AND ending with the closing-instruction template. The entry node reads<run_input>and distills it into its summary.assigned_agent— kept nodes: carry the existing persona verbatim fromaramb_mcp.workflows_get(both paths). Freshly authored nodes: one dedicated agent per node by its role, decided identically in solo and team — reuse a fitting existing agent (roster persona / persona already in the graph), else provision a bespoke agent viacreate-agentnamed for its role. Bare"solo"only for a trivial glue node. Nevernullor empty.acceptance_criteria— how to know the step succeededrequired_toolkits— copied from the source task / existing node, grounded viaaramb_mcp.toolkits_list_toolkits;[]for orchestration / file-only nodes; never omit.toolkit— the primary slug; a member ofrequired_toolkits; omit (ornull) whenrequired_toolkitsis[].settings— JSONB; preserve existing per-node overrides fromaramb_mcp.workflows_get, edit only where the user asked;{}when the node has no overrides.
And on the call itself:
default_node_settings— carry the existing block forward (or seed sensible defaults if empty), then apply any workflow-wide setting changes the user requested.- No
env_variables— omit the field; drop any the old definition declared (the schema rejects a non-empty map).
Bugs that silently break downstream behaviour, as fatal as in create-workflow:
- Missing
required_toolkits— kills Evaluate's missing-connection warnings. toolkitnot inrequired_toolkits(or missing on a toolkit-using node) — the platform rejects the call.- A
{{env.KEY}}/{{input.KEY}}placeholder in any prompt — the platform rejects the call. - Missing closing instruction in
prompt— outputs stay NULL, downstream sees "(no summary)" preamble.
Each node's prompt should look like this (markdown, multi-line) before you JSON-encode it:
Concrete instruction with the real business context baked in.
When done — record your output for the next step:
npx mcporter call aramb_mcp.workflows_update_step \
project_id="<your Project ID from User Message>" \
step_id="<your Workflow Run Step ID from User Message>" \
status="done" \
outputs='{"summary":"<hand-off paragraph under 500 chars>","files":["<relative/path>"]}'
If you can't complete the step:
npx mcporter call aramb_mcp.workflows_update_step \
project_id="<your Project ID from User Message>" \
step_id="<your Workflow Run Step ID from User Message>" \
status="failed" \
error="<concise reason>"
aramb_mcp.workflows_update skeleton (kept nodes carry their existing persona verbatim; freshly authored nodes carry a bespoke agent, a roster persona, or "solo" per the work — otherwise identical across paths):
npx mcporter call aramb_mcp.workflows_update \
workflow_id="<workflow_id>" \
name="Updated Workflow Name" \
description="What this workflow does in 1-2 sentences" \
default_node_settings='{"model":"claude-opus-4-7","effort":"medium","thinking":"adaptive","max_turns":35,"admin":false,"budget_usd":50.0,"approval_mode":"auto","instructions":""}' \
nodes='[
{"unique_id": 1, "name": "First step", "prompt": "<reads <run_input> + closing template>", "assigned_agent": "agent-name", "acceptance_criteria": "...", "required_toolkits": ["GMAIL"], "toolkit": "GMAIL", "settings": {}},
{"unique_id": 2, "name": "Second step", "prompt": "<body + closing template>", "assigned_agent": "agent-name", "acceptance_criteria": "...", "required_toolkits": [], "settings": {"approval_mode":"manual"}}
]' \
edges='[
{"source": 1, "target": 2}
]'
The example shows a workflow whose user said "switch the model to Opus and raise the budget to $50, but make me approve step 2" — workflow-level changes land in default_node_settings, the per-step gating lands in node 2's settings.
name, description, default_node_settings are optional — omit them to keep existing values. Do NOT pass env_variables (omit it). nodes is required and must not be empty. edges may be [] for a single-node workflow.
required_toolkits per node — always include it. Copy the existing list from
the matching node in aramb_mcp.workflows_get (step 1), plus or minus what the user is
changing. If you omit it, the platform falls back to the prior node's toolkits matched by
name — brittle across renames. Emit the field explicitly. [] only when the node
genuinely needs no toolkits.
The response includes:
workflow_id,status,node_count,message(familiar from create)stateful_continuity:"preserved"or"reset"stateful_reset_reason(only when reset)schedule_paused+schedule_paused_reason(only when an enabled schedule was auto-paused due to env mismatch)
The response status is always "draft" after a successful update — an updated workflow returns to draft so the change ships deliberately. A workflow is part of its owning agent (whether it was created with agent_id or later attached via aramb_mcp.agents_attach_workflow — same end state) and has no publish step of its own: the draft goes live automatically when the agent is (re-)published (aramb_mcp.agents_publish) — but only if the workflow's required toolkits are connected. A workflow whose steps need third-party toolkits (Gmail, Slack…) is published with the agent ONLY once those toolkits are CONNECTED; otherwise it stays a draft and the publish response reports it as blocked, naming the missing toolkits. Test the draft via Preview (aramb_mcp.workflows_run works on the draft) in the meantime; never call a workflow-publish tool yourself.
Never retry aramb_mcp.workflows_update. If the first call succeeds you're done. If it errors (bad payload, cycle in edges), close the task as failed (Path A) or tell the user the concise reason and stop (Path C) — don't retry silently. The original definition is intact on failure (the swap is atomic; rejection happens before it). The platform emits workflow.update_failed so the UI shows "Update failed, original kept".
Step 6. Tell the user about side effects + setting changes
Describe setting changes in inheritance terms ("workflow default + per-node override"), so the user can predict behavior:
- workflow default change → "Set the workflow default model to Opus." (applies everywhere)
- per-node override → "Switched the synth step to Opus; other steps still use the workflow default of Sonnet."
- removing an override → "Cleared the node-level model override on the synth step so it inherits the workflow default."
- mixed → "Set the workflow default to Sonnet AND overrode the writer step to Opus."
If you only edited the graph (no settings touched), no settings line needed.
Status is now draft — goes live when the AGENT is published. Every successful
update returns the workflow to draft, regardless of where it was before. The new
definition is NOT live until the owning agent is (re-)published
(aramb_mcp.agents_publish) — there is no separate workflow-publish step, and you must
not call one. And if this workflow's steps require third-party toolkits, it goes
live at publish ONLY once those toolkits are CONNECTED — otherwise it stays a draft
and the publish response flags it as blocked with the missing toolkit names. So if the
workflow needs a toolkit the user hasn't connected, tell them plainly to connect it on
the Integrations page before publishing the agent (verify with
aramb_mcp.toolkits_check_connection). The builder can Preview / aramb_mcp.workflows_run the
draft to test it now. Cron schedules fire from the live (published) version, so a
scheduled workflow runs the previous published definition until the agent is
re-published. Always surface this.
If stateful_continuity is "reset": the workflow is stateful=true AND the new
entry node uses a different agent than before. The next stateful run starts a fresh
trunk. Mention it.
If schedule_paused is true: an enabled cron schedule was auto-paused because the
new env_variables no longer satisfy required keys. Tell the user the reason and that
they can resume once the env values are sorted out.
Step 7. Close out
Path A (task dispatch) — close the task. On success, use the workflow_id from the response:
npx mcporter call aramb_mcp.tasks_update \
task_id="<your task_id>" \
status="done" \
outputs='{"workflow_id":"<workflow_id>","node_count":<number>,"summary":"Updated workflow: <one-line summary, in inheritance terms when settings were touched>. Status: draft (publish the agent to put it live). Stateful chain: preserved | reset. Schedule: unchanged | paused."}'
If the user's request also contained a schedule-shaped phrase you didn't handle
(mixed intent), include "schedule_hint":"User also asked to change the schedule: \"<verbatim phrase>\". Dispatch schedule-workflow with workflow_id=<id>." so master
dispatches schedule-workflow next.
On failure (aramb_mcp.tasks_list / aramb_mcp.workflows_get / aramb_mcp.workflows_update error, cycle, invalid status):
npx mcporter call aramb_mcp.tasks_update \
task_id="<your task_id>" \
status="failed" \
rejection_reason="<concise one-line reason>"
CRITICAL: After calling aramb_mcp.tasks_update, STOP. Do not send any follow-up messages.
Path C (chat dispatch, solo) — confirm in chat. Write a one-line confirmation in your reply text (the platform saves it as the chat row):
Updated workflow "<name>" — <one-line summary of what changed>. Status: draft (goes live when you publish the agent).
Include any side effects (stateful chain reset, schedule auto-paused) in the same
line. If the user's message was mixed (definition + schedule), call
aramb_mcp.workflows_set_schedule yourself right after aramb_mcp.workflows_update succeeds
and bundle the schedule into the same confirmation. Don't punt the schedule back to
the user. On error, tell the user the concise reason and stop — the original
definition is intact.
Rules
- One shot: never call
aramb_mcp.workflows_updatetwice. If the first call succeeded, you're done. If it errored, close as failed (Path A) or tell the user and stop (Path C). - Each node's
promptcarries real business context baked in. - Each node's
promptMUST end with the closing-instruction template so the executing agent callsaramb_mcp.workflows_update_step(with the explicitstep_idrendered into its dispatch User Message) at the end of its run. Without it,outputsstays NULL and the upstream-context hand-off chain shows "(no summary)". - Each node carries
required_toolkits—[]when the node touches no third-party service; never omit. Ground slugs viaaramb_mcp.toolkits_list_toolkits. - Each toolkit-using node carries a singular
toolkit— its primary slug, a member ofrequired_toolkits; omit (ornull) whenrequired_toolkitsis[]. - No placeholder syntax in prompts — no
{{env.KEY}}, no{{input.KEY}}; the platform rejects prompts containing{{ env.… }}. Per-run values arrive in<run_input>(step 1 only); rewrite any legacy placeholders carried over from the old definition. - Do NOT declare
env_variables— omit the field; drop any the old definition carried. The schema rejects a non-empty map; the column has no runtime path in v2. - The entry node's prompt distills
<run_input>into itsoutputs.summary— downstream steps never see<run_input>. - Each node carries
settings— preserve existing per-node overrides fromaramb_mcp.workflows_get;{}when none. - Carry
default_node_settingsforward unchanged fromaramb_mcp.workflows_get, edited only where the user asked. Never silently drop the workflow defaults block. - Reject pure firing-condition change requests — cron → route to
schedule-workflow; event trigger → route toconfigure-trigger. Path A: close failed with arejection_reasonnaming the skill. Path C: use that skill directly. Only callaramb_mcp.workflows_updatefor definition changes. - Apply setting changes at the right level: workflow-wide phrases ("all steps" / "the workflow" / "everywhere") →
default_node_settings. Single-step phrases ("the synth step" / "this step") → that one node'ssettingsoverride. - Preserve per-node
assigned_agentverbatim fromaramb_mcp.workflows_get— multi-persona workflows keep their personas through updates. For freshly authored nodes, give each its own dedicated agent by role (identically in solo and team): reuse a fitting existing agent, else provision a bespoke one viacreate-agent. Bare"solo"only for a trivial glue node. - For history-derived chat deltas, generalize the new work — strip one-off dates / values from any new node prompts before adding them.
unique_idvalues are sequential integers starting at 1.- Dependencies live ONLY in the top-level
edgesarray. Never on nodes. edgesmust be a DAG — no cycles.assigned_agentshould match existing agent names.- Close out: Path A — always
aramb_mcp.tasks_update(doneorfailed), then STOP; never leavein_progress. Path C — confirm inline in your reply text (success or failure), always mention on success that the update is adraftthat goes live when the agent is published (once its required toolkits are connected; no separate workflow-publish step).