Skip to content
Merged
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
18 changes: 16 additions & 2 deletions scripts/generate-docs.js
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,20 @@ function rewriteSkillLinks(body, skillDir) {
});
}

// Rewrite cross-references to a skill's `SKILL.md` into docusaurus-friendly slug links.
// Source files link to skills via relative paths like `../skills/<name>/SKILL.md` (from
// agent sources) or `../<name>/SKILL.md` (from sibling skill sources). The generated
// docusaurus pages live at `docs/skills/<slug>.md`, so rewrite the target to the slug
// using the supplied base (`../skills/` from agent pages, `./` from skill pages).
function rewriteSkillRefLinks(body, targetBase) {
return body.replace(/(\[[^\]\n]+\])\(([^)\s]+\/SKILL\.md)\)/g, (_match, label, url) => {
if (/^https?:\/\//i.test(url)) return `${label}(${url})`;
const segments = url.replace(/\/SKILL\.md$/, '').split('/');
const skillName = segments[segments.length - 1];
return `${label}(${targetBase}${slugify(skillName)})`;
});
}

// ---------------------------------------------------------------------------
// Agent doc generation
// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -123,7 +137,7 @@ function generateAgentDocs() {
agents.push({ name, slug, description, userInvocable, file });

// Extract meaningful body (skip the frontmatter warning section, keep substance)
const bodyTrimmed = rewriteAgentLinks(body.trim());
const bodyTrimmed = rewriteSkillRefLinks(rewriteAgentLinks(body.trim()), '../skills/');

let content = `---
title: "${name}"
Expand Down Expand Up @@ -262,7 +276,7 @@ function generateSkillDocs() {

skills.push({ name, slug, description, userInvocable, phase, dir });

const bodyTrimmed = rewriteSkillLinks(body.trim(), dir);
const bodyTrimmed = rewriteSkillRefLinks(rewriteSkillLinks(body.trim(), dir), './');

let content = `---
title: "${toTitleCase(name)}"
Expand Down
26 changes: 13 additions & 13 deletions website/docs/agents/azure-resource-deployer.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ This agent is a thin orchestrator over the following skills. Do not duplicate th

| Stage | Skill | Why |
|-------|-------|-----|
| Pre-flight | [`/prereq-check`](../skills/prereq-check/SKILL.md) | Verify `az`, `jq`, `gh`, `git` are installed and `az login` is active |
| Pre-flight | [`/azure-deployment-preflight`](../skills/azure-deployment-preflight/SKILL.md) | What-if analysis, permission checks, change preview (CREATE/MODIFY/DELETE) |
| Deploy | [`/azure-stack-deploy`](../skills/azure-stack-deploy/SKILL.md) | The canonical `az stack sub create` runner — writes `state.json` (schemaVersion 1.0), classifies soft-deletable + purge-protected resources |
| Verify | [`/azure-integration-tester`](../skills/azure-integration-tester/SKILL.md) | Post-deployment health checks and endpoint tests |
| Rollback | [`/azure-stack-destroy`](../skills/azure-stack-destroy/SKILL.md) | `az stack sub delete --action-on-unmanage deleteAll` + soft-delete purge sweep |
| Pre-flight | [`/prereq-check`](../skills/prereq-check) | Verify `az`, `jq`, `gh`, `git` are installed and `az login` is active |
| Pre-flight | [`/azure-deployment-preflight`](../skills/azure-deployment-preflight) | What-if analysis, permission checks, change preview (CREATE/MODIFY/DELETE) |
| Deploy | [`/azure-stack-deploy`](../skills/azure-stack-deploy) | The canonical `az stack sub create` runner — writes `state.json` (schemaVersion 1.0), classifies soft-deletable + purge-protected resources |
| Verify | [`/azure-integration-tester`](../skills/azure-integration-tester) | Post-deployment health checks and endpoint tests |
| Rollback | [`/azure-stack-destroy`](../skills/azure-stack-destroy) | `az stack sub delete --action-on-unmanage deleteAll` + soft-delete purge sweep |

