UIGraph AgentsArtifacts agent

CI/CD

The artifacts agent belongs in a push-triggered job that commits what it updates, so artifacts never fall behind the branch.

Artifacts on every push

name: UIGraph Artifacts

on:
  push:

permissions:
  contents: write

concurrency:
  group: artifacts-${{ github.ref }}
  cancel-in-progress: false

jobs:
  artifacts:
    name: Detect drift and update artifacts
    runs-on: ubuntu-latest
    if: github.actor != 'github-actions[bot]' && !contains(github.event.head_commit.message, '[skip ci]')

    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 2

      - uses: actions/setup-node@v4
        with:
          node-version: 22

      - name: Detect drift
        env:
          AI_PROVIDER_NPM: ${{ secrets.AI_PROVIDER_NPM }}
          AI_PROVIDER_MODEL: ${{ secrets.AI_PROVIDER_MODEL }}
          AI_PROVIDER_API_URL: ${{ secrets.AI_PROVIDER_API_URL }}
          AI_PROVIDER_API_KEY: ${{ secrets.AI_PROVIDER_API_KEY }}
          UIGRAPH_API_URL: ${{ secrets.UIGRAPH_API_URL }}
          UIGRAPH_TOKEN: ${{ secrets.UIGRAPH_TOKEN }}
        run: |
          set -o pipefail
          npx @uigraph/agents artifacts sync --previous commit | tee -a "$GITHUB_STEP_SUMMARY"

      - name: Commit updated artifacts
        run: |
          if [ -z "$(git status --porcelain -- .uigraph.yaml .uigraph)" ]; then
            echo "No artifact changes to commit."
            exit 0
          fi

          git config user.name "github-actions[bot]"
          git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
          git add -- .uigraph.yaml .uigraph
          git commit -m "chore: update UIGraph artifacts [skip ci]"
          git push origin "HEAD:${{ github.ref_name }}"

Four details matter here:

  • fetch-depth: 2 — check out the previous commit too, or the agent has nothing to compare against.
  • The if: guard and [skip ci] — the job pushes a commit of its own. Without these it would keep triggering itself.
  • permissions: contents: write — give the job permission to push, or it cannot commit what it fixes.
  • tee -a "$GITHUB_STEP_SUMMARY" — puts the report straight on the run summary page, where reviewers will see it.

UIGRAPH_API_URL and UIGRAPH_TOKEN are required. Every run is recorded in UIGraph as an agent session, and the job fails before it calls the model when those secrets are missing or wrong.

On hosted UIGraph, drop UIGRAPH_API_URL and add --enterprise to the command instead:

          npx @uigraph/agents artifacts sync --previous commit --enterprise | tee -a "$GITHUB_STEP_SUMMARY"

Open a pull request instead of pushing

If pushing to the branch is too invasive, have the agent write to a branch and open a PR:

      - name: Detect drift
        env:
          AI_PROVIDER_MODEL: ${{ secrets.AI_PROVIDER_MODEL }}
          AI_PROVIDER_API_URL: ${{ secrets.AI_PROVIDER_API_URL }}
          AI_PROVIDER_API_KEY: ${{ secrets.AI_PROVIDER_API_KEY }}
          UIGRAPH_API_URL: ${{ secrets.UIGRAPH_API_URL }}
          UIGRAPH_TOKEN: ${{ secrets.UIGRAPH_TOKEN }}
        run: npx @uigraph/agents artifacts sync --previous commit --report artifacts-report.md

      - uses: peter-evans/create-pull-request@v6
        with:
          add-paths: |
            .uigraph.yaml
            .uigraph
          branch: uigraph/artifacts
          title: 'chore: update UIGraph artifacts'
          body-path: artifacts-report.md

Onboard a repository from CI

Onboarding is a one-off job rather than something you run on every push. It seeds a minimal config, runs init, then repairs anything the CLI rejects:

      - name: Seed the config
        run: |
          cat > .uigraph.yaml <<'YAML'
          version: 1
          service:
            name: Booking Service
            repository:
              provider: github
              url: https://github.com/company/booking-service
            ownership:
              team: platform
          YAML

      - name: Generate artifacts
        env:
          AI_PROVIDER_MODEL: ${{ secrets.AI_PROVIDER_MODEL }}
          AI_PROVIDER_API_URL: ${{ secrets.AI_PROVIDER_API_URL }}
          AI_PROVIDER_API_KEY: ${{ secrets.AI_PROVIDER_API_KEY }}
          UIGRAPH_API_URL: ${{ secrets.UIGRAPH_API_URL }}
          UIGRAPH_TOKEN: ${{ secrets.UIGRAPH_TOKEN }}
        run: |
          npx @uigraph/agents artifacts init --seeded || true

          PREVIOUS=""
          while :; do
            OUTPUT=$(uigraph-cli sync --dry-run 2>&1) && break
            [ "$OUTPUT" = "$PREVIOUS" ] && break
            PREVIOUS="$OUTPUT"
            npx @uigraph/agents artifacts fix "$OUTPUT"
          done

--seeded keeps the values you wrote in the seed file and fills in the artifacts around them. If the run crashes, it restores the seed and removes what that run created, so the job is safe to retry.

init exits 1 when it leaves errors behind but keeps its files, which is why the loop reads the CLI dry run rather than the exit code. Writing the report to a file needs an absolute path outside the repository, such as --report "$RUNNER_TEMP/init-report.md".

Notes for CI

  • Start with --dryRun. Run the sync job in dry-run mode for a few days and read the reports before letting it commit.
  • Pin the version. npx @uigraph/agents@<version> keeps a model-driven job reproducible.
  • Allow internet access. The runner needs it.
  • Budget the runtime. This job calls a model repeatedly, so it is slower than a lint job. steps and shell.timeout in Configuration cap the worst case.

To also comment a change-impact report on pull requests, see the impact agent's CI/CD page.

On this page