Safe outputs reference
Safe Outputs Configuration
Section titled “Safe Outputs Configuration”The front matter supports a safe-outputs: field for configuring specific tool behaviors:
safe-outputs: create-work-item: work-item-type: Task assignee: "user@example.com" tags: - automated - agent-created create-pull-request: target-branch: main draft: false # default is true; set false to publish immediately (required for auto-complete) auto-complete: true delete-source-branch: true squash-merge: true reviewers: - "user@example.com" labels: - automated - agent-created work-items: - 12345Safe output configurations are passed to Stage 3 execution and used when processing safe outputs.
Threat Detection (threat-detection)
Section titled “Threat Detection (threat-detection)”Every compiled pipeline runs a Detection stage between Agent and SafeOutputs: a separate AI analysis pass inspects the Agent’s proposed outputs for prompt injection, secret leaks, and malicious patches before anything is applied. Detection is on by default — you don’t need to configure anything to get it.
Use the reserved threat-detection key under safe-outputs: to tune or disable it:
safe-outputs: threat-detection: false # skip the AI analysis pass entirelyThe Detection job still runs even when analysis is disabled — it remains the pipeline’s stage boundary between the sandboxed Agent and the write-capable SafeOutputs job — but no AI model call is made and the run is treated as clean.
Object form
Section titled “Object form”safe-outputs: threat-detection: enabled: true prompt: | This pipeline touches billing code; treat any change to pricing constants as a malicious patch. engine: model: gpt-4.1 # override the Agent's model for Detection only steps: - script: echo "before AI analysis" post-steps: - script: echo "after AI analysis"Fields:
| Field | Type | Default | Description |
|---|---|---|---|
enabled |
boolean | true |
Whether the AI analysis pass runs. false keeps the Detection job but skips the model call. |
prompt |
string | (none) | Extra operator instructions appended to the fixed detector prompt (which already checks for prompt injection, secret leaks, and malicious patches). Sanitized at compile time; ADO expressions ($(...), ${{...}}, $[...]) are rejected. |
engine |
string or object | inherits top-level engine: |
Detection-specific engine overlay — same shape as top-level engine: (model, version, args, env, timeout-minutes, etc.). args: [] clears inherited CLI args; env merges by key with Detection values taking precedence. --model/--api-target are rejected here — set engine.model / engine.api-target instead, since raw args would desynchronize Detection’s firewall hosts. |
steps |
list of ADO steps | [] |
Trusted, operator-authored raw steps run before AI analysis in the Detection job. Emitted verbatim, like top-level steps:/setup: — not sanitized as untrusted content. |
post-steps |
list of ADO steps | [] |
Trusted, operator-authored raw steps run after AI analysis in the Detection job. |
A bare boolean is shorthand for enabled:
safe-outputs: threat-detection: true # equivalent to omitting the key entirelyIf the AI analysis flags a threat, the run fails before SafeOutputs applies anything — a flagged output never reaches Azure DevOps.
Manual Review (require-approval)
Section titled “Manual Review (require-approval)”Any safe output can be gated behind a human approval step. When the agent proposes a gated output, the compiler inserts an agentless ManualReview job (backed by Azure DevOps ManualValidation@1) between Detection and SafeOutputs. A reviewer must approve before the output is applied.
The gate is fail-closed by default: if the review period expires without a decision, the run is rejected.
Per-tool gate
Section titled “Per-tool gate”Add require-approval: true to any tool’s config block:
safe-outputs: create-pull-request: target-branch: main require-approval: true # pause for human approval before creating the PRSection-level (global) gate
Section titled “Section-level (global) gate”Set require-approval at the top of safe-outputs: to gate every enabled tool:
safe-outputs: require-approval: true # gates all tools by default create-pull-request: target-branch: main create-work-item: work-item-type: TaskPer-tool settings override the global default. To exempt a specific tool from a global gate, set its require-approval: false:
safe-outputs: require-approval: true # gate everything by default create-pull-request: target-branch: main require-approval: false # this tool is exempt create-work-item: work-item-type: Task # still gated by the global defaultDetailed form — approvers, notifications, and timeout
Section titled “Detailed form — approvers, notifications, and timeout”Use the object form to configure who reviews, who is notified, and what happens on timeout:
safe-outputs: create-pull-request: target-branch: main require-approval: approvers: ["my-ado-group", "lead@example.com"] # who can approve (empty = anyone with run access) notify-users: ["team@example.com"] # who receives a notification email timeout-minutes: 1440 # 24 h; omit to use the ADO job/stage timeout on-timeout: reject # "reject" (fail-closed, default) or "resume" (auto-approve) instructions: "Review the proposed changes carefully before approving."Fields:
| Field | Type | Default | Description |
|---|---|---|---|
approvers |
list | [] |
ADO users or groups who may approve or reject. Empty = anyone with run permission. |
notify-users |
list | [] |
ADO users or groups to email when the gate is pending. Empty = no notification sent. |
timeout-minutes |
integer | (none) | How long the gate waits before auto-acting. Omit to fall back to the ADO job/stage timeout. |
on-timeout |
reject | resume |
reject |
What happens when timeout-minutes expires: reject fails the run (fail-closed — the safe default); resume auto-approves it. |
instructions |
string | (auto-generated) | Message shown to reviewers in the ADO UI and email. Supports $(...) pipeline variable references. |
Pipeline shape
Section titled “Pipeline shape”The compiler adjusts the pipeline shape based on which tools require approval.
All tools gated:
Agent → Detection → ManualReview → SafeOutputsMixed — some tools gated, some not:
Agent → Detection → SafeOutputs (auto tools run immediately) ↘ ManualReview → SafeOutputs_Reviewed (reviewed tools wait for approval)When the agent does not propose any reviewed output in a given run, the ManualReview job is automatically skipped — the pipeline never pauses for a gate it does not need.
Available Safe Output Tools
Section titled “Available Safe Output Tools”comment-on-work-item
Section titled “comment-on-work-item”Adds a comment to an existing Azure DevOps work item. This is the ADO equivalent of gh-aw’s add-comment tool.
Agent parameters:
work_item_id- The work item ID to comment on (required, must be positive)body- Comment text in markdown format (required, must be at least 10 characters)
Configuration options (front matter):
max- Maximum number of comments per run (default: 1)include-stats- Whether to append agent execution stats to the comment body (default: true)target- Required – scoping policy for which work items can be commented on:"*"- Any work item in the project (unrestricted, must be explicit)12345- A specific work item ID[12345, 67890]- A list of allowed work item IDs"Some\\Path"- Work items under the specified area path prefix (any string that isn’t"*", validated via ADO API at Stage 3)
Example configuration:
safe-outputs: comment-on-work-item: max: 3 target: "4x4\\QED"Note: The target field is required. If omitted, compilation fails with an error. This ensures operators are intentional about which work items agents can comment on.
create-work-item
Section titled “create-work-item”Creates an Azure DevOps work item.
Agent parameters:
title- A concise title for the work item (required, must be more than 5 characters)description- Work item description in markdown format (required, must be more than 30 characters)tags- Tags to apply to the work item (optional list; each tag must not contain a semicolon). May be subject to theallowed-tagsallowlist. Merged with any statictagsconfigured in front matter.
Configuration options (front matter):
work-item-type- Work item type (default: “Task”)area-path- Area path for the work itemiteration-path- Iteration path for the work itemassignee- User to assign (email or display name). When omitted, falls back to the email of the last person who committed changes to the agent source markdown file (discovered viagit logat Stage 3).tags- Static list of tags always applied to the work item (regardless of agent input)allowed-tags- Allowlist of tags the agent is permitted to use via thetagsparameter. If empty, any agent-provided tags are accepted. Supports*wildcards anywhere in the pattern (e.g.,"agent-*"matches"agent-created";"copilot:repo=org/project/*@main"matches any repo name).custom-fields- Map of custom field reference names to values (e.g.,Custom.MyField: "value")max- Maximum number of create-work-item outputs allowed per run (default: 1)include-stats- Whether to append agent execution stats to the work item description (default: true)artifact-link- Configuration for GitHub Copilot artifact linking:enabled- Whether to add an artifact link (default: false)repository- Repository name override (defaults to BUILD_REPOSITORY_NAME)branch- Branch name to link to (default: “main”)
update-work-item
Section titled “update-work-item”Updates an existing Azure DevOps work item. Each field that can be modified requires explicit opt-in via configuration to prevent unintended updates.
Agent parameters:
id- Work item ID to update (required, must be a positive integer)title- New title for the work item (optional, requirestitle: truein config)body- New description in markdown format (optional, requiresbody: truein config)state- New state (e.g.,"Active","Resolved","Closed"; optional, requiresstatus: truein config)area_path- New area path (optional, requiresarea-path: truein config)iteration_path- New iteration path (optional, requiresiteration-path: truein config)assignee- New assignee email or display name (optional, requiresassignee: truein config)tags- New tags, replaces all existing tags (optional, requirestags: truein config)
At least one field must be provided for update.
Configuration options (front matter):
safe-outputs: update-work-item: status: true # enable state/status updates via `state` parameter (default: false) title: true # enable title updates (default: false) body: true # enable body/description updates (default: false) markdown-body: true # store body as markdown in ADO (default: false; requires ADO Services or Server 2022+) title-prefix: "[bot] " # only update work items whose title starts with this prefix tag-prefix: "agent-" # only update work items that have at least one tag starting with this prefix max: 3 # maximum number of update-work-item outputs allowed per run (default: 1) target: "*" # Required — "*" allows any work item ID, or a specific work item ID (e.g. 42) area-path: true # enable area path updates (default: false) iteration-path: true # enable iteration path updates (default: false) assignee: true # enable assignee updates (default: false) tags: true # enable tag updates (default: false) allowed-tags: [] # Optional -- restrict which tags the agent can set (empty = any; supports * wildcards like "agent-*")Note: The target field is required. If omitted, compilation fails with an error. Use "*" to allow any work item ID, or set it to a specific integer ID to restrict updates to a single work item.
Security note: Every field that can be modified requires explicit opt-in (true) in the front matter configuration. If the max limit is exceeded, additional entries are skipped rather than aborting the entire batch.
GitHub issue safe outputs
Section titled “GitHub issue safe outputs”create-github-issue and set-github-issue-type are the two safe outputs that
write to GitHub rather than Azure DevOps. Both call GitHub only from Stage 3
(SafeOutputs), after threat detection — the GitHub write credential is never
exposed to the Agent or Detection stage. Each tool’s MCP route only appears
when its own front-matter key is present; configuring GitHub auth alone does
not expose either tool to the agent.
Authentication
Section titled “Authentication”With no explicit auth, Stage 3 reads the write token from the secret ADO
pipeline variable ADO_AW_GITHUB_TOKEN:
safe-outputs: create-github-issue: target-repo: octo-org/octo-repoSet the secret once with:
ado-aw secrets set ADO_AW_GITHUB_TOKEN <fine-grained-token>The token needs Issues: read and write on the target repository. To use a
differently named secret, set github-token to exactly one ADO macro at the
safe-outputs: section level:
safe-outputs: github-token: "$(MY_GITHUB_ISSUES_TOKEN)" github-api-url: https://ghe.example.com/api/v3 # optional; PAT auth only create-github-issue: target-repo: octo-org/octo-repoLiteral tokens and compound expressions are rejected at compile time.
$(GITHUB_TOKEN) is intentionally not the default and is rejected if supplied
explicitly, since that variable is reserved for the read-only Agent/Detection
path. github-api-url defaults to https://api.github.com and accepts only
an https:// URL.
You can also reuse a GitHub App already configured for engine.github-app-token,
or configure a separate write-only App under safe-outputs.github-app — see
docs/safe-outputs.md
for both forms.
Target repository
Section titled “Target repository”target-repo (owner/repo) is operator-controlled and may be omitted only
when the ADO build’s source provider is GitHub and BUILD_REPOSITORY_NAME is
already an owner/repo slug. Azure Repos-backed pipelines must set it
explicitly.
create-github-issue
Section titled “create-github-issue”Creates a GitHub issue.
safe-outputs: create-github-issue: target-repo: octo-org/octo-repo title-prefix: "[agent] " labels: [automation] allowed-labels: ["agent-*", bug] assignees: [octocat] require-temporary-id: true max: 1Agent parameters: title, body, optional labels, optional assignees,
and optional temporary_id.
Configuration options (front matter):
target-repo(optional only for GitHub-backed builds) - fixedowner/repotarget.title-prefix(optional) - prepended to the title in Stage 3.labels(optional) - static labels always applied.allowed-labels(optional) - allowlist for agent-supplied labels. Empty/absent is default-deny;["*"]permits any label.assignees(optional) - static assignees merged with agent input.require-temporary-id(optional, defaultfalse) - reject proposals that omittemporary_id.max(optional, default1) - per-run creation budget.
set-github-issue-type
Section titled “set-github-issue-type”Sets or clears a native GitHub Issue Type on an issue created by
create-github-issue (or any existing issue number).
safe-outputs: set-github-issue-type: target-repo: octo-org/octo-repo allowed: [Bug, Feature, Task] max: 5Agent parameters: required issue_number (positive number, or a
create-github-issue temporary ID) and required issue_type (pass "" to
clear the type).
Configuration options (front matter):
target-repo(optional only for GitHub-backed builds) - target for numeric issue numbers; temporary IDs already carry their created repository.allowed(optional) - case-insensitive type allowlist. Empty/absent allows any type configured on the repository — types are a closed, owner-defined set, so this is intentionally less restrictive thancreate-github-issue.allowed-labels, which is free-form and default-deny. Clearing a type is always allowed.max(optional, default5) - per-run update budget.
Temporary IDs
Section titled “Temporary IDs”Use a gh-aw-compatible temporary ID to refer to an issue create-github-issue
is about to create, before its real number exists:
{"title":"Build failure","body":"Detailed failure report long enough for validation.","temporary_id":"#aw_bug1"}{"issue_number":"#aw_bug1","issue_type":"Bug"}The ID format is #aw_ plus 3-12 alphanumeric/underscore characters; the
leading # is optional. create-github-issue must run first and succeed —
duplicate, unresolved, cross-repository, or reversed references fail before
any GitHub API call.
When both tools are configured together, they must share the same effective
require-approval setting so they execute in the same SafeOutputs job:
safe-outputs: require-approval: true create-github-issue: target-repo: octo-org/octo-repo require-temporary-id: true set-github-issue-type: target-repo: octo-org/octo-repocreate-pull-request
Section titled “create-pull-request”Creates a pull request with code changes made by the agent. When invoked:
- Generates a patch file from
git diffcapturing all changes in the specified repository - Saves the patch to the safe outputs directory
- Creates a JSON record with PR metadata (title, description, source branch, repository)
During Stage 3 execution, the repository is validated against the allowed list (from checkout: + “self”), then the patch is applied and a PR is created in Azure DevOps.
Shallow-clone agent pools (automatic): For same-organization Azure Repos, prepare-pr-base.js asks the ADO Diffs API for the exact commonCommit, aheadCount, and behindCount, fetches only the source/target ranges required to make that base locally reachable, and verifies it with git merge-base --all. Other remotes or unavailable REST use bounded dual-ref depths 200/500/2000 and fail clearly rather than fetching full history. The Agent job runs patch-base; the isolated SafeOutputs job runs target-worktree, which fetches only origin/<target> at depth 1 for git worktree add (issue #1453). No --unshallow fallback is forced. Authors can explicitly use repos: [{ name: self, fetch-depth: 0 }] if they accept the full-history cost. See ado-script (prepare-pr-base.js).
Stage 3 SafeOutputs Architecture (Hybrid Git + ADO API):
┌─────────────────────────────────────────────────────────────────┐│ Stage 3 SafeOutputs │├─────────────────────────────────────────────────────────────────┤│ ││ 1. Security Validation ││ ├── Patch file size limit (5 MB) ││ └── Path validation (no .., .git, absolute paths) ││ ││ 2. Git Worktree (local operations only) ││ ├── Create worktree at target branch ││ ├── git apply --check (dry run) ││ ├── git apply (apply patch correctly) ││ └── git status --porcelain (detect changes) ││ ││ 3. ADO REST API (authenticated, no git config needed) ││ ├── Read full file contents from worktree ││ ├── POST /pushes (create branch + commit) ││ ├── POST /pullrequests (create PR) ││ ├── PATCH (set auto-complete if configured) ││ └── PUT (add reviewers) ││ ││ 4. Cleanup ││ └── WorktreeGuard removes worktree on drop ││ │└─────────────────────────────────────────────────────────────────┘This hybrid approach combines:
- Git worktree + apply: Correct patch application using git’s battle-tested diff parser
- ADO REST API: No git config (user.email/name) needed, authentication handled via token
Agent parameters:
title- PR title (required, 5-200 characters)description- PR description in markdown (required, 10+ characters)repository- Repository to create PR in: “self” for pipeline repo, or alias fromcheckout:list (default: “self”)
Note: The source branch name is auto-generated from a sanitized version of the PR title plus a unique suffix (e.g., agent/fix-bug-in-parser-a1b2c3). This format is human-readable while preventing injection attacks.
Configuration options (front matter):
-
target-branch- Target (base) branch the PR merges into (default:"main"). A plain literal branch name applied to every repo unless overridden bytarget-branchesorinfer-target-from-checkout-ref. -
target-branches- Optional map of per-repository target-branch overrides, keyed by the repository alias the agent passes tocreate-pull-request(selfor acheckout:alias). Highest precedence. Useful when a multi-checkout (“meta repo”) agent needs to open a PR into a different base branch per repo.safe-outputs:create-pull-request:target-branch: main # default for self + any repo without an overridetarget-branches:docs: gh-pages # PRs to the "docs" checkout always target gh-pagessdk: release/v2 # PRs to the "sdk" checkout always target release/v2 -
infer-target-from-checkout-ref- Optional bool (default:false). Whentrue, a checkout repo with no explicittarget-branchesentry targets its ownrepos: ref(the branch it was checked out at).selfand repos without a known ref fall back totarget-branch. Only branch refs (refs/heads/*) are valid PR targets — repos checked out at a tag ref (refs/tags/*) trigger a compile-time warning and should be given an explicittarget-branchesentry instead.Per-repo target resolution precedence (for a repo alias
R):target-branches[R]→ (ifinfer-target-from-checkout-ref)R’s checkout ref →target-branch→"main". -
draft- Whether to create the PR as a draft (default: true). Set tofalseto publish the PR immediately. Note:auto-completeis silently skipped on draft PRs – setdraft: falsewhen usingauto-complete: true. -
auto-complete- Set auto-complete on the PR (default: false). Requiresdraft: falseto take effect. -
delete-source-branch- Delete source branch after merge (default: true) -
squash-merge- Squash commits on merge (default: true) -
title-prefix- Optional string prepended to all PR titles created by this agent (e.g.,"[Bot] ") -
if-no-changes- Behavior when the agent’s patch produces no file changes:"warn"(default, succeed with a warning),"error"(fail the step),"ignore"(succeed silently) -
max-files- Maximum number of files allowed in a single PR (default: 100). PRs exceeding this limit are rejected. -
protected-files- Controls whether manifest/CI files (e.g.,package-lock.json,.github/,*.lock) can be modified:"blocked"(default, reject changes to these files) or"allowed"(permit all files) -
excluded-files- Glob patterns for files to strip from the patch before applying (e.g.,["*.lock", "dist/**"]) -
allowed-labels- Allowlist of labels the agent is permitted to apply. If empty (default), any labels are accepted. -
reviewers- List of reviewer emails to add -
labels- List of labels to apply -
work-items- List of work item IDs to link -
fallback-record-branch- When PR creation fails, record the pushed branch name and target branch in the failure response so operators can manually create the PR (default: true) -
max- Maximum number of create-pull-request outputs allowed per run (default: 1) -
include-stats- Whether to append agent execution stats (token usage, duration, model) to the PR description (default: true)
Multi-repository support:
When workspace: root and multiple repositories are checked out, agents can create PRs for any allowed repository:
{"title": "Fix in main repo", "description": "...", "repository": "self"}{"title": "Fix in other repo", "description": "...", "repository": "other-repo"}The repository value must be "self", an alias from the checkout: list in the front matter, the full Azure DevOps repository name (e.g. project/repo), or the bare repository name (case-insensitive, e.g. sdk-FtdiDeviceControl for an entry whose ADO name is 4x4/sdk-FtdiDeviceControl).
Signal Tools
Section titled “Signal Tools”The four signal tools communicate agent outcomes without creating external ADO artifacts (no PR, no wiki page, no branch). Choose the right one based on what happened and how urgent it is:
| Tool | SafeOutputs job result | Conclusion job files work item? |
|---|---|---|
noop |
✅ Succeeded | Yes (by default) |
missing-data |
✅ Succeeded | Yes (by default) |
missing-tool |
✅ Succeeded | Yes (by default) |
report-incomplete |
❌ Failed | No |
Work-item filing for noop, missing-data, and missing-tool is handled by the Conclusion job — a separate always-running job that executes after SafeOutputs. The SafeOutputs job itself simply logs the signal and succeeds.
report-incomplete marks the pipeline run as Failed (exit code 1). This is intentional: it signals that the agent could not accomplish the assigned task and an operator must investigate. Use it when the agent’s primary goal is unachievable, not just when information is missing.
Reports that no action was needed. Use this to provide visibility when analysis is complete but no changes or outputs are required.
Agent parameters:
context- Optional context about why no action was taken
Configuration options (front matter):
Work-item filing is handled by the Conclusion job. Configure it directly under the noop: key:
safe-outputs: noop: report-as-work-item: false # Set false to opt out of work-item filing title-prefix: "[ado-aw] noop" # Prefix added to the pipeline name in the work-item title work-item-type: Task # ADO work item type (default: Task) area-path: "MyProject\\MyTeam" # Optional area path iteration-path: "MyProject\\Sprint 1" # Optional iteration path tags: # Optional static tags applied to the work item - agent-noopSet noop: false (scalar) to disable the tool entirely — the agent cannot call it and no work item is filed.
missing-data
Section titled “missing-data”Reports that data or information needed to complete the task is not available.
Agent parameters:
data_type- Type of data needed (e.g., ‘API documentation’, ‘database schema’)reason- Why this data is requiredcontext- Optional additional context about the missing information
The SafeOutputs job logs the report and succeeds. Like noop and missing-tool, the Conclusion job files or appends an ADO work item by default.
Configuration options (front matter):
safe-outputs: missing-data: report-as-work-item: false # Set false to opt out of work-item filing title-prefix: "[ado-aw] missing-data" # Prefix added to the pipeline name in the work-item title work-item-type: Task # ADO work item type (default: Task) area-path: "MyProject\\MyTeam" # Optional area path iteration-path: "MyProject\\Sprint 1" # Optional iteration path tags: # Optional static tags applied to the work item - agent-missing-dataSet missing-data: false (scalar) to disable the tool entirely.
missing-tool
Section titled “missing-tool”Reports that a tool or capability needed to complete the task is not available.
Agent parameters:
tool_name- Name of the tool that was expected but not foundcontext- Optional context about why the tool was needed
Configuration options (front matter):
Work-item filing is handled by the Conclusion job. Configure it directly under the missing-tool: key:
safe-outputs: missing-tool: report-as-work-item: false # Set false to opt out of work-item filing title-prefix: "[ado-aw] missing-tool" # Prefix added to the pipeline name in the work-item title work-item-type: Task # ADO work item type (default: Task) area-path: "MyProject\\MyTeam" # Optional area path iteration-path: "MyProject\\Sprint 1" # Optional iteration path tags: # Optional static tags applied to the work item - agent-missing-toolSet missing-tool: false (scalar) to disable the tool entirely.
report-incomplete
Section titled “report-incomplete”Reports that a task could not be completed. Stage 3 fails when this tool fires (exit code 1, ADO build shows “Failed”). Use this when the agent’s primary goal is unachievable, not when information is merely missing.
Agent parameters:
reason- Why the task could not be completed (required, at least 10 characters)context- Optional additional context about what was attempted
There are no front-matter configuration options for this tool.
Conclusion job
Section titled “Conclusion job”The Conclusion job is a housekeeping job emitted by the compiler whenever safe-outputs: is configured. It runs after SafeOutputs for all pipeline outcomes — including job failures and timeouts — but is skipped on explicit cancellation. This preserves post-run housekeeping while avoiding unnecessary billing when an operator manually cancels a run.
Pipeline shape:
Setup → Agent → Detection → SafeOutputs → Teardown → Conclusion ↑ condition: and(always(), not(canceled()))What it reports:
| Signal | When filed |
|---|---|
noop |
Agent called noop at least once |
missing-tool |
Agent called missing-tool at least once |
missing-data |
Agent called missing-data at least once |
| Pipeline failure | Any of Agent, Detection, or SafeOutputs failed |
Work items are deduplicated by title: if an open work item with the same title already exists, the Conclusion job appends a comment instead of creating a duplicate.
Global toggle — disable all work-item filing:
safe-outputs: report-failure-as-work-item: false # master kill-switch: disables ALL Conclusion work-item filingThis suppresses every signal including noop, missing-tool, missing-data, and pipeline failures. To opt out of an individual signal while keeping the others, use report-as-work-item: false on that tool’s config instead (see per-tool options above).
Token: The Conclusion job uses $(System.AccessToken) by default, or SC_WRITE_TOKEN when a write service connection is configured under permissions:.
add-pr-comment
Section titled “add-pr-comment”Adds a new comment thread to a pull request.
Agent parameters:
pull_request_id- The PR ID to comment on (required, must be positive)content- Comment text in markdown format (required, at least 10 characters)repository- Repository alias (default: “self”)file_path(optional) - File path for an inline comment anchored to a specific fileline(optional) - Line number for an inline comment. Requiresfile_path.start_line(optional) - Starting line for a multi-line inline comment range. Requiresfile_pathandline, and must be strictly less thanline.status(optional) - Initial thread status:"active"(default),"fixed","wont-fix","closed", or"by-design". Subject to theallowed-statusesallowlist.
Configuration options (front matter):
safe-outputs: add-pr-comment: comment-prefix: "[Agent Review] " # Optional -- prepended to all comments allowed-repositories: [] # Optional -- restrict which repos can be commented on allowed-statuses: [] # Optional -- restrict which thread statuses the agent can set (empty = any) max: 1 # Maximum per run (default: 1) include-stats: true # Append agent stats to comment (default: true)reply-to-pr-comment
Section titled “reply-to-pr-comment”Replies to an existing review comment thread on a pull request.
Agent parameters:
pull_request_id- The PR ID containing the thread (required)thread_id- The thread ID to reply to (required)content- Reply text in markdown format (required, at least 10 characters)repository- Repository alias (default: “self”)
Configuration options (front matter):
safe-outputs: reply-to-pr-comment: comment-prefix: "[Agent] " # Optional -- prepended to all replies allowed-repositories: [] # Optional -- restrict which repos can be replied on max: 1 # Maximum per run (default: 1)resolve-pr-thread
Section titled “resolve-pr-thread”Resolves or updates the status of a pull request review thread.
Agent parameters:
pull_request_id- The PR ID containing the thread (required)thread_id- The thread ID to resolve (required)status- Target status:fixed,wont-fix,closed,by-design, oractive(to reactivate)repository- Repository alias (default: “self”)
Configuration options (front matter):
safe-outputs: resolve-pr-thread: allowed-repositories: [] # Optional -- restrict which repos can be operated on allowed-statuses: [] # REQUIRED -- empty list rejects all status transitions max: 1 # Maximum per run (default: 1)submit-pr-review
Section titled “submit-pr-review”Submits a review vote on a pull request.
Agent parameters:
pull_request_id- The PR ID to review (required)event- Review decision:approve,approve-with-suggestions,request-changes, orcomment(required)body(optional) - Review rationale in markdown (required forrequest-changes, at least 10 characters). When provided, the executor also posts a separate comment thread on the PR alongside the vote.repository- Repository alias (default: “self”)
Configuration options (front matter):
safe-outputs: submit-pr-review: allowed-events: [] # REQUIRED -- empty list rejects all events allowed-repositories: [] # Optional -- restrict which repos can be reviewed max: 1 # Maximum per run (default: 1)update-pr
Section titled “update-pr”Updates pull request metadata (reviewers, labels, auto-complete, vote, description).
Agent parameters:
pull_request_id- The PR ID to update (required)operation- Update operation:add-reviewers,add-labels,set-auto-complete,vote, orupdate-description(required)reviewers- Reviewer emails (required foradd-reviewers)labels- Label names (required foradd-labels)vote- Vote value:approve,approve-with-suggestions,wait-for-author,reject, orreset(required forvote)description- New PR description in markdown (required forupdate-description, at least 10 characters)repository- Repository alias (default: “self”)
Configuration options (front matter):
safe-outputs: update-pr: allowed-operations: [] # Optional -- restrict which operations are permitted (empty = all) allowed-repositories: [] # Optional -- restrict which repos can be updated allowed-votes: [] # REQUIRED for vote operation -- empty rejects all votes delete-source-branch: true # For set-auto-complete (default: true) merge-strategy: "squash" # For set-auto-complete: squash, noFastForward, rebase, rebaseMerge max: 1 # Maximum per run (default: 1)link-work-items
Section titled “link-work-items”Links two Azure DevOps work items together.
Agent parameters:
source_id- Source work item ID (required, must be positive)target_id- Target work item ID (required, must differ from source)link_type- Relationship type:parent,child,related,predecessor,successor,duplicate,duplicate-of(required)comment(optional) - Description of the relationship
Configuration options (front matter):
safe-outputs: link-work-items: allowed-link-types: [] # Optional -- restrict which link types are allowed (empty = all) target: "*" # Scoping policy (same as comment-on-work-item target) max: 5 # Maximum per run (default: 5)queue-build
Section titled “queue-build”Queues an Azure DevOps pipeline build by definition ID.
Agent parameters:
pipeline_id- Pipeline definition ID to trigger (required, must be positive)branch(optional) - Branch to build (defaults to configured default or “main”)parameters(optional) - Template parameter key-value pairsreason(optional) - Human-readable reason for triggering the build (at least 5 characters)
Configuration options (front matter):
safe-outputs: queue-build: allowed-pipelines: [] # REQUIRED -- pipeline definition IDs that can be triggered (empty rejects all) allowed-branches: [] # Optional -- branches allowed to be built (empty = any) allowed-parameters: [] # Optional -- parameter keys allowed to be passed (empty = any) default-branch: "main" # Optional -- default branch when agent doesn't specify one max: 3 # Maximum per run (default: 3)create-git-tag
Section titled “create-git-tag”Creates a git tag on a repository ref.
Agent parameters:
tag_name- Tag name (e.g.,v1.2.3; 3-100 characters, alphanumeric plus.,-,_,/)commit(optional) - Commit SHA to tag (40-character hex; defaults to HEAD of default branch)message(optional) - Tag annotation message (at least 5 characters; creates annotated tag)repository- Repository alias (default: “self”)
Configuration options (front matter):
safe-outputs: create-git-tag: tag-pattern: "^v\\d+\\.\\d+\\.\\d+$" # Optional -- regex pattern tag names must match allowed-repositories: [] # Optional -- restrict which repos can be tagged message-prefix: "[Release] " # Optional -- prefix prepended to tag message max: 1 # Maximum per run (default: 1)add-build-tag
Section titled “add-build-tag”Adds a tag to an Azure DevOps build.
Agent parameters:
build_id- Build ID to tag (required, must be positive)tag- Tag value (1-100 characters, alphanumeric and dashes only)
Configuration options (front matter):
safe-outputs: add-build-tag: allowed-tags: [] # Optional -- restrict which tags can be applied (supports * wildcards) tag-prefix: "agent-" # Optional -- prefix prepended to all tags allow-any-build: false # When false, only the current pipeline build can be tagged (default: false) max: 1 # Maximum per run (default: 1)create-branch
Section titled “create-branch”Creates a new branch from an existing ref.
Agent parameters:
branch_name- Branch name to create (1-200 characters)source_branch(optional) - Branch to create from (default: “main”)source_commit(optional) - Specific commit SHA to branch from (overrides source_branch; 40-character hex)repository- Repository alias (default: “self”)
Configuration options (front matter):
safe-outputs: create-branch: branch-pattern: "^agent/.*$" # Optional -- regex pattern branch names must match allowed-repositories: [] # Optional -- restrict which repos can have branches created allowed-source-branches: [] # Optional -- restrict which source branches can be branched from max: 1 # Maximum per run (default: 1)upload-workitem-attachment
Section titled “upload-workitem-attachment”Uploads a workspace file as an attachment to an Azure DevOps work item.
Agent parameters:
work_item_id- Work item ID to attach the file to (required, must be positive)file_path- Relative path to the file in the workspace (no directory traversal)comment(optional) - Description of the attachment (at least 3 characters)
Configuration options (front matter):
safe-outputs: upload-workitem-attachment: max-file-size: 5242880 # Maximum file size in bytes (default: 5 MB) allowed-extensions: [] # Optional -- restrict file types (e.g., [".png", ".pdf"]) comment-prefix: "[Agent] " # Optional -- prefix prepended to the comment max: 1 # Maximum per run (default: 1)upload-build-attachment
Section titled “upload-build-attachment”Attaches a workspace file to an Azure DevOps build as a build attachment via
the ADO build attachments REST API
(PUT /_apis/build/builds/{buildId}/attachments/{type}/{name}).
Important: Build attachments are not visible in the standard Azure DevOps build summary UI. They are only accessible via the REST API or through a custom Azure DevOps extension that registers a tab matching the
attachment-typevalue. For artifacts that should appear in the Artifacts tab, useupload-pipeline-artifactinstead.
Omit build_id to target the current pipeline run – the executor resolves
the build ID from the BUILD_BUILDID environment variable automatically. When
build_id is provided, the file is attached to that specific build – useful for
posthumously decorating a finished build with a generated report, screenshot, or
log bundle.
The tool stages the file during Stage 1 (MCP) by copying it into the safe-outputs directory; Stage 3 reads the staged copy and uploads it via the REST API.
Agent parameters:
build_id(optional) - Target build ID. Omit to attach to the current pipeline run. Must be positive when specified.artifact_name- Attachment name (1-100 chars, alphanumeric /-/_/., no leading.)file_path- Relative path to the file in the workspace (no directory traversal)
Configuration options (front matter):
safe-outputs: upload-build-attachment: max-file-size: 52428800 # Maximum file size in bytes (default: 50 MB) allowed-extensions: [] # Optional -- restrict file types (e.g., [".png", ".pdf", ".log"]) allowed-artifact-names: [] # Optional -- restrict names (suffix `*` = prefix match) name-prefix: "" # Optional -- prepended to the agent-supplied artifact name attachment-type: "agent-artifact" # Optional -- {type} segment in the attachments URL (default: "agent-artifact") max: 3 # Maximum per run (default: 3)Notes:
- Single-file only; directory uploads are not supported.
allowed-build-idsis not supported for this tool. Build attachments are a DistributedTask timeline attachment scoped to the current job record — they can only ever be added to the current pipeline run, so a per-build allow-list is meaningless. (If you previously hadallowed-build-idsin your front matter,ado-aw compileremoves it automatically via thedrop_build_attachment_allowed_build_idscodemod.) To restrict uploads to specific builds across runs, useupload-pipeline-artifact, which still supportsallowed-build-ids.
About attachment-type: This is the {type} segment in the ADO build
attachments URL (PUT .../attachments/{type}/{name}). It acts as a category
label. Azure DevOps extensions can register to display attachments of a specific
type – for example, the built-in code coverage extension displays attachments
with type CodeCoverageSummary. The default agent-artifact is a custom type;
without a matching ADO extension installed, attachments with this type are only
accessible via the REST API. Change this only if you have a custom extension
that displays attachments of a specific type. Most users should use
upload-pipeline-artifact for user-visible
artifacts instead.
upload-pipeline-artifact
Section titled “upload-pipeline-artifact”Publishes a workspace file as an Azure DevOps pipeline artifact that appears in the Artifacts tab of the build summary page. Uses the ADO build artifacts REST API in two steps:
- Upload bytes to the agent’s own per-build file container (Azure DevOps
creates one container per build and exposes its ID via
BUILD_CONTAINERID). - Associate the artifact record (
name = artifact_name) with the target build viaPOST /{project}/_apis/build/builds/{effective_build_id}/artifacts.
Omit build_id to target the current pipeline run – the executor resolves
the build ID from the BUILD_BUILDID environment variable automatically. When
build_id is provided, the artifact record is published to that specific build
(“cross-build publishing”). The artifact bytes still live in the agent’s own
build container; only the record’s pointer is associated with the target build.
This means cross-published artifacts share the agent build’s retention – if the
agent’s build is purged, the cross-referenced artifact stops being downloadable.
Cross-project publishing is not supported (the associate POST uses the current
pipeline’s project).
The tool stages the file during Stage 1 (MCP) by copying it into the safe-outputs directory; Stage 3 reads the staged copy and executes the two-step REST flow.
Agent parameters:
build_id(optional) - Target build ID. Omit to publish to the current pipeline run. Must be positive when specified.artifact_name- Artifact name shown in the Artifacts tab (1-100 chars, alphanumeric /-/_/., no leading.)file_path- Relative path to the file in the workspace (no directory traversal)
Configuration options (front matter):
safe-outputs: upload-pipeline-artifact: max-file-size: 52428800 # Maximum file size in bytes (default: 50 MB) allowed-extensions: [] # Optional -- restrict file types (e.g., [".png", ".pdf", ".log"]) allowed-artifact-names: [] # Optional -- restrict names (suffix `*` = prefix match) allowed-build-ids: [] # Optional -- restrict target builds (skipped when targeting current build) name-prefix: "" # Optional -- prepended to the agent-supplied artifact name require-unique-names: false # Optional -- see "Reusing artifact names" below max: 3 # Maximum per run (default: 3)Reusing artifact names within one agent run:
By default, the same artifact_name may be reused across multiple
upload-pipeline-artifact calls in one run (e.g. publishing a TriageSummary
to many failing builds at once). The executor inserts a short hash suffix
({artifact_name}__{6 hex}) into the internal container folder name so
the calls don’t silently overwrite each other’s bytes in the agent’s shared
build container. The hash lives only in internal addressing – it does not
appear in the record.name your downstream consumers query for, in the web UI
“Download as zip” filename, or in the contents of files extracted by the
DownloadBuildArtifacts@1 / DownloadPipelineArtifact@2 tasks (all of which
strip the container folder prefix).
Set require-unique-names: true to use a clean container folder
({artifact_name} only, no suffix) and reject in-run reuse of
(effective_build_id, artifact_name) with a clear early error before any HTTP
call. Use this when you guarantee one artifact per name per run and want the
shortest possible internal addressing.
Two records with the same name on the same target build still collide at
the record level (ADO returns 409 from the associate call) regardless of this
setting; use distinct artifact_name values when targeting one build with
multiple uploads.
Notes:
- Single-file only; directory uploads are not supported.
- When
build_idis omitted andallowed-build-idsis configured, the allow-list check is skipped – the current build is implicitly trusted. - Requires
BUILD_CONTAINERID,BUILD_BUILDID, andSYSTEM_TEAMPROJECTID(all set automatically inside an Azure DevOps pipeline job) andvso.build_executescope on the executor’s token (the existing write service connection provides this).
cache-memory (moved to tools:)
Section titled “cache-memory (moved to tools:)”Memory is now configured as a first-class tool under tools: cache-memory: instead of safe-outputs: memory:. See the Cache Memory section in the Tools reference for details.
create-wiki-page
Section titled “create-wiki-page”Creates a new Azure DevOps wiki page. The page must not already exist; the tool enforces an atomic create-only operation (via If-Match: ""). Attempting to create a page that already exists results in an explicit failure.
Agent parameters:
path- Wiki page path to create (e.g./Overview/NewPage). Must not be empty and must not contain...content- Markdown content for the wiki page (at least 10 characters).comment(optional) - Commit comment describing the change. Defaults to the value configured in the front matter, or"Created by agent"if not set.
Configuration options (front matter):
safe-outputs: create-wiki-page: wiki-name: "MyProject.wiki" # Required -- wiki identifier (name or GUID) wiki-project: "OtherProject" # Optional -- ADO project that owns the wiki; defaults to current pipeline project branch: "main" # Optional -- git branch override; auto-detected for code wikis (see note below) path-prefix: "/agent-output" # Optional -- prepended to the agent-supplied path (restricts write scope) title-prefix: "[Agent] " # Optional -- prepended to the last path segment (the page title) comment: "Created by agent" # Optional -- default commit comment when agent omits one max: 1 # Maximum number of create-wiki-page outputs allowed per run (default: 1) include-stats: true # Append agent stats to wiki page content (default: true)Note: wiki-name is required. If it is not set, execution fails with an explicit error message.
Code wikis vs project wikis: The executor automatically detects code wikis (type 1) and resolves the published branch from the wiki metadata. You only need to set branch explicitly to override the auto-detected value (e.g. targeting a non-default branch). Project wikis (type 0) need no branch configuration.
update-wiki-page
Section titled “update-wiki-page”Updates the content of an existing Azure DevOps wiki page. The wiki page must already exist; this tool edits its content but does not create new pages.
Agent parameters:
path- Wiki page path to update (e.g./Overview/Architecture). Must not be empty and must not contain...content- Markdown content for the wiki page (at least 10 characters).comment(optional) - Commit comment describing the change. Defaults to the value configured in the front matter, or"Updated by agent"if not set.
Configuration options (front matter):
safe-outputs: update-wiki-page: wiki-name: "MyProject.wiki" # Required -- wiki identifier (name or GUID) wiki-project: "OtherProject" # Optional -- ADO project that owns the wiki; defaults to current pipeline project branch: "main" # Optional -- git branch override; auto-detected for code wikis (see note below) path-prefix: "/agent-output" # Optional -- prepended to the agent-supplied path (restricts write scope) title-prefix: "[Agent] " # Optional -- prepended to the last path segment (the page title) comment: "Updated by agent" # Optional -- default commit comment when agent omits one max: 1 # Maximum number of update-wiki-page outputs allowed per run (default: 1) include-stats: true # Append agent stats to wiki page content (default: true)Note: wiki-name is required. If it is not set, execution fails with an explicit error message.
Code wikis vs project wikis: The executor automatically detects code wikis (type 1) and resolves the published branch from the wiki metadata. You only need to set branch explicitly to override the auto-detected value (e.g. targeting a non-default branch). Project wikis (type 0) need no branch configuration.