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.
stepsandshell.timeoutin Configuration cap the worst case.
To also comment a change-impact report on pull requests, see the impact agent's CI/CD page.