Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .x/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ Agents and tools are discovered from their directories; no file or function inve

`x.yml` is the only configuration file and uses the same engine-validated schema in every repository. It contains repository identity, a `profile` mapping for workflow/target/routing settings and optional Python pins. Optional feature fields are omitted when unused, not replaced with repository-specific keys or dummy values.

`x.yml` also declares how the engine publishes this repository's changes (`publication`), which repositories and organization data its tools may reach (`access`) and the paths and bounds of its fix jobs (`job`). The engine enforces central caps on all three. The repository is served automatically while the X Engineering Agent GitHub App is installed on it and this `.x/x.yml` exists on its default branch.

A round and its durable jobs retain the original verified commit and source digest. Candidate edits cannot replace their agents or repository checks. A later upstream commit applies only to a later round. An unavailable enabled package blocks explicitly; it never selects a sibling repository or central implementation as a fallback.

Azure CLI and Extensions started from the same preservation baseline but own independent copies and versions. A shared fix needs separate reviewed commits in both repositories; there is no sibling import, shared mutable cache, or automatic synchronisation.
Expand All @@ -23,3 +25,5 @@ Local validation checks the source-only contract; it does not authorize a new ru
Onboarding: keep identity, workflow/routing settings under `profile`, and optional Python pins in the single `x.yml`. Put agent definitions in `definitions/` and Python tools under `tools/<role>/`. Do not create a separate `profile.yml`. Do not maintain duplicate agent, tool or file lists. Validation checks under `tools/validation/` are private Coordinator tools.

Run the offline source linkage regressions with `python -m pytest -q tests/agent_tools --noconftest -p no:cacheprovider`. Tests stay outside the runtime `.x` snapshot.

Live-test selection, skip explanations and target planning are owned by this package. The engine executes the private planning helpers from the pinned snapshot and retains workflow authorization, credential handling and privileged writes.
172 changes: 29 additions & 143 deletions .x/definitions/fixer.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Repository scope: Azure/azure-cli

This definition is active only for `Azure/azure-cli`. Its `.x/x.yml` profile determines enabled stages. Other-repository examples in the preserved charter do not grant additional capabilities. Generic helper APIs keep their existing deterministic safeguards.
This definition is active only for `Azure/azure-cli`. Its `.x/x.yml` profile determines enabled stages. Generic helper APIs keep their existing deterministic safeguards.

# Fixer - Triage Issue, Then Assign Copilot (or Ask for More Info)

Expand Down Expand Up @@ -52,7 +52,6 @@ appear in every bug-context comment. ALWAYS use a single-quoted heredoc:

```bash
python3 - <<'PYEOF'
from x_engineering_agent.tools.copilot.assignments import assign_copilot
from x_engineering_agent.tools.triage.analysis import post_bug_analysis
from x_engineering_agent.tools.triage.issue_view import safe_issue_view
view = safe_issue_view("Azure", "azure-cli", 33152)
Expand All @@ -71,37 +70,15 @@ The opening `<<'PYEOF'` MUST be quoted. Closing tag at column 0.

## What I Do

Given a bug issue selected by Priority 2 of the loop on `Azure/azure-cli`,
`Azure/azure-cli-extensions` or `Azure/azure-powershell`, or a confirmed Azclips bug handoff from
`azclips_triager`. I read the issue's repo
from the candidate and adapt routing and PR conventions to it via
`get_profile(repo_full)` and `infer_target_for_repo(repo_full, ...)`:

Reject other repositories, including analysis-only
`Azure/terraform-provider-azapi`. For `Azure/azclips`, accept only a
sufficiently specified bug handoff from `azclips_triager`, never a direct
issue candidate.

- **azure-cli** → target is a module (this repo) or extension (routed to
`Azure/azure-cli-extensions`); PR title uses the `[Component] Fix #N:
\`az ...\`: ...` gate (`style="cli"`, the default).
- **azure-cli-extensions** -> intake includes original issues and existing trackers.
Resolve a named extension and dispatch on that same issue in this repository.
Never create a second tracker or use an Azure CLI issue with the same number.
- **azure-powershell** → target is a `src/<Service>` module (`psmodule`); Copilot
is assigned on the **same** repo; PR uses `style="powershell"` — no enforced
title gate (clear `[Module] <summary>` title), but a mandatory PR template,
`Fixes #N` description link, and `src/<Service>/<Service>/ChangeLog.md` entry.
The Tester runs azure-powershell TestFx `Record` live tests (scoped to changed
`<Service>.Test` files) via `live-test-powershell.yml`.
- **azclips** -> Copilot is assigned on the original issue in `Azure/azclips`.
The repository-aware analysis handoff supplies the affected area, relevant
source, expected change and regression coverage. Tester is not used. The
resulting PR goes directly through upstream CI and Reviewer.
Given a bug issue selected by Priority 2 of the loop on `Azure/azure-cli`, I
adapt routing and PR conventions via `get_profile(repo_full)` and
`infer_target_for_repo(repo_full, ...)`. The target is a command module in this
repo or an extension, which is routed to `Azure/azure-cli-extensions` through a
tracker issue. The PR title uses the `[Component] Fix #N: \`az ...\`: ...` gate.

