---
title: "Diff two workflow revisions"
method: GET
path: "/v1/workflows/{workflow_id}/revisions/diff"
tags: ["workflows"]
---

# Diff two workflow revisions

`GET /v1/workflows/{workflow_id}/revisions/diff`

Compute a two-layer diff between two revisions of the same workflow.

Returns:
  - ``source_diff``: deterministic diff of the authored config columns
    (always present, always exact).
  - ``graph_diff``: projected behavior diff over the compiled graphs
    (null when either side is uncompiled or the stored graph is unparseable).
  - ``fidelity``: ``"exact"`` | ``"approximate"`` | ``"source_only"``.

## Path parameters

- `workflow_id` string, uuid, required

## Query parameters

- `base` string, uuid, required
- `target` string, uuid, required

## Response `200`

Successful Response

- WorkflowRevisionDiffResponse — Top-level response returned by GET /workflows/{id}/revisions/diff.
  - `workflow_id` string, uuid, required
  - `base` RevisionDiffSide, required — Metadata about one side of the diff (base or target).
    - `revision_id` string, uuid, required
    - `name` string, required
    - `provenance` 'compiled' | 'hand_edited' | 'uncompiled', required
  - `target` RevisionDiffSide, required — Metadata about one side of the diff (base or target).
    - `revision_id` string, uuid, required
    - `name` string, required
    - `provenance` 'compiled' | 'hand_edited' | 'uncompiled', required
  - `fidelity` 'exact' | 'approximate' | 'source_only', required
  - `source_diff` SourceDiff, required — Source-layer diff — exactly what the author edited (authored config columns). Always present and always deterministic regardless of graph provenance.
    - `instructions` TextDiff, required — Line-level prose diff built from difflib.SequenceMatcher opcodes.
      - `segments` TextDiffSegment[], required
        - `op` 'equal' | 'insert' | 'delete', required
        - `text` string, required
    - `system_prompt` TextDiff, required — Line-level prose diff built from difflib.SequenceMatcher opcodes.
      - `segments` TextDiffSegment[], required
        - `op` 'equal' | 'insert' | 'delete', required
        - `text` string, required
    - `config` FieldChangeCollection — Generic collection diff for scalar config fields.
      - `added` FieldChange[]
        - `field` string, required
        - `op` 'added' | 'removed' | 'modified', required
        - `text_diff` TextDiff — Line-level prose diff built from difflib.SequenceMatcher opcodes.
          - `segments` TextDiffSegment[], required
            - `op` 'equal' | 'insert' | 'delete', required
            - `text` string, required
        - `before` unknown
        - `after` unknown
      - `removed` FieldChange[]
        - `field` string, required
        - `op` 'added' | 'removed' | 'modified', required
        - `text_diff` TextDiff — Line-level prose diff built from difflib.SequenceMatcher opcodes.
          - `segments` TextDiffSegment[], required
            - `op` 'equal' | 'insert' | 'delete', required
            - `text` string, required
        - `before` unknown
        - `after` unknown
      - `changed` FieldChange[]
        - `field` string, required
        - `op` 'added' | 'removed' | 'modified', required
        - `text_diff` TextDiff — Line-level prose diff built from difflib.SequenceMatcher opcodes.
          - `segments` TextDiffSegment[], required
            - `op` 'equal' | 'insert' | 'delete', required
            - `text` string, required
        - `before` unknown
        - `after` unknown
    - `policies` PolicyNamesDiff — Added/removed policy names (name-resolved).
      - `added` string[]
      - `removed` string[]
    - `tool_input_defaults` FieldChangeCollection — Generic collection diff for scalar config fields.
      - `added` FieldChange[]
        - `field` string, required
        - `op` 'added' | 'removed' | 'modified', required
        - `text_diff` TextDiff — Line-level prose diff built from difflib.SequenceMatcher opcodes.
          - `segments` TextDiffSegment[], required
            - `op` 'equal' | 'insert' | 'delete', required
            - `text` string, required
        - `before` unknown
        - `after` unknown
      - `removed` FieldChange[]
        - `field` string, required
        - `op` 'added' | 'removed' | 'modified', required
        - `text_diff` TextDiff — Line-level prose diff built from difflib.SequenceMatcher opcodes.
          - `segments` TextDiffSegment[], required
            - `op` 'equal' | 'insert' | 'delete', required
            - `text` string, required
        - `before` unknown
        - `after` unknown
      - `changed` FieldChange[]
        - `field` string, required
        - `op` 'added' | 'removed' | 'modified', required
        - `text_diff` TextDiff — Line-level prose diff built from difflib.SequenceMatcher opcodes.
          - `segments` TextDiffSegment[], required
            - `op` 'equal' | 'insert' | 'delete', required
            - `text` string, required
        - `before` unknown
        - `after` unknown
    - `model_settings` ModelSettingsDiff — Diff over analyzer and router model settings dicts.
      - `analyzer` FieldChange[]
        - `field` string, required
        - `op` 'added' | 'removed' | 'modified', required
        - `text_diff` TextDiff — Line-level prose diff built from difflib.SequenceMatcher opcodes.
          - `segments` TextDiffSegment[], required
            - `op` 'equal' | 'insert' | 'delete', required
            - `text` string, required
        - `before` unknown
        - `after` unknown
      - `router` FieldChange[]
        - `field` string, required
        - `op` 'added' | 'removed' | 'modified', required
        - `text_diff` TextDiff — Line-level prose diff built from difflib.SequenceMatcher opcodes.
          - `segments` TextDiffSegment[], required
            - `op` 'equal' | 'insert' | 'delete', required
            - `text` string, required
        - `before` unknown
        - `after` unknown
  - `graph_diff` GraphDiff — Full behavior diff — projected graph comparison.
    - `summary` GraphSummary, required — Counts of changes across the graph diff (for the summary header).
      - `nodes_added` integer
      - `nodes_removed` integer
      - `nodes_changed` integer
      - `edges_added` integer
      - `edges_removed` integer
      - `edges_changed` integer
      - `context_vars_added` integer
      - `context_vars_removed` integer
      - `context_vars_changed` integer
      - `escape_hatches_added` integer
      - `escape_hatches_removed` integer
      - `escape_hatches_changed` integer
    - `graph_meta` SrcWorkflowDiffModelsGraphMeta, required — Workflow-scope graph metadata diff (persona + system_prompt prose fields).
      - `persona` TextDiff, required — Line-level prose diff built from difflib.SequenceMatcher opcodes.
        - `segments` TextDiffSegment[], required
          - `op` 'equal' | 'insert' | 'delete', required
          - `text` string, required
      - `system_prompt` TextDiff, required — Line-level prose diff built from difflib.SequenceMatcher opcodes.
        - `segments` TextDiffSegment[], required
          - `op` 'equal' | 'insert' | 'delete', required
          - `text` string, required
    - `nodes` NodeCollectionDiff — Diff over the node collection.
      - `added` ProjectedNode[]
        - `id` string, required
        - `kind` 'agent' | 'action' | 'handoff' | 'approval', required
        - `is_entry` boolean
        - `instructions` string, nullable
        - `required_writes` string[]
        - `writes` string[]
        - `done_when_readable` string, nullable
        - `tools` ProjectedTool[]
          - `canonical_key` string, required
          - `display_name` string, required
          - `produces_variables` string[]
        - `knowledge_bases` ProjectedKnowledgeBase[]
          - `kb_id` string, required
          - `display_name` string, required
          - `clearance_level` integer, nullable
        - `description` string, nullable
        - `failure_message` string, nullable
        - `steps` ProjectedActionStep[]
          - `id` string, required
          - `kind` 'speak' | 'tool_call' | 'knowledge_retrieval', required
          - `text` string, nullable
          - `tool_display_name` string, nullable
          - `knowledge_base_names` string[]
        - `result_write_names` string[]
        - `static_text` string, nullable
        - `voice_config` ProjectedVoiceHandoff — Voice channel config — targets + text, no internal destination fields.
          - `targets` ProjectedVoiceTarget[]
            - `label` string, required
            - `when_to_use` string, nullable
          - `connecting_text` string, nullable
          - `mode` string
          - `max_retries` integer
          - `retry_text` string, nullable
        - `on_failure` string, nullable
        - `condition_readable` string, nullable
        - `approver_role` string, nullable
        - `suspend_message` string, nullable
        - `timeout_seconds` integer, nullable
        - `on_approve` string, nullable
        - `on_deny` string, nullable
      - `removed` ProjectedNode[]
        - `id` string, required
        - `kind` 'agent' | 'action' | 'handoff' | 'approval', required
        - `is_entry` boolean
        - `instructions` string, nullable
        - `required_writes` string[]
        - `writes` string[]
        - `done_when_readable` string, nullable
        - `tools` ProjectedTool[]
          - `canonical_key` string, required
          - `display_name` string, required
          - `produces_variables` string[]
        - `knowledge_bases` ProjectedKnowledgeBase[]
          - `kb_id` string, required
          - `display_name` string, required
          - `clearance_level` integer, nullable
        - `description` string, nullable
        - `failure_message` string, nullable
        - `steps` ProjectedActionStep[]
          - `id` string, required
          - `kind` 'speak' | 'tool_call' | 'knowledge_retrieval', required
          - `text` string, nullable
          - `tool_display_name` string, nullable
          - `knowledge_base_names` string[]
        - `result_write_names` string[]
        - `static_text` string, nullable
        - `voice_config` ProjectedVoiceHandoff — Voice channel config — targets + text, no internal destination fields.
          - `targets` ProjectedVoiceTarget[]
            - `label` string, required
            - `when_to_use` string, nullable
          - `connecting_text` string, nullable
          - `mode` string
          - `max_retries` integer
          - `retry_text` string, nullable
        - `on_failure` string, nullable
        - `condition_readable` string, nullable
        - `approver_role` string, nullable
        - `suspend_message` string, nullable
        - `timeout_seconds` integer, nullable
        - `on_approve` string, nullable
        - `on_deny` string, nullable
      - `changed` NodeChange[]
        - `id` string, required
        - `kind` 'agent' | 'action' | 'handoff' | 'approval', required
        - `changes` FieldChange[]
          - `field` string, required
          - `op` 'added' | 'removed' | 'modified', required
          - `text_diff` TextDiff — Line-level prose diff built from difflib.SequenceMatcher opcodes.
            - `segments` TextDiffSegment[], required
              - …
          - `before` unknown
          - `after` unknown
    - `edges` EdgeCollectionDiff — Diff over the edge collection.
      - `added` ProjectedEdge[]
        - `from_node` string, required
        - `to_node` string, required
        - `condition_readable` string, nullable
        - `is_failure_path` boolean
      - `removed` ProjectedEdge[]
        - `from_node` string, required
        - `to_node` string, required
        - `condition_readable` string, nullable
        - `is_failure_path` boolean
      - `changed` EdgeChange[]
        - `from_node` string, required
        - `to_node` string, required
        - `changes` FieldChange[]
          - `field` string, required
          - `op` 'added' | 'removed' | 'modified', required
          - `text_diff` TextDiff — Line-level prose diff built from difflib.SequenceMatcher opcodes.
            - `segments` TextDiffSegment[], required
              - …
          - `before` unknown
          - `after` unknown
    - `context_variables` ContextVarCollectionDiff — Diff over the context_variables collection.
      - `added` ProjectedContextVar[]
        - `name` string, required
        - `type` string, required
        - `source` string, required
        - `enum_values` string[], nullable
        - `reask_cap` integer, nullable
        - `description` string, nullable
      - `removed` ProjectedContextVar[]
        - `name` string, required
        - `type` string, required
        - `source` string, required
        - `enum_values` string[], nullable
        - `reask_cap` integer, nullable
        - `description` string, nullable
      - `changed` ContextVarChange[]
        - `name` string, required
        - `changes` FieldChange[]
          - `field` string, required
          - `op` 'added' | 'removed' | 'modified', required
          - `text_diff` TextDiff — Line-level prose diff built from difflib.SequenceMatcher opcodes.
            - `segments` TextDiffSegment[], required
              - …
          - `before` unknown
          - `after` unknown
    - `escape_hatches` EscapeHatchCollectionDiff — Diff over the escape_hatches collection.
      - `added` ProjectedEscapeHatch[]
        - `trigger` string, required
        - `target_label` string, required
        - `static_line` string, nullable
      - `removed` ProjectedEscapeHatch[]
        - `trigger` string, required
        - `target_label` string, required
        - `static_line` string, nullable
      - `changed` EscapeHatchChange[]
        - `trigger` string, required
        - `changes` FieldChange[]
          - `field` string, required
          - `op` 'added' | 'removed' | 'modified', required
          - `text_diff` TextDiff — Line-level prose diff built from difflib.SequenceMatcher opcodes.
            - `segments` TextDiffSegment[], required
              - …
          - `before` unknown
          - `after` unknown

## Other responses

- `400` — Bad request
- `401` — Authentication required
- `404` — Resource not found
- `422` — Validation Error

---

[API](https://skmtc.net/oneloop-hq/apis/feather-api.md) · [All operations](https://skmtc.net/oneloop-hq/apis/feather-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/oneloop-hq/feather-api/versions/888bdd5c076e/schema)
