Skip to content

GitHub Actions

Run Erode as a GitHub Actions workflow that checks every pull request automatically.

Create .github/workflows/erode.yml in your repository:

name: Architecture Drift Check
on: [pull_request]
jobs:
erode:
if: github.actor != 'dependabot[bot]' && !github.event.pull_request.draft
runs-on: ubuntu-latest
steps:
- uses: erode-app/erode@0
with:
model-repo: your-org/architecture
github-token: ${{ secrets.GITHUB_TOKEN }}
gemini-api-key: ${{ secrets.GEMINI_API_KEY }}

The if guard skips dependabot PRs and draft PRs. Since Erode uses AI tokens on every run, this avoids spending them on automated dependency bumps and work-in-progress PRs that rarely introduce architectural drift. Remove the guard if you want Erode to run on all PRs.

The action runs in a Docker container that clones the model repository directly. You do not need an actions/checkout step.

Erode expects the architecture model to live in its own repository (or a subdirectory of one). The model-repo input tells the action where to find it.

- uses: erode-app/erode@0
with:
model-repo: your-org/architecture # required
model-path: models/backend # subdirectory within the repo
model-ref: v2 # branch or tag (default: main)
github-token: ${{ secrets.GITHUB_TOKEN }}
gemini-api-key: ${{ secrets.GEMINI_API_KEY }}

If the model repo requires different credentials than the repository running the workflow, pass a separate token:

- uses: erode-app/erode@0
with:
model-repo: your-org/architecture
model-repo-token: ${{ secrets.MODEL_REPO_TOKEN }}
github-token: ${{ secrets.GITHUB_TOKEN }}
gemini-api-key: ${{ secrets.GEMINI_API_KEY }}

model-repo-token is used only for cloning the model repository. All other GitHub API calls (reading the PR diff, posting comments) use github-token.

InputDescriptionRequiredDefault
model-repoRepository containing the architecture model (owner/repo)Yes
model-pathPath to the model within the model repositoryNo.
model-refGit ref (branch/tag) of the model repositoryNomain
model-formatArchitecture model formatNolikec4
ai-providerAI provider (gemini, openai, or anthropic)Noanthropic
gemini-api-keyGemini API keyWhen using Gemini
openai-api-keyOpenAI API keyWhen using OpenAI
anthropic-api-keyAnthropic API key (experimental)When using Anthropic
github-tokenGitHub token for reading PRs and posting commentsYes
model-repo-tokenSeparate GitHub token for cloning the model repositoryNoUses github-token
open-prOpen a PR with model updates (true, false, or auto)Nofalse
fail-on-violationsFail the workflow if violations are detectedNofalse
skip-file-filteringAnalyze all changed files instead of filtering by relevanceNofalse
OutputDescription
has-violationsWhether architectural violations were detected
violations-countNumber of violations detected
analysis-summarySummary of the analysis results
model-formatThe architecture model format used

Use outputs in subsequent workflow steps:

steps:
- uses: erode-app/erode@0
id: erode
with:
model-repo: your-org/architecture
github-token: ${{ secrets.GITHUB_TOKEN }}
gemini-api-key: ${{ secrets.GEMINI_API_KEY }}
- if: steps.erode.outputs.has-violations == 'true'
run: echo "Found ${{ steps.erode.outputs.violations-count }} violations"

The open-pr input controls whether Erode creates a pull request against the model repository with updated relationship declarations. It accepts three values:

ValueBehavior
falseNever create a model PR (default)
trueAlways create or update a model PR when model updates are found
autoOnly update a model PR if one was previously created for this source PR (sticky opt-in)

When open-pr is true or auto (with an existing branch), Erode runs Stage 4 (Model Update) to generate a deterministic patch from the Stage 3 structured analysis data, then creates or updates a pull request against the model repository.

  • PRs are created as drafts by default (GitHub/GitLab). Bitbucket has no draft support.
  • The PR body includes a link to the source analysis PR for traceability.
  • If a subsequent analysis finds no violations, any existing model PR for that source PR is automatically closed.

On-demand updates with /erode update-model

Section titled “On-demand updates with /erode update-model”

With open-pr: 'auto', Erode skips PR creation on regular analysis runs. Instead, when model updates are detected, the analysis comment includes a call-to-action:

To handle that comment, add the issue_comment trigger to your workflow. Use open-pr: 'true' for comment-triggered runs so the initial model PR is created, and 'auto' for regular pull_request runs so subsequent pushes keep it updated:

name: Architecture Drift Check
on:
pull_request:
issue_comment:
types: [created]
jobs:
erode:
if: >-
(github.event_name == 'pull_request' &&
github.actor != 'dependabot[bot]' &&
!github.event.pull_request.draft)
||
(github.event_name == 'issue_comment' &&
github.event.issue.pull_request &&
contains(github.event.comment.body, '/erode update-model'))
runs-on: ubuntu-latest
steps:
- uses: erode-app/erode@0
with:
model-repo: your-org/architecture
open-pr: ${{ github.event_name == 'issue_comment' && 'true' || 'auto' }}
github-token: ${{ secrets.GITHUB_TOKEN }}
gemini-api-key: ${{ secrets.GEMINI_API_KEY }}

The flow:

  1. A pull_request run with auto finds no existing branch, so it skips PR creation and shows the CTA.
  2. A reviewer comments /erode update-model. The issue_comment trigger fires with open-pr: 'true', creating the model PR.
  3. Further pushes to the source PR trigger pull_request with auto. The branch now exists, so the model PR is updated automatically.

The issue_comment trigger fires for all PR comments. The if guard ensures the job only runs when the comment contains /erode update-model and the issue is actually a pull request.

After analysis, Erode posts a comment on the pull request containing:

  • A summary of the analysis result
  • A violations table listing each finding with its severity (high, medium, or low), the affected dependency, and a description
  • Suggestions for resolving each violation
  • The component and architecture context used during analysis

If no violations are found, the comment confirms that the PR aligns with the declared architecture.

For organizations, GitHub Apps are the recommended authentication method. Unlike personal access tokens, App tokens are short-lived, scoped to specific repositories, and not tied to individual user accounts, so they keep working when people leave the organization. Permissions are managed centrally through the App’s installation settings.

Use the create-github-app-token action to generate a token at the start of each workflow run:

name: Architecture Drift Check
on: [pull_request]
concurrency:
group: erode-${{ github.event.pull_request.number }}
cancel-in-progress: true
permissions: {}
jobs:
erode:
if: github.actor != 'dependabot[bot]' && !github.event.pull_request.draft
runs-on: ubuntu-latest
steps:
- uses: actions/create-github-app-token@v2
id: app-token
with:
app-id: ${{ vars.ERODE_APP_ID }}
private-key: ${{ secrets.ERODE_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
- uses: erode-app/erode@0
with:
model-repo: your-org/architecture
github-token: ${{ steps.app-token.outputs.token }}
gemini-api-key: ${{ secrets.GEMINI_API_KEY }}

The owner field ensures the token covers all repositories the App is installed on within the organization. permissions: {} drops the default GITHUB_TOKEN permissions since the App token provides its own, and concurrency cancels stale runs when a PR is updated.

  • Start with the Gemini provider during evaluation. It is cheaper per request. OpenAI is another good option for production workflows.
  • Keep your architecture model up to date. Erode can only detect drift against what is declared in the model.
  • Set fail-on-violations: 'true' to block PRs that introduce undeclared dependencies.
  • See Configuration for tuning diff limits, timeouts, and model overrides.