engsys 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +202 -0
- package/core/agents/aaron.md +152 -0
- package/core/agents/bert.md +115 -0
- package/core/agents/isabelle.md +136 -0
- package/core/agents/jody.md +150 -0
- package/core/agents/leith.md +111 -0
- package/core/agents/marcelo.md +282 -0
- package/core/agents/melvin.md +101 -0
- package/core/agents/nyx.md +152 -0
- package/core/agents/otto.md +168 -0
- package/core/agents/patricia.md +283 -0
- package/core/commands/design-audit-local.md +155 -0
- package/core/commands/design-audit.md +235 -0
- package/core/commands/design-critique.md +96 -0
- package/core/commands/file-issue.md +22 -0
- package/core/commands/generate-project.md +45 -0
- package/core/commands/implement-issue.md +37 -0
- package/core/commands/implement-project.md +40 -0
- package/core/commands/naturalize.md +61 -0
- package/core/commands/pre-push.md +29 -0
- package/core/commands/prep-review-collect.md +130 -0
- package/core/commands/prep-review-finalize.md +121 -0
- package/core/commands/prep-review-publish.md +113 -0
- package/core/commands/prep-review.md +65 -0
- package/core/commands/project-closeout.md +25 -0
- package/core/skills/agentic-eval/SKILL.md +195 -0
- package/core/skills/chrome-devtools/SKILL.md +97 -0
- package/core/skills/code-review/SKILL.md +26 -0
- package/core/skills/gh-cli/SKILL.md +2202 -0
- package/core/skills/git-commit/SKILL.md +124 -0
- package/core/skills/git-workflow-agents/SKILL.md +462 -0
- package/core/skills/git-workflow-agents/reference.md +220 -0
- package/core/skills/github-actions/SKILL.md +190 -0
- package/core/skills/github-issues/SKILL.md +154 -0
- package/core/skills/llm-structured-outputs/SKILL.md +323 -0
- package/core/skills/llm-structured-outputs/references/provider-details.md +392 -0
- package/core/skills/pre-push/SKILL.md +115 -0
- package/core/skills/refactor/SKILL.md +645 -0
- package/core/skills/web-design-reviewer/SKILL.md +371 -0
- package/core/skills/webapp-testing/SKILL.md +127 -0
- package/core/skills/webapp-testing/test-helper.js +56 -0
- package/core/templates/CLAUDE.md.tmpl +98 -0
- package/core/templates/adr-template.md +67 -0
- package/core/templates/gh-issue-templates/bug.md +39 -0
- package/core/templates/gh-issue-templates/content.md +42 -0
- package/core/templates/gh-issue-templates/enhancement.md +36 -0
- package/core/templates/gh-issue-templates/feature.md +39 -0
- package/core/templates/gh-issue-templates/infrastructure.md +41 -0
- package/core/templates/post-edit-reminders.sh.tmpl +19 -0
- package/core/templates/settings.json.tmpl +90 -0
- package/core/templates/settings.local.json.tmpl +3 -0
- package/core/workflows/agent-implementation-workflow.md +346 -0
- package/core/workflows/generate-project.md +258 -0
- package/core/workflows/implement-project-workflow.md +190 -0
- package/core/workflows/issue-tracking.md +89 -0
- package/core/workflows/project-closeout-ceremony.md +77 -0
- package/core/workflows/review-workflow.md +266 -0
- package/engsys.config.example.yaml +46 -0
- package/install +202 -0
- package/lessons-library/README.md +80 -0
- package/lessons-library/async-callbacks-verify-liveness.md +15 -0
- package/lessons-library/change-isnt-done-until-every-surface-updated.md +15 -0
- package/lessons-library/claim-then-act-for-irreversible-ops.md +16 -0
- package/lessons-library/co-commit-entangled-work.md +15 -0
- package/lessons-library/dependabot-triage-playbook.md +17 -0
- package/lessons-library/deploy-by-digest-and-verify-the-running-revision.md +15 -0
- package/lessons-library/enforce-your-guarantee-at-your-boundary.md +16 -0
- package/lessons-library/gate-changes-on-measurement-not-vibes.md +15 -0
- package/lessons-library/iac-first-no-console-changes.md +15 -0
- package/lessons-library/independent-objective-review-gate.md +15 -0
- package/lessons-library/keep-an-immutable-source-of-truth.md +15 -0
- package/lessons-library/long-agent-runs-checkpoint-not-poll.md +15 -0
- package/lessons-library/model-identity-with-stable-ids-and-provenance.md +15 -0
- package/lessons-library/operator-choices-are-first-class.md +15 -0
- package/lessons-library/prefer-tool-enforced-structured-output.md +15 -0
- package/lessons-library/prove-causation-before-acting.md +15 -0
- package/lessons-library/re-read-state-before-acting.md +14 -0
- package/lessons-library/read-layer-tolerates-unbackfilled-rows.md +15 -0
- package/lessons-library/shell-safety-pipefail-and-validate-before-teardown.md +14 -0
- package/lessons-library/shift-correctness-left-and-distrust-false-greens.md +15 -0
- package/lessons-library/stray-control-bytes-hide-changes.md +14 -0
- package/lessons-library/tests-can-assert-the-bug.md +15 -0
- package/lessons-library/verify-ground-truth-not-reports.md +15 -0
- package/lessons-library/worktrees-need-bootstrap-from-origin-main.md +15 -0
- package/lib/commands.js +356 -0
- package/lib/generate-team-avatars.mjs +251 -0
- package/lib/manifest.js +155 -0
- package/lib/render.js +135 -0
- package/lib/selftest.js +90 -0
- package/lib/util.js +89 -0
- package/lib/yaml.js +156 -0
- package/optional-agents/gary.md +86 -0
- package/optional-agents/jos.md +136 -0
- package/optional-agents/sandy.md +101 -0
- package/optional-agents/steve.md +161 -0
- package/package.json +43 -0
- package/stacks/cloud/aws/claude.fragment.md +17 -0
- package/stacks/cloud/aws/settings.fragment.json +39 -0
- package/stacks/cloud/aws/skills/aws-deployment-preflight/SKILL.md +165 -0
- package/stacks/cloud/aws/skills/cloud-architecture-aws/SKILL.md +265 -0
- package/stacks/cloud/azure/claude.fragment.md +17 -0
- package/stacks/cloud/azure/settings.fragment.json +45 -0
- package/stacks/cloud/azure/skills/azure-deployment-preflight/SKILL.md +175 -0
- package/stacks/cloud/azure/skills/cloud-architecture-azure/SKILL.md +211 -0
- package/stacks/cloud/cloudflare/claude.fragment.md +21 -0
- package/stacks/cloud/cloudflare/settings.fragment.json +31 -0
- package/stacks/cloud/cloudflare/skills/cloud-architecture-cloudflare/SKILL.md +294 -0
- package/stacks/cloud/cloudflare/skills/cloudflare-deployment-preflight/SKILL.md +175 -0
- package/stacks/cloud/gcp/claude.fragment.md +17 -0
- package/stacks/cloud/gcp/settings.fragment.json +40 -0
- package/stacks/cloud/gcp/skills/cloud-architecture-gcp/SKILL.md +208 -0
- package/stacks/cloud/gcp/skills/gcp-deployment-preflight/SKILL.md +137 -0
- package/stacks/db/mongo/skills/mongo-conventions/SKILL.md +96 -0
- package/stacks/db/prisma/claude.fragment.md +49 -0
- package/stacks/db/prisma/skills/docker-database-package-copy/SKILL.md +44 -0
- package/stacks/db/prisma/skills/prisma-conventions/SKILL.md +37 -0
- package/stacks/domain/mobile-growth/skills/apple-ads/SKILL.md +184 -0
- package/stacks/domain/mobile-growth/skills/apple-ads/references/benchmark-notes.md +47 -0
- package/stacks/domain/mobile-growth/skills/apple-ads/references/official-links.md +53 -0
- package/stacks/domain/mobile-growth/skills/google-play-growth/SKILL.md +197 -0
- package/stacks/domain/mobile-growth/skills/google-play-growth/references/benchmark-notes.md +47 -0
- package/stacks/domain/mobile-growth/skills/google-play-growth/references/official-links.md +45 -0
- package/stacks/iac/bicep/claude.fragment.md +14 -0
- package/stacks/iac/bicep/settings.fragment.json +20 -0
- package/stacks/iac/bicep/skills/iac-bicep/SKILL.md +113 -0
- package/stacks/iac/cdk/claude.fragment.md +14 -0
- package/stacks/iac/cdk/settings.fragment.json +23 -0
- package/stacks/iac/cdk/skills/iac-cdk/SKILL.md +104 -0
- package/stacks/iac/terraform/claude.fragment.md +13 -0
- package/stacks/iac/terraform/settings.fragment.json +25 -0
- package/stacks/iac/terraform/skills/iac-terraform/SKILL.md +93 -0
- package/stacks/iac/terraform/skills/terraform-conventions/SKILL.md +87 -0
- package/stacks/lang/kotlin/skills/android-testing/SKILL.md +263 -0
- package/stacks/lang/kotlin/skills/jetpack-compose/SKILL.md +264 -0
- package/stacks/lang/kotlin/skills/kotlin-coroutines/SKILL.md +329 -0
- package/stacks/lang/python/skills/python-conventions/SKILL.md +61 -0
- package/stacks/lang/shell/skills/shell-scripting/SKILL.md +110 -0
- package/stacks/lang/swift/skills/swift-concurrency/SKILL.md +423 -0
- package/stacks/lang/swift/skills/swift-concurrency/references/approachable-concurrency.md +80 -0
- package/stacks/lang/swift/skills/swift-concurrency/references/concurrency-patterns.md +233 -0
- package/stacks/lang/swift/skills/swift-concurrency/references/swiftui-concurrency.md +187 -0
- package/stacks/lang/swift/skills/swift-concurrency/references/synchronization-primitives.md +341 -0
- package/stacks/lang/swift/skills/swift-testing/SKILL.md +497 -0
- package/stacks/lang/swift/skills/swift-testing/references/testing-advanced.md +106 -0
- package/stacks/lang/swift/skills/swift-testing/references/testing-patterns.md +504 -0
- package/stacks/lang/swift/skills/swiftdata/SKILL.md +334 -0
- package/stacks/lang/swift/skills/swiftdata/references/core-data-coexistence.md +504 -0
- package/stacks/lang/swift/skills/swiftdata/references/swiftdata-advanced.md +975 -0
- package/stacks/lang/swift/skills/swiftdata/references/swiftdata-queries.md +675 -0
- package/stacks/lang/swift/skills/swiftui-patterns/SKILL.md +371 -0
- package/stacks/lang/swift/skills/swiftui-patterns/references/architecture-patterns.md +486 -0
- package/stacks/lang/swift/skills/swiftui-patterns/references/deprecated-migration.md +1097 -0
- package/stacks/lang/swift/skills/swiftui-patterns/references/design-polish.md +780 -0
- package/stacks/lang/swift/skills/swiftui-patterns/references/platform-and-sharing.md +696 -0
- package/stacks/lang/typescript/skills/typescript-conventions/SKILL.md +91 -0
- package/stacks/platform/android/claude.fragment.md +40 -0
- package/stacks/platform/android/hooks/pre-push-gradle.sh +70 -0
- package/stacks/platform/android/settings.fragment.json +13 -0
- package/stacks/platform/android/skills/android-build-conventions/SKILL.md +247 -0
- package/stacks/platform/ios/claude.fragment.md +24 -0
- package/stacks/platform/ios/hooks/pre-push-xcodebuild.sh +82 -0
- package/stacks/platform/ios/settings.fragment.json +21 -0
- package/stacks/platform/ios/skills/xcodebuildmcp-simulator-logs/SKILL.md +76 -0
- package/stacks/platform/web/skills/frontend-testing/SKILL.md +246 -0
- package/stacks/platform/web/skills/react-conventions/SKILL.md +261 -0
- package/stacks/platform/web/skills/web-platform-conventions/SKILL.md +55 -0
- package/stacks/tooling/issue-tracker-github/claude.fragment.md +10 -0
- package/stacks/tooling/issue-tracker-github/settings.fragment.json +24 -0
- package/stacks/tooling/issue-tracker-github/skills/issue-tracker-github/SKILL.md +278 -0
- package/stacks/tooling/issue-tracker-linear/claude.fragment.md +17 -0
- package/stacks/tooling/issue-tracker-linear/settings.fragment.json +9 -0
- package/stacks/tooling/issue-tracker-linear/skills/issue-tracker-linear/SKILL.md +183 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cloud-architecture-aws
|
|
3
|
+
description: AWS service-level architecture knowledge โ compute (Lambda/Fargate/ECS/EC2), data (DynamoDB/Aurora/RDS), messaging (SQS/SNS/EventBridge/Step Functions), edge (CloudFront/API Gateway), storage (S3/KMS), and Bedrock. Cost models, service quotas, failure modes, and p99/cold-start gotchas. Activate when the active cloud is AWS and the work involves designing, scaling, costing, or diagnosing AWS architecture (Lambda cold starts, Aurora connection limits, DynamoDB hot partitions, NAT egress, Fargate task warm-up).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# AWS Architecture Knowledge
|
|
7
|
+
|
|
8
|
+
Service-level detail for an AWS-backed project. Pairs with Melvin's cloud-agnostic
|
|
9
|
+
diagnostic checklist (traffic pattern, state location, SLAs, blast radius, cost
|
|
10
|
+
explosion, coordination, limits, observability) โ this pack supplies the AWS-specific
|
|
11
|
+
answers for each. For concrete project topology, cost tiers, and stack context, read
|
|
12
|
+
the architecture docs named in `CLAUDE.md`.
|
|
13
|
+
|
|
14
|
+
## Compute
|
|
15
|
+
|
|
16
|
+
### Lambda
|
|
17
|
+
|
|
18
|
+
- **Cold starts** are the p99 killer. Node/Python ~100-400ms; JVM/.NET worse;
|
|
19
|
+
VPC-attached used to add seconds (now ~sub-100ms with Hyperplane ENI, but still
|
|
20
|
+
non-zero). A function called rarely is *always* cold.
|
|
21
|
+
- **Mitigations:** provisioned concurrency (you pay for warm instances), keeping the
|
|
22
|
+
bundle small (esbuild/tree-shake), avoiding heavy module-level init, SnapStart for
|
|
23
|
+
JVM. Provisioned concurrency defeats the "scale to zero" cost story โ only buy it
|
|
24
|
+
where the latency SLA demands it.
|
|
25
|
+
- **Concurrency limits:** default account limit is 1,000 concurrent executions (raise
|
|
26
|
+
via quota request). Burst concurrency adds a few thousand instantly then scales
|
|
27
|
+
+500/min. A traffic spike past burst headroom = throttles (429), not infinite scale.
|
|
28
|
+
- **Reserved concurrency** carves a function's share out of the account pool AND caps
|
|
29
|
+
it โ useful to protect a downstream (e.g. a DB) from a stampede, but it can starve
|
|
30
|
+
other functions.
|
|
31
|
+
- **15-minute max** execution; 10GB memory ceiling (CPU scales with memory). Payload
|
|
32
|
+
6MB sync / 256KB async. `/tmp` is 512MB default (up to 10GB).
|
|
33
|
+
- **Good for:** spiky/event-driven work, glue, APIs with tolerant latency budgets.
|
|
34
|
+
**Bad for:** sustained high-throughput, long-running, or latency-critical-at-tail.
|
|
35
|
+
|
|
36
|
+
### Fargate / ECS
|
|
37
|
+
|
|
38
|
+
- Serverless containers โ no node management, but **task warm-up** (image pull +
|
|
39
|
+
container start) is tens of seconds. Scale-out is *not* instant; keep a warm pool /
|
|
40
|
+
min task count for latency-sensitive services. This is the Fargate analogue of cold
|
|
41
|
+
starts.
|
|
42
|
+
- **Cost:** billed per vCPU-second and GB-second. A perpetually-running over-provisioned
|
|
43
|
+
task (the proverbial 8-vCPU task nobody can explain) bleeds money. Right-size from
|
|
44
|
+
CloudWatch container metrics, don't guess.
|
|
45
|
+
- **ECS on EC2** vs Fargate: EC2 is cheaper at steady high utilization and gives GPU /
|
|
46
|
+
special-instance access; Fargate wins on operational simplicity and bursty workloads.
|
|
47
|
+
- **EKS** only when you genuinely need the Kubernetes ecosystem (operators, complex
|
|
48
|
+
scheduling, multi-tenant platform). For most app workloads it's operational overhead
|
|
49
|
+
you'll regret โ prefer Fargate/ECS or Lambda.
|
|
50
|
+
|
|
51
|
+
### EC2
|
|
52
|
+
|
|
53
|
+
- The escape hatch: full control, any instance family (compute/memory/GPU-optimized),
|
|
54
|
+
Spot for fault-tolerant batch (up to ~90% off, can be reclaimed with 2-min warning).
|
|
55
|
+
- Savings Plans / Reserved Instances for steady baseline; on-demand for the spiky top.
|
|
56
|
+
- You own patching, AMIs, autoscaling groups, health checks. Reach for it when managed
|
|
57
|
+
compute can't meet a hardware, licensing, or latency requirement.
|
|
58
|
+
|
|
59
|
+
## Data
|
|
60
|
+
|
|
61
|
+
### DynamoDB
|
|
62
|
+
|
|
63
|
+
- **Partition key design is everything.** A hot partition (uneven key distribution)
|
|
64
|
+
throttles even when table-level capacity looks fine โ each partition has its own
|
|
65
|
+
throughput ceiling (~3,000 RCU / 1,000 WCU). Design keys for even spread; use
|
|
66
|
+
write-sharding for naturally-skewed keys.
|
|
67
|
+
- **Capacity:** on-demand (pay-per-request, instant scaling, ~7x the per-request cost)
|
|
68
|
+
vs provisioned (cheaper at predictable load, autoscaling lags spikes). On-demand for
|
|
69
|
+
unknown/spiky; provisioned+autoscaling for steady, known traffic.
|
|
70
|
+
- **Consistency:** eventually consistent reads by default (half the cost); strongly
|
|
71
|
+
consistent on request (single-region, not for GSIs). Global tables = multi-region,
|
|
72
|
+
last-writer-wins, eventually consistent across regions.
|
|
73
|
+
- **Single-table design** maximizes performance but is a modeling discipline โ get the
|
|
74
|
+
access patterns right *first*. Item size max 400KB. Use conditional writes for
|
|
75
|
+
optimistic concurrency / idempotency.
|
|
76
|
+
- **Cost traps:** GSIs double the write cost (every write replicates to each index);
|
|
77
|
+
scans are anti-patterns; large items inflate RCU/WCU.
|
|
78
|
+
|
|
79
|
+
### Aurora / RDS PostgreSQL
|
|
80
|
+
|
|
81
|
+
- **Connection limits** are the classic bottleneck. Postgres connections are expensive
|
|
82
|
+
(memory per connection); instance size caps `max_connections`. Lambda + RDS is a
|
|
83
|
+
notorious mismatch โ N concurrent Lambdas = N connections. Use **RDS Proxy** (or
|
|
84
|
+
PgBouncer) to pool, or you'll exhaust connections under burst.
|
|
85
|
+
- **Aurora** vs RDS: Aurora separates compute from a distributed storage layer โ faster
|
|
86
|
+
failover (~30s), up to 15 read replicas sharing storage (no replication lag from
|
|
87
|
+
storage copy), auto-scaling storage. Costs more per hour but often wins on HA + read
|
|
88
|
+
scaling. **Aurora Serverless v2** scales ACUs with load for spiky workloads.
|
|
89
|
+
- **Read replicas** scale reads, not writes. Route read traffic deliberately; beware
|
|
90
|
+
replica lag for read-after-write.
|
|
91
|
+
- **IOPS cost:** Aurora bills per I/O on the standard config (can dominate the bill on
|
|
92
|
+
I/O-heavy workloads โ consider Aurora I/O-Optimized). Provisioned IOPS on RDS gp3/io2
|
|
93
|
+
is a real line item.
|
|
94
|
+
- **Failover:** Multi-AZ is a standby promotion (brief downtime, connections drop โ
|
|
95
|
+
apps must reconnect/retry). Know what breaks when the primary fails over.
|
|
96
|
+
|
|
97
|
+
## Messaging & Orchestration
|
|
98
|
+
|
|
99
|
+
### SQS
|
|
100
|
+
|
|
101
|
+
- Standard (at-least-once, best-effort ordering, near-unlimited throughput) vs **FIFO**
|
|
102
|
+
(exactly-once-processing, strict order, 300 msg/s without batching / 3,000 with).
|
|
103
|
+
Default to standard unless ordering/dedup is a hard requirement โ FIFO throughput is
|
|
104
|
+
a real ceiling.
|
|
105
|
+
- **Always configure a DLQ** with a sane `maxReceiveCount`. Poison messages without a
|
|
106
|
+
DLQ loop forever and burn money.
|
|
107
|
+
- **Visibility timeout** must exceed worst-case processing time, or you get duplicate
|
|
108
|
+
delivery. Idempotent consumers are mandatory (at-least-once).
|
|
109
|
+
- Lambda+SQS event source scales pollers automatically; watch the batch size and the
|
|
110
|
+
interaction with reserved concurrency (can throttle and silently back up the queue).
|
|
111
|
+
|
|
112
|
+
### SNS / EventBridge
|
|
113
|
+
|
|
114
|
+
- **SNS:** pub/sub fan-out (topic โ many subscribers: SQS, Lambda, HTTP). Simple, high
|
|
115
|
+
throughput.
|
|
116
|
+
- **EventBridge:** content-based routing with rule filtering, schema registry, many SaaS
|
|
117
|
+
+ AWS-service event sources, scheduler. Higher latency than SNS but far richer routing.
|
|
118
|
+
Use EventBridge when you need to *route by content*; SNS when you just need fan-out.
|
|
119
|
+
- EventBridge has per-rule and PutEvents throughput quotas โ check before betting a
|
|
120
|
+
high-volume pipeline on it.
|
|
121
|
+
|
|
122
|
+
### Step Functions
|
|
123
|
+
|
|
124
|
+
- Managed orchestration for multi-step workflows โ retries, error handling, parallel,
|
|
125
|
+
map, wait, human-approval. **Standard** workflows (long-running, up to 1 year, billed
|
|
126
|
+
per state transition โ gets expensive at high volume) vs **Express** (โค5 min, billed
|
|
127
|
+
per request+duration, high throughput, cheaper for short high-volume flows).
|
|
128
|
+
- Use it to make coordination explicit and observable instead of hiding a state machine
|
|
129
|
+
inside Lambda code. Don't use it for tight inner loops (per-transition cost).
|
|
130
|
+
|
|
131
|
+
## Edge & Networking
|
|
132
|
+
|
|
133
|
+
### CloudFront
|
|
134
|
+
|
|
135
|
+
- CDN + edge caching. Fronts S3 (static), ALB/API Gateway (dynamic), Lambda@Edge /
|
|
136
|
+
CloudFront Functions for edge logic. Cuts origin load and egress cost (CloudFront
|
|
137
|
+
egress is cheaper than direct S3/EC2 egress and the origin fetch is free within AWS).
|
|
138
|
+
- Cache key design and TTLs determine hit ratio โ a bad cache key (e.g. including a
|
|
139
|
+
unique query param) tanks it. Honor `Cache-Control`; use cache policies deliberately.
|
|
140
|
+
|
|
141
|
+
### API Gateway
|
|
142
|
+
|
|
143
|
+
- REST (feature-rich, caching, usage plans, request validation โ higher cost/latency)
|
|
144
|
+
vs **HTTP API** (cheaper, lower latency, fewer features โ prefer it unless you need
|
|
145
|
+
REST-only features) vs WebSocket. Built-in throttling (account + per-method) protects
|
|
146
|
+
backends; tune it.
|
|
147
|
+
|
|
148
|
+
### VPC / Networking โ the cost landmines
|
|
149
|
+
|
|
150
|
+
- **NAT Gateway** is the silent budget-eater: hourly charge **plus per-GB processing on
|
|
151
|
+
all egress through it**. High-egress workloads behind NAT bleed money. Mitigate with
|
|
152
|
+
**VPC Gateway/Interface Endpoints** (S3 + DynamoDB gateway endpoints are *free* and
|
|
153
|
+
bypass NAT entirely; PrivateLink interface endpoints have an hourly+per-GB cost but
|
|
154
|
+
beat NAT for AWS-service traffic).
|
|
155
|
+
- **Cross-AZ data transfer** is charged per GB *each direction* โ chatty cross-AZ
|
|
156
|
+
traffic adds up fast. Cross-region is more expensive still.
|
|
157
|
+
- Default to private subnets; public only for ALBs / NAT / bastions.
|
|
158
|
+
|
|
159
|
+
## Storage & Crypto
|
|
160
|
+
|
|
161
|
+
### S3
|
|
162
|
+
|
|
163
|
+
- Eleven 9s durability. Storage classes: Standard โ Intelligent-Tiering (auto, good
|
|
164
|
+
default for unknown access) โ Standard-IA / One Zone-IA โ Glacier tiers (retrieval
|
|
165
|
+
latency + cost). Lifecycle policies to age data down.
|
|
166
|
+
- **Cost:** storage + **per-request** (GET/PUT/LIST add up at high volume) + egress.
|
|
167
|
+
Globally-unique bucket names (see preflight). Enable encryption (SSE-S3/KMS),
|
|
168
|
+
versioning, and block public access by default.
|
|
169
|
+
|
|
170
|
+
### KMS
|
|
171
|
+
|
|
172
|
+
- Envelope encryption: KMS-managed CMK wraps per-object data keys (DEKs). Pattern for
|
|
173
|
+
crypto-shred (delete the key โ data is unrecoverable). KMS request volume is cheap โ
|
|
174
|
+
it's a rounding error on most bills; don't over-optimize it. Customer-managed keys
|
|
175
|
+
cost a small monthly fee + per-request; key rotation is built-in.
|
|
176
|
+
|
|
177
|
+
## Bedrock
|
|
178
|
+
|
|
179
|
+
- Managed access to foundation models (Anthropic Claude, Amazon Nova/Titan, Meta Llama,
|
|
180
|
+
Mistral, etc.) via a single API โ no infra to run. On-demand (per-token) vs
|
|
181
|
+
**Provisioned Throughput** (reserved model units for guaranteed capacity/latency,
|
|
182
|
+
committed spend).
|
|
183
|
+
- **Quotas matter:** per-model requests-per-minute and tokens-per-minute limits will
|
|
184
|
+
throttle a naive high-volume pipeline โ request increases early and build in backoff.
|
|
185
|
+
- Knobs: Guardrails (content filtering), Knowledge Bases (managed RAG), Agents. Cold
|
|
186
|
+
region availability varies by model โ check the model is available in your region.
|
|
187
|
+
- Cost is token-driven; long contexts and large outputs dominate. Cache/trim prompts,
|
|
188
|
+
pick the right model size per task (don't use a frontier model for a classification).
|
|
189
|
+
|
|
190
|
+
## Cost realism (where AWS bills explode)
|
|
191
|
+
|
|
192
|
+
1. **NAT Gateway egress** โ per-GB on everything leaving via NAT. Use VPC endpoints.
|
|
193
|
+
2. **Cross-AZ / cross-region data transfer** โ per-GB each way.
|
|
194
|
+
3. **Fargate/EC2 over-provisioning** โ vCPU-seconds on idle headroom.
|
|
195
|
+
4. **Aurora/RDS IOPS** โ per-I/O can exceed compute cost on I/O-heavy workloads.
|
|
196
|
+
5. **DynamoDB** โ on-demand premium, GSI write amplification, scans.
|
|
197
|
+
6. **Lambda provisioned concurrency** โ pays for warm = no scale-to-zero savings.
|
|
198
|
+
7. **S3 request volume** โ per-request charges at high object counts.
|
|
199
|
+
8. **Bedrock tokens** โ context + output length.
|
|
200
|
+
|
|
201
|
+
Levers: Savings Plans / Reserved Instances (steady baseline), Spot (fault-tolerant
|
|
202
|
+
batch), right-sizing from CloudWatch, VPC endpoints, Intelligent-Tiering, Cost Explorer
|
|
203
|
+
+ budgets/alarms.
|
|
204
|
+
|
|
205
|
+
## Service quotas (request increases *before* they bite)
|
|
206
|
+
|
|
207
|
+
Lambda concurrent executions (1,000 default), VPC/EIP/ENI counts, Fargate task limits,
|
|
208
|
+
DynamoDB table/account throughput, RDS instances + Postgres `max_connections`, API
|
|
209
|
+
Gateway throttle rates, SQS FIFO throughput, Bedrock per-model RPM/TPM, S3 globally-
|
|
210
|
+
unique bucket namespace, ECR repos. Many are soft โ raise via Service Quotas console /
|
|
211
|
+
support โ but a few are hard. Check `aws service-quotas list-service-quotas` for the
|
|
212
|
+
service and plan around the hard ones.
|
|
213
|
+
|
|
214
|
+
## Observability
|
|
215
|
+
|
|
216
|
+
CloudWatch (metrics, logs, alarms), CloudWatch Embedded Metric Format for high-cardinality
|
|
217
|
+
custom metrics, X-Ray for distributed tracing, Cost Explorer + Budgets for spend. Alarm
|
|
218
|
+
on the things that predict pain: Lambda throttles/errors/duration p99, SQS queue depth +
|
|
219
|
+
age-of-oldest-message, DynamoDB throttled requests, Aurora connections + replica lag, NAT
|
|
220
|
+
bytes processed.
|
|
221
|
+
|
|
222
|
+
## Hard-won lessons
|
|
223
|
+
|
|
224
|
+
### CloudFront VPC Origins preserve CloudFront's PUBLIC source IP
|
|
225
|
+
**Symptom:** CloudFront โ internal-ALB VPC Origin returns 504; ALB `RequestCount`
|
|
226
|
+
is exactly 0; flow logs show the managed ENI's SYN with no SYN-ACK back.
|
|
227
|
+
**Cause:** VPC Origins forward to the origin with **CloudFront's public origin-facing
|
|
228
|
+
source IP preserved** (`130.176.x` โ prefix list `pl-3b927c52`), not the managed
|
|
229
|
+
ENI's private VPC IP โ so an ALB SG that admits only the VPC CIDR (`10.20.0.0/16`)
|
|
230
|
+
REJECTs every CloudFront packet at the ALB-node ENI's ingress.
|
|
231
|
+
**Fix:** Admit the service-managed `CloudFront-VPCOrigins-Service-SG` (an SG-to-SG
|
|
232
|
+
rule, one per listener port) โ or the origin-facing managed prefix list. A
|
|
233
|
+
"looks-equivalent" VPC-CIDR rule is not a substitute.
|
|
234
|
+
|
|
235
|
+
### Black-box 5xx: is the origin even hit? RequestCount + Flow Logs first
|
|
236
|
+
**Symptom:** A fronted service (CloudFront/ELB) returns 5xx and you can't tell
|
|
237
|
+
whether the request reached the origin, the targets, or the app.
|
|
238
|
+
**Cause:** Reasoning from indirect proofs (Reachability Analyzer, intra-VPC curl)
|
|
239
|
+
validates *adjacent* customer-controlled hops, not the actual managed path โ they
|
|
240
|
+
mislead you into "propagation" or "subnet" theories.
|
|
241
|
+
**Fix:** Read ALB `RequestCount` first (0 = nothing completed โ look upstream), then
|
|
242
|
+
VPC Flow Logs filtered to the two ENI IPs. For an SG drop, read the **destination**
|
|
243
|
+
ENI's *ingress* ACCEPT/REJECT โ a source-side egress ACCEPT proves nothing about
|
|
244
|
+
admission. Localize before hypothesizing.
|
|
245
|
+
|
|
246
|
+
### Endpoint-only (NAT-less) VPC silently breaks public-internet egress
|
|
247
|
+
**Symptom:** Server-side SSO token exchange (OAuth/JWKS) and SES email fail with a
|
|
248
|
+
generic error, but only on the first *real* user โ cloud smoke tests pass.
|
|
249
|
+
**Cause:** VPC interface/gateway endpoints cover only **AWS** services (ECR, KMS,
|
|
250
|
+
S3, Secrets Manager, Logs). Anything on the public internet that isn't an AWS
|
|
251
|
+
PrivateLink service has no route out without NAT.
|
|
252
|
+
**Fix:** Enumerate every public-internet dependency (OAuth/JWKS, SES/SMTP, webhooks,
|
|
253
|
+
third-party APIs) before calling a private network "done"; each needs a NAT gateway
|
|
254
|
+
or proxy. Add NAT additively (keep subnets isolated, attach NAT + `0.0.0.0/0`); a
|
|
255
|
+
task whose SG denies egress stays isolated regardless.
|
|
256
|
+
|
|
257
|
+
### One-off ECS task on a multi-container task def: judge by container NAME
|
|
258
|
+
**Symptom:** A migration/job run on a shared multi-essential-container task def
|
|
259
|
+
flakily fails the deploy with an exit-137 it didn't cause.
|
|
260
|
+
**Cause:** When the overridden container (`host`) exits 0, ECS SIGKILLs the still-
|
|
261
|
+
running sibling (`mcp` โ 137). Reading `task.containers[0].exitCode` misattributes
|
|
262
|
+
it because `DescribeTasks` container ordering is **not guaranteed**.
|
|
263
|
+
**Fix:** Select the overridden container by **name** (`containers.find(c => c.name
|
|
264
|
+
=== โฆ)`), never by index. Better: give one-off jobs a dedicated single-container
|
|
265
|
+
task definition so there's no sibling to kill.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
## Cloud stack
|
|
2
|
+
|
|
3
|
+
- **Active cloud: Azure.** Architecture and IaC target Azure; agents load the
|
|
4
|
+
`cloud-architecture-azure` and `azure-deployment-preflight` skill packs.
|
|
5
|
+
- **Tool preference order** (when investigating or validating cloud state):
|
|
6
|
+
1. **Azure CLI, read-only** โ `az account show`, `az resource list`,
|
|
7
|
+
`az deployment group list`, `az monitor`, `az keyvault list`,
|
|
8
|
+
`az postgres flexible-server show` and similar inspection commands. Never mutate
|
|
9
|
+
state to answer a question.
|
|
10
|
+
2. **Docs source** โ the `microsoft-docs` skill (Microsoft Learn MCP:
|
|
11
|
+
`microsoft_docs_search` / `microsoft_docs_fetch`) for service limits, SKU/tier
|
|
12
|
+
behavior, and API details. Verify quotas/SKUs against docs rather than from memory.
|
|
13
|
+
- Mutating actions (deploy/provision/delete) go through Bicep + the
|
|
14
|
+
`azure-deployment-preflight` gate, never ad-hoc CLI writes.
|
|
15
|
+
|
|
16
|
+
<!-- naturalize: confirm the subscription, region(s), resource-group naming, and the
|
|
17
|
+
path to the architecture/cost docs Melvin and Aaron should read for concrete topology. -->
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(az account show:*)",
|
|
5
|
+
"Bash(az account list:*)",
|
|
6
|
+
"Bash(az group list:*)",
|
|
7
|
+
"Bash(az group show:*)",
|
|
8
|
+
"Bash(az resource list:*)",
|
|
9
|
+
"Bash(az resource show:*)",
|
|
10
|
+
"Bash(az deployment group list:*)",
|
|
11
|
+
"Bash(az deployment group show:*)",
|
|
12
|
+
"Bash(az deployment group validate:*)",
|
|
13
|
+
"Bash(az deployment group what-if:*)",
|
|
14
|
+
"Bash(az deployment sub what-if:*)",
|
|
15
|
+
"Bash(az bicep build:*)",
|
|
16
|
+
"Bash(bicep build:*)",
|
|
17
|
+
"Bash(az keyvault list:*)",
|
|
18
|
+
"Bash(az keyvault show:*)",
|
|
19
|
+
"Bash(az acr show:*)",
|
|
20
|
+
"Bash(az acr list:*)",
|
|
21
|
+
"Bash(az postgres flexible-server show:*)",
|
|
22
|
+
"Bash(az postgres flexible-server list:*)",
|
|
23
|
+
"Bash(az containerapp show:*)",
|
|
24
|
+
"Bash(az containerapp list:*)",
|
|
25
|
+
"Bash(az containerapp revision list:*)",
|
|
26
|
+
"Bash(az monitor metrics list:*)",
|
|
27
|
+
"Bash(az monitor log-analytics query:*)",
|
|
28
|
+
"Bash(azd provision --preview:*)",
|
|
29
|
+
"Bash(azd env list:*)"
|
|
30
|
+
],
|
|
31
|
+
"deny": [
|
|
32
|
+
"Bash(az deployment group create:*)",
|
|
33
|
+
"Bash(az deployment sub create:*)",
|
|
34
|
+
"Bash(az group delete:*)",
|
|
35
|
+
"Bash(az resource delete:*)",
|
|
36
|
+
"Bash(azd up:*)"
|
|
37
|
+
]
|
|
38
|
+
},
|
|
39
|
+
"mcpServers": {
|
|
40
|
+
"microsoft-docs": {
|
|
41
|
+
"type": "http",
|
|
42
|
+
"url": "https://learn.microsoft.com/api/mcp"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: azure-deployment-preflight
|
|
3
|
+
description: Preflight validation for Azure infrastructure deployments (Bicep/ARM). Run before any az deployment / azd up. Validates templates (bicep build, az deployment group validate / what-if), cleans up stale failed ARM deployments that block re-deploy, catches globally-unique naming conflicts (Key Vault/ACR/etc.), and checks SKU/tier and service-limit restrictions. Carries the hard-won Bicep lessons (PgBouncer Burstable limit, alert module location, KQL interpolation, ACR SKU). Activate when the active cloud is Azure and the user mentions deploying, validating Bicep, what-if, preview, az deployment, azd provision, or deploy failures.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Azure Deployment Preflight
|
|
7
|
+
|
|
8
|
+
Validate Bicep/ARM deployments locally and clear blocking state *before* you deploy,
|
|
9
|
+
so CI doesn't discover what you could have caught. Supports both `az` CLI and `azd`
|
|
10
|
+
workflows. Continue through all steps even if one fails โ capture every issue, then fix
|
|
11
|
+
them in a batch.
|
|
12
|
+
|
|
13
|
+
> Discipline: **batch your fixes.** Each push triggers a ~15-30 min CI run. Read the
|
|
14
|
+
> entire failing module, reason about *all* potential issues, fix them all, push once.
|
|
15
|
+
> One CI run per problem cluster, not one per error message.
|
|
16
|
+
|
|
17
|
+
## When to use
|
|
18
|
+
|
|
19
|
+
- Before deploying infrastructure to Azure (`az deployment`, `azd up`, `azd provision`).
|
|
20
|
+
- When preparing or reviewing Bicep files.
|
|
21
|
+
- To preview what a deployment will change (what-if).
|
|
22
|
+
- To verify permissions are sufficient.
|
|
23
|
+
- After a failed deployment left ARM in a blocking state.
|
|
24
|
+
|
|
25
|
+
## Step 1 โ Detect project type & locate templates
|
|
26
|
+
|
|
27
|
+
- **azd project:** `azure.yaml` at root โ use the **azd workflow**. Bicep usually under
|
|
28
|
+
`infra/`. Otherwise use the **`az` CLI workflow**.
|
|
29
|
+
- **Locate `.bicep` files** (common: `infra/`, `infrastructure/`, `deploy/`, root) and
|
|
30
|
+
the matching parameter file per template: `<name>.bicepparam` (preferred) or
|
|
31
|
+
`<name>.parameters.json`.
|
|
32
|
+
- Determine the **deployment scope** from `targetScope` in the template
|
|
33
|
+
(`resourceGroup` default / `subscription` / `managementGroup` / `tenant`) โ it picks
|
|
34
|
+
the validate/what-if command in Step 3.
|
|
35
|
+
- Confirm context: `az account show` (subscription), resource group, location. Prompt
|
|
36
|
+
for any missing required value before proceeding.
|
|
37
|
+
|
|
38
|
+
## Step 2 โ Validate Bicep syntax
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
bicep build <bicep-file> --stdout # or: az bicep build --file <bicep-file>
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
> **`bicep build` / `az bicep build` only checks syntax.** It will **not** catch metric
|
|
45
|
+
> names, KQL scope, secret-ref mismatches, invalid property combinations, or naming
|
|
46
|
+
> collisions. Treat it as the first gate, not the gate.
|
|
47
|
+
|
|
48
|
+
If the Bicep CLI is missing, note it and continue โ Azure validates syntax during
|
|
49
|
+
validate/what-if anyway.
|
|
50
|
+
|
|
51
|
+
## Step 3 โ Full preflight validation (the real gate)
|
|
52
|
+
|
|
53
|
+
### azd projects
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
azd provision --preview # or --environment <env>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Standalone Bicep โ `az deployment ... validate` then `what-if`
|
|
60
|
+
|
|
61
|
+
`validate` catches deployment-time errors (property combos, secret refs, quota where
|
|
62
|
+
checkable) that `bicep build` misses. Pass dummy values for required secure params so
|
|
63
|
+
validation can run:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
cd infrastructure
|
|
67
|
+
az deployment group validate \
|
|
68
|
+
--resource-group <rg-name> \
|
|
69
|
+
--template-file main.bicep \
|
|
70
|
+
--parameters environments/<env>.bicepparam \
|
|
71
|
+
--parameters postgresAdminPassword="dummy" \
|
|
72
|
+
--parameters postgresAdminUsername="dummy"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**If it fails locally, fix it locally. Do not push and let CI discover it.**
|
|
76
|
+
|
|
77
|
+
Then preview changes with what-if (command by scope):
|
|
78
|
+
|
|
79
|
+
| targetScope | what-if command |
|
|
80
|
+
| --- | --- |
|
|
81
|
+
| `resourceGroup` (default) | `az deployment group what-if` |
|
|
82
|
+
| `subscription` | `az deployment sub what-if --location <loc>` |
|
|
83
|
+
| `managementGroup` | `az deployment mg what-if --management-group-id <id> --location <loc>` |
|
|
84
|
+
| `tenant` | `az deployment tenant what-if --location <loc>` |
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
az deployment group what-if \
|
|
88
|
+
--resource-group <rg-name> \
|
|
89
|
+
--template-file main.bicep \
|
|
90
|
+
--parameters environments/<env>.bicepparam \
|
|
91
|
+
--validation-level Provider
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**Fallback:** if `--validation-level Provider` fails on RBAC, retry with
|
|
95
|
+
`ProviderNoRbac` and note in the report that the user may lack full deploy permissions.
|
|
96
|
+
|
|
97
|
+
What-if change symbols: `+` create ยท `-` delete ยท `~` modify ยท `=` no change ยท `*`
|
|
98
|
+
ignored ยท `!` deploy (unknown). Flag any **delete** or replacement of a stateful
|
|
99
|
+
resource (PostgreSQL, Key Vault, storage).
|
|
100
|
+
|
|
101
|
+
## Step 4 โ Clean up stale failed ARM deployments
|
|
102
|
+
|
|
103
|
+
ARM tracks deployment records **by name**. A failed sub-deployment (e.g.
|
|
104
|
+
`<proj>-dev-alerts`) blocks a new run with **`DeploymentActive`** even while it sits in
|
|
105
|
+
`Failed`. Clean up before each new attempt:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
az deployment group list --resource-group <rg-name> \
|
|
109
|
+
--query "[?properties.provisioningState=='Failed'].name" -o tsv \
|
|
110
|
+
| grep -v "Failure-Anomalies" \
|
|
111
|
+
| xargs -I{} az deployment group delete --name {} --resource-group <rg-name> --no-wait
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Step 5 โ Globally-unique naming conflicts
|
|
115
|
+
|
|
116
|
+
Several Azure resource types have **globally-unique** names, and names from a prior /
|
|
117
|
+
deleted deployment are either reserved or **soft-deleted** (Key Vault purge protection
|
|
118
|
+
keeps the name reserved). Parameterize the name and override on conflict:
|
|
119
|
+
|
|
120
|
+
| Resource | Typical default (gets taken) | Override pattern |
|
|
121
|
+
| --- | --- | --- |
|
|
122
|
+
| Key Vault | `<proj>-<env>-kv` | `<proj>-<env>-kv-<suffix>` |
|
|
123
|
+
| Storage account | `<proj><env>sa` (3-24, lowercase alnum) | append short unique suffix |
|
|
124
|
+
| ACR | `<proj><env>acr` | append short unique suffix |
|
|
125
|
+
| Redis / Service Bus / Front Door / App | `<proj>-<env>-<x>` | `...-<suffix>` |
|
|
126
|
+
|
|
127
|
+
**Pattern:** add `param keyVaultName` / `param <x>Name` to `main.bicep` and set the
|
|
128
|
+
override in `environments/*.bicepparam` โ don't hard-code the bare default. If a script
|
|
129
|
+
(e.g. a Key Vault seeder) defaults the name internally, **pass the override explicitly**
|
|
130
|
+
and make every workflow step that references it use the same resolved name.
|
|
131
|
+
|
|
132
|
+
## Step 6 โ SKU / tier & known Bicep gotchas (hard-won)
|
|
133
|
+
|
|
134
|
+
These were discovered the expensive way โ don't rediscover them.
|
|
135
|
+
|
|
136
|
+
- **ACR SKU:** `Basic` may be unavailable on some subscriptions (e.g. Microsoft for
|
|
137
|
+
Startups). `Standard` works but **`retentionPolicy` requires `Premium`** โ remove it
|
|
138
|
+
from dev/staging. If a failed deploy left a broken ACR, create it manually then let
|
|
139
|
+
Bicep treat it as no-change.
|
|
140
|
+
- **PgBouncer not on Burstable:** dev/staging on `Standard_B*` (Burstable) cannot run
|
|
141
|
+
PgBouncer (needs GeneralPurpose+). Guard it:
|
|
142
|
+
`resource pgBouncer ... = if (currentSku.tier != 'Burstable') { ... }`.
|
|
143
|
+
- **Alert module location:**
|
|
144
|
+
- `Microsoft.Insights/metricAlerts` โ `location: 'global'` โ
|
|
145
|
+
- `Microsoft.Insights/scheduledQueryRules` โ `location: 'global'` โ; use the real
|
|
146
|
+
region (e.g. `eastus2`).
|
|
147
|
+
- `scheduledQueryRules` must scope to the **Log Analytics workspace ID**, not the App
|
|
148
|
+
Insights ID โ the `AppRequests` table lives in the workspace.
|
|
149
|
+
- **KQL in Bicep:** queries in `'''` verbatim strings **do not interpolate** `${vars}`
|
|
150
|
+
โ build the query with string-concatenation variables instead.
|
|
151
|
+
- **Metric names:** PostgreSQL Flexible Server uses `active_connections`, not
|
|
152
|
+
`connection_percent` (that's Azure SQL).
|
|
153
|
+
|
|
154
|
+
## Step 7 โ Check for an in-flight deploy before triggering
|
|
155
|
+
|
|
156
|
+
If CI auto-deploys on push to a branch, don't fire a manual deploy on top โ the auto-run
|
|
157
|
+
wins and yours sits queued (the user has to cancel it).
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
gh run list --workflow="<deploy workflow>" --limit 3
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
If a run is `queued`/`in_progress`, wait.
|
|
164
|
+
|
|
165
|
+
## Step 8 โ Report
|
|
166
|
+
|
|
167
|
+
Summarize: validation + what-if results (creates / modifies / **deletes** /
|
|
168
|
+
replacements), stale deployments cleaned, naming overrides applied, SKU/tier issues, and
|
|
169
|
+
whether it's safe to deploy. Note any `ProviderNoRbac` fallback (permission gap).
|
|
170
|
+
|
|
171
|
+
## Tool requirements
|
|
172
|
+
|
|
173
|
+
`az` CLI 2.76+ (for `--validation-level`), `azd` (azd projects), `bicep` CLI, `gh` (if
|
|
174
|
+
CI-driven). Verify auth: `az account show` / `azd auth login`. For deep Azure service
|
|
175
|
+
docs, use the `microsoft-docs` skill (Microsoft Learn MCP).
|