# AgentOps GenAIOps GitFlow on GitHub Actions
This guide shows how to wire AgentOps into a complete GenAIOps CI/CD
pipeline on GitHub Actions, mapped to a classic GitFlow branching model
with three deployment environments (`dev`, `qa`, `production`).
Start with `agentops workflow analyze`. It reads the repo and recommends both
deployment wiring (azd, prompt-agent, or placeholder) and the eval runner.
Generate the PR gate first: `agentops workflow generate --kinds pr`. Add
DEV/QA/PROD after GitHub Environments and Azure OIDC are ready. Repos with
`azure.yaml` use azd-backed deploys; Foundry prompt agents can use
prompt-agent deploys and AgentOps cloud eval in Foundry when the dataset is
compatible.
The default scaffold ships four release-path templates. A scheduled Doctor
workflow is available separately when you explicitly generate `--kinds doctor`.
| File | Trigger | GitHub Environment | Purpose |
|---|---|---|---|
| `agentops-pr.yml` | PRs to `develop`, `release/**`, `main` | `dev` | Eval gate + Doctor gate (default blocks on critical findings; configurable via `--doctor-gate`) + PR comment |
| `agentops-deploy-dev.yml` | push to `develop` | `dev` | Eval → build → deploy DEV |
| `agentops-deploy-qa.yml` | push to `release/**` | `qa` | Eval → build → deploy QA |
| `agentops-deploy-prod.yml` | push to `main` | `production` | Safety eval → evidence → build → deploy PROD |
| `agentops-doctor.yml` | daily cron | `dev` | Optional scheduled Doctor + release evidence |
## GitFlow assumed
```mermaid
flowchart LR
feat["feature/*"] -->|PR| prGate1{{"agentops-pr.yml
(gate)"}}
prGate1 -->|merge| dev["develop"]
dev --> deployDev["agentops-deploy-dev.yml"]
deployDev --> DEV(["DEV"])
rel["release/*"] -->|push| deployQa["agentops-deploy-qa.yml"]
deployQa --> QA(["QA"])
rel -->|PR| prGate2{{"agentops-pr.yml
(gate)"}}
prGate2 -->|merge| main["main"]
main --> deployProd["agentops-deploy-prod.yml"]
deployProd --> PROD(["PROD
(required reviewers)"])
classDef gate fill:#fff3cd,stroke:#856404,color:#000;
classDef env fill:#d1ecf1,stroke:#0c5460,color:#000;
class prGate1,prGate2 gate;
class DEV,QA,PROD env;
```
If you are on trunk-based development, generate only the templates you
need: `agentops workflow generate --kinds pr,dev,prod`.
## Quick start
```bash
# 1. Analyze and fix eval setup before the first blocking run.
agentops eval analyze
# 2. Make sure your eval works locally first.
agentops eval run
# 3. Analyze the repo shape before generating workflows.
agentops workflow analyze
# 4. Generate the PR gate first.
agentops workflow generate --kinds pr
# 5. Configure GitHub (see sections below):
# - OIDC repo variables
# - dev environment
# - branch protection on develop and main
# 6. Commit and push the PR gate.
# 7. Only after deploy wiring is real, generate the full scaffold.
# auto uses azd when azure.yaml exists, or prompt-agent when agentops.yaml
# targets a Foundry prompt agent (name:version).
agentops workflow generate --kinds pr,dev,qa,prod --deploy-mode auto --force
```
## Copilot-assisted setup
The GitHub setup spans repository creation, Azure OIDC, Actions variables,
GitHub Environments, and branch protection. For a smoother first run, install
the AgentOps workflow skill and hand this setup to Copilot:
```bash
agentops skills install --platform copilot --force
```
Then open Copilot and run `/skills`. Confirm `agentops-workflow` is loaded
before continuing.
When the skill is loaded, ask Copilot:
```text
Use the AgentOps workflow skill to get the generated AgentOps GitHub Actions
workflows running end to end.
This may be a new folder with no Git repo or GitHub remote yet. Create or
connect the GitHub repo if needed, wire Azure OIDC and required Actions
variables, verify the OIDC principal has Foundry User access, create only the
environments used by the generated workflows, show me the plan before changing
GitHub or Azure, and call out anything that needs owner/admin permission.
```
## Configuration walkthrough
### 1. Repository variables (OIDC)
In Settings → Secrets and variables → Actions → **Variables**, add:
| Variable | Purpose |
|---|---|
| `AZURE_CLIENT_ID` | App registration / managed identity used for federated login |
| `AZURE_TENANT_ID` | Azure AD tenant |
| `AZURE_SUBSCRIPTION_ID` | Target subscription |
| `AZURE_AI_FOUNDRY_PROJECT_ENDPOINT` | Foundry project URL (used by the eval step) |
| `AZURE_OPENAI_DEPLOYMENT` | Model deployment used by local evaluators and AgentOps cloud eval judges |
| `APPLICATIONINSIGHTS_CONNECTION_STRING` | Optional fallback when the Foundry project's App Insights connection cannot be auto-discovered |
Set `AZURE_TENANT_ID` to the tenant that owns the app registration / federated
credential used by `AZURE_CLIENT_ID`. Do not use a subscription
`managedByTenants` tenant id unless the app registration and federated
credential are also visible in that tenant; otherwise `azure/login` can fail at
token issuance before AgentOps starts.
Then on the Azure side, configure Workload Identity Federation
(federated credentials) on the app registration so it can be assumed
from GitHub Actions runs. See
[Microsoft's WIF docs](https://learn.microsoft.com/azure/active-directory/workload-identities/workload-identity-federation-create-trust?pivots=identity-wif-apps-methods-azp).
For Foundry prompt-agent gates, the same app registration / service principal
needs **two** Azure RBAC roles before the first workflow run. Both are required
and the eval step fails silently (every metric returns `null`) if only one is
in place:
- **Foundry User** on the Foundry project or Foundry resource. Azure `Reader`
is not enough because the eval step calls Foundry data-plane APIs such as
`Microsoft.CognitiveServices/accounts/AIServices/agents/read`.
- **Cognitive Services OpenAI User** on the underlying Azure AI Services
account that hosts the evaluator model deployment. Foundry `azure_ai_evaluator`
graders impersonate the OIDC principal to call OpenAI; without this role
they fail with a 401 `PermissionDenied` on
`Microsoft.CognitiveServices/accounts/OpenAI/deployments/chat/completions/action`
and every metric returns `null` in the cloud eval report. AgentOps lifts that
error into `results.json` and the orchestrator's "0 usable metric scores"
warning so you can see the cause in CI logs, but the workflow still fails the
gate. The role ids are `53ca6127-db72-4b80-b1b0-d745d6d5456d` (Foundry User)
and `5e0bd9bd-7b93-4f28-af87-19fc36ad61bd` (Cognitive Services OpenAI User).
The generated eval and doctor workflows install AgentOps telemetry support.
When `AZURE_AI_FOUNDRY_PROJECT_ENDPOINT` is set, AgentOps first tries to
auto-discover the Foundry project's Application Insights resource. If that
is not available in your tenant, set `APPLICATIONINSIGHTS_CONNECTION_STRING`
as either a repository/environment variable or a secret. CI eval runs then
emit `agentops.eval.*` spans, and scheduled Doctor runs emit
`agentops.agent.finding.*` spans that the Cockpit can deep-link into Azure
Monitor Logs.
### 2. GitHub Environments
In Settings → Environments, create three:
#### `dev`
- Usually no protection rules.
- Override env-specific variables here (e.g. dev resource group, dev
ACA app name).
#### `qa`
- Optional: restrict deployment branches to `release/**`.
- Override env-specific variables for QA infra.
#### `production`
- **Required reviewers**: at least one. Deploys to PROD pause until
approved.
- Optional: **Wait timer** for an extra cool-down.
- Optional: **Deployment branches**: restrict to `main`.
- Override env-specific variables for production infra.
Environment-level variables override repo-level ones automatically
when the workflow's `environment:` matches.
### 3. Analyze evaluation setup first
Before making eval a required PR/deploy gate, run:
```bash
agentops eval analyze --format markdown
```
This command is read-only and local-only. It checks whether `agentops.yaml`,
the target kind, and the dataset columns are ready for `agentops eval run`. If
the project looks like a RAG app, tool-using agent, HTTP/containerized app, or
other accelerator where deterministic inference is not enough, it recommends
using Copilot with `agentops-config`, `agentops-dataset`, and/or
`agentops-eval` before the first blocking run. When skills are missing from the
repo, the output includes the install command and a copy/paste Copilot handoff
prompt.
### 4. Choose deployment mode
AgentOps is azd-first for deployment: AgentOps runs the evaluation gate,
while Azure Developer CLI manages infrastructure, packaging, deployment, and
hooks declared in `azure.yaml`.
Before choosing manually, run:
```bash
agentops workflow analyze --format markdown
```
The analyzer is read-only and local-only. It looks for `azure.yaml`, Bicep
files, `agentops.yaml`, Foundry prompt-agent shape, source-controlled prompt
files, landing-zone manifests, private-network terms, Docker/Container Apps
signals, and existing CI folders. README matches such as GPT-RAG, Live Voice, or
AI Landing Zone are treated as hints; structural files drive the recommendation.
`workflow generate --deploy-mode auto` uses the same recommendation, so the
analysis and generated templates do not drift. The analyzer also reports the
eval runner: AgentOps cloud eval in Foundry for compatible Foundry prompt
agents, otherwise AgentOps local eval. If you omit `--deploy-mode`, the default
is `auto`; the command output prints the selected effective mode, for example
`azd (auto default)` or `placeholder (auto default)`.
Use one of these modes:
| Mode | When to use it |
|---|---|
| `--deploy-mode auto` | Pick azd, prompt-agent, or placeholders from repo signals. |
| `--deploy-mode azd` | Use `azd provision` / `azd deploy` templates. |
| `--deploy-mode prompt-agent` | Create, evaluate, and record a Foundry prompt-agent candidate. |
| `--deploy-mode placeholder` | Keep stack-agnostic build/deploy placeholders. |
For azd-managed repos:
```bash
agentops workflow generate --kinds pr,dev,qa,prod --deploy-mode azd --force
```
The generated deploy workflows:
1. install `azd`;
2. run `azd env new ... || azd env select ...` on each CI runner;
3. run `azd provision --no-prompt` for DEV by default;
4. run `azd provision --no-prompt` for QA/PROD only when manually requested;
5. run the selected eval runner as the quality/safety gate;
6. run `azd env refresh` on the deploy runner;
7. run `azd deploy --no-prompt`.
For production deploys, generated templates also run
`agentops doctor --evidence-pack` after the eval gate and upload
`.agentops/release/latest/evidence.json` plus `evidence.md`. Warnings do not
change the exit-code contract; critical Doctor findings block because the
production templates run with `--severity-fail critical`.
Set `AZURE_ENV_NAME` per GitHub Environment if your azd env names differ
from `dev`, `qa`, and `production`. Set `AZURE_LOCATION` when the azd
template needs an explicit region.
#### Placeholder mode
When `azure.yaml` is missing or `--deploy-mode placeholder` is selected,
each `agentops-deploy-*.yml` ships with `Build (placeholder)` and
`Deploy (placeholder)` steps. Prefer creating an azd deployment first; if
that is not possible, replace the placeholders with project-specific
commands.
#### Foundry prompt agent
For the simplest Foundry prompt-agent workflow, keep the instructions in
source control and point `agentops.yaml` at them:
```yaml
version: 1
agent: "quickstart-agent:2"
dataset: .agentops/data/smoke.jsonl
execution: cloud
prompt_file: .agentops/prompts/agent-instructions.md
```
Then generate prompt-agent deploy workflows:
```bash
agentops workflow generate --kinds pr,dev,qa,prod --deploy-mode prompt-agent --force
```
Each deploy workflow does this:
1. stages a candidate Foundry prompt-agent version from `prompt_file`;
2. writes `.agentops/deployments/agentops.candidate.yaml` pointing at the
candidate `name:version`;
3. runs `agentops eval run` against that candidate version, using Foundry cloud
eval when supported or the local runner as the fallback;
4. runs `agentops doctor --evidence-pack` so the exact candidate has release evidence;
5. records `.agentops/deployments/foundry-agent.json` as a CI artifact only
after the gate passes.
This keeps the invariant clear: **the evaluated agent version is the deployed
agent version**. Foundry manages the candidate agent versions; AgentOps
records normalized AgentOps results, and always supplies the repo-side gate,
deployment record, and Cockpit visibility.
Legacy workflows that explicitly use the Microsoft Foundry eval Action/task can
still be regenerated by older AgentOps versions, but new prompt-agent gates use
AgentOps cloud eval so threshold failures produce normalized PR evidence.
#### Container Apps
```yaml
# Build
- name: Build image
run: |
az acr build \
--registry "${{ vars.ACR_NAME }}" \
--image "myapp:${{ github.sha }}" \
.
# Deploy
- name: Deploy to ACA
run: |
az containerapp update \
--name "${{ vars.ACA_APP_NAME }}" \
--resource-group "${{ vars.AZURE_RESOURCE_GROUP }}" \
--image "${{ vars.ACR_NAME }}.azurecr.io/myapp:${{ github.sha }}"
```
#### App Service
```yaml
# Build
- uses: actions/setup-python@v6
with: { python-version: "3.11" }
- run: pip install -r requirements.txt -t ./dist
- run: cp -r src ./dist/
# Deploy
- uses: azure/webapps-deploy@v3
with:
app-name: ${{ vars.WEBAPP_NAME }}
package: ./dist
```
#### Foundry hosted agent
```yaml
# Build is typically empty: hosted agents are configured, not packaged.
# Deploy: publish a new agent version with whatever your project uses
# to manage Foundry agents (project-specific tooling).
```
#### Zero-trust deployment with azd
If you ask a coding agent to generate a zero-trust deployment, have it
create or adapt `azure.yaml`, `infra/`, and azd-native hooks such as
`preprovision`, `postprovision`, `predeploy`, and `postdeploy`. Do not
wire ad-hoc hook scripts directly into AgentOps workflows. After the azd
path is valid locally, regenerate the workflows with
`--deploy-mode azd`.
#### Copied Azure AI accelerators and AI Landing Zone projects
For copied accelerators such as GPT-RAG, Live Voice Practice, or apps based on
the Azure AI Landing Zone pattern, use AgentOps to turn the deployment path into
actionable readiness: landing-zone preflight, azd/Bicep workflow stages, Doctor
checks, eval gates, and post-deploy evidence.
```bash
agentops workflow analyze --format markdown --out agentops-workflow-plan.md
```
Use the output as the plan for your coding agent:
1. AgentOps handles repo-side eval gates, Doctor readiness checks, artifacts, and
Cockpit visibility.
2. `azd` manages `provision`, `deploy`, and hooks for app/infra lifecycle when
`azure.yaml` is present or can be added.
3. Foundry manages hosted agents, evaluations, traces, and operations.
4. Project-specific steps such as indexing data, seeding search, building
containers, updating app config, or running private-network post-provision
work stay in the accelerator's azd hooks or existing deployment tooling.
When `scripts/Invoke-PreflightChecks.ps1` is present, generated azd deploy
workflows run it with `-Strict` before `azd provision`. Doctor also reports
`AI Landing Zone deployment readiness` in the Operational Excellence findings,
including whether the preflight script, `agentops.yaml`, azd deploy workflow,
network isolation, and private-runner path are ready.
If the analyzer reports network isolation, private endpoints, jumpbox/Bastion,
Azure Firewall, or ACR Tasks signals, plan where private data-plane work runs
before making deployment automatic. GitHub-hosted runners usually cannot reach
private endpoints; use a self-hosted runner in the VNet, a jumpbox handoff, or
an ACR Tasks agent pool depending on the accelerator.
### 5. Branch protection
In Settings → Branches, add a rule for **both `develop` and `main`**:
- ✅ Require a pull request before merging.
- ✅ Require status checks to pass: select
**`AgentOps PR / Eval (PR gate)`**.
- (Optional) Require linear history.
This makes the AgentOps eval a hard merge requirement.
## Gate result
The PR workflow uses the eval step as the hard merge gate. It still runs
Doctor and uploads `evidence.json` / `evidence.md`, but that PR-stage Doctor
evidence is advisory: it can say `Release readiness: blocked` without failing
the PR. Treat that as release-review guidance. Production deploy workflows still
run Doctor with a critical finding gate.
The GitHub run summary includes the same `evidence.md` content, including the
Doctor finding summary. When a release gate blocks, start there: the summary
lists the critical and warning finding IDs, categories, and titles before you
open the full artifact.
When `agentops-local` is selected, the eval step uses the AgentOps exit code
contract to gate deploys:
| Exit code | Meaning | Job result |
|---|---|---|
| `0` | Eval ran, all thresholds passed | ✅ pass |
| `2` | Eval ran, one or more thresholds failed | ❌ fail (deploy never runs) |
| `1` | Runtime / config error | ❌ fail |
For prompt-agent cloud eval, Foundry runs the managed evaluation and
AgentOps enforces the CI exit code. A threshold failure exits `2`, so the PR/deploy
gate fails with the failing threshold rows in `report.md`.
## Artifacts
Eval and deploy workflows upload (always - even on failure):
- `results.json` - machine-readable, versioned
- `report.md` - human-readable
- `cloud_evaluation.json` - present when using Foundry cloud evaluation;
contains a deep link to the New Foundry Experience Evaluations page
- `.agentops/official-eval/input.json`, `metadata.json`, and `result.json` -
present only for legacy official Action/task workflows
- `evidence.json` and `evidence.md` - present in PR, PROD, and optional Doctor
workflows after `agentops doctor --evidence-pack`
Artifact names per workflow:
| Workflow | Artifact name |
|---|---|
| `agentops-pr.yml` | `agentops-pr-results` plus release evidence in the same artifact |
| `agentops-deploy-dev.yml` | `agentops-dev-results` |
| `agentops-deploy-qa.yml` | `agentops-qa-results` |
| `agentops-deploy-prod.yml` | `agentops-prod-results` plus release evidence |
| `agentops-doctor.yml` | `agentops-doctor-history` plus release evidence |
## CLI reference
```bash
agentops eval analyze # inspect eval setup before first run
agentops eval promote-traces --source traces.jsonl --apply
agentops doctor --evidence-pack # write release evidence
agentops workflow analyze # inspect repo and recommend stages
agentops workflow analyze --format json # stable machine-readable analysis
agentops workflow generate --kinds pr # PR gate
agentops workflow generate # PR + DEV/QA/PROD; deploy mode defaults to auto
agentops workflow generate --kinds pr,dev,prod # subset (trunk-based)
agentops workflow generate --kinds doctor # optional scheduled Doctor workflow
agentops workflow generate --deploy-mode azd # delegate deploy to azd
agentops workflow generate --deploy-mode prompt-agent # Foundry prompt deployment
agentops workflow generate --doctor-gate warning # PR also blocks on warnings
agentops workflow generate --doctor-gate none # PR Doctor advisory (pre-1.x)
agentops workflow generate --platform azure-devops
agentops workflow generate --force # overwrite existing files
agentops workflow generate --dir # different repo root
```
| Flag | Description | Default |
|---|---|---|
| `--kinds` | Comma-separated subset of `pr,dev,qa,prod,doctor` | `pr,dev,qa,prod` |
| `--platform` | `github` or `azure-devops` | `github` |
| `--deploy-mode` | `auto`, `placeholder`, `azd`, or `prompt-agent` | `auto` |
| `--doctor-gate` | Severity floor for the PR Doctor step: `critical`, `warning`, or `none` | `critical` |
| `--force` | Overwrite existing workflow files | `false` |
| `--dir` | Repository root | `.` |
### PR Doctor gate (`--doctor-gate`)
The PR template runs `agentops doctor --evidence-pack` after the eval
step. The `--doctor-gate` flag controls how Doctor failures interact with
the PR merge check:
| `--doctor-gate` value | PR-template behavior |
|---|---|
| `critical` (default) | Doctor blocks the PR on **critical** findings. Notably this includes the `regression.` checks, which fire when an evaluator score drops by `>= 2 * threshold_drop` (default `0.20`, i.e. a 20 % drop) versus the rolling baseline. Catches drift like groundedness moving 5.0 → 4.0 even when the configured eval thresholds technically still pass. |
| `warning` | Doctor blocks on **warning or higher** findings. Use when you also want the smaller (≥10 %) regression drops to block. |
| `none` | Doctor still writes release evidence and uploads it as a PR artifact, but does not block the PR (pre-1.x behavior). The eval step remains the only hard gate. |
Deploy templates (`agentops-deploy-dev.yml`, `…-qa.yml`, `…-prod.yml`)
always run `agentops doctor --severity-fail critical`; the
`--doctor-gate` flag does not affect deploy templates. Existing workflows
keep their generated `--severity-fail` value until you re-generate with
`--force`.
## Customisation tips
- **Tighten thresholds for QA / PROD** - copy `agentops.yaml` to
`agentops-qa.yaml` / `agentops-prod.yaml` and tighten the
`thresholds:` block. Update the `inputs.config` default in the
matching workflow file.
- **Scheduled runs** - add a `schedule:` entry in `agentops-pr.yml` (or
a new file) to evaluate against `main` nightly.
- **Matrix per scenario** - if you have multiple AgentOps config files, extend
the eval job with `strategy.matrix.config:` and reference
`${{ matrix.config }}` in the eval step.
- **Regression baseline** - wire deploy templates to download the
previous run's `results.json` artifact and call
`agentops eval run --baseline `.
## Migration from the older 3-template layout
If your repository still has `agentops-eval.yml`, `agentops-eval-ci.yml`,
or `agentops-eval-cd.yml` from a prior version of AgentOps:
1. Delete the three old files.
2. Run `agentops workflow generate`.
3. Re-add Build / Deploy commands you had customised.
4. Update branch-protection status checks to point at the new
`AgentOps PR` job.