Skip to content

Feasibility & Strategic Direction

This is the most detailed rung of the “how it works” ladder — start with Why FoundryGate? for the plain-English version or the system overview for the middle level.

FoundryGate’s premise: a drop-in Azure solution that provisions Microsoft Foundry models for agentic coding harnesses (Claude Code, Codex CLI) and gives platform teams cost management, per-developer quotas, rate limiting, and metrics in one deployment. This page assesses that premise against the Azure platform as of September 2026 and states the architecture decisions that follow. All claims trace to Microsoft Learn or Anthropic documentation current at that date.

Verdict

Feasible — and better-timed than when the project was specced. Every pillar now has a first-party Azure mechanism:

RequirementMechanismAssessment
Drop-in provisioning (Bicep)AIServices account + Anthropic/OpenAI deployments + APIM v2, Marketplace attestation inline✅ Fully supported
Monthly token quota per developerAPIM llm-token-limit with token-quota-period="Monthly" per subscription key✅ Native, GA, real-time
Transient TPM/RPM smoothingPer-developer TPM policy caps + backend pools + circuit breakers honoring Retry-After✅ Gateway-native
Per-developer metricsllm-emit-token-metric (dashboards) + ApiManagementGatewayLlmLog (billing-grade)✅ Native
Per-developer costToken telemetry × rate card⚠️ Buildable — not available from Azure Cost Management for Claude
Claude at large scaleMulti-region pools; no PTU exists for Claude⚠️ Structural ceiling remains
”One click” drop-inOne Bicep deploy + ~30-minute tenant prep checklist⚠️ Near, not absolute

What changed on the platform

Three developments since the original spec reshape the architecture:

1. APIM enforces monthly token budgets natively — in real time

The llm-token-limit policy (GA, all tiers except Consumption) supports, in one policy:

  • tokens-per-minute — rolling TPM cap per counter-key, returning 429 with Retry-After when exceeded.
  • token-quota + token-quota-period="Hourly|Daily|Weekly|Monthly|Yearly" — a fixed calendar-window token budget per counter-key, returning 403 when exhausted.

With counter-key="@(context.Subscription.Id)", each developer’s APIM subscription carries its own TPM cap and monthly budget, enforced on the request path with no sync lag. The original design — a Function polling Log Analytics every 15 minutes and suspending subscriptions — is no longer the enforcement mechanism. It survives as reconciliation: authoritative usage numbers for dashboards, drift detection, and audit.

2. APIM understands the Anthropic Messages API

On APIM v2 tiers (Basic v2 / Standard v2 / Premium v2), the LLM policies (llm-token-limit, llm-emit-token-metric) support the Anthropic Messages API schema alongside OpenAI Chat Completions/Responses — token metering works on Claude Code’s native /v1/messages traffic without format translation. This is the single most consequential fact for FoundryGate: it makes one gateway with two front doors (Anthropic-format for Claude Code, OpenAI-format for Codex CLI) fully meterable.

3. Claude on Foundry went GA with broader eligibility

  • Claude models are GA (claude-opus-5, claude-opus-4-8, claude-sonnet-5, claude-haiku-4-5 hosted on Azure; Anthropic-hosted variants for others).
  • Eligibility is no longer EA/MCA-E-only: any paid subscription with an active pay-as-you-go billing method qualifies (CSP, free-trial, student, and credit-only subscriptions remain excluded).
  • Rate limits are now cache-aware: RPM + uncached input TPM + output TPM. Cache reads don’t count against input TPM — a major effective-capacity win for Claude Code, which caches prompts aggressively.
  • Claude Code and Codex CLI both officially support Azure endpoints, and both accept an arbitrary base URL — pointing them at an APIM gateway is Microsoft’s documented pattern.

The architecture that follows

FoundryGate splits cleanly into a control plane and a data plane:

Control plane (FoundryGate app) — identity and lifecycle: Entra sync, APIM subscription key issuance/rotation/revocation, quota tier assignment, increase approvals, deployment provisioning/resizing, dashboards, audit.

Data plane (APIM v2 gateway) — everything on the request path: subscription-key auth, per-developer TPM caps and monthly budgets, token metric emission, backend pool routing with circuit breakers, retry-across-deployments on 429.

