Key takeaways
- Gate shared shell UX with product feature flags, not agent-id branches.
- Carry scope, starters, export prefixes, and access arrays as per-agent overlay data.
- Let the SPA render an authorized catalog payload; do not parse JWTs for visibility.
- Ship specialist agents as packs and config so the core stays free of per-team hard-coding.
- Expand CI by flag and role matrix, not by forked copies of the shell.
- Validate overlay access claims against API authorization rules before merge.
Multi-agent shells rot when every new assistant becomes an if-else on agent ids. Microcopy forks. Export prefixes fork. Access checks fork. Soon the SPA is a one-off catalog pretending to be a product.
Default-open with overlays. Product feature flags gate shared UX. Per-agent overlay rows carry the differences. The SPA never invents policy from a JWT. The core stays clean because specialist agents are data, not code forks.
Named model: default-open with overlays
- Product feature flags: shared surfaces (chat layout, citations, export, follow-up chips) default open and flip without deleting an agent.
- Per-agent overlays: scope labels, starter prompts, export prefixes, and access arrays live as row data under those flags.
- Catalog API / authZ: the API returns what this caller may see; the SPA only renders that list.
- Rule: shared behavior is a product feature. Agent differences are overlay data. Policy stays on the API.
Figure 1. Default-open with overlays. Flags gate shared UX. Overlay rows carry agent differences. The catalog API owns what the SPA may show.
Context and constraint
Agent catalogs tend to grow faster than the shared UX can absorb. Each "quick" special case for one assistant taught the next engineer that hard-coding was normal. Feature flags plus overlay rows restored a single shell with many agents.
If starters, export names, and access arrays live in code beside agent ids, every team wants a fork. If they live in overlay rows gated by flags, the core stays boring and the catalog stays honest. Authorization still belongs on the API; overlays describe what the API already allows the shell to show.
Figure 2 is the Learn surface for managing feature flags. Treat it as product posture for shared surfaces, not as a place to encode team preferences in React.

Figure 2. Shared shell UX is a product feature. Agent differences belong in overlay rows the API already authorizes. Source: Microsoft Learn: manage feature flags.
Figure 3 is the create-flag switch. Flags gate surfaces. App roles still decide what the catalog may show.

Figure 3. Feature flags gate surfaces. App roles still decide what the catalog may show. The SPA should not invent policy from JWTs. Source: Microsoft Learn: manage feature flags.
Design
1. Default-open shared UX behind flags
Chat layout, citation drawers, export affordances, and follow-up chips are product features. Gate them with flags so you can disable a surface without deleting an agent. Flags are for product posture, not for encoding team preferences in React.
2. Overlay rows per agent, not per forked shell
Each agent row can carry scope labels, starter prompts, export prefixes, and access arrays. Variation between deployments should select which rows are loaded, not rewrite the shell. Overlays scale; forks multiply support. Figure 4 is the row shape.
Figure 4. Overlay row as data. Scope, starters, export prefixes, and access arrays ride with the agent. Selecting rows is not rewriting the shell.
3. Access arrays without JWT archaeology in the SPA
The catalog API returns what this caller may see. The SPA renders that list. Decoding roles in the browser to filter hard-coded ids duplicates policy and drifts. One access payload beats three copies of role strings. Figure 5 is the ownership split.
Figure 5. Catalog API owns visibility. React that decodes JWTs and filters hard-coded agent ids is how policy drifts from the API.
4. Microcopy stays under parent toggles
Tone and helper text for a feature belong with the feature flag, not scattered beside agent ids. Otherwise you fix a typo in four branches and miss the fifth. Parent toggles keep copy reviewable.
5. The core stays free of specialist agents
Specialist packs arrive as data and config. The core repo should not need a pull request every time a specialist agent is added for one team. If the core PR list is mostly agent ids, you inverted the architecture.
6. Expand tests by flag matrix
Test general-only, specialized-only, flag-off, and flag-on. Do not maintain a separate test suite per forked shell. When a flag changes default, CI should tell you before a release does.
How overlays and authZ stay friends
Overlays are not a second authorization system. They decorate an already authorized catalog. If an access array on a row disagrees with the API role check, the API wins and the row is wrong. Build a validator that fails CI when overlay access claims exceed what roles can grant. Configuration that over-promises is a security bug with a friendly JSON face.
Migration from hard-coded ids
Inventory every branch on agent id. Classify each as product feature, overlay field, or true one-off that should be a flag. Move fields into rows. Replace branches with flag checks. Delete dead id lists. Keep a short ADR so the next engineer does not reintroduce "just one if" for a favored agent. Favored agents are still rows.
Operability for on-call
When a starter prompt is wrong, on-call should edit overlay data or a flagged config, not ship a shell hotfix. When a feature misbehaves for everyone, flip the parent flag. Separate those runbooks. Mixing "fix one agent" with "disable citations globally" in the same panic path is how you take down the wrong surface.
Common mistakes
If-else catalogs. Every agent id teaches a new special case.
JWT parsing in React. Policy drifts from the API. Figure 5 is that failure made visible.
Copy forks. Same feature, five wordings, no owner.
Per-team branches. One shell becomes many apps.
Flag soup without owners. Nobody knows what "true" means in production.
Tests per fork. Velocity dies; fear of merge rises.
Use as-is or adapt
Use as-is
- Shared shell UX is gated by product feature flags, not by agent id branches.
- Per-agent overlays carry scope, starters, export prefixes, and access arrays as data.
- SPA consumes authorized catalog payloads; no JWT role parsing for agent visibility.
- Specialist agents ship as packs/config; core stays free of per-team agent hard-coding.
- CI expands by flag and role matrix, not by forked shells.
- Overlay access claims are validated against API authorization rules.
Adapt before you use
Flags and overlays add configuration surface. Hard-coded ids feel faster for the first few agents and collapse as the catalog grows. API-driven catalogs need API-level tests; browser-side role parsing needs tribal knowledge. Flag ownership and naming discipline are mandatory; unnamed flags become landmines. A clean core with overlays takes packaging work up front and removes fork tax forever after.
Primary references: Azure App Configuration feature flag guidance and your Microsoft Foundry / agent catalog API docs on Microsoft Learn where applicable. Pair product flag docs with the authorization ADR so toggles never become a backdoor.
Gate shared UX with flags. Describe agents as overlays. Keep policy on the API. Test the matrix. The shell should feel like one product even when the catalog is many specialists.