You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Add opt-in AppHost Server v2 to the CLI bundle - #20897
Introduce AppHost Server v2 as an opt-in component of the Aspire product bundle. It separates AppHost authoring from application execution: the guest describes the application through ATS, while a long-lived server owns the resource graph, workloads, and lifecycle.
Existing AppHosts continue to use the managed server by default. This is a bounded first product slice, not a replacement for the full managed Hosting surface. Related to #20873.
The flag is project-scoped, including inherited project configuration, and cannot be enabled globally. Selection follows the target AppHost's configuration rather than the directory where the CLI was invoked. The first supported boundary is TypeScript/Node.js on Windows and Unix, core resources, and qualified protocol-v2 npm providers.
The normal bundle includes the server and its matching ATS metadata. An opted-in project reports an explicit error if that payload is missing; it does not silently fall back. Disabling the flag restores managed-server selection, regenerates the managed SDK, and removes v2-only generated files.
A small core, with integrations outside it
The server is built around Aspire.Hosting.Native.Core, a BCL-only model and execution kernel. Resource kinds are identifiers, not integration-specific CLR subclasses. The kernel owns declarations, dependency ordering, configuration, graph-scoped annotations, execution authority, and immutable snapshots.
Integration code lives in separate provider processes. Providers contribute offline ATS contracts, portable authoring modules, and activation coordinates. Service-client libraries and integration tooling stay outside the kernel; resource-scoped lifecycle callbacks connect providers to execution without giving them arbitrary ownership of the model.
The server reuses DCP for containers and executables, the existing Dashboard frontend, and the CLI's backchannel contracts. The full server includes ASP.NET Core and gRPC for the Dashboard resource-service adapter; the BCL-only boundary is the kernel, not the entire executable.
ATS without runtime scanning
NativeAOT is an implementation detail, not a separate feature or experiment. Build-time generation produces static ATS dispatch, contract metadata, and an embedded core TypeScript SDK. The execution core does not load a scanner or code generator.
Provider SDK preparation uses the bundled aspire-managed apphost-codegen-v2 worker and the existing ATS TypeScript generator. This keeps generation consistent with the managed path while allowing provider contracts to be combined outside the execution core.
Guest RPC uses authenticated Unix-domain sockets on Unix and current-user-only named pipes on Windows. Existing CLI and auxiliary backchannels remain unchanged. Opt-in setup is isolated from the default CLI path, and one bundle lease covers preparation, execution, DCP, and Dashboard.
References and reload-friendly lifetimes
Reference expressions are immutable, server-owned values that retain resource dependencies and secret classification until resolution. The core does not depend on JSON: immutable wire parsing and mutable reply construction belong to the server boundary.
AppHost authoring and workload execution have separate lifetimes. A workspace can stage a new graph, retain compatible execution identities and workloads, and retire removed resources. Old authoring handles and callbacks lose authority when their revision is retired. This provides the foundation for guest reexecution without restarting the whole application, but automatic CLI file watching and revision handoff are not implemented.
The Dashboard adapter exposes resource snapshots, logs, commands, and the supported confirmation flow. DCP continues to own the Dashboard process and workload cleanup.
Resource footprint
Representative local macOS arm64 measurements, using the median of three runs per mode:
Scenario
Server RSS
Other process RSS
Contract-only, empty graph
32.31 MiB
None
Contract-only, 100 declared resources
37.89 MiB
None
DCP + resource service, empty graph
44.14 MiB
155.69 MiB
DCP + resource service, workloads ready
46.45 MiB
551.56 MiB
The measured server executable is 17.51 MiB. Direct server readiness was 32.14 ms in contract-only mode and 4.90 s with DCP and the resource service.
Contract-only mode uses the same full server binary with DCP/resource-service startup disabled, not a separately linked minimal-core executable. Other process RSS covers DCP and workload/helper processes, excluding the server. The scenario has no integration host or Dashboard frontend; Docker VM/container memory and the driving Node process are excluded. RSS can double-count shared pages, and timing starts at direct server launch, not aspire run. These are recorded benchmark measurements, not a fresh measurement of the current PR head.
Current boundaries
Managed integration assemblies, other guest runtimes, publishing, and server debugging are explicitly unsupported in this first slice. Broader integration acquisition, complete provider reconciliation, and full Dashboard protocol parity remain follow-up work. Dev Tunnels currently uses a local forwarding fixture, not the live service.
The new boundary includes authenticated local RPC, generation-scoped handles and callbacks, workload execution, generated credentials, and authenticated DCP access. Listener permissions, authority revocation, process containment, secret-safe diagnostics, certificate validation, and cleanup ownership require security review. No formal threat model or security review has been completed.
Checklist
Is this feature complete?
Yes. Ready to ship.
No. Follow-up changes expected.
Are you including unit tests for the changes and scenario tests if relevant?
Yes
No
Did you add public API?
Yes
If yes, did you have an API Review for it?
Yes
No
Did you add <remarks /> and <code /> elements on your triple slash comments?
Yes
No
No
Does the change make any security assumptions or guarantees?
Yes
If yes, have you done a threat model and had a security review?
Add an isolated Native AOT resource core, unchanged managed Redis execution, a TypeScript Nuxt integration process, and a real workload/deployment-context harness. Record the ownership, orchestration, publishing, containment, and measurement limitations without changing production behavior.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5232bd9d-6550-4411-a521-cd6be239f67e
Exercise native containers, database children, executable readiness, deferred values, restart persistence, and owner-scoped cleanup. Preserve a mixed path through the unchanged managed Redis integration and document the production gaps.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5232bd9d-6550-4411-a521-cd6be239f67e
Add run-only custom endpoints with owner/generation fencing, deferred URL consumers, command cancellation, DCP log observation, and owner invalidation. Exercise real DCP and HTTP forwarding with an explicit local CLI fixture; record live relay validation as blocked by expired authentication.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5232bd9d-6550-4411-a521-cd6be239f67e
Generate the real ATS guest SDK and static AOT dispatch from a minimal primitive contract. Replatform bounded Redis, PostgreSQL and Dev Tunnels integrations, exercise actual DCP workloads, and demonstrate guest graph replacement with persistent native server and integration host processes.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5232bd9d-6550-4411-a521-cd6be239f67e
Integrate direct AOT-safe DCP bootstrap and execution-document cleanup, embed the offline ATS SDK, and reuse CLI process and session lifetimes through an explicit headless override. Add real CLI workload and failure scenarios, focused regression coverage, and runnable samples.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5232bd9d-6550-4411-a521-cd6be239f67e
The reason will be displayed to describe this comment to others. Learn more.
🟡 Changes recommended
The override leaks into unsupported CLI operations, alters managed shutdown behavior, retains a DCP startup race, and leaves the principal PoC outside CI coverage.
Graph cleanup is fail-fast: one rejected monitor task or one failed tunnel deletion aborts releaseGraph, so later session-owned tunnels are never deleted. This is especially likely after a monitor transport failure. Settle monitor tasks and attempt every owned-tunnel deletion before reporting aggregate cleanup failure.
This discards the captured stream and marks stderr as Information. Native server and DCP failures are intentionally written to stderr, so CLI diagnostic files and extension forwarding will present failures as ordinary output. Preserve stream and map StdErr to LogLevel.Error.
Consolidate the native runtime into one AOT server project with generated ATS dispatch, DCP execution, and a Dashboard protocol adapter. Add server-owned workspaces, staged model revisions, stable resource executions, integration configuration acknowledgements, and ordered workload replacement. Cover actual guest reexecution, retained workloads and data, dependent endpoint rebinding, and cleanup with real CLI and Dashboard E2E fixtures.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5232bd9d-6550-4411-a521-cd6be239f67e
Implement the existing CLI backchannel on the native server, use source-generated wire DTOs and validated runtime policies, and launch the authenticated Dashboard through DCP. Fix playground composition, connection-material startup retries, integration registration, output bounds, and CI-owned coverage.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5232bd9d-6550-4411-a521-cd6be239f67e
Assert the classified execution-prerequisite error and its milestone chain for rejected staged revisions.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5232bd9d-6550-4411-a521-cd6be239f67e
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Introduce AppHost Server v2 as an opt-in component of the Aspire product bundle. It separates AppHost authoring from application execution: the guest describes the application through ATS, while a long-lived server owns the resource graph, workloads, and lifecycle.
Existing AppHosts continue to use the managed server by default. This is a bounded first product slice, not a replacement for the full managed Hosting surface. Related to #20873.
Architecture
flowchart TB CLI["Aspire CLI<br/>standard run / codegen / process supervision"] Guest["TypeScript guest AppHost<br/>generated ATS SDK"] Codegen["Bundled managed codegen helper<br/>offline ATS contracts + shared TypeScript generator"] TS["TypeScript integration host<br/>Redis / PostgreSQL / Dev Tunnels ports<br/>service clients + callbacks + controllers"] CS["Future C# integration host<br/>generated core projection<br/>managed integration dependencies"] subgraph Native["AppHost Server v2: opt-in product component"] RPC["Authenticated ATS dispatch<br/>handles + capability routing"] Model["BCL-only Native.Core kernel<br/>declarations / execution ownership / revisions<br/>observations / commands / confirmation"] DCPClient["BCL HTTPS + source-generated JSON<br/>DCP execution and cleanup"] DashboardAdapter["Native resource-service gRPC<br/>observations / logs / commands / confirmation"] Backchannels["Existing baseline.v2 and auxiliary RPC<br/>discovery / describe / logs / wait / stop"] RPC --> Model --> DCPClient Model --> DashboardAdapter Model --> Backchannels end DCP["DCP process"] Dashboard["Dashboard frontend<br/>DCP-owned lifecycle"] Workloads["Redis + PostgreSQL containers<br/>Nuxt executable + tunnel fixture"] CLI -->|"supervise"| Native CLI -->|"launch"| Guest CLI <-->|"generateCode / getRuntimeSpec"| RPC CLI -->|"prepare provider SDK"| Codegen Codegen -->|"prepared SDK overlay"| RPC Guest <-->|"ATS calls + typed handles"| RPC RPC <-->|"exported calls + projected core calls + callbacks"| TS CS -.->|"planned ATS projection; not live CLR objects"| RPC DCPClient -->|"authenticated API"| DCP DCP -->|"own execution"| Workloads DCP -->|"launch and stop"| Dashboard Dashboard <-->|"existing resource-service protocol"| DashboardAdapter CLI <-->|"existing CLI contracts"| Backchannels classDef native fill:#DFF6DD,stroke:#107C10,color:#000; classDef external fill:#CFE4FA,stroke:#0078D4,color:#000; classDef planned fill:#FFF4CE,stroke:#F7630C,color:#000,stroke-dasharray:5 5; class RPC,Model,DCPClient,DashboardAdapter,Backchannels native; class CLI,Guest,Codegen,TS,DCP,Workloads,Dashboard external; class CS planned;Opting in
Enable v2 in the AppHost's
aspire.config.json:{ "features": { "appHostServerV2": true } }The flag is project-scoped, including inherited project configuration, and cannot be enabled globally. Selection follows the target AppHost's configuration rather than the directory where the CLI was invoked. The first supported boundary is TypeScript/Node.js on Windows and Unix, core resources, and qualified protocol-v2 npm providers.
The normal bundle includes the server and its matching ATS metadata. An opted-in project reports an explicit error if that payload is missing; it does not silently fall back. Disabling the flag restores managed-server selection, regenerates the managed SDK, and removes v2-only generated files.
A small core, with integrations outside it
The server is built around
Aspire.Hosting.Native.Core, a BCL-only model and execution kernel. Resource kinds are identifiers, not integration-specific CLR subclasses. The kernel owns declarations, dependency ordering, configuration, graph-scoped annotations, execution authority, and immutable snapshots.Integration code lives in separate provider processes. Providers contribute offline ATS contracts, portable authoring modules, and activation coordinates. Service-client libraries and integration tooling stay outside the kernel; resource-scoped lifecycle callbacks connect providers to execution without giving them arbitrary ownership of the model.
The server reuses DCP for containers and executables, the existing Dashboard frontend, and the CLI's backchannel contracts. The full server includes ASP.NET Core and gRPC for the Dashboard resource-service adapter; the BCL-only boundary is the kernel, not the entire executable.
ATS without runtime scanning
NativeAOT is an implementation detail, not a separate feature or experiment. Build-time generation produces static ATS dispatch, contract metadata, and an embedded core TypeScript SDK. The execution core does not load a scanner or code generator.
Provider SDK preparation uses the bundled
aspire-managed apphost-codegen-v2worker and the existing ATS TypeScript generator. This keeps generation consistent with the managed path while allowing provider contracts to be combined outside the execution core.Guest RPC uses authenticated Unix-domain sockets on Unix and current-user-only named pipes on Windows. Existing CLI and auxiliary backchannels remain unchanged. Opt-in setup is isolated from the default CLI path, and one bundle lease covers preparation, execution, DCP, and Dashboard.
References and reload-friendly lifetimes
Reference expressions are immutable, server-owned values that retain resource dependencies and secret classification until resolution. The core does not depend on JSON: immutable wire parsing and mutable reply construction belong to the server boundary.
AppHost authoring and workload execution have separate lifetimes. A workspace can stage a new graph, retain compatible execution identities and workloads, and retire removed resources. Old authoring handles and callbacks lose authority when their revision is retired. This provides the foundation for guest reexecution without restarting the whole application, but automatic CLI file watching and revision handoff are not implemented.
The Dashboard adapter exposes resource snapshots, logs, commands, and the supported confirmation flow. DCP continues to own the Dashboard process and workload cleanup.
Resource footprint
Representative local macOS arm64 measurements, using the median of three runs per mode:
The measured server executable is 17.51 MiB. Direct server readiness was 32.14 ms in contract-only mode and 4.90 s with DCP and the resource service.
Contract-only mode uses the same full server binary with DCP/resource-service startup disabled, not a separately linked minimal-core executable. Other process RSS covers DCP and workload/helper processes, excluding the server. The scenario has no integration host or Dashboard frontend; Docker VM/container memory and the driving Node process are excluded. RSS can double-count shared pages, and timing starts at direct server launch, not
aspire run. These are recorded benchmark measurements, not a fresh measurement of the current PR head.Current boundaries
Managed integration assemblies, other guest runtimes, publishing, and server debugging are explicitly unsupported in this first slice. Broader integration acquisition, complete provider reconciliation, and full Dashboard protocol parity remain follow-up work. Dev Tunnels currently uses a local forwarding fixture, not the live service.
The design and remaining model work are described in the App Model v2 specification. This PR remains draft.
Security considerations
The new boundary includes authenticated local RPC, generation-scoped handles and callbacks, workload execution, generated credentials, and authenticated DCP access. Listener permissions, authority revocation, process containment, secret-safe diagnostics, certificate validation, and cleanup ownership require security review. No formal threat model or security review has been completed.
Checklist
<remarks />and<code />elements on your triple slash comments?