FoundryGate system diagram — data plane and control plane

FoundryGate system diagram. Real-time path: developer CLIs (Claude Code sends x-api-key, Codex CLI sends api-key) call the Azure API Management v2 gateway over HTTPS with a personal subscription key. The gateway has 2 front doors, /anthropic and /openai/v1, requires the subscription to belong to a tier product (Standard 5M tokens per month and 20K tokens per minute, Power 20M tokens per month and 40K tokens per minute, Unlimited with no monthly cap and 100K tokens per minute), applies the tier model allowlist and the llm-token-limit policy which returns 403 when the monthly quota is exhausted and 429 with Retry-After when the per-minute cap is hit, then routes with managed identity to backend pools with circuit breakers (Anthropic pool: priority 1 eastus2, priority 2 swedencentral; single OpenAI backend) and on to Azure AI Foundry accounts in eastus2 (primary) hosting claude-sonnet-4-5, claude-haiku-4-5, claude-opus-4-5, gpt-4-1-mini; swedencentral (pool-member) hosting claude-sonnet-4-5, claude-haiku-4-5, claude-opus-4-5. Gateway diagnostics stream LLM logs and token metrics to Log Analytics and Application Insights. Control plane, out of the request path: Entra ID signs users in and is the source of users and groups; the Blazor UI on Azure Static Web Apps calls FoundryGate.Api on Azure Container Apps, which stores state in Azure SQL through EF Core; FoundryGate.Functions run the monthly reset, usage reconciliation (reading ApiManagementGatewayLlmLog from Log Analytics, every 15 minutes) and an Entra directory sync daily at 02:00 UTC that reconciles users then groups from Microsoft Graph; Key Vault holds the APIM key-encryption key (no client secrets; Graph is called as each host's own managed identity). The API manages APIM subscriptions through the Management API: create under a tier product, regenerate both keys, move tier, delete. FoundryGate.Functions reaches the same Management API for one operation only — moving a subscription to another tier product when a reset resolves a new tier. Legend: solid azure arrows are the real-time enforcement path on the request; dashed grey arrows are telemetry and reconciliation, out of band; dashed amber arrows are control-plane calls for lifecycle and tiers.

Developer workstations
Claude Code → x-api-key · Codex CLI → api-key · one personal APIM subscription key per developer
HTTPS — every request carries the developer's key
Data plane Azure API Management v2 · the request path · enforcement happens here
Front door /anthropic
Anthropic Messages API — Claude Code
Front door /openai/v1
OpenAI Responses / Chat Completions — Codex CLI
fg-require-product — a key with no tier product is refused (403)
Standard
5M tokens / month
20K tokens / minute
Power
20M tokens / month
40K tokens / minute
Unlimited
no monthly cap
100K tokens / minute
Tier products — one llm-token-limit policy each, counter keyed on the subscription
model alias + allowlist → 403 monthly quota exhausted 429 + Retry-After per-minute cap
gateway managed identity → Foundry (no account keys anywhere)
Anthropic backend pool
priority 1eastus2 → priority 2swedencentral
circuit breaker per backend: 3 × 429/5xx in 30 s trips it, honours Retry-After · retry ×2 across the pool
OpenAI backend
primary region only
Azure AI Foundry — eastus2 (primary)
claude-sonnet-4-5 · claude-haiku-4-5 · claude-opus-4-5 · gpt-4-1-mini
Azure AI Foundry — swedencentral (pool-member)
claude-sonnet-4-5 · claude-haiku-4-5 · claude-opus-4-5
APIM diagnostic settings — LLM logs + token metrics, emitted by the gateway asynchronously
Log Analytics + Application Insights
ApiManagementGatewayLlmLog — per-request prompt / completion tokens, joined to the subscription (billing-grade) · llm-emit-token-metric — near-real-time dashboards
APIM Management API — API: create subscription under a tier product · regenerate both keys · move tier · delete
Functions: move tier only, when a reset resolves a new one
KQL rollup of ApiManagementGatewayLlmLog → usage reconciliation, every 15 min
Control plane FoundryGate app · out of the request path · lifecycle, tiers, reporting
Microsoft Entra ID
users · groups · sign-in · Graph sync
JWT
FoundryGate.Web
Blazor WASM · Static Web Apps
REST
FoundryGate.Api
ASP.NET Core · Container Apps · managed identity
EF Core
Azure SQL
Users · Groups · QuotaAllocations · Requests · AuditLog
FoundryGate.Functions
MonthlyReset — daily at 00:01 UTC, on the configured reset day · UsageSync — every 15 minutes, reconciliation
EntraSync — daily at 02:00 UTC: users then groups, from Microsoft Graph
.NET isolated worker + storage account (runtime, job locks) → Azure SQL via EF Core
Moves a subscription's tier product when a reset resolves a new one
Azure Key Vault
fg-apim-key-encryption key · no app secrets (Graph uses the API identity)
@KeyVault(...) references resolved at startup
real-time enforcement — on the request path telemetry & reconciliation — out of band control-plane calls — lifecycle & tiers Layout hand-drawn; the regions, tiers, model deployments, front-door paths and Function schedules above are generated from infra/ and src/ at build time.

The solid path is the only thing a developer’s request ever touches. The telemetry path (diagnostics → Log Analytics → reconciliation Function) can lag or fail without changing what the gateway enforces — it reports, it does not decide. The control plane’s management-plane calls are different: they select what the gateway enforces (which tier product a subscription lives under), so a failed call means the intended change never lands — but the previously configured limits keep being enforced meanwhile.

Quota tiers as products

Products (Standard / Power / Unlimited) carry the token-limit policies. Changing a developer’s budget = moving their subscription between products. Per-user arbitrary values are a PoC question (policy-expression support); tiers are the safe default.

Two front doors, one gateway

/anthropic/* passes Anthropic Messages traffic to Foundry for Claude Code; /openai/v1 serves Codex CLI’s Responses API. Each front door accepts the key in the header its CLI actually sends (wire-verified): x-api-key for Claude Code, api-key for Codex — which additionally needs env_http_headers in its config.

Pools instead of PTU

Claude has no provisioned throughput and no spillover. Backend pools with priority groups and circuit breakers that honor Retry-After are the equivalent: priority-1 deployment saturates → traffic drains to priority-2 (other region, DataZone, or hosting variant) automatically.

Cost from telemetry

Claude bills as one aggregate Marketplace CCU meter — Cost Management can’t split it by user or deployment. FoundryGate computes per-developer cost as tokens × rate card, reconciled from gateway logs.

How this solves the transient-limit problem

The rate limits reference documents the deployment-level ceilings. The gateway addresses the transient symptoms in three layers:

  1. Fairness before saturation — per-developer tokens-per-minute caps mean one developer’s agentic burst gets a targeted 429 + Retry-After (which Claude Code and Codex both back off on) instead of saturating the shared deployment for everyone.
  2. Absorption at saturation — when a deployment itself returns 429, the circuit breaker trips for that backend (honoring its Retry-After, which for AI backends can be long) and the pool retries the request against the next deployment. The client sees a slower response, not an error.
  3. Headroom by construction — pools multiply capacity across regions and deployment types. Claude quota pools are subscription-scoped and shared across regions for Global Standard, so pooling buys availability and burst diversity rather than raw multiplied TPM — pairing Global Standard with DataZone Standard or Anthropic-hosted variants diversifies actual capacity.

What APIM does not provide is queueing — there is no request-queue primitive. For interactive CLI workloads this is acceptable: the CLIs’ own backoff is the queue.

Honest caveats

What “drop-in” honestly means

One Bicep deployment provisions: the Foundry account, Claude + GPT deployments (with Marketplace attestation handled inline — no portal click-through), the APIM v2 gateway with products/policies/pools, SQL, the API container app, the static web app, Key Vault, and monitoring. Tenant prep that cannot be Bicep’d — roughly 30 minutes:

  1. An Entra app registration (redirect URI, FoundryGate.Admin app role, Graph permissions + admin consent).
  2. Billing eligibility for Claude: paid subscription with active pay-as-you-go billing method; deploying principal needs Marketplace/SaaS permissions (Microsoft.SaaS/register/action et al.).
  3. GitHub OIDC secrets for the Actions pipelines.

That checklist is the honest gap between “drop-in” and “one click” — documented in the fork guide rather than papered over.