──────
Build and Push Docker Images / detect-changes (push) Successful in 11s
Build and Push Docker Images / build-auth-api (push) Successful in 1m0s
Build and Push Docker Images / build-employee-api (push) Successful in 1m2s
Build and Push Docker Images / build-transit-api (push) Successful in 1m1s
Build and Push Docker Images / build-error-log-api (push) Successful in 1m5s
Build and Push Docker Images / build-admin-ui (push) Successful in 1m13s
Build and Push Docker Images / build-monitoring-ui (push) Successful in 1m15s
Build and Push Docker Images / deploy-test-node (push) Successful in 3s

### Summary of Changes
  1. Documentation Consolidation:
      • Relocated the docs/ folder and all repository .md files (README.md, DEPLOYMENT.md, DOCKER_README.md,
      DOMAINS_README.md, GETTING_STARTED.md, CI_CD_PORTAINER_GUIDE.md, ADMIN_DEPLOYMENT_SUMMARY.md,
      SECURITY_PRIVATE_FILES.md, handoff.md, azure-project-plan.md, plus service-specific READMEs) into .
      • Updated document links in README.md.
  2. AI Agent Project Map:
      • Created PROJECT_MAP.md in the project root containing complete architecture diagrams, service specs, ports, DB
      schemas, environment variables, and developer workflows.
      • Added PROJECT_MAP.md to .gitignore.
  3. Monitoring UI & Infrastructure Integration:
      • Added monitoring_ui service to docker-compose.yml (port 5175).
      • Configured Gitea workflow docker-build.yml for monitoring_ui builds.
      • Added CORS middleware headers in index.js.
      • Added nginx.conf copy step in Dockerfile.

  ──────
  ### Recommended Commit Message

    docs: consolidate project documentation into monitoring_ui and add agent project map

    - Move all markdown documentation files and docs/ folder into monitoring_ui/docs/
    - Update documentation hub index (monitoring_ui/docs/README.md) with relative paths
    - Generate comprehensive AI agent reference map (PROJECT_MAP.md) in repository root
    - Add PROJECT_MAP.md and monitoring_ui build output/env overrides to .gitignore
    - Integrate monitoring_ui service into docker-compose.yml and Gitea CI workflow
    - Configure CORS handling in employee_api for monitoring dashboard access
    ──────
  ### Alternative Short Commit Message

    refactor(docs): move docs to monitoring_ui and create AI agent PROJECT_MAP.md