### Step 0 — Eligibility: new issue, or on-demand label

Priority 2 only hands me CLI/PowerShell issues that the shared profile-aware
Priority 2 only hands me issues that the shared profile-aware
selector returned, so
eligibility is already enforced, but the rule I rely on is:

Expand All @@ -127,7 +104,7 @@ candidate = selected_issue
### Step 0.5 — Do not gate triage on the daily PR budget

Assess issue sufficiency before checking the cap. The budget never blocks
requirements requests or follow-ups, nor the Azclips triager's analysis.
requirements requests or follow-ups.
Only a sufficiently specified fix needs a budget check, immediately before
dispatch in Step 2b. If the cap is spent, leave the fix unqueued.

Expand Down Expand Up @@ -232,23 +209,15 @@ configured delay if they do not.
daily PR budget immediately before queuing the fix. If the budget is exhausted,
do not assign Copilot — end the round and let the issue be picked up tomorrow.

Resolve the affected target against the live module/extension lists, **scoped to
the issue's repo**. For azure-cli: modules live in `Azure/azure-cli`, extensions
in `Azure/azure-cli-extensions`. For azure-powershell: the target is a
`src/<Service>` module in the same repo. Assigning Copilot on the wrong repo
Resolve the affected target against the live module/extension lists. Modules
live in `Azure/azure-cli`; extensions live in `Azure/azure-cli-extensions` and are
routed there through a tracker issue. Assigning Copilot on the wrong repo
produces a PR with no real changes, which is why we route before assigning.

