Docs & Code Guide

GitHub Actions workflow diagram: the needs graph is your pipeline map

GitHub draws a job graph on every run page, and that graph has two limits: it shows one workflow at a time, and it vanishes into run history. What a team actually needs on its wiki is the standing map: every workflow in .github/workflows, what triggers each, how jobs depend on each other through needs, and where the reusable workflows plug in. All of it is in the YAML, which means all of it can be drawn from the YAML, and redrawn by the same machinery it describes.

7 min readFor teams whose .github/workflows directory has become load-bearing and unexplained

See it as a diagram

Everything below, as a diagram you can edit. Describe yours and see it in seconds.

210/20003 credits left
Try:

No account needed · Editable canvas, not a picture

needs defines the DAG

Jobs in a workflow run in parallel unless told otherwise, and needs is the only ordering primitive: a job listing needs: [build, lint] waits for both and receives their outputs. The set of needs declarations is therefore the complete dependency graph, explicit in the file, no inference required. A job with no needs entry is a root that starts immediately, and a job several needs deep marks the critical path a slow build walks.

That per-workflow DAG is what GitHub's run page renders. The standing map adds what the run page cannot: all workflows side by side, their trigger events, which of them deploy where, and the shared plumbing between them. That is a diagram worth keeping, and the CI/CD pipeline generator builds the first version from a description or pasted YAML.

Reusable workflows and composite actions are your subgraphs

A reusable workflow, one that declares on: workflow_call, is invoked by other workflows with uses: org/repo/.github/workflows/deploy.yml@main at the job level. On the map it should be drawn once, as a subgraph, with edges in from every caller: that single picture answers the question grep answers slowly, which pipelines actually deploy through the shared path.

Composite actions bundle steps, not jobs, and live below the granularity a pipeline map needs. Annotate the jobs that use the important ones rather than drawing them as nodes, or the diagram sinks into step-level noise.

Lint before you draw

A diagram generated from a broken workflow is a picture of nothing. actionlint, the standard static checker for workflow files, catches exactly the errors that corrupt a map: needs entries referencing jobs that do not exist, malformed trigger events, expression typos. Run it in the same job that regenerates the diagram, before the regeneration, so the map is only ever redrawn from YAML that parses and resolves.

The workflow that redraws the map

The regeneration trigger belongs in the system being diagrammed: a workflow with a paths filter on .github/workflows/** runs exactly when the pipeline definition changes. The self-reference is honest because of what it does not claim: Datadef does not watch the repository, and no app detects the change. The paths filter is the detection, and the step below is the one command. Two credentials are involved: the agent CLI needs its own key, passed as a repository secret, and the Datadef MCP server, registry name io.datadef/mcp, is declared in the repo's .mcp.json with its API key referenced from a secret there, available on paid plans.

name: refresh-ci-diagram
on:
  push:
    branches: [main]
    paths:
      - ".github/workflows/**"
jobs:
  redraw:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: actionlint
      # Any MCP-capable agent works here; Claude Code shown. The Datadef
      # MCP server and its API key live in the repo's .mcp.json.
      - run: |
          claude -p "Read .github/workflows/, rebuild the job graph from the
          needs declarations, and update our CI pipeline diagram through the
          Datadef MCP server."
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

Close the loop in the README, and the honest limits

The natural home for the CI map is the repository itself. The live image URL drops into the README as ordinary Markdown, and because GitHub strips iframes, the image form is the only live option there; the mechanics are covered in embedding diagrams in a GitHub README. The requirement to state plainly: the live embed exists only for projects shared public, which suits open source repos and rules out some private ones.

Two scope limits: matrix jobs expand at run time, so the map shows the job as one node, not the twenty variants a matrix spawns, which is usually what a reader wants anyway. And the diagram documents structure, not outcomes; for gating merges on documentation freshness itself, see docs checks in CI.

FAQ

How do I visualize a GitHub Actions workflow as a diagram?

The dependency graph is explicit in the YAML: each needs declaration is an edge, jobs without needs are roots. Generate the diagram from the workflow files, drawing reusable workflows as shared subgraphs and annotating trigger events. GitHub renders a per-run graph on the run page, but a standing cross-workflow map has to be generated from the files.

Can the CI diagram update itself when workflows change?

Yes, through CI itself: a workflow with a paths filter on .github/workflows/** triggers when any workflow file changes, lints with actionlint, and runs an MCP-connected agent that updates the diagram. Nothing watches the repo from outside; the paths filter is the detection and the agent call is the redraw.

How should reusable workflows appear on a pipeline diagram?

As a single subgraph with edges from every workflow that calls it via uses. Drawing the shared deploy workflow once, with all its callers pointing in, shows at a glance which pipelines ship through the common path, which is the main question a shared workflow raises.

What does actionlint add to a diagram pipeline?

It guarantees the map is drawn from valid input. actionlint statically catches needs references to nonexistent jobs, malformed events, and expression errors, exactly the mistakes that would produce a wrong graph. Running it before regeneration means the diagram only ever updates from YAML that resolves.

Do matrix jobs show up as multiple nodes?

Not from the YAML: a matrix is one job definition that expands at run time, so a file-derived diagram shows one node, ideally annotated with the matrix dimensions. That is usually the right granularity for a map; the per-run expansion is what the GitHub run page already shows well.