Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
8cf87a6
chore(scripts): Refresh AVM module index and Azure deprecations
jonathan-vella Oct 13, 2026
54f9239
chore(mcp): Bump @azure/mcp to 3.0.0
jonathan-vella Oct 13, 2026
7964acb
feat(agents): Use Azure MCP azureterraform for Terraform lookup
jonathan-vella Oct 13, 2026
17aa2d8
feat(scripts): Ship ALZ Corp default governance baseline
jonathan-vella Oct 13, 2026
5ab3300
docs(skills): Document assumed ALZ Corp default governance path
jonathan-vella Oct 13, 2026
4b2fe5b
docs(skills): Add trailing newline to baseline-check reference
jonathan-vella Oct 13, 2026
bdcff60
docs(skills): Note azqr 3.0.0 requirement for extension_azqr
jonathan-vella Oct 13, 2026
8cb79d3
Merge branch 'chore/bump-azure-mcp-3.0.0' into feat/terraform-avm-mcp…
jonathan-vella Oct 13, 2026
5564ee4
docs(skills): Record probed azureterraform response shapes
jonathan-vella Oct 13, 2026
1a1344c
feat(devcontainer): Install pinned azqr for Azure MCP extension_azqr
jonathan-vella Oct 13, 2026
75ea12f
docs(skills): Remove references to the nonexistent azd MCP tool
jonathan-vella Oct 13, 2026
9e2b2f8
refactor(skills): Remove AVM authoring requirements reference
jonathan-vella Oct 13, 2026
a46f251
docs(skills): Use 3.0.0 command names for Resource Health and App Ser…
jonathan-vella Oct 13, 2026
0808bb2
fix(scripts): Pick the real retirement date and test the deprecation …
jonathan-vella Oct 13, 2026
b4e0872
docs(skills): Document assumed ALZ Corp default governance path
jonathan-vella Oct 13, 2026
2fc6451
Merge pull request #759 from jonathan-vella/chore/bump-azure-mcp-3.0.0
jonathan-vella Oct 13, 2026
1d2b47b
Merge pull request #760 from jonathan-vella/feat/terraform-avm-mcp-lo…
jonathan-vella Oct 13, 2026
25d6424
Merge pull request #761 from jonathan-vella/chore/refresh-avm-depreca…
jonathan-vella Oct 13, 2026
d5ce899
Merge pull request #762 from jonathan-vella/feat/alz-corp-governance-…
jonathan-vella Oct 13, 2026
f8eaac1
fix(skills): Correct azd and azqr tool guidance from live Azure MCP 3…
jonathan-vella Oct 13, 2026
90d4912
fix(scripts): Make the SK-14 fixture parser tolerate CRLF working copies
jonathan-vella Oct 13, 2026
e2cbd98
fix(skills): Make CLI the default for azqr, az graph and installs
jonathan-vella Oct 13, 2026
3c5274f
Revert "fix(skills): Make CLI the default for azqr, az graph and inst…
jonathan-vella Oct 13, 2026
7740dfb
docs(skills): Correct azqr notes and CLI flags after re-probing defau…
jonathan-vella Oct 13, 2026
75a9cd4
feat(mcp): Validate Azure MCP tool references against a committed sna…
jonathan-vella Oct 13, 2026
f91208d
feat(scripts): add bounded Azure SLA lookup helper
jonathan-vella Oct 14, 2026
5fa17a9
docs(skills): Document Azure MCP tool-name prefixes and skill-by-path…
jonathan-vella Oct 14, 2026
6d94a19
fix(scripts): Accept the decision_log entries apex-recall actually wr…
jonathan-vella Oct 14, 2026
cbb0433
fix(instructions): Cover aliased rm/mv/cp and warn on interactive ali…
jonathan-vella Oct 15, 2026
b9be724
docs(agents): apply Step 2 restart lessons to Architect, Orchestrator…
jonathan-vella Oct 15, 2026
7912a4a
docs(skills): apply nordic-foods lessons to templates, gates and Bice…
jonathan-vella Oct 15, 2026
7dcc147
feat(scripts): add review-input, readiness and policy-status checks
jonathan-vella Oct 15, 2026
3e5344d
feat(mcp): cascade stale steps on reopen and gate Step 2 completion
jonathan-vella Oct 15, 2026
9e4f0e1
feat(scripts): show stale steps in handoff and add changelog with mig…
jonathan-vella Oct 15, 2026
691e8e1
feat(scripts): check phase order and private endpoint dependencies in…
jonathan-vella Oct 15, 2026
6ad95e1
fix(scripts): strip unterminated tags in the SLA docx parser
jonathan-vella Oct 15, 2026
f809248
feat(agents): add a new-project intake prompt for the Orchestrator
jonathan-vella Oct 15, 2026
2a72ba0
feat(agents): add an Eventdesk Orchestrator intake prompt
jonathan-vella Oct 15, 2026
70e5967
feat(instructions): align the security baseline with the ALZ Corp floor
jonathan-vella Oct 15, 2026
72e24af
feat(agents): price with Azure MCP pricing_get only, one decision per…
jonathan-vella Oct 15, 2026
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
6 changes: 5 additions & 1 deletion .devcontainer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,15 @@ are installed in the image layer. uv 0.12.23 and gitleaks 8.30.1 are pinned and
`amd64` and `arm64` using [the download manifest](download-checksums.json).
The existing tool updater does not update these pins; maintain their versions and checksums explicitly.