## Output Styling

Expand All @@ -64,7 +64,7 @@ Use the shared progress bar and status line patterns for polling updates and sum

Detect the auth context and configure accordingly. Never hardcode credentials.

> **Tool + session check:** Invoke [`/prereq-check`](../skills/prereq-check/SKILL.md) once at the very start of Stage 3 to confirm `az`, `jq`, and `gh` are installed at minimum versions AND that `az account show` returns an active subscription. The skill prints platform-specific install commands for anything missing.
> **Tool + session check:** Invoke [`/prereq-check`](../skills/prereq-check) once at the very start of Stage 3 to confirm `az`, `jq`, and `gh` are installed at minimum versions AND that `az account show` returns an active subscription. The skill prints platform-specific install commands for anything missing.

### Interactive (VS Code / local)
The user is already authenticated via `az login`. The `prereq-check` skill above verifies this. If you need the subscription details directly:
Expand Down Expand Up @@ -124,7 +124,7 @@ If invoked without user confirmation, **STOP** and report: "Deployment requires

### 1. Pre-Deployment Validation

**Delegate to:** [`/azure-deployment-preflight`](../skills/azure-deployment-preflight/SKILL.md)
**Delegate to:** [`/azure-deployment-preflight`](../skills/azure-deployment-preflight)

Do not run ad-hoc `az deployment sub validate` or `az stack sub validate` yourself — the preflight skill already owns this and produces a structured report (`preflight-report.md`) with what-if categorization, permission checks, and a CREATE/MODIFY/DELETE summary.

Expand All @@ -144,7 +144,7 @@ If the preflight report flags any blocking issue, **STOP** and surface the issue

**Always deploy as a subscription-scoped Deployment Stack.** Stacks track every managed resource (across resource groups and subscription scope) and make destroy idempotent — a single `az stack sub delete --action-on-unmanage deleteAll` removes everything the stack owns, regardless of resource scope.

> **Single source of truth:** the deploy command, fallback handling, state.json writer, soft-delete classification, and Key Vault purge-protection detection all live in the [`azure-stack-deploy`](../skills/azure-stack-deploy/SKILL.md) skill. Both bash and PowerShell implementations are provided.
> **Single source of truth:** the deploy command, fallback handling, state.json writer, soft-delete classification, and Key Vault purge-protection detection all live in the [`azure-stack-deploy`](../skills/azure-stack-deploy) skill. Both bash and PowerShell implementations are provided.

**Pre-flight: validate the stack before deploying**

Expand Down Expand Up @@ -237,7 +237,7 @@ az deployment operation sub list \

### 4. Verify Resource Creation

**Delegate to:** [`/azure-integration-tester`](../skills/azure-integration-tester/SKILL.md)
**Delegate to:** [`/azure-integration-tester`](../skills/azure-integration-tester)

The integration tester is the single source of truth for post-deployment verification. It reads `state.json` (written by `azure-stack-deploy` in Step 2) to know what to check, then runs health probes per resource type — Function App HTTP probe, Storage Account `az storage account show`, App Service health endpoint, Database connection check, etc.

Expand Down Expand Up @@ -281,7 +281,7 @@ Common outputs to capture:

### 6. Verify `state.json` was written

The [`azure-stack-deploy`](../skills/azure-stack-deploy/SKILL.md) skill writes `state.json` (schemaVersion 1.0) and updates `metadata.json` with `deployMethod` and `resourceGroups[]` as part of step 2. The agent's job here is to confirm the write succeeded and surface its contents for the user.
The [`azure-stack-deploy`](../skills/azure-stack-deploy) skill writes `state.json` (schemaVersion 1.0) and updates `metadata.json` with `deployMethod` and `resourceGroups[]` as part of step 2. The agent's job here is to confirm the write succeeded and surface its contents for the user.

