It compiles. It's still wrong.
Let an AI agent build a Flutter feature with no guidance and you get code that runs. Mostly. But it looks like it was written by someone who has never seen your project.
Hardcoded colors in widgets. Strings in the code instead of localization. Navigation through string paths. A Cubit that creates its own repository because that's the quickest way. API keys sitting in a Dart file.
None of that is nonsense. It compiles, it works. It's just not what your team expects. That's what a talk at FlutterCon 2026 was about, and it's been on my mind since: how do you get agents to write code that's allowed to stay in your project?
Why agents write average code
The explanation in the talk was simple. Models learned from the internet. If you don't say anything else, you get the internet's average. The average isn't bad, but it isn't your standard either.
I think that's the most important mental shift. The AI isn't too dumb. It just doesn't know how you do things. So you have to teach it, and in more than one place, not just in a single prompt.
The team behind the talk, Very Good Ventures, built a plugin for this. According to them it's open source. It has three parts: skills, hooks and fixed tools. The principle works for any project.
Skills: your standard as a file
A skill is basically a file with metadata (name, description) and a body. The body holds standards, folder structure, code samples, testing strategy and anti-patterns.
The catch: the description decides whether the agent pulls the skill at all. You write a prompt, the agent matches it against all skill descriptions and, on a hit, loads the content into context. Until then the skill costs almost nothing. Only when it's needed do a few thousand tokens land in context. Or you call it directly with a slash command.
The plugin ships 15 skills, roughly in four groups:
- Architecture: Bloc, layered architecture, navigation
- UI: Material theming, UI packages, accessibility, internationalization, animations
- Quality and security: testing, security, license compliance
- Operations: project creation, SDK and analysis upgrades
The examples from the talk show what changes. Without a skill: a Cubit with a hardwired repository and several flags. With a skill: sealed classes for events and states, repository injected through the constructor, tests with Mocktail. Without: strings and colors inside the widget. With: theme, ColorScheme and localization. For navigation: typed routes the compiler checks, instead of string paths.
Accessibility and internationalization are the first things to fall off under deadline pressure. That's a perfect job for a skill. It doesn't forget because there's a deadline.
Hooks: don't hope the model remembers
Skills are instructions. Whether the agent follows them is still partly a matter of probability. So for me the second part of the talk was the more interesting one: hooks.
A hook is an event handler. The model tooling fires events like "session started", "a tool is about to be used" or "a file was edited", and your hook can react. You set it up in a JSON file. The idea: don't rely on the model, rely on deterministic steps around it.
The plugin comes with six hooks. Three examples from the talk:
- Session start: if the Very Good CLI is missing or outdated, you get a notice.
- Before a tool call: if the agent reaches for the CLI although an MCP server is available, it gets sent back. Similar for
flutter test:very_good testshould handle that, which the speaker said is faster. - After an edit: analysis and formatting run automatically. The model doesn't have to decide whether to remember.
The last one is the underrated one, in my opinion. The model only roughly knows your lint rules. A hook that runs the analyzer after every change knows them exactly.
Fixed tools instead of burning tokens
One thought runs through the whole talk: whatever can be deterministic shouldn't be done by the model.
Take project setup. The Very Good CLI generates new projects from ready-made templates (Mason). You give it a package name and organization, done. If you leave that to the model instead, you wait longer, pay tokens and probably still don't get the structure you wanted.
Take licenses. You can ask the model to check your dependencies' licenses. It might miss something. A tool that walks through all packages and reports back misses nothing.
On top of that come two MCP servers: the Dart and Flutter MCP server and one for the Very Good CLI. Analysis errors, pub.dev search or package scaffolding go through those, not through the model's guesswork.
By the way, VGV's minimum for testing is 100 percent coverage. A "green gate" skill loops over analysis and tests and only finishes once everything passes.
Bloc or Cubit? A question from the audience
Someone in the audience asked why the skill defaults to Bloc when Cubit is simpler. I liked the answers because they were honest:
- Bloc is easier to scale and predict. Events can be traced.
- With the
BlocObserveryou can track events and states automatically, for analytics for example. In a Cubit the event is just a method signature, so you end up putting the tracker into the logic. Then your business logic contains things that aren't business logic. - According to the speaker, models make fewer mistakes with Bloc because the structure is more strictly defined.
- If you give the skill context (no analytics needed, no rollback), it can go with Cubit.
I find the attitude behind this notable: more code, but more automation. I wrote down where I stand in my post on state management in Flutter. For small apps a Cubit is plenty. For large codebases I get the Bloc argument.
You never finish writing a skill
Three takeaways on writing skills:
Let the model write the first draft. Finish a feature in a normal prompting session, then ask the agent to turn it into a skill. Skills are written for models, not humans. The model knows how to structure one for another model.
Your code is a reference too. The agent looks at the existing codebase. And, paraphrasing: bad patterns spread faster than good ones. If the skill says A and your code shows B, you get spaghetti. That's why clean scaffolding at the start of a project pays off.
With legacy code, say explicitly what not to copy. The agent should follow your new knowledge, not rebuild the old bugs.
And one more thing: a skill is never done. When the team spots a bad pattern, it goes straight into the skill.
Evaluate skills, and sometimes delete them
The part I took away most: skills need to be measured. The team compares output with and without the skill. If the sealed events or the repository injection are missing without it and present with it, the skill has proven its worth. If the output is the same either way, the content can go and you save tokens.
Important here: models aren't deterministic. The speaker recommended running it at least three times so you see an average and not a lucky hit. And re-measure with every new model. What's needed today, the next model may already do on its own.
What I take from this
I see this as the opposite of the "I'll just prompt better" mindset. Better prompts help. But a standard that only lives in your head or in a chat history doesn't survive a team change or a model version.
My conclusion in three steps, as I understood the talk: write the standards down first. Then pull everything checkable out of the model and into hooks and tools. Then measure whether the model still needs the skill at all.
It also fits what I write about AI in app development: producing code is cheap. The bottleneck is being able to trust it. And if you want to ship faster instead of perfecting, you need guardrails like these so speed doesn't turn into chaos. How this plays with CI/CD is the logical next step.
"Wingspan" got a brief mention too, a workflow layer on top (brainstorming, planning, build, review), along with plans to support other agent environments. The talk gave no details on that, so I'll leave it there.
Conclusion
An agent writes what it has seen on the internet. If you want something different, you need three things: skills that describe your standard, hooks and fixed tools that enforce it, and measurements that show whether both still help.
Whether you use the VGV plugin or build your own skills is secondary. The principle matters: trust the model to write, but not to check.
Frequently asked questions (FAQ)
A file with a name, a description and instructions. If your prompt matches the description, the agent loads the content into context and sticks to the standards and examples in it. You can also call it directly with a slash command.
Skills are instructions the model is supposed to read and follow. Hooks are event handlers that run automatically, for example analysis and formatting after every file change. Hooks don't depend on the model remembering.
According to the talk, Bloc is the sturdier default for large codebases. Events are traceable, analytics can be automated through the BlocObserver, and models make fewer mistakes with the fixed structure. For small projects without those needs, a Cubit can be enough.
Templates are faster, cost no tokens and give you the same structure every time. The Very Good CLI creates new projects from vetted templates. The model only has to call the tool.
Compare the output with and without the skill, and do it several times, at least three, because models aren't deterministic. If the result is the same, the skill is redundant and can be trimmed. Repeat when a new model version comes out.
This article was inspired by the Very Good Ventures team's talk on their Flutter AI plugin at FlutterCon 2026.



