Skip to content
Shiny.Maui.Shell v6 support for AI routing tools Learn More

MAUI Shell

1 post with the tag “MAUI Shell”

AI-Powered Navigation in Shiny MAUI Shell

What if your app could understand “My furnace is broken — it’s urgent!” and automatically open the right form with the description filled in and the priority set to Urgent? That’s exactly what the new AI integration in Shiny MAUI Shell does.

Mobile apps have dozens of pages. Users have to know where things are, tap through menus, and manually fill in fields. But with AI chat becoming the norm, we asked: what if the AI could navigate your app for you?

Shiny Shell’s source generator already knows every route in your app and every parameter each page accepts. We just needed to make that metadata available to an AI model — and give it a way to act on what it discovers.

Instead of registering a separate AI tool for every page (which doesn’t scale), we generate just two:

  1. GetAiToolApplicableGeneratedRoutes() — returns all routes that have intent descriptions and parameters. The AI calls this to discover what pages exist and what they do.
  2. NavigateToRoute() — accepts a route name and a Dictionary<string, string> of parameters. The AI calls this to navigate and pre-fill the form.

That’s it. Add a new page with [ShellMap] descriptions and [ShellProperty] inference hints, and the AI automatically discovers it. No tool registration changes needed.

The key insight is that descriptions should express user intent, not page names:

// Good — the AI matches "my pipe burst" to this route
[ShellMap<WorkOrderPage>(description: "Use when the user reports something broken,
malfunctioning, needing repair, maintenance, or service")]
// Bad — the AI has to guess what "Work order page" means
[ShellMap<WorkOrderPage>(description: "Work order page")]

Similarly, property descriptions tell the AI how to infer values from natural language. Properties can use real types — enums, ints, bools — and the generator handles conversion automatically:

public enum WorkOrderPriority { Low, Medium, High, Urgent }
[ShellProperty("Summarize what is broken based on what the user said", required: true)]
public string Description { get; set; } = string.Empty;
[ShellProperty("Infer urgency from the user's tone. Must be: Low, Medium, High, or Urgent", required: true)]
public WorkOrderPriority Priority { get; set; } = WorkOrderPriority.Medium;

The AI sends "Urgent" as a string, and the generated NavigateToRoute converts it to WorkOrderPriority.Urgent via case-insensitive Enum.Parse. The same works for int, bool, double, DateTime, Guid, and other common types.

Note that AI-compatible ViewModels do not need to implement IQueryAttributable. The generated NavigateToRoute sets [ShellProperty] properties directly on the ViewModel instance — no query attribute plumbing required.

The source generator produces GeneratedRouteInfo metadata with full parameter schemas:

public record GeneratedRouteInfo(
string Route,
string Description,
GeneratedRouteParameter[] Parameters
);
public record GeneratedRouteParameter(
string ParameterName,
string Description,
string TypeName,
bool IsRequired
);

The AI model sees the route descriptions, parameter names, types, requirements, and inference hints — everything it needs to match intent and extract values.

First, enable AI extensions in your .csproj and install Microsoft.Extensions.AI:

<PropertyGroup>
<ShinyMauiShell_GenerateAiExtensions>true</ShinyMauiShell_GenerateAiExtensions>
</PropertyGroup>

Then use the generated GetAiTools() method — one line to get ready-to-use AITool instances:

var tools = navigator.GetAiTools();
var options = new ChatOptions { Tools = [.. tools] };

You can also seed route info into the system prompt upfront via the generated navigator.AiRoutePrompt() extension method, so the model knows what’s available without a discovery call.

The sample app includes a full working demo with GitHub Copilot authentication. Users authenticate with their own GitHub account through the OAuth device flow, and the app uses the Copilot API as the chat backend. Try saying things like:

  • “My furnace is not working! URGENT” — opens the work order form with description and priority filled in
  • “I’d like to discuss a partnership. My name is Allan, email allan@test.com — opens the contact form with fields populated

Check out the AI Integration documentation for the full setup guide, or browse the sample code on GitHub.