```bash
DEPLOYMENT_ID="{deployment-id}"
Expand All @@ -295,7 +295,7 @@ jq '{schemaVersion, deploymentId, deployMethod, stackId, resourceGroups, managed

If `deployMethod == "stack"` and `stackId` is empty, the deploy fell back silently — re-run the skill with `--no-fallback` to surface why stacks were rejected.

The destroy skill ([`azure-stack-destroy`](../skills/azure-stack-destroy/SKILL.md)) consumes this file as its sole source of truth.
The destroy skill ([`azure-stack-destroy`](../skills/azure-stack-destroy)) consumes this file as its sole source of truth.

### 7. Report Deployment Results

Expand Down Expand Up @@ -330,7 +330,7 @@ Provide a comprehensive summary:
To destroy this deployment and delete all its resources:
> `@git-ape destroy deployment {deployment-id}`
>
> Locally this invokes the [`azure-stack-destroy`](../skills/azure-stack-destroy/SKILL.md) skill, which uses `az stack sub delete --action-on-unmanage deleteAll --bypass-stack-out-of-sync-error true` (single command, idempotent across resource groups and subscription scope) and purges any soft-deletable resources that are not purge-protected.
> Locally this invokes the [`azure-stack-destroy`](../skills/azure-stack-destroy) skill, which uses `az stack sub delete --action-on-unmanage deleteAll --bypass-stack-out-of-sync-error true` (single command, idempotent across resource groups and subscription scope) and purges any soft-deletable resources that are not purge-protected.
>
> Or via GitHub: create a PR that sets `metadata.json` status to `destroy-requested`, then merge after approval.

Expand Down Expand Up @@ -441,7 +441,7 @@ if [[ "$USER_CHOICE" == "A" ]]; then
fi
```

> **Important:** Never mix individual `az resource delete` calls when a `stackId` is present in `state.json`. The stack path is canonical — always invoke the [`azure-stack-destroy`](../skills/azure-stack-destroy/SKILL.md) skill, which encapsulates the stack delete, fallback RG delete, and soft-delete purge sweep (Key Vault, Cognitive Services, etc.) for any resources that are not purge-protected.
> **Important:** Never mix individual `az resource delete` calls when a `stackId` is present in `state.json`. The stack path is canonical — always invoke the [`azure-stack-destroy`](../skills/azure-stack-destroy) skill, which encapsulates the stack delete, fallback RG delete, and soft-delete purge sweep (Key Vault, Cognitive Services, etc.) for any resources that are not purge-protected.

