Update a single step in a workflow by step ID. Preferred path for any single-step edit on an existing workflow — only the fields in updates / replace / unset are touched, every other step and field is left as-is. Use this instead of update_workflow for any one-step change (prompt, inputs, entry c...
Risk signalsAdmin/system-level operation
Part of the Agentled server.
Free to start. No card required.
AI agents use update_step to create or modify resources in Agentled. Write operations carry medium risk because an autonomous agent could trigger bulk unintended modifications. Rate limits prevent a single agent session from making hundreds of changes in rapid succession. Argument validation ensures the agent passes expected values.
Without a policy, an AI agent could call update_step repeatedly, creating or modifying resources faster than any human could review. PolicyLayer's rate limiting ensures write operations happen at a controlled pace, and argument validation catches malformed or unexpected inputs before they reach Agentled.
Write tools can modify data. A rate limit prevents runaway bulk operations from AI agents.
{
"version": "1",
"default": "deny",
"tools": {
"update_step": {
"limits": [
{
"counter": "update_step_rate",
"window": "minute",
"max": 30,
"scope": "grant"
}
]
}
}
} See the full Agentled policy for all 119 tools.
These attack patterns abuse exactly the kind of access update_step gives an agent. Each links to the full case and the policy that stops it:
Other write tools across the catalogue. The same approach applies to each: rate-limit and validate the arguments.
Update a single step in a workflow by step ID. Preferred path for any single-step edit on an existing workflow — only the fields in updates / replace / unset are touched, every other step and field is left as-is. Use this instead of update_workflow for any one-step change (prompt, inputs, entry conditions, switching shape, swapping tools). update_workflow with a full steps array is for imports/round-trips only. KG-First — when editing a prompt template If this edit introduces or changes workspace-specific content in a prompt template (thesis, ICP, rubric, sector list, geo focus, brand voice), check the KG first: call list_memories / list_knowledge_lists / get_knowledge_text. Seed the content there if it isn't already present, then reference it at runtime ({{steps.read-kg.content}}) instead of pasting text inline. Boundary: strategy → KG; execution wiring → workflow context; workflow structure → workflow. Merge semantics update_step accepts three independent operations on the same call. At least one must be non-empty. - updates — partial step patch. Top-level fields are replaced; nested objects (pipelineStepPrompt, stepInputData, entryConditions, renderer, etc.) are deep-merged ONE LEVEL deep — keys nested two levels deep are overwritten as a unit, not merged. Arrays are replaced wholesale. - replace: string[] — dot-paths (e.g. "stepInputData.fieldUpdates") whose values from updates are assigned WHOLESALE onto the step, skipping the deep-merge. Use for dictionary-shaped fields where keys are user data. - unset: string[] — dot-paths to DELETE. Each must exist on the original step. When to use which | Situation | Verb | Example | |---|---|---| | Change one config key, keep siblings | updates | updates: { pipelineStepPrompt: { template: "new..." } } keeps responseStructure | | Add a stepInputData entry | updates | updates: { stepInputData: { profileUrls: "{{input.url}}" } } | | Replace a dictionary wholesale (keys = user data) | replace | updates: { stepInputData: { fieldUpdates: {...} } }, replace: ["stepInputData.fieldUpdates"] | | Replace responseStructure / knowledgeSync.fieldMapping | replace | replace: ["pipelineStepPrompt.responseStructure"] | | Remove a step input | unset | unset: ["stepInputData.oldKey"] | | Swap full arrays (tools, integrations) | updates | updates: { tools: [...] } (arrays already replaced wholesale) | The trap. Default deep-merge is one level deep — patching stepInputData.fieldUpdates with a partial dict silently wipes the others. Either send the FULL dict + replace: ["stepInputData.fieldUpdates"], or call get_step first, edit locally, send back via replace. Read-before-write for dictionary fields For dictionary fields where keys are user data (stepInputData.fieldUpdates, responseStructure, fieldMapping): get_step (~1KB), modify locally, send full object back under replace[]. Diff + warnings Response includes diff: { addedPaths, changedPaths, removedPaths } and warnings[]. ≥6 fields removed without explicit unset triggers a warning — usually a "you wiped a dictionary" signal. Shape conversions Fetch the canonical example before changing shape: - email: get_step_schema({ stepType: "aiAction", shape: "email" }) - report: get_step_schema({ stepType: "aiAction", shape: "report" }) Send under updates, replace[] for dictionary children, unset[] for stale type-specific fields. Won't do - Cannot change step.id — root id is immutable; API returns 400. Nested *.id is fine. - Does not enforce step.type immutability. Stale type-specific fields (pipelineStepPrompt, app, tools) persist unless unset. For clean conversions, prefer remove_step + add_step. - Does not validate the merged result against shape rules — call validate_workflow after edits. Draft routing (live workflows) Edits are routed to a draft snapshot (editingDraft: true in response). Inspect via get_draft, ship via promote_draft, discard via discard_draft. When a draft exists, the response carries a draft summary: { exists, draftCreatedAt, liveUpdatedAt, stale, modifiedStepIds, modifiedFields }. If draft.stale === true, the live workflow advanced past the draft — promoting will land older values for fields you didn't touch. A staleness warning is pushed into warnings[]. Recovery: discard_draft + retry, or inspect via get_draft first.. It is categorised as a Write tool in the Agentled MCP Server, which means it can create or modify data. Consider rate limits to prevent runaway writes.
Register the Agentled MCP server in PolicyLayer and add a rule for update_step: allow, deny, rate-limit, or require approval. Point your MCP client at the PolicyLayer proxy URL and the rule is enforced on every call, before it reaches Agentled. Nothing to install.
update_step is a Write tool with medium risk. Write tools should be rate-limited to prevent accidental bulk modifications.
Yes. Add a rate_limit block to the update_step rule in your PolicyLayer policy. For example, setting max: 10 and window: 60 limits the tool to 10 calls per minute. Rate limits are tracked per agent session and reset automatically.
Set action: deny in the PolicyLayer policy for update_step. The AI agent will receive a policy violation error and cannot call the tool. You can also include a reason field to explain why the tool is blocked.
update_step is provided by the Agentled MCP server (@agentled/mcp-server). PolicyLayer sits as a proxy in front of this server to enforce policies before tool calls reach the server.
Deterministic rules across all 119 Agentled tools. Per-identity grants. Full audit log. Live in minutes. Nothing to install.
Free to start. No card required.
4,600+ MCP servers and 31,000+ tools scanned and risk-classified.