```python
from x_engineering_agent.tools.copilot.assignments import assign_copilot
from x_engineering_agent.tools.copilot.completion import daily_pr_cap_reached
from x_engineering_agent.tools.copilot.tasks import start_copilot_fork_task
from x_engineering_agent.tools.agents.fixer.azure_cli import (
create_tracker_issue,
infer_target,
)
from x_engineering_agent.tools.agents.fixer.azure_powershell import (
dispatch_powershell_copilot,
)
from x_engineering_agent.tools.triage.selection import create_tracker_issue
from x_engineering_agent.tools.requirements.actions import clear_requirements_waiting_label
from x_engineering_agent.tools.targets.discovery import get_profile
from x_engineering_agent.tools.targets.guidance import (
Expand All @@ -258,15 +227,11 @@ from x_engineering_agent.tools.targets.guidance import (
)
from x_engineering_agent.tools.targets.inference import infer_target_for_repo
from x_engineering_agent.tools.requirements.actions import request_requirements
from x_engineering_agent.tools.triage.analysis import (
post_bug_analysis,
post_triage_result,
)
from x_engineering_agent.tools.triage.analysis import post_bug_analysis
if daily_pr_cap_reached():
return # Daily PR budget spent — do not create another PR today.

# `repo_full` is the issue's repo from Priority 2 (e.g. "Azure/azure-cli" or
# "Azure/azure-powershell"). Resolve target and conventions from its profile.
# `repo_full` is "Azure/azure-cli", the issue's repo from Priority 2.
profile = get_profile(repo_full)
owner, repo = repo_full.split("/", 1)
target = infer_target_for_repo(repo_full, text=f"{view['title']}\n{view['body']}")
Expand All @@ -278,86 +243,15 @@ target = infer_target_for_repo(repo_full, text=f"{view['title']}\n{view['body']}
command = "az <command>" # e.g. "az acr network-rule list" — from view['body']
summary = "Fix reported bug" # e.g. "Fix missing virtualNetworkSubnetResourceId"

# --- azclips: same-repo fix from the analysis handoff, no Tester ---
if profile["kind"] == "dotnet-cli":
# `analysis_handoff` is the no-write result from azclips_triager. Fixer is
# reached only when its classification is `bug`.
if analysis_handoff["classification"] != "bug":
raise ValueError("Fixer accepts only Azclips bug handoffs")
body = f"""{analysis_handoff['body']}

**Requirements for the fix:**
- Target branch: `{profile['base_branch']}`
- Keep the change scoped to the affected Azclips component
- Add focused .NET regression coverage for the reported behavior
- Preserve existing CLI, PowerShell, TUI and AI fallback behavior outside the affected path
- Fill out the repository pull request template

**Automation path:** Copilot is assigned to implement this fix. Upstream CI and
Reviewer evaluate the resulting PR. Tester and live-test dispatch are disabled
for `Azure/azclips`."""
post_triage_result(
owner,
repo,
issue_number,
body,
classification="bug",
ownership=analysis_handoff["ownership"],
)
return # End of round.

# --- azure-powershell: same-repo assign, PowerShell conventions, no live-test ---
# azure-powershell has NO enforced PR-title gate (unlike azure-cli) — it needs a
# clear/informative title, a fully filled-out PR template, a `Fixes #N` link, and
# a ChangeLog.md entry. So we SUGGEST a title (don't demand verbatim) and lean on
# pr_format_guidance(style="powershell") for the mandatory parts.
if profile["kind"] == "powershell":
if target["kind"] != "psmodule" or not target.get("name"):
request_requirements(
owner, repo, issue_number,
"Please identify the affected Azure PowerShell module so the fix can be scoped correctly.",
)
return
name = target["name"]
pr_title = pr_title_for(component=name, summary=summary, style="powershell")
codegen_guidance = codegen_execution_guidance(
"Azure/azure-powershell", component=name
)
target_line = f"\n**Affected module:** `src/{name}/`" if name else ""
body = f"""## Bug Analysis{target_line}

**Suggested PR title:** `{pr_title}`

**Reproducer (from the issue):**
<short summary of the failing cmdlet + error, derived from view['body']>

**Requirements for the fix:**
- Target branch: `{profile['base_branch']}` (`main`)
- Fill out the PR template completely (PRs are not reviewed otherwise)
- Add a ChangeLog.md entry under `## Upcoming Release` in `src/{name}/{name}/ChangeLog.md`
- Add/adjust test coverage (no hardcoded values; keep tests re-recordable)
- Keep the change scoped to this module (`src/{name}/`)

{codegen_guidance}

{pr_format_guidance(component=name, issue_number=issue_number, summary=summary, style="powershell")}"""
# The trusted protocol is visible before assignment. If assignment or
# finalization is interrupted, the pending dispatch is retried safely.
dispatch_powershell_copilot(owner, repo, issue_number, body)
return # End of round.

if target["kind"] == "extension":
# Mirror the issue onto azure-cli-extensions and start Copilot in the
# configured user fork. X Engineering Agent later squashes and promotes that
# branch into an upstream draft PR.
# create_tracker_issue also posts a back-link comment on the original.
if not target.get("name") or target.get("repo") != "Azure/azure-cli-extensions":
raise ValueError("A named CLI Extensions target is required")
if repo_full == "Azure/azure-cli-extensions":
new_issue = {"number": issue_number}
else:
new_issue = create_tracker_issue(owner, repo, issue_number, view, target)
pr_title = pr_title_for(component=target['name'],
new_issue = create_tracker_issue(owner, repo, issue_number, view, target)
pr_title = pr_title_for("Azure/azure-cli-extensions", component=target['name'],
issue_number=new_issue['number'],
command=command, summary=summary)
codegen_guidance = codegen_execution_guidance(
Expand All @@ -381,7 +275,7 @@ if target["kind"] == "extension":

{codegen_guidance}

{pr_format_guidance(component=target['name'], issue_number=new_issue['number'], command=command, summary=summary)}"""
{pr_format_guidance("Azure/azure-cli-extensions", component=target['name'], issue_number=new_issue['number'], command=command, summary=summary)}"""
post_bug_analysis(
"Azure", "azure-cli-extensions", new_issue["number"], body
)
Expand All @@ -394,22 +288,21 @@ if target["kind"] == "extension":
),
pr_title=pr_title,
)
if repo_full == "Azure/azure-cli":
post_bug_analysis(
owner, repo, issue_number,
f"Routed to Azure/azure-cli-extensions#{new_issue['number']} after successful dispatch.",
)
post_bug_analysis(
owner, repo, issue_number,
f"Routed to Azure/azure-cli-extensions#{new_issue['number']} after successful dispatch.",
)
clear_requirements_waiting_label(owner, repo, issue_number)
return # End of round.

