wind_kit_diagnostics_contracts
Read wind_kit widget state without depending on wind_kit.
Pure abstract contracts and a process-global registry, so debug tools and AI agents see className, breakpoint, brightness and states while wind_kit and the tool stay strangers. Frozen v1 contract.
Documentation · pub.dev · Issues
At a glance
| Fact | Value |
|---|---|
| Package | wind_kit_diagnostics_contracts |
| Install | flutter pub add wind_kit_diagnostics_contracts |
| Import | package:wind_kit_diagnostics_contracts/wind_kit_diagnostics_contracts.dart |
| Entry points | WindDebugResolver (per-element widget state), WindPerfResolver (process-wide counters), WindDebugRegistry (the two slots) |
| Platforms | All: plain Dart over Flutter's Element, no UI, no native code |
| Requires | Dart >=3.4, Flutter >=3.27 |
| Dependencies | flutter and meta only |
| License | MIT |
Install
flutter pub add wind_kit_diagnostics_contracts
Most apps never add it by hand: wind_kit depends on it, so any app that uses wind_kit already has it. Add it when you author a debug tool that reads wind_kit state.
Why it exists
wind_kit knows each widget's resolved state (className, breakpoint, brightness, platform, states, colours). Debug tools such as tapir put that state in their snapshots so an LLM agent can reason about the rendered tree. Handing it over through wind_kit's own API would make every tool depend on wind_kit's whole rendering surface; the other way round would make wind_kit depend on every tool.
This package breaks the loop. Both sides depend on the contract here, and neither imports the other. It follows Flutter's *_platform_interface convention.
wind_kit_diagnostics_contracts
|
+-------------+-------------+
| |
wind_kit tapir
(implements a resolver) (reads it at snapshot time)
WindDebugResolver
One method, resolve(Element), answers per-element widget state. An element with nothing to report (not a W-widget, or one without a className) resolves to an empty map, so a tool can walk any tree.
import 'package:flutter/widgets.dart';
import 'package:wind_kit_diagnostics_contracts/wind_kit_diagnostics_contracts.dart';
void emitWindBlock(StringBuffer buffer, Element element) {
final WindDebugResolver? resolver = WindDebugRegistry.current;
if (resolver == null) return; // wind_kit is not in this app, or this is a release build.
final Map<String, Object?> data = resolver.resolve(element);
if (data.isEmpty) return; // Nothing to report for this element.
buffer.writeln('wind:');
data.forEach((String key, Object? value) => buffer.writeln(' $key: $value'));
}
| Key | Type | Present |
|---|---|---|
className |
String |
For a W-widget with a non-empty className |
breakpoint |
String |
sm, md, lg, ... |
brightness |
String |
light or dark |
platform |
String |
web, ios, android, macos, ... |
states |
List<String> |
hover, focus, ... |
bgColor, textColor |
String (hex) |
Only when resolved |
WindPerfResolver
A second, independent contract for numbers that belong to no single element: cache hits, build counts, inherited-widget reads. It has its own slot, and registering one contract never touches the other.
import 'package:wind_kit_diagnostics_contracts/wind_kit_diagnostics_contracts.dart';
Map<String, Object?>? readStats() {
final WindPerfResolver? perf = WindDebugRegistry.currentPerf;
if (perf == null) return null; // No resolver was ever registered.
return perf.stats();
}
stats() returns cacheHits, cacheMisses, cacheBypasses, cacheSize, wDivBuilds and wTextBuilds as int, plus widgetBuilds, wrapperEmissions and inheritedReads as Map<String, int>. Keep the null: it tells "no resolver registered" apart from a resolver that reports zeros. A zero is ambiguous on its own, because wind_kit counts only during a measurement session (cacheSize is always live).
Registering
The host app installs both resolvers through wind_kit at boot, behind !kReleaseMode, so a release build tree-shakes them. wind_kit never makes these calls itself:
import 'package:flutter/foundation.dart';
import 'package:wind_kit/wind_kit.dart';
void main() {
if (!kReleaseMode) {
Wind.installDebugResolver();
Wind.installPerfResolver();
}
}
Testing
WindDebugRegistry ships three @visibleForTesting seams: resetForTesting() clears both slots, registerForTesting and registerPerfForTesting fill one each. See the testing guide.
For AI coding agents
Rules for an agent writing code against this package. Each one is a mistake the maintainers already made once.
| Do | Because |
|---|---|
Import only package:wind_kit_diagnostics_contracts/wind_kit_diagnostics_contracts.dart |
It is the only library; everything is public through it. |
Read WindDebugRegistry.current and currentPerf on every use and handle null |
The host may install after your tool starts, or never (release build, no wind_kit, or no install call). null means no resolver; an empty map means the element has nothing to report. |
| Read the keys you need and ignore the rest | A minor release adds keys. Renaming or removing one is a major bump. |
Take per-type build counts from widgetBuilds, not wDivBuilds or wTextBuilds |
The two older keys duplicate widgetBuilds['WDiv'] and ['WText'] and stay only for the 1.x line. |
Treat zeros in stats() as ambiguous |
wind_kit counts only during a measurement session, so a zero can mean it is off. Only cacheSize is always live. |
Register through register and registerPerf, and call *ForTesting only from test/ |
The testing seams are @visibleForTesting; a fake installed through register reads as production wiring. |
Call WindDebugRegistry.resetForTesting() in setUp or tearDown |
The registry is process-global and survives between tests. |
| Never add a method to either contract | It breaks every implementer, test fakes included, so it is a major bump. Add a key, or a new contract. |
Dependencies
flutter (for Element) and meta (for @visibleForTesting). That is the whole surface, on purpose: a dependency added here is a dependency forced on wind_kit and every tool.
Links
- Documentation: installation, the registry, both resolvers, testing and versioning
- API reference
- llms.txt for AI coding agents
- Changelog
- Report an issue
- Security policy
License
MIT, see LICENSE. Built by Anılcan Çakır.
Libraries
- wind_kit_diagnostics_contracts
- Pure abstract contracts for Wind UI diagnostic introspection.