> ## Documentation Index
> Fetch the complete documentation index at: https://docs.armature.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# Repair workflow tools: propose and apply changes

> Stage workflow patches, draft regression workflows from failed runs, and apply approved changes — the full agent-driven repair loop.

The repair tools give you and your agents a structured, auditable path from a failing run to an updated workflow. Instead of editing workflows directly, you stage a proposal, review the field-level diff, and apply only after approval. This loop keeps a full record of what changed, why, and what evidence supported the change — without Armature making any hidden LLM decisions on your behalf. You supply the rationale; Armature validates, diffs, and persists it.

<Note>
  `propose_workflow_patch` and `draft_regression_workflow_from_run` are available to all roles (viewer and above). `apply_workflow_change` requires **editor or higher**. See [Roles](/mcp-api/roles) for the full permissions matrix.
</Note>

## The repair loop

The recommended repair loop connects triage tools directly to proposal and apply tools. Follow these steps when an agent detects a failing run:

<Steps>
  <Step title="Diagnose the failing run">
    Call `diagnose_run` with the run ID to get a structured breakdown of which criteria failed, which tool calls contributed, and what remediation Armature suggests. This output becomes the basis for your patch.

    ```json theme={null}
    {
      "name": "diagnose_run",
      "arguments": {
        "runId": "run_xyz789"
      }
    }
    ```

    See [Triage tools](/mcp-api/tools/triage) for the full `diagnose_run` reference.
  </Step>

  <Step title="Stage a patch proposal">
    Call `propose_workflow_patch` with your intended changes and a rationale you have authored based on the diagnosis. Armature validates the proposal, computes a field-level diff, and persists the proposal record. The response includes the diff and any validation warnings.

    ```json theme={null}
    {
      "name": "propose_workflow_patch",
      "arguments": {
        "workflowId": "wf_abc123",
        "baseVersionId": "ver_001",
        "rationale": "Criterion 2 was failing because the order ID field name changed in the API response. Updating the criterion to reference `orderId` instead of `order_id`.",
        "changes": {
          "criteria": [
            {
              "op": "update",
              "id": "crit_002",
              "text": "The tester creates one run-scoped order and the response contains an `orderId` field."
            }
          ]
        },
        "evidence": {
          "runIds": ["run_xyz789"],
          "criterionIds": ["crit_002"]
        }
      }
    }
    ```
  </Step>

  <Step title="Review the diff">
    Inspect the proposal resource at `armature://workflow-change-proposals/{id}` to review the exact field-level diff before proceeding. Present this diff to a human approver if your deployment requires human-in-the-loop sign-off. See [Resources](/mcp-api/resources).
  </Step>

  <Step title="Apply the approved proposal">
    Call `apply_workflow_change` with the proposal ID. This creates a new immutable workflow version. If the workflow was updated between staging and apply, Armature returns `base_version_stale` with the current version ID so you can re-propose against the correct base.

    ```json theme={null}
    {
      "name": "apply_workflow_change",
      "arguments": {
        "proposalId": "prop_def456"
      }
    }
    ```
  </Step>

  <Step title="Run and verify">
    After applying, dispatch a manual run with `run_workflow_now` and compare it against the failing baseline using `compare_runs`. See [Run and sync tools](/mcp-api/tools/runs).
  </Step>
</Steps>

## Tools

