From d8fc9894691d99669931b28d962672897362bb0b Mon Sep 17 00:00:00 2001 From: Kamil Sztandur Date: Mon, 21 Sep 2026 18:54:58 +0200 Subject: [PATCH 1/8] Make the skill a Dart package skill: `dart run skills@ get` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dart's skills CLI installs the skills a project's dependencies carry into the folder the detected agent reads, and offers updates after a package upgrade — nobody has to know we have a skill or where their agent keeps skills. It requires the folder to be named -, so skills/advanced_forms/ becomes skills/advanced_forms-forms/ and `name:` follows. Verified against example/, which depends on the package by path: the CLI detects Claude Code, installs to .claude/skills/advanced_forms-forms/ and lists it. The docs page leads with the CLI; copy-paste and curl stay for reading the skill before adding the package, or for an agent the CLI does not know. README and CHANGELOG follow. Co-Authored-By: Claude Fable 5.1 --- CHANGELOG.md | 1 + README.md | 8 ++-- docs/agent-skill.mdx | 38 ++++++++++++++----- docs_app/lib/shared.ts | 4 +- docs_app/lib/skill.ts | 4 +- landing/lib/site.dart | 2 +- .../SKILL.md | 2 +- 7 files changed, 39 insertions(+), 20 deletions(-) rename skills/{advanced_forms => advanced_forms-forms}/SKILL.md (99%) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3b7f92..fc99041 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ * `setOptions(List)` on `AdvancedSingleSelectFieldController` and `AdvancedMultiSelectFieldController`: the list of options can change while the form is open. A selected value that is not on the new list is cleared as a program write (no user edit, no error on an untouched field); widgets rebuild even when the value stayed the same. * The single-select controller now copies the `options` you pass, as the multi-select always did. `options` is an unmodifiable list on both. +* The Agent Skill is a [package skill](https://dart.dev/tools/pub/package-skills): `dart run skills@ get` installs it into your agent's skills folder. The folder moved from `skills/advanced_forms/` to `skills/advanced_forms-forms/`, the name the CLI requires; the skill now adds the package with `flutter pub add advanced_forms` when the project lacks it. ## 0.2.1+1 diff --git a/README.md b/README.md index a8519a6..28d53af 100644 --- a/README.md +++ b/README.md @@ -23,13 +23,13 @@ - **Granular rebuilds** — one builder per field, so a keystroke rebuilds one subtree and nothing else. > [!TIP] -> **Using Claude Code (or another agent that supports Agent Skills)?** This package ships an [Agent Skill](https://advanced-forms.leancode.co/docs/agent-skill) that teaches your agent the full API, so it generates fields, validation, cross-field logic, and subforms idiomatically. Installing it is one command: +> **Using Claude Code (or another agent that supports Agent Skills)?** This package ships an [Agent Skill](https://advanced-forms.leancode.co/docs/agent-skill) that teaches your agent the full API, so it generates fields, validation, cross-field logic, and subforms idiomatically. With `advanced_forms` in your `pubspec.yaml`, one command installs it into your agent's skills folder: > > ```sh -> mkdir -p .claude/skills/advanced_forms && curl -fsSL https://advanced-forms.leancode.co/skill.md -o .claude/skills/advanced_forms/SKILL.md +> dart run skills@ get > ``` > -> Or copy the file from [the docs](https://advanced-forms.leancode.co/docs/agent-skill) and paste it into `.claude/skills/advanced_forms/SKILL.md`. Then say *"build me a sign-up form"* — the agent adds the package if it is missing and writes the form. +> Not using the package yet? Copy the file from [the docs](https://advanced-forms.leancode.co/docs/agent-skill) into `.claude/skills/advanced_forms-forms/SKILL.md`, then say *"build me a sign-up form"* — the agent adds the package and writes the form. ## Website: interactive examples and docs @@ -150,7 +150,7 @@ Own the controller wherever you like — it's a `ChangeNotifier`, so any DI pack - [MIGRATION.md](https://github.com/leancodepl/advanced_forms/blob/main/MIGRATION.md) — coming from 0.1.x. - `example/` — a runnable app where every pattern in these docs has a working screen. See [example/example.md](https://github.com/leancodepl/advanced_forms/blob/main/example/example.md) for the screen guide. - [API reference](https://pub.dev/documentation/advanced_forms/latest/) — the generated dartdoc, for every member and its edge cases. -- [Agent Skill](https://advanced-forms.leancode.co/docs/agent-skill) — `skills/advanced_forms/SKILL.md`, a skill that teaches your agent the full API, so it generates fields, validation, cross-field logic, and subforms idiomatically. One `curl` or one copy-paste puts it into your project's `.claude/skills/`. +- [Agent Skill](https://advanced-forms.leancode.co/docs/agent-skill) — `skills/advanced_forms-forms/SKILL.md`, a skill that teaches your agent the full API, so it generates fields, validation, cross-field logic, and subforms idiomatically. `dart run skills@ get` installs it into your project's agent skills folder. ## Rendering fields diff --git a/docs/agent-skill.mdx b/docs/agent-skill.mdx index e7ceb4a..7777055 100644 --- a/docs/agent-skill.mdx +++ b/docs/agent-skill.mdx @@ -14,8 +14,9 @@ The package ships an [Agent Skill](https://agentskills.io): a single Markdown fi a task looks like form work, so it generates fields, validation, cross-field logic and subforms the way these docs describe them rather than the way a generic Flutter tutorial would. -Copy the file into your project and say *"build me a sign-up form"*. The agent adds the package to `pubspec.yaml` if -it is not there yet, writes the controller and the widgets, and wires the validation — you do not open the docs. +Run `dart run skills@ get` in your project — or copy the file — and say *"build me a sign-up form"*. The agent adds the +package to `pubspec.yaml` if it is not there yet, writes the controller and the widgets, and wires the validation — you +do not open the docs. @@ -32,17 +33,33 @@ it is not there yet, writes the controller and the widgets, and wires the valida ### Create the file - + + + +The skill ships inside the package, so once `advanced_forms` is in your `pubspec.yaml`, +[Dart's skills CLI](https://dart.dev/tools/pub/package-skills) installs it — and every other skill your dependencies +carry — into the folder your agent reads: + +```sh +dart run skills@ get +``` + +It detects the agent from the project (`.claude/skills/` for Claude Code, `.cursor/skills/`, `.github/skills/`, +`.agents/skills/` for the rest; `--agent claude` to force one) and asks which skills to install; `--all` skips the +question. After a package upgrade, run it again and it offers to update the skill. `dart run skills@ list` shows what +is installed, `dart run skills@ prune` removes skills of dependencies you dropped. + + Press **Copy SKILL.md** above, create this file in your project and paste: ```text -.claude/skills/advanced_forms/SKILL.md +.claude/skills/advanced_forms-forms/SKILL.md ``` Commit it, and every contributor's agent picks it up. To have it in every project you work on instead, put the same -file under `~/.claude/skills/advanced_forms/SKILL.md`. +file under `~/.claude/skills/advanced_forms-forms/SKILL.md`. @@ -50,11 +67,11 @@ file under `~/.claude/skills/advanced_forms/SKILL.md`. The file is served raw at [`/skill.md`](/skill.md), so the terminal can fetch it into place: ```sh title="Into the project" -mkdir -p .claude/skills/advanced_forms && curl -fsSL https://advanced-forms.leancode.co/skill.md -o .claude/skills/advanced_forms/SKILL.md +mkdir -p .claude/skills/advanced_forms-forms && curl -fsSL https://advanced-forms.leancode.co/skill.md -o .claude/skills/advanced_forms-forms/SKILL.md ``` ```sh title="For every project you work on" -mkdir -p ~/.claude/skills/advanced_forms && curl -fsSL https://advanced-forms.leancode.co/skill.md -o ~/.claude/skills/advanced_forms/SKILL.md +mkdir -p ~/.claude/skills/advanced_forms-forms && curl -fsSL https://advanced-forms.leancode.co/skill.md -o ~/.claude/skills/advanced_forms-forms/SKILL.md ``` Run it again whenever you upgrade the package: the URL always serves the skill for the current release. @@ -62,8 +79,9 @@ Run it again whenever you upgrade the package: the URL always serves the skill f -`.claude/skills/` is where Claude Code looks. Other agents that support Agent Skills read the same file from their own -skills folder — check the agent's docs for the path. +The skills CLI is the one that keeps up with releases; the other two are for reading the skill before you add the +package, or for an agent the CLI does not know. `.claude/skills/` is where Claude Code looks; other agents read the same +file from their own skills folder. @@ -108,7 +126,7 @@ context. It knows the two rules that prevent most bugs — call `registerFields` ## The file This is the skill, whole — the same bytes the copy button and `/skill.md` give you. It lives in the repository at -[`skills/advanced_forms/SKILL.md`](https://github.com/leancodepl/advanced_forms/blob/main/skills/advanced_forms/SKILL.md) +[`skills/advanced_forms-forms/SKILL.md`](https://github.com/leancodepl/advanced_forms/blob/main/skills/advanced_forms-forms/SKILL.md) and this page is built from it, so what you read here is what ships. diff --git a/docs_app/lib/shared.ts b/docs_app/lib/shared.ts index 88f5460..d0eee12 100644 --- a/docs_app/lib/shared.ts +++ b/docs_app/lib/shared.ts @@ -28,7 +28,7 @@ export const docsContentRoute = "/llms.mdx" /** The Agent Skill, served raw so one `curl` (or an agent) can fetch it. */ export const skillRoute = "/skill.md" /** Where the skill goes in a project; `~/` in front makes it global. */ -export const skillInstallPath = ".claude/skills/advanced_forms/SKILL.md" +export const skillInstallPath = ".claude/skills/advanced_forms-forms/SKILL.md" export const gitConfig = { user: "leancodepl", @@ -46,7 +46,7 @@ export const urls = { changelog: `${repo}/blob/${gitConfig.branch}/CHANGELOG.md`, migration: `${repo}/blob/${gitConfig.branch}/MIGRATION.md`, license: `${repo}/blob/${gitConfig.branch}/LICENSE`, - skill: `${repo}/blob/${gitConfig.branch}/skills/advanced_forms/SKILL.md`, + skill: `${repo}/blob/${gitConfig.branch}/skills/advanced_forms-forms/SKILL.md`, exampleApp: `${repo}/tree/${gitConfig.branch}/example`, exampleGuide: `${repo}/blob/${gitConfig.branch}/example/example.md`, exampleWidgets: `${repo}/tree/${gitConfig.branch}/example/lib/widgets`, diff --git a/docs_app/lib/skill.ts b/docs_app/lib/skill.ts index fd2cc4b..e9ea811 100644 --- a/docs_app/lib/skill.ts +++ b/docs_app/lib/skill.ts @@ -7,11 +7,11 @@ import { readFileSync, statSync } from "node:fs" import path from "node:path" /** - * The Agent Skill is one Markdown file in the repo root (`skills/advanced_forms/`), + * The Agent Skill is one Markdown file in the repo root (`skills/advanced_forms-forms/`), * the same one the package ships. Read at build time, like `../docs`, so the * site can never serve a stale copy of it. */ -const skillFile = path.join(process.cwd(), "..", "skills", "advanced_forms", "SKILL.md") +const skillFile = path.join(process.cwd(), "..", "skills", "advanced_forms-forms", "SKILL.md") export interface Skill { /** The file, verbatim. */ diff --git a/landing/lib/site.dart b/landing/lib/site.dart index 318237a..3bc80ae 100644 --- a/landing/lib/site.dart +++ b/landing/lib/site.dart @@ -46,7 +46,7 @@ const apiReferenceUrl = 'https://pub.dev/documentation/advanced_forms/latest/'; const changelogUrl = '$repoUrl/blob/main/CHANGELOG.md'; const migrationUrl = '$repoUrl/blob/main/MIGRATION.md'; const issuesUrl = '$repoUrl/issues'; -const skillUrl = '$repoUrl/blob/main/skills/advanced_forms/SKILL.md'; +const skillUrl = '$repoUrl/blob/main/skills/advanced_forms-forms/SKILL.md'; /// The docs page that installs the Agent Skill: one copy, one file. const skillDocsPath = '$docsPath/agent-skill'; diff --git a/skills/advanced_forms/SKILL.md b/skills/advanced_forms-forms/SKILL.md similarity index 99% rename from skills/advanced_forms/SKILL.md rename to skills/advanced_forms-forms/SKILL.md index 8a57ef6..1f29ff2 100644 --- a/skills/advanced_forms/SKILL.md +++ b/skills/advanced_forms-forms/SKILL.md @@ -1,5 +1,5 @@ --- -name: advanced_forms +name: advanced_forms-forms description: Build Flutter forms with the advanced_forms package (AdvancedFormController, AdvancedTextFieldController, AdvancedFieldBuilder). Use whenever the user creates a form, adds or edits form fields, wires validation (sync, async, or cross-field), chooses when errors appear (ValidationMode), builds dropdowns/checkboxes/multi-selects/sliders bound to field controllers, handles submit buttons or server-side errors, or works with subforms in any Flutter project — whether or not it depends on advanced_forms yet (add it with `flutter pub add advanced_forms`) — even if they never say the word "form". --- From c7866e4b070054b3bb1a4fcb156d03470b60b817 Mon Sep 17 00:00:00 2001 From: Kamil Sztandur Date: Mon, 21 Sep 2026 19:05:12 +0200 Subject: [PATCH 2/8] Landing: the skill band installs with one command too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The band still told visitors to copy a file. Now it carries the same copyable command box the hero has — `dart run skills@ get` — with the box extracted into InstallCommand so the two stay one component. Co-Authored-By: Claude Fable 5.1 --- landing/lib/components/hero.dart | 25 ++----------- landing/lib/components/install_command.dart | 40 +++++++++++++++++++++ landing/lib/components/sections.dart | 28 ++++++++------- landing/lib/site.dart | 3 ++ landing/web/landing.css | 4 +++ 5 files changed, 65 insertions(+), 35 deletions(-) create mode 100644 landing/lib/components/install_command.dart diff --git a/landing/lib/components/hero.dart b/landing/lib/components/hero.dart index 7a86adc..1c51812 100644 --- a/landing/lib/components/hero.dart +++ b/landing/lib/components/hero.dart @@ -1,6 +1,6 @@ import 'package:advanced_forms_landing/components/button.dart'; import 'package:advanced_forms_landing/components/example_frame.dart'; -import 'package:advanced_forms_landing/components/icons.dart'; +import 'package:advanced_forms_landing/components/install_command.dart'; import 'package:advanced_forms_landing/components/pill.dart'; import 'package:advanced_forms_landing/components/section.dart'; import 'package:advanced_forms_landing/examples.dart'; @@ -51,28 +51,7 @@ class Hero extends StatelessComponent { .text(' your app already uses.'), ]), div(classes: 'af-install', [ - div(classes: 'af-install-command', [ - const span( - classes: 'af-prompt', - attributes: {'aria-hidden': 'true'}, - [.text(r'$')], - ), - const code([.text(installCommand)]), - button( - classes: 'af-copy-button', - attributes: const { - 'type': 'button', - 'data-copy-text': installCommand, - 'aria-label': 'Copy to clipboard', - 'aria-live': 'polite', - }, - [ - span(classes: 'af-copy-idle', [Icon.copy.build(size: 15)]), - span(classes: 'af-copy-done', [Icon.check.build(size: 15)]), - const span(classes: 'af-copy-label', [.text('Copy')]), - ], - ), - ]), + const InstallCommand(installCommand), p(classes: 'af-install-alt', [ const .text('Coming from '), const code([.text('leancode_forms')]), diff --git a/landing/lib/components/install_command.dart b/landing/lib/components/install_command.dart new file mode 100644 index 0000000..b1eacff --- /dev/null +++ b/landing/lib/components/install_command.dart @@ -0,0 +1,40 @@ +import 'package:advanced_forms_landing/components/icons.dart'; +import 'package:jaspr/dom.dart'; +import 'package:jaspr/jaspr.dart'; + +/// A shell command in a box with a copy button: `flutter pub add …` in the +/// hero, `dart run skills@ get` in the skill band. The button is wired by +/// `[data-copy-text]` in web/landing.js. +/// +/// Styled by `.af-install-command*` in web/landing.css. +class InstallCommand extends StatelessComponent { + const InstallCommand(this.command, {super.key}); + + final String command; + + @override + Component build(BuildContext context) { + return div(classes: 'af-install-command', [ + const span( + classes: 'af-prompt', + attributes: {'aria-hidden': 'true'}, + [.text(r'$')], + ), + code([.text(command)]), + button( + classes: 'af-copy-button', + attributes: { + 'type': 'button', + 'data-copy-text': command, + 'aria-label': 'Copy to clipboard', + 'aria-live': 'polite', + }, + [ + span(classes: 'af-copy-idle', [Icon.copy.build(size: 15)]), + span(classes: 'af-copy-done', [Icon.check.build(size: 15)]), + const span(classes: 'af-copy-label', [.text('Copy')]), + ], + ), + ]); + } +} diff --git a/landing/lib/components/sections.dart b/landing/lib/components/sections.dart index d9da5f6..c5bf1c2 100644 --- a/landing/lib/components/sections.dart +++ b/landing/lib/components/sections.dart @@ -1,6 +1,7 @@ import 'package:advanced_forms_landing/components/button.dart'; import 'package:advanced_forms_landing/components/example_frame.dart'; import 'package:advanced_forms_landing/components/icons.dart'; +import 'package:advanced_forms_landing/components/install_command.dart'; import 'package:advanced_forms_landing/components/pill.dart'; import 'package:advanced_forms_landing/components/section.dart'; import 'package:advanced_forms_landing/examples.dart'; @@ -364,21 +365,24 @@ class SkillBand extends StatelessComponent { 'The package ships an Agent Skill that teaches Claude ' 'Code — or any agent that supports skills — the full ' '`advanced_forms` API, so it generates fields, validation, ' - 'cross-field logic and subforms idiomatically. One file, ' - 'one copy — then say "build me a sign-up form" and it adds ' - 'the package and writes the form.', + 'cross-field logic and subforms idiomatically. It ships ' + "in the package: one command puts it into your agent's " + 'skills folder, then say "build me a sign-up form".', ), ), ]), - const div(classes: 'af-hero-actions', [ - Button('Get the skill', href: skillDocsPath, leading: .bot), - Button( - 'Read SKILL.md', - href: skillUrl, - variant: .secondary, - external: true, - trailing: .arrowRight, - ), + const div([ + InstallCommand(skillInstallCommand), + div(classes: 'af-hero-actions', [ + Button('How it works', href: skillDocsPath, leading: .bot), + Button( + 'Read SKILL.md', + href: skillUrl, + variant: .secondary, + external: true, + trailing: .arrowRight, + ), + ]), ]), ]), ]), diff --git a/landing/lib/site.dart b/landing/lib/site.dart index 3bc80ae..a5ef214 100644 --- a/landing/lib/site.dart +++ b/landing/lib/site.dart @@ -61,6 +61,9 @@ const patrolUrl = 'https://patrol.leancode.co/?$_utm'; const installCommand = 'flutter pub add advanced_forms'; +/// Installs the package's Agent Skill into the agent's skills folder. +const skillInstallCommand = 'dart run skills@ get'; + /// The package version, read from the repository's own pubspec so the site /// can never announce a stale number. The build number is not shown. String packageVersion() { diff --git a/landing/web/landing.css b/landing/web/landing.css index 7727888..cdcfc11 100644 --- a/landing/web/landing.css +++ b/landing/web/landing.css @@ -857,6 +857,10 @@ a.af-pill-accent:hover { margin-top: 0; } +.af-band .af-install-command + .af-hero-actions { + margin-top: 1rem; +} + /* ---------- Footer ---------- */ .af-footer { From c6e4767689f3794a836599f2202ca6181fe2d8f2 Mon Sep 17 00:00:00 2001 From: Kamil Sztandur Date: Mon, 21 Sep 2026 19:22:34 +0200 Subject: [PATCH 3/8] Put the install command where nobody misses it `dart run skills@ get` sat inside a tab in the first install step and was easy to skip. Now it is the first code block on the skill page and in the callout on the docs home. On the landing, the skill band moves up from the bottom to right under the hero, above "The model". Co-Authored-By: Claude Fable 5.1 --- docs/agent-skill.mdx | 12 +++++++++--- docs/index.mdx | 4 ++-- docs/installation.mdx | 2 +- landing/lib/app.dart | 4 +++- 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/docs/agent-skill.mdx b/docs/agent-skill.mdx index 7777055..8596528 100644 --- a/docs/agent-skill.mdx +++ b/docs/agent-skill.mdx @@ -14,9 +14,15 @@ The package ships an [Agent Skill](https://agentskills.io): a single Markdown fi a task looks like form work, so it generates fields, validation, cross-field logic and subforms the way these docs describe them rather than the way a generic Flutter tutorial would. -Run `dart run skills@ get` in your project — or copy the file — and say *"build me a sign-up form"*. The agent adds the -package to `pubspec.yaml` if it is not there yet, writes the controller and the widgets, and wires the validation — you -do not open the docs. +It ships inside the package. With `advanced_forms` in your `pubspec.yaml`, one command installs it into the folder your +agent reads: + +```sh title="In your project" +dart run skills@ get +``` + +Then say *"build me a sign-up form"*. The agent writes the controller and the widgets and wires the validation — you do +not open the docs. Not using the package yet? Copy the file instead; the skill adds the dependency itself. diff --git a/docs/index.mdx b/docs/index.mdx index e3b672d..f743bd1 100644 --- a/docs/index.mdx +++ b/docs/index.mdx @@ -58,8 +58,8 @@ Why the package makes the choices it makes — no widgets, no `Form`, no codegen [Design decisions](./internals/decisions.mdx). - The repository ships an [Agent Skill](./agent-skill.mdx) that teaches your agent the full API, so it generates fields, - validation, cross-field logic and subforms idiomatically. + The package ships an [Agent Skill](./agent-skill.mdx) that teaches your agent the full API, so it generates fields, + validation, cross-field logic and subforms idiomatically. `dart run skills@ get` installs it. `advanced_forms` is maintained by [LeanCode](https://leancode.co/?utm_source=advanced-forms-docs&utm_medium=referral&utm_campaign=advanced-forms) diff --git a/docs/installation.mdx b/docs/installation.mdx index 1a6f0b9..959fbcb 100644 --- a/docs/installation.mdx +++ b/docs/installation.mdx @@ -41,7 +41,7 @@ None are required. Two are worth knowing about: disposed for you. The example app uses it; a `StatefulWidget` works just as well. See [Lifecycle and ownership](./lifecycle/index.mdx). - **An [Agent Skill](./agent-skill.mdx)** — if you write forms with Claude Code or another agent that supports - skills, one copy-paste (or one `curl`) puts `SKILL.md` into your project and the agent generates idiomatic + skills, `dart run skills@ get` installs it into your agent's skills folder and the agent generates idiomatic `advanced_forms` code. ## Coming from `leancode_forms` 0.1.x diff --git a/landing/lib/app.dart b/landing/lib/app.dart index 49b1fb8..9b42d76 100644 --- a/landing/lib/app.dart +++ b/landing/lib/app.dart @@ -25,11 +25,13 @@ class App extends StatelessComponent { classes: 'af-landing', children: [ Hero(version: version, demo: loadExample('hero')), + // Right under the fold: the fastest way to a working form comes + // before the explanation of how forms work. + const SkillBand(), ModelSection(example: loadExample('signup')), ValidationSection(example: loadExample('modes')), AsyncSection(example: loadExample('async')), const Features(), - const SkillBand(), ], ), SiteFooter(version: version), From 7080d5415a20c8920e468912c5be9d2f78703508 Mon Sep 17 00:00:00 2001 From: Kamil Sztandur Date: Mon, 21 Sep 2026 19:32:43 +0200 Subject: [PATCH 4/8] Skill page: copy card on top, then the CLI, step by step MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The copy-paste card stays where a visitor lands, for reading the skill before adding the package. Under it, a banner in the accent — "Get this skill with one command line" — opens the default path: add the package, `dart run skills@ get`, check, ask for a form, keep it current. Copy-paste and curl move into one closing callout. Co-Authored-By: Claude Fable 5.1 --- docs/agent-skill.mdx | 98 +++++++++++---------------- docs_app/components/mdx.tsx | 3 +- docs_app/components/skill-install.tsx | 18 ++++- 3 files changed, 58 insertions(+), 61 deletions(-) diff --git a/docs/agent-skill.mdx b/docs/agent-skill.mdx index 8596528..3ccd600 100644 --- a/docs/agent-skill.mdx +++ b/docs/agent-skill.mdx @@ -14,15 +14,9 @@ The package ships an [Agent Skill](https://agentskills.io): a single Markdown fi a task looks like form work, so it generates fields, validation, cross-field logic and subforms the way these docs describe them rather than the way a generic Flutter tutorial would. -It ships inside the package. With `advanced_forms` in your `pubspec.yaml`, one command installs it into the folder your -agent reads: - -```sh title="In your project" -dart run skills@ get -``` - -Then say *"build me a sign-up form"*. The agent writes the controller and the widgets and wires the validation — you do -not open the docs. Not using the package yet? Copy the file instead; the skill adds the dependency itself. +Copy the file below into your project, or install it with one command — then say *"build me a sign-up form"*. The +agent adds the package to `pubspec.yaml` if it is not there yet, writes the controller and the widgets, and wires the +validation — you do not open the docs. @@ -32,86 +26,72 @@ not open the docs. Not using the package yet? Copy the file instead; the skill a hardened by having agents generate real forms from it alone, compiling those forms, and feeding every defect back. -## Install it +Get this skill with one command line + +The skill ships inside the package, so Dart's [skills CLI](https://dart.dev/tools/pub/package-skills) can install it — +and every other skill your dependencies carry — into the folder your agent reads. -### Create the file - - - +### Have the package in your project -The skill ships inside the package, so once `advanced_forms` is in your `pubspec.yaml`, -[Dart's skills CLI](https://dart.dev/tools/pub/package-skills) installs it — and every other skill your dependencies -carry — into the folder your agent reads: +The CLI reads `pubspec.yaml`, so `advanced_forms` has to be a dependency first: ```sh -dart run skills@ get +flutter pub add advanced_forms ``` -It detects the agent from the project (`.claude/skills/` for Claude Code, `.cursor/skills/`, `.github/skills/`, -`.agents/skills/` for the rest; `--agent claude` to force one) and asks which skills to install; `--all` skips the -question. After a package upgrade, run it again and it offers to update the skill. `dart run skills@ list` shows what -is installed, `dart run skills@ prune` removes skills of dependencies you dropped. - - - - -Press **Copy SKILL.md** above, create this file in your project and paste: - -```text -.claude/skills/advanced_forms-forms/SKILL.md -``` - -Commit it, and every contributor's agent picks it up. To have it in every project you work on instead, put the same -file under `~/.claude/skills/advanced_forms-forms/SKILL.md`. - - - + + -The file is served raw at [`/skill.md`](/skill.md), so the terminal can fetch it into place: +### Run the skills CLI -```sh title="Into the project" -mkdir -p .claude/skills/advanced_forms-forms && curl -fsSL https://advanced-forms.leancode.co/skill.md -o .claude/skills/advanced_forms-forms/SKILL.md +```sh +dart run skills@ get ``` -```sh title="For every project you work on" -mkdir -p ~/.claude/skills/advanced_forms-forms && curl -fsSL https://advanced-forms.leancode.co/skill.md -o ~/.claude/skills/advanced_forms-forms/SKILL.md -``` +`skills@` runs the CLI straight from pub.dev — nothing to install, nothing added to your pubspec. It detects the agent +from the project (`.claude/skills/` for Claude Code, `.cursor/skills/`, `.github/skills/` for Copilot, `.agents/skills/` +for the rest; `--agent claude` to force one) and asks which skills to install; `--all` skips the question. -Run it again whenever you upgrade the package: the URL always serves the skill for the current release. + + - - +### Check it is loaded -The skills CLI is the one that keeps up with releases; the other two are for reading the skill before you add the -package, or for an agent the CLI does not know. `.claude/skills/` is where Claude Code looks; other agents read the same -file from their own skills folder. +`dart run skills@ list` shows what the CLI manages. In Claude Code, `/skills` lists the skills in scope. The skill's +description mentions forms, fields, validation and subforms, so it triggers on a request like *"add a shipping address +section to the checkout"* even when the word "form" never appears. -### Check it is loaded +### Ask for a form -In Claude Code, `/skills` lists the skills in scope. The skill's description mentions forms, fields, validation and -subforms, so it triggers on a request like *"add a shipping address section to the checkout"* even when the word -"form" never appears. +*"Build me a sign-up form with email, password and terms."* That is the whole prompt. The skill is enough on its own: +the agent does not need the docs, the README or the package source in context. It knows the two rules that prevent +most bugs — call `registerFields` once with every field, and bind text widgets to `field.textController` — and it knows +the API surface well enough not to invent parameters. -### Ask for a form +### Keep it current -*"Build me a sign-up form with email, password and terms."* That is the whole prompt: if `advanced_forms` is not in -`pubspec.yaml` yet, the agent runs `flutter pub add advanced_forms` first, then writes the controller, the widgets and -the validation. The skill is enough on its own: the agent does not need the docs, the README or the package source in -context. It knows the two rules that prevent most bugs — call `registerFields` once with every field, and bind text widgets to -`field.textController` — and it knows the API surface well enough not to invent parameters. +After a package upgrade, run `dart run skills@ get` again: it offers to update the skill to the one the new version +ships. `dart run skills@ prune` removes skills of dependencies you dropped. + + The file is the skill. Paste what **Copy SKILL.md** gives you into `.claude/skills/advanced_forms-forms/SKILL.md` + (or `~/.claude/skills/…` for every project), or fetch it raw: + `curl -fsSL https://advanced-forms.leancode.co/skill.md -o .claude/skills/advanced_forms-forms/SKILL.md`. Other agents + read the same file from their own skills folder. + + ## What it teaches - Setup: if `pubspec.yaml` does not list `advanced_forms`, the agent runs `flutter pub add advanced_forms` before diff --git a/docs_app/components/mdx.tsx b/docs_app/components/mdx.tsx index 36f230e..b396f1e 100644 --- a/docs_app/components/mdx.tsx +++ b/docs_app/components/mdx.tsx @@ -11,7 +11,7 @@ import { TypeTable } from "fumadocs-ui/components/type-table" import type { MDXComponents } from "mdx/types" import type { ImgHTMLAttributes } from "react" import { AdvancedFormsExample } from "./advanced-forms-example" -import { SkillCopy, SkillSource } from "./skill-install" +import { SkillBanner, SkillCopy, SkillSource } from "./skill-install" import { cn } from "@/lib/cn" function toPixel(value: ImgHTMLAttributes["width"]): number | undefined { @@ -37,6 +37,7 @@ export function getMDXComponents(components?: MDXComponents) { Tabs, TypeTable, AdvancedFormsExample, + SkillBanner, SkillCopy, SkillSource, ...components, diff --git a/docs_app/components/skill-install.tsx b/docs_app/components/skill-install.tsx index 3b027ba..aebf38d 100644 --- a/docs_app/components/skill-install.tsx +++ b/docs_app/components/skill-install.tsx @@ -4,7 +4,8 @@ * harness: Claude Code */ import { CodeBlock, Pre } from "fumadocs-ui/components/codeblock" -import { ExternalLink, FileText } from "lucide-react" +import { ExternalLink, FileText, Terminal } from "lucide-react" +import type { ReactNode } from "react" import { CopySkillButton } from "./copy-skill-button" import { readSkill } from "@/lib/skill" import { skillRoute, urls } from "@/lib/shared" @@ -61,3 +62,18 @@ export function SkillSource() { ) } + +/** + * The loud title over the install steps: the accent fill, so the one-command + * path is the first thing the eye lands on after the copy card. + */ +export function SkillBanner({ children }: { children: ReactNode }) { + return ( +
+ +

{children}

+
+ ) +} From 83735cbf3e565c4a092f99aea62e6808b9f1537c Mon Sep 17 00:00:00 2001 From: Kamil Sztandur Date: Mon, 21 Sep 2026 19:35:50 +0200 Subject: [PATCH 5/8] Skill page: a quieter banner The accent fill shouted over the copy card. Now a soft tint with an accent rule and a smaller title, aligned with its icon. Co-Authored-By: Claude Fable 5.1 --- docs_app/components/skill-install.tsx | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs_app/components/skill-install.tsx b/docs_app/components/skill-install.tsx index aebf38d..93ada60 100644 --- a/docs_app/components/skill-install.tsx +++ b/docs_app/components/skill-install.tsx @@ -64,16 +64,17 @@ export function SkillSource() { } /** - * The loud title over the install steps: the accent fill, so the one-command - * path is the first thing the eye lands on after the copy card. + * The title over the install steps. A quiet accent — a soft tint and a rule + * in the accent colour — so the one-command path reads as the main road + * without shouting over the copy card above it. */ export function SkillBanner({ children }: { children: ReactNode }) { return (
- -

{children}

+ className="not-prose text-fd-foreground mt-12 mb-6 flex items-center gap-4 rounded-r-xl px-5 py-4" + style={{ background: "var(--af-accent-soft)", borderLeft: "4px solid var(--af-accent)" }}> + +

{children}

) } From dac6d846ab4904f33a0ab97af49bc13803426c4b Mon Sep 17 00:00:00 2001 From: Kamil Sztandur Date: Mon, 21 Sep 2026 19:36:42 +0200 Subject: [PATCH 6/8] Skill banner: the heading sits in its box The docs' heading rules give every h2 a top margin and padding, which pushed the banner's title under its icon. Inline zeroes beat them. Co-Authored-By: Claude Fable 5.1 --- docs_app/components/skill-install.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs_app/components/skill-install.tsx b/docs_app/components/skill-install.tsx index 93ada60..36ac498 100644 --- a/docs_app/components/skill-install.tsx +++ b/docs_app/components/skill-install.tsx @@ -74,7 +74,10 @@ export function SkillBanner({ children }: { children: ReactNode }) { className="not-prose text-fd-foreground mt-12 mb-6 flex items-center gap-4 rounded-r-xl px-5 py-4" style={{ background: "var(--af-accent-soft)", borderLeft: "4px solid var(--af-accent)" }}> -

{children}

+ {/* The docs' heading rules add a top margin and padding to every h2; this one sits in a box. */} +

+ {children} +

) } From 21e70dacc078f5f187fd2d47001d18f56a961ffe Mon Sep 17 00:00:00 2001 From: Kamil Sztandur Date: Mon, 21 Sep 2026 19:49:50 +0200 Subject: [PATCH 7/8] Name the skill after what it does: advanced_forms-build-forms "advanced_forms-forms" stuttered. The Dart team names its skills - (dart-add-unit-test, dart-build-cli-app); ours builds forms. The CLI still finds it on example/. Co-Authored-By: Claude Fable 5.1 --- CHANGELOG.md | 2 +- README.md | 4 ++-- docs/agent-skill.mdx | 6 +++--- docs_app/lib/shared.ts | 4 ++-- docs_app/lib/skill.ts | 4 ++-- landing/lib/site.dart | 2 +- .../SKILL.md | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) rename skills/{advanced_forms-forms => advanced_forms-build-forms}/SKILL.md (99%) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc99041..2cae02e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ * `setOptions(List)` on `AdvancedSingleSelectFieldController` and `AdvancedMultiSelectFieldController`: the list of options can change while the form is open. A selected value that is not on the new list is cleared as a program write (no user edit, no error on an untouched field); widgets rebuild even when the value stayed the same. * The single-select controller now copies the `options` you pass, as the multi-select always did. `options` is an unmodifiable list on both. -* The Agent Skill is a [package skill](https://dart.dev/tools/pub/package-skills): `dart run skills@ get` installs it into your agent's skills folder. The folder moved from `skills/advanced_forms/` to `skills/advanced_forms-forms/`, the name the CLI requires; the skill now adds the package with `flutter pub add advanced_forms` when the project lacks it. +* The Agent Skill is a [package skill](https://dart.dev/tools/pub/package-skills): `dart run skills@ get` installs it into your agent's skills folder. The folder moved from `skills/advanced_forms/` to `skills/advanced_forms-build-forms/`, the name the CLI requires; the skill now adds the package with `flutter pub add advanced_forms` when the project lacks it. ## 0.2.1+1 diff --git a/README.md b/README.md index 28d53af..0985b31 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ > dart run skills@ get > ``` > -> Not using the package yet? Copy the file from [the docs](https://advanced-forms.leancode.co/docs/agent-skill) into `.claude/skills/advanced_forms-forms/SKILL.md`, then say *"build me a sign-up form"* — the agent adds the package and writes the form. +> Not using the package yet? Copy the file from [the docs](https://advanced-forms.leancode.co/docs/agent-skill) into `.claude/skills/advanced_forms-build-forms/SKILL.md`, then say *"build me a sign-up form"* — the agent adds the package and writes the form. ## Website: interactive examples and docs @@ -150,7 +150,7 @@ Own the controller wherever you like — it's a `ChangeNotifier`, so any DI pack - [MIGRATION.md](https://github.com/leancodepl/advanced_forms/blob/main/MIGRATION.md) — coming from 0.1.x. - `example/` — a runnable app where every pattern in these docs has a working screen. See [example/example.md](https://github.com/leancodepl/advanced_forms/blob/main/example/example.md) for the screen guide. - [API reference](https://pub.dev/documentation/advanced_forms/latest/) — the generated dartdoc, for every member and its edge cases. -- [Agent Skill](https://advanced-forms.leancode.co/docs/agent-skill) — `skills/advanced_forms-forms/SKILL.md`, a skill that teaches your agent the full API, so it generates fields, validation, cross-field logic, and subforms idiomatically. `dart run skills@ get` installs it into your project's agent skills folder. +- [Agent Skill](https://advanced-forms.leancode.co/docs/agent-skill) — `skills/advanced_forms-build-forms/SKILL.md`, a skill that teaches your agent the full API, so it generates fields, validation, cross-field logic, and subforms idiomatically. `dart run skills@ get` installs it into your project's agent skills folder. ## Rendering fields diff --git a/docs/agent-skill.mdx b/docs/agent-skill.mdx index 3ccd600..de8d101 100644 --- a/docs/agent-skill.mdx +++ b/docs/agent-skill.mdx @@ -86,9 +86,9 @@ ships. `dart run skills@ prune` removes skills of dependencies you dropped. - The file is the skill. Paste what **Copy SKILL.md** gives you into `.claude/skills/advanced_forms-forms/SKILL.md` + The file is the skill. Paste what **Copy SKILL.md** gives you into `.claude/skills/advanced_forms-build-forms/SKILL.md` (or `~/.claude/skills/…` for every project), or fetch it raw: - `curl -fsSL https://advanced-forms.leancode.co/skill.md -o .claude/skills/advanced_forms-forms/SKILL.md`. Other agents + `curl -fsSL https://advanced-forms.leancode.co/skill.md -o .claude/skills/advanced_forms-build-forms/SKILL.md`. Other agents read the same file from their own skills folder. @@ -112,7 +112,7 @@ ships. `dart run skills@ prune` removes skills of dependencies you dropped. ## The file This is the skill, whole — the same bytes the copy button and `/skill.md` give you. It lives in the repository at -[`skills/advanced_forms-forms/SKILL.md`](https://github.com/leancodepl/advanced_forms/blob/main/skills/advanced_forms-forms/SKILL.md) +[`skills/advanced_forms-build-forms/SKILL.md`](https://github.com/leancodepl/advanced_forms/blob/main/skills/advanced_forms-build-forms/SKILL.md) and this page is built from it, so what you read here is what ships. diff --git a/docs_app/lib/shared.ts b/docs_app/lib/shared.ts index d0eee12..9e03a19 100644 --- a/docs_app/lib/shared.ts +++ b/docs_app/lib/shared.ts @@ -28,7 +28,7 @@ export const docsContentRoute = "/llms.mdx" /** The Agent Skill, served raw so one `curl` (or an agent) can fetch it. */ export const skillRoute = "/skill.md" /** Where the skill goes in a project; `~/` in front makes it global. */ -export const skillInstallPath = ".claude/skills/advanced_forms-forms/SKILL.md" +export const skillInstallPath = ".claude/skills/advanced_forms-build-forms/SKILL.md" export const gitConfig = { user: "leancodepl", @@ -46,7 +46,7 @@ export const urls = { changelog: `${repo}/blob/${gitConfig.branch}/CHANGELOG.md`, migration: `${repo}/blob/${gitConfig.branch}/MIGRATION.md`, license: `${repo}/blob/${gitConfig.branch}/LICENSE`, - skill: `${repo}/blob/${gitConfig.branch}/skills/advanced_forms-forms/SKILL.md`, + skill: `${repo}/blob/${gitConfig.branch}/skills/advanced_forms-build-forms/SKILL.md`, exampleApp: `${repo}/tree/${gitConfig.branch}/example`, exampleGuide: `${repo}/blob/${gitConfig.branch}/example/example.md`, exampleWidgets: `${repo}/tree/${gitConfig.branch}/example/lib/widgets`, diff --git a/docs_app/lib/skill.ts b/docs_app/lib/skill.ts index e9ea811..e4d3a64 100644 --- a/docs_app/lib/skill.ts +++ b/docs_app/lib/skill.ts @@ -7,11 +7,11 @@ import { readFileSync, statSync } from "node:fs" import path from "node:path" /** - * The Agent Skill is one Markdown file in the repo root (`skills/advanced_forms-forms/`), + * The Agent Skill is one Markdown file in the repo root (`skills/advanced_forms-build-forms/`), * the same one the package ships. Read at build time, like `../docs`, so the * site can never serve a stale copy of it. */ -const skillFile = path.join(process.cwd(), "..", "skills", "advanced_forms-forms", "SKILL.md") +const skillFile = path.join(process.cwd(), "..", "skills", "advanced_forms-build-forms", "SKILL.md") export interface Skill { /** The file, verbatim. */ diff --git a/landing/lib/site.dart b/landing/lib/site.dart index a5ef214..67687a0 100644 --- a/landing/lib/site.dart +++ b/landing/lib/site.dart @@ -46,7 +46,7 @@ const apiReferenceUrl = 'https://pub.dev/documentation/advanced_forms/latest/'; const changelogUrl = '$repoUrl/blob/main/CHANGELOG.md'; const migrationUrl = '$repoUrl/blob/main/MIGRATION.md'; const issuesUrl = '$repoUrl/issues'; -const skillUrl = '$repoUrl/blob/main/skills/advanced_forms-forms/SKILL.md'; +const skillUrl = '$repoUrl/blob/main/skills/advanced_forms-build-forms/SKILL.md'; /// The docs page that installs the Agent Skill: one copy, one file. const skillDocsPath = '$docsPath/agent-skill'; diff --git a/skills/advanced_forms-forms/SKILL.md b/skills/advanced_forms-build-forms/SKILL.md similarity index 99% rename from skills/advanced_forms-forms/SKILL.md rename to skills/advanced_forms-build-forms/SKILL.md index 1f29ff2..09ddcb0 100644 --- a/skills/advanced_forms-forms/SKILL.md +++ b/skills/advanced_forms-build-forms/SKILL.md @@ -1,5 +1,5 @@ --- -name: advanced_forms-forms +name: advanced_forms-build-forms description: Build Flutter forms with the advanced_forms package (AdvancedFormController, AdvancedTextFieldController, AdvancedFieldBuilder). Use whenever the user creates a form, adds or edits form fields, wires validation (sync, async, or cross-field), chooses when errors appear (ValidationMode), builds dropdowns/checkboxes/multi-selects/sliders bound to field controllers, handles submit buttons or server-side errors, or works with subforms in any Flutter project — whether or not it depends on advanced_forms yet (add it with `flutter pub add advanced_forms`) — even if they never say the word "form". --- From 8aabbd5a699bd5e63a3778e043415bf2ff79589b Mon Sep 17 00:00:00 2001 From: Kamil Sztandur Date: Mon, 21 Sep 2026 19:52:46 +0200 Subject: [PATCH 8/8] landing: format site.dart Co-Authored-By: Claude Fable 5.1 --- landing/lib/site.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/landing/lib/site.dart b/landing/lib/site.dart index 67687a0..e149fe8 100644 --- a/landing/lib/site.dart +++ b/landing/lib/site.dart @@ -46,7 +46,8 @@ const apiReferenceUrl = 'https://pub.dev/documentation/advanced_forms/latest/'; const changelogUrl = '$repoUrl/blob/main/CHANGELOG.md'; const migrationUrl = '$repoUrl/blob/main/MIGRATION.md'; const issuesUrl = '$repoUrl/issues'; -const skillUrl = '$repoUrl/blob/main/skills/advanced_forms-build-forms/SKILL.md'; +const skillUrl = + '$repoUrl/blob/main/skills/advanced_forms-build-forms/SKILL.md'; /// The docs page that installs the Agent Skill: one copy, one file. const skillDocsPath = '$docsPath/agent-skill';