AG-UI .NET — Add a GettingStarted Sample Step
The samples/GettingStarted/Step01..StepNN pairs are the primary consumer-facing
deliverable: each Step is a self-contained Server + Client that demonstrates one
feature, written to look like the code we want users to write. Adding a Step is a
recurring, multi-artifact task. This skill covers the sample anatomy and wiring; it
routes the integration-test mechanics to agui-dotnet-integration-tests and the doc
sync to agui-dotnet-agents-sync.
Run all commands from sdks/dotnet/. Confirm the next free number and the current naming
by listing samples/GettingStarted/Step* first — never assume the range.
Anatomy of a Step
A Step is a folder samples/GettingStarted/StepNN_<Name>/ with two projects:
StepNN_<Name>.Server — an ASP.NET host (Microsoft.NET.Sdk.Web, net10.0).
Program.cs calls builder.Services.AddAGUI(), registers an IChatClient, and ends
with app.MapAGUI("/"). The IChatClient is the whole point: the SDK turns any
IChatClient into an AG-UI endpoint, so the sample logic is just MEAI.
- References
src/AGUI.Abstractions + samples/AGUI.Samples.Shared (the ASP.NET glue).
It does not reference an src/ server package directly.
InternalsVisibleTo the integration-test project so its replay test can reach the
server's Program and any FakeChatClient.
- Provide a deterministic
FakeChatClient fallback (fixed clocks, canned tool
results) used when no real LLM is configured. Replayable determinism is what lets the
integration test record once and replay forever.
StepNN_<Name>.Client — a console app (Microsoft.NET.Sdk, OutputType Exe,
net10.0). Program.cs builds the client and hands it to a shared SampleClient:
using HttpClient httpClient = new() { BaseAddress = new Uri(baseUrl) };
var aguiClient = new AGUIChatClient(new(httpClient, baseUrl));
await SampleClient.RunAsync(aguiClient, Console.Out);
- References only
src/AGUI.Client. (AGUIChatClient is constructed from
AGUIChatClientOptions — see agui-dotnet-transport for the protobuf opt-in via
AGUIEventStreamHandler.)
Mirror the closest existing Step rather than inventing structure: the feature determines
which one (tools → Step02/03, interrupts → Step09/10, state → Step05, parallel calls →
Step12). Keep the file-name/type-name/namespace consistent (StepNN_<Name>.Server etc.).
Wiring (the parts agents forget)
- Solution. Add both
.csproj paths to AGUI.slnx under the
/samples/GettingStarted/ folder, in Step order.
- Integration-test references. Add a
ProjectReference to both the Server and Client
projects in tests/AGUI.Hosting.AspNetCore.IntegrationTests/*.csproj (it references
every Step pair so its replay tests can host them).
- Replay test. Add
Samples/GettingStarted/StepNN_<Name>Test.cs deriving from
IntegrationTestBase<StepNN_<Name>.Server.Program>, then record its baseline. The
recording/Verify/8-capture-point mechanics belong to
agui-dotnet-integration-tests — use that skill; don't reinvent them here. Fixtures
land under Samples/GettingStarted/fixtures/StepNN_<Name>/ and baselines under
baselines/StepNN_<Name>/.
- Doc tables. Add the Step to the Step tables in
sdks/dotnet/AGENTS.md and
sdks/dotnet/docs/architecture.md (and the PR review guide's Step table if present) via
agui-dotnet-agents-sync.
GettingStarted Steps are standalone console samples, not dojo scenarios. The dojo is a
separate host (samples/AGUIClientServer/AGUIDojoServer) — only touch it via agui-dojo
if the feature also needs a dojo demo.
Verify
dotnet build samples/GettingStarted/StepNN_<Name>/StepNN_<Name>.Server/StepNN_<Name>.Server.csproj
dotnet build samples/GettingStarted/StepNN_<Name>/StepNN_<Name>.Client/StepNN_<Name>.Client.csproj
dotnet test tests/AGUI.Hosting.AspNetCore.IntegrationTests/ --filter StepNN_<Name>
Run the pair end to end (server in one shell, client in another) to confirm it reads like
the code a user would write — the bar for a sample is exemplary, not merely passing.
❌ Anti-patterns
- Non-deterministic sample behavior. A wall-clock, RNG, or live network call in the
FakeChatClient path breaks record/replay. Use fixed values.
- Protocol or hosting code in the sample. A Step composes existing SDK APIs; if it
needs a new event/encoding, that lands in
src/ first (agui-dotnet-wire-types /
agui-dotnet-transport), and the sample only consumes it.
- Half-wired Step. Forgetting
AGUI.slnx, the integration-test ProjectReference, or
the doc Step tables leaves a sample that builds locally but isn't covered, shipped in the
solution, or documented.
- Diverging from the sibling Steps. Copy the closest Step's shape (naming, csproj refs,
Program.cs skeleton, InternalsVisibleTo) instead of a new layout.
References
- Replay/Verify test mechanics:
agui-dotnet-integration-tests.
- Step tables / structure sync:
agui-dotnet-agents-sync.
- Protobuf opt-in or a new encoding the Step demos:
agui-dotnet-transport.
- End-to-end workflow context:
agui-dotnet-feature-workflow.
1---2name: agui-dotnet-sample-step3description: Add a GettingStarted sample Step (a Server/Client pair) to the AG-UI .NET SDK that demonstrates one protocol feature the way we want users to write it. USE FOR: adding a new samples/GettingStarted/StepNN_<Name> Server+Client pair, wiring it into AGUI.slnx and the integration-test project, giving it a deterministic FakeChatClient for replay, and registering it in the Step tables in AGENTS.md / docs/architecture.md. DO NOT USE FOR: the replay/Verify integration-test mechanics (use agui-dotnet-integration-tests), the dojo scenarios under samples/AGUIClientServer (use agui-dojo), or protocol/wire changes the sample exercises (use agui-dotnet-wire-types / agui-dotnet-transport).4---5
6# AG-UI .NET — Add a GettingStarted Sample Step
7
8The `samples/GettingStarted/Step01..StepNN` pairs are the primary consumer-facing
9deliverable: each Step is a self-contained Server + Client that demonstrates **one**
10feature, written to look like the code we want users to write. Adding a Step is a
11recurring, multi-artifact task. This skill covers the sample anatomy and wiring; it
12**routes the integration-test mechanics to `agui-dotnet-integration-tests`** and the doc
13sync to `agui-dotnet-agents-sync`.
14
15Run all commands from `sdks/dotnet/`. Confirm the next free number and the current naming
16by listing `samples/GettingStarted/Step*` first — never assume the range.
17
18## Anatomy of a Step
19
20A Step is a folder `samples/GettingStarted/StepNN_<Name>/` with two projects:
21
22- **`StepNN_<Name>.Server`** — an ASP.NET host (`Microsoft.NET.Sdk.Web`, `net10.0`).
23 `Program.cs` calls `builder.Services.AddAGUI()`, registers an `IChatClient`, and ends
24 with `app.MapAGUI("/")`. The `IChatClient` is the whole point: the SDK turns any
25 `IChatClient` into an AG-UI endpoint, so the sample logic is just MEAI.
26 - References `src/AGUI.Abstractions` + `samples/AGUI.Samples.Shared` (the ASP.NET glue).
27 It does **not** reference an `src/` server package directly.
28 - `InternalsVisibleTo` the integration-test project so its replay test can reach the
29 server's `Program` and any `FakeChatClient`.
30 - Provide a **deterministic `FakeChatClient`** fallback (fixed clocks, canned tool
31 results) used when no real LLM is configured. Replayable determinism is what lets the
32 integration test record once and replay forever.
33- **`StepNN_<Name>.Client`** — a console app (`Microsoft.NET.Sdk`, `OutputType Exe`,
34 `net10.0`). `Program.cs` builds the client and hands it to a shared `SampleClient`:
35
36 ```csharp
37 using HttpClient httpClient = new() { BaseAddress = new Uri(baseUrl) };
38 var aguiClient = new AGUIChatClient(new(httpClient, baseUrl));
39 await SampleClient.RunAsync(aguiClient, Console.Out);
40 ```
41
42 - References only `src/AGUI.Client`. (`AGUIChatClient` is constructed from
43 `AGUIChatClientOptions` — see `agui-dotnet-transport` for the protobuf opt-in via
44 `AGUIEventStreamHandler`.)
45
46Mirror the closest existing Step rather than inventing structure: the feature determines
47which one (tools → Step02/03, interrupts → Step09/10, state → Step05, parallel calls →
48Step12). Keep the file-name/type-name/namespace consistent (`StepNN_<Name>.Server` etc.).
49
50## Wiring (the parts agents forget)
51
521. **Solution.** Add both `.csproj` paths to `AGUI.slnx` under the
53 `/samples/GettingStarted/` folder, in Step order.
542. **Integration-test references.** Add a `ProjectReference` to both the Server and Client
55 projects in `tests/AGUI.Hosting.AspNetCore.IntegrationTests/*.csproj` (it references
56 every Step pair so its replay tests can host them).
573. **Replay test.** Add `Samples/GettingStarted/StepNN_<Name>Test.cs` deriving from
58 `IntegrationTestBase<StepNN_<Name>.Server.Program>`, then record its baseline. The
59 recording/Verify/8-capture-point mechanics belong to
60 **`agui-dotnet-integration-tests`** — use that skill; don't reinvent them here. Fixtures
61 land under `Samples/GettingStarted/fixtures/StepNN_<Name>/` and baselines under
62 `baselines/StepNN_<Name>/`.
634. **Doc tables.** Add the Step to the Step tables in `sdks/dotnet/AGENTS.md` and
64 `sdks/dotnet/docs/architecture.md` (and the PR review guide's Step table if present) via
65 **`agui-dotnet-agents-sync`**.
66
67GettingStarted Steps are standalone console samples, **not** dojo scenarios. The dojo is a
68separate host (`samples/AGUIClientServer/AGUIDojoServer`) — only touch it via `agui-dojo`
69if the feature also needs a dojo demo.
70
71## Verify
72
73```bash
74dotnet build samples/GettingStarted/StepNN_<Name>/StepNN_<Name>.Server/StepNN_<Name>.Server.csproj
75dotnet build samples/GettingStarted/StepNN_<Name>/StepNN_<Name>.Client/StepNN_<Name>.Client.csproj
76dotnet test tests/AGUI.Hosting.AspNetCore.IntegrationTests/ --filter StepNN_<Name>
77```
78
79Run the pair end to end (server in one shell, client in another) to confirm it reads like
80the code a user would write — the bar for a sample is exemplary, not merely passing.
81
82## ❌ Anti-patterns
83
841. **Non-deterministic sample behavior.** A wall-clock, RNG, or live network call in the
85 `FakeChatClient` path breaks record/replay. Use fixed values.
862. **Protocol or hosting code in the sample.** A Step composes existing SDK APIs; if it
87 needs a new event/encoding, that lands in `src/` first (`agui-dotnet-wire-types` /
88 `agui-dotnet-transport`), and the sample only consumes it.
893. **Half-wired Step.** Forgetting `AGUI.slnx`, the integration-test `ProjectReference`, or
90 the doc Step tables leaves a sample that builds locally but isn't covered, shipped in the
91 solution, or documented.
924. **Diverging from the sibling Steps.** Copy the closest Step's shape (naming, csproj refs,
93 `Program.cs` skeleton, `InternalsVisibleTo`) instead of a new layout.
94
95## References
96
97- Replay/Verify test mechanics: **`agui-dotnet-integration-tests`**.
98- Step tables / structure sync: **`agui-dotnet-agents-sync`**.
99- Protobuf opt-in or a new encoding the Step demos: **`agui-dotnet-transport`**.
100- End-to-end workflow context: **`agui-dotnet-feature-workflow`**.