<AccordionGroup>
  <Accordion title="propose_workflow_patch" icon="file-pen">
    `propose_workflow_patch` stages a patch against a specific workflow version and returns a field-level diff. Armature validates the proposal before persisting it — it does not apply any changes to the live workflow.

    **What Armature validates**

    * Workflow ownership: the workflow must belong to your organization.
    * Source and evidence ownership: all cited `runIds`, `criterionIds`, `toolCallIds`, and `traceEventIds` must belong to your organization. Criterion IDs must belong to any version of the target workflow; tool-call and trace-event IDs must belong to a cited run or the proposal source run.
    * Criteria operations: each operation must be `add`, `update`, or `remove`, and must reference a valid position or criterion ID.
    * Tool policy entries: tools referenced in `toolPolicy.allowed_tools` or `toolPolicy.blocked_tools` are validated against the active tool catalog. If a tool is missing, Armature may attempt a `tools/list` sync and return either `unknown_tool_policy_entry` or a warning if `allowUndiscoveredTools` is set.

    **What Armature persists**

    The proposal record in `workflow_change_proposals` contains: the proposed spec, your supplied rationale, evidence references, validation warnings, and the exact field-level diff.

    **Arguments**

    | Argument                 | Type    | Required | Description                                                                  |
    | ------------------------ | ------- | -------- | ---------------------------------------------------------------------------- |
    | `workflowId`             | string  | Yes      | The workflow to patch.                                                       |
    | `baseVersionId`          | string  | Yes      | The version ID you are patching against.                                     |
    | `rationale`              | string  | Yes      | Your explanation of why this change is warranted.                            |
    | `changes`                | object  | Yes      | Criteria and/or tool policy changes to stage.                                |
    | `evidence`               | object  | No       | Run, criterion, tool-call, and trace-event IDs supporting the change.        |
    | `allowUndiscoveredTools` | boolean | No       | If true, unknown tool names produce a warning instead of a validation error. |

    **Returns**

    A proposal object with: proposal ID, field-level diff, validation warnings, and expiry timestamp (24 hours from creation).

    **Example invocation**

    ```json theme={null}
    {
      "name": "propose_workflow_patch",
      "arguments": {
        "workflowId": "wf_abc123",
        "baseVersionId": "ver_001",
        "rationale": "The target API renamed the order identifier field. Updating criterion text to match the current response shape.",
        "changes": {
          "criteria": [
            {
              "op": "update",
              "id": "crit_002",
              "text": "The tester creates one run-scoped order and the response contains an `orderId` field."
            }
          ]
        },
        "evidence": {
          "runIds": ["run_xyz789"],
          "criterionIds": ["crit_002"],
          "toolCallIds": ["tc_001"]
        }
      }
    }
    ```

    <Warning>
      Agents must supply their own rationale. Armature does not make hidden LLM calls to generate or infer rationale on your behalf. An empty or generic rationale will be accepted but reduces the auditability of the proposal record.
    </Warning>

    <Note>
      Proposal records expire after 24 hours. If a proposal expires before you apply it, you must stage a new one.
    </Note>
  </Accordion>

  <Accordion title="draft_regression_workflow_from_run" icon="code-branch">
    `draft_regression_workflow_from_run` stages a deterministic, manual-only regression workflow derived from a failed run. Use it when the original workflow is too broad to isolate a specific failure, or when you want to lock in a focused guardrail that will catch regressions of a known issue.

    **What the draft contains**

    Armature builds the regression workflow deterministically — no LLM inference is involved:

    * The tester prompt is copied verbatim from the source run.
    * Only failed or partial required criteria are selected (based on evaluation rows).
    * `toolPolicy.allowed_tools` is narrowed to the tools actually called in the failed run.
    * The schedule is set to manual-only.

    **Arguments**

    | Argument    | Type   | Required | Description                                                 |
    | ----------- | ------ | -------- | ----------------------------------------------------------- |
    | `runId`     | string | Yes      | The failed run to derive the regression workflow from.      |
    | `rationale` | string | Yes      | Your explanation of why this regression workflow is needed. |

    **Returns**

    A proposal object (same shape as `propose_workflow_patch`) representing the staged regression workflow draft, including a field-level diff against an empty baseline and any validation warnings.

    **Example invocation**

    ```json theme={null}
    {
      "name": "draft_regression_workflow_from_run",
      "arguments": {
        "runId": "run_xyz789",
        "rationale": "Locking in a focused regression test for the order creation failure to prevent recurrence."
      }
    }
    ```

    <Tip>
      After staging the draft, review it via `armature://workflow-change-proposals/{id}` before applying. You can modify the draft further by calling `propose_workflow_patch` against the staged proposal version if needed.
    </Tip>
  </Accordion>

  <Accordion title="apply_workflow_change" icon="check-circle">
    `apply_workflow_change` applies a staged proposal and creates a new immutable workflow version. The workflow's active version is updated atomically. Applied proposals are retained indefinitely for auditability; only unapplied expired proposals are cleaned up.

    **Concurrency and idempotency**

    Apply uses optimistic concurrency against the `baseVersionId` captured when the proposal was staged. If another change was applied to the workflow after your proposal was created, Armature returns `base_version_stale` with the current version ID. In that case, re-examine the new version and stage a fresh proposal if your change is still needed.

    Calling `apply_workflow_change` on an already-applied proposal is safe and returns `alreadyApplied: true` rather than an error.

    **Arguments**

    | Argument     | Type   | Required | Description                             |
    | ------------ | ------ | -------- | --------------------------------------- |
    | `proposalId` | string | Yes      | The ID of the staged proposal to apply. |

    **Returns**

    An apply result containing: the new workflow version ID, a confirmation that the change was applied, or `alreadyApplied: true` if the proposal was already applied.

    **Example invocation**

    ```json theme={null}
    {
      "name": "apply_workflow_change",
      "arguments": {
        "proposalId": "prop_def456"
      }
    }
    ```

    <Warning>
      `apply_workflow_change` requires **editor, admin, or owner** role. Agents authenticated with a viewer-role API key will receive a `forbidden_role` error. See [Roles](/mcp-api/roles).
    </Warning>
  </Accordion>
</AccordionGroup>

## Error codes

| Code                        | Meaning                                                                                           |
| --------------------------- | ------------------------------------------------------------------------------------------------- |
| `proposal_not_found`        | The proposal ID does not exist or has already been cleaned up.                                    |
| `proposal_expired`          | The proposal was not applied within 24 hours. Stage a new proposal.                               |
| `base_version_stale`        | The workflow was updated after the proposal was staged. Re-propose against the current version.   |
| `validation_failed`         | One or more field-level validation errors. The `details.fieldErrors` array identifies each issue. |
| `unknown_tool_policy_entry` | A tool referenced in the patch is not in the active catalog.                                      |
| `forbidden_role`            | Your API key does not have the role required by this tool.                                        |
| `workflow_inactive`         | The target workflow is inactive and cannot be patched.                                            |

See [Errors](/mcp-api/errors) for the full list and JSON-RPC error shapes.

## Next steps

<CardGroup cols={2}>
  <Card title="Triage tools" icon="magnifying-glass" href="/mcp-api/tools/triage">
    Search runs, inspect traces, and diagnose failures before entering the repair loop.
  </Card>

  <Card title="Run and sync tools" icon="play" href="/mcp-api/tools/runs">
    Dispatch manual runs and compare results after applying a patch.
  </Card>
</CardGroup>
