Architecture#
How flet-pkg works internally.
Overview#
flowchart LR
A[CLI<br/>Typer] --> B[Prompts<br/>Rich]
B --> C[Validators]
C --> D[Registry<br/>Check]
D --> E[Scaffolder<br/>Jinja2]
E --> F[Pipeline]
F --> G{--ai-refine?}
G -->|yes| H[AI Refine]
G -->|no| I[Output]
H --> I[Output]
Module structure#
src/flet_pkg/
├── __init__.py # Version and app name
├── __main__.py # python -m flet_pkg support
├── main.py # Typer app, version callback
├── commands/
│ └── create.py # Create command logic
├── core/
│ ├── analyzer.py # PackageAnalyzer → GenerationPlan
│ ├── downloader.py # PubDevDownloader (pub.dev cache)
│ ├── generators/ # Code generators (Python + Dart)
│ │ ├── base.py # CodeGenerator abstract base
│ │ ├── python_control.py # Main control file
│ │ ├── python_submodule.py # Sub-module files
│ │ ├── python_types.py # types.py (enums, events)
│ │ ├── python_init.py # __init__.py exports
│ │ └── dart_service.py # Dart FletService/FletWidget
│ ├── models.py # DartPackageAPI, GenerationPlan
│ ├── parser.py # Dart API parser + detect_extension_type()
│ ├── pipeline.py # GenerationPipeline orchestrator
│ ├── prompts.py # Rich interactive prompts
│ ├── registry_checker.py # PyPI, GitHub, Flet SDK name conflict check
│ ├── scaffolder.py # Jinja2 template engine
│ ├── type_map.py # Dart → Python type mapping
│ └── validators.py # Name validation + derivation
├── core/ai/
│ ├── agent.py # pydantic-ai Architect/Editor agents
│ ├── config.py # AIConfig + provider detection
│ ├── gap_analyzer.py # Deterministic coverage gap analyzer
│ ├── models.py # GapReport, RefinementResult, etc.
│ ├── provider.py # Model factory for pydantic-ai
│ └── refiner.py # AIRefiner orchestrator
├── mcp/
│ ├── server.py # FastMCP server (tools, resources, prompts)
│ └── _serializers.py # Dataclass → dict helpers
├── ui/
│ ├── console.py # Rich console instance
│ ├── coverage.py # Coverage score + breakdown table
│ ├── panels.py # Header, info, error panels
│ └── tree.py # Project tree display
└── templates/
├── service/ # Service extension template
└── ui_control/ # UI Control extension template
Data model#
Two aggregates flow through the pipeline: the parser produces a
DartPackageAPI (a faithful view of the Dart source), and the analyzer
transforms it into a GenerationPlan (what the generators emit). Both live in
core/models.py.
classDiagram
direction LR
class DartPackageAPI {
+list~DartClass~ classes
+list~DartEnum~ enums
+list~DartClass~ helper_classes
+list~DartMethod~ top_level_functions
+dict reexported_types
}
class DartClass {
+str name
+str parent_class
+str source_file
+list~DartMethod~ methods
+list~DartParam~ constructor_params
}
class DartMethod {
+str name
+str return_type
+bool is_static
+bool is_getter
+bool is_async
}
class DartParam {
+str name
+str dart_type
+bool required
+bool named
}
class DartEnum {
+str name
+list values
}
DartPackageAPI o-- DartClass
DartPackageAPI o-- DartEnum
DartClass o-- DartMethod
DartClass o-- DartParam : constructor_params
DartMethod o-- DartParam
class GenerationPlan {
+str control_name
+str base_class
+list~PropertyPlan~ properties
+list~MethodPlan~ main_methods
+list~EventPlan~ events
+list~SubModulePlan~ sub_modules
+list~EnumPlan~ enums
}
class MethodPlan {
+str python_name
+str return_type
+bool is_async
+bool dart_is_async
+bool is_static
+list~ParamPlan~ params
}
class PropertyPlan {
+str python_name
+str python_type
+str dart_getter
}
class EventPlan {
+str python_attr_name
+str event_class_name
}
class SubModulePlan {
+str module_name
+str class_name
+list~MethodPlan~ methods
}
GenerationPlan o-- PropertyPlan
GenerationPlan o-- MethodPlan
GenerationPlan o-- EventPlan
GenerationPlan o-- SubModulePlan
MethodPlan o-- ParamPlan
SubModulePlan o-- MethodPlan
DartPackageAPI ..> GenerationPlan : PackageAnalyzer.analyze()
Key components#
Typer CLI (main.py)#
The entry point registers the create command and a --version callback. Uses rich_markup_mode="rich" for styled help text.
Create command (commands/create.py)#
Orchestrates the creation flow:
- Determines extension type (from flag or interactive prompt). If
auto, downloads the Flutter package and callsdetect_extension_type()to resolve it. - Collects Flutter package name, project name, package name, control class name
- Calls
derive_names()to auto-suggest names - Checks PyPI, GitHub, and Flet SDK monorepo for name conflicts via
registry_checker - Builds a context dict and passes it to
Scaffolder - Runs the analysis pipeline (download → parse → analyze → generate)
- Optionally runs AI refinement if
--ai-refineis set - Displays coverage score and the generated project tree
Registry checker (core/registry_checker.py)#
Checks for existing packages with the same name before scaffolding:
- PyPI —
GET https://pypi.org/pypi/{name}/json(200 = exists) - Flet SDK — checks
flet-dev/fletmonorepo atsdk/python/packages/{name}via GitHub Contents API - GitHub — searches repositories matching the name (top 3 results)
All checks fail silently on network errors to avoid blocking the flow.
Validators (core/validators.py)#
validate_flutter_package()— valid pub.dev namevalidate_project_name()— lowercase + hyphensvalidate_package_name()— valid Python identifiervalidate_control_name()— PascalCasederive_names()— strips Flutter affixes and derives all names from the Flutter package name
Scaffolder (core/scaffolder.py)#
Uses Jinja2 to render templates:
- Walks the template directory tree
- Resolves
{{variable}}placeholders in directory and file names - Renders
.jinjafiles through Jinja2 with the context dict - Copies non-Jinja files as-is
Generation Pipeline (core/pipeline.py)#
Orchestrates the full code generation flow:
- Download — fetches the Flutter package from pub.dev (or uses a local path)
- Parse — extracts
DartPackageAPIfrom Dart source files - Analyze — produces a
GenerationPlan(methods, events, enums, properties, sub-modules) - Generate — runs 5 generators to produce Python + Dart files
- Write — writes generated files to the project directory, overwriting template stubs
- Gap analysis — computes coverage percentage
- AI refine (optional) — runs the Architect/Editor pattern for improvements
flowchart TD
DL[Download<br/>pub.dev or local] --> PA[Parse<br/>DartPackageAPI]
PA --> AN[Analyze<br/>GenerationPlan]
AN --> GEN[Generate<br/>5 generators]
GEN --> WR[Write files<br/>overwrite stubs]
WR --> GAP[Gap analysis<br/>coverage percent]
GAP --> REF{--ai-refine?}
REF -->|yes| AI[AI Refine<br/>Architect/Editor]
REF -->|no| OUT[Project ready]
AI --> OUT
PA -. produces .-> APIOBJ[(DartPackageAPI)]
AN -. produces .-> PLANOBJ[(GenerationPlan)]
APIOBJ -. consumed by .-> AN
PLANOBJ -. consumed by .-> GEN
Generators (core/generators/)#
Five specialized generators produce different parts of the output:
| Generator | Output |
|---|---|
PythonControlGenerator |
Main control file (e.g. onesignal.py) |
PythonSubModuleGenerator |
Sub-module files (e.g. user.py, notifications.py) |
PythonTypesGenerator |
types.py with enums and event dataclasses |
PythonInitGenerator |
__init__.py with exports |
DartServiceGenerator |
Dart service/widget files + extension.dart |
AI Refinement (core/ai/)#
Optional LLM-powered code improvement using the Architect/Editor pattern:
- Gap Analyzer (
gap_analyzer.py) — deterministic comparison ofDartPackageAPIvsGenerationPlanto find coverage gaps - Architect agent — LLM reasons about WHAT to improve based on the gap report
- Editor agent — LLM produces search/replace edits (HOW to fix)
- Validator — checks syntax of edited files and retries on failure
flowchart LR
GA[Gap Analyzer<br/>DartPackageAPI vs GenerationPlan] --> R[(Gap report)]
R --> AR[Architect agent<br/>WHAT to improve]
AR --> ED[Editor agent<br/>search/replace edits]
ED --> V{Validator<br/>syntax OK?}
V -->|no, retry| ED
V -->|yes| DONE[Refined files]
Supports multiple providers: Ollama (local, free), Anthropic, OpenAI, Google.
Coverage#
The gap analyzer computes a coverage score:
Categories tracked: Methods, Events, Enums, Properties.
MCP Server (mcp/server.py)#
Exposes flet-pkg capabilities to AI agents via the Model Context Protocol:
- 7 tools: derive_names, map_dart_type, fetch_metadata, detect_extension_type, scaffold, run_pipeline, analyze_gaps
- 2 resources: type-map, templates
- 3 prompts: scaffold_service, scaffold_ui_control, analyze_package
See the MCP Server documentation for configuration details.
Templates#
Templates live under src/flet_pkg/templates/. Each template type has:
template.yaml— template metadata- A directory tree with
{{variable}}placeholders in names .jinjasuffix on files that need rendering
Variable substitution happens both in file/directory names and in file contents (for .jinja files).