**Step 4: Update deployment state:**
```json
Expand Down
32 changes: 16 additions & 16 deletions website/docs/agents/azure-template-generator.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,14 @@ This agent is a thin orchestrator over the following skills. Do not duplicate th

| Stage | Skill | Why |
|-------|-------|-----|
| Step 0 (lookup) | [`/azure-rest-api-reference`](../skills/azure-rest-api-reference/SKILL.md) | Get exact property schemas, required fields, valid enum values, latest stable API version per resource type. **Mandatory before writing any resource.** |
| Step 0 (lookup) | [`/azure-naming-research`](../skills/azure-naming-research/SKILL.md) | CAF abbreviation, length / charset constraints, uniqueness scope. **Mandatory before naming any resource.** |
| Step 1 (write) | [`/azure-role-selector`](../skills/azure-role-selector/SKILL.md) | Least-privilege RBAC role lookup — returns the GUIDs for `Storage Blob Data Owner`, `Storage Account Contributor`, etc. Do NOT hardcode GUIDs in the agent. |
| Step 2 (assess) | [`/azure-security-analyzer`](../skills/azure-security-analyzer/SKILL.md) | Per-resource security best practices assessment + the BLOCKING security gate |
| Step 2 (assess) | [`/azure-policy-advisor`](../skills/azure-policy-advisor/SKILL.md) | Azure Policy compliance check against CIS / NIST / org framework (advisory) |
| Step 2 (assess) | [`/azure-resource-availability`](../skills/azure-resource-availability/SKILL.md) | Validate SKU + API version availability in target region + subscription quota (BLOCKING) |
| Step 2 (assess) | [`/azure-deployment-preflight`](../skills/azure-deployment-preflight/SKILL.md) | What-if analysis showing what will Create / Modify / Delete |
| Step 2 (assess) | [`/azure-cost-estimator`](../skills/azure-cost-estimator/SKILL.md) | Real pricing from Azure Retail Prices API |
| Step 0 (lookup) | [`/azure-rest-api-reference`](../skills/azure-rest-api-reference) | Get exact property schemas, required fields, valid enum values, latest stable API version per resource type. **Mandatory before writing any resource.** |
| Step 0 (lookup) | [`/azure-naming-research`](../skills/azure-naming-research) | CAF abbreviation, length / charset constraints, uniqueness scope. **Mandatory before naming any resource.** |
| Step 1 (write) | [`/azure-role-selector`](../skills/azure-role-selector) | Least-privilege RBAC role lookup — returns the GUIDs for `Storage Blob Data Owner`, `Storage Account Contributor`, etc. Do NOT hardcode GUIDs in the agent. |
| Step 2 (assess) | [`/azure-security-analyzer`](../skills/azure-security-analyzer) | Per-resource security best practices assessment + the BLOCKING security gate |
| Step 2 (assess) | [`/azure-policy-advisor`](../skills/azure-policy-advisor) | Azure Policy compliance check against CIS / NIST / org framework (advisory) |
| Step 2 (assess) | [`/azure-resource-availability`](../skills/azure-resource-availability) | Validate SKU + API version availability in target region + subscription quota (BLOCKING) |
| Step 2 (assess) | [`/azure-deployment-preflight`](../skills/azure-deployment-preflight) | What-if analysis showing what will Create / Modify / Delete |
| Step 2 (assess) | [`/azure-cost-estimator`](../skills/azure-cost-estimator) | Real pricing from Azure Retail Prices API |

## Output Styling

Expand All @@ -68,15 +68,15 @@ see [git-ape.agent.md](git-ape).

**Two skill invocations are mandatory before you write a single resource block.** Skipping either step is the #1 cause of preventable deployment failures (wrong property names, expired API versions, invalid characters, length overruns).

**0a. Property and API version lookup** — Invoke [`/azure-rest-api-reference`](../skills/azure-rest-api-reference/SKILL.md) for every resource type in the deployment. The skill returns:
**0a. Property and API version lookup** — Invoke [`/azure-rest-api-reference`](../skills/azure-rest-api-reference) for every resource type in the deployment. The skill returns:
- Latest stable (non-preview) API version
- Required vs optional properties
- Valid enum values per property
- Common gotchas (e.g. `kind` discriminator on `Microsoft.Web/sites`)

Never rely on memorized schemas. Re-invoke whenever you change the API version of an existing resource.

**0b. Naming research** — Invoke [`/azure-naming-research`](../skills/azure-naming-research/SKILL.md) for every resource type. The skill returns:
**0b. Naming research** — Invoke [`/azure-naming-research`](../skills/azure-naming-research) for every resource type. The skill returns:
- CAF abbreviation (e.g. `func`, `st`, `kv`, `cae`)
- Length min / max
- Valid character set (alphanumeric, hyphens, lowercase-only, etc.)
Expand Down Expand Up @@ -245,7 +245,7 @@ Many Azure subscriptions enforce `allowSharedKeyAccess: false` via Azure Policy.

**Required RBAC Roles for Function App → Storage:**

Do NOT hardcode role definition GUIDs in this agent. Invoke [`/azure-role-selector`](../skills/azure-role-selector/SKILL.md) with the resource pair (e.g. "Function App needs blob + file share access on Storage Account") and use the GUIDs the skill returns. The skill encodes least-privilege — it will recommend `Storage Blob Data Owner` (`b7e6dc6d-f1e8-4753-8033-0f276bb0955b`) + `Storage Account Contributor` (`17d1049b-9a84-46fb-8f53-869881c3d3ab`) for this specific pair, or narrower roles (`Storage Blob Data Contributor`, `Storage File Data SMB Share Contributor`) when full ownership is not needed.
Do NOT hardcode role definition GUIDs in this agent. Invoke [`/azure-role-selector`](../skills/azure-role-selector) with the resource pair (e.g. "Function App needs blob + file share access on Storage Account") and use the GUIDs the skill returns. The skill encodes least-privilege — it will recommend `Storage Blob Data Owner` (`b7e6dc6d-f1e8-4753-8033-0f276bb0955b`) + `Storage Account Contributor` (`17d1049b-9a84-46fb-8f53-869881c3d3ab`) for this specific pair, or narrower roles (`Storage Blob Data Contributor`, `Storage File Data SMB Share Contributor`) when full ownership is not needed.

The GUIDs above appear in the example block only so you can verify the skill output matches — do not copy them into new templates without running the skill first.

Expand All @@ -270,17 +270,17 @@ The GUIDs above appear in the example block only so you can verify the skill out

#### General Best Practices

These are **write-time guardrails** — apply them while assembling resource blocks so the template starts in a known-good state. The full assessment runs in Step 3 via [`/azure-security-analyzer`](../skills/azure-security-analyzer/SKILL.md), which has the complete severity-tagged checklist per resource type. Do not duplicate that checklist here.
These are **write-time guardrails** — apply them while assembling resource blocks so the template starts in a known-good state. The full assessment runs in Step 3 via [`/azure-security-analyzer`](../skills/azure-security-analyzer), which has the complete severity-tagged checklist per resource type. Do not duplicate that checklist here.

For **ALL resources**:
- ✓ Use latest **stable** API versions — returned by [`/azure-rest-api-reference`](../skills/azure-rest-api-reference/SKILL.md) in Step 0a; never hardcode
- ✓ Use names returned by [`/azure-naming-research`](../skills/azure-naming-research/SKILL.md) in Step 0b
- ✓ Use latest **stable** API versions — returned by [`/azure-rest-api-reference`](../skills/azure-rest-api-reference) in Step 0a; never hardcode
- ✓ Use names returned by [`/azure-naming-research`](../skills/azure-naming-research) in Step 0b
- ✓ Enable diagnostic settings and logging
- ✓ Apply resource tags from workspace standards
- ✓ Use `dependsOn` for proper ordering
- ✓ Output resource IDs and endpoints
- ✓ **Use managed identity for all inter-resource access** (no keys/secrets)
- ✓ **Include RBAC role assignments** with GUIDs from [`/azure-role-selector`](../skills/azure-role-selector/SKILL.md), not from memory
- ✓ **Include RBAC role assignments** with GUIDs from [`/azure-role-selector`](../skills/azure-role-selector), not from memory

**Non-negotiable identity patterns** — these are write-time, not assessment-time, because once a template ships with shared keys / connection strings it is hard to retrofit:

Expand Down Expand Up @@ -728,7 +728,7 @@ After showing the preview, provide the complete ARM template:

## Deployment Commands

The canonical deploy and destroy paths live in the [`azure-stack-deploy`](../skills/azure-stack-deploy/SKILL.md) and [`azure-stack-destroy`](../skills/azure-stack-destroy/SKILL.md) skills. The commands below are reference recipes — prefer invoking the skills so local CLI / VS Code and CI pipelines stay in sync.
The canonical deploy and destroy paths live in the [`azure-stack-deploy`](../skills/azure-stack-deploy) and [`azure-stack-destroy`](../skills/azure-stack-destroy) skills. The commands below are reference recipes — prefer invoking the skills so local CLI / VS Code and CI pipelines stay in sync.

**Azure CLI (Subscription-scoped Deployment Stack — preferred):**
```bash
Expand Down
Loading