CLI
Copies components into your Flutter app. Run it in the project's root.
ashlar init
Writes the theme and AshlarApp into lib/ui, saves your choices in ashlar.yaml, and writes them to
app_theme.dart for AshlarApp(theme: appTheme, darkTheme: appDarkTheme).
ashlar init --base zinc --accent blue --style compact
--base is one of neutral, stone, zinc, mauve, olive, mist or taupe; --accent
one of seventeen colours; --style standard, compact, rounded, sharp, dense or soft. --path lib/widgets/ui
puts components in another folder. --prefix SL puts your own prefix on every name the components declare, as a design system marks its parts: SLButton, SLTheme, showSLToast. They then never clash with Material's Card or Dialog in a file that imports both. Text and prose are left alone, and blocks, whole screens of your app, keep their own names.
ashlar apply
Chooses the theme again with the same options, in a project that has one; --accent none takes the accent away. Your components are left as they are.
--prefix Mz renames everything to a new prefix: the components, ashlar's copies of them, and every use in your own code under lib and test, so the app still builds.
--prefix none takes it away.
ashlar add <item>...
Copies the components named, with the ones they need, and adds any package they need. A file you already have is kept: it is yours.
--overwrite replaces it, --all adds every component, and --blocks
every block, whole screens, into lib/blocks with their imports pointing at your components.
Each component comes with the tests that check what it promises, written to test/ashlar and run by flutter test with your own: that a screen reader reaches Swipe Actions without swiping, that a dialog rises above the keyboard. Change a component and its tests say which promise the change broke. A test that uses another component, as most use a Button to open things, is written once you have that one too.
--no-tests, or tests: false in ashlar.yaml, leaves them out.
ashlar view <item>...
What an item is, what it needs, its files and its tests, before you add it.
ashlar search [words]
Items whose name or description has the words. ashlar list lists them all, ticking the ones you have.
ashlar diff [item...]
For each item you have, whether your copy is as it was written, changed by you, or older than this version: ashlar keeps a fingerprint of each file it writes. Name items to see the lines that differ.
ashlar update [item...]
Takes what is newer and keeps your changes. A file you have not changed is replaced; one you have is merged, line by line, from the copy ashlar kept of what it wrote. Where you and the new version changed the same lines, both are kept between
<<<<<<< yours and >>>>>>> ashlar for you to choose.
--dry-run says what it would do. The copies are in .ashlar/base: commit them, so your whole team can update.
--preview draws each component the update would change, in your theme, as it is and as it would be, side by side on a page in .ashlar/review. Nothing in your app changes until you run it without.
ashlar check
Reports what can be proved about your app's accessibility, each with where it is and what to do, and exits 1 when it finds something, for CI. It measures your theme's contrast by building it in a flutter test: text against WCAG 1.4.3 (4.5:1), the focus ring and field borders against 1.4.11 (3:1). In your source under lib it finds a Button or Toggle holding only an icon with no
semanticLabel; physical left and right where start and end follow the reading direction, such as
EdgeInsets.only(left:) and TextAlign.left; and touch targets turned off with
tapTarget: 0.
Contrast, measured in lib/ui/app_theme.dart:
light field border on the page is 1.26:1; WCAG 1.4.11 needs 3:1.
Labels:
lib/orders.dart:16 A Button with only an icon has no semanticLabel: a screen
reader says only "button". Give it semanticLabel: '…'.
Right to left:
lib/orders.dart:24 TextAlign.right stays put in a right-to-left language:
use TextAlign.end.
It says what it did not check, as source cannot show it: the size of your own tap areas and labels on your own controls. A line that means it can say
// ashlar: ignore. --no-contrast skips the measuring.
ashlar book
A catalog of the components you have, in your theme: an app of its own, written to .ashlar/book, with a page for each and switches for dark, text at 200% and right to left. Run it on any device:
flutter run -t .ashlar/book/main.dart
ashlar mcp
These commands for a coding agent, over the Model Context Protocol: search, view (the source, whose doc comments are the API), add, update and check, each running what you would run, in the folder the agent starts it in. In Claude Code:
claude mcp add ashlar -- ashlar mcp
Other agents take the same command in their MCP settings:
{ "mcpServers": { "ashlar": { "command": "ashlar", "args": ["mcp"] } } }
ashlar build [registry.json]
Makes the files of a registry of your own, in public/r unless --out says otherwise. Describe your items the way Ashlar's own are:
{
"brand-card": {
"description": "A card with our mark.",
"files": ["brand_card.dart"],
"requires": ["card", "brand"]
}
}
Host the files anywhere, or keep them in a folder, and name the registry in a project's ashlar.yaml:
registries:
"@acme": https://acme.dev/r
Then ashlar add @acme/brand-card, view and search @acme work as they do for Ashlar's items. A file that would land outside the components or blocks folder is refused.