π¬ v0.25.0 β Static Analysis, MCP Introspection & Form Autosave
Midwest becomes introspectable. A new bin/ast command exports a static AST and a whole-library dependency graph for every component, and three new MCP tools β get_motion_system, get_performance_characteristics, and get_bundle_analysis β let an AI assistant reason about how the library animates, how expensive a component is to render, and what a component pulls in when you use it. The MCP server now exposes 21 tools. On the app side, midwest_form_with gains three opt-in behaviors: background autosave, ajax submission, and close-a-modal-on-success.
What's New
bin/ast β Static AST & dependency-graph export
bin/ast generates static, per-component AST files (options, slots, constants, methods, and Stimulus values/targets/actions) plus a whole-library render graph β which components render which. The graph is derived from every render syntax: typed slots, midwest_* helper calls in ERB, direct render Midwest::YComponent.new, and Midwest::YComponent.new constructions in the Ruby definition.
The Ruby side is parsed with Prism, so it's immune to class names appearing in comments, strings, is_a? checks, or < Superclass inheritance β no regex, no false edges. Each component gets a <name>.ast.json and a <name>.ast.md (the latter embeds a Mermaid graph TD of its render edges) in its own sidecar directory, while the aggregate graph.json, index.json, and DEPENDENCIES.md land in a top-level ast/ directory.
bin/ast # summary (default)bin/ast graph # dependency graphThese files travel with the gem via app/** and never reach the npm package. Everything is derived from the same parsers the MCP server uses, so the files never drift, and bin/build regenerates them automatically on every version cut.
get_motion_system β Holistic motion documentation
A new MCP tool documents the motion system as a whole rather than component-by-component: the standardized duration/easing scales (token-derived, with what each step is for), the slide-distance scale, the animation/direction/trigger vocabulary, the library-wide prefers-reduced-motion / no-JS contract, and how app-wide defaults are configured and resolved. It's sectioned (strategy / durations / easings / distances / vocabulary / reduced_motion / configuration) and complements the per-component get_animation_info and raw-value get_design_tokens tools.
get_performance_characteristics β Rendering-cost tiers & dataset limits
This tool reports each component's rendering-cost tier (light / moderate / heavy) and dataset limits. Structural signals are derived from the code so they never drift (does it render a collection via renders_many, ship a Stimulus controller, or run looping keyframe motion?), and a curated data/performance.yml overlay adds recommended dataset sizes and scaling strategies (pagination, infinite scroll, lazy loading). Two modes: a per-component profile, or a library-wide overview ranking the dataset-sensitive components by tier.
get_bundle_analysis β Transitive footprint & cycle detection
get_bundle_analysis reports the transitive set of components a given component renders (via slots, template helpers, direct renders, and Ruby constructions β from the Prism-backed render graph), the summed asset footprint of that set (co-located CSS + Stimulus controller source, with a per-component breakdown), and render-cycle detection. It's built on the same ComponentIndex render graph that backs bin/ast.
What Changed
midwest_form_with β Autosave, ajax & close-on-success
midwest_form_with gains three opt-in behaviors driven by the midwest-form Stimulus controller:
autosave:β debounced background submit on field change (truefor the 600 ms default, or a number of milliseconds). Submissions run throughrequestSubmit(), so constraint validation still fires and buttons still reflect their loading state.ajax:β forces a Turbo background submission (never a full-page navigation) and emitsmidwest-form:success/midwest-form:errorDOM events you can hook into.close_modal_on_success:β reuses the dialog controller'shideaction to dismiss an enclosingmidwest_dialogon a successfulturbo:submit-end.
The options compose freely β an autosaving form can also be an ajax form, and a modal form can close on success while submitting in the background.
<%= midwest_form_with(model: @profile, autosave: true) do |f| %> <%= f.text_field :display_name %><% end %>See the new Form Behaviors reference for full details.
get_component_relationships β Full render graph
The get_component_relationships MCP tool now reports the complete render graph from bin/ast's Prism-backed parser β typed slots, direct renders, and Ruby-side constructions β instead of just midwest_* helper calls. The relationships it returns now match what ships in the AST sidecar files.
What Was Removed
Nothing was removed, and there are no breaking API changes this release. For the record, three items originally scoped to the v0.25 milestone were cut from the pre-1.0 roadmap: Parallax effects, the Web Audio suite, and the runtime Animation Controller (along with its documentation API).
Dev Process
- CI drift-guard β a new CI step runs
bin/ast buildand checksgit status, failing the build if the committed AST/graph files have gone stale relative to the source.bin/releasealso stages the regenerated files on every version cut. - Parsers β the render-graph logic lives in a testable
Midwest::MCP::AstExporter, built onComponentIndex#render_edges_for,#render_targets, and#source_bytes_for. A newPerformanceIndexbacks the performance tool. - Tests β new suites for the AST exporter, the component parser and index, the new MCP tools, and a button-loading system test (β700 lines of new test code).
- Docs β a new Form Behaviors reference page, plus an expanded MCP server doc covering all 21 tools.
- Gemfile locks β routine lock bumps for the Rails 7, Rails 8, and Bridgetown v1/v2 gemfiles.