Tell an AI agent: "Write this screen with FmgLib.MauiMarkup."
You will most likely get something like this:
new Label()
.SetText("Hello")
.SetFontSize(30)
.HorizontalAlign("Center")
The code looks plausible. Not one of those methods exists.
The correct version:
new Label()
.Text("Hello")
.FontSize(30)
.CenterHorizontal()
This post is about why that gap appears and how it gets closed. The answer is not “wait for a better model”.
The problem isn't the model
Look at the invented names: SetText, SetFontSize, HorizontalAlign. None of them is absurd — every one is real in some other library. The model is averaging over the dozens of fluent APIs it has seen and producing a reasonable guess.
The real issue is this: FmgLib.MauiMarkup's rules are simple, but they are not guessable.
- A bindable property
Foobecomes.Foo(...). NoSetprefix. - An event
Barbecomes.OnBar(...). - The attached property
Grid.Rowbecomes.Row(...)— the prefix drops. ButShell.TitleColorbecomes.ShellTitleColor(...)— the prefix stays. Build()re-runs on every hot reload, so state has to live in fields, not insideBuild().- There is no registration call. Nobody should look for
builder.UseFmgLibMauiMarkup().
None of that is derivable from the type system. An agent looking at Label sees TextProperty, but nothing tells it whether the extension is named .Text or .SetText — both are equally sensible.
There's a second factor: the overwhelming majority of MAUI code in public corpora is XAML. Asked for a MAUI screen, an agent leans toward XAML; asked for C# markup, it often transcribes XAML habits literally — emitting a .xaml + .xaml.cs pair, calling InitializeComponent(), handing ContentTemplate a ready-made page instead of a lambda.
So the gap is not intelligence. It is missing information — and missing information can simply be written down.
What a skill is
A “skill” is a plain Markdown file with a YAML header:
---
name: mauimarkup-mvvm
description: Structure FmgLib.MauiMarkup apps with MVVM — FmgLibContentPage<TViewModel>,
typed BindingContext, compiled Getter/Setter bindings, commands, dependency injection…
Use when writing or refactoring view models, wiring pages to view models…
license: MIT
---
# MVVM with FmgLib.MauiMarkup
...
The subtlety is in the description. The agent continuously sees only the descriptions; it reads a body only when the task at hand matches one. So installing ten skills does not mean loading ten documents into context. The catalogue is always there; the content arrives on demand.
The format is the Agent Skills standard, so it works with Claude Code, the Claude apps, the Agent SDK and any agent that can read a SKILL.md.
The ten skills
Roughly 3,000 lines in total, each covering one area of the library and focused on the places agents get it wrong.
| Skill | What it teaches |
|---|---|
mauimarkup (required) |
The fluent model, page skeleton, the four property overloads, layout, events, Assign, name-derivation rules, Build() discipline. Ships a five-file references/ bundle: cheatsheet, bindings, layout tables, styling & theming, pitfalls |
mauimarkup-xaml-migration |
A per-page migration procedure, a 30-row XAML→C# mapping table, and the constructs that need judgement rather than translation |
mauimarkup-mvvm |
FmgLibContentPage<TViewModel>, typed BindingContext, compiled Getter/Setter, commands, DI, CommunityToolkit.Mvvm |
mauimarkup-shell |
Shell, FlyoutItem, Tab, ContentTemplate lambdas, routes, windows, menu bars |
mauimarkup-collections |
ItemsSource/ItemTemplate, template selectors, item layouts, EmptyView, infinite scroll, and when not to use BindableLayout |
mauimarkup-styling |
Style<T>, resource organization, AppThemeBinding dark mode, visual states, triggers, Animate…To |
mauimarkup-localization |
JSON and RESX setup, Translate/TranslateFormat, live culture switching, fallback chains, RTL |
mauimarkup-thirdparty |
[MauiMarkup], [MauiMarkupAttachedProp], automatic generator mode, base-class generation, the New suffix rule |
mauimarkup-hotreload |
IFmgLibHotReload, handler options, dotnet watch vs IDE channels, a reload-safe Build(), the troubleshooting matrix |
mauimarkup-review |
Nine audit passes with ready-to-run ripgrep queries, a severity model and a reporting format |
Installing all ten is fine — an unused skill costs nothing, because its body is never read.
If you want a starting point:
| You are | Install |
|---|---|
| Starting a new app | mauimarkup + shell + mvvm + hotreload |
| Migrating an existing XAML app | mauimarkup + xaml-migration + styling |
| Building a data-heavy app | mauimarkup + mvvm + collections |
| Shipping to several markets | add localization |
| Using Syncfusion / UraniumUI / SkiaSharp | add thirdparty |
| Cleaning up an inherited codebase | mauimarkup + review |
Installing
Automatic. Just tell your agent:
Fetch https://fmglibmauimarkup.vodisoft.com/llms.txt and install the FmgLib.MauiMarkup AI skills.
It finds the catalogue page, reads the list and downloads the files into place.
Manual. Each skill is a folder containing a SKILL.md. Put it in one of two places:
| Scope | Location |
|---|---|
| Personal — available in every project | ~/.claude/skills/<skill-name>/SKILL.md |
| Project — versioned with the repository | <repo>/.claude/skills/<skill-name>/SKILL.md |
NAME=mauimarkup-mvvm
mkdir -p ~/.claude/skills/$NAME
curl -fsSL https://raw.githubusercontent.com/VodiSoft/FmgLib.MauiMarkup/master/skills/$NAME/SKILL.md \
-o ~/.claude/skills/$NAME/SKILL.md
The core skill also has a references/ folder; copy it as-is so its relative links keep resolving.
Teams should prefer project scope. Commit the folder under <repo>/.claude/skills/ and every developer and CI agent works from the same instructions — which ends the “it wrote it correctly on my machine” conversation before it starts.
What actually changes
A few of the corrections the skills encode — each one a mistake agents make reliably without them:
| Without skills | With skills |
|---|---|
Invents .SetText(), .HorizontalAlign() |
Derives .Text(), .CenterHorizontal() from the property name |
Emits a .xaml + .xaml.cs pair |
One .cs file, no InitializeComponent() |
new MyViewModel() inside Build() |
View model in a constructor field — state survives hot reload |
.ContentTemplate(new HomePage()) |
.ContentTemplate(() => new HomePage()) |
.TextColor(isDark ? white : black) |
.TextColor(e => e.OnLight(black).OnDark(white)) — a live theme binding |
e.Path("UserName") everywhere |
e.Getter(static (VM vm) => vm.UserName) — compile-checked |
BindableLayout for a 5,000-item list |
CollectionView, because only it virtualizes |
Adds builder.UseFmgLibMauiMarkup() |
Knows no such registration call exists |
| Hand-writes extensions for a Syncfusion control | [MauiMarkup(typeof(SfButton))] and lets the generator do it |
Most of these aren't even in the “doesn't compile” category — three of them (the theme conditional, Path instead of Getter, BindableLayout) compile perfectly well and are still wrong. The distance between the first thing that works and the right thing is exactly the gap the skills fill.
Verifying the install
Ask for something the skills make unambiguous:
Write a MauiMarkup login page with an email entry, a password entry, and a submit button that stays disabled until both are filled.
A correct answer is a single .cs file that implements IFmgLibHotReload, builds the tree in Build(), captures the entries with .Assign(out var …), and contains no XAML at all. If any of that is missing, the skill didn't engage — usually the file is in the wrong folder.
The wider lesson for library authors
The interesting part of this isn't specific to FmgLib.
For years we've written documentation for humans: prose that explains concepts, gives examples, offers rationale. What agents need is different — short, definite instructions that settle decisions. “The method name is the property name” is a boring detail to a human; to an agent it is the difference between a file full of invented methods and a file that compiles.
Three practical conclusions:
- Skills belong in the library's own repository. An API change and its skill update should travel in the same commit; a separate repo or web page inevitably drifts.
- A stale skill is worse than no skill. The agent repeats wrong guidance confidently, and you end up debugging your code instead of its instructions.
- A skill's value is not the API it covers but the mistakes it prevents. Build the “without / with” table before writing the skill: give the agent the task, note what it gets wrong, and write the skill against those failures.
Summary
- Agents get your library wrong not because they don't know it, but because they can't guess your conventions.
- A skill is Markdown with a YAML header; the agent sees only the description and reads the body when the task matches. Unused skills cost nothing.
- Ten skills cover the library's areas; the core
mauimarkupis required in every setup. - If you work in a team, commit them to
<repo>/.claude/skills/so people and CI share one source of truth. - To verify, ask for a simple login page: the answer should be one
.csfile with zero XAML.
What you end up with isn't “letting the AI write code” — it's the agent writing code that follows your library's rules. That difference is roughly the difference between reviewing its output and rewriting it.