OCNORA
opsadvanced15 min setupby Mantle

workflow_health (system)

Acts on Workflow Health findings Auto Fix cannot answer: plans, branches, fixes, validates, commits and opens a pull request for a code defect through the host runner; files the rest for a person; reports back to the health check. Tag the installed workflow system:health and point Settings → Workflow Health at it.

Drag to pan, pinch to zoom. This is the real graph the template installs.

How it works

What it does

  • Started by the Workflow Health role (never by hand) with the findings of one health check that Auto Fix could not answer.
  • For each finding: a code finding goes to the host runner — Plan (Claude Code, read-only: root cause + an immediate fix and an isolate/mitigate alternative), then if the plan is safe now Branch (a health/… worktree off origin/main) → Fix → the repo's own checksCommit and push the branch → a draft pull request against main; a plan that is not safe now becomes a GitHub issue listing the options. Every other kind (connection, external, design, unknown) is handed to a person.
  • Collect outcomes gathers one result per finding and Report back posts them to POST /workflows/{id}/health/{hid}/complete; the check then reads code_fix_open, fixed or needs_user_input.
  • Nothing here merges, publishes, or pushes to main.

Setup

  • Tenant variables: HEALTH_RUNNER_URL (the host runner, e.g. http://host.docker.internal:8787), HEALTH_RUNNER_TOKEN (secret, its bearer token), MANTLE_API_URL (this API as reached from inside the deployment) and MANTLE_API_KEY (secret; an API key with workflows:read/write/run and runs:read).
  • Tag the installed workflow system:health (Settings → Tags) so health never checks it, publish it, and point Settings → Workflow Health at it.
  • workflows/build-workflow-health.py in the workspace does all of the above for the local tenant.

Nodes 17

  1. 01Health findings receivedtrigger.workflowTrigger
  2. 02For each findingcontrol.for_eachLogic
  3. 03Which kind of problem?control.noopLogic
  4. 04Plan the fix (Claude Code, read-only)http.requestHTTP
  5. 05Branch off main (worktree)http.requestHTTP
  6. 06Fix on the branch (Claude Code, 5–13 min)http.requestHTTP
  7. 07Run the repo's checkshttp.requestHTTP
  8. 08Commit and push the branchhttp.requestHTTP
  9. 09Open the pull requesthttp.requestHTTP
  10. 10Outcome: pull request opendata.setData
  11. 11Outcome: fix failed validationdata.setData
  12. 12No immediate fix: file the plans as an issuehttp.requestHTTP
  13. 13Outcome: issue open with the optionsdata.setData
  14. 14Outcome: needs a persondata.setData
  15. 15Collect outcomescontrol.gatherLogic
  16. 16Report back to Workflow Healthhttp.requestHTTP
  17. 17Donecontrol.stopLogic
View template JSON
{
  "format": "mantle-workflow/v1",
  "id": "system-workflow-health",
  "name": "workflow_health (system)",
  "graph": {
    "nodes": [
      {
        "id": "receive",
        "type": "trigger.workflow",
        "label": "Health findings received",
        "worker_type": "generic-worker",
        "connection_id": null,
        "position": {
          "x": 60,
          "y": 300
        },
        "config": {}
      },
      {
        "id": "each",
        "type": "control.for_each",
        "label": "For each finding",
        "worker_type": "generic-worker",
        "connection_id": null,
        "position": {
          "x": 340,
          "y": 300
        },
        "config": {
          "items": "findings",
          "item_as": "finding",
          "parallel": false,
          "on_error": "continue",
          "empty_collection": "skip",
          "max_items": 20
        }
      },
      {
        "id": "route",
        "type": "control.noop",
        "label": "Which kind of problem?",
        "worker_type": "generic-worker",
        "connection_id": null,
        "position": {
          "x": 620,
          "y": 300
        },
        "config": {}
      },
      {
        "id": "plan",
        "type": "http.request",
        "label": "Plan the fix (Claude Code, read-only)",
        "worker_type": "generic-worker",
        "connection_id": null,
        "position": {
          "x": 900,
          "y": 120
        },
        "config": {
          "method": "POST",
          "url": "{{ $vars.HEALTH_RUNNER_URL }}/remediate/plan",
          "headers": {
            "Authorization": "Bearer {{ $vars.HEALTH_RUNNER_TOKEN }}",
            "Accept": "application/json"
          },
          "timeout_seconds": 600,
          "body_from_input": true
        },
        "retry": {
          "max_attempts": 4,
          "backoff": "exponential",
          "initial_ms": 15000,
          "max_ms": 120000
        }
      },
      {
        "id": "branch_repo",
        "type": "http.request",
        "label": "Branch off main (worktree)",
        "worker_type": "generic-worker",
        "connection_id": null,
        "position": {
          "x": 1180,
          "y": 60
        },
        "config": {
          "method": "POST",
          "url": "{{ $vars.HEALTH_RUNNER_URL }}/remediate/branch",
          "headers": {
            "Authorization": "Bearer {{ $vars.HEALTH_RUNNER_TOKEN }}",
            "Accept": "application/json"
          },
          "timeout_seconds": 120,
          "json": {
            "repo": "steps.plan.body.repo",
            "health_id": "steps.plan.body.health_id",
            "finding_id": "steps.plan.body.finding_id",
            "plan": "steps.plan.body"
          }
        },
        "retry": {
          "max_attempts": 4,
          "backoff": "exponential",
          "initial_ms": 15000,
          "max_ms": 120000
        }
      },
      {
        "id": "fix",
        "type": "http.request",
        "label": "Fix on the branch (Claude Code, 5–13 min)",
        "worker_type": "generic-worker",
        "connection_id": null,
        "position": {
          "x": 1460,
          "y": 60
        },
        "config": {
          "method": "POST",
          "url": "{{ $vars.HEALTH_RUNNER_URL }}/remediate/fix",
          "headers": {
            "Authorization": "Bearer {{ $vars.HEALTH_RUNNER_TOKEN }}",
            "Accept": "application/json"
          },
          "timeout_seconds": 840,
          "json": {
            "repo": "steps.plan.body.repo",
            "health_id": "steps.plan.body.health_id",
            "finding_id": "steps.plan.body.finding_id",
            "branch": "steps.branch_repo.body.branch",
            "plan": "steps.plan.body"
          }
        },
        "retry": {
          "max_attempts": 4,
          "backoff": "exponential",
          "initial_ms": 15000,
          "max_ms": 120000
        }
      },
      {
        "id": "validate",
        "type": "http.request",
        "label": "Run the repo's checks",
        "worker_type": "generic-worker",
        "connection_id": null,
        "position": {
          "x": 1740,
          "y": 60
        },
        "config": {
          "method": "POST",
          "url": "{{ $vars.HEALTH_RUNNER_URL }}/remediate/validate",
          "headers": {
            "Authorization": "Bearer {{ $vars.HEALTH_RUNNER_TOKEN }}",
            "Accept": "application/json"
          },
          "timeout_seconds": 900,
          "json": {
            "repo": "steps.plan.body.repo",
            "health_id": "steps.plan.body.health_id",
            "finding_id": "steps.plan.body.finding_id",
            "branch": "steps.branch_repo.body.branch"
          }
        },
        "retry": {
          "max_attempts": 4,
          "backoff": "exponential",
          "initial_ms": 15000,
          "max_ms": 120000
        }
      },
      {
        "id": "commit",
        "type": "http.request",
        "label": "Commit and push the branch",
        "worker_type": "generic-worker",
        "connection_id": null,
        "position": {
          "x": 2020,
          "y": 20
        },
        "config": {
          "method": "POST",
          "url": "{{ $vars.HEALTH_RUNNER_URL }}/remediate/commit",
          "headers": {
            "Authorization": "Bearer {{ $vars.HEALTH_RUNNER_TOKEN }}",
            "Accept": "application/json"
          },
          "timeout_seconds": 180,
          "json": {
            "repo": "steps.plan.body.repo",
            "health_id": "steps.plan.body.health_id",
            "finding_id": "steps.plan.body.finding_id",
            "branch": "steps.branch_repo.body.branch",
            "plan": "steps.plan.body"
          }
        },
        "retry": {
          "max_attempts": 4,
          "backoff": "exponential",
          "initial_ms": 15000,
          "max_ms": 120000
        }
      },
      {
        "id": "pr",
        "type": "http.request",
        "label": "Open the pull request",
        "worker_type": "generic-worker",
        "connection_id": null,
        "position": {
          "x": 2300,
          "y": 20
        },
        "config": {
          "method": "POST",
          "url": "{{ $vars.HEALTH_RUNNER_URL }}/remediate/pr",
          "headers": {
            "Authorization": "Bearer {{ $vars.HEALTH_RUNNER_TOKEN }}",
            "Accept": "application/json"
          },
          "timeout_seconds": 120,
          "json": {
            "repo": "steps.plan.body.repo",
            "health_id": "steps.plan.body.health_id",
            "finding_id": "steps.plan.body.finding_id",
            "branch": "steps.branch_repo.body.branch",
            "plan": "steps.plan.body"
          }
        },
        "retry": {
          "max_attempts": 4,
          "backoff": "exponential",
          "initial_ms": 15000,
          "max_ms": 120000
        }
      },
      {
        "id": "code_done",
        "type": "data.set",
        "label": "Outcome: pull request open",
        "worker_type": "generic-worker",
        "connection_id": null,
        "position": {
          "x": 2580,
          "y": 20
        },
        "config": {
          "values": {
            "finding_id": "{{ $steps.plan.body.finding_id }}",
            "status": "pr_open",
            "kind": "code_fix",
            "repo": "{{ $steps.plan.body.repo }}",
            "branch": "{{ $steps.branch_repo.body.branch }}",
            "commit": "{{ $steps.commit.body.commit }}",
            "pr_url": "{{ $steps.pr.body.url }}",
            "pr_number": "{{ $steps.pr.body.number }}",
            "chosen_plan_id": "{{ $steps.plan.body.recommended }}",
            "detail": "{{ $steps.pr.body.summary }}"
          },
          "include_input": false,
          "types": {
            "pr_number": "number"
          }
        }
      },
      {
        "id": "code_blocked",
        "type": "data.set",
        "label": "Outcome: fix failed validation",
        "worker_type": "generic-worker",
        "connection_id": null,
        "position": {
          "x": 2020,
          "y": 200
        },
        "config": {
          "values": {
            "finding_id": "{{ $steps.plan.body.finding_id }}",
            "status": "failed",
            "kind": "code_fix",
            "repo": "{{ $steps.plan.body.repo }}",
            "branch": "{{ $steps.branch_repo.body.branch }}",
            "detail": "{{ $steps.validate.body.summary }}"
          },
          "include_input": false
        }
      },
      {
        "id": "code_issue",
        "type": "http.request",
        "label": "No immediate fix: file the plans as an issue",
        "worker_type": "generic-worker",
        "connection_id": null,
        "position": {
          "x": 1180,
          "y": 240
        },
        "config": {
          "method": "POST",
          "url": "{{ $vars.HEALTH_RUNNER_URL }}/remediate/issue",
          "headers": {
            "Authorization": "Bearer {{ $vars.HEALTH_RUNNER_TOKEN }}",
            "Accept": "application/json"
          },
          "timeout_seconds": 120,
          "json": {
            "repo": "steps.plan.body.repo",
            "health_id": "steps.plan.body.health_id",
            "finding_id": "steps.plan.body.finding_id",
            "plan": "steps.plan.body"
          }
        },
        "retry": {
          "max_attempts": 4,
          "backoff": "exponential",
          "initial_ms": 15000,
          "max_ms": 120000
        }
      },
      {
        "id": "code_issue_done",
        "type": "data.set",
        "label": "Outcome: issue open with the options",
        "worker_type": "generic-worker",
        "connection_id": null,
        "position": {
          "x": 1460,
          "y": 240
        },
        "config": {
          "values": {
            "finding_id": "{{ $steps.plan.body.finding_id }}",
            "status": "issue_open",
            "kind": "code_fix",
            "repo": "{{ $steps.plan.body.repo }}",
            "issue_url": "{{ $steps.code_issue.body.url }}",
            "detail": "{{ $steps.code_issue.body.summary }}"
          },
          "include_input": false
        }
      },
      {
        "id": "other",
        "type": "data.set",
        "label": "Outcome: needs a person",
        "worker_type": "generic-worker",
        "connection_id": null,
        "position": {
          "x": 900,
          "y": 460
        },
        "config": {
          "values": {
            "finding_id": "{{ $json.id }}",
            "status": "needs_user_input",
            "kind": "notified",
            "detail": "{{ $json.classification.reason }}"
          },
          "include_input": false
        }
      },
      {
        "id": "gather",
        "type": "control.gather",
        "label": "Collect outcomes",
        "worker_type": "generic-worker",
        "connection_id": null,
        "position": {
          "x": 2860,
          "y": 300
        },
        "config": {
          "mode": "loop"
        }
      },
      {
        "id": "complete",
        "type": "http.request",
        "label": "Report back to Workflow Health",
        "worker_type": "generic-worker",
        "connection_id": null,
        "position": {
          "x": 3140,
          "y": 300
        },
        "config": {
          "method": "POST",
          "url": "{{ $vars.MANTLE_API_URL }}/workflows/{{ $steps.receive.workflow.id }}/health/{{ $steps.receive.health_id }}/complete",
          "headers": {
            "Authorization": "Bearer {{ $vars.MANTLE_API_KEY }}",
            "Accept": "application/json"
          },
          "json": {
            "outcomes": "input.items",
            "delegate_run_id": "{{ $run.id }}"
          },
          "timeout_seconds": 30
        },
        "retry": {
          "max_attempts": 3,
          "backoff": "fixed",
          "initial_ms": 5000,
          "max_ms": 5000
        }
      },
      {
        "id": "done",
        "type": "control.stop",
        "label": "Done",
        "worker_type": "generic-worker",
        "connection_id": null,
        "position": {
          "x": 3420,
          "y": 300
        },
        "config": {
          "status": "succeed",
          "message": "Health findings handled"
        }
      }
    ],
    "edges": [
      {
        "from": "receive",
        "to": "each"
      },
      {
        "from": "each",
        "to": "route"
      },
      {
        "from": "route",
        "to": "plan",
        "condition": "kind == 'code'"
      },
      {
        "from": "route",
        "to": "other",
        "condition": "kind != 'code'"
      },
      {
        "from": "plan",
        "to": "branch_repo",
        "condition": "body.immediate == true"
      },
      {
        "from": "plan",
        "to": "code_issue",
        "condition": "body.immediate != true"
      },
      {
        "from": "branch_repo",
        "to": "fix"
      },
      {
        "from": "fix",
        "to": "validate"
      },
      {
        "from": "validate",
        "to": "commit",
        "condition": "body.ok == true"
      },
      {
        "from": "validate",
        "to": "code_blocked",
        "condition": "body.ok != true"
      },
      {
        "from": "commit",
        "to": "pr"
      },
      {
        "from": "pr",
        "to": "code_done"
      },
      {
        "from": "code_issue",
        "to": "code_issue_done"
      },
      {
        "from": "code_done",
        "to": "gather"
      },
      {
        "from": "code_blocked",
        "to": "gather"
      },
      {
        "from": "code_issue_done",
        "to": "gather"
      },
      {
        "from": "other",
        "to": "gather"
      },
      {
        "from": "gather",
        "to": "complete"
      },
      {
        "from": "complete",
        "to": "done"
      }
    ]
  }
}

Use it, then make it yours.

Templates install as drafts. Change anything, and Workflow Health re-checks the graph on every save.