This commit is contained in:
Sven laptop
2026-09-20 23:33:55 +02:00
parent f935bbeb8c
commit 635a130f0b
195 changed files with 28309 additions and 957 deletions
@@ -0,0 +1,4 @@
{
"name": "azure-debug-generate",
"version": "0.0.1"
}
@@ -0,0 +1,92 @@
<!-- azure-cor-disclaimer -->
> **Important:** This skill provides guidance and recommended instructions to assist the AI system. Outputs are not guaranteed to be complete, correct, secure, or applicable to every scenario. Results should be reviewed and validated by a human before being applied. The AI model may choose not to follow all instructions exactly, and additional verification may be required.
# Azure Debug Generate
> **AUTHORITATIVE GUIDANCE — MANDATORY COMPLIANCE**
>
> This document is the **official, canonical source** for generating VS Code debug
> configuration from an approved plan. You **MUST** follow these instructions
> exactly as written. When in doubt, defer to this document. Do not improvise,
> infer, or substitute steps.
---
## Global Rules (NO EXCEPTIONS)
1. **Plan is the source of truth** — Read `.azure/vscode-debug-plan.md` and generate exactly what it specifies. Only generate artifacts for rows where `Generate` is checked (`[x]`).
2. **Update plan progressively** — Mark steps complete as you go; update **Last Updated** timestamp on every status change
3. ❌ **Destructive actions require `ask_user`** — Always confirm before overwriting, deleting, or modifying existing files
4. **Preserve existing config** — Never silently overwrite project configuration files or `docker-compose.yml`. Merge or ask first.
5. **Scope — VS Code debug setup only** — These instructions are for generating local debug configurations in VS Code. Cloud architecture, IaC generation, provisioning, and deployment are handled by the **azure-deploy** agent through the complete **azure-app-onboard** pipeline.
6. **Warn on limited support** — When a project type, runtime, or emulator declared in the plan has no matching reference file, emit a `⚠️ LIMITED SUPPORT:` warning — [limited-support.md](references/limited-support.md).
---
## Autopilot mode
**Active when** the invoking chat query begins with `[AUTOPILOT MODE]`, **or** `.azure/vscode-debug-plan.md` contains `executionMode: auto` or equivalent. When active, run fully unattended:
- **Do NOT call `ask_user`.** This is the tail of an autopilot chain over a freshly generated project, so overwriting/merging the scaffolded config files is expected and safe — proceed without prompting (still preserve and merge existing configs rather than blindly overwriting).
- Validation (Phase 3) still runs in full — autopilot never skips validation or the `Implemented` status write. Setting status to `Implemented` is what signals the workflow is complete (the extension restores its auto-approve setting at that point).
---
## Phase 1: Pre-Flight
Verify the plan and environment before generating any files.
| # | Action | Reference |
|---|--------|-----------|
| 1 | **Verify plan** — Confirm `.azure/vscode-debug-plan.md` exists with status `Approved`. Set status to `Executing` and update **Last Updated**. | `.azure/vscode-debug-plan.md` |
| 2 | **Load references** — For each service in the plan's Services table (where Generate is checked), load the corresponding project-type and runtime reference files. If no reference file exists, emit a limited-support warning. | [limited-support.md](references/limited-support.md) |
| 3 | **Run pre-flight checks** — Stale data directories and port conflicts. | [preflight.md](references/preflight.md) |
---
## Phase 2: Generate
The plan drives implementation. Read each section of `.azure/vscode-debug-plan.md` and generate the corresponding artifacts. Use the reference files for implementation details — the plan specifies WHAT to generate, the references specify HOW.
Follow the generation steps in [generate.md](references/generate.md) in order.
---
## Phase 3: Validate
> ⚠️ **CRITICAL:** You MUST complete every validation step before proceeding. Do NOT mark the task as complete, do NOT set status to `Implemented`, and do NOT deliver a closing message until validation is finished and the checklist is updated with real results.
| # | Action | Reference |
|---|--------|-----------|
| 1 | **Validate each launch configuration** — Follow every step in validation.md for each non-compound config. | [validation.md](references/validation.md) |
| 2 | **Validate the compound configuration** — Faithfully run each compound's orchestration per validation.md § Step 9, never inferring the result from the individual configs. | [validation.md](references/validation.md) § Step 9 |
| 3 | **Tear down validation processes** — Stop **every** process and emulator validation spawned (`docker compose down`) and verify all app HTTP, debug, and emulator ports are free again, so a subsequent user F5 starts from a clean slate. | [validation.md](references/validation.md) § Final Teardown |
| 4 | **Update Debug Configuration Checklist** — Create or update the `## Debug Configuration Checklist` section in `.azure/vscode-debug-plan.md` with real ✅ or ❌ results for each configuration. | [validation.md](references/validation.md) § Plan Integration |
| 5 | **Set status** — Only after every checklist stub has been replaced with a real result, set plan status to `Implemented` and update **Last Updated**. | `.azure/vscode-debug-plan.md` |
> ⛔ **VALIDATION IS NOT OPTIONAL.** Do NOT set status to `Implemented` until every stub in the Debug Configuration Checklist has been replaced with a real ✅ or ❌ result. A checklist with any remaining stubs or missing entries means validation is incomplete — go back and finish it. This is the single most common failure mode.
---
## Outputs
| Artifact | Location |
|----------|----------|
| **Plan** (updated) | `.azure/vscode-debug-plan.md` |
| Docker Compose | `docker-compose.yml` |
| VS Code Debug Config | `.vscode/launch.json` — see [project-types/](references/project-types/) and [runtimes/](references/runtimes/) |
| VS Code Build Config | `.vscode/tasks.json` — see [project-types/](references/project-types/) and [runtimes/](references/runtimes/) |
| VS Code Extensions | `.vscode/extensions.json` — see [generate.md](references/generate.md) § assembly protocol |
| VS Code Settings | `.vscode/settings.json` — see [generate.md](references/generate.md) § assembly protocol |
| Connection Strings | `local.settings.json` or `.env` |
| Convenience Scripts | Runtime-specific script runner (see [runtimes/](references/runtimes/)) |
| API Test Collections | `api-test-collections/{service-id}/<test-name>/invoke.{sh,ps1}` |
---
## Post-Generation
After validation completes with status `Implemented`, **stop**. Do not present next steps or a closing message — the `azure-debug-generate` agent handles post-generation guidance and interactive next steps.
## Troubleshooting
For Edge or Chrome related startup issues, consult [chromium.md](references/project-types/frontend-spa/debug-adapters/chromium.md).
@@ -0,0 +1,224 @@
<!-- azure-cor-disclaimer -->
> **Important:** This skill provides guidance and recommended instructions to assist the AI system. Outputs are not guaranteed to be complete, correct, secure, or applicable to every scenario. Results should be reviewed and validated by a human before being applied. The AI model may choose not to follow all instructions exactly, and additional verification may be required.
# API Test Collection Patterns
> Reference for generating `api-test-collections/{service-id}/` scripts, where `{service-id}` is the canonical service ID derived from the plan's **Service Label** column (see [generate.md](generate.md) § Service ID Derivation). Only generate test collections for services whose **Generate** column is checked in the plan. Scripts should be language-agnostic commands that exercise the running app and test its integration with any live emulators.
---
## HTTP
**HTTP patterns** use `{baseUrl}` — the project type supplies the base URL (e.g., `http://localhost:7071/api` for Functions). All other patterns target the emulator directly and are reusable across project types.
### GET request
```sh
curl -i "{baseUrl}/{FunctionName}"
```
### POST with JSON body
```sh
curl -i -X POST "{baseUrl}/{FunctionName}" \
-H "Content-Type: application/json" \
-d @sample-data.json
```
> **`{baseUrl}` by project type:**
>
> | Project Type | Base URL |
> |-------------|---------|
> | Azure Functions | `http://localhost:7071/api` |
> | Container App | `http://localhost:{port}` (from Dockerfile `EXPOSE`) |
> | App Service | `http://localhost:{port}` (from framework dev server) |
---
## Storage (Azurite — Blob / Queue / Table)
> Requires Azurite running. Uses `--connection-string "UseDevelopmentStorage=true"` for all commands.
### Blob trigger — upload a file
```sh
az storage blob upload \
--connection-string "UseDevelopmentStorage=true" \
--container-name {container-name} \
--name "sample-file.json" \
--file sample-file.json \
--overwrite
```
### Queue trigger — send a message
```sh
az storage message put \
--connection-string "UseDevelopmentStorage=true" \
--queue-name {queue-name} \
--content '{"id": "test-001", "data": "sample"}'
```
### Table trigger — insert an entity
```sh
az storage entity insert \
--connection-string "UseDevelopmentStorage=true" \
--table-name {table-name} \
--entity PartitionKey=pk RowKey=rk001 Value=test
```
---
## Cosmos DB
> Requires Cosmos DB Emulator running on `https://localhost:8081`. TLS verification must be disabled for local calls.
### Insert a document
```sh
curl -k -X POST "https://localhost:8081/dbs/{database}/colls/{collection}/docs" \
-H "Authorization: type=master&ver=1.0&sig=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==" \
-H "Content-Type: application/json" \
-H "x-ms-documentdb-partitionkey: [\"test\"]" \
-H "x-ms-version: 2018-12-31" \
-d '{"id": "test-001", "partitionKey": "test", "data": "sample"}'
```
> `-k` disables TLS verification for the emulator's self-signed cert. Never use in production.
---
## Service Bus
> Requires Service Bus Emulator running. Uses curl against the Service Bus Emulator's HTTP endpoint.
### Send a message to a queue
```sh
curl -i -X POST "http://localhost:5672/messages" \
-H "Content-Type: application/json" \
-H "BrokerProperties: {\"Label\": \"test\"}" \
-d '{"id": "test-001", "data": "sample"}'
```
> The Service Bus Emulator's HTTP endpoint and port may vary. Check the emulator documentation and docker-compose configuration for the correct URL. For SDK-based testing, use the Azure Service Bus SDK with the emulator connection string from `emulators/` config.
### Send a message to a topic
```sh
curl -i -X POST "http://localhost:5672/messages" \
-H "Content-Type: application/json" \
-H "BrokerProperties: {\"Label\": \"test\"}" \
-d '{"id": "test-001", "data": "sample"}'
```
> Adjust the URL path for topic-specific endpoints per the emulator's API surface.
---
## Event Hubs
> Requires Event Hubs Emulator running.
### Send an event
```sh
curl -i -X POST "http://localhost:5672/messages" \
-H "Content-Type: application/json" \
-d '{"id": "test-001", "data": "sample"}'
```
> The Event Hubs Emulator's HTTP endpoint and port may vary. Check the emulator documentation and docker-compose configuration for the correct URL. For SDK-based testing, use the Azure Event Hubs SDK with the emulator connection string from `emulators/` config.
---
## Timer (Azure Functions only)
Timer triggers cannot be fired by an external event — the Functions host fires them on schedule. Use the Functions admin API to trigger them on demand:
```sh
curl -i -X POST "http://localhost:7071/admin/functions/{FunctionName}" \
-H "Content-Type: application/json" \
-d '{}'
```
> This calls the Functions admin endpoint which is only available locally. The `{}` body is required; the timer trigger ignores it.
---
## Generation Rules
When generating API test collections during Phase 2:
1. Resolve endpoints from the implemented route registrations, not only `.azure/project-plan.md`. The project plan intentionally omits derived authentication routes, so include implemented registration, login, and current-user endpoints when `API Login` is enabled.
2. Create one top-level subdirectory per service: `api-test-collections/{service-id}/`, where `{service-id}` is derived from the plan's **Service Label** column (see [generate.md](generate.md) § Service ID Derivation). Only generate for services whose **Generate** column is checked in the plan.
3. Within each service directory, generate one subdirectory per trigger/endpoint found during inventory.
4. Name the trigger directory after the trigger: `{trigger-type}-{function-or-endpoint-name}` (e.g., `http-GetOrder`, `blob-ProcessUpload`).
5. Create an `invoke` script (`.sh` on macOS/Linux, `.ps1` on Windows) with the appropriate pattern from this file, substituting discovered values (function name, container name, etc.).
6. Create a `sample-data.json` or `sample-message.json` next to the invoke script when the test requires a body.
7. On macOS/Linux, make the script executable (`chmod +x`).
> **Do not generate timer test scripts** unless the user explicitly requests it — they're rarely needed for local debugging.
---
## Plan Section Formatting Rules
When writing the **API Test Collections** section of the plan, the heading format may vary by trigger type. In all cases, the subfolder names under `api-test-collections/{service-id}/` (e.g., `http-register`, `http-createOrder`) should also be referenced in each section's markdown heading when they differ so users can easily see which routes map to each invokable script.
---
### HTTP triggers / web API endpoints
```
### {METHOD} {route} [{🔒}] `{folder-name}`
```
- **`{METHOD} {route}`** — HTTP verb and full route path (e.g., `GET /api/health`)
- **`🔒`** — Include this emoji when the endpoint requires authentication (any auth scheme: Bearer JWT, API key, etc.). Omit entirely for anonymous/public endpoints.
- **`` `{folder-name}` ``** — The exact folder name under `api-test-collections/{service-id}/` (e.g., `` `http-health` ``)
**Examples:**
```markdown
### GET /api/health `http-health`
### POST /api/auth/register `http-register`
### GET /api/auth/me 🔒 `http-getMe`
### POST /api/orders 🔒 `http-createOrder`
```
**Auth key** — add this once at the top of the API Test Collections section, just after the folder tree, when any 🔒 routes are present:
```markdown
> 🔒 = requires authentication (replace `<token>` with a JWT from the login endpoint before running)
```
---
### Non-HTTP triggers (blob, queue, Service Bus, Event Hubs, etc.)
```
### {TriggerType}: {function-or-resource-name} `{folder-name}`
```
- **`{TriggerType}`** — Human-readable trigger category: `Blob`, `Queue`, `Service Bus`, `Event Hubs`, `Table`, `Cosmos DB`, etc.
- **`{function-or-resource-name}`** — The function name or the specific resource being targeted (container name, queue name, topic name, etc.)
- **`` `{folder-name}` ``** — The exact folder name under `api-test-collections/{service-id}/` (e.g., `` `blob-ProcessUpload` ``)
**Examples:**
```markdown
### Blob: uploads container `blob-processUpload`
### Queue: order-requests `queue-sendOrder`
### Service Bus: invoices topic `servicebus-sendInvoice`
### Event Hubs: telemetry `eventhubs-sendTelemetry`
```
> The 🔒 indicator does not apply to non-HTTP triggers — they are invoked by pushing data into the resource directly, not via an authenticated HTTP call.
@@ -0,0 +1,68 @@
<!-- azure-cor-disclaimer -->
> **Important:** This skill provides guidance and recommended instructions to assist the AI system. Outputs are not guaranteed to be complete, correct, secure, or applicable to every scenario. Results should be reviewed and validated by a human before being applied. The AI model may choose not to follow all instructions exactly, and additional verification may be required.
# {Emulator Name}
> **Template** — Copy this file to `emulators/{name}.md` when adding a new emulator.
---
## Docker Image
<!-- Official image and recommended pinned tag. -->
```
{org}/{image}:{tag}
```
## docker-compose Service Block
<!-- Complete service YAML block, ready to paste. Includes ports, volumes, health check. -->
```yaml
services:
{service-name}:
image: {org}/{image}:{tag}
ports:
- "{host-port}:{container-port}"
volumes:
- ./.{service-name}:/data
restart: unless-stopped
```
## Connection String
<!-- Default local connection string for the app to use. -->
```
{connection-string}
```
## Required App Environment Variables
<!-- Variable names the app must set to point at this emulator. -->
| Variable | Value |
|----------|-------|
| `{VAR_NAME}` | `{value}` |
## Healthcheck (Database Emulators Only)
<!-- If this emulator is a database, include a healthcheck block in the docker-compose service above AND document it here. The migration service (see migrations.md) depends on `condition: service_healthy` to wait for the database before running migrations. Without a healthcheck, auto-migration will not work. -->
<!-- Delete this section if the emulator is not a database. -->
## Container Runtime Support
<!-- State whether this emulator has been certified for Docker, Podman, or both. -->
<!-- The compose service block is engine-agnostic, but some Microsoft emulator images make Docker-specific assumptions (privileged mode, architecture, licensing). -->
<!-- If this emulator is NOT yet certified for Podman, say so here so the generation phase emits a `⚠️ LIMITED SUPPORT` warning when the plan selects Podman. -->
| Docker | Podman |
|--------|--------|
| {✅ certified / 🔲 planned} | {✅ certified / 🔲 planned} |
## Notes
<!-- Platform caveats (arm64/x86), known issues, resource requirements. -->
<!-- Note any Podman-specific caveats here (SELinux `:Z` labels on Linux, rootless port ranges, Podman-machine bind-mount paths). -->
@@ -0,0 +1,50 @@
<!-- azure-cor-disclaimer -->
> **Important:** This skill provides guidance and recommended instructions to assist the AI system. Outputs are not guaranteed to be complete, correct, secure, or applicable to every scenario. Results should be reviewed and validated by a human before being applied. The AI model may choose not to follow all instructions exactly, and additional verification may be required.
# Azurite (Azure Blob / Queue / Table Storage)
## Docker Image
```
mcr.microsoft.com/azure-storage/azurite
```
## docker-compose Service Block
```yaml
services:
azurite:
image: mcr.microsoft.com/azure-storage/azurite
# Overriding the default command requires re-specifying --blobHost/--queueHost/--tableHost 0.0.0.0
# so Azurite listens on all interfaces (the image's default). Without them, Azurite falls back to
# 127.0.0.1 inside the container and becomes unreachable from the host via port mapping.
# --skipApiVersionCheck allows newer Azure SDK API versions to work with older Azurite releases.
command: azurite --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost 0.0.0.0 --skipApiVersionCheck
ports:
- "10000:10000"
- "10001:10001"
- "10002:10002"
volumes:
- ./.azurite:/data
restart: unless-stopped
```
## Connection String
```
UseDevelopmentStorage=true
```
## Required App Environment Variables
| Variable | Value |
|----------|-------|
| `AzureWebJobsStorage` (Functions) | `UseDevelopmentStorage=true` |
| `AZURE_STORAGE_CONNECTION_STRING` (SDK) | `UseDevelopmentStorage=true` |
## Notes
- Ports: 10000 (Blob), 10001 (Queue), 10002 (Table)
- **Consolidation:** If multiple storage bindings are detected (blob + queue + table), use a **single** Azurite service — not one per binding type.
- The Event Hubs Emulator requires Azurite for checkpointing. If both are needed, the `azurite` service is shared.
- **Container runtime:** Certified for both **Docker** and **Podman** — the service block above is unchanged for either engine. Under Podman on Windows/macOS the ports are published from the Podman machine to the host exactly as with Docker; no `:Z`/`:z` volume label is needed for the `./.azurite` bind mount.
@@ -0,0 +1,128 @@
<!-- azure-cor-disclaimer -->
> **Important:** This skill provides guidance and recommended instructions to assist the AI system. Outputs are not guaranteed to be complete, correct, secure, or applicable to every scenario. Results should be reviewed and validated by a human before being applied. The AI model may choose not to follow all instructions exactly, and additional verification may be required.
# PostgreSQL
> PostgreSQL has no Azure-provided emulator. Use the standard `postgres` Docker image for local development. If the project targets **Azure Cosmos DB for PostgreSQL**, note in the plan that no local emulator is available.
## Docker Image
```
postgres:16
```
## docker-compose Service Block
Declare the local credentials **once** in a workspace-root `.env`, then reference them everywhere
else. Compose interpolates `${...}` from `.env` (or the shell environment), so the same values feed
the database service and every application service.
`.env` is required — without it Compose interpolates `${POSTGRES_USER}` to an empty string and the
database silently fails to authenticate:
```
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DB=localdev
```
> ⛔ **`.gitignore` must list `.env` before you create it.** A credential that reaches a commit is
> compromised and has to be rotated — deleting it in a later commit leaves the value in history and
> in every existing clone and fork. Private repositories are no exception. If the project has no
> `.gitignore`, or has one that omits `.env`, fix that before writing the file.
> **Never inline a concrete `user:password@host` URL** in a generated file — build it from the
> variables above. Beyond hard-coding a credential, such literals are rewritten by secret-redaction
> filters, and a masked value starting with `*` is a fatal YAML parse error: YAML reads a leading
> `*` as an alias reference.
```yaml
services:
postgres:
image: postgres:16
ports:
- "5432:5432"
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
volumes:
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
interval: 5s
timeout: 5s
retries: 5
start_period: 30s
restart: unless-stopped
# Declare the named volume at the top level of the compose file (merge into an
# existing top-level `volumes:` key if the file already has one).
volumes:
postgres_data:
```
> ⛔ **Use a named volume for the Postgres data dir — not a `./.postgres` bind mount.** On its first
> start Postgres's `initdb` sets the data directory's permissions to `0700`, which requires `chown`/`chmod`
> on the mount. Against a **host bind mount on Windows/macOS** — especially **rootless Podman**, where the
> container user can't change ownership of a Windows-side path — that fails with
> `could not change permissions of directory "/var/lib/postgresql/data": Operation not permitted`, and the
> database never initializes. A **named volume** is managed inside the engine's VM (ext4), so `initdb`
> succeeds on Docker Desktop and Podman alike. This also sidesteps the bind-mount performance and
> permission quirks Postgres hits on Docker Desktop for Windows/macOS. (Azurite and most other emulators
> tolerate a workspace bind mount fine — this named-volume rule is specific to database emulators like
> Postgres that `chown` their data directory.)
## Connection String
The host depends on where the client runs:
| Client location | Host |
|---|---|
| Host machine (VS Code debug target, `npm` task) | `localhost` |
| Another docker-compose service | `postgres` (the service name) |
```
postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432/${POSTGRES_DB}
```
## Required App Environment Variables
Declare these in the workspace-root **`.env`**, alongside the `POSTGRES_*` values:
| Variable | Value |
|----------|-------|
| `DATABASE_URL` | `postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432/${POSTGRES_DB}` |
| `POSTGRES_CONNECTION_STRING` | `postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432/${POSTGRES_DB}` |
> Use whichever variable name the project's ORM or SDK expects. Both forms above are shown as reference.
> When the value is set on a docker-compose service, replace the `localhost` host with `postgres`.
> **`.env` must declare every key `.env.example` declares.** `.env.example` is documentation —
> nothing loads it, so a key that appears only there is undefined at run time.
> **A runtime settings file does not cover host-run tasks.** `local.settings.json` is read by the
> Azure Functions host and a compose `environment:` block by its own container; neither reaches a
> VS Code task that runs a tool directly on the host, such as `npm run db:migrate`. That client
> fails with "Unable to acquire a connection", which reads like an unready database but is a
> missing variable — it never opened a socket. Put the value in `.env` so both paths resolve it.
## Healthcheck
The healthcheck is included in the docker-compose service block above. It uses `pg_isready` to verify PostgreSQL is accepting connections. The migration service (see [migrations.md](../migrations.md)) depends on `condition: service_healthy` to wait for readiness before running migrations.
```yaml
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER}"]
interval: 5s
timeout: 5s
retries: 5
start_period: 30s
```
## Notes
- Port 5432 is the standard PostgreSQL port.
- Default credentials (`postgres`/`postgres`) are intentionally simple for local dev and are declared in the workspace-root `.env`. Never use in production.
- Data is persisted to the **named volume `postgres_data`** (managed by the container engine, not a workspace folder). Reset it with `docker compose down -v` / `podman compose down -v`, or `docker volume rm <project>_postgres_data`. Because it is not a workspace directory, it needs no `.vscode/settings.json` `files.exclude` entry and is not part of the workspace stale-**directory** preflight check.
- **Container runtime:** Certified for both **Docker** and **Podman** — the service block, healthcheck, and named `postgres_data` volume are unchanged for either engine. The named volume (not a bind mount) is what lets `initdb` run under rootless Podman on Windows/macOS. The `condition: service_healthy` gate that migrations depend on is honored by both `docker compose` and `podman compose`.
@@ -0,0 +1,292 @@
<!-- azure-cor-disclaimer -->
> **Important:** This skill provides guidance and recommended instructions to assist the AI system. Outputs are not guaranteed to be complete, correct, secure, or applicable to every scenario. Results should be reviewed and validated by a human before being applied. The AI model may choose not to follow all instructions exactly, and additional verification may be required.
# Artifact Generation
Cross-cutting rules, step sequence, and assembly protocols for generating local development configuration files from an approved plan.
---
## Reading the Plan
The plan's tables drive all generation:
| Plan Section | What It Drives |
|-------------|----------------|
| **Services** table | Which services get launch.json/tasks.json entries. |
| **Emulators** table | Which emulator compose services to generate. |
| **Orchestrator** table | The container runtime (Docker/Podman) and the **Compose Command** (`docker compose` / `podman compose`) to write into every emulator/migration task. |
| **Migrations** table | Which migration compose services to generate. |
| **API Test Collections** table | Which API test scripts to generate. |
| **Convenience Scripts** table | Which convenience scripts to generate. |
> **Container runtime is a plan value — never hard-code `docker compose`.** Read the **Compose Command** cell from the plan's Orchestrator table and use it verbatim for every generated Compose invocation (Start Emulators task, migration task, convenience scripts, validation, teardown). It is `docker compose` by default and `podman compose` when the plan selected Podman. The generated `docker-compose.yml` itself is **identical for either engine** — only the command that drives it changes. In the examples throughout these references, `docker compose` stands in for the plan's Compose Command; substitute `podman compose` when the plan says Podman.
### Targeted Resolution
The plan provides high-level intent. For implementation details, perform **targeted resolution scans** of the workspace:
- **Migration details** — Scan for migration directory path, existing migration scripts, connection env var names. See [migrations.md](migrations.md).
- **API endpoints** — Parse function definitions or route handlers to get specific endpoint names, methods, routes, auth levels.
- **Connection string keys** — Check `local.settings.json`, `.env`, or app config for existing key names.
- **Existing config** — Check for existing `.vscode/launch.json`, `.vscode/tasks.json`, `docker-compose.yml` to determine merge vs create.
- **Framework details** — For frontend SPAs, detect the specific framework (Vite, Next.js, Angular, CRA) and dev server port from config files.
- **TypeScript source maps** — For TypeScript services, verify `tsconfig.json` has `"sourceMap": true` in `compilerOptions`. Without it, breakpoints in `.ts` files appear as unverified. See `runtimes/node.md` § Debugger Properties.
---
## Generation Steps
For each service in the plan's Services table (where Generate is checked), generate the following artifacts in order. The plan specifies WHAT to generate; the reference files linked below specify HOW.
| # | Action | Reference |
|---|--------|-----------|
| 1 | **Generate docker-compose** — For each emulator in the plan's Emulators table, load the emulator reference and assemble the docker-compose service block. If migrations are checked, add healthcheck and migration service. | [emulators/](emulators/), [migrations.md](migrations.md) |
| 2 | **Generate VS Code debug config** — Assemble `launch.json` and `tasks.json` entries from the project-type and runtime references. For multi-service workspaces, generate compound configuration. | generate.md § Source Ownership, [project-types/](project-types/), [runtimes/](runtimes/), [multi-service.md](multi-service.md) |
| 3 | **Generate VS Code workspace config** — Assemble `.vscode/extensions.json` and `.vscode/settings.json` from project-type and runtime references. Add emulator data directory exclusions. | generate.md § VS Code Extension Recommendations, generate.md § VS Code Workspace Settings |
| 4 | **Configure connection strings** — Update `local.settings.json`, `.env`, or app config with emulator connection strings. Never overwrite existing values. | `project-types/{type}.md` § Connection Strings, `emulators/{name}.md` § Required App Environment Variables |
| 5 | **Generate convenience scripts** — For each checked script in the plan's Convenience Scripts table, add to the project's native script runner. | `runtimes/{rt}.md` § Convenience Scripts |
| 6 | **Generate migrations** — If the plan's Migrations table has checked rows, do targeted resolution for migration details, then generate the docker-compose migration service. | [migrations.md](migrations.md) |
| 7 | **Generate API test collections** — If the plan's API Test Collections table has checked rows, do targeted resolution for endpoints/triggers, then generate test scripts. | [api-test-collections.md](api-test-collections.md) |
> **Podman emulator certification.** When the plan's container runtime is **Podman**, each emulator's reference file declares its Podman status under `## Container Runtime Support`. Azurite and PostgreSQL are certified. For any emulator not marked Podman-certified, emit a `⚠️ LIMITED SUPPORT: Emulator "{name}" is not yet certified for Podman` warning (per [limited-support.md](limited-support.md)) and generate a best-effort compose service anyway — do **not** silently swap the runtime back to Docker.
---
## Dependency Availability
> ⚠️ **Do not assume CLI tools or packages are installed in the target project.**
Before writing any script or task command that invokes a CLI tool (e.g., `rimraf`, `concurrently`, `cross-env`):
1. **Check** — Verify the tool is already a project dependency.
2. **Add dependency** — Add it as a project dev dependency. This ensures it is version-locked and works consistently across all machines.
3. **Ask if uncertain** — Use `ask_user` if the tool is expensive, opinionated, or has multiple alternatives.
---
## Local Credentials
> ⚠️ **Never inline a literal credential into a task or a compose file.** Declare local credentials
> once in a workspace-root `.env` and reference them through Compose `${VAR}` interpolation
> everywhere else.
| Correct | Do **not** generate |
|---|---|
| Compose `${VAR}` interpolation from `.env` | A literal credential inlined into a task or compose file |
A concrete credential literal is rewritten by secret-redaction filters, and a masked value that
begins with `*` is a fatal YAML parse error — YAML reads a leading `*` as an alias reference, so the
whole compose file stops parsing.
Interpolation only resolves if the variable is actually defined: Compose reads `${...}` from `.env`
or the shell environment, never from a service's own `environment:` block. Whenever a generated
file references a variable — a compose service, a host task, or a connection string — `.env` must
declare every variable it needs, or the value silently becomes an empty string.
> ⛔ **`.gitignore` must list `.env` before you create it.** A credential that reaches a commit is
> compromised and has to be rotated — deleting it in a later commit leaves it in history, in every
> clone, and in every fork. Private repositories are no exception. If the project has no
> `.gitignore`, or has one that omits `.env`, fix that first.
See `emulators/{name}.md` § Required App Environment Variables for the per-emulator variable set.
---
## VS Code Debug & Task Configuration
Assemble `.vscode/launch.json` and `.vscode/tasks.json` by combining properties from the detected **project type** and **runtime** references. Use the source ownership table below to determine which file provides each property.
### Source Ownership
| Concern | Server-side project source | Browser SPA source |
|---------|---------------------------|-------------------|
| Debugger type (`node`, `coreclr`) | `runtimes/{rt}.md` § Debugger Properties | `project-types/frontend-spa/debug-adapters/{adapter}.md` |
| Debug port | `runtimes/{rt}.md` § Debugger Properties | N/A (uses dev server URL) |
| Request mode (`attach` / `launch`) | `project-types/{type}.md` § Runtime Wiring | `project-types/frontend-spa/frontend-spa.md` § Runtime Wiring |
| Top-level startup task (type, command, problem matcher) | `project-types/{type}.md` § VS Code Task Configuration | `project-types/frontend-spa/frontend-spa.md` § VS Code Task Configuration |
| Build chain tasks (install, clean, watch) | `runtimes/{rt}.md` § Build Chain | N/A (dev server handles compilation) |
| Runtime-specific launch properties (`outFiles`, `processName`) | `runtimes/{rt}.md` § Debugger Properties | N/A |
| Compound configuration | [multi-service.md](multi-service.md) § Compound Debug Configuration | [multi-service.md](multi-service.md) § Compound Debug Configuration |
| Working directory (`cwd`) rules | generate.md § Working Directory (`cwd`) Rules | generate.md § Working Directory (`cwd`) Rules |
| Task `runOptions` rules | generate.md § Task `runOptions` Rules | generate.md § Task `runOptions` Rules |
| Emulator startup task (`Start Emulators`) | `runtimes/{rt}.md` § Build Chain | N/A (backend service owns emulators) |
> `project-types/{type}.md` § VS Code Task Configuration provides **concrete task JSON per runtime** — use those blocks directly. `runtimes/{rt}.md` § Build Chain provides the dependency tasks that the startup task's `dependsOn` references.
### Service ID Derivation
Derive a canonical service ID from the plan's **Service Label** column: lowercase, kebab-case (e.g., "Functions API" → `functions-api`, "Web App" → `web-app`). This ID is used for:
- Task labels (e.g., `functions-api: func host start`)
- Launch config naming (use the plan's **Launch Config Name** column directly)
- Compound config member references
If two services resolve to the same ID, append the project type: `payments-api-functions`.
> ⛔ Every generated task label should conform to `{service-id}: {task name}` (e.g., `functions-api: func host start`, `functions-api: dotnet build`). Wherever a task label is referenced — generation blocks, `dependsOn` chains, `preLaunchTask` values, validation Ready-Signal tables, and validation checklists — it **MUST** use this `{service-id}:` form. Instruction files and any examples that show a label without the `{service-id}:` prefix added are illustrating the latter part of the label; resolve it to the full form before writing or matching.
### Task Chain Shape (Server-side only)
> Browser-based projects (e.g., Frontend SPA) skip the build chain — the dev server task is the only task. See `project-types/{type}.md` § VS Code Task Configuration.
```
"{service-id}: {top-level-task}" ← project-type-specific (see project-types/{type}.md)
├── dependsOn: "{service-id}: {watch-task}" ← from runtimes/{rt}.md
│ └── dependsOn: "{service-id}: {clean-task}"
│ └── dependsOn: "{service-id}: {install-task}"
└── dependsOn: "Start Emulators" ← only when emulators are required
```
> Adjust task labels and commands for alternative package managers (`yarn`, `pnpm`, `gradle`). The key invariant is the chain shape: **install → clean → build/watch → top-level task** (with `Start Emulators` as a sibling dependency of the top-level task, NOT nested under install). Some runtimes skip steps — use only what applies.
### Project Type Path Resolution
Most project types have a single reference file at `project-types/{type}.md`. Some use a subdirectory:
| Project Type | Reference Path |
|--------------|---------------|
| `functions` | `project-types/functions.md` |
| `frontend-spa` | `project-types/frontend-spa/frontend-spa.md` |
When instructions reference `project-types/{type}.md`, resolve via this table. If the type is not listed, look for `project-types/{type}.md` first, then `project-types/{type}/{type}.md`.
### Working Directory (`cwd`) Rules
> ⚠️ **CRITICAL for multi-service repos.** Without correct `cwd`, commands like `npm install` or `func host start` will run from the workspace root and fail.
Use the **Service Root** column from the plan's Services table to determine the `cwd` for each task.
| Task Scope | `cwd` Setting | Example |
|------------|--------------|---------|
| **Per-service tasks** (install, clean, watch, build, top-level) | `"options": { "cwd": "${workspaceFolder}/{service-root}" }` | `"cwd": "${workspaceFolder}/api"` |
| **Shared tasks** (Start Emulators) | Workspace root (omit `cwd` — it defaults to workspace root) | — |
| **Single-service repos** | Omit `cwd` — workspace root is the service root | — |
### Task `runOptions` Rules
**Every** task in `tasks.json` must include `runOptions` with `instanceLimit: 1` and `instancePolicy: "silent"` — install, clean, watch, build, top-level, emulator, **and the sequenced compound task** from [multi-service.md](multi-service.md) § Compound Debug Configuration. There is no task type this is optional for; if you are writing a `"label"`, you are writing `runOptions` beside it.
This prevents duplicate task instances and silently skips re-invocations when a task is already running (e.g., from compound + individual `preLaunchTask` chains). The compound task is the one that needs it most, not least: it is reachable both directly and as a `preLaunchTask`, so it is the likeliest to be invoked twice.
### Start Emulators Task
When the plan includes emulators, generate a shared `Start Emulators` task. This task is a **sibling dependency** of each service's top-level startup task (e.g., `func host start`). Do NOT place `Start Emulators` as a dependency of build chain tasks like `npm install` or `npm watch` — it belongs in the startup task's `dependsOn` array alongside the build chain prerequisite.
Use the plan's **Compose Command** for the task `command` — `docker compose up -d` by default, or `podman compose up -d` when the plan's Orchestrator selected Podman.
```json
{
"type": "shell",
"label": "Start Emulators",
"command": "docker compose up -d",
"problemMatcher": [],
"runOptions": { "instanceLimit": 1, "instancePolicy": "silent" }
}
```
### instanceLimit and instancePolicy
Set **`instanceLimit: 1`** and **`instancePolicy: "silent"`** on every task. You never want parallel instances of the same build or startup task, and `"silent"` ensures that duplicate invocations are skipped without prompting the user.
### Problem Matchers
**Background tasks (`isBackground: true`) MUST have a real `problemMatcher`.** An empty matcher (`"problemMatcher": []`) on a background task causes a blocking VS Code dialog ("This task is tracked by a problem matcher"). Look up the correct matcher from the relevant reference file:
- **Runtime tasks** (build, watch) → `runtimes/{rt}.md` § VS Code Problem Matchers
- **Project-type tasks** (top-level startup) → `project-types/{type}.md` § VS Code Task Configuration
- **Frontend dev servers** → `project-types/frontend-spa/frontend-spa.md` § Framework Lookup Table
For non-background tasks:
| Task Type | Matcher |
|-----------|---------|
| Short-lived commands (`npm install`, `npm clean`, `docker compose up -d`) | `"problemMatcher": []` |
| Dependency-only tasks (only `dependsOn`, no `command`) | Omit `problemMatcher` entirely |
Short-lived commands use an empty matcher to suppress matching on tasks that don't produce compiler-style output.
### Example
```json
{
"type": "shell",
"label": "npm install",
"command": "npm install",
"runOptions": { "instanceLimit": 1, "instancePolicy": "silent" },
"problemMatcher": []
}
```
---
## VS Code Extension Recommendations (`.vscode/extensions.json`)
Aggregate extension recommendations from the detected **runtime** and **project type** into `.vscode/extensions.json`. Each source lists its required extensions in a `## VS Code Extension Recommendations` section with an `Extension ID | Why Required` table.
### Assembly Protocol
| Step | Action | Details |
|------|--------|---------|
| 1. Collect | Gather from runtime | Read extension IDs from `runtimes/{rt}.md § VS Code Extension Recommendations` |
| 2. Collect | Gather from project type | Read extension IDs from `project-types/{type}.md § VS Code Extension Recommendations` |
| 3. Deduplicate | Remove duplicates | Each extension ID appears once in the final list |
| 4. Write | Output `.vscode/extensions.json` | Contribute to the file — do not replace existing entries |
### Output Format
```json
{
"recommendations": [
"{runtime-extension-1}",
"{project-type-extension-1}"
]
}
```
---
## VS Code Workspace Settings (`.vscode/settings.json`)
Aggregate workspace settings from the detected **runtime**, **project type**, and **emulator configuration** into `.vscode/settings.json`. Each source lists its contributed settings in a `## VS Code Workspace Settings` section with a `Setting | Value | Why` table.
### Assembly Protocol
| Step | Action | Details |
|------|--------|---------|
| 1. Collect | Gather from runtime | Read settings from `runtimes/{rt}.md § VS Code Workspace Settings` |
| 2. Collect | Gather from project type | Read settings from `project-types/{type}.md § VS Code Workspace Settings` |
| 3. Collect | Gather emulator exclusions | Derive data directory exclusions from `docker-compose.yml` `volumes:` mounts |
| 4. Collect | Gather required debug settings | Add the mandatory keys from generate.md § Required Debug Settings |
| 5. Write | Output `.vscode/settings.json` | Merge into the file — contribute without replacing existing entries or user customizations |
### Required Debug Settings
Always merge these keys into the workspace `.vscode/settings.json` on **every** run which is workspace scope only. Preserve any existing entries; if a key is already present, leave its value untouched.
| Setting | Value | Why |
|---------|-------|-----|
| `debug.onTaskErrors` | `"debugAnyway"` | Suppresses VS Code's blocking "task errors" modal on F5, which can appear as a project launching blocker when it's often not. |
```json
{
"debug.onTaskErrors": "debugAnyway"
}
```
### Emulator Data Directory Exclusions
When emulators are configured with **workspace bind mounts** (e.g. Azurite's `./.azurite:/data`), add their data directories to both `files.exclude` and `search.exclude` in **`.vscode/settings.json`** to reduce workspace noise:
```json
{
"files.exclude": {
"**/.azurite": true
},
"search.exclude": {
"**/.azurite": true
}
}
```
> Derive directory names from the actual **bind-mount** `volumes:` entries in `docker-compose.yml` (a `./.name:/path` host mount) — do not hardcode. **Named volumes** (e.g. Postgres's `postgres_data`) live inside the container engine, not the workspace, so they need no exclusion. Each emulator's data pattern is defined in `emulators/{name}.md`.
@@ -0,0 +1,74 @@
<!-- azure-cor-disclaimer -->
> **Important:** This skill provides guidance and recommended instructions to assist the AI system. Outputs are not guaranteed to be complete, correct, secure, or applicable to every scenario. Results should be reviewed and validated by a human before being applied. The AI model may choose not to follow all instructions exactly, and additional verification may be required.
# Limited Support Warnings
> Emit a standardized warning when the skill detects a feature that is not yet fully supported. The warning format is consistent across all feature categories so the user always knows what to expect.
---
## ⛔ Detection Algorithm — MANDATORY
For every project type, runtime, and emulator declared in the plan's tables, follow this procedure **exactly**:
1. **Check for a matching reference file** — List the files and subdirectories in the category folder (ignoring `_template.md`). If any filename or subdirectory name loosely matches the declared value (ignoring case, spaces, dashes, and underscores), the feature has a reference file.
2. **Check the status inside the reference file** — Open the matched reference file and look for a status indicator. If the file is marked `🔲 Planned` (in a frontmatter note, status field, or top-level callout), the feature has **limited support** despite having a reference file. You **MUST** emit a warning.
3. **If a match exists AND the file is not marked Planned** → the feature is fully supported. Proceed normally.
4. **If no match exists** → the feature has limited support. You **MUST** emit a warning. Do NOT substitute a different, supported feature.
| Category | Category Folder | Path Notes |
|----------|-----------------|------------|
| Project type | `references/project-types/` | Some types use subdirectories (e.g., `frontend-spa/frontend-spa.md`). Match against both filenames and subdirectory names. |
| Runtime | `references/runtimes/` | |
| Emulator | `references/emulators/` | |
> ⚠️ **Do NOT skip this check.** Every declared feature MUST be verified against the category folder before generating artifacts.
---
## Warning Format
```
⚠️ LIMITED SUPPORT: {Category} "{value}" is not yet fully supported.
```
Where:
- `{Category}` — a short label for the feature area (e.g., `Project type`, `Runtime`, `Emulator`)
- `{value}` — the specific feature declared in the plan (e.g., `python`, `Container App`, `Cosmos DB`)
---
## ⛔ Emission Protocol — MANDATORY
When a limited-support feature is detected, you **MUST** follow this exact sequence:
### Step 1: Emit in assistant message
Write the canonical warning in your **regular assistant message text**. This is mandatory — the warning must be visible in the chat output, not hidden inside a tool call.
```
⚠️ LIMITED SUPPORT: Emulator "Durable Task Scheduler" is not yet fully supported.
```
### Step 2: Confirm with user
For the **first** limited-support feature encountered in the session, call `ask_user` to confirm whether to proceed:
```
ask_user(
question: "⚠️ LIMITED SUPPORT: {Category} \"{value}\" is not yet fully supported. Would you still like me to put forth a best-effort attempt?",
choices: [
"Yes, proceed with best effort",
"No, stop here"
]
)
```
If the user agrees, treat that as blanket consent for the rest of the session. Any additional limited-support features discovered later should still be emitted as a warning — but do **not** call `ask_user` again.
> Emit each `⚠️ LIMITED SUPPORT:` warning exactly once per `(Category, value)` pair in assistant messages.
---
## No Silent Substitution
**Do NOT silently substitute a supported alternative** when a feature has limited support (e.g. switching a Container App to Azure Functions, or Python to Node.js). Always generate for the project type, runtime, and emulators declared in the plan, even when support is limited.
@@ -0,0 +1,87 @@
<!-- azure-cor-disclaimer -->
> **Important:** This skill provides guidance and recommended instructions to assist the AI system. Outputs are not guaranteed to be complete, correct, secure, or applicable to every scenario. Results should be reviewed and validated by a human before being applied. The AI model may choose not to follow all instructions exactly, and additional verification may be required.
# Database Migrations — Generation
Generate compose migration services from the plan's Migrations table. The plan records WHAT migration tool is in use and which service needs it. This reference covers HOW to generate the compose configuration.
> The migration service is ordinary compose content and is **identical for Docker or Podman**. Any task or command that drives it (`docker compose up db-migrate`) uses the plan's Orchestrator **Compose Command** — substitute `podman compose` when the plan selected Podman.
---
## Targeted Resolution
The plan's Migrations table provides: `Generate | Service | Migration Tool`. Before generating the docker-compose migration service, perform targeted resolution to fill in the details:
| Detail | How to Resolve |
|--------|---------------|
| **Migration directory** | Scan for tool-specific directories: `prisma/migrations/`, `migrations/`, `Migrations/`, `alembic/` |
| **Migration command** | Check the project's script runner (e.g., `package.json` scripts) for an existing migration command. If found, use it. If not, construct from the tool name. |
| **Target database service** | Match against the plan's Emulators table — the database emulator's compose service name |
| **Connection env var** | Check `local.settings.json`, `.env`, or the migration tool's config file for the variable name |
| **Compose-network connection string** | Same shape as the local connection string but with the compose service name as host instead of `localhost` |
| **Existing script** | Check whether a migration script already exists in the project's script runner |
### Migration Script Lookup
| Detection Evidence | Instruction |
|--------------------|-------------|
| Existing migration script in project (e.g., `npm run db:migrate`) | Use it as-is in the docker-compose service |
| Migration tool detected but no script | Create a script in the project's native script runner that wraps the tool's CLI command (e.g., `"db:migrate": "npx prisma migrate deploy"` in `package.json`) |
| Raw SQL files only, no migration tool | Recommend and install a lightweight migration tool as a dev dependency (e.g., `node-pg-migrate` for Node.js). Ask the user before installing. |
---
## Docker Compose Patterns
Two patterns are needed: a **healthcheck** on the database service and a one-shot **migration service**.
### Healthcheck Pattern
When migrations are present, the target database service **must** have a healthcheck so the migration service can use `depends_on` with `condition: service_healthy`. The healthcheck definition belongs in the emulator's docker-compose config — see the emulator reference files in [emulators/](emulators/).
### Migration Service Pattern
```yaml
services:
db-migrate:
image: ${RUNTIME_IMAGE}
working_dir: /app
depends_on:
${DATABASE_SERVICE}:
condition: service_healthy
volumes:
- ./:/app:ro
${EXTRA_VOLUME_MOUNTS}
environment:
${CONNECTION_ENV_VAR}: ${CONNECTION_STRING_FOR_COMPOSE_NETWORK}
entrypoint: ${MIGRATION_SCRIPT}
restart: "no"
```
**Filling in the template — use resolved details:**
| Placeholder | How to determine |
|-------------|-----------------|
| `RUNTIME_IMAGE` | A Docker image that provides the language runtime. See the table below. |
| `DATABASE_SERVICE` | The compose service name for the target database (from Emulators table) |
| `CONNECTION_ENV_VAR` | The environment variable the migration tool expects (from targeted resolution) |
| `CONNECTION_STRING_FOR_COMPOSE_NETWORK` | Same shape as local connection string but with compose service name as host |
| `EXTRA_VOLUME_MOUNTS` | Additional mounts needed for the ecosystem. See the table below. |
| `MIGRATION_SCRIPT` | The project's migration script command (from targeted resolution) |
**Runtime images and extra volume mounts:**
| Ecosystem | Image | Extra Volume Mounts | Notes |
|-----------|-------|-------------------|-------|
| Node.js / TypeScript | `node:{major}-slim` | `./node_modules:/app/node_modules:ro` | Mount node_modules separately for native modules |
| .NET | `mcr.microsoft.com/dotnet/sdk:{version}` | — | Best-effort — emit limited support warning |
| Python | `python:{version}-slim` | `./.venv:/app/.venv:ro` (if applicable) | Best-effort — emit limited support warning |
| Java | `eclipse-temurin:{version}` | — | Best-effort — emit limited support warning |
| Go | `golang:{version}` | — | Best-effort — emit limited support warning |
> **Key properties:**
> - `depends_on` with `condition: service_healthy` — waits for the database to accept connections
> - `volumes` with `:ro` — mounts project files read-only for safety
> - `restart: "no"` — runs once per `docker compose up`, does not restart after exit
> - Mount ecosystem-specific dependency directories when the migration tool is installed as a project dependency
@@ -0,0 +1,119 @@
<!-- azure-cor-disclaimer -->
> **Important:** This skill provides guidance and recommended instructions to assist the AI system. Outputs are not guaranteed to be complete, correct, secure, or applicable to every scenario. Results should be reviewed and validated by a human before being applied. The AI model may choose not to follow all instructions exactly, and additional verification may be required.
# Multi-Service Orchestration — Generation
> Applies when the plan's Services table has **2+ rows** (excluding the compound config row). Governs compound debug configuration, working directory rules, startup ordering, and partial configuration handling.
---
## Port Assignment
When two or more services share the same runtime, each needs a unique debug port. Look up the `Base debug port` from `runtimes/{rt}.md` and assign ports sequentially: first service gets the base port, second gets base + 1, third gets base + 2, etc.
> Browser-based project types (e.g., Frontend SPA) do not use debug ports — they connect via the dev server URL instead.
---
## Partial Configuration Handling
Check each service root for existing VS Code debug config before generating anything. A service is considered already configured if it has an existing debug configuration entry in `.vscode/launch.json` matching its service ID or Launch Config Name.
| State | Action |
|-------|--------|
| **Fully configured service** | Skip all artifact generation for that service; carry its existing config into the compound configuration unchanged |
| **Partially configured service** | Generate only what is missing (e.g. tasks but no debug config → generate debug config only) |
| **Unconfigured service** | Generate all artifacts as normal |
Adding a second service to an existing single-service repo is safe — the original service's config is preserved and the new service is added alongside it.
---
## Compound Debug Configuration
> ⛔ **MANDATORY:** When 2+ service roots are detected (including Frontend SPA projects), a compound debug configuration **must** be generated. A frontend SPA counts as a service root — it does not need emulators, but it does need a debug config entry and inclusion in the compound.
> ⚠️ **Working directory:** Multi-service task chains require correct `cwd` on every per-service task. See [generate.md § Working Directory (`cwd`) Rules](generate.md) — without it, commands like `npm install` or `func host start` run from the workspace root and fail.
Use the plan's Services table to assemble the compound config. The compound config row in the plan specifies the Launch Config Name (e.g., "Debug All Services").
### Startup Ordering
VS Code compound launch configurations always start their listed configurations **in parallel**. There is no `dependsOrder` property for compounds — only individual tasks support sequenced dependencies. This means you cannot directly tell a compound to "start the backend before the frontend."
When a frontend service proxies to a local backend (e.g., a dev server proxy for API calls), the backend must be ready before the frontend starts. Otherwise the frontend proxy may produce `ECONNREFUSED` errors on startup. Since compounds cannot enforce this ordering, the workaround is to push the sequencing into a **compound task** that uses `dependsOrder: "sequence"`, and set that task as the compound's `preLaunchTask`.
> The plan may include a note like "ℹ️ **Proxy detected:**" indicating this dependency. Check the frontend's config files (e.g., `vite.config.ts` `server.proxy`) to confirm.
#### Pattern
**1. Generate a sequenced compound task** that starts services in order. Give it any descriptive label (referred to below as `{sequenced-compound-task}`):
```json
{
"label": "{sequenced-compound-task}",
"dependsOn": [
"{backend-service-id}: {backend-top-level-task}",
"{frontend-service-id}: {frontend-top-level-task}"
],
"dependsOrder": "sequence",
"runOptions": { "instanceLimit": 1, "instancePolicy": "silent" }
}
```
The backend is listed first. Its `problemMatcher` (from `project-types/{type}.md`) signals "ready" before the frontend task starts.
**2. Set the compound config's `preLaunchTask`** to the sequenced task:
```json
{
"name": "{Launch Config Name from plan's compound row}",
"configurations": ["{Backend Launch Config Name}", "{Frontend Launch Config Name}"],
"preLaunchTask": "{sequenced-compound-task}",
"stopAll": true
}
```
**3. Individual configs keep their own `preLaunchTask`** so they work standalone:
```json
{
"name": "{Backend Launch Config Name}",
"preLaunchTask": "{backend-service-id}: {backend-top-level-task}"
}
```
```json
{
"name": "{Frontend Launch Config Name}",
"preLaunchTask": "{frontend-service-id}: {frontend-top-level-task}"
}
```
**4. Set `instanceLimit: 1` and `instancePolicy: "silent"` on background tasks** to prevent duplicate instances.
When the compound runs, the sequenced compound task starts both services via `dependsOrder: "sequence"`. Then each individual configuration's `preLaunchTask` fires again — but those services are already running. With `instanceLimit: 1` and `instancePolicy: "silent"`, the duplicate invocation is silently skipped and the existing instance keeps running.
#### Why This Pattern Is Necessary
| Concern | How it's solved |
|---------|----------------|
| Compounds can't sequence configurations | The sequenced compound **task** (`dependsOrder: "sequence"`) handles ordering instead |
| Backend must be ready before frontend starts | Backend is listed first in `dependsOn`; its problem matcher signals readiness |
| Debuggers must not attach before services are running | The compound's `preLaunchTask` ensures all services are started before any debugger attaches |
| Individual configs must still work standalone | Each config has its own `preLaunchTask` pointing to its service's top-level task |
| Duplicate task invocations from compound + individual preLaunchTasks | `instanceLimit: 1` + `instancePolicy: "silent"` silently skips the duplicate — the first instance keeps running |
---
### Deduplicated Startup Graph
Any generated compound configuration MUST satisfy **all** of the following. Each rule is checkable against `tasks.json` / `launch.json`:
| # | Rule | How to check |
|---|------|--------------|
| 1 | **Each service's top-level task appears exactly once** across the compound's effective task graph (the transitive `dependsOn` closure of the sequenced compound task). No service's start task is reachable via two different paths. | Expand the `dependsOn` closure of the sequenced compound task; every service's top-level task label occurs exactly once. |
| 2 | **The sequenced compound task is the single owner of startup ordering.** No per-service task re-declares a `dependsOn` on another service's start task; ordering lives only in the sequenced compound task. | No service start task lists another service's start task in its own `dependsOn`. |
| 3 | **Every background task sets `instanceLimit: 1` and `instancePolicy: "silent"`.** | Every long-running task in the chain carries both properties. |
Because the individual configs keep their own `preLaunchTask` (so they work standalone), the compound WILL invoke each service's start task a second time. Rule 3 makes that second invocation a silent no-op instead of a duplicate process, while Rules 1 and 2 ensure the *first* pass never double-starts a service either.
@@ -0,0 +1,88 @@
<!-- azure-cor-disclaimer -->
> **Important:** This skill provides guidance and recommended instructions to assist the AI system. Outputs are not guaranteed to be complete, correct, secure, or applicable to every scenario. Results should be reviewed and validated by a human before being applied. The AI model may choose not to follow all instructions exactly, and additional verification may be required.
# Pre-Flight Checks
Verify the plan exists and environment is ready before proceeding onwards to generating files.
## Container Runtime Readiness Check
Read the container runtime from the plan's Orchestrator table (**Docker**, **Podman**, or **Podman (Docker-compatible)**) and confirm the engine is actually running before you generate or validate anything. A CLI on PATH is not the same as a running engine.
- **Docker** — confirm the daemon is reachable (`docker info`). If it errors, tell the user to start Docker Desktop / the Docker service and wait, then retry.
- **Podman (Docker-compatible)** — the plan runs the Podman engine through its Docker-compatible socket, and the generated tasks use `docker compose`. Confirm the socket answers with `docker info` (it will report the Podman server). If `docker info` errors, the Docker-compatible socket isn't up: tell the user to enable Docker compatibility in Podman Desktop and ensure the **Podman machine** is started (same machine check as below), then retry.
- **Podman** — confirm the engine is reachable (`podman info`). On **Windows and macOS** this needs a running **Podman machine**:
```bash
podman machine list --format '{{.Name}} {{.Running}}'
```
- If a machine exists but is **stopped**, ask the user before starting it (starting a VM is a stateful, resource-consuming action):
```
ask_user(
question: "Your Podman machine \"podman-machine-default\" is stopped. Start it so the emulators can run?",
choices: [
"Yes, start the Podman machine",
"No, I'll start it myself"
]
)
```
On approval, run `podman machine start` and wait for it to report ready.
- If **no machine exists**, do NOT silently `podman machine init` — tell the user to run `podman machine init && podman machine start` (a one-time, multi-minute setup) and re-run once it is ready.
> ⛔ **NEVER switch the plan's container runtime on your own — not at readiness, not during generation, not during validation.** The runtime in the Orchestrator table was chosen (and, when the user asked for a specific engine, chosen *by them*). If the selected engine fails at **any** point — the engine won't start, a container won't come up, ports don't forward to the host, a volume/permission error, a health check never passes — **STOP and surface the blocker to the user with `ask_user`**, describing the failure and the options (fix the engine, or explicitly switch to the other engine). Do **not** silently rewrite the Orchestrator row, the `Start Emulators` task, or the convenience scripts to a different engine and continue. Silently falling back — e.g. from a user-requested Podman to Docker because Podman had a networking or bind-mount issue — is a **failure of this agent**, even if the resulting app works: the user asked for Podman and must decide, not discover after the fact that Docker ran everything.
>
> When you do surface a runtime blocker, prefer offering the **fix** first (many Podman-on-Windows issues are config, not dead ends — e.g. use the WSL machine provider for host port forwarding; database emulators must use a named volume, not a workspace bind mount, so `initdb` can `chown` its data dir). Only switch engines if the user explicitly chooses to.
## Stale Data Directory Check
Before generating any files, check for leftover emulator state from a previous run — both **workspace data directories** (bind-mounted emulators such as Azurite's `.azurite/`, `.cosmos/`, `.servicebus/`) and **named volumes** (database emulators such as Postgres's `postgres_data`; see [emulators/postgres.md](emulators/postgres.md)). Stale state can cause container startup failures — for example, PostgreSQL's `initdb` will refuse to initialize if the data directory (the `postgres_data` volume) already contains files from an incompatible or partially-initialized cluster.
- **Bind-mounted data directories:** list them with `ls`/`Get-ChildItem` in the workspace.
- **Named volumes:** list them with `docker compose ls` / `docker volume ls` (or the `podman` equivalents) — a project-scoped `*_postgres_data` volume from a prior run is the database equivalent of a stale directory.
If any stale state is found:
1. **List all found directories and named volumes** with their sizes.
2. **Ask the user how to proceed** using `ask_user`:
```
ask_user(
question: "Leftover emulator state was found from a previous run:\n\n- .azurite/ (12 MB, workspace directory)\n- postgres_data (45 MB, named volume)\n\nThese can cause container startup failures. How would you like to handle this?",
choices: [
"Delete them and start fresh (recommended)",
"Keep them — I want to preserve the existing data"
]
)
```
3. **If the user chooses to delete** — Remove bind-mounted directories with platform-appropriate removal (`rm -rf` on macOS/Linux, `Remove-Item -Recurse -Force` on Windows), and remove named volumes with `docker compose down -v` / `podman compose down -v` (or `docker volume rm <project>_postgres_data`), before proceeding with generation.
4. **If the user wants to keep them** — Proceed, but warn that containers may fail to start. If they do fail, offer to clean up at that point.
5. **Never delete data directories or volumes silently** — Always confirm with the user first.
---
## Port Conflict Check
Before generating any files, scan all ports required by the planned emulators (e.g. `lsof -i -P -n`). For each occupied port, identify the process name and PID.
If any conflicts are found:
1. **List all conflicts clearly** — port number, process name, PID.
2. **Ask the user how to proceed** using `ask_user`:
```
ask_user(
question: "The following ports are already in use on your machine:\n\n- Port 5432 → postgres (PID 1234)\n\nThese ports are needed by the planned emulators. How would you like to handle this?",
choices: [
"Help me remap the conflicting ports to alternatives",
"I'll handle it myself — proceed with the plan as-is"
]
)
```
3. **If the user wants help remapping** — Propose alternative port numbers, update all references in the plan and project files (docker-compose service ports, connection strings, convenience scripts, VS Code debug config), then resume generation.
4. **If the user will handle it themselves** — Proceed with generation using the original ports.
5. **Never remap ports or modify config silently** — Always confirm with the user before making changes.
@@ -0,0 +1,169 @@
<!-- azure-cor-disclaimer -->
> **Important:** This skill provides guidance and recommended instructions to assist the AI system. Outputs are not guaranteed to be complete, correct, secure, or applicable to every scenario. Results should be reviewed and validated by a human before being applied. The AI model may choose not to follow all instructions exactly, and additional verification may be required.
# {Type} — Project Type
> **Template** — Copy this file to `project-types/{type}.md` when adding a new server-side project type. For browser-based project types, use `project-types/frontend-spa/` as a reference — the structure differs (Framework Lookup Table replaces Startup Command, debug adapters replace Debugger Properties).
---
## Detection Signals
<!-- Files/packages/patterns that identify this project type. Used during the plan phase. -->
| Signal | Notes |
|--------|-------|
| `{file}` | {description} |
---
## Prerequisites
<!-- Tools or CLIs required by this project type (not the runtime — those go in runtimes/{rt}.md § Prerequisites).
Example: Azure Functions Core Tools for functions.md. Omit this section if the project type has no additional tool requirements. -->
| Tool | Detection Command | Required For | Install Link |
|------|-------------------|-------------|-------------|
| `{tool}` | `{command}` | {purpose} | `{install-url}` |
---
## Runtime Support Matrix
<!-- Tracks implementation readiness — separate from Runtime Wiring below.
Fill in status per runtime: ✅ Full, ⚠️ Emulators only, 🔲 Planned. -->
| Runtime | Status | Reference |
|---------|--------|-----------|
| node-ts | | |
| node-js | | |
| dotnet | | |
| python | | |
| java | | |
| go | | |
---
## Dependency Discovery
<!-- How Azure service dependencies are found: bindings, SDK scan, or framework conventions. -->
<!-- Maps to emulators/{name}.md entries. -->
| Dependency Signal | Azure Service | Emulator |
|------------------|---------------|---------|
| `{signal}` | {service} | [{name}](../emulators/{name}.md) |
---
## Startup Command
<!-- How the app starts locally. E.g.: func host start, docker compose up, npm run dev.
For VS Code custom task types (e.g., "type": "func"), the executable prefix is supplied
by the extension — omit it from the task JSON command. Show the full CLI equivalent here. -->
```
{command}
```
---
## Runtime Wiring
<!-- Quick-reference index mapping runtimes to project-type-specific task configuration.
See § VS Code Task Configuration below for the concrete task JSON per runtime.
See generate.md § Source Ownership for how project-type and runtime refs combine. -->
> See **§ VS Code Task Configuration** below for the concrete task JSON for each runtime.
| Runtime | Startup task label | Task type | Problem matcher | Request Mode | Status | Reference |
|---------|--------------------|-----------|-----------------|--------------|--------|-----------|
| node-ts | {label} | {shell\|func\|...} | {matcher} | {attach\|launch} | | |
| node-js | {label} | {shell\|func\|...} | {matcher} | {attach\|launch} | | |
| dotnet | {label} | {shell\|func\|...} | {matcher} | {attach\|launch} | | |
| python | {label} | {shell\|func\|...} | {matcher} | {attach\|launch} | | |
| java | {label} | {shell\|func\|...} | {matcher} | {attach\|launch} | | |
| go | {label} | {shell\|func\|...} | {matcher} | {attach\|launch} | | |
### VS Code Debug Configuration
<!-- Only needed for browser-based project types where the debugger type comes from the project type
rather than the runtime (e.g., Frontend SPA uses "chrome").
Server-side project types get their debugger type from runtimes/{rt}.md instead — omit this section for those. -->
### VS Code Task Configuration
<!-- THE authoritative source for top-level task JSON for this project type.
Provide one concrete JSON block per implemented runtime.
Include type, label, command, problemMatcher, isBackground, runOptions, and dependsOn.
The dependsOn array references task labels from runtimes/{rt}.md § Build Chain.
See generate.md § Task runOptions Rules for instanceLimit and instancePolicy guidance. -->
### Connection Strings
<!-- Where emulator conn strings are placed. E.g.: local.settings.json, .env, compose env vars -->
| Emulator | Key | Value | File |
|----------|-----|-------|------|
| {emulator} | `{VAR_NAME}` | `{value}` | `{file}` |
---
## API Test Collections
<!-- Which test patterns to generate for this project type. Reference api-test-collections.md for the script templates. -->
See [api-test-collections.md](../api-test-collections.md) for all test script patterns.
---
## VS Code Extension Recommendations (`.vscode/extensions.json`)
<!-- Extensions required by this project type. Aggregated with runtime extensions into .vscode/extensions.json by generate.md. -->
| Extension ID | Why Required |
|--------------|-------------|
| `{extension-id}` | {reason} |
---
## VS Code Workspace Settings (`.vscode/settings.json`)
<!-- Settings contributed by this project type. Aggregated with runtime settings into .vscode/settings.json by generate.md. -->
| Setting | Value | Why |
|---------|-------|-----|
| `{setting.key}` | `{value}` | {reason} |
---
## Validation Signals
<!-- Used by validation.md during Phase 3 to verify the generated debug configuration works.
When adding a new project type, you MUST fill in these tables — validation.md references them. -->
### Ready Signal
| Top-Level Task | Ready Signal (stdout) |
|----------------|----------------------|
| {task label} | `"{pattern}"` |
### HTTP Verification
| Curl Target | Expected Status | Notes |
|-------------|-----------------|-------|
| `http://localhost:{port}/{path}` | `{status}` | {notes} |
---
## Checklist — {Type} Project Validation
<!-- Post-generation self-check for this project type. Verify generated artifacts are correct — do not run or start anything. -->
After generating `launch.json`, `tasks.json`, and `extensions.json`, verify the following were produced correctly:
1. ✅ Startup task exists in `tasks.json` with the correct type and problem matcher
2. ✅ `launch.json` `preLaunchTask` points to the startup task
3. ✅ `.vscode/extensions.json` includes project-type extensions listed above
4. ✅ `dependsOn` chain includes runtime build/watch task and `Start Emulators` (when emulators are required)
> Runtime-specific checks (e.g., build task, debugger type) are defined in `runtimes/{rt}.md`.
@@ -0,0 +1,40 @@
<!-- azure-cor-disclaimer -->
> **Important:** This skill provides guidance and recommended instructions to assist the AI system. Outputs are not guaranteed to be complete, correct, secure, or applicable to every scenario. Results should be reviewed and validated by a human before being applied. The AI model may choose not to follow all instructions exactly, and additional verification may be required.
# {Adapter} — Browser Debug Adapter
> **Template** — Copy this file to `{adapter}.md` when adding a new browser debug adapter.
## VS Code Debugger Type
| Browser | VS Code Debugger Type | Required Extension |
|---------|----------------------|-------------------|
| {browser} | `{type}` | {extension or "None — built-in"} |
---
## Launch Configuration
```json
{
"name": "{id} (debug)",
"type": "{type}",
"request": "launch",
"url": "http://localhost:{port from Framework Lookup Table}",
"preLaunchTask": "{id} dev"
}
```
| Field | Source |
|-------|--------|
| `type` | VS Code Debugger Type from table above |
| `url` | Default Port from [frontend-spa.md § Framework Lookup Table](../frontend-spa.md) |
| `preLaunchTask` | `{id} dev` — the dev server task from [frontend-spa.md § VS Code Task Configuration](../frontend-spa.md) |
<!-- Add any adapter-specific fields and notes below. -->
---
## Notes
<!-- Document adapter-specific behavior, extra fields, or required extensions here. -->
@@ -0,0 +1,43 @@
<!-- azure-cor-disclaimer -->
> **Important:** This skill provides guidance and recommended instructions to assist the AI system. Outputs are not guaranteed to be complete, correct, secure, or applicable to every scenario. Results should be reviewed and validated by a human before being applied. The AI model may choose not to follow all instructions exactly, and additional verification may be required.
# Blazor WASM — Browser Debug Adapter
> 🔲 **Planned** — This adapter is not yet implemented. Emit a `⚠️ LIMITED SUPPORT:` warning per [limited-support.md](../../../limited-support.md).
## VS Code Debugger Type
| Browser / Runtime | VS Code Debugger Type | Required Extension |
|-------------------|----------------------|-------------------|
| Blazor WASM (.NET) | `blazorwasm` | `ms-dotnettools.csharp` |
---
## Launch Configuration
```json
{
"name": "{id} (debug)",
"type": "blazorwasm",
"request": "launch",
"url": "http://localhost:{port from Framework Lookup Table}",
"browser": "chrome",
"cwd": "${workspaceFolder}/{service-root}",
"preLaunchTask": "{id} dev"
}
```
| Field | Source |
|-------|--------|
| `type` | Always `blazorwasm` |
| `url` | Default Port from [frontend-spa.md § Framework Lookup Table](../frontend-spa.md) |
| `browser` | Which browser to launch — defaults to `chrome` |
| `cwd` | .NET project root |
| `preLaunchTask` | `{id} dev` — the dev server task from [frontend-spa.md § VS Code Task Configuration](../frontend-spa.md) |
---
## Notes
- The `blazorwasm` adapter is provided by the C# extension, not built into VS Code.
- The launch config shape differs from the CDP-based `chrome`/`msedge` adapter — it requires `browser` and `cwd` fields, and does not use `webRoot`.
@@ -0,0 +1,76 @@
<!-- azure-cor-disclaimer -->
> **Important:** This skill provides guidance and recommended instructions to assist the AI system. Outputs are not guaranteed to be complete, correct, secure, or applicable to every scenario. Results should be reviewed and validated by a human before being applied. The AI model may choose not to follow all instructions exactly, and additional verification may be required.
# Chromium — Browser Debug Adapter
> Covers all **Chromium-based browsers** (Chrome, Edge, etc.). The launch configuration is identical — only the `type` field differs.
## VS Code Debugger Type
| Browser | VS Code Debugger Type | Required Extension |
|---------|----------------------|-------------------|
| Chrome | `chrome` | None — built-in |
| Edge | `msedge` | None — built-in |
Use the browser recorded in the plan's Prerequisites section (see [prerequisites.md](../../../../../shared-references/prerequisites.md) § Browser detection) to pick the `type`.
---
## Launch Configuration
```json
{
"name": "{id} (debug)",
"type": "{chrome or msedge}",
"request": "launch",
"url": "http://localhost:{port from Framework Lookup Table}",
"webRoot": "${workspaceFolder}/{service-root}",
"preLaunchTask": "{id} dev"
}
```
| Field | Source |
|-------|--------|
| `type` | Browser Debugger Type from table above — matches the browser recorded in the plan's Prerequisites (`chrome` for Chrome, `msedge` for Edge) |
| `url` | Default Port from [frontend-spa.md § Framework Lookup Table](../frontend-spa.md) |
| `webRoot` | **Framework root** — see `webRoot` Resolution below |
| `preLaunchTask` | `{id} dev` — the dev server task from [frontend-spa.md § VS Code Task Configuration](../frontend-spa.md) |
---
## `webRoot` Resolution
> **Universal rule:** `webRoot` must ALWAYS be the **framework root directory** (where the framework's config file lives), NEVER a subdirectory within it. The dev server determines its URL path structure relative to this root. Setting `webRoot` to a subdirectory like `src/` causes path doubling and breaks breakpoint resolution.
This applies to **all frameworks** — any framework where the config file lives in a parent directory of `src/` will exhibit the same bug.
| Framework | Config file that defines the root | `webRoot` value |
|-----------|----------------------------------|-----------------|
| Vite | `vite.config.*` | Directory containing `vite.config.*` |
| CRA | `package.json` (with `react-scripts`) | Directory containing `package.json` |
| Angular | `angular.json` | Workspace root (or project root in monorepo) |
| Next.js | `next.config.*` | Directory containing `next.config.*` |
| Blazor WASM | `*.csproj` | Directory containing `*.csproj` |
> ⛔ **Before writing `webRoot`**, verify: does `{service-root}` contain the framework config file (e.g., `vite.config.ts`, `angular.json`)? If the plan's Service Root points to a `src/` subdirectory that does NOT contain the config file, walk up to the parent that does.
---
## Notes
- The `"request": "launch"` mode opens a new browser window with CDP debugging enabled — breakpoints work immediately.
- `webRoot` maps the browser's served files back to workspace source files for correct breakpoint resolution.
- Chrome and Edge share the same CDP protocol, so all behavior is identical between them.
---
## Troubleshooting — first-launch browser failure
> ⚠️ A browser debug config can fail on the **first** launch (**F5**) — the browser window doesn't open, or the debugger never attaches. This is almost always **browser process / first-run state, NOT a defect in the generated `launch.json`**. The two common causes are (1) a browser instance is already running, and (2) a one-time development HTTPS certificate prompt interrupts startup (e.g. after a TLS/dev-cert setup by the app or a local emulator).
**Don't assume a first-launch failure is a bad config.** The generated config may be correct — jumping straight to rewriting it (e.g. swapping `launch`→`attach` or hand-authoring a dedicated Edge process task) may treat the wrong cause. Guide the user through the following fixes below **first**:
- **Close every window of the debug browser** (all Edge windows, or all Chrome windows), then press **F5** again. An already-running browser is the most common cause of a failed debug launch.
- If a **development certificate / HTTPS prompt** appeared during the first run, accept it, then close all browser windows and retry so the trusted certificate takes effect.
- If it still fails, explore if you can switch the config `type` between `msedge` and `chrome` (whichever other Chromium browser is installed), or use `editor-browser` to debug inside VS Code.
- **Only if normal launch keeps failing after the above**, fall back to launching the browser explicitly with a dedicated remote-debugging port and its own `--user-data-dir`, then switch the config to `attach`. This is heavier but a viable last resort.
@@ -0,0 +1,181 @@
<!-- azure-cor-disclaimer -->
> **Important:** This skill provides guidance and recommended instructions to assist the AI system. Outputs are not guaranteed to be complete, correct, secure, or applicable to every scenario. Results should be reviewed and validated by a human before being applied. The AI model may choose not to follow all instructions exactly, and additional verification may be required.
# Project Type: Frontend SPA
Reference guide for local development setup of frontend single-page application projects.
> All SPA frameworks share the same VS Code debug configuration shape: browser debugger type (e.g., `chrome`, `msedge`), `launch` request mode, dev server as a prerequisite task. The per-framework differences — runtime, startup command, default port, and background problem matcher — are resolved from the Framework Lookup Table below.
---
## Detection Signals
Match against these signals to classify a workspace root as a frontend SPA. If the workspace clearly is an SPA but doesn't match a specific signal below, still classify it as Frontend SPA — use the Framework Lookup Table's fallback row for configuration.
| Signal | Notes |
|--------|-------|
| `vite.config.*` or `vite` in devDependencies | Vite-based SPA |
| `next.config.*` or `next` in dependencies | Next.js app |
| `angular.json` | Angular app |
| `react-scripts` in dependencies | Create React App |
| `*.razor` files + `Microsoft.AspNetCore.Components.WebAssembly` in `*.csproj` | Blazor WASM |
---
## Prerequisites
No VS Code extension is required — browser debugging uses VS Code's built-in adapter. A Chromium-based browser (Chrome or Edge) must be installed, though; that is captured as a Debug prerequisite via [prerequisites.md](../../../../shared-references/prerequisites.md) § Browser detection. Runtime prerequisites (e.g., Node.js) are listed in `runtimes/{rt}.md § Prerequisites`.
---
## Runtime Support Matrix
Runtime support for Frontend SPAs is tracked per-framework in the **Framework Lookup Table** below. Each row's `Status` column indicates implementation readiness.
---
## Dependency Discovery
Frontend SPAs communicate with backend services via HTTP during local development — they do not connect to Azure emulators directly. In monorepo setups, Azure service dependencies (storage, databases, etc.) are handled by the backend project type. In standalone SPA projects, the backend may already be running as a deployed service or a separate local process — no emulator setup is needed for the SPA itself.
---
## Backend Proxy Dependencies
Frontend dev servers often proxy API requests to a local backend during development. In multi-service setups, if a proxy config is detected pointing to another local service, that backend service's startup task should be a dependency of the frontend's dev server task to prevent `ECONNREFUSED` errors during initial page load.
| Framework | Proxy Config Location |
|-----------|----------------------|
| Vite | `server.proxy` in `vite.config.*` |
| Create React App | `"proxy"` field in `package.json` |
| Angular | `proxy.conf.json` |
| Next.js | `rewrites()` in `next.config.*` |
---
## Startup Command
The startup command varies per framework. See the **Framework Lookup Table** below for the specific command for each detected framework (e.g., `npm run dev` for Vite, `npm start` for Angular).
---
## Framework Lookup Table
Use this table to resolve per-framework values when generating the VS Code configuration. The `Status` column is the source of truth for implementation readiness — if a framework is not ✅ Implemented, emit a `⚠️ LIMITED SUPPORT:` warning per [limited-support.md](../../limited-support.md).
> **To add a new framework:** add a row with its runtime, detection signal, startup command, default port, problem matcher patterns, and status.
| Framework | Runtime | Detection | Startup Command | Default Port | Ready Pattern (begins) | Ready Pattern (ends) | Status |
|-----------|---------|----------|-----------------|--------------|----------------------|---------------------|--------|
| Vite | node | `vite.config.*` or `vite` in devDependencies | `npm run dev` | 5173 | `VITE` | `Local:` | ✅ Implemented |
| Next.js | node | `next.config.*` or `next` in dependencies | `npm run dev` | 3000 | `\s*ready` | `started server on` | ✅ Implemented |
| Angular | node | `angular.json` | `npm start` | 4200 | `Compiling` | `Compiled successfully` | ✅ Implemented |
| Create React App | node | `react-scripts` in dependencies | `npm start` | 3000 | `Starting the development server` | `Compiled` | ✅ Implemented |
| Blazor WASM | dotnet | `*.razor` + `WebAssembly` SDK in `*.csproj` | `dotnet watch run` | 5000 | `Now listening on` | `Application started` | 🔲 Planned |
| other | — | No match | — | — | — | — | [limited-support.md](../../limited-support.md) |
> ⚠️ **ANSI escape codes:** Dev servers often wrap output in color codes (e.g., `\x1b[32m...\x1b[0m`). Prefer plain-text anchors that appear outside styled regions (e.g., `Local:` instead of `ready in \d+`) to avoid regex mismatches.
---
## Runtime Wiring
<!-- For Frontend SPAs, all configuration comes from this file — the Framework Lookup Table and VS Code Debug Configuration.
Browser-based projects do not use runtimes/{rt}.md for debugger type or build chain.
See generate.md § Source Ownership for the server-side vs browser distinction. -->
| Startup command | Startup task label | Task type | Problem matcher | Request Mode |
|----------------|-------------------|-----------|-----------------|--------------|
| From Framework Lookup Table | `{id} dev` | `shell` | From Framework Lookup Table | `launch` |
### VS Code Debug Configuration
The request mode is always `launch` (VS Code opens the browser). The browser (Chrome or Edge) is the one recorded in the plan's Prerequisites section during the browser detection pass (see [prerequisites.md](../../../../shared-references/prerequisites.md) § Browser detection) — use its debug adapter `type` (`chrome` for Chrome, `msedge` for Edge). The user can change the browser in the plan before approval.
Look up the launch configuration template from the corresponding adapter file in [`debug-adapters/`](debug-adapters/):
| Browser / Adapter | Adapter File | Status |
|-------------------|-------------|--------|
| Chromium (Chrome, Edge, etc.) | [debug-adapters/chromium.md](debug-adapters/chromium.md) | ✅ Implemented |
| Blazor WASM (.NET) | [debug-adapters/blazorwasm.md](debug-adapters/blazorwasm.md) | 🔲 Planned |
| ∞ | [debug-adapters/_template.md](debug-adapters/_template.md) | — |
> **To add a new debug adapter:** copy `debug-adapters/_template.md` to `debug-adapters/{adapter}.md` and add a row to this table.
### VS Code Task Configuration
The top-level task is the framework's dev server. No runtime build chain — the dev server handles compilation internally. The task label follows the pattern `"{id} dev"`.
```json
{
"type": "shell",
"label": "{id} dev",
"command": "{command from Framework Lookup Table}",
"options": { "cwd": "${workspaceFolder}/{service-root}" },
"isBackground": true,
"runOptions": { "instanceLimit": 1, "instancePolicy": "silent" },
"problemMatcher": {
"owner": "{framework name, lowercased}",
"pattern": { "regexp": "^$" },
"background": {
"activeOnStart": true,
"beginsPattern": "{Ready Pattern (begins) from Framework Lookup Table}",
"endsPattern": "{Ready Pattern (ends) from Framework Lookup Table}"
}
}
}
```
### Connection Strings
Not applicable — Frontend SPAs do not connect to Azure emulators directly. In monorepo setups, connection strings are owned by the backend project type.
---
## API Test Collections
Not applicable — Frontend SPAs do not expose API endpoints. In monorepo setups, API test collections are owned by the backend project type. See [api-test-collections.md](../../api-test-collections.md) for backend patterns.
---
## VS Code Extension Recommendations (`.vscode/extensions.json`)
No project-type-specific extensions. Browser debugging uses VS Code's built-in capabilities.
> Framework-specific extensions (if any) would be listed here. Runtime extensions are listed in `runtimes/{rt}.md`.
---
## VS Code Workspace Settings (`.vscode/settings.json`)
No project-type-specific workspace settings.
---
## Validation Signals
Used by [validation.md](../../validation.md) during Phase 3 to verify the generated debug configuration works.
### Ready Signal
Use the `Ready Pattern (begins)` and `Ready Pattern (ends)` columns from the **Framework Lookup Table** above for the detected framework. The ready signal is observed on stdout of the dev server task.
### HTTP Verification
| Curl Target | Expected Status | Notes |
|-------------|-----------------|-------|
| `http://localhost:{dev-server-port}` | `200` or `301` | Use the resolved dev server port from the Framework Lookup Table. Validates the dev server started — do NOT launch a browser. Framework-specific redirects (e.g., `301` for Next.js) are acceptable. |
---
## Checklist — Frontend SPA Project Validation
After generating `launch.json` and `tasks.json`, verify the following were produced correctly:
1. ✅ Dev server task exists in `tasks.json` with a custom `background` problem matcher using the correct begin/end patterns from the Framework Lookup Table
2. ✅ `launch.json` uses the browser debug adapter matching the browser recorded in the plan's Prerequisites (`chrome` or `msedge`) with `"request": "launch"`
3. ✅ `launch.json` `url` matches the framework's default port from the Framework Lookup Table
4. ✅ `launch.json` `preLaunchTask` points to the dev server task
> Runtime-specific checks (e.g., build task, debugger type) are defined in `runtimes/{rt}.md`.
@@ -0,0 +1,281 @@
<!-- azure-cor-disclaimer -->
> **Important:** This skill provides guidance and recommended instructions to assist the AI system. Outputs are not guaranteed to be complete, correct, secure, or applicable to every scenario. Results should be reviewed and validated by a human before being applied. The AI model may choose not to follow all instructions exactly, and additional verification may be required.
# Project Type: Azure Functions
Reference guide for local development setup of Azure Functions projects.
---
## Detection Signals
| Signal | Notes |
|--------|-------|
| `host.json` present | Primary signal — required |
| Azure Functions SDK in dependencies | Confirms it's a Functions project — identified during the plan phase |
---
## Prerequisites
| Tool | Detection Command | Required For | Install Link |
|------|-------------------|-------------|-------------|
| Azure Functions Core Tools | `func --version` | Run Functions host locally | [aka.ms/azure-functions-core-tools](https://aka.ms/azure-functions-core-tools) |
---
## Runtime Support Matrix
| Runtime | Status | Reference |
|---------|--------|-----------|
| node-ts | ✅ Implemented | [runtimes/node.md](../runtimes/node.md) |
| node-js | ✅ Implemented | [runtimes/node.md](../runtimes/node.md) |
| dotnet (Functions isolated) | ✅ Implemented | [runtimes/dotnet.md](../runtimes/dotnet.md) |
| python | 🔲 Planned | [limited-support.md](../limited-support.md) |
| java | 🔲 Planned | [limited-support.md](../limited-support.md) |
> **Limited-support runtimes:** When a runtime with limited support is detected, emit a `⚠️ LIMITED SUPPORT:` warning per [limited-support.md](../limited-support.md) and ask the user whether to proceed. If the user agrees, proceed with best-effort generation for all artifacts (emulators, debug config, tasks). Do not silently skip debug/launch configuration — let the user decide.
---
## Dependency Discovery
Scan every `function.json` for its `"type"` binding field, **or** scan Python/Java source files for trigger decorator/attribute names. Each binding maps to an emulator.
### Binding → Emulator Mapping
| Binding Type(s) | Azure Service | Default Ports | Connection String | Status | Reference |
|----------------|---------------|---------------|-------------------|--------|-----------|
| `blobTrigger`, `blob` | Blob Storage | 10000 | `UseDevelopmentStorage=true` | ✅ Implemented | [emulators/azurite.md](../emulators/azurite.md) |
| `queueTrigger`, `queue` | Queue Storage | 10001 | `UseDevelopmentStorage=true` | ✅ Implemented | [emulators/azurite.md](../emulators/azurite.md) |
| `table` | Table Storage | 10002 | `UseDevelopmentStorage=true` | ✅ Implemented | [emulators/azurite.md](../emulators/azurite.md) |
| `cosmosDBTrigger`, `cosmosDB` | Cosmos DB | 8081, 10250–10254 | — | 🔲 Planned | [limited-support.md](../limited-support.md) |
| `serviceBusTrigger`, `serviceBus` | Service Bus | 5672 | — | 🔲 Planned | [limited-support.md](../limited-support.md) |
| `eventHubTrigger`, `eventHub` | Event Hubs | 9093 | — | 🔲 Planned | [limited-support.md](../limited-support.md) |
| `sql`, `sqlTrigger` | Azure SQL | 1433 | — | 🔲 Planned | [limited-support.md](../limited-support.md) |
| `httpTrigger` | (built-in) | — | — | ✅ Implemented | — |
| `timerTrigger` | (built-in) | — | — | ✅ Implemented | — |
> **Azurite consolidation:** If multiple storage bindings (blob + queue + table) are detected, create a **single** Azurite service — not one per binding type.
### Services Without Azure Emulators
| Binding Type | Azure Service | Recommendation |
|-------------|---------------|----------------|
| `signalR` | Azure SignalR | Use a dev-tier Azure SignalR instance |
| PostgreSQL (SDK, not a binding) | Azure Database for PostgreSQL | [emulators/postgres.md](../emulators/postgres.md) |
---
## Startup Command
> For VS Code `"type": "func"` tasks, omit the `func` executable prefix — the Azure Functions extension supplies it. The equivalent CLI commands are shown below for reference.
**Node.js (TypeScript & JavaScript):**
```
languageWorkers__node__arguments="--inspect=9229" func host start
```
> ⚠️ The Azure Functions Core Tools do **not** automatically enable the Node.js debugger. You **must** supply `--inspect=9229` to the Node worker so it opens a debug port for VS Code to attach to. Without it, the `attach` configuration connects to nothing. In the VS Code `func` task, set this via `options.env` (`languageWorkers__node__arguments`) rather than a command-line flag — the env-var form avoids shell/JSON quoting issues and uses the same `languageWorkers__<runtime>__arguments` convention across runtimes.
**dotnet:**
```
func host start
```
> For .NET, the Functions host spawns a worker process that VS Code attaches to via `coreclr` — no additional debug flags are needed on the command line.
---
## Runtime Wiring
<!-- Quick-reference index. See § VS Code Task Configuration below for the concrete task JSON per runtime. -->
> See **§ VS Code Task Configuration** below for the concrete task JSON for each runtime.
| Runtime | Startup task label | Task type | Problem matcher | Request mode | Status | Reference |
|---------|--------------------|-----------|-----------------|--------------|--------|-----------|
| node-ts | `{service-id}: func host start` | `func` | `$func-node-watch` | `attach` | ✅ Implemented | [runtimes/node.md](../runtimes/node.md) |
| node-js | `{service-id}: func host start` | `func` | `$func-node-watch` | `attach` | ✅ Implemented | [runtimes/node.md](../runtimes/node.md) |
| dotnet | `{service-id}: func host start` | `func` | `$func-dotnet-watch` | `attach` | ✅ Implemented | [runtimes/dotnet.md](../runtimes/dotnet.md) |
| python | `{service-id}: func host start` | `func` | `$func-python-watch` | `attach` | 🔲 Planned | [limited-support.md](../limited-support.md) |
| java | `{service-id}: func host start` | `func` | `$func-java-watch` | `attach` | 🔲 Planned | [limited-support.md](../limited-support.md) |
> `{service-id}` is the kebab-case ID derived from the plan's Service Label column — see [generate.md § Service ID Derivation](../generate.md).
> **dotnet `processName` warning.** The .NET `coreclr` (request: `attach`) configuration requires the literal `processName` in `launch.json` — `.exe` suffix on Windows, no extension on macOS/Linux. Without it, F5 fails with `"No process with the specified name is currently running"`. Do NOT use `${command:pickProcess}`. See [runtimes/dotnet.md § processName Determination](../runtimes/dotnet.md).
The startup step `dependsOn`:
1. The runtime-specific build/watch task label from `runtimes/{rt}.md` § Build Chain (e.g., `{service-id}: npm watch` for node-ts, `{service-id}: dotnet build` for dotnet)
2. `"Start Emulators"` (only when emulators are required — omit when the plan has no checked emulators)
### VS Code Task Configuration
The top-level task uses the VS Code `func` task type provided by the Azure Functions extension (`ms-azuretools.vscode-azurefunctions`). The launch configuration's `preLaunchTask` points to this task.
> **Task label scoping:** All task labels MUST be prefixed with the service ID (e.g., `functions-api: func host start`). This prevents label collisions in multi-service workspaces. See [generate.md § Service ID Derivation](../generate.md).
#### Debug Argument Injection
The Functions host runs your code in a separate **language-worker** process, so the worker must start with the runtime's debug flag. Inject it through the task's `options.env` using the `languageWorkers__<runtime>__arguments` convention, then point a matching `attach` config at the resulting port. Only the env key, the flag value, and the attach `type`/`port` change per runtime — the rest of the `func host start` task stays identical, so new runtimes slot straight into this table.
| Runtime | `options.env` setting | Value to inject | Debug port | `attach` type | Status |
|---------|-----------------------|-----------------|------------|---------------|--------|
| node-ts | `languageWorkers__node__arguments` | `--inspect=9229` | 9229 | `node` | ✅ Implemented |
| node-js | `languageWorkers__node__arguments` | `--inspect=9229` | 9229 | `node` | ✅ Implemented |
**node-ts** (has watch task):
```json
{
"type": "func",
"label": "{service-id}: func host start",
"command": "host start",
"options": {
"cwd": "${workspaceFolder}/{path-to-functions-project}",
"env": { "languageWorkers__node__arguments": "--inspect=9229" }
},
"problemMatcher": "$func-node-watch",
"isBackground": true,
"runOptions": { "instanceLimit": 1, "instancePolicy": "silent" },
"dependsOn": ["{service-id}: npm watch", "Start Emulators"]
}
```
> Remove `"Start Emulators"` from `dependsOn` when the plan has no checked emulators.
**node-js** (no compile/watch step):
```json
{
"type": "func",
"label": "{service-id}: func host start",
"command": "host start",
"options": {
"cwd": "${workspaceFolder}/{path-to-functions-project}",
"env": { "languageWorkers__node__arguments": "--inspect=9229" }
},
"problemMatcher": "$func-node-watch",
"isBackground": true,
"runOptions": { "instanceLimit": 1, "instancePolicy": "silent" },
"dependsOn": ["{service-id}: npm install", "Start Emulators"]
}
```
> Remove `"Start Emulators"` from `dependsOn` when the plan has no checked emulators.
> `dependsOn`: first entry is the runtime-specific prerequisite — watch task for TypeScript, install task for JavaScript. The exact task labels come from `runtimes/{rt}.md` § Build Chain, prefixed with the service ID.
**dotnet** (compiled — requires build before host start):
```json
{
"type": "func",
"label": "{service-id}: func host start",
"command": "host start",
"options": { "cwd": "${workspaceFolder}/{path-to-functions-project}" },
"problemMatcher": "$func-dotnet-watch",
"isBackground": true,
"runOptions": { "instanceLimit": 1, "instancePolicy": "silent" },
"dependsOn": ["{service-id}: dotnet build", "Start Emulators"]
}
```
> Remove `"Start Emulators"` from `dependsOn` when the plan has no checked emulators.
> **dotnet `processName`:** The `coreclr` attach configuration requires a literal `processName` in `launch.json`. See [runtimes/dotnet.md § processName Determination](../runtimes/dotnet.md) for how to derive it from the `.csproj`, including cross-platform rules (`.exe` suffix on Windows only).
#### .NET Isolated Worker Version Constraints
Functions Worker **2.x** is required for .NET 10:
- `Microsoft.Azure.Functions.Worker >= 2.50.0`
- `Microsoft.Azure.Functions.Worker.Sdk >= 2.0.5`
When detecting a .NET Functions project, verify these minimum versions. Worker 2.x uses the canonical `func host start` + `coreclr` (request: `attach`) flow where the Functions host spawns the worker process.
### Connection Strings
| Emulator | Key | Value | Status | Reference |
|----------|-----|-------|--------|-----------|
| Azurite (storage) | `AzureWebJobsStorage` | `UseDevelopmentStorage=true` | ✅ Implemented | [emulators/azurite.md](../emulators/azurite.md) |
| Cosmos DB | {detected from bindings} | — | 🔲 Planned | [limited-support.md](../limited-support.md) |
| Service Bus | {detected from bindings} | — | 🔲 Planned | [limited-support.md](../limited-support.md) |
| Event Hubs | {detected from bindings} | — | 🔲 Planned | [limited-support.md](../limited-support.md) |
| SQL Edge | {detected from bindings} | — | 🔲 Planned | [limited-support.md](../limited-support.md) |
| PostgreSQL | {detected from code} | See [emulators/postgres.md](../emulators/postgres.md) | ✅ Implemented | [emulators/postgres.md](../emulators/postgres.md) |
> **Key discovery:** Except for `AzureWebJobsStorage` (a well-known Azure Functions convention), connection string key names are not fixed. Perform targeted resolution — check `local.settings.json`, `.env`, binding configurations, and SDK usage to detect the actual key names. Use the detected names — do not invent defaults.
> **Never overwrite** existing values in `local.settings.json` — only add missing keys.
---
## API Test Collections
See [api-test-collections.md](../api-test-collections.md) for all test script patterns. For this project type, generate tests for:
- HTTP triggers → HTTP patterns with `baseUrl: http://localhost:7071/api`
- Blob triggers → Storage § Blob trigger pattern
- Queue triggers → Storage § Queue trigger pattern
- Timer triggers → Timer § admin API pattern (only if explicitly requested)
- Cosmos DB triggers → Cosmos DB pattern
- Service Bus triggers → Service Bus pattern
- Event Hub triggers → Event Hubs pattern
---
## VS Code Extension Recommendations (`.vscode/extensions.json`)
Contribute the following to `.vscode/extensions.json`.
| Extension ID | Why Required |
|--------------|-------------|
| `ms-azuretools.vscode-azurefunctions` | Contributes the `"type": "func"` task type |
---
## VS Code Workspace Settings (`.vscode/settings.json`)
Contribute the following to `.vscode/settings.json`.
| Setting | Value | Why |
|---------|-------|-----|
| `azureFunctions.showProjectWarning` | `false` | Suppresses the "failed to detect project" prompt that fires when the extension scans the workspace — our generated config already handles project setup |
| `azureFunctions.validateEmulators` | `false` | Suppresses emulator validation warnings from the extension — emulators are managed via user's orchestrator configuration |
---
## Validation Signals
Used by [validation.md](../validation.md) during Phase 3 to verify the generated debug configuration works.
### Ready Signal
| Top-Level Task | Ready Signal (stdout) |
|----------------|----------------------|
| `{service-id}: func host start` | `"Host lock lease acquired"` or `"Functions host started"` |
> The `Top-Level Task` column uses the canonical `{service-id}:`-prefixed label — see [generate.md § Service ID Derivation](../generate.md). Resolve `{service-id}` to the same value used during generation before matching against `tasks.json`.
### HTTP Verification
| Curl Target | Expected Status | Notes |
|-------------|-----------------|-------|
| First discovered anonymous `httpTrigger` route (e.g., `http://localhost:7071/api/{function-name}`) | `200` | Port `7071` is the Functions host HTTP port; debug port `9229` is for the debugger only. Use the first anonymous HTTP trigger found during targeted resolution. If only function-key/admin routes exist, skip HTTP verification with a warning rather than assuming a route. |
---
## Checklist — Functions Project Validation
After generating `launch.json`, `tasks.json`, and `extensions.json`, verify the following were produced correctly:
1. ✅ `{service-id}: func host start` task exists in `tasks.json` with `"type": "func"`
2. ✅ `launch.json` `preLaunchTask` points to `{service-id}: func host start`
3. ✅ `.vscode/extensions.json` includes `ms-azuretools.vscode-azurefunctions`
4. ✅ `local.settings.json` contains all required connection string keys (e.g., `AzureWebJobsStorage`)
5. ✅ `dependsOn` chain includes the runtime build/watch task and `Start Emulators` (when emulators are required)
> Runtime-specific checks (e.g., `dotnet build` task, `processName` derivation) are defined in `runtimes/{rt}.md`.
@@ -0,0 +1,138 @@
<!-- azure-cor-disclaimer -->
> **Important:** This skill provides guidance and recommended instructions to assist the AI system. Outputs are not guaranteed to be complete, correct, secure, or applicable to every scenario. Results should be reviewed and validated by a human before being applied. The AI model may choose not to follow all instructions exactly, and additional verification may be required.
# {Runtime} — Debug & Build Configuration
> **Template** — Copy this file to `runtimes/{rt}.md` when adding a new runtime.
---
## Prerequisites
<!-- Required tools, SDKs, version managers — language toolchain only. -->
<!-- Do NOT list project-type-specific tools here (e.g., Functions Core Tools belongs in functions.md). -->
| Tool | Detection Command | Required For | Install Link |
|------|-------------------|-------------|-------------|
| `{tool}` | `{tool} --version` | {purpose} | `{install-url}` |
---
## Debugger Properties
<!-- Generic debug properties for this runtime.
See project-types/{type}.md § Runtime Wiring for how these combine with the host command.
See generate.md § Source Ownership for how runtime and project-type refs compose. -->
| Property | Value | Notes |
|----------|-------|-------|
| Debug protocol | `{protocol}` | The wire protocol the runtime exposes (e.g., `Node Inspector`, `CoreCLR DAP`, `debugpy DAP`, `JDWP`, `Delve DAP`). |
| VS Code debugger type | `{type}` | The VS Code debugger adapter identifier (e.g., `node`, `coreclr`, `debugpy`, `java`, `go`). |
| Base debug port | `{port}` | Default debug port for this runtime; overridden per-service in monorepos |
### VS Code Problem Matchers
<!-- Problem matchers for VS Code tasks.json. -->
| Task | Watch Problem Matcher | Build Problem Matcher |
|------|----------------------|----------------------|
| {task} | `{matcher}` | `{matcher}` |
---
## Build Chain
<!-- Build steps owned by this runtime: install, build/watch.
The startup task is provided by the project type's Runtime Wiring table, not this file.
Wire: startup task depends on ["build/watch step", "Start Emulators"]. -->
Chain shape (startup task comes from the project type):
```
"{service-id}: {startup task}" ← from project-types/{type}.md Runtime Wiring
├── dependsOn: "{service-id}: {build/watch step}" ← this file
└── dependsOn: "Start Emulators" ← only when emulators are required
```
> **Task label scoping:** All task labels MUST be prefixed with the service ID derived from the plan's Service Label column. See [generate.md § Service ID Derivation](../generate.md).
### Build Commands
| Step | Command | Purpose | Background? |
|------|---------|---------|------------|
| Start Emulators | `docker compose up -d` | Start all emulator services (idempotent — no-op if already running) | No |
See [generate.md](../generate.md) § Task `runOptions` Rules for how these build steps are rendered into VS Code task configuration.
---
## Convenience Scripts
<!-- HOW scripts are registered for this runtime (package.json, Makefile, pyproject.toml, scripts/ dir).
The plan's Convenience Scripts table drives WHICH scripts to generate — do not hardcode script names here. -->
The plan's Convenience Scripts table specifies WHICH scripts to generate. This section covers HOW to register them for this runtime.
**Script runner:** `{file}` (e.g., `package.json` scripts, `scripts/` directory, `Makefile`, `pyproject.toml`)
**Run command pattern:** `{command}` (e.g., `npm run {script}`, `./scripts/{script}.sh`)
> When the runtime's script runner is not inherently cross-platform (e.g., standalone scripts vs `package.json`), generate platform-appropriate scripts or document cross-platform alternatives.
### Script Format
<!-- Show the format for adding a script entry to this runtime's script runner. -->
### Common Script Implementations
Use these implementations when building scripts from the plan:
| Script Purpose | Typical Command | Notes |
|---------------|-----------------|-------|
| Start emulators | `docker compose up -d` | Idempotent — safe to re-run |
| Stop emulators | `docker compose down` | Stops and removes containers |
| Clean emulator data | Stop containers with volumes, then remove bind-mount data directories | Run `docker compose down -v` (`-v` also drops **named volumes** like Postgres's `postgres_data`), then remove `{data-dirs}` = `./.{name}` **bind-mount** directories derived from `docker-compose.yml` `volumes:` mounts. Use platform-appropriate removal. |
| Run migrations | `{migration tool CLI command}` | See [migrations.md](../migrations.md) for how to determine the command |
---
## VS Code Extension Recommendations (`.vscode/extensions.json`)
<!-- Extensions required by this runtime. Aggregated with project-type extensions into .vscode/extensions.json by generate.md. -->
| Extension ID | Why Required |
|--------------|-------------|
| `{extension-id}` | {reason} |
---
## VS Code Workspace Settings (`.vscode/settings.json`)
<!-- Settings contributed by this runtime. Aggregated with project-type settings into .vscode/settings.json by generate.md. -->
| Setting | Value | Why |
|---------|-------|-----|
| `{setting.key}` | `{value}` | {reason} |
---
## Checklist — {Runtime} Validation
> ⛔ **MANDATORY — runs during Phase 3 validation after all artifacts are generated.** You MUST verify every item below. Do NOT skip, assume, or approximate results.
<!-- Post-generation self-check for this runtime. Verify generated artifacts are correct — do not run or start anything. -->
After generating VS Code configuration, verify the following were produced correctly:
### Post-Generation Checks
1. ✅ Build task exists in `tasks.json` with the correct problem matcher
2. ✅ `launch.json` uses the correct debugger type and request mode
3. ✅ `.vscode/extensions.json` includes runtime extensions listed above
### Live Validation Checks
<!-- These checks run during Phase 3 validation (validation.md Step 7), after the ready signal is observed.
Add debugger-specific verifications here (e.g., process attachment, source map verification).
validation.md delegates to this section — if you add checks here, they WILL be executed. -->
> Project-type-specific checks (e.g., startup task, connection strings) are defined in `project-types/{type}.md`.
@@ -0,0 +1,194 @@
<!-- azure-cor-disclaimer -->
> **Important:** This skill provides guidance and recommended instructions to assist the AI system. Outputs are not guaranteed to be complete, correct, secure, or applicable to every scenario. Results should be reviewed and validated by a human before being applied. The AI model may choose not to follow all instructions exactly, and additional verification may be required.
# .NET / C# — Debug & Build Configuration
> Covers **.NET** projects. Project-type-specific hosting (Functions, App Service, etc.) is defined in `project-types/{type}.md` — this file covers the .NET runtime layer only.
## Prerequisites
| Tool | Detection Command | Required For | Install Link |
|------|-------------------|-------------|-------------|
| .NET SDK | `dotnet --version` | Build and run .NET projects | [dotnet.microsoft.com](https://dotnet.microsoft.com/download) |
| C# extension | VS Code extension `ms-dotnettools.csharp` installed | Contributes the `coreclr` debugger type required for F5 debugging | [Marketplace](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp) |
---
## Debugger Properties
<!-- Generic debug properties for this runtime.
See project-types/{type}.md § Runtime Wiring for how these combine with the host command.
See generate.md § Source Ownership for how runtime and project-type refs compose. -->
| Property | Value | Notes |
|----------|-------|-------|
| Debug protocol | `CoreCLR DAP` | .NET Core / .NET 5+ debug adapter protocol |
| VS Code debugger type | `coreclr` | Contributed by the C# extension (`ms-dotnettools.csharp`) |
| Request mode | `attach` | VS Code attaches to a running .NET process by `processName` |
| Base debug port | — | CoreCLR attach uses `processName`, not a port |
### VS Code Problem Matchers
| Task | Watch Problem Matcher | Build Problem Matcher |
|------|----------------------|----------------------|
| `dotnet build` | — | `$msCompile` |
---
## processName Determination
The `coreclr` debugger (request: `attach`) matches `processName` **literally** against the OS process list. Getting this wrong means F5 silently fails.
### Cross-Platform Rules
| Platform | Process name | Example |
|----------|-------------|---------|
| Windows | `{AssemblyName}.exe` | `Scrapbook.Api.exe` |
| macOS / Linux | `{AssemblyName}` (no extension) | `Scrapbook.Api` |
> ⛔ **Windows requires the `.exe` suffix.** Writing `"Scrapbook.Api"` instead of `"Scrapbook.Api.exe"` produces:
>
> ```
> No process with the specified name is currently running.
> ```
### Deriving `AssemblyName`
The process name is derived from the project's `.csproj`:
1. If `<AssemblyName>` is defined, use that value
2. Otherwise, the `.csproj` filename without extension (e.g., `Functions.csproj` → `Functions`)
3. The `.csproj` **MUST** have `<OutputType>Exe</OutputType>` — otherwise no executable is produced and there's no target to debug
**Verify before writing `launch.json`:** after `dotnet build`, confirm the executable exists at `{projectDir}/bin/Debug/{tfm}/{AssemblyName}[.exe]`.
> ❌ **Do NOT use `${command:pickProcess}` or `${command:azureFunctions.pickProcess}`** — both pop a blocking dialog every F5. Use literal `processName`.
---
## Build Chain
Tasks owned by this runtime: build. The startup task and its dependency wiring are provided by the project type's Runtime Wiring table — not this file.
> **Task label scoping:** All task labels MUST be prefixed with the service ID (e.g., `functions-api: dotnet build`). See [generate.md § Service ID Derivation](../generate.md).
Chain shape (startup task comes from the project type):
```
"{service-id}: {startup task}" ← from project-types/{type}.md Runtime Wiring
├── dependsOn: "{service-id}: dotnet build" ← this file
└── dependsOn: "Start Emulators" ← only when emulators are required
```
### Build Commands
| Step | Task Label | Command | Purpose | Background? |
|------|-----------|---------|---------|------------|
| build | `{service-id}: dotnet build` | `dotnet build {path-to-csproj} --configuration Debug` | Restore + compile | No |
```json
{
"label": "{service-id}: dotnet build",
"type": "process",
"command": "dotnet",
"args": [
"build",
"${workspaceFolder}/{path-to-csproj}",
"--configuration",
"Debug"
],
"problemMatcher": "$msCompile",
"group": "build",
"runOptions": { "instanceLimit": 1, "instancePolicy": "silent" }
}
```
> .NET does not have a watch-based incremental compile step in the debug chain (unlike TypeScript's `tsc --watch`). Each F5 re-runs `dotnet build`.
See [generate.md](../generate.md) § Task `runOptions` Rules for how these build steps are rendered into VS Code task configuration.
---
## Convenience Scripts
The plan's Convenience Scripts table specifies WHICH scripts to generate. This section covers HOW to register them for .NET projects.
Because .NET projects do not have a built-in script runner equivalent to `npm run`, convenience scripts live as standalone scripts under `scripts/`.
**Script runner:** Scripts in `scripts/` directory
**Run command pattern:** Platform-dependent (see below)
### Script Format
Generate scripts appropriate for the user's platform:
| Platform | File extension | Shebang / header | Make executable |
|----------|---------------|-------------------|-----------------|
| macOS / Linux | `.sh` | `#!/bin/bash` | `chmod +x` |
| Windows | `.ps1` | — | — (PowerShell scripts run directly) |
> When the platform is ambiguous, generate `.sh` scripts — they also work on Windows via Git Bash or WSL.
### Common Script Implementations
Use these implementations when building scripts from the plan:
| Script Purpose | Typical Command | Notes |
|---------------|-----------------|-------|
| Start emulators | `docker compose up -d` | Idempotent — safe to re-run |
| Stop emulators | `docker compose down` | Stops and removes containers |
| Clean emulator data | Stop containers with volumes, then remove bind-mount data directories | Run `docker compose down -v` (`-v` also drops **named volumes** like Postgres's `postgres_data`), then remove `{data-dirs}` = `./.{name}` **bind-mount** directories derived from `docker-compose.yml` `volumes:` mounts. Use platform-appropriate removal (e.g., `rm -rf` on macOS/Linux, `Remove-Item -Recurse` on Windows) |
| Run migrations | `{migration tool CLI command}` | See [migrations.md](../migrations.md) for how to determine the command |
---
## VS Code Extension Recommendations (`.vscode/extensions.json`)
<!-- Extensions required by this runtime. Aggregated with project-type extensions into .vscode/extensions.json by generate.md. -->
| Extension ID | Why Required |
|--------------|-------------|
| `ms-dotnettools.csharp` | Contributes the `"type": "coreclr"` debugger for .NET attach/launch |
| `ms-dotnettools.csdevkit` | C# Dev Kit — adds Solution Explorer, test discovery, and enhanced debugging experience |
> Project-type-specific extensions (e.g., `ms-azuretools.vscode-azurefunctions` for Functions) are listed in `project-types/{type}.md`.
---
## VS Code Workspace Settings (`.vscode/settings.json`)
<!-- Settings contributed by this runtime. Aggregated with project-type settings into .vscode/settings.json by generate.md. -->
| Setting | Value | Why |
|---------|-------|-----|
| `files.exclude: **/bin` | `true` | Hide .NET build output from explorer |
| `files.exclude: **/obj` | `true` | Hide .NET intermediate build files from explorer |
> These exclusions reduce workspace noise. They are deep-merged with any existing `files.exclude` entries — see [generate.md § VS Code Workspace Settings](../generate.md).
---
## Checklist — .NET Runtime Validation
> ⛔ **MANDATORY — runs during Phase 3 validation after all artifacts are generated.** You MUST verify every item below. Do NOT skip, assume, or approximate results.
After generating VS Code configuration, verify the following were produced correctly:
### Post-Generation Checks
1. ✅ `dotnet build` task exists in `tasks.json` with `$msCompile` problem matcher
2. ✅ `processName` in `launch.json` matches the `AssemblyName` derived from `.csproj` (platform-appropriate — see § processName Determination)
3. ✅ `launch.json` uses `"type": "coreclr"` with `"request": "attach"`
4. ✅ `.vscode/extensions.json` includes `ms-dotnettools.csharp` and `ms-dotnettools.csdevkit`
### Live Validation Checks
These checks run during Phase 3 validation ([validation.md](../validation.md) Step 7), after the ready signal is observed:
1. ✅ Verify the target process exists for attachment — the `processName` in `launch.json` must match a running OS process:
- **Windows PowerShell:** `Get-Process -Name "<processName without .exe>" -ErrorAction SilentlyContinue` → must return a process
- **macOS/Linux:** `pgrep -x "<processName>"` → must return a PID
2. ✅ On Windows, confirm `processName` includes the `.exe` suffix (e.g., `"Scrapbook.Api.exe"`, NOT `"Scrapbook.Api"`)
3. ✅ If process check fails, fix `launch.json` before marking the config ✅
> If the process is not found, the F5 attach WILL fail with: `"No process with the specified name is currently running"`
@@ -0,0 +1,190 @@
<!-- azure-cor-disclaimer -->
> **Important:** This skill provides guidance and recommended instructions to assist the AI system. Outputs are not guaranteed to be complete, correct, secure, or applicable to every scenario. Results should be reviewed and validated by a human before being applied. The AI model may choose not to follow all instructions exactly, and additional verification may be required.
# Node.js — Debug & Build Configuration
> Covers both **JavaScript** and **TypeScript** projects. The debugger properties are identical; only the build chain differs.
## Prerequisites
| Tool | Detection Command | Required For | Install Link |
|------|-------------------|-------------|-------------|
| Node.js | `node --version` | All Node projects | [nodejs.org](https://nodejs.org/) |
| npm | `npm --version` | Dependency management | (bundled with Node) |
---
## Debugger Properties
| Property | Value | Notes |
|----------|-------|-------|
| Debug protocol | `Node Inspector` | V8 inspector protocol over WebSocket |
| VS Code debugger type | `node` | Maps Node Inspector to VS Code's built-in Node debugger |
| Base debug port | `9229` | Default Node.js inspector port |
| Auto-restart | `true` | Re-attach after the host restarts on file changes |
### `outFiles` (node-ts only — REQUIRED)
For any TypeScript Node.js project, the `launch.json` attach configuration **must** include `outFiles` pointing to the compiled JavaScript output. Without it, VS Code cannot locate `.js.map` files and breakpoints set in `.ts` source files will not trigger.
**Derivation:** Read the project's `tsconfig.json` to determine the output directory:
1. Check `compilerOptions.outDir` — this is the compiled output root (e.g., `"outDir": "./dist"`)
2. Construct the glob: `${workspaceFolder}/{service-root}/{outDir}/**/*.js`
3. If `outDir` is not set, fall back to the project root: `${workspaceFolder}/{service-root}/**/*.js`
> `{service-root}` is the path from the workspace root to the project directory. In a single-project workspace this is empty (just `${workspaceFolder}/dist/**/*.js`). In a monorepo it includes the nested path (e.g., `${workspaceFolder}/services/functions/dist/**/*.js`).
**Example:**
```json
{
"name": "My API (debug)",
"type": "node",
"request": "attach",
"port": 9229,
"restart": true,
"outFiles": ["${workspaceFolder}/services/functions/dist/**/*.js"],
"preLaunchTask": "{service-id}: func host start"
}
```
> `preLaunchTask` uses the canonical `{service-id}:`-prefixed task label — see [generate.md § Service ID Derivation](../generate.md). The example above corresponds to a `functions-api` service, so the resolved value is `functions-api: func host start`.
> **Verify:** `tsconfig.json` must have `"sourceMap": true` in `compilerOptions` for any TypeScript project that will be debugged. Without source maps, VS Code breakpoints in `.ts` files cannot bind to the compiled `.js` output and will appear as gray (unverified) dots — even when the debugger is successfully attached. The build/watch task must run **before** the startup task so compiled output exists when the debugger attaches.
### VS Code Problem Matchers
| Variant | Watch Problem Matcher | Build Problem Matcher |
|---------|----------------------|----------------------|
| node-ts | `$tsc-watch` | `$tsc` |
| node-js | — | — |
> **Monorepo / multi-service:** When multiple Node services are present, each is assigned a sequential debug port starting from the base port defined in the project type's Runtime Wiring table. See [multi-service.md](../multi-service.md) for port assignment rules.
---
## Variant Detection
| Signal | Variant | Notes |
|--------|---------|-------|
| `tsconfig.json` present | **node-ts** | TypeScript — requires compile step |
| `package.json` without `tsconfig.json` | **node-js** | Plain JavaScript — no compile step |
---
## Build Chain
Tasks owned by this runtime: install, clean, build, watch. The startup task and its dependency wiring are provided by the project type's Runtime Wiring table — not this file.
> **Task label scoping:** All task labels MUST be prefixed with the service ID (e.g., `functions-api: npm watch`). See [generate.md § Service ID Derivation](../generate.md).
### Build Commands
#### node-ts (TypeScript)
```
"{service-id}: {startup task}" ← from project-types/{type}.md Runtime Wiring
├── dependsOn: "{service-id}: npm watch"
│ └── dependsOn: "{service-id}: npm clean"
│ └── dependsOn: "{service-id}: npm install"
└── dependsOn: "Start Emulators" ← only when emulators are required
```
| Step | Task Label | Command | Purpose | Background? |
|------|-----------|---------|---------|------------|
| install | `{service-id}: npm install` | `npm install` | Installs dependencies | No |
| clean | `{service-id}: npm clean` | `npm run clean` | Cleans build output | No |
| watch | `{service-id}: npm watch` | `npm run watch` | Runs `tsc --watch` for incremental builds | ✅ Yes |
| build | `{service-id}: npm build` | `npm run build` | One-shot build (used outside debug flow) | No |
#### node-js (JavaScript)
```
"{service-id}: {startup task}" ← from project-types/{type}.md Runtime Wiring
├── dependsOn: "{service-id}: npm install"
└── dependsOn: "Start Emulators" ← only when emulators are required
```
| Step | Task Label | Command | Purpose | Background? |
|------|-----------|---------|---------|------------|
| install | `{service-id}: npm install` | `npm install` | Installs dependencies | No |
> No compile, clean, or watch step — JavaScript runs directly.
> **Monorepo / alternative package managers:** Adjust commands if the project uses `yarn`, `pnpm`, or a monorepo layout. The key invariant is the chain shape: **install → [clean → build/watch →] startup task** (compile steps only for TypeScript).
See [generate.md](../generate.md) § Task `runOptions` Rules for how these build steps are rendered into VS Code task configuration.
---
## Convenience Scripts
The plan's Convenience Scripts table specifies WHICH scripts to generate. This section covers HOW to register them for Node.js projects.
**Script runner:** `package.json` `"scripts"` block
**Run command pattern:** `npm run {script-name}`
### Script Format
Each script is a shell command added to `package.json` `"scripts"`. Example entry:
```json
{
"{script-name}": "{shell command}"
}
```
### Common Script Implementations
Use these implementations when building scripts from the plan:
| Script Purpose | Typical Command | Notes |
|---------------|-----------------|-------|
| Start emulators | `docker compose up -d` | Idempotent — safe to re-run |
| Stop emulators | `docker compose down` | Stops and removes containers |
| Clean emulator data | `docker compose down -v && rimraf {data-dirs}` | `-v` (`--volumes`) also removes **named volumes** (e.g. Postgres's `postgres_data`). `{data-dirs}` = space-separated `./.{name}` **bind-mount** directories derived from `docker-compose.yml` `volumes:` mounts (e.g., `.azurite`). Use `rimraf` for cross-platform compatibility. Requires `rimraf` in `devDependencies` — see [generate.md § Dependency Availability](../generate.md). |
| Run migrations | `{migration tool CLI command}` | See [migrations.md](../migrations.md) for how to determine the command |
---
## VS Code Extension Recommendations (`.vscode/extensions.json`)
No recommended extensions.
---
## VS Code Workspace Settings (`.vscode/settings.json`)
<!-- Settings contributed by this runtime. Aggregated with project-type settings into .vscode/settings.json by generate.md. -->
| Setting | Value | Why |
|---------|-------|-----|
| `files.exclude: **/node_modules` | `true` | Hide dependency tree from explorer — large and noisy |
> This exclusion reduces workspace noise. It is deep-merged with any existing `files.exclude` entries — see [generate.md § VS Code Workspace Settings](../generate.md).
---
## Checklist — Node.js Runtime Validation
> ⛔ **MANDATORY — runs during Phase 3 validation after all artifacts are generated.** You MUST verify every item below. Do NOT skip, assume, or approximate results.
After generating VS Code configuration, verify the following were produced correctly:
### Post-Generation Checks
1. ✅ `launch.json` uses `"type": "node"` with the correct debug port
2. ✅ For TypeScript: `launch.json` includes `"outFiles"` derived from `tsconfig.json` `outDir` (e.g., `["${workspaceFolder}/{service-root}/{outDir}/**/*.js"]`)
3. ✅ For TypeScript: `tsconfig.json` has `"sourceMap": true` — without it, breakpoints in `.ts` files appear as gray (unverified) dots
4. ✅ For TypeScript: watch task exists in `tasks.json` with `$tsc-watch` problem matcher
5. ✅ For TypeScript: build chain follows install → clean → watch dependency order
### Live Validation Checks
These checks run during Phase 3 validation ([validation.md](../validation.md) Step 7), after the ready signal is observed:
1. ✅ For TypeScript: verify `tsconfig.json` has `"sourceMap": true` in `compilerOptions`. If missing, add `"sourceMap": true` and re-run the build task before marking the config ✅
> The Node Inspector debug port (`9229`) is handled automatically by the Functions host or `--inspect` flag.
> Project-type-specific checks (e.g., `{service-id}: func host start` task, connection strings) are defined in `project-types/{type}.md`.
@@ -0,0 +1,139 @@
<!-- azure-cor-disclaimer -->
> **Important:** This skill provides guidance and recommended instructions to assist the AI system. Outputs are not guaranteed to be complete, correct, secure, or applicable to every scenario. Results should be reviewed and validated by a human before being applied. The AI model may choose not to follow all instructions exactly, and additional verification may be required.
# Validation
Verify that the generated VS Code debug configuration actually works. This phase runs after all artifacts are generated (Phase 2) and before the closing message.
> ⛔ **MANDATORY.** You MUST execute every step in this file for each launch configuration. Do NOT skip, assume, or approximate results. Do NOT proceed to the closing message until every checklist entry has a real ✅ or ❌ result.
> **Compose command comes from the plan.** Every `docker compose …` invocation below is a stand-in for the plan's Orchestrator **Compose Command** — use `docker compose` by default, or `podman compose` when the plan selected Podman. The commands (`up -d`, `ps`, `logs`, `down`) are identical across both engines.
> ⛔ **Do NOT switch the container runtime to make validation pass.** If an emulator fails to start, a port doesn't reach the host, a volume/permission error occurs, or a health check never passes on the plan's selected engine, **STOP and surface it to the user** (per [preflight.md § Container Runtime Readiness Check](preflight.md)) — offer the fix first, and only switch engines if the user explicitly chooses to. Silently rewriting the Orchestrator/tasks to the other engine and re-validating is a failure even if the app then works.
---
## Validation Algorithm
Steps 1–8 apply to each **non-compound** launch configuration in `.vscode/launch.json`; Step 9 then validates each **compound** configuration.
For each **non-compound** launch configuration in `.vscode/launch.json`:
### Step 1: Resolve the Task Chain
- Read the config's `preLaunchTask` value
- Trace the full `dependsOn` chain in `.vscode/tasks.json` to resolve the dependency order
### Step 2: Verify Script Dependencies
- For each task in the resolved chain, verify that its command can actually execute:
- **Package scripts** (e.g., `npm run clean`, `dotnet build`) — Confirm a matching script entry or build target exists in the project
- **CLI tool invocations** (e.g., `rimraf`, `concurrently`) — Confirm the tool is installed as a project dependency
- If a dependency is missing, add it as a project dev dependency before proceeding (see [generate.md § Dependency Availability](generate.md))
### Step 3: Start Services
- Run prerequisite tasks first (install, clean, emulators), then start the `preLaunchTask` itself as a background process
### Step 4: Verify Emulators
- If a `docker-compose.yml` was generated, verify all services started correctly after `docker compose up -d` (or `podman compose up -d`):
- **Long-running services** (database emulators, Azurite) → should be running and healthy
- **One-shot services** (e.g., `db-migrate`) → should have exited with code 0
- Use `docker compose ps` and `docker compose logs <service>` (or the `podman compose` equivalents) to check
- If any service failed, diagnose the issue, fix the configuration, and re-run until all services are healthy or exited cleanly
- Only mark the config ❌ after exhausting reasonable fix attempts
### Step 5: Confirm Ready Signal
- Watch stdout from the **top-level task** for the ready signal. Look up the expected pattern from `project-types/{type}.md` § Validation Signals § Ready Signal.
### Step 6: Confirm HTTP Reachability
- After the ready signal, confirm with `curl` using the **application HTTP port** (not the debug port). Look up the expected URL and status from `project-types/{type}.md` § Validation Signals § HTTP Verification.
> Use the curl template: `curl -s -o /dev/null -w "%{http_code}" <target>`
> **HTTP verification not applicable:** If the project type's HTTP Verification table says "N/A" or no anonymous/public endpoint is available (e.g., all routes require auth keys), skip HTTP verification. The config can still pass (✅) based on the ready signal alone — note "HTTP verification skipped: {reason}" in the checklist entry.
### Step 7: Per-Debugger-Type Checks
- Run additional checks based on the `type` field in the launch configuration. See the [Per-Runtime Validation Checks](#per-runtime-validation-checks) section below. If no additional checks are listed for the debugger type, skip this step.
### Step 8: Cleanup
- Tear down **every** process this config started — not just the last one. Kill the top-level `preLaunchTask` process **and every task in its resolved `dependsOn` chain** (dev servers, `func host`, watchers, and any emulators started for this config), then confirm the app HTTP port and the debug port are released (e.g. `lsof -i :<port>` returns nothing) before moving to the next config. A lingering process here causes the next config — or the compound — to hit "port already in use".
### Step 9: Validate the Compound Configuration
For each **compound** launch configuration, faithfully run its orchestration — do NOT infer the result from the individual configs.
> ⛔ **Do NOT skip running the compound.** Configs that each pass standalone can still fail when launched together: overlapping or duplicated `dependsOn` chains can start a service more than once, or a second invocation can grab an already-bound port. The user must never see this. You MUST run the compound's orchestration and observe the real result.
- **Confirm the startup graph is deduplicated.** Before running, verify the compound satisfies every rule in [multi-service.md § Deduplicated Startup Graph](multi-service.md) — the compound's effective task graph must start each service exactly once. If any rule is violated, fix the generated config before running; do not validate a graph that can duplicate a service.
- **Run the compound orchestration.** Execute the compound's `preLaunchTask` (the sequenced compound task chain) exactly as VS Code would — run its `dependsOn` members in `dependsOrder: "sequence"`. This is the same terminal-driven orchestration used for the individual configs.
- **Assert each service starts exactly once.** Watch the task output: each service's top-level task must produce exactly one running instance. When an individual config's `preLaunchTask` fires again for an already-running service, that duplicate invocation MUST be a silent no-op (via `instancePolicy: "silent"`) — never a second process. If any service starts a second instance or grabs an already-bound port, that is considered a fail and should be fixed before proceeding.
- **Assert readiness and HTTP reachability per service.** For each member service, confirm its ready signal (as in Step 5) and HTTP reachability (as in Step 6), reusing the same `project-types/{type}.md § Validation Signals` lookups the per-config algorithm uses. Every service must reach its ready signal; every service with an HTTP endpoint must return the expected status via `curl`.
- **Record the result.** Mark the compound ✅ only after **each service started exactly once AND reached its ready signal AND (where applicable) passed HTTP reachability**. Otherwise mark it ❌ with the duplicate/failure evidence.
> **Known limitation:** As with individual configs, the agent validates task orchestration and readiness through the terminal — it does not attach VS Code debuggers to the compound's member configs. Keep the assertion focused on **started exactly once + ready + reachable**.
- **Tear down the compound.** Stop every process the compound started (all member configs and their full task chains) and confirm their ports are released, exactly as in Step 8. This feeds into the final teardown sweep below.
---
## Validation Signal Lookup
Ready signals and HTTP verification targets are defined in each project-type reference file under `§ Validation Signals`. Load the project-type file for the service being validated and read its signal tables.
| Information | Where to find it |
|-------------|-----------------|
| Ready signal (stdout pattern) | `project-types/{type}.md` § Validation Signals § Ready Signal |
| HTTP verification (curl target, expected status) | `project-types/{type}.md` § Validation Signals § HTTP Verification |
| Debugger-specific checks (processName, etc.) | `runtimes/{rt}.md` § Checklist — Live Validation Checks |
| Runtime-specific details (debug port, outFiles) | `runtimes/{rt}.md` § Debugger Properties |
> **Path resolution:** Some project types use subdirectories — see [generate.md § Project Type Path Resolution](generate.md) for the lookup table.
---
## Per-Runtime Validation Checks
Additional runtime-specific checks beyond the generic algorithm. These run after the ready signal and HTTP verification.
> ⛔ You **MUST** load and execute the runtime's live validation checks. Do NOT skip this step or assume the checks pass.
- Load `runtimes/{rt}.md` § Checklist and execute every item under **Live Validation Checks**. Each runtime's checklist contains debugger-specific verifications (e.g., source map verification for Node.js, process attachment verification for .NET).
---
## Final Teardown — Free All Ports Before Handing Back
After all individual configs **and** every compound have been validated, and **before** the Plan Integration / status write, sweep and stop everything validation spun up:
1. **Stop every lingering background process** you started during validation — every dev server, `func host`, watcher, and task/language process, across all configs and the compound. Nothing you launched may still be running.
2. **Stop every emulator you started.** If validation ran `docker compose up` (or `podman compose up`), run the matching `docker compose down` / `podman compose down` (or stop the specific services you started). Do not leave Azurite, database emulators, or any compose service running.
3. **Verify the ports are free again.** Confirm that every port the generated configs will use is released — application HTTP ports, debug ports, and emulator ports. Use `lsof -i :<port>` (and the plan's `docker compose ps` / `podman compose ps` for emulators); each must show nothing bound. If any port is still held, find and stop the owning process before finishing.
> A subsequent user **F5** must start from a completely clean slate. Do NOT proceed to the closing message or set status to `Implemented` while any validation-spawned process or emulator is still running, or while any of these ports is still bound.
---
## Plan Integration
After validating all configurations, **create or update** the `## Debug Configuration Checklist` section in `.azure/vscode-debug-plan.md`. If the section does not exist, add it at the end of the plan before closing.
```
## Debug Configuration Checklist
Debug Configuration Checklist:
✅ <config-name> — <ready signal + curl result>
✅ <config-name> — <ready signal + curl result>
✅ <compound-name> — each service started once + ready + curl result
```
One line per config (non-compound and compound). For a **non-compound** config, ✅ requires the ready signal observed AND curl confirmed (or curl skipped with a valid reason). For a **compound** config, ✅ requires the real compound test from Step 9 — each member service started **exactly once** AND reached its ready signal AND (where applicable) passed HTTP reachability — never an inferred pass from the individual results.