Skip to content

docs(spec): Bicep-less Foundry agent init design (#8065)#8577

Open
hund030 wants to merge 5 commits into
mainfrom
spec/bicepless-foundry
Open

docs(spec): Bicep-less Foundry agent init design (#8065)#8577
hund030 wants to merge 5 commits into
mainfrom
spec/bicepless-foundry

Conversation

@hund030

@hund030 hund030 commented Jun 9, 2026

Copy link
Copy Markdown
Collaborator

Design spec for RFC #8065 — make azd ai agent init Bicep-less by default, with the azure.ai.agents extension owning provisioning via a custom provider named microsoft.foundry.

Summary

Moves infrastructure templates from Azure-Samples/azd-ai-starter-basic into the azure.ai.agents extension binary. azd ai agent init produces only azure.yaml and an agent code project — no infra/ directory. At azd provision time, the extension's own provisioning provider synthesizes Bicep in memory from azure.yaml and applies it. azd ai agent init --infra ejects on demand: same synthesis, written to ./infra/; subsequent provisions read from disk.

The azure.yaml shape is fixed by the Foundry azure.yaml reference: a single host: microsoft.foundry service per project, with nested agents:, deployments:, connections:, etc. This spec only changes how that file is provisioned; it does not redesign the YAML.

Key design decisions

  • host: microsoft.foundry — one consolidated service per Foundry project, with nested agents[], deployments[], connections[], toolboxes[], skills[], routines[]. Matches the reference doc.
  • infra.provider: microsoft.foundry — explicit declaration required until service-host-driven auto-routing lands. Reuses the custom provisioning provider framework from feat: Add provisioning provider support to extension framework #7482 (merged).
  • Brownfield via endpoint: URL — not ARM resource ID. Matches what Portal and az CLI show; deploy verb resolves ARM ID from endpoint when it needs control-plane access.
  • Three deploy modes per agent: docker:, runtime:, or image: (pre-built container). Exactly one is required; validator rejects two-or-none.
  • On-disk reuse after eject: extension reads ./infra/ when present, synthesizes otherwise. azure.yaml is never mutated by eject.
  • No --force flag for eject. To regenerate, the user deletes ./infra/ and re-runs the command.
  • Preview via ARM What-If — mirrors Core's Bicep provider (scope.go:132 uses WhatIfDeployToResourceGroup).

Scope

In scope: Bicep-less default behavior, eject command, embedded templates, ARM-backed synthesis only (Foundry project + model deployments + ACR when needed), schema relaxation to allow extension-named providers in infra.provider.

Out of scope:

  • azd deploy — agent code push and data-plane reconciliation (connections, toolboxes, skills, routines, agent definitions) are deploy's job, not provisioning's. This spec ends at "ARM resources are in place."
  • Data-plane YAML fieldsconnections:, toolboxes:, skills:, routines:, agent-level tools:/skill:, $ref: resolution. Synthesizer reads them only to skip them; deploy verb owns them.
  • Service-host-driven auto-routing (RFC Core Ask 1) — would remove the explicit infra.provider:. Defers to a future spec.
  • Unified azure.yaml schema (Unify Foundry agent configuration in azure.yaml #7962); incremental composition (Add connections, models, tools, and skills to Foundry Agent projects after init #8049); coexistence with non-Foundry services (use infra.layers[] as escape hatch).

Core changes collapsed. The original RFC asked Core to surface services.<svc>.uses and a typed services.<svc>.runtime on the extension-facing proto. With nested agents[], runtime lives inside the service body (read via additional_properties); no proto/struct/mapper plumbing needed. Down to one Core change: relax the infra.provider enum.

Related

Notes for reviewers

Doc-only PR. Adds docs/specs/bicepless-foundry/spec.md. No code changes — the spec is the implementation contract; code PRs follow.

Particular attention welcomed on:

  1. The "What the synthesizer ignores" table — is the data-plane / ARM split drawn at the right line?
  2. The Open Question and its proposed answer (drift detection on Deploy()).
  3. The eject "delete-and-rerun" model with no --force flag — does this match azd's broader UX posture?

Design spec for RFC #8065 — make `azd ai agent init` Bicep-less by

default with the `azure.ai.agents` extension owning provisioning.

Adopts the compromise of explicit `infra.provider: azure.ai.agents`

in azure.yaml (per PR #7482's custom provisioning provider framework),

deferring service-host-driven auto-routing to v0.3+. Covers in-memory

synthesis, on-disk reuse after eject, brownfield `resourceId:` flow,

5-step validation pipeline, and the small Core changes required to

surface `uses` / `runtime` on the extension-facing `ServiceConfig`.
@hund030 hund030 requested a review from therealjohn June 9, 2026 10:26
@hund030 hund030 marked this pull request as ready for review June 9, 2026 10:26
Copilot AI review requested due to automatic review settings June 9, 2026 10:26
@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown

🔗 Linked Issue Required

Thanks for the contribution! Please link a GitHub issue to this PR by adding Fixes #123 to the description or using the sidebar.
No issue yet? Feel free to create one!

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new design spec documenting the proposed “Bicep-less by default” experience for azd ai agent init, where the azure.ai.agents extension owns provisioning via a custom provisioning provider and can optionally “eject” generated Bicep to ./infra/.

Changes:

  • Introduces a detailed design spec for extension-owned provisioning + in-memory Bicep synthesis.
  • Defines activation/eject behavior, validation pipeline, and post-eject drift/UX expectations.
  • Outlines required (future) Core schema/proto surfacing for uses and a service-level runtime.

Comment thread docs/specs/bicepless-foundry/spec.md
Comment thread docs/specs/bicepless-foundry/spec.md
Comment thread docs/specs/bicepless-foundry/spec.md Outdated
Comment thread docs/specs/bicepless-foundry/spec.md Outdated
Comment thread docs/specs/bicepless-foundry/spec.md Outdated
hund030 added 4 commits June 10, 2026 14:17
Review-pass revisions on docs/specs/bicepless-foundry/spec.md:

- Fix Core Changes #1: Uses already exists on ServiceConfig (service_config.go:58) and the v1 schema (azure.yaml.json:234); the gap is proto-only. Runtime remains the larger gap. Rewrote the section narrative and trimmed the file-change table accordingly.

- Fix On-Disk Reuse table: azdFileShareUploadOperations is at infra/provisioning/manager.go:125, not :121. Disambiguated all four rows with full paths and 'call'/'gate' suffix.

- Fix Core Changes mapper range: mapper_registry.go:102-162 (was :139-161, which was a sub-slice).

- Remove all v0.2/v0.3+/0.1.x/0.2.x version markers; the spec doesn't own a release schedule.

- Trim Problem, Solution, Provider Resolution, Explicit Declaration, Brownfield, In-Memory Synthesis, and Embedded Templates sections; remove duplicate eject example; consolidate Post-Eject trade paragraph.

- Open Questions: drop --preview-bicep entry, add one-line proposals to the remaining two.
…ecision)

- Preview: replace 'Same as Deploy with validationOnly mode' with 'ARM What-If, mirrors Core's Bicep provider'. validationOnly hits ARM's /validate endpoint and returns template-validity errors; What-If hits /whatIf and returns a real change diff. Core's bicep provider uses WhatIfDeployToResourceGroup (cli/azd/pkg/infra/scope.go:132); the spec now matches.

- pathHasModule row: clarify that os.ReadDir returns NotExist on missing ./infra/, and the caller's 'err == nil && moduleExists' guard is what falls through. Prior wording 'returns false' was imprecise.
…y host, nested agents)

Adopts the consolidated YAML shape from
therealjohn/foundry-azd-config-preview/REFERENCE.md and trims the spec
accordingly.

Shape changes:
- Host: azure.ai.project + azure.ai.agent (two services, uses: link) ->
  microsoft.foundry (single service with nested agents[]).
- Provider name: azure.ai.agents -> microsoft.foundry (matches host
  kind, reads like an engine next to bicep/terraform).
- Brownfield signal: resourceId (ARM ID) -> endpoint (URL, matches
  Portal/CLI UX).
- Deploy modes: added image: as third option alongside docker:/runtime:.

Scope tightening:
- azd deploy explicitly out of scope (agent code push and data-plane
  reconciliation are deploy's job).
- Data-plane fields (connections, toolboxes, skills, routines,
  agent-level tools/skill, $ref) silently ignored by synthesizer; new
  field-skip table makes this explicit.
- Coexistence with non-Foundry services out of scope; infra.layers[]
  noted as escape hatch.

Core changes collapsed:
- Removed "Surface uses/runtime to extensions" as a Core ask. With
  nested agents[], the runtime is inside the service body (read via
  additional_properties); no proto/struct/mapper plumbing needed.
- Down to two Core changes: relax infra.provider enum, and the deferred
  auto-install (#7502).

Validation pipeline rewritten to match the new invariants. Per-agent
deploy-mode check now allows exactly one of docker/runtime/image.
Brownfield validation checks endpoint URL shape. Foundry server-side
templating syntax pass-through made explicit.
- Remove Core Changes section on auto-install (#7502 — already delivered
  by #7482; not a gap, not in our scope).
- Drop Open Question 2 (schema branch ownership with #7962). It was a
  coordination artifact, not a real dependency.
- Drop #7962 and #8049 References entries.
- Drop the forward reference to `azd ai agent add monitoring` (per #8049)
  from Embedded templates — monitoring is out of scope.
- Drop the auto-install Risks row.

Keeps #7962 and #8049 only as one-line out-of-scope pointers in the
Scope section.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants