AI, Can! for VS Code
Deploy ai-can — to Azure or to Cloudflare Edge — and audit it for misconfigurations, both from inside VS Code, in the order that actually works.
This extension does three distinct jobs. They don't require each other, but if you're doing more than one, do them in this order:
- Choose a deployment target —
AI, Can!: New Project opens with exactly this question. Azure Managed Application is the original, self-hosted-in-your-tenant path; Cloudflare Edge is the Artemis-hosted, multi-tenant SaaS SKU. Everything below forks on this choice.
- Deploy — a strict, six-step pipeline either way, from first setup to a running deployment. Each step produces the file or resource the next step needs; skipping ahead fails fast with a message telling you which step to go back to.
- Audit —
AI, Can!: Scan Workspace, which you can run at any time, before deploy exists, mid-deploy, or against a deployment that's been live for a year. Azure-only today — see Auditing.
Table of Contents
Before you start: requirements
Check these off before you open the walkthrough — several deploy steps fail immediately without them, and the failure won't always point back here. Requirements differ depending on which deployment target you choose; only the first row applies to both.
Azure Managed Application
| Requirement |
Needed for |
Notes |
| VS Code 1.100.0+ |
Everything |
— |
| A Partner Center private-plan link |
Step 1 (Marketplace) |
Get this from whoever manages the ai-can private offer before you start. Step 1 will tell you to stop and get one if you don't have it. |
Azure CLI (az) |
Steps 2–4, and the optional live audit |
Install below. You don't need to sign in ahead of time — the first command that needs it prompts you. |
| A sufficient Azure subscription role |
Step 3 (Bootstrap) |
Owner, User Access Administrator, or Contributor on the subscription, plus Entra ID Application Administrator, plus Global Administrator or Privileged Role Administrator to grant admin consent. The extension checks the subscription-level role automatically before Step 3 and warns if it's missing; the Entra ID roles aren't checkable via Azure Resource Manager, so verify those yourself. |
Terraform CLI (terraform) |
Steps 5–6 |
Not installed by this extension. Terraform Plan, Terraform Apply, and Show Deployment Outputs all shell out to your local terraform binary — install it via the official guide before you reach Step 5. Plan/Apply also let you store the plan in Cloudflare R2 or Azure Blob Storage instead of locally — optional, defaults to Local Disk, and only needs a signed-in wrangler/az session if you pick one of them. |
sudo / admin rights on your machine |
Step 3 (Bootstrap) |
On macOS/Linux, the bootstrap script runs via sudo and will prompt for your local account password in the integrated terminal — that's your machine's password, not an Azure credential. |
Install Azure CLI:
| Platform |
Install |
| Windows 11 |
winget install Microsoft.AzureCLI, or the MSI installer |
| macOS |
brew install azure-cli, or the official guide |
| Linux |
curl -sL https://aka.ms/InstallAzureCLIDeb \| sudo bash (Debian/Ubuntu), or your distro's package per the official guide |
Cloudflare Edge
| Requirement |
Needed for |
Notes |
| VS Code 1.100.0+ |
Everything |
— |
| A Cloudflare account with Workers for Platforms |
Step 1 (Configure Account) onward |
The whole SKU depends on a dispatch namespace, which requires this entitlement. Prompted for account id and zone id — find both on the Cloudflare dashboard's Overview pages. |
| An AI Gateway created in the dashboard |
Step 1 onward |
Named to match AI_GATEWAY_ID in the wrangler configs (artemis-edge by default). Nothing in this pipeline provisions it — create it by hand before deploying, or inference calls fail at runtime. |
Terraform CLI (terraform) |
Step 2 |
Same binary as the Azure path, pointed at cloudflare-edge/terraform instead of infrastructure/. Same optional Cloudflare R2/Azure Blob Storage choice for the plan too, defaulting to Local Disk. |
| A scoped Cloudflare API token |
Step 2, Step 4 |
Account-level Workers Scripts:Edit, Workers KV:Edit, D1:Edit, Queues:Edit, Vectorize:Edit, Access:Edit; zone-level Zone WAF:Edit, DNS:Edit. Prompted for fresh each time it's needed and never written to disk — see Security and privacy. |
npx / Node.js |
Steps 3–5 |
Wrangler is invoked as npx wrangler, not a separately installed CLI. The first Wrangler command in a session prompts you to run wrangler login (opens a browser) if you're not already signed in — same "check, then offer to sign in" shape as the Azure CLI flow. |
A cloudflare-edge/ folder in your workspace |
Everything |
This is the ai-can repo's Cloudflare Edge SKU source (cloudflare-edge/) — open that folder, or a workspace containing it, before running any Cloudflare Edge command. If Configure Cloudflare Account doesn't find it, it offers to reopen VS Code at the right folder for you, or (new-environment case only) to scaffold a fresh cloudflare-edge/terraform module — see Step 1. |
| ⚠ R2 enabled on the account |
Optional |
Not required to complete the pipeline — FEATURE_R2_ENABLED defaults off and artifacts fall back to inline D1 storage. See cloudflare-edge/README.md §2 if you need it. |
Choosing a deployment target
Run AI, Can!: New Project. The very first prompt is Deployment Target (1/6):
- Azure Managed Application — Sovereign / self-hosted in your own Azure tenant. The original path this extension has always driven:
infrastructure/, a Managed Application, a zero-trust network. Picking this continues into the same four prompts (project name, environment, region, deployment profile) as before, just renumbered 2/5–5/5.
- Cloudflare Edge — Artemis-hosted, multi-tenant Workers for Platforms SaaS (AI, Can! Edge). No Azure account needed; shared-tenant SaaS, not sovereign — no data-residency guarantee, no CMK, inference runs on Cloudflare's GPUs. Picking this sets the workspace's target and offers to jump straight into Configure Cloudflare Account, the first step of that pipeline.
The choice is stored per-workspace and controls which six-step pipeline the sidebar's Pipeline view, the Command Palette, and the Walkthrough picker all show next. Change your mind later with AI, Can!: Switch Deployment Target — it doesn't touch any files, just which pipeline the extension is pointed at.
A workspace that has never run New Project (or Switch Deployment Target) defaults to Azure — existing workspaces from before Cloudflare Edge existed behave exactly as they always did.
The Azure deploy pipeline, step by step
Open View → Open Walkthrough → AI, Can!: Deploy to Azure to run these in order with progress tracked automatically — VS Code checks off each step as its command completes, and you can close VS Code and resume later without losing your place. Or run each command from the Command Palette (Cmd+Shift+P / Ctrl+Shift+P) yourself; the dependency chain is the same either way.
Prefer a persistent checklist you don't have to reopen? The AI, Can! icon in the Activity Bar shows this same pipeline as a sidebar — see The AI, Can! sidebar.
Each step below names exactly what it needs from the step before it, and exactly what it produces for the step after — that chain is the whole reason order matters here. As of 0.1.8, Bootstrap, Configure Infrastructure, and Terraform Plan each also offer to jump straight into the next step when they succeed — a shortcut past the Command Palette, never a chain you can't opt out of (Not Now always leaves you exactly where the command already left you). As of 0.1.10, New Project offers the same shortcut for Step 2 — see the New Project note under Step 4.
1. Open Private Offer → 2. Fetch Staged Artifacts → 3. Run Bootstrap Script
(Marketplace/Portal) (infrastructure/*.tf, (Terraform backend +
terraform.tfvars.example) service principal)
│
▼
6. Show Deployment Outputs ← 5. Terraform Plan → Apply ← 4. Configure Infrastructure
(endpoint URLs, etc.) (creates real resources) (terraform.tfvars)
1. Open Private Offer in Marketplace
Requires: your Partner Center private-plan link (see Requirements).
Produces: a deployed Managed Application whose storage account holds ai-can's Terraform code — not yet visible in your workspace.
Run AI, Can!: Open Private Offer in Marketplace. It confirms you have your private-plan link, then opens portal.azure.com — from there go to Marketplace → Private products → your offer → Create.
This step only stages the codebase into a storage account — it deploys no infrastructure. That surprises people who expect "Create" in the Portal to mean "provisioned." It doesn't, yet.
2. Fetch Staged Artifacts
Requires: the Managed Application name and resource group from Step 1, and to be signed in to the Azure CLI (you'll be prompted if not).
Produces: infrastructure/*.tf and infrastructure/terraform.tfvars.example in your open workspace folder.
Run AI, Can!: Fetch Staged Artifacts. It resolves the Managed Application's managed resource group, finds the storage account inside it, and downloads the artifacts container into your workspace. This is the step that actually puts Terraform code where you can read, configure, and version-control it.
Once the download is verified against the bundle's own SHA256SUMS checksums, everything lands directly at your workspace root — infrastructure/, frontend/, ci-cd/, and so on — exactly as if you'd git cloned the product repo into it. (As of 0.1.10: earlier versions left the download nested one level too deep, under an artifact/ folder the rest of the pipeline never looked at — see the terraform.tfvars.example troubleshooting entry if you're stuck with one of those from an old fetch.) Re-running this command refreshes the bundle in place, overwriting whatever an earlier fetch left there.
If the download reports success but no SHA256SUMS manifest turns up afterward, the "artifacts" container itself was empty — double-check the Managed Application name and resource group you entered actually match what you deployed in Step 1.
You need a workspace folder open before running this — File → Open Folder first if you started from an empty editor.
3. Run Bootstrap Script
Requires: nothing you have to do by hand first. If infrastructure/bootstrap/scripts/setup.sh (or .ps1) isn't in your workspace yet, the command runs Step 2's fetch for you inline (or lets you point at a local folder that already has it) — you don't need to have run "Fetch Staged Artifacts" separately, and there's no dead end if you jump straight to this step. If the inline fetch succeeds but the script still isn't found afterward (an old or incompatible bundle), you get an explicit error saying so, rather than the command silently doing nothing.
Produces: the remote Terraform state backend and a service principal that Steps 5–6 authenticate with.
Run AI, Can!: Run Bootstrap Script. It asks for environment and region, checks your signed-in account has a sufficient subscription role (warns, doesn't hard-block, if not — see Requirements), then runs the setup script as a VS Code Task streaming into the integrated terminal.
On macOS/Linux this runs via sudo and the integrated terminal will prompt for your local machine password. That's expected — it's not asking for an Azure credential. The extension also makes sure the script is executable before running it — az storage blob download doesn't preserve the Unix executable bit the way git clone would, so both "Fetch Staged Artifacts" (right after a successful download) and this step (right before running) set it, matching the chmod +x setup.sh the manual CLI instructions have you run yourself.
Once the script finishes, the extension offers to jump straight into Configure Infrastructure (Step 4) — click through, or Not Now to do it later from the Command Palette or Pipeline sidebar.
Requires: infrastructure/terraform.tfvars.example — again, Step 2's output. The command errors out immediately if it isn't there yet.
Produces: infrastructure/terraform.tfvars, the file Steps 5–6 actually deploy from.
Run AI, Can!: Configure Infrastructure. It's the CLI equivalent of the web "Advanced Configuration" page: the same 16 sections, the same validation rules, the same merge logic that produces terraform.tfvars. If a terraform.tfvars already exists in the workspace, this resumes from its current values instead of starting blank.
There's also a non-interactive path for scripted setups: call the ai-can.configureInfrastructure command with an { answersFile: "<path.json>" } argument (e.g. from a tasks.json entry or another extension) — there's no literal --answers flag to type into the Command Palette itself, since the Palette can't pass arguments to a command.
Shortcut for a first deploy: AI, Can!: New Project writes a working terraform.tfvars in one pass from a handful of quick prompts (sign-in/subscription, project name, environment, region, a Lean or Full zero-trust profile, and how to handle DDoS protection) instead of all 16 sections — good for getting to Step 5 fast. Before it writes anything, it also runs a subscription preflight — resource-group name collisions, resource-provider registration, CIDR overlap against your subscription's existing VNets, VM SKU availability — and shows the results in a panel, so a likely-fatal problem surfaces in seconds instead of after a failed terraform apply minutes later. It still needs Step 2's infrastructure/ folder underneath it to actually plan or apply against, but as of 0.1.10 it checks for that itself: if infrastructure/bootstrap/scripts/setup.sh (or .ps1) isn't in the workspace yet, New Project offers to run Fetch Staged Artifacts right there before asking about the bootstrap script — so a first deploy no longer needs you to separately discover and run Step 2 by hand.
Once terraform.tfvars is written, the extension offers to jump straight into Terraform Plan (Step 5).
Requires: infrastructure/terraform.tfvars (Step 4) and the actual .tf files (Step 2) in the same infrastructure/ folder, plus the terraform CLI on your PATH. Also looks for infrastructure/set-env.sh (Step 3's output) to authenticate as the sp-terraform-aican Service Principal — see the authentication note below. Choosing Cloudflare R2 or Azure Blob Storage below also needs a signed-in wrangler/az session — you're prompted to sign in inline if you aren't.
Produces: a reviewed plan file (Plan), then real Azure resources (Apply).
Authentication: before running Terraform at all, both commands read infrastructure/set-env.sh and inject its ARM_CLIENT_ID/ARM_CLIENT_SECRET/ARM_TENANT_ID/ARM_SUBSCRIPTION_ID into that one Task's environment, so terraform authenticates as the least-privilege sp-terraform-aican Service Principal Bootstrap (Step 3) provisioned — not your own signed-in identity. This is never silent: if the file is missing, or missing one of those four values (e.g. a credential reset that failed partway through), you get a warning with an explicit Continue with az login choice before Terraform falls back to whatever az login session is ambient. Choosing Run Bootstrap Script from that warning jumps back to Step 3 to fix it. As of 0.1.8 — earlier versions had no way to reach the Service Principal's credentials from Plan/Apply at all.
Run AI, Can!: Terraform Plan first. It asks where to store the plan — Local Disk (the default), Cloudflare R2, or Azure Blob Storage. Choosing R2 or Azure Blob adds one more check before terraform ever runs: the extension confirms the bucket/container you named actually exists (a quick, read-only wrangler r2 bucket list / az storage container exists call) and, if it doesn't, asks — with an explicit Create Bucket/Create Container confirmation, never silently — whether to create it right there. This is what catches a typo'd or never-created destination in seconds, instead of after a multi-minute terraform plan only to fail on the upload at the very end. Once that's settled, it runs terraform init -input=false && terraform validate && terraform plan -out=tfplan -input=false, each phase logged as its own labeled step so the terminal reads as a clear step-by-step run rather than a wall of raw output. (-input=false matters here: a required variable with no default fails immediately with a specific error instead of silently blocking the Task forever on an unanswerable prompt.) It renders the result as a color-coded create/update/destroy summary (readable even at 200 resources on the Full zero-trust profile) and, for R2/Azure Blob, uploads tfplan plus a plain-text summary — authenticated via your already-signed-in wrangler/az session, never a new credential prompt. For R2 specifically, each file is immediately read back right after its upload to confirm it's actually retrievable, so a put that reports success but isn't really there can't reach Apply undetected — the success message says "(verified readable back from R2)" when this happens. A failure shows the actual Terraform (or storage CLI) error text, read back from a log file, with an Open Log button — not just "see the terminal above" — and for a storage upload failure specifically, a likely cause and fix (expired wrangler/az session, missing bucket/container, R2 not yet enabled on the account, no network) is appended automatically when the extension can identify one from the CLI's own error text. Once Plan succeeds, it offers to jump straight into Terraform Apply — review the plan first; this offer is just a shortcut past the Command Palette, it doesn't skip Apply's own separate confirmation below.
Run AI, Can!: Terraform Apply only when the plan looks right. It asks the same storage question, and for R2/Azure Blob checks the bucket/container exists (same as Plan, but without offering to create it — an empty destination has nothing to download regardless) before attempting the download, then fetches the plan (with the same cause-and-fix diagnosis on a failed download — e.g. an object that was never actually uploaded reads as "the specified key does not exist", and the message points you back to check that Plan's own Upload step succeeded), so Apply always runs against the exact file that was reviewed. Apply never runs automatically after Plan — it's a separate, explicit command that refuses to run until a plan exists (locally, or fetched from wherever you stored it), and asks for confirmation every time. terraform apply itself also runs with -input=false, same reasoning as Plan. An accidental apply is a real-money mistake here (Firewall + APIM StandardV2 + a build agent VM + Premium ACR on the Full profile), which is exactly why this extension keeps the two steps apart.
6. Show Deployment Outputs
Requires: a completed terraform apply (Step 5) in infrastructure/.
Produces: nothing new — just surfaces what you already have.
Run AI, Can!: Show Deployment Outputs to see terraform output — endpoint URLs, resource group names, the APIM gateway URL — rendered in the same results panel Plan uses, instead of raw Terraform JSON. Sensitive outputs are masked automatically.
You're done deploying. Now, or any time later, run the audit.
The Cloudflare Edge deploy pipeline, step by step
Open View → Open Walkthrough → AI, Can!: Deploy to Cloudflare Edge, or run each command from the Command Palette yourself — same two options as the Azure pipeline, same dependency chain either way. The sidebar's Pipeline view shows these six steps instead of the Azure ones once the workspace targets Cloudflare Edge.
1. Configure Cloudflare Account → 2. Terraform Plan → Apply → 3. Deploy Edge Workers
(terraform.tfvars) (dispatch namespace, KV, (control-plane schema,
D1, Queues, WAF, Access, outbound + tail Workers)
DNS records)
│
▼
6. Show Deployment Outputs ← 5. Deploy Dispatcher ← 4. Set Secrets
(ids, hostnames, etc.) (tenant bundle, dispatcher, (CLOUDFLARE_API_TOKEN,
CONFIG_KV/OAUTH_KV seed) generated ADMIN_API_KEY)
Requires: a Cloudflare account with Workers for Platforms, and its account id and zone id (see Requirements).
Produces: cloudflare-edge/terraform/terraform.tfvars.
Before you run this: create the AI Gateway by hand in the Cloudflare dashboard, named to match AI_GATEWAY_ID in the wrangler configs (artemis-edge by default). Nothing in this pipeline — not Terraform, not this extension — provisions it, and inference calls fail at runtime without it.
Run AI, Can! Edge: Configure Cloudflare Account. It first checks that cloudflare-edge/terraform actually has a Terraform module (.tf files) in this workspace — Cloudflare Edge's Terraform state is local-only and gitignored, not remote-backed, so there's exactly one real checkout with the live terraform.tfstate tracking the account's actual resources. If none is found here, you're offered Open the Correct Folder… (pick the ai-can checkout; if it has cloudflare-edge/terraform, VS Code reopens pointed at it) or Scaffold a New Module Here (writes a fresh main.tf/variables.tf, with an explicit warning first — only do this for a genuinely new environment, since a second local state next to an existing one can't see it, and a plan/apply there would propose to recreate resources that already exist).
Once the module's in place, four prompts — account id, zone id, edge hostname (defaults to edge.aican.dev, the live production value — must be that zone's apex or a subdomain of it), dispatch namespace (defaults to artemis-edge) — write cloudflare-edge/terraform/terraform.tfvars. Each field is validated as you type (account/zone id must be the 32-character hex id from the dashboard, not a login email or dashboard URL; hostname and namespace are checked against Cloudflare's actual naming rules), so a wrong value is caught immediately instead of surfacing later as an opaque terraform plan failure.
A fifth, optional step then offers to verify the account id, zone id, and edge hostname against the Cloudflare API before anything is written — you're prompted for a token (used once, in memory only, for this check) and the wizard loops you back to fix exactly the field that's wrong if verification fails, rather than aborting. That includes catching an edge hostname that doesn't actually belong to the verified zone (e.g. the zone resolves to aican.dev but the hostname is still pointed at some other domain) — a mismatch Terraform would otherwise only report at apply, when it fails to create the DNS record. You can skip verification. Your Cloudflare API token is never written to disk here, at this step or any other — see Security and privacy for why.
Once terraform.tfvars is written, the extension offers to run Terraform Plan immediately.
If you change the default hostname or namespace, you'll also need to hand-edit routes and dispatch_namespaces[0].namespace in the wrangler.*.jsonc configs to match — those two defaults are baked into the checked-in configs, not auto-patched.
Requires: Step 1's terraform.tfvars, the terraform CLI on your PATH, and your Cloudflare API token (prompted fresh, for Plan and again for Apply). Choosing Cloudflare R2 or Azure Blob Storage for the plan also needs a signed-in wrangler/az session — you're prompted to sign in inline if you aren't.
Produces: the account resources — dispatch namespace, KV namespaces, the control-plane D1 database, the usage and jobs Queues (plus their dead-letter queues), WAF and rate-limiting rulesets, the Access application, and the DNS records the dispatcher's routes need — then the wrangler.*.jsonc configs' REPLACE_ME ids patched in automatically.
Run AI, Can! Edge: Terraform Plan first — it checks that Step 1 has configured a Cloudflare account for this workspace and offers to run Configure Cloudflare Account if not, rather than prompting for a token it can't use yet. Once configured, it shows the same color-coded create/update/destroy summary as the Azure path, run against cloudflare-edge/terraform instead of infrastructure/, with -input=false on init/plan so a required variable with no value fails fast instead of hanging the Task on a prompt. It also asks the same storage question as Azure's Plan (Local Disk, Cloudflare R2, or Azure Blob Storage — the chosen bucket/container is checked for existence before terraform runs, with an explicit-confirmation offer to create it if missing; R2 uploads are also verified by an immediate read-back, and a failed upload's error message includes a likely cause and fix), logs each phase as its own labeled step, and on failure shows the real Terraform error text read back from a log file rather than "see the terminal above." Run AI, Can! Edge: Terraform Apply only when it looks right — same storage question, same up-front bucket/container existence check (without the offer to create — nothing to fetch from an empty one) and same cause-and-fix diagnosis on a failed download, downloading the plan first for R2/Azure Blob so Apply always runs against the exact file reviewed; same confirmation-required, never-runs-automatically discipline as Azure's Apply. Once Apply finishes (a real task exit, not just the command returning), the extension reads terraform output -json and patches CLOUDFLARE_ACCOUNT_ID, ACCESS_AUD, the CONFIG_KV binding id, and the control-plane database_id into all four wrangler configs. The OAUTH_KV namespace id is captured too, but cached rather than patched into a config file — wrangler.tenant.jsonc has no OAUTH_KV binding of its own, since real tenants get it wired in dynamically during provisioning; Step 5 (Deploy Dispatcher) reads the cached id back out to seed it into KV. Nothing here is copy-paste by hand.
3. Deploy Edge Workers
Requires: Step 2's account resources to exist, and a signed-in wrangler session (prompted via wrangler login if needed).
Produces: the control-plane D1 schema applied, plus the outbound Worker and tail Worker deployed.
Run AI, Can! Edge: Deploy Edge Workers. Runs migrate:control-plane, then deploy:outbound, then deploy:tail, as one Task. The outbound Worker has to exist before the dispatcher (Step 5) because the dispatch namespace binding references it by name — that's why this step comes before Set Secrets and Deploy Dispatcher, not after.
4. Set Secrets
Requires: the same Cloudflare API token as Step 2.
Produces: the dispatcher's own CLOUDFLARE_API_TOKEN secret (it calls the Cloudflare API during tenant provisioning), a generated ADMIN_API_KEY, and — optionally — the tail Worker's LOG_SINK_URL/LOG_SINK_TOKEN secrets.
Run AI, Can! Edge: Set Secrets. Prompts for the API token once more, then generates the Admin API key for you — a 32-byte random value, never typed in. It's stored in VS Code's SecretStorage for this workspace and is what the Tenants panel authenticates with afterward; an information message offers to copy it to your clipboard if you need it elsewhere too.
You're then asked for an optional log sink URL (and, if you give one, a bearer token) — the tail Worker forwards redacted error/warning events there when set. Leave the URL blank to skip both; the SKU works fine without a log sink.
5. Deploy Dispatcher
Requires: Step 3 (outbound Worker must already exist) and Step 4 (secrets must already be set), plus the CONFIG_KV and OAUTH_KV ids cached from Step 2's Terraform outputs.
Produces: the tenant-worker bundle released, the dispatcher itself deployed — the control-plane API, the usage meter, the Workflows and queue consumers all go live here — and the CONFIG_KV/OAUTH_KV namespace ids seeded into KV, which the tenant-provisioning Workflow reads back to wire OAuth into every real tenant's Worker.
Run AI, Can! Edge: Deploy Dispatcher. This is the step that makes the Tenants panel actually work — projects created there don't provision until this has run at least once.
6. Show Deployment Outputs
Requires: a completed terraform apply (Step 2) in cloudflare-edge/terraform.
Produces: nothing new — just surfaces what you already have.
Run AI, Can! Edge: Show Deployment Outputs to see the dispatch namespace, KV and D1 ids, and the Access application audience, in the same results panel Azure's Plan/Outputs commands use. Sensitive outputs are masked automatically.
You're done deploying. Head to the Tenants panel to create your first project.
The Cloudflare Edge Tenants panel
A sidebar view — the Cloudflare Edge Tenants view under the AI, Can! Activity Bar icon — for managing projects on a deployed Cloudflare Edge stack. Unlike the Pipeline view, this isn't a one-time setup checklist: it's a live client for the dispatcher's own Admin API, useful any time after Deploy Dispatcher has run once.
Requires the edge hostname from Step 1 and the Admin API key generated in Step 4. If either is missing, the view shows a prompt instead of an error — configure the account and set secrets first.
- List — every non-deleted project, with its status (
provisioning / active / suspended) and plan shown inline, refreshed with the toolbar's refresh button (AI, Can! Edge: Refresh Tenants).
- Create (
AI, Can! Edge: Create Project, toolbar + button) — prompts for a project id, an owner email, and a plan (trial / edge / edge-plus), then shows the new MCP endpoint URL once provisioning starts.
- View Usage (click a project, or
AI, Can! Edge: View Usage) — reports usage ratio, cost, and margin to the "AI, Can! Edge — Tenants" Output channel.
- View Project Details (right-click a project →
AI, Can! Edge: View Project Details) — reports the full tenant record (plan, status, script name, D1/Vectorize/R2 resource names, BYO-provider setting, overage flag) to the same Output channel.
- Set Egress Policy (right-click a project →
AI, Can! Edge: Set Egress Policy) — a three-step prompt (allowlist or denylist mode, comma-separated hosts, whether to block private/loopback/link-local/cloud-metadata destinations) that updates the tenant's outbound egress policy.
- Delete (
AI, Can! Edge: Delete Project) — asks for confirmation first; stops dispatch immediately. The confirmation message tells you whether the project's resources were actually reclaimed — today that's normally not: D1, Vectorize, and the script are typically left allocated (deprovisioning is a follow-up job, not yet built — see cloudflare-edge/README.md §5). This deletes one tenant off an otherwise still-running platform — for tearing down the whole Cloudflare Edge deployment itself (every tenant on it, not just one), see the separate top-level AI, Can!: Delete Project command instead.
The Admin API key is the same "break-glass" automation credential the dispatcher's own control-plane.ts documents for humans and CI — this panel is exactly that kind of automation, not the Cloudflare Access human sign-in flow.
Deleting a project
AI, Can!: Delete Project is one command that asks Azure or Cloudflare, then what to tear down. It's deliberately not part of either six-step pipeline — no Walkthrough step, no Pipeline-view checkmark of its own — and, like everything else in this extension, nothing runs until you explicitly invoke it and then confirm.
Azure
After confirming you're signed in to the Azure CLI (prompts to az login if not, same as every other Azure command here), it asks which of two things to delete:
- Terraform Backend Storage Account — the storage account in
rg-terraform-state-<env> (created by Step 3's bootstrap script) that holds tfstate and any plan artifact uploaded via the Azure Blob storage option. Pick the environment, confirm or edit the resource group name (pre-filled as rg-terraform-state-<env>), and — if it holds more than one storage account — pick which one.
- Hub + Spoke Resource Groups —
<project>-<env>-hub-rg and -spoke-rg, named exactly as infrastructure/main.tf builds them: the resource groups holding everything Terraform Apply actually deployed. Provide the project name and environment (pre-filled from infrastructure/terraform.tfvars if it's in the workspace); the extension checks which of the two groups actually exist and only offers to delete those. This runs az group delete, not terraform destroy — reliable even if terraform.tfstate is stale, missing, or was never in this workspace at all.
Either way, a modal warning states exactly what's about to be destroyed, then you must retype the resource's exact name to proceed — the same confirmation the Azure Portal itself requires before a resource group delete. The delete then runs as a visible, verbose (--verbose) Task, logged to delete-storage-account.log / delete-resource-groups.log in the workspace root, and a success message confirms once it's done. Either flavor also clears the Pipeline sidebar's "Terraform Plan / Apply" and "Show Deployment Outputs" checkmarks — both leave Terraform's own view of the deployment invalid, so those steps shouldn't keep reading as done.
Cloudflare Edge
After confirming you're signed in to Wrangler and that Configure Cloudflare Account has actually run for this workspace, it prompts for a fresh Cloudflare API token (never stored — same as Plan, Apply, and Set Secrets) and runs a full terraform destroy against cloudflare-edge/terraform, logged to cloudflare-edge/terraform/tfdestroy.log. That tears down Worker routes, the DNS record for the configured edge hostname, and the dispatch namespace configuration itself.
This is deliberately the only flavor on the Cloudflare side — there's no per-account "resource group" to bulk-delete by id the way Azure has one. It is not the same command as AI, Can! Edge: Delete Project in the Tenants panel, even though they share a title: the Tenants panel version soft-deletes one customer's project off an otherwise still-running shared dispatch namespace via the Admin API; this one tears down the shared stack itself, taking every tenant still on it down with it. The warning modal says so explicitly, and — same Portal-style gate as Azure — you must retype the edge hostname exactly to proceed. On success it clears the Pipeline sidebar's checkmarks for Terraform Plan/Apply, Deploy Edge Workers, Set Secrets, Deploy Dispatcher, and Show Deployment Outputs, since the dispatcher, its secrets, and the KV/D1 resources those steps depend on no longer exist.
Both
Progress streams into the same dedicated Task terminal panel Plan/Apply already use, and a failure shows the actual CLI/Terraform error read back from the log file, with an Open Log button — the same failure-reporting shape as every other Task-based command in this extension, described in full under Terraform Plan → Terraform Apply.
Auditing: AI, Can! Scan Workspace
Azure only. This command scans .tf/.tfvars files and, optionally, a live Azure resource group — it has no Cloudflare Edge equivalent yet. Unlike the deploy steps, it has no prerequisites and no position in the pipeline — run it before you've written a line of Terraform, mid-configuration, or against a deployment that's been live for months.
1. Run the command. Cmd+Shift+P / Ctrl+Shift+P → AI, Can!: Scan Workspace.
2. Local scan result — a notification appears immediately, checking every .tf/.tfvars/.py/.js/.ts/.cs file plus a root .env and .gitignore in your open workspace:
AI, Can!: no misconfigurations found.
or
AI, Can!: 3 finding(s) — see the Problems panel.
Open the Problems panel (Cmd+Shift+M / Ctrl+Shift+M) for each finding: grouped by file, with severity, the exact line, the rule that fired (e.g. ai-can.free-tier-in-prod), and a message explaining the fix. Diagnostics are fully replaced on every run — fix an issue and re-run, and it clears with nothing stale left behind.
3. The live-check prompt appears right after, whether or not the local scan found anything:
Also check the live Managed Application? Enter its Azure Resource Group, or leave empty to skip
Press Esc or Enter on an empty box to stop here. Type a resource group name (e.g. contoso-prod-spoke-rg) to continue — this is the one point where auditing needs the Azure CLI and a sign-in, exactly like the deploy steps do.
4. Sign-in, if needed. Not installed → an error with an Install Guide button. Installed but not signed in:
AI, Can!: you are not signed in to the Azure CLI. Sign in to check the live resource group, or skip to keep this scan local-only.
Sign In opens an integrated terminal running az login — complete whatever it asks (usually a browser window, sometimes a device code), then click I've Signed In. Already signed in? This step is skipped silently.
5. Live scan runs, with a progress notification, then a result:
AI, Can!: no live misconfigurations found in contoso-prod-spoke-rg.
or
AI, Can!: 2 live finding(s) in contoso-prod-spoke-rg — see the "AI, Can! — Live Azure Scan" output channel.
6. Live findings open automatically in their own Output channel (Output panel → channel dropdown → "AI, Can! — Live Azure Scan"):
AI, Can! — live scan of resource group "contoso-prod-spoke-rg"
Run at 2026-08-10T17:12:01.112Z
[ERROR] contoso-ai-foundry (Microsoft.CognitiveServices/accounts)
ai-can.live-public-network-access
contoso-ai-foundry (Microsoft.CognitiveServices/accounts) has publicNetworkAccess = Enabled. AI, Can!'s
zero-trust profile reaches this resource over a private endpoint — this deployed resource is reachable
from the public internet right now.
[ERROR] contoso-ai-foundry (Microsoft.CognitiveServices/accounts)
ai-can.live-foundry-local-auth
contoso-ai-foundry still accepts API keys alongside Entra ID (disableLocalAuth is not true). This is the
live account, not the tfvars intent — set disable_local_auth = true and re-apply to force managed identity.
(Resource names and rule IDs above are examples — your own output will reflect your actual resource group.)
Click the AI, Can! icon in the Activity Bar (the left-hand icon strip) to open a sidebar with three views — a persistent alternative to the Walkthroughs and Output channels above, for anyone who'd rather glance at a sidebar than reopen a tab.
Pipeline — the current deployment target's six deploy steps as a checklist; it's the same view either way, showing whichever pipeline the workspace is currently pointed at. Each step shows whether it's done or still pending, and clicking a step runs its command directly, exactly as if you'd typed it into the Command Palette. Status is based on what's actually on disk or already run — for the Azure pipeline, "Fetch Staged Artifacts" and "Configure Infrastructure" show done as soon as infrastructure/terraform.tfvars.example and infrastructure/terraform.tfvars exist; for Cloudflare Edge, "Configure Cloudflare Account" works the same way against cloudflare-edge/terraform/terraform.tfvars, and the other five steps show done once their command has completed successfully at least once. If no folder is open, this view shows a prompt to open one.
Live Findings — results from the live-Azure scan (the resource-group check described in Auditing), grouped by severity instead of the flat scrolling list in the Output channel. Click a finding to open that exact resource in the Azure Portal. This view is empty until you run AI, Can!: Scan Workspace and enter a resource group at the prompt; the local scan's results always go to the Problems panel, not here. Azure only, like the scan itself.
Cloudflare Edge Tenants — the tenant-ops panel for a deployed Cloudflare Edge stack; see The Cloudflare Edge Tenants panel above for the full rundown of list/create/view usage/view details/set egress policy/delete.
Command reference
For lookup once you know the flow. The Pipeline step column shows where each command sits in its pipeline — "—" means it's independent of pipeline order.
Azure Managed Application
| Command |
Pipeline step |
What it does |
AI, Can!: New Project |
— (starts either pipeline) |
Deployment Target, then — if Azure — signs in and resolves which subscription (only asks if you have more than one), project name, environment, region, deployment profile, and how to protect this deployment's public ingress against DDoS traffic (None / Cloudflare / Azure DDoS Protection Plan — Cloudflare only offered for Lean, whose APIM is public by design). Runs a subscription preflight (resource-group name collisions, resource-provider registration, CIDR overlap against existing VNets, VM SKU availability) and shows the results in a panel before writing terraform.tfvars, instead of all 16 Configure Infrastructure sections. Offers to run Fetch Staged Artifacts (Step 2) first if the bootstrap script isn't in the workspace yet. |
AI, Can!: Open Private Offer in Marketplace |
1 |
Starts the Managed Application deploy from your Partner Center private-plan link. |
AI, Can!: Fetch Staged Artifacts |
2 |
Pulls the product's Terraform code out of the Managed Application's storage account and into the workspace. |
AI, Can!: Run Bootstrap Script |
3 |
Runs infrastructure/bootstrap/scripts/setup.sh/.ps1 as a Task, with a pre-flight check for a sufficient subscription role. Uses the subscription already resolved by New Project's sign-in gate (or its own, if run standalone) — no longer asks you to retype a subscription id. |
AI, Can!: Configure Infrastructure |
4 |
The CLI equivalent of the web "Advanced Configuration" page — same 16 sections, same validation, same terraform.tfvars output. Supports resuming from an existing terraform.tfvars (including a profile-generated one's apim_config override, so a Full zero-trust deployment's private-APIM posture survives a resume), and a non-interactive answersFile command-argument mode for automation. |
AI, Can!: Terraform Plan |
5 |
Reads infrastructure/set-env.sh to authenticate as sp-terraform-aican (warns and offers az login as a fallback if it's missing/incomplete). Checks terraform.tfvars/backend.tf agree on environment, and (for a Full zero-trust terraform.tfvars) that apim_config still matches that profile's private-ingress posture, before running anything. Asks where to store the plan (Local Disk / R2 / Azure Blob); for R2/Azure Blob, confirms the bucket/container exists first (offers to create it if not) before running init -input=false && validate && plan -input=false, each phase logged as its own step, then shows a color-coded create/update/destroy summary. R2 uploads are verified by an immediate read-back. A failure gets a specific diagnosis (unregistered resource provider, expired service-principal secret, state lock, Azure Policy denial, quota, name collision) alongside the raw log. Offers to jump into Terraform Apply once it succeeds. |
AI, Can!: Terraform Apply |
5 |
Same sp-terraform-aican authentication as Terraform Plan. Asks where the plan lives and fetches it first if remote, runs terraform init before applying (so a plan fetched to a fresh checkout still works), then applies it (-input=false) — never runs automatically after Plan, and always asks for confirmation first. That confirmation names the plan's actual change counts and every resource being destroyed/replaced, not just a generic "apply the reviewed plan?". A failed upload/download/apply gets a likely-cause-and-fix hint alongside the raw CLI error. |
AI, Can!: Configure DDoS Protection (Cloudflare) |
— |
For a Lean deployment that chose Cloudflare over the Azure DDoS Protection Plan: verifies a Cloudflare API token + zone (never stores the token), saves the zone id and public hostname, and — once Terraform Apply has produced APIM's gateway hostname — points that hostname at it as a proxied Cloudflare DNS record. Safe to run again (e.g. to save the config before Apply, then actually create the record after). |
AI, Can!: Show Deployment Outputs |
6 |
Shows terraform output — endpoint URLs, resource group names, the APIM gateway URL — with sensitive values masked. |
AI, Can!: Scan Workspace |
— |
Runs the local audit, then optionally the live Azure audit. Works at any point before, during, or after deploy. |
Cloudflare Edge
| Command |
Pipeline step |
What it does |
AI, Can! Edge: Configure Cloudflare Account |
1 |
Account id, zone id, edge hostname, dispatch namespace → cloudflare-edge/terraform/terraform.tfvars. |
AI, Can! Edge: Terraform Plan |
2 |
Same as Azure's Terraform Plan (storage choice, per-phase logging), run against cloudflare-edge/terraform. Prompts for the Cloudflare API token fresh — never stored. |
AI, Can! Edge: Terraform Apply |
2 |
Same as Azure's Terraform Apply (storage choice, fetch-before-apply). On success, patches the wrangler.*.jsonc configs' REPLACE_ME ids from the Terraform outputs. |
AI, Can! Edge: Deploy Edge Workers |
3 |
Applies the control-plane D1 schema, then deploys the outbound and tail Workers. |
AI, Can! Edge: Set Secrets |
4 |
Puts the dispatcher's CLOUDFLARE_API_TOKEN secret and generates a new ADMIN_API_KEY. |
AI, Can! Edge: Deploy Dispatcher |
5 |
Releases the tenant-worker bundle, then deploys the dispatcher and control plane. |
AI, Can! Edge: Show Deployment Outputs |
6 |
Shows terraform output for cloudflare-edge/terraform, sensitive values masked. |
AI, Can! Edge: Refresh Tenants |
— |
Refreshes the Tenants panel's project list. |
AI, Can! Edge: Create Project |
— |
Creates a new tenant via the deployed dispatcher's Admin API. |
AI, Can! Edge: View Usage |
— |
Reports a tenant's usage ratio, cost, and margin to an Output channel. |
AI, Can! Edge: View Project Details |
— |
Reports a tenant's full config record (plan, status, script name, resource ids, BYO provider, overage flag) to an Output channel. |
AI, Can! Edge: Set Egress Policy |
— |
Three-step prompt (mode, hosts, block-private-networks) that updates a tenant's outbound egress policy. |
AI, Can! Edge: Delete Project |
— |
Soft-deletes a tenant after confirmation (stops dispatch immediately); the confirmation reports whether its D1/Vectorize/script were actually reclaimed. |
Shared
| Command |
What it does |
AI, Can!: Switch Deployment Target |
Changes which pipeline the Pipeline view and Walkthrough picker show, without touching any files. |
AI, Can!: Delete Project |
Asks Azure or Cloudflare, then what to tear down — full details under Deleting a project. Azure: the Terraform backend storage account, or the hub + spoke resource groups (az group delete, not terraform destroy). Cloudflare: a full terraform destroy against cloudflare-edge/terraform — tears down the whole Edge deployment (every tenant on it, not just one; not the same command as AI, Can! Edge: Delete Project above). Both require retyping the exact resource name to confirm, Azure Portal–style, run as a verbose, logged Task, and clear the relevant Pipeline sidebar checkmarks on success. |
Every command activates on demand — you don't need a .tf/.tfvars file open first, though opening one also triggers activation.
The six local scan rules
| Rule ID |
Severity |
Fires on |
ai-can.plaintext-credential |
Warning |
AzureKeyCredential(...), or app code that assigns a quoted string literal to a variable named credential, in .py/.js/.ts/.cs source — ai-can injects AZURE_CLIENT_ID for managed identity, so a key credential shouldn't be necessary. |
ai-can.hardcoded-secret |
Warning |
A quoted value shaped like a Cognitive Services or storage account key (long, mixed letters+digits, or assigned to a key/secret/token-sounding name) in app code, .tfvars, or .env. |
ai-can.public-network-access |
Error |
public_network_access = true / "Enabled" inside a web_app_config, ai_foundry_config, cosmos_db_config, or app_storage_config block in a .tfvars file. |
ai-can.foundry-local-auth |
Error |
An ai_foundry_config block whose disable_local_auth is false or simply absent. |
ai-can.env-not-gitignored |
Error |
A .env file at the workspace root with no .gitignore entry that would exclude it. |
ai-can.free-tier-in-prod |
Error |
An App Service SKU of F1/F0/Free anywhere in a .tfvars file whose top-level env is "prod" or "staging". Carries the exact message: "Free tier apps disable automatically after 60 CPU-minutes/day — this will break production deploys." |
The three live Azure scan rules (optional)
Same intent as three of the rules above, checked against what's actually deployed instead of what a .tfvars file says — config drift shows up here even if your source of truth looks correct.
| Rule ID |
Severity |
Fires on |
ai-can.live-public-network-access |
Error |
A deployed AI Foundry account, Web App, Cosmos DB account, or Storage Account with publicNetworkAccess = Enabled. |
ai-can.live-foundry-local-auth |
Error |
A deployed AI Foundry account (kind = AIServices) whose disableLocalAuth isn't true. |
ai-can.live-free-tier |
Error |
A deployed App Service Plan on the F1/F0/Free tier — unconditional here, unlike the local rule, since an actual deployment is assumed to be real regardless of what env its .tfvars claims. |
Only these five resource types are checked; anything else in the resource group (networking, DNS, monitoring, etc.) is intentionally out of scope for this command.
Security and privacy
Azure Managed Application
- The local scan makes zero network calls. It reads files already present in your open workspace and nothing else.
- The live audit is opt-in and read-only. It only runs if you type in a resource group; it calls
az resource list / az resource show (read-only Azure Resource Manager calls) and nothing else.
Fetch Staged Artifacts is also read-only against Azure, but it does write to disk: it downloads the staged Terraform code into your workspace folder.
Configure Infrastructure and New Project write terraform.tfvars locally — no network call, but they do modify your workspace.
Run Bootstrap Script and Terraform Apply are not read-only. Bootstrap creates a Terraform state backend and service principal in your Azure subscription; sudo is used for local machine privileges, never sent anywhere. Terraform Apply provisions real, billable Azure resources; it always requires an explicit confirmation after you've reviewed a Plan.
- Storing the plan in Cloudflare R2 or Azure Blob Storage (optional, Plan/Apply) is the one new network call this pipeline makes outside Azure/Terraform itself — a read-only bucket/container existence check before Plan or Apply runs anything (and, only with your explicit confirmation, a create call if Plan finds it missing), an upload on Plan (for R2, immediately followed by a read-back of the same object to verify it actually landed, before Plan reports success), a download on Apply, all authenticated via your already-signed-in
wrangler/az session (see the Cloudflare section below), never a new credential prompt or anything written to disk beyond the plan file and its summary.
- The extension creates no new credential storage of its own. For sign-in itself,
az login's own credential cache is the only thing involved — the extension only ever asks whether you're signed in (az account show), never how. For the local scan, secret-shaped strings already in your files are only detected, never handled.
- One exception, by design: Terraform Plan/Apply read the
sp-terraform-aican Service Principal's secret out of infrastructure/set-env.sh (the file Bootstrap already wrote, gitignored — see Step 3) to authenticate Terraform as that Service Principal instead of your own identity. The value is read into the extension host once per Plan/Apply run and passed to that one Task's spawned process via a transient environment variable — the same "read once, hand to the process, never re-written or logged" pattern the Cloudflare API token uses below. Nothing new is written to disk, and if the file is missing or incomplete you're always asked explicitly before Terraform falls back to your az login session instead — see Step 5.
AI, Can!: Delete Project (Azure flavor) is the most destructive command in the extension — see Deleting a project. It authenticates the same way as every other Azure command here (your signed-in az session, nothing new stored), but both flavors permanently delete real Azure resources — a storage account (with its tfstate) or entire resource groups — with no undo. The only things standing between a slip and an actual deletion are the modal confirmation and retyping the exact resource name; there is no dry-run.
Cloudflare Edge
- The same "never store a credential" rule, extended the same way
az's does: wrangler commands rely entirely on wrangler login's own local session — the extension only ever asks wrangler whoami, never touches the underlying token.
- The Cloudflare API token is never written to disk, ever — not even in
terraform.tfvars. It's prompted fresh, in memory only, at Terraform Plan, Terraform Apply, and Set Secrets, passed to that one Task's spawned process via a transient environment variable, and discarded the moment the call that set it returns. A ShellExecution without an explicit env inherits the parent process's environment at spawn time (a snapshot, not a live reference), so clearing it afterward cannot affect the already-spawned process.
- One deliberate exception: the generated Admin API key. Set Secrets generates it (you never type or invent one) and stores it in VS Code's SecretStorage, scoped to that workspace. This is the one credential the extension holds — justified because it's the "break-glass, for automation" credential the dispatcher's own backend code documents, not a human Cloudflare login. It's what the Tenants panel authenticates with.
- Terraform Apply and Deploy Dispatcher are not read-only. Terraform Apply provisions real, billable Cloudflare resources and always requires explicit confirmation after a reviewed Plan, same as Azure's. Deploy Edge Workers, Set Secrets, and Deploy Dispatcher all push real code/config to your Cloudflare account.
- Storing the plan in R2 or Azure Blob Storage never touches a credential either — same as the Azure section above, authenticated via
wrangler/az's own signed-in session.
- The Tenants panel's Create/Delete/Set Egress Policy actions are live writes, and View Usage/View Project Details are live reads, all against the deployed dispatcher's Admin API. Delete asks for confirmation first and its result message names exactly what was and wasn't reclaimed.
AI, Can!: Delete Project (Cloudflare flavor) is the widest-blast-radius command in the extension — see Deleting a project. It's a real terraform destroy, gated by a fresh (never stored) API token prompt, a modal warning naming what's about to be torn down, and retyping the edge hostname to confirm — but once confirmed, it takes down the whole shared dispatch namespace, every tenant on it included, not just one. This is a different, much larger action than the Tenants panel's own AI, Can! Edge: Delete Project, which only ever affects the one tenant you right-clicked.
Both
- Nothing outside the pipelines above happens automatically. Every command does exactly one described thing when you invoke it — there's no auto-fix, no background provisioning, and no step that chains into the next without you explicitly running it.
Troubleshooting
| Symptom |
Likely cause / fix |
| Command doesn't appear in the Command Palette after installing |
Reload the window (Developer: Reload Window), or check the Extensions view shows "AI, Can!" as enabled, not disabled. |
| "No misconfigurations found" on a workspace you know has issues |
Confirm a folder is actually open (File → Open Folder, not just a loose file). Also check the file extension is one of .py/.js/.ts/.cs/.tf/.tfvars/.env/.gitignore. |
| The resource-group prompt doesn't seem to appear |
It shows immediately after the local-scan notification, and stays open until you type something or press Esc — easy to miss if you're looking at the Problems panel at that moment. |
| "the Azure CLI (az) was not found on PATH" |
Install it (see Requirements), then restart VS Code's integrated terminal — or all of VS Code — so it picks up the updated PATH. |
"terraform.tfvars.example was not found" on Configure Infrastructure, or "was not found in this workspace" on Run Bootstrap Script |
You're ahead of the pipeline — run Fetch Staged Artifacts (Step 2) first, so the infrastructure/ folder actually exists. As of 0.1.10, New Project also offers to do this for you inline once it notices the bootstrap script is missing. |
infrastructure/, frontend/, etc. exist but only inside an artifact/ folder, and every pipeline command still reports them as missing |
You fetched with an extension version older than 0.1.10, which left the download nested one level too deep. Move everything out of artifact/ up to the workspace root (merging into anything already there) and delete the empty artifact/ folder, or just re-run AI, Can!: Fetch Staged Artifacts on 0.1.10+ — a fresh fetch lands correctly and overwrites the old files in place. |
"couldn't fetch staged artifacts — ERROR: The specified container does not exist. ... ErrorCode:ContainerNotFound" on Fetch Staged Artifacts |
As of 0.1.11, the extension first checks whether the storage account has an artifacts container and, if not, falls back to it if there's exactly one container present — most likely causes if you still see this: (1) the Managed Application's staging deployment script hasn't finished yet or failed — check the Managed Application's deployment status and, in its managed resource group, the Microsoft.Resources/deploymentScripts resource's logs in the Azure Portal; or (2) the deployer typed something other than artifacts into the deployment wizard's "Target Container Name" field and the storage account also has more than one container, so the extension can't guess which one to use — confirm the actual container name in the Portal and re-run the command once the container exists. |
"no reviewed plan found" on Terraform Apply |
Run Terraform Plan first — Apply refuses to run without a plan file it can verify you've seen (locally, or fetchable from wherever you told Plan to store it). |
"terraform apply failed — Error: Too many command line arguments / Expected at most one positional argument" on Terraform Apply |
Fixed in 0.1.12 — Apply was invoking terraform apply tfplan -input=false, and Terraform's flag parser stops recognizing flags after the first positional argument, so -input=false was mistaken for a second one. Update the extension to 0.1.12+ and re-run Apply. |
| "no infrastructure/set-env.sh found" / "... is missing ARM_..." warning on Terraform Plan or Apply |
As of 0.1.8, Plan/Apply read infrastructure/set-env.sh (written by Bootstrap, Step 3) to authenticate as sp-terraform-aican instead of your own az login identity. Click Run Bootstrap Script to (re-)generate it, or Continue with az login if you deliberately want to plan/apply as yourself — e.g. an account with broader rights than the Service Principal was granted. |
Terraform Plan/Apply seems to be using the wrong Azure identity (resources created under your own account, not sp-terraform-aican) |
You likely dismissed the "Continue with az login" warning above, or infrastructure/set-env.sh doesn't exist yet. Re-run AI, Can!: Run Bootstrap Script, then Plan/Apply again. |
terraform: command not found on Plan, Apply, or Show Deployment Outputs |
Install the Terraform CLI (see Requirements) and restart VS Code's integrated terminal so it picks up the updated PATH. |
"has no Terraform configuration (.tf files) — nothing to plan" on Terraform Plan (Azure or Cloudflare Edge) |
The extension checked the target directory (infrastructure/ or cloudflare-edge/terraform/) before running terraform init and found no .tf files — usually means the wrong VS Code window/workspace folder is open, since that path is resolved relative to it. For Cloudflare Edge, run AI, Can! Edge: Configure Cloudflare Account instead of Terraform Plan directly — it catches this same situation first and offers to reopen the correct folder or scaffold a fresh module, rather than just erroring. |
"no Cloudflare account configured for this workspace yet" on AI, Can! Edge: Terraform Plan |
Run AI, Can! Edge: Configure Cloudflare Account first (Step 1) — the prompt offers to launch it directly. This is workspace-scoped, so configuring it with a different folder open doesn't count. |
"no Terraform configuration (.tf files) found" on AI, Can! Edge: Configure Cloudflare Account itself |
This is the same missing-module situation caught earlier, before any prompts — choose Open the Correct Folder… if you have an existing ai-can checkout elsewhere, or Scaffold a New Module Here only if this is genuinely a new environment (see Step 1 for why that second option needs care — local, gitignored Terraform state means two checkouts can't see each other's resources). |
| "plan succeeded locally, but uploading it failed" / "downloading the reviewed plan failed" |
The error message itself usually already names the fix — the extension recognizes common wrangler r2/az storage blob failure text and appends one: "the specified key does not exist" on download means Plan's own Upload step never actually completed (re-run Plan and confirm its Upload task ends in success this time); a missing bucket/container names the exact create command to run; an auth/session error points at wrangler login/az login; R2 never having been switched on for the account points at the Cloudflare dashboard (the only place that toggle lives); anything DNS/connection-shaped points at your network. Click Open Log for the full raw text if you need more, or switch to Local Disk. |
"R2 bucket ... doesn't exist yet" / "Azure Blob container ... doesn't exist yet" prompt on Terraform Plan |
Expected the first time you point Plan at a new bucket/container — click Create Bucket/Create Container to have the extension create it via your already-signed-in wrangler/az session (no key/credential is asked for), or Cancel and pick an existing one instead. Nothing is created without this explicit confirmation. |
"R2 bucket ... doesn't exist" / "Azure Blob container ... doesn't exist" error (not a prompt) on Terraform Apply |
Apply checks the destination exists before trying to download from it, but — unlike Plan — never offers to create one, since an empty bucket/container still has no plan in it. Run Terraform Plan first (it uploads into this same bucket/container), or double-check the bucket/container name matches what Plan actually used. |
Terraform Plan/Apply seems to hang with no output right after "Initializing the backend..."/terraform init |
As of 0.1.3, init/plan/apply all run with -input=false, so this should now fail immediately with a specific "no value for required variable" error instead — if you're still seeing a silent hang, you're likely running a terraform command directly (a custom Task, or the integrated terminal) rather than through an AI, Can! command, so the extension never got a chance to add that flag or prompt for its own inputs (e.g. the Cloudflare API token). Use the AI, Can!/AI, Can! Edge Terraform Plan/Apply commands, not a hand-rolled one, for a required variable's value to actually be supplied. |
| "Cloudflare R2 needs a cloudflare-edge/ folder in this workspace" when choosing R2 for the plan |
This can happen even on the Azure pipeline's Plan/Apply, since R2 uploads always run wrangler from cloudflare-edge/ (the one place it's installed) — open a workspace containing that folder, or choose Azure Blob Storage / Local Disk instead. |
| Bootstrap script prompts for a password and seems stuck |
That's sudo asking for your local machine password (macOS/Linux only) — type it into the integrated terminal and press Enter; nothing is displayed as you type, which is normal terminal behavior. |
| Bootstrap warns about an insufficient subscription role |
You need Owner, User Access Administrator, or Contributor on the subscription (see Requirements). The warning offers Run Anyway if you believe the check is wrong, but the script is likely to fail partway through without one of those roles. |
| The sign-in terminal opens but nothing seems to happen |
az login opens a browser window, or prints a device code to enter at a URL — complete that flow, then click I've Signed In back in VS Code. Still stuck? Run az account show yourself to check your actual sign-in state. |
couldn't list resources in "..." error |
Usually a wrong resource group name, or the signed-in account lacks at least Reader access to it. Run az group show --name <your-rg> yourself to check both at once. |
| Live scan completed but found nothing, though you expected an issue |
The live check only covers the five resource types in the live rules table — everything else in the resource group is out of scope by design. |
| Can't find the live scan results |
Output panel → channel dropdown → "AI, Can! — Live Azure Scan". It also opens automatically right after a live scan completes. |
| The Pipeline sidebar shows the wrong six steps |
It follows the workspace's deployment target. Run AI, Can!: Switch Deployment Target to change it. |
| "no cloudflare-edge folder found" / Cloudflare Edge commands seem to do nothing |
Open the ai-can repo (or a workspace containing its cloudflare-edge/ folder) — see Requirements. |
| "you are not signed in to Wrangler" |
Click Sign In — an integrated terminal runs wrangler login (opens a browser), then click I've Signed In back in VS Code. Still stuck? Run npx wrangler whoami yourself inside cloudflare-edge/ to check your actual sign-in state. |
| Terraform Plan/Apply for Cloudflare Edge asks for an API token every time |
That's intentional — see Security and privacy. It's never cached, so both Plan and Apply prompt for it fresh. |
| Terraform Plan/Apply (either pipeline) asks where to store the plan every time |
Also intentional — Apply always confirms where to fetch the plan from rather than assuming. Your last choice (and bucket/container name) is pre-filled, so it's usually just pressing Enter through a couple of prompts, not re-typing. |
| "Terraform outputs are missing access_aud / config_kv_id / ..." after Cloudflare Edge Apply |
Apply may not have finished, or failed partway through — check the integrated terminal's output, then re-run AI, Can! Edge: Terraform Apply. |
| "no cached CONFIG_KV id" on Deploy Dispatcher |
Run Terraform Plan / Apply (Step 2) for Cloudflare Edge first — Deploy Dispatcher needs the id Apply caches from the Terraform outputs. |
| The Cloudflare Edge Tenants view is empty with a configuration prompt |
Run AI, Can! Edge: Configure Cloudflare Account and AI, Can! Edge: Set Secrets — the panel needs both the edge hostname and the generated Admin API key before it can call the Admin API. |
AdminApiError / a project action fails with an HTTP status |
The message includes the dispatcher's own error detail and status code — e.g. 409 means a project id is already taken, 401/403 means the Admin API key is missing or wrong (re-run Set Secrets to generate a fresh one). |
AI, Can!: Delete Project keeps rejecting what I typed into the confirmation box |
That's intentional — see Deleting a project. It's an exact, case-sensitive match against the resource/hostname name shown in the prompt; anything else (a typo, extra whitespace, partial name) is treated the same as cancelling, not retried. |
"resource group ... doesn't exist — nothing to delete" on Delete Project (Azure) |
The name shown is either rg-terraform-state-<env> (Storage Account flavor) or <project>-<env>-hub-rg/-spoke-rg (Resource Groups flavor) — double-check the environment/project name you entered matches what was actually used to deploy (infrastructure/terraform.tfvars, if it's still in the workspace), or that you're signed in to the right subscription (az account show). |
"no storage accounts found in ..." on Delete Project → Terraform Backend Storage Account |
Either the bootstrap script (Step 3) hasn't run yet in this subscription, or the storage account was already deleted in a previous run. |
"no Cloudflare account configured for this workspace" on Delete Project → Cloudflare |
Same fix as elsewhere: run AI, Can! Edge: Configure Cloudflare Account first. This check happens before anything destructive, so seeing it means nothing was touched. |
Delete Project succeeded but the Pipeline sidebar still shows an earlier step (e.g. Configure Infrastructure / Configure Cloudflare Account) as done |
Expected — Delete Project only clears the steps whose resources it actually tore down (Terraform Plan/Apply and everything downstream); it never touches files on disk, so a step whose "done" check is terraform.tfvars existing (Configure Infrastructure / Configure Cloudflare Account) still reads as done. Delete the .tfvars file yourself, or run New Project/Configure Cloudflare Account again, if you want a genuinely clean slate. |
"terraform destroy failed" on Delete Project → Cloudflare |
Click Open Log for the real Terraform error. A common cause is drift — something in the stack was already deleted or changed outside Terraform (e.g. by hand in the Cloudflare dashboard) — re-running AI, Can!: Delete Project usually finishes the job; check the dashboard directly if it keeps failing on the same resource. |
License
Proprietary — © Artemis Industries. See the LICENSE file included with this extension for the full terms. Installing and using this extension (via the Marketplace or a .vsix) is permitted for working with ai-can; the source itself is not open for redistribution or reuse.
Learn more
The two deploy pipelines, audit commands, and sidebar above are pieces of a larger planned extension — terraform.tfvars IntelliSense, a live cost panel, and more are still ahead. For the Cloudflare Edge SKU specifically, see cloudflare-edge/README.md in the root of the ai-can repo — it documents the deployed architecture in depth, including what's fully implemented versus intentionally thin (a tenant deprovisioning workflow and Marketplace metering integration, notably, are not yet built).