AG-UI .NET SDK — Feature Workflow (Orchestrator)
This is the hub skill. Given a request to build or change a feature in the AG-UI
.NET SDK (sdks/dotnet/), it lays out the correct end-to-end order and routes the
depth of each step to a focused sibling skill. It does not duplicate their content.
The SDK has a multi-artifact definition of done. An agent working ad hoc forgets
artifacts — most often cross-language parity, docs, AGENTS.md/docs/architecture.md sync,
and PublicAPI.Unshipped.txt. Use this skill to avoid that.
Package map
sdks/dotnet/src/:
| Package |
Responsibility |
AGUI.Abstractions |
Wire types: events, messages, tools, capabilities, AGUIJsonSerializerContext |
AGUI.Formatting |
JSON formatter + SSE encode/decode |
AGUI.Protobuf |
Protobuf encoding of the protocol |
AGUI.Client |
AGUIChatClient (IChatClient) + transport negotiation |
AGUI.Server |
Hosting-agnostic agent-side conversion (ChatResponseUpdate → events) |
ASP.NET hosting glue lives in samples/AGUI.Samples.Shared (not a src/ package).
sdks/dotnet/AGENTS.md and docs/architecture.md are the canonical description of
the layout and conventions (kept current via agui-dotnet-agents-sync); AGUI.slnx
is the ground truth if you need to re-derive the package list.
Build & test commands
# from sdks/dotnet/
dotnet build sdks/dotnet/AGUI.slnx # whole solution
dotnet test tests/AGUI.Abstractions.UnitTests/ # per-project, fast feedback
Directory.Build.props treats warnings as errors, and PublicApiAnalyzers is on
for every src/ project with a PublicAPI.Shipped.txt. The build fails if you skip
the AOT serialization wiring or forget PublicAPI.Unshipped.txt — these are not
optional polish steps, they are enforced.
Definition of done (feature checklist)
Ordered workflow → route each step
Do the steps in this order. Skip a step only if it genuinely doesn't apply
(e.g. a non-wire-affecting internal refactor skips cross-language parity).
Understand the wire contract. Read the TypeScript (and Python) reference for
the type/behavior so the .NET shape matches the spec. Porting an existing feature
from another SDK? → agui-cross-sdk-parity.
Implement the type/behavior in the right package.
- New/changed wire type (event, message, tool, capability) →
agui-dotnet-wire-types
(covers the AGUI.Abstractions recipe: class in Events/, AGUIEventTypes
constant, converter case, AOT registration, PublicAPI.Unshipped.txt).
- New/changed transport or encoding (SSE, protobuf, formatter) →
agui-dotnet-transport (AGUI.Formatting, AGUI.Protobuf).
Wire AOT serialization. Every protocol type goes through
AGUIJsonSerializerContext — no reflection. agui-dotnet-wire-types has the
per-type recipe; the build enforces it.
Update client/server mapping. Server-side ChatResponseUpdate → event lives in
AGUI.Server; client-side event → ChatResponseUpdate lives in AGUI.Client
(EventStreamConverter, builders). Update both directions if the wire shape changed.
Unit tests (round-trip + behavior) → agui-dotnet-unit-tests.
Integration tests (HTTP + SSE pipeline, WebApplicationFactory,
AGUIChatClient) → agui-dotnet-integration-tests. Required when the change
crosses the transport boundary.
Cross-language parity tests (if wire-affecting) →
agui-dotnet-cross-language-tests (tests/AGUI.CrossLanguage.IntegrationTests,
CrossLanguage.TestServer, CrossLanguage.Vitest). This is the step agents most
often forget — .NET must agree with TS/Python on the bytes.
Update PublicAPI.Unshipped.txt for every changed public member, in each
affected src/ project. The PublicAPI analyzer fails the build otherwise.
Docs (user-facing change) → agui-dotnet-sdk-docs (docs.ag-ui.com).
Sync AGENTS.md / docs/architecture.md if you changed structure, recipes, or
commands → agui-dotnet-agents-sync. Fix stale package references while here.
Build + test green. dotnet build sdks/dotnet/AGUI.slnx, then the relevant
dotnet test <project> (unit + integration + cross-language as applicable).
Validate & review. Run/inspect in the dojo → agui-dojo; manual UI/docs
checks → agui-playwright-validate; review the change → agui-dotnet-code-review.
Routing table (quick reference)
| Step / need |
Sibling skill |
| Add/modify a wire type |
agui-dotnet-wire-types |
| Add/modify transport or encoding |
agui-dotnet-transport |
| Port a feature from TS/Python |
agui-cross-sdk-parity |
| Write unit tests |
agui-dotnet-unit-tests |
| Write integration tests |
agui-dotnet-integration-tests |
| Write cross-language tests |
agui-dotnet-cross-language-tests |
| Add a GettingStarted sample Step (Server/Client pair) |
agui-dotnet-sample-step |
| Update SDK docs site |
agui-dotnet-sdk-docs |
| Keep AGENTS.md / docs/architecture.md current |
agui-dotnet-agents-sync |
| Run/validate in the dojo |
agui-dojo |
| Manual UI/docs validation |
agui-playwright-validate |
| Review the change |
agui-dotnet-code-review |
The depth of each step lives in the sibling skill it routes to; fall back to the
recipes in AGENTS.md and the deep content in docs/architecture.md for anything a
sibling doesn't cover.
❌ Anti-patterns
- Don't stop at "it compiles and unit tests pass." Wire-affecting changes are not
done until cross-language parity tests and docs are updated.
- Don't put protocol or server code in a sample. It belongs in
src/; the server is
AGUI.Server, hosting glue is in samples/AGUI.Samples.Shared, and no src/ project
references ASP.NET.
- Don't skip
PublicAPI.Unshipped.txt or AOT registration "to fix later" — the
warnings-as-errors build will block you immediately.
- Don't do the deep work here. This skill routes; the depth lives in the sibling
skills. Open the relevant one before implementing a step.
Source: ag-ui-protocol/ag-ui → .github/skills/agui-dotnet-feature-workflow/SKILL.md
1---2name: agui-dotnet-feature-workflow3description: > Orchestrator/hub for implementing a feature or change in the AG-UI .NET SDK (sdks/dotnet). USE FOR: "what's the workflow", "what order do I do things in", "how do I implement a feature in the .NET SDK", starting any non-trivial AG-UI .NET SDK change, planning the end-to-end steps and definition-of-done (code + AOT serialization + client/server mapping + unit/integration/cross-language tests + docs + PublicAPI + AGENTS.md sync). DO NOT USE FOR: the deep how-to of a single step — this skill ROUTES to focused siblings: adding wire types (agui-dotnet-wire-types), transport/encoding (agui-dotnet-transport), unit tests (agui-dotnet-unit-tests), integration tests (agui-dotnet-integration-tests), cross-language tests (agui-dotnet-cross-language-tests), porting from TS/Python (agui-cross-sdk-parity), adding a GettingStarted sample Step (agui-dotnet-sample-step), SDK docs...4---5# AG-UI .NET SDK — Feature Workflow (Orchestrator)
6
7This is the **hub** skill. Given a request to build or change a feature in the AG-UI
8.NET SDK (`sdks/dotnet/`), it lays out the correct end-to-end order and **routes the
9depth of each step to a focused sibling skill**. It does not duplicate their content.
10
11The SDK has a multi-artifact **definition of done**. An agent working ad hoc forgets
12artifacts — most often cross-language parity, docs, `AGENTS.md`/`docs/architecture.md` sync,
13and `PublicAPI.Unshipped.txt`. Use this skill to avoid that.
14
15## Package map
16
17`sdks/dotnet/src/`:
18
19| Package | Responsibility |
20|---|---|
21| `AGUI.Abstractions` | Wire types: events, messages, tools, capabilities, `AGUIJsonSerializerContext` |
22| `AGUI.Formatting` | JSON formatter + SSE encode/decode |
23| `AGUI.Protobuf` | Protobuf encoding of the protocol |
24| `AGUI.Client` | `AGUIChatClient` (`IChatClient`) + transport negotiation |
25| `AGUI.Server` | Hosting-agnostic agent-side conversion (`ChatResponseUpdate` → events) |
26
27ASP.NET hosting glue lives in `samples/AGUI.Samples.Shared` (not a `src/` package).
28`sdks/dotnet/AGENTS.md` and `docs/architecture.md` are the canonical description of
29the layout and conventions (kept current via `agui-dotnet-agents-sync`); `AGUI.slnx`
30is the ground truth if you need to re-derive the package list.
31
32## Build & test commands
33
34```bash
35# from sdks/dotnet/
36dotnet build sdks/dotnet/AGUI.slnx # whole solution
37dotnet test tests/AGUI.Abstractions.UnitTests/ # per-project, fast feedback
38```
39
40`Directory.Build.props` **treats warnings as errors**, and `PublicApiAnalyzers` is on
41for every `src/` project with a `PublicAPI.Shipped.txt`. **The build fails if you skip
42the AOT serialization wiring or forget `PublicAPI.Unshipped.txt`** — these are not
43optional polish steps, they are enforced.
44
45## Definition of done (feature checklist)
46
47- [ ] Wire contract understood (matched against TS/Python reference if wire-affecting)
48- [ ] Type/behavior implemented in the **right package** (see map)
49- [ ] AOT serialization wired (`[JsonSerializable]` in `AGUIJsonSerializerContext`, converter case, `[JsonPropertyName]`)
50- [ ] Client/server mapping updated (`AGUI.Client` event→update and/or `AGUI.Server` update→event)
51- [ ] Unit tests (serialization round-trip + behavior)
52- [ ] Integration tests (full pipeline) if it crosses the HTTP/SSE boundary
53- [ ] Cross-language parity tests if wire-affecting
54- [ ] `PublicAPI.Unshipped.txt` updated for every changed public member
55- [ ] Docs updated (docs.ag-ui.com / SDK docs) if user-facing
56- [ ] `AGENTS.md` / `docs/architecture.md` synced if structure/recipe changed
57- [ ] `dotnet build sdks/dotnet/AGUI.slnx` and relevant `dotnet test` projects green
58
59## Ordered workflow → route each step
60
61Do the steps **in this order**. Skip a step only if it genuinely doesn't apply
62(e.g. a non-wire-affecting internal refactor skips cross-language parity).
63
641. **Understand the wire contract.** Read the TypeScript (and Python) reference for
65 the type/behavior so the .NET shape matches the spec. Porting an existing feature
66 from another SDK? → **`agui-cross-sdk-parity`**.
67
682. **Implement the type/behavior in the right package.**
69 - New/changed wire type (event, message, tool, capability) → **`agui-dotnet-wire-types`**
70 (covers the `AGUI.Abstractions` recipe: class in `Events/`, `AGUIEventTypes`
71 constant, converter case, AOT registration, `PublicAPI.Unshipped.txt`).
72 - New/changed transport or encoding (SSE, protobuf, formatter) →
73 **`agui-dotnet-transport`** (`AGUI.Formatting`, `AGUI.Protobuf`).
74
753. **Wire AOT serialization.** Every protocol type goes through
76 `AGUIJsonSerializerContext` — no reflection. `agui-dotnet-wire-types` has the
77 per-type recipe; the build enforces it.
78
794. **Update client/server mapping.** Server-side `ChatResponseUpdate` → event lives in
80 `AGUI.Server`; client-side event → `ChatResponseUpdate` lives in `AGUI.Client`
81 (`EventStreamConverter`, builders). Update both directions if the wire shape changed.
82
835. **Unit tests** (round-trip + behavior) → **`agui-dotnet-unit-tests`**.
84
856. **Integration tests** (HTTP + SSE pipeline, `WebApplicationFactory`,
86 `AGUIChatClient`) → **`agui-dotnet-integration-tests`**. Required when the change
87 crosses the transport boundary.
88
897. **Cross-language parity tests** (if wire-affecting) →
90 **`agui-dotnet-cross-language-tests`** (`tests/AGUI.CrossLanguage.IntegrationTests`,
91 `CrossLanguage.TestServer`, `CrossLanguage.Vitest`). This is the step agents most
92 often forget — .NET must agree with TS/Python on the bytes.
93
948. **Update `PublicAPI.Unshipped.txt`** for every changed public member, in each
95 affected `src/` project. The PublicAPI analyzer fails the build otherwise.
96
979. **Docs** (user-facing change) → **`agui-dotnet-sdk-docs`** (docs.ag-ui.com).
98
9910. **Sync `AGENTS.md` / `docs/architecture.md`** if you changed structure, recipes, or
100 commands → **`agui-dotnet-agents-sync`**. Fix stale package references while here.
101
10211. **Build + test green.** `dotnet build sdks/dotnet/AGUI.slnx`, then the relevant
103 `dotnet test <project>` (unit + integration + cross-language as applicable).
104
10512. **Validate & review.** Run/inspect in the dojo → **`agui-dojo`**; manual UI/docs
106 checks → **`agui-playwright-validate`**; review the change → **`agui-dotnet-code-review`**.
107
108## Routing table (quick reference)
109
110| Step / need | Sibling skill |
111|---|---|
112| Add/modify a wire type | `agui-dotnet-wire-types` |
113| Add/modify transport or encoding | `agui-dotnet-transport` |
114| Port a feature from TS/Python | `agui-cross-sdk-parity` |
115| Write unit tests | `agui-dotnet-unit-tests` |
116| Write integration tests | `agui-dotnet-integration-tests` |
117| Write cross-language tests | `agui-dotnet-cross-language-tests` |
118| Add a GettingStarted sample Step (Server/Client pair) | `agui-dotnet-sample-step` |
119| Update SDK docs site | `agui-dotnet-sdk-docs` |
120| Keep AGENTS.md / docs/architecture.md current | `agui-dotnet-agents-sync` |
121| Run/validate in the dojo | `agui-dojo` |
122| Manual UI/docs validation | `agui-playwright-validate` |
123| Review the change | `agui-dotnet-code-review` |
124
125> The depth of each step lives in the sibling skill it routes to; fall back to the
126> recipes in `AGENTS.md` and the deep content in `docs/architecture.md` for anything a
127> sibling doesn't cover.
128
129## ❌ Anti-patterns
130
1311. **Don't stop at "it compiles and unit tests pass."** Wire-affecting changes are not
132 done until cross-language parity tests and docs are updated.
1332. **Don't put protocol or server code in a sample.** It belongs in `src/`; the server is
134 `AGUI.Server`, hosting glue is in `samples/AGUI.Samples.Shared`, and no `src/` project
135 references ASP.NET.
1363. **Don't skip `PublicAPI.Unshipped.txt` or AOT registration** "to fix later" — the
137 warnings-as-errors build will block you immediately.
1384. **Don't do the deep work here.** This skill routes; the depth lives in the sibling
139 skills. Open the relevant one before implementing a step.
140
141---
142
143**Source:** [`ag-ui-protocol/ag-ui`](https://github.com/ag-ui-protocol/ag-ui) → `.github/skills/agui-dotnet-feature-workflow/SKILL.md`