update_workflow
Make a partial update to a workflow template; only the fields you send change. Use it to set a workflow Active or Inactive, rename, archive, or edit its steps — call get_workflow first. It cannot edit a schedule or turn one on.
Parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
workflow_id | string | Yes | — | UUID of the workflow to update, as returned by `list_workflows`, `create_workflow` or `get_workflow`. Required, and the workflow must belong to the user's current team. Call `get_workflow` first so you can send a minimal change set and know what the current values are. |
name | string | No | — | New display name for the workflow. Omit it to leave the name as it is — only the keys you send are written. |
description | string | No | — | Replacement description. It is inserted into the prompt given to the agent that runs the workflow, so refresh it whenever the steps change meaningfully. Omit to leave it unchanged. |
status | string | No | — | Lifecycle state of the workflow: "active" (allowed to run — required before `run_workflow` will start it or its schedule will fire), "inactive" (nothing runs, by any route; its schedule, if any, is kept exactly as it is) or "archived" (the soft-delete convention; the record is kept but taken out of normal use). Set "active" only once the user has confirmed the steps. Any other value is rejected and nothing is saved — there is no "paused" status: pausing is something a schedule does, and the user does it in the app. |
steps | array | No | — | Replacement ordered list of actions. It overwrites the existing steps outright rather than merging, so start from the list `get_workflow` returned and send the whole intended sequence. Omit it — or send an empty object, which counts as "not provided" — to leave the steps unchanged. |
inputs | object | No | — | Replacement declaration of the values the workflow expects at run time. It overwrites the previous declaration outright. Omit it to leave it unchanged; note an empty object `{}` is also treated as "not provided" and changes nothing. |
allowed_tools | array of string | No | — | Replacement list of the tools the workflow's agent is permitted to call. It overwrites the existing allowlist, so send the full intended set rather than just additions, and keep it tight for scheduled workflows. Omit it (or send an empty object) to leave the allowlist unchanged. |
tags | array of string | No | — | Replacement array of label strings; it overwrites the existing tags. Must be an array — any other value leaves the tags untouched. |
Input Schema
{
"type": "object",
"required": [
"workflow_id"
],
"properties": {
"name": {
"type": "string",
"description": "New display name for the workflow. Omit it to leave the name as it is — only the keys you send are written."
},
"tags": {
"description": "Replacement array of label strings; it overwrites the existing tags. Must be an array — any other value leaves the tags untouched."
},
"steps": {
"description": "Replacement ordered list of actions. It overwrites the existing steps outright rather than merging, so start from the list `get_workflow` returned and send the whole intended sequence. Omit it — or send an empty object, which counts as \"not provided\" — to leave the steps unchanged."
},
"inputs": {
"description": "Replacement declaration of the values the workflow expects at run time. It overwrites the previous declaration outright. Omit it to leave it unchanged; note an empty object `{}` is also treated as \"not provided\" and changes nothing."
},
"status": {
"type": "string",
"description": "Lifecycle state of the workflow: \"active\" (allowed to run — required before `run_workflow` will start it or its schedule will fire), \"inactive\" (nothing runs, by any route; its schedule, if any, is kept exactly as it is) or \"archived\" (the soft-delete convention; the record is kept but taken out of normal use). Set \"active\" only once the user has confirmed the steps. Any other value is rejected and nothing is saved — there is no \"paused\" status: pausing is something a schedule does, and the user does it in the app."
},
"description": {
"type": "string",
"description": "Replacement description. It is inserted into the prompt given to the agent that runs the workflow, so refresh it whenever the steps change meaningfully. Omit to leave it unchanged."
},
"workflow_id": {
"type": "string",
"description": "UUID of the workflow to update, as returned by `list_workflows`, `create_workflow` or `get_workflow`. Required, and the workflow must belong to the user's current team. Call `get_workflow` first so you can send a minimal change set and know what the current values are."
},
"allowed_tools": {
"description": "Replacement list of the tools the workflow's agent is permitted to call. It overwrites the existing allowlist, so send the full intended set rather than just additions, and keep it tight for scheduled workflows. Omit it (or send an empty object) to leave the allowlist unchanged."
}
}
}Output Schema
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"id": {
"type": "string",
"format": "uuid"
},
"name": {
"type": "string"
},
"tags": {
"type": "array"
},
"steps": {
"type": "array"
},
"inputs": {
"type": "object"
},
"status": {
"type": "string"
},
"link_url": {
"type": "string",
"format": "uri",
"description": "Direct URL to view this workflow in Marcora."
},
"schedule": {
"type": "object",
"properties": {
"summary": {
"type": "string",
"description": "Plain-language description of what is saved (times in UTC)."
},
"is_enabled": {
"type": "boolean",
"description": "false = the schedule is Paused: it does not fire until the user clicks \"Resume schedule\" in the app. true = On, which fires only while the workflow is Active."
},
"trigger_id": {
"type": "string",
"format": "uuid"
},
"schedule_config": {
"type": "object"
}
},
"description": "Present whenever the workflow has a schedule, on every update. Inert context, read back from the saved trigger."
},
"next_step": {
"type": "string",
"description": "Present ONLY when this call set status to \"active\" or \"inactive\". What will and won't run afterwards, across both switches — the workflow's status and its schedule — with the words to use. Follow it in substance. A call that changes anything else (a rename, say) returns no next_step, so nothing asserts a change that did not happen or pushes the user toward a schedule they did not ask about."
},
"updated_at": {
"type": "integer"
},
"allowed_tools": {
"type": "array"
}
}
}Instructions
Partial update of a workflow template. Only keys you send mutate — unspecified keys are preserved. Call get_workflow first to see the current state; then construct the minimal diff.
Input roles:
- workflow_id: UUID string of the workflow to update.
- name / description / steps / inputs / allowed_tools / tags: partial overrides.
- status: "active" | "inactive" | "archived". Use "archived" as soft-delete.
Usage patterns:
- To set Active: {workflow_id: "
", status: "active"}. - To set Inactive: {workflow_id: "
", status: "inactive"}. Nothing runs while it is Inactive, and its schedule is kept exactly as it was — a schedule that was On is still On, and fires again once the workflow is Active. - To soft-delete: {workflow_id: "
", status: "archived"}. - To rename: call get_workflow first, then send just {workflow_id, name}.
Do NOT send:
- schedule / schedule_config — this tool CANNOT edit a schedule, and it fails silently rather than loudly: the field is ignored, no error is raised, and you get a normal success response, so sending it looks like it worked when nothing changed. Editing a schedule and turning it On or Paused are app-only; direct the user to the UI.
Links: present link_url to the user exactly as returned — copy it character for character. Never retype, shorten, or rebuild a link or the IDs inside it.
Only set status: "active" when the user has actually asked for it — a workflow the user has not approved stays Inactive.
Two switches, two vocabularies — never mix them. The workflow's status is Active or Inactive. Its schedule, if it has one, is On or Paused. Never call a schedule "active" or "inactive", never call a workflow "paused" or "on" — in any language. "Active" does not mean running; it only means the workflow is allowed to run.
What actually runs needs BOTH switches — describe the pair that exists when you finish:
- Inactive → nothing runs, by any route (manual runs are refused too).
- Active, no schedule → runs only when started manually; never starts by itself.
- Active, schedule Paused → manual runs work; it won't run on its schedule until the user turns the schedule on with Resume schedule in the app.
- Active, schedule On → runs on its schedule.
- Inactive, schedule On → nothing runs until the workflow is set Active.
When this call changes the status (to Active or Inactive), the response carries a next_step stating what will and won't run afterwards, across both switches, computed from the saved schedule. Follow it: describe the state that exists after this call. status: "active" does not turn a schedule On — a Paused schedule stays Paused until the user clicks "Resume schedule" — so never tell the user the workflow will run on its own unless its schedule is On too. Equally, after you set it Active, never tell the user it is Inactive or that they still need to activate it.