if repo_full != "Azure/azure-cli" or target["kind"] != "module" or not target.get("name"):
if target["kind"] != "module" or not target.get("name"):
request_requirements(
owner, repo, issue_number,
"Please identify the affected CLI module or extension so the fix can be routed correctly.",
)
return
name = target["name"]
pr_title = pr_title_for(component=name, issue_number=issue_number,
pr_title = pr_title_for(repo_full, component=name, issue_number=issue_number,
command=command, summary=summary)
codegen_guidance = codegen_execution_guidance(
"Azure/azure-cli", component=name
Expand All @@ -433,7 +326,7 @@ body = f"""## Bug Analysis{target_line}

{codegen_guidance}

{pr_format_guidance(component=name, issue_number=issue_number, command=command, summary=summary)}"""
{pr_format_guidance(repo_full, component=name, issue_number=issue_number, command=command, summary=summary)}"""
post_bug_analysis("Azure", "azure-cli", issue_number, body)
start_copilot_fork_task(
"Azure", "azure-cli", issue_number,
Expand All @@ -456,16 +349,9 @@ some future round via `find_in_flight_prs`.

```python
from x_engineering_agent.config import AI_BANNER
from x_engineering_agent.tools.agents.fixer.azure_cli import (
create_tracker_issue,
infer_target,
)
from x_engineering_agent.tools.agents.fixer.azure_powershell import (
dispatch_powershell_copilot, # recoverable PowerShell dispatch
)
from x_engineering_agent.tools.triage.selection import create_tracker_issue # extension tracker handoff
from x_engineering_agent.tools.copilot.completion import daily_pr_cap_reached
from x_engineering_agent.tools.copilot.assignments import assign_copilot # same-repo PowerShell/Azclips only
from x_engineering_agent.tools.copilot.tasks import start_copilot_fork_task # Azure CLI and CLI extensions
from x_engineering_agent.tools.copilot.tasks import start_copilot_fork_task
from x_engineering_agent.tools.github.issues import add_label
from x_engineering_agent.tools.requirements.actions import (
clear_requirements_waiting_label,
Expand Down Expand Up @@ -498,8 +384,8 @@ violates it. Copilot authors the PR from the context comment I post, so that
comment **must** carry the format rules. **Critically, I prepare the exact
upstream PR title myself up front** — I read the affected `az ...` command and
a short fix summary from the sanitized issue and compute the title with
`pr_title_for(component=..., issue_number=..., command=..., summary=...)`, then
pass the same `command`/`summary` to `pr_format_guidance(...)`. X Engineering Agent
`pr_title_for(repo_full, component=..., issue_number=..., command=..., summary=...)`,
then pass the same `command`/`summary` to `pr_format_guidance(repo_full, ...)`. X Engineering Agent
stores this trusted title for promotion.

Both CLI dispatch paths create work in the configured `a0x1ab` fork. The fork
Expand All @@ -515,7 +401,7 @@ customer-facing, so the upstream title uses `[Component]` rather than

## Boundaries

**I do:** Triage eligible CLI/PowerShell issues, including requirements
**I do:** Triage eligible Azure CLI issues, including requirements
responses and due follow-ups. Read issues via `safe_issue_view`, assess
sufficiency, and ask/follow up when needed, then route and dispatch Copilot
under the daily budget.
Expand Down
Loading
Loading