`post-create.sh` also installs azqr 4.2.0 to `~/.local/bin` with `install-azqr.sh`, verified against the same manifest.
Azure MCP 3.0.0 lists `extension_azqr` only while azqr 3.0.0 or later is on `PATH`. The install is optional: if it
fails, the compliance and cost skills fall back to running `azqr` directly.

### MCP Servers (auto-configured in `.vscode/mcp.json`)

| Server | Transport | Purpose |
| ----------------- | ----------------- | ------------------------------------------------ |
| Azure Resource Manager MCP | http | Retail pricing and Azure cost management |
| Azure Resource Manager MCP | http | Azure cost management (retail pricing uses Azure MCP) |
| GitHub MCP | http | Copilot-provided GitHub context |
| Azure MCP Server | stdio (`npx`) | RBAC-aware Azure context for agents |

Expand Down
4 changes: 2 additions & 2 deletions .devcontainer/configure-mcp.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ const defaults = {
"azure-resource-manager-mcp": {
type: "http",
url: "https://mcp.management.azure.com",
headers: { "x-mcp-toolset": "CostManagement, Pricing" },
headers: { "x-mcp-toolset": "CostManagement" },
},
"azure-mcp": {
type: "stdio",
command: "npx",
args: ["-y", "@azure/mcp@2.0.5", "server", "start"],
args: ["-y", "@azure/mcp@3.0.0", "server", "start"],
env: { NPM_CONFIG_ALLOW_REMOTE: "all" },
},
};
Expand Down
15 changes: 15 additions & 0 deletions .devcontainer/download-checksums.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,20 @@
"checksumUrl": "https://github.com/gitleaks/gitleaks/releases/download/v8.30.1/gitleaks_8.30.1_checksums.txt"
}
}
},
"azqr": {
"version": "4.2.0",
"artifacts": {
"amd64": {
"url": "https://github.com/Azure/azqr/releases/download/v.4.2.0/azqr-linux-amd64.zip",
"sha256": "1cf2482520e9724761084eb3587100bb68f33cd98e15c065a0ec94d807821ee3",
"checksumUrl": "https://github.com/Azure/azqr/releases/download/v.4.2.0/azqr-linux-amd64.zip.sha256"
},
"arm64": {
"url": "https://github.com/Azure/azqr/releases/download/v.4.2.0/azqr-linux-arm64.zip",
"sha256": "f7524d77a5b85ea34a4a2230b37404d9d0383824c5a01b1ae6b1c71c883e059d",
"checksumUrl": "https://github.com/Azure/azqr/releases/download/v.4.2.0/azqr-linux-arm64.zip.sha256"
}
}
}
}
47 changes: 47 additions & 0 deletions .devcontainer/install-azqr.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/env bash
# Install the pinned azqr release verified against download-checksums.json; requires jq and unzip.
# azqr is optional: Azure MCP lists extension_azqr only when azqr 3.0.0 or later is on PATH.
set -euo pipefail

SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
MANIFEST="${SCRIPT_DIR}/download-checksums.json"
INSTALL_DIR="${AZQR_INSTALL_DIR:-${HOME}/.local/bin}"
ARCHITECTURE="$(dpkg --print-architecture)"

case "$ARCHITECTURE" in
amd64 | arm64) ;;
*) echo "Unsupported architecture: ${ARCHITECTURE}; expected amd64 or arm64" >&2; exit 1 ;;
esac

version="$(jq -er '.azqr.version' "$MANIFEST")"
if command -v azqr >/dev/null 2>&1 && azqr --version 2>&1 | grep -qF "$version"; then
echo "azqr ${version} already installed"
exit 0
fi

url="$(jq -er --arg arch "$ARCHITECTURE" '.azqr.artifacts[$arch].url' "$MANIFEST")"
checksum="$(jq -er --arg arch "$ARCHITECTURE" '.azqr.artifacts[$arch].sha256' "$MANIFEST")"
if [[ ! "$url" =~ ^https://github\.com/Azure/azqr/ || ! "$checksum" =~ ^[0-9a-f]{64}$ ]]; then
echo "Invalid download manifest entry: azqr/${ARCHITECTURE}" >&2
exit 1
fi

WORK_DIR="$(mktemp -d)"
trap 'rm -rf -- "$WORK_DIR"' EXIT

archive="${WORK_DIR}/azqr.zip"
curl --fail --silent --show-error --location --retry 3 \
--proto '=https' --proto-redir '=https' --tlsv1.2 \
--output "$archive" "$url"
printf '%s %s\n' "$checksum" "$archive" | sha256sum --check --strict
unzip -q -o "$archive" -d "${WORK_DIR}/extract"

# The archive nests the binary under bin/linux_<arch>/.
binary="$(find "${WORK_DIR}/extract" -type f -name azqr | head -n 1)"
if [[ -z "$binary" ]]; then
echo "azqr binary not found in the downloaded archive" >&2
exit 1
fi
mkdir -p "$INSTALL_DIR"
install -m 0755 "$binary" "${INSTALL_DIR}/azqr"
echo "Installed azqr ${version} to ${INSTALL_DIR}/azqr"
3 changes: 3 additions & 0 deletions .devcontainer/post-create.sh
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ elif ! az bicep version --only-show-errors; then
az bicep version --only-show-errors
fi

printf "Installing pinned azqr for the Azure MCP extension_azqr tool...\n"
bash .devcontainer/install-azqr.sh || printf "azqr install skipped; compliance scans fall back to the azqr CLI.\n"

printf "Adding only missing MCP defaults...\n"
node .devcontainer/configure-mcp.mjs
node tools/scripts/validate-tool-versions.mjs
Expand Down
13 changes: 13 additions & 0 deletions .devcontainer/post-start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,17 @@ else
printf "not authenticated - run 'azd auth login'\n"
fi

# An interactive rm/mv/cp alias can hang an agent terminal waiting for a prompt it never gets.
# post-start.sh itself is non-interactive, so .bashrc's aliases must be probed via -i.
interactive_aliases=""
for name in rm mv cp; do
if bash -i -c "alias $name" 2>/dev/null | grep -qE -- '-[a-zA-Z]*i[a-zA-Z]*'; then
interactive_aliases="$interactive_aliases $name"
fi
done
if [ -n "$interactive_aliases" ]; then
printf " WARNING: interactive shell alias(es) found:%s\n" "$interactive_aliases"
printf " Agent terminals inherit these; drop the -i flag (see dotfiles shell/.bashrc).\n"
fi

printf " Container ready\n\n"
4 changes: 4 additions & 0 deletions .github/agents/01-orchestrator.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,10 @@ Do not require a session-state file before attempting recovery of existing work.
the applicable approval gate or exact handoff, then stop. Do not ask who should choose the next step.
5. For an in-progress step or review, preserve its sub-step checkpoint in the handoff context;
do not skip required review or approval evidence, and do not invoke the next agent directly.
6. **Reopening a completed step** (`start-step --force`) must leave later steps visibly stale. Confirm
`session.steps` marks every dependent step stale and `plan_status` is superseded; otherwise record
both with `apex-recall decide`. Regenerate `00-handoff.md` with `render-session-handoff` so Completed
Steps and carried findings survive; never hand-write a replacement. Report only verified state.

**Starting a new chat thread mid-workflow?**
The agent auto-detects progress via `apex-recall show <project> --json`. Just invoke the
Expand Down
8 changes: 6 additions & 2 deletions .github/agents/02-requirements.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,9 @@ Use `askQuestions` for:
- **`cost_monitoring_mode`** — surface this prompt **only when the
selected environments include `dev` or `sandbox` and exclude
`prod`/`staging`**. Options: `enforced` (recommended; full
budget+AG+anomaly), `minimal` (budget only, no AG, no anomaly), or
budget+AG+anomaly), `minimal` (budget only: no cost AG or anomaly alert; operational
alerts remain; budget notices reach only Owner-role holders, so say so when the named
recipient is not an Owner), or
`deferred` (no cost-monitoring resources). When `deferred` is
chosen, follow up with two required freeform prompts:
`cost_monitoring_exception.rationale` and
Expand Down Expand Up @@ -378,7 +380,9 @@ Use `askQuestions` for:
- Additional security measures beyond the baseline with `multiSelect: true`, only when relevant.
- Authentication method.
- Region, defaulting to `swedencentral` unless service availability requires an exception.

- Operations and ownership, batched in one call: how operators reach private services, who owns web
sign-in (platform or application team), the budget alert recipient and whether they hold Owner,
the SQL Entra admin principal, and tag values the target policy requires. Unanswered items block Step 1.
Apply GDPR and data residency guardrails when relevant:

- Flag global services such as Front Door, Entra External ID, Traffic Manager, and Azure DNS for
Expand Down
43 changes: 13 additions & 30 deletions .github/agents/03-architect.agent.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: 03-Architect
description: Expert Architect providing guidance using Azure Well-Architected Framework principles and Microsoft best practices. Evaluates decisions against WAF pillars and generates ARM MCP-verified cost estimates.
description: Expert Architect providing guidance using Azure Well-Architected Framework principles and Microsoft best practices. Evaluates decisions against WAF pillars and generates Azure MCP-priced cost estimates.
model: ["Claude Sonnet 5.5 (copilot)"]
reasoning-effort: high
user-invocable: true
Expand All @@ -10,7 +10,7 @@ tools: [vscode/askQuestions, execute, read, agent, edit, search, web, 'azure-mcp
handoffs:
- label: "▶ Refresh Cost Estimate"
agent: 03-Architect
prompt: "Re-query Azure Resource Manager MCP through cost-estimate-subagent to update current pricing and totals. Input: agent-output/{project}/02-architecture-assessment.md SKU list. Output: agent-output/{project}/03-des-cost-estimate.md."
prompt: "Re-query Azure MCP pricing through cost-estimate-subagent to update current pricing and totals. Input: agent-output/{project}/02-architecture-assessment.md SKU list. Output: agent-output/{project}/03-des-cost-estimate.md."
send: true
- label: "▶ Deep Dive WAF Pillar"
agent: 03-Architect
Expand Down Expand Up @@ -73,9 +73,9 @@ chart outputs; missing essential tools/models stop work rather than weakening ch

- Without asking: research, WAF scoring, delegated pricing, charts, writing and validating the
Step 2 outputs, and the required reviews.
- Needs the user: missing NFR, compliance or budget values; SKU confirmation before committed
pricing; non-standard SKU/tier choices or deviations from Well-Architected guidance; and the
final [Approval Gate](#approval-gate), which alone completes Step 2 and allows handoff.
- Needs the user: missing NFR, compliance or budget values; an over-budget owner decision (ask, never substitute);
SKU confirmation before committed pricing; non-standard SKU/tier choices or deviations from Well-Architected
guidance; and the final [Approval Gate](#approval-gate), which alone completes Step 2 and allows handoff.
- Never: advance to the next step without that gate, or hand off directly to the IaC Planner.

Deliver the requested Step 2 scope. Raise a better approach in one sentence instead of silently
Expand Down Expand Up @@ -180,7 +180,7 @@ in a single form:
| NFRs | SLA, RTO, RPO, performance targets |
| Compliance | Regulatory frameworks |
| Budget | Approximate monthly budget |
| Scale | Users, transactions, data volume |
| Scale | Users, transactions, data volume; operator access path, auth owner, alert recipient, SQL admin |

## Session State

Expand Down Expand Up @@ -240,8 +240,9 @@ the bulk is authored.
before pricing; record rejection reasons without requesting irrelevant rates. If one tier is forced,
document why and include it in the confirmed full estimate; do not invent alternatives to satisfy a count.
2. **Call `cost-estimate-subagent` in `candidate_sets[]` mode** to price
A-vs-B _before_ committing. This comparison-only mode does not require SKU
approval and cannot write back the manifest or count as approved pricing.
A-vs-B _before_ committing: one call per `decision_id` (own `02-cost-candidates-{decision_id}.json`, no stale `.tmp`),
with exact meter hints and usage per the [candidate-set contract](../skills/apex-azure-defaults/references/cost-estimate-parent-contract.md#candidate-set-calls).
Comparison-only: no SKU approval, no manifest writeback, not approved pricing.
Preserve user pins; a worker's cheapest candidate is advice, not an approved choice.
3. **Pick winners** for each decision; never change user-pinned entries
(`source: user-pin`) — they are locked.
Expand Down Expand Up @@ -410,6 +411,7 @@ in your WAF assessment recommendations (still produce the identical artifact str
for architecture and the separate cost estimate before presenting final approval.
14. **Approval gate** — follow [Approval Gate](#approval-gate) and resolve blocking findings
before completion and handoff. Budget or SKU approval alone does not complete Step 2.
First archive superseded or `FAILED` files to `_meta/` and delete `02-waf-research.tmp.md`.

## Cost Estimation

Expand Down Expand Up @@ -600,28 +602,9 @@ Do not narrate routine tool calls.

## Validation Checklist

- [ ] All 5 WAF pillars scored with rationale and confidence level
- [ ] Service Maturity Assessment table included
- [ ] Cost estimate uses worker-verified MCP data or the documented direct-API evidence fallback, with truthful sources
- [ ] **Every dollar figure** in 02 and 03 artifacts traces back to `cost-estimate-subagent` response — no hardcoded prices
- [ ] Line-item totals sum correctly to reported monthly total
- [ ] H2 headings match apex-azure-artifacts templates exactly
- [ ] Region selection justified (default: swedencentral)
- [ ] AVM modules recommended where available
- [ ] No deprecated services recommended (checked against apex-azure-defaults Deprecated Services table)
- [ ] Service retirement timelines verified for any multi-year RI commitments
- [ ] Storage redundancy tier compatible with data residency requirements (no GRS with single-region GDPR)
- [ ] Global/non-regional services (Front Door, Entra, Traffic Manager) flagged for EU Data Boundary compliance
- [ ] SKU zone-redundancy capabilities verified for all services claiming AZ support

### WAF scoring table format
Illustrative structure only; compute every score and confidence from project evidence, never from examples.

```markdown
| WAF Pillar | Score | Confidence | Key Factor |
| --- | --- | --- | --- |
| {pillar} | {evidence-based score}/10 | {confidence} | {verified factor} |
```
Before the Approval Gate, load
[`architect-validation-checklist.md`](../skills/apex-azure-defaults/references/architect-validation-checklist.md)
once and satisfy every item and its WAF scoring table format.

## Completion Handoff

Expand Down
2 changes: 1 addition & 1 deletion .github/agents/04-design.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ handoffs:
send: false
- label: "▶ Generate Cost Estimate"
agent: 03-Architect
prompt: "Generate a detailed cost estimate through cost-estimate-subagent and Azure Resource Manager MCP. Save it to agent-output/{project}/03-des-cost-estimate.md."
prompt: "Generate a detailed cost estimate through cost-estimate-subagent and Azure MCP pricing. Save it to agent-output/{project}/03-des-cost-estimate.md."
send: false
- label: "Step 3.5: Governance Discovery"
agent: 04g-Governance
Expand Down
3 changes: 2 additions & 1 deletion .github/agents/04g-governance.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ Reuse current content; recover missing/changed evidence after compaction or resu
2. Run `apex-recall show <project> --json` to verify project context exists (project name, complexity, decisions)
3. **Read the committed baseline subscription entry when present**. It is
comparison evidence, not live policy authority or a prerequisite for live discovery.
A missing baseline routes to live discovery; never fabricate an entry. Determine the target
A missing baseline routes to live discovery; never fabricate an entry. An `alz-corp-default`
baseline has no entry for the target subscription; follow Phase 0.45 instead. Determine the target
subscription ID from the architecture, load the entire
`.github/data/governance-policy-baseline.json.gz → subscriptions[<sub-id>]`
object into context for baseline selection/comparison. The subscription
Expand Down
6 changes: 3 additions & 3 deletions .github/agents/05-iac-planner.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,8 @@ and the saved checkpoint; read only the predecessor sections the current phase n
## IaC Track Detection

Run `apex-recall show <project> --json` and check `decisions.iac_tool`; ask the user when it is unset.
`"Bicep"` uses the Bicep AVM metadata tools and patterns. `"Terraform"` uses the public Terraform Registry API
and Terraform patterns; no Terraform MCP server is required.
`"Bicep"` uses Bicep AVM metadata tools and patterns. `"Terraform"` uses Azure MCP `azureterraform` lookup
with the public Terraform Registry API as fallback and the AVM module index for existence; plus Terraform patterns.

## Read Skills First

Expand Down Expand Up @@ -368,7 +368,7 @@ Build **one structured `askQuestions` panel** combining:

Single-shot panel: one `askQuestions` call with all questions. Omit any
question whose key already appears in `apex-recall show <project>`
decisions (resume support).
decisions (resume support). Show the architecture's value per question (see reference).

Persist each answer (MANDATORY) — one `apex-recall decide` call per key:

Expand Down
10 changes: 6 additions & 4 deletions .github/agents/06t-terraform-codegen.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -322,15 +322,17 @@ For EACH resource in `04-iac-contract.json#resources[]` (canonical
source; `04-implementation-plan.md` is the prose mirror):

1. Read the approved source and exact version from `04-iac-contract.json#modules.terraform[]`.
2. Query the public Terraform Registry API for that pinned module version;
inspect inputs, outputs, and linked source. No Terraform MCP server is required.
2. Retrieve the pinned module version's README with the Azure MCP `azureterraform` `avm get` command
(`--module-name`, `--module-version`); fall back to the public Terraform Registry API when the tool is
unavailable. Inspect inputs, outputs, and linked source.
3. Cross-check the approved pins and parameter types against the retrieved schema;
flag mismatches using the AVM Known Pitfalls in the Terraform patterns skill.
4. Preserve the approved exact `X.Y.Z` module version. Do not replace it with
a version range or select a newer release. An unavailable pin or required
version change returns to the Planner under the existing plan-lock contract.
5. For non-AVM resources, verify arguments against the pinned provider's official
Registry documentation and `terraform providers schema -json` after isolated
5. For non-AVM resources, verify arguments against the pinned provider's documentation (Azure MCP
`azureterraform` `azurerm get` or `azapi get`, else the official Registry docs) and
`terraform providers schema -json` after isolated
`terraform init -backend=false -input=false`. Do not infer missing schemas from memory.
6. Check region limitations
7. Save to `agent-output/{project}/04-preflight-check.md`
Expand Down
Loading
Loading