From a917f5558d3c56eb0005ab0f684422b3d896fcae Mon Sep 17 00:00:00 2001 From: Pinkesh Date: Wed, 22 Apr 2026 19:13:34 +0530 Subject: [PATCH 01/20] Add Flash Docs --- docs/ff-concepts/advanced/flash.md | 613 ++++++++++++++++++ .../flash-ff-builder-using-same-ff-app.avif | Bin 0 -> 36631 bytes 2 files changed, 613 insertions(+) create mode 100644 docs/ff-concepts/advanced/flash.md create mode 100644 docs/ff-concepts/advanced/imgs/flash-ff-builder-using-same-ff-app.avif diff --git a/docs/ff-concepts/advanced/flash.md b/docs/ff-concepts/advanced/flash.md new file mode 100644 index 00000000..16b026f3 --- /dev/null +++ b/docs/ff-concepts/advanced/flash.md @@ -0,0 +1,613 @@ +--- +slug: /concepts/advanced/flash +title: Flash +description: Flash is FlutterFlow's Dart SDK and CLI for building and modifying FlutterFlow apps in code. Install, concepts, tutorials, and reference on one page. +tags: [Flash, Flutter, Dart, CLI, AI Agents] +sidebar_position: 1 +keywords: [Flash, FlutterFlow, Flutter, Dart, CLI, SDK, AI agents, code-first] +--- + +# Flash + +[Flash](https://pub.dev/packages/flutterflow_flash_beta) lets you build FlutterFlow apps by writing Dart code instead of clicking around the visual builder. You write your app in a simple Dart file, check it for errors on your computer, then push it to FlutterFlow with one command. It works for brand-new apps and for changes to apps you already have, and it's designed so both people and AI agents can use it. + +:::info[Remember] + +- **Flash is not a replacement for the visual builder.** FlutterFlow is still faster for most visual work. Flash is for precision, repeatability, and automation. +- **Flash doesn't execute your app.** It produces a FlutterFlow project, which you can test and run inside FlutterFlow visual builder. + +::: + +A FlutterFlow project is the source of truth. Flash is how you create or change it from code. You can write your app in Dart, open the result in FlutterFlow's visual editor, and keep going in either direction. Both paths give you the same FlutterFlow app. + +![flash-ff-builder-using-same-ff-app.avif](imgs/flash-ff-builder-using-same-ff-app.avif) + +Flash serves two kinds of builders equally, operating on the same workspace: + +- **FlutterFlow Developers:** Flash is useful when you want changes you can review like any other code, rather than diffs that only live inside the editor. It's faster for repetitive or structured edits, lets you inspect a project before you change it, and gives you a reliable local workflow with validation, traces, and history. +- **AI-driven Builders:** Flash is useful when you want agents to work in a real code workspace instead of an opaque visual-only surface. It lets them generate or refine app changes in Dart, keeps the workflow deterministic and easy to hand off, and combines FlutterFlow's visual builder with agent-friendly development. + +:::caution + +- Flash is in beta. The API surface may change before 1.0. +- Tutorials on this documentation were tested against `flutterflow_flash_beta: ^0.1.5`. If you're on a newer version, it should still work, but flag anything that looks off. + +::: + +## Flash vs. FlutterFlow Visual Builder + +Flash and the FlutterFlow visual builder aren't rivals. They operate on the same FlutterFlow projects. The question is always **which tool is faster and safer for the change you're about to make.** Here is the quick decision table you can use when you're not sure which to reach for: + +| You want to… | Reach for | +| --- | --- | +| Quickly lay out a new screen by dragging widgets | Visual builder | +| Tweak a color, swap an image, adjust padding | Visual builder | +| Explore what an interaction feels like before committing | Visual builder | +| Create a new app from a structured spec or template | Flash | +| Make the same change across many pages, components, or projects | Flash | +| Let an AI agent build or edit the app deterministically | Flash | +| Do exploratory UI work with instant feedback | Visual builder | +| Refactor page structure programmatically | Flash | + +**When the Visual Builder wins** + +The visual builder is unbeatable at three things: **exploration, feel, and small edits.** Dragging widgets onto a canvas, trying layouts, and seeing the result instantly is the fastest way to figure out what you want. Adjusting spacing, colors, fonts, and animations is easier when you can see the change as you make it. Changing a button label, swapping an icon, or moving a single widget is a five-second job in the editor. + +If you're still deciding what the app *should look like*, stay in the visual builder. + +**When Flash wins** + +Flash wins when **precision, repeatability, or review** matters more than instant visual feedback. + +- **Large or structured changes.** "Add the same search-and-filter bar to eight list pages" is one well-scoped Flash patch. In the visual builder it's eight manual edits with drift between them. +- **Scaffolding a new app from a spec.** If you already know what you want i.e., shapes of pages, data models, navigation — writing it in Dart is often faster than clicking it into existence. +- **Reviewable changes.** A Flash change is a Dart diff. You can review it in a pull request, ask for feedback, revert it, and replay it in another project. +- **Source control.** Your FlutterFlow work lives in a git repo, not only in FlutterFlow's own history. +- **AI agents.** Agents make far fewer mistakes with a code workspace, a validator, and a run history than they do in a visual surface. + +## Install + +:::tip[Prerequisites] + +- **Dart 3.7 or newer.** Check with `dart --version`. If you don't have Dart, install it from [**dart.dev/get-dart**](https://dart.dev/get-dart) — or install Flutter, which includes Dart. +- **A FlutterFlow API key.** Generate one from your FlutterFlow account settings. + +::: + +You can install the Flash CLI by hitting the following command in your terminal: + +```bash +dart pub global activate flutterflow_flash_beta +``` + +This installs the `flash` command globally. + +To use Flash as a library in an existing Dart package instead of (or in addition to) the CLI: + +```bash +dart pub add flutterflow_flash_beta +``` + +Now, verify the installation with Flash Doctor: + +```bash +flash doctor +``` + +`flash doctor` prints: + +- The installed Flash version +- The current proto fingerprint (the schema version your Flash install targets) +- Whether the matching local validator binary is cached for your platform + +If anything is missing or mismatched, `flash doctor` tells you what to do next. + +## Create New App + +Let’s build a single-page FlutterFlow app with a title, a short description, and a button that shows a snackbar when tapped. Nothing fancy — the point is to walk the full round-trip from Dart source to a live FlutterFlow project. + +:::info + +Before you start, make sure you've completed [**Flash Install**](#install). + +::: + +### 1. Create a Workspace + +Create a new Flash workspace called `hello-flash`: + +```bash +flash init hello-flash +cd hello-flash +``` + +`flash init` scaffolds a ready-to-edit workspace. Take a moment to look around: + +``` +hello-flash/ +├── .env.example +├── AGENTS.md +├── CLAUDE.md +├── flash/ +│ ├── app.dart ← you'll edit this +│ └── brownfield_patch.dart +├── patterns/ +├── pubspec.yaml +├── references/ +└── tooling/ +``` + +You'll only touch `flash/app.dart` in this tutorial. + +### 2. Add your API key + +Copy the example environment file: + +```bash +cp .env.example .env +``` + +Edit `.env` and paste your FlutterFlow API key: + +```bash +FF_API_KEY=your-key-here +``` + +Install Dart dependencies: + +```bash +dart pub get +``` + +:::caution[Keep your API key private] +Treat your API key like a password. Don't paste it into chat, commit it to source control, or share it in screenshots. `.env` should always be in `.gitignore`. + +If you think a key has been exposed, rotate it in FlutterFlow immediately. +::: + +### 3. Write the App + +Open `flash/app.dart` and replace the Scaffold widget with this: + +```dart +Scaffold( + appBar: AppBar(title: 'Flash Demo'), + body: Container( + padding: 24, + child: Column( + spacing: 16, + crossAxis: CrossAxis.start, + children: [ + Text('Build FlutterFlow apps with Dart', style: Styles.headlineSmall), + Text( + 'Flash makes FlutterFlow changes reviewable, repeatable, and agent-friendly.', + style: Styles.bodyMedium, + color: Colors.secondaryText, + ), + Button( + 'Show Snackbar', + width: double.infinity, + onTap: Snackbar('Flash is wired correctly.'), + ), + ], + ), + ), + ), +``` + +What's happening here: + +- `app.page` declares a page called `StarterPage` at route `/`, marked as the initial page. +- The `body` is a standard Flutter-like tree: `Scaffold` → `AppBar` + `Container` → `Column` of `Text`, `Text`, `Button`. +- `onTap: Snackbar(...)` wires the button to a FlutterFlow Snackbar action. + +If you've written Flutter before, this will feel familiar. If you've used FlutterFlow, every one of these elements maps to a widget you'd otherwise drag onto the canvas. + +### 4. Validate Locally + +Before pushing anything to FlutterFlow, run a dry run: + +```bash +flash validate flash/app.dart +``` + +Your Dart file is what Flash calls a DSL — short for "domain-specific language," which just means code written for one specific purpose (in this case, describing a FlutterFlow app). `flash validate` compiles your DSL, checks it against the FlutterFlow schema, and reports any errors. + +:::tip[Validate early, validate often] +`flash validate` is fast and free. Run it every time you change the DSL. If it fails, fix it before `flash run`. +::: + +### 5. Push to FlutterFlow + +Now create the real project in your FlutterFlow account: + +```bash +flash run flash/app.dart --project-name "Hello Flash" --commit-message "Create starter page" +``` + +Flash will compile your DSL, create a new FlutterFlow project named "Hello Flash", apply your page, theme, and font, and return the project ID and a URL to open it. + +### 6. Open it in FlutterFlow + +Open the URL from the `flash run` output, or go to your FlutterFlow dashboard and find the "Hello Flash" project. + +You'll see `StarterPage` in the page list, your theme colors applied, the `Text` + `Text` + `Button` column laid out in the canvas, and the button wired to a Snackbar action. + +Try running the project in FlutterFlow's preview. Tap the button. The snackbar you declared in Dart fires just like any other FlutterFlow action. + +Here's exactly how you do it: + +
+ +
+

+ +## Create New App with AI agent + +Flash workspaces are designed to hand off to AI agents. Here's the same tutorial from an agent's perspective: + +1. Complete [step 1](#1-create-a-workspace) and [step 2](#2-add-your-api-key) from the Create New App section. +2. You open the workspace in Claude Code (or any agent that can read `AGENTS.md`). +3. You prompt: *"Read AGENTS.md, then edit flash/app.dart to create a single-page starter app with a title, description, and a snackbar button. Validate before telling me you're done."* +4. The agent reads `AGENTS.md`, browses `references/` for similar DSLs, edits `flash/app.dart`, runs `flash validate`, and reports back. +5. You run `flash run` yourself. + +
+ +
+

+ +## Modify Existing App + +Let’s modify the existing FlutterFlow app with AI agents. Every Flash workspace ships with `AGENTS.md` and `CLAUDE.md` — briefing files that tell an agent what the environment is, where to read, where to write, and which commands are safe to run. + +**The key principle**: The agent drafts, the human ships. The agent can write DSL, validate it, and iterate on errors. You stay in control of `flash run` — the command that actually modifies your FlutterFlow project. + +### 1. Prepare the Workspace + +Pick a FlutterFlow project you're happy to change. Then set up a fresh workspace scoped to it: + +```bash +flash init agent-edits --project +cd agent-edits +cp .env.example .env +# edit .env and paste your FF_API_KEY +dart pub get +flash refresh-context +``` + +All the usual setup — nothing agent-specific yet. The important part is that you do this **before** the agent takes over, so the agent doesn't have to handle your API key. + +:::caution[Your API key stays with you] +Never paste your `FF_API_KEY` into the agent chat. Put it in `.env` yourself. The agent reads and writes files in the workspace; it doesn't need to see the key, and it shouldn't. +::: + +### 2. Open the Workspace in your Agent + +Open `agent-edits/` in Claude Code (or your agent of choice). You can also confirm that the agent can read and write files in the workspace directory. + +### 3. Point the Agent at AGENTS.md + +Open a conversation with the agent and start with something like: + +> Read `AGENTS.md` and `CLAUDE.md` in this workspace before doing anything else. Then browse `references/` and `patterns/` so you understand the DSL shape and the brownfield patterns available. Don't edit anything yet — just tell me what you understand about this workspace. +> + +Wait for the agent to respond. Read its summary. If it misunderstands something, correct it before proceeding. It's much cheaper to fix framing now than after the agent has written a patch against the wrong file. + +### 4. Give the Task + +Now describe the change in natural language. Some examples, in rough order of difficulty: + +- "Add a heading and a short description block to the top of the `HomePage` body. Text values: 'Welcome' as heading, 'Your dashboard at a glance.' as description." +- "On the `Products` page, add a search field above the existing product list." +- "Replace the primary theme color with `0xFF6750A4` and make sure any places that reference it explicitly still look correct." + +:::tip[Also add explicit rules, such as:] +- Inspect the target page with `flash inspect --page ` before writing anything. +- Write the patch in `flash/brownfield_patch.dart`. +- Run `flash validate flash/brownfield_patch.dart --project-id ` and iterate until it passes. +- Do NOT run `flash run`. I will review your changes and run it myself. +- If you hit an error you can't explain, stop and ask — don't guess. + +::: + +This prompt pattern: **Read context, do the work, stop before the irreversible step** — is the shape of a good agent handoff in Flash. + +### 5. Let the Agent Work + +The agent will go through a loop roughly like this: + +1. Run `flash inspect` to understand the target page's current shape. +2. Open one or more files in `references/` or `patterns/` to find the closest example. +3. Write a first draft of `flash/brownfield_patch.dart`. +4. Run `flash validate`. +5. Read the error (if any), adjust the DSL, and validate again. +6. Report back when validation passes. + +:::info[Things to Know] + +- **Thrashing on the same error:** If the agent fails validation the same way three times in a row, interrupt. The framing is likely wrong. Point it at a more specific reference DSL, or clarify the task. +- **Making changes you didn't ask for:** Agents sometimes "improve" things adjacent to the task. Tell it to stick to the task and revert any out-of-scope changes before continuing. + +::: + +### 6. Run it Yourself + +When you're satisfied with the patch, you run the final command: + +```bash +flash run flash/brownfield_patch.dart --project-id --commit-message "Agent: add welcome block to HomePage" +``` + +Open the project in FlutterFlow. Confirm the change is exactly what you intended. + +:::tip[Tips for longer agent sessions] + +- **Commit after every successful `flash run`.** Your git history becomes the project's change log. +- **Keep tasks small.** A single agent prompt should produce a single patch that does a single logical thing. "Refactor the whole app" is not a task — break it into ten of them. +- **When the agent gets stuck, check context first.** Run `flash context-check`. Stale context produces errors that look like agent confusion but are actually cache drift — see [**Project context and staleness**](#project-context-and-staleness). +- **Keep `flash run` to yourself for now.** Even once you trust the agent, the discipline of reviewing before running keeps the workflow honest. + +::: + +Here's exactly how you do it: + +
+ +
+

+ +## Flash Concepts + +This section covers the mental model you need to use Flash effectively. If you've completed tutorial “Create New App” and “Modify Existing App”, a lot of this will feel like names for things you've already seen. + +### Workspace Anatomy + +Every `flash init` produces the same workspace shape: + +``` +my-app/ +├── .env.example Template for your API key. Copy to .env. +├── AGENTS.md Instructions for AI agents. +├── CLAUDE.md Claude-specific agent instructions. +├── flash/ +│ ├── app.dart Entry point for building a NEW app (greenfield). +│ └── brownfield_patch.dart Entry point for editing an existing app. +├── patterns/ Copy-paste recipes for common brownfield changes. +├── pubspec.yaml Dart dependencies. +├── references/ Complete working DSLs to learn from. +├── tooling/ Wrapper scripts for common flows. +└── .flash/ Local run history, traces, and cached context. + (Created automatically on first run.) +``` + +A few of these deserve special attention: + +- **`flash/app.dart`** and **`flash/brownfield_patch.dart`** are the two places your DSL lives. You'll almost never have both active at once — see [Greenfield vs. brownfield](#greenfield-vs-brownfield). +- **`references/`** is your teacher. When you don't know how to express something in the DSL, open the most similar reference app and copy the pattern. This is the single most effective way to learn Flash. +- **`patterns/`** is more focused: short, named recipes like "add a search filter to an existing list page" that you adapt into your `brownfield_patch.dart`. +- **`AGENTS.md`** and **`CLAUDE.md`** are what make the workspace agent-friendly. An agent that reads these files gets a working understanding of the environment without needing you to explain it. +- **`.flash/`** is where Flash stores state: run history, traces, and a cached representation of the FlutterFlow project you're working on. Don't commit this folder — add it to `.gitignore`. + +### Greenfield vs. Brownfield + +Flash has two modes for two situations: + +- **Greenfield**: You're creating a new FlutterFlow project from scratch. You work in `flash/app.dart`. Your DSL describes the entire app. When you `flash run`, Flash creates a new project in your FlutterFlow account. + + ```bash + flash run flash/app.dart --project-name "My New App" --commit-message "Initial app" + ``` + +- **Brownfield**: A FlutterFlow project already exists and you want to change it. You work in `flash/brownfield_patch.dart`. Your DSL describes only the *changes* you want to make, not the whole app. When you `flash run`, Flash applies the patch to the existing project. + + ```bash + flash run flash/brownfield_patch.dart --project-id --commit-message "Add search filter" + ``` + +The rule of thumb: + +- **First-time push of a new app** > greenfield, `flash/app.dart`, `-project-name`. +- **Every subsequent change** > brownfield, `flash/brownfield_patch.dart`, `-project-id`. + +Once a project exists in FlutterFlow, you almost never go back to `flash/app.dart` for it — brownfield is the normal mode. + +### Validate vs. Run + +These two commands are your inner dev loop. + +**`flash validate `** is a dry run. It: + +- Compiles your DSL. +- Checks it against the FlutterFlow schema. +- Reports errors and warnings. +- Does **not** touch your FlutterFlow account. + +It's fast and free. Run it every time you change the DSL. + +**`flash run `** is the real thing. It validates first (same check as above), then serializes the result and pushes it to FlutterFlow. This creates or modifies an actual project in your account. + +The rhythm: + +``` +edit → flash validate → edit → flash validate → flash run → review in FlutterFlow → repeat +``` + +If `flash validate` fails, fix it before `flash run`. Running straight to `flash run` without validating is a common mistake that wastes time — `flash run` does the same validation internally, so you're just moving the error report later. + +### Project Context and Staleness + +For brownfield edits, Flash keeps a **local cached representation** of the FlutterFlow project under `.flash/`. This is called the project **context**. It's what lets `flash inspect` show you the project structure quickly and what Flash uses to reason about your patch. + +Context can go stale. This happens whenever the FlutterFlow project changes in a way Flash doesn't see: + +- Someone else edits the project in the visual builder. +- You yourself edit it in the visual builder between Flash runs. +- A teammate runs `flash run` from another workspace. + +Two commands manage context: + +- **`flash context-check`** : Tells you whether your local context matches the current state of the project. Run this before starting non-trivial brownfield work. +- **`flash refresh-context `**: Pulls a fresh copy of the project into your workspace. Run this whenever `context-check` reports drift, or as a habit at the start of a work session. + +Stale context usually shows up as confusing `flash validate` errors — Flash thinks a page exists when it doesn't, or misses a field that was added. If a brownfield validation fails for a reason that doesn't match what you see in the editor, refresh context first and try again. + +## FAQs + +
+ +`flash run` fails with an authentication error + + +

+Confirm `FF_API_KEY` is set in `.env` and the key is valid. Try passing `--api-key ` directly to rule out env-loading issues. If the CLI flag works but `.env` doesn't, check that your shell is running `flash` from the same directory as the `.env` file — Flash loads `.env` from the current working directory. +

+
+ + +
+ +`flash doctor` says the validator is missing + + +

+Try running the `flash precache` to download it. +

+
+ +
+ +`flash validate` fails with a proto fingerprint mismatch + + +

+Your local validator is out of date with the Flash version you're running. Run `flash precache` to refresh it, or reinstall Flash with `dart pub global activate flutterflow_flash_beta`. +

+
+ +
+ +`flash validate --project-id ` fails saying a page or widget doesn't exist, but you can see it in FlutterFlow + + +

+This is often caused by stale local project context. Flash caches a local copy of your FlutterFlow project under `.flash/`, and when that cache is out of date, validation can fail in ways that look like logic bugs. + +Fix it by running: + +```bash +flash context-check +flash refresh-context +``` + +`context-check` tells you whether your local copy matches the current state of the project. `refresh-context` pulls a fresh copy. + +

+
+ +
+ +Validation passes locally but `flash run` reports conflicting state + + +

+This is usually caused by stale cached project context under `.flash/`. Refresh your local copy of the project: + +```bash +flash context-check +flash refresh-context +``` + +

+
+ + +
+ +Error messages reference widget keys or IDs you don't recognize + + +

+This is another common sign of stale local project context. Run: + +```bash +flash context-check +flash refresh-context +``` + +

+
+ +
+ +How can I prevent stale context issues? + + +

+Run `flash context-check` at the start of every brownfield work session. Run `flash refresh-context` whenever someone else has edited the project, or whenever you've edited it in the visual builder between Flash runs. In team environments, treat `refresh-context` like `git pull` — do it reflexively before starting work. +

+
diff --git a/docs/ff-concepts/advanced/imgs/flash-ff-builder-using-same-ff-app.avif b/docs/ff-concepts/advanced/imgs/flash-ff-builder-using-same-ff-app.avif new file mode 100644 index 0000000000000000000000000000000000000000..524babb5b18a030e5c5fa8199aa1c5f9e3e74d99 GIT binary patch literal 36631 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 V&YaSC8Q6DM!#S}z`li#9#UQnr`4|8I literal 0 HcmV?d00001 From 836e2c5f0e8dfff6751917b8baca1af99ae8f868 Mon Sep 17 00:00:00 2001 From: Pinkesh Date: Mon, 27 Apr 2026 10:53:25 +0530 Subject: [PATCH 02/20] clarify API key setup and update create with agent --- docs/ff-concepts/advanced/flash.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/docs/ff-concepts/advanced/flash.md b/docs/ff-concepts/advanced/flash.md index 16b026f3..6bd41f7c 100644 --- a/docs/ff-concepts/advanced/flash.md +++ b/docs/ff-concepts/advanced/flash.md @@ -147,12 +147,22 @@ Copy the example environment file: cp .env.example .env ``` -Edit `.env` and paste your FlutterFlow API key: +Edit `.env` and paste your FlutterFlow API key. You can get the API key from your [FlutterFlow Account](https://app.flutterflow.io/account) — look for the API Token section. ```bash FF_API_KEY=your-key-here ``` +:::tip You can also pass your key at init +You can skip this step by passing `--api-key` when you run `flash init` in [**step 1**](#1-create-a-workspace): + +```bash +flash init hello-flash --api-key +``` + +Flash will set up the workspace with your key already in place, so you don't need to edit `.env` yourself. Useful for quick one-off workspaces. For anything you'll keep around, the `.env` approach is safer — it keeps the key out of your shell history. +::: + Install Dart dependencies: ```bash @@ -269,7 +279,7 @@ Flash workspaces are designed to hand off to AI agents. Here's the same tutorial 1. Complete [step 1](#1-create-a-workspace) and [step 2](#2-add-your-api-key) from the Create New App section. 2. You open the workspace in Claude Code (or any agent that can read `AGENTS.md`). -3. You prompt: *"Read AGENTS.md, then edit flash/app.dart to create a single-page starter app with a title, description, and a snackbar button. Validate before telling me you're done."* +3. You prompt: *"Read AGENTS.md, then create a futurstic meditation app"* 4. The agent reads `AGENTS.md`, browses `references/` for similar DSLs, edits `flash/app.dart`, runs `flash validate`, and reports back. 5. You run `flash run` yourself. From 5933059bb82353b4f77e759eaa09aaa02e2e1f6b Mon Sep 17 00:00:00 2001 From: Pinkesh Date: Tue, 28 Apr 2026 12:08:17 +0530 Subject: [PATCH 03/20] Moved from flash to ff cli --- docs/ff-concepts/advanced/flash.md | 623 ------------------ .../flash-ff-builder-using-same-ff-app.avif | Bin 36631 -> 0 bytes .../exporting-code/ff-cli.md | 146 +++- .../ff-cli-ff-builder-using-same-ff-app.avif | Bin 0 -> 25913 bytes 4 files changed, 137 insertions(+), 632 deletions(-) delete mode 100644 docs/ff-concepts/advanced/flash.md delete mode 100644 docs/ff-concepts/advanced/imgs/flash-ff-builder-using-same-ff-app.avif create mode 100644 docs/testing-deployment-publishing/exporting-code/imgs/ff-cli-ff-builder-using-same-ff-app.avif diff --git a/docs/ff-concepts/advanced/flash.md b/docs/ff-concepts/advanced/flash.md deleted file mode 100644 index 6bd41f7c..00000000 --- a/docs/ff-concepts/advanced/flash.md +++ /dev/null @@ -1,623 +0,0 @@ ---- -slug: /concepts/advanced/flash -title: Flash -description: Flash is FlutterFlow's Dart SDK and CLI for building and modifying FlutterFlow apps in code. Install, concepts, tutorials, and reference on one page. -tags: [Flash, Flutter, Dart, CLI, AI Agents] -sidebar_position: 1 -keywords: [Flash, FlutterFlow, Flutter, Dart, CLI, SDK, AI agents, code-first] ---- - -# Flash - -[Flash](https://pub.dev/packages/flutterflow_flash_beta) lets you build FlutterFlow apps by writing Dart code instead of clicking around the visual builder. You write your app in a simple Dart file, check it for errors on your computer, then push it to FlutterFlow with one command. It works for brand-new apps and for changes to apps you already have, and it's designed so both people and AI agents can use it. - -:::info[Remember] - -- **Flash is not a replacement for the visual builder.** FlutterFlow is still faster for most visual work. Flash is for precision, repeatability, and automation. -- **Flash doesn't execute your app.** It produces a FlutterFlow project, which you can test and run inside FlutterFlow visual builder. - -::: - -A FlutterFlow project is the source of truth. Flash is how you create or change it from code. You can write your app in Dart, open the result in FlutterFlow's visual editor, and keep going in either direction. Both paths give you the same FlutterFlow app. - -![flash-ff-builder-using-same-ff-app.avif](imgs/flash-ff-builder-using-same-ff-app.avif) - -Flash serves two kinds of builders equally, operating on the same workspace: - -- **FlutterFlow Developers:** Flash is useful when you want changes you can review like any other code, rather than diffs that only live inside the editor. It's faster for repetitive or structured edits, lets you inspect a project before you change it, and gives you a reliable local workflow with validation, traces, and history. -- **AI-driven Builders:** Flash is useful when you want agents to work in a real code workspace instead of an opaque visual-only surface. It lets them generate or refine app changes in Dart, keeps the workflow deterministic and easy to hand off, and combines FlutterFlow's visual builder with agent-friendly development. - -:::caution - -- Flash is in beta. The API surface may change before 1.0. -- Tutorials on this documentation were tested against `flutterflow_flash_beta: ^0.1.5`. If you're on a newer version, it should still work, but flag anything that looks off. - -::: - -## Flash vs. FlutterFlow Visual Builder - -Flash and the FlutterFlow visual builder aren't rivals. They operate on the same FlutterFlow projects. The question is always **which tool is faster and safer for the change you're about to make.** Here is the quick decision table you can use when you're not sure which to reach for: - -| You want to… | Reach for | -| --- | --- | -| Quickly lay out a new screen by dragging widgets | Visual builder | -| Tweak a color, swap an image, adjust padding | Visual builder | -| Explore what an interaction feels like before committing | Visual builder | -| Create a new app from a structured spec or template | Flash | -| Make the same change across many pages, components, or projects | Flash | -| Let an AI agent build or edit the app deterministically | Flash | -| Do exploratory UI work with instant feedback | Visual builder | -| Refactor page structure programmatically | Flash | - -**When the Visual Builder wins** - -The visual builder is unbeatable at three things: **exploration, feel, and small edits.** Dragging widgets onto a canvas, trying layouts, and seeing the result instantly is the fastest way to figure out what you want. Adjusting spacing, colors, fonts, and animations is easier when you can see the change as you make it. Changing a button label, swapping an icon, or moving a single widget is a five-second job in the editor. - -If you're still deciding what the app *should look like*, stay in the visual builder. - -**When Flash wins** - -Flash wins when **precision, repeatability, or review** matters more than instant visual feedback. - -- **Large or structured changes.** "Add the same search-and-filter bar to eight list pages" is one well-scoped Flash patch. In the visual builder it's eight manual edits with drift between them. -- **Scaffolding a new app from a spec.** If you already know what you want i.e., shapes of pages, data models, navigation — writing it in Dart is often faster than clicking it into existence. -- **Reviewable changes.** A Flash change is a Dart diff. You can review it in a pull request, ask for feedback, revert it, and replay it in another project. -- **Source control.** Your FlutterFlow work lives in a git repo, not only in FlutterFlow's own history. -- **AI agents.** Agents make far fewer mistakes with a code workspace, a validator, and a run history than they do in a visual surface. - -## Install - -:::tip[Prerequisites] - -- **Dart 3.7 or newer.** Check with `dart --version`. If you don't have Dart, install it from [**dart.dev/get-dart**](https://dart.dev/get-dart) — or install Flutter, which includes Dart. -- **A FlutterFlow API key.** Generate one from your FlutterFlow account settings. - -::: - -You can install the Flash CLI by hitting the following command in your terminal: - -```bash -dart pub global activate flutterflow_flash_beta -``` - -This installs the `flash` command globally. - -To use Flash as a library in an existing Dart package instead of (or in addition to) the CLI: - -```bash -dart pub add flutterflow_flash_beta -``` - -Now, verify the installation with Flash Doctor: - -```bash -flash doctor -``` - -`flash doctor` prints: - -- The installed Flash version -- The current proto fingerprint (the schema version your Flash install targets) -- Whether the matching local validator binary is cached for your platform - -If anything is missing or mismatched, `flash doctor` tells you what to do next. - -## Create New App - -Let’s build a single-page FlutterFlow app with a title, a short description, and a button that shows a snackbar when tapped. Nothing fancy — the point is to walk the full round-trip from Dart source to a live FlutterFlow project. - -:::info - -Before you start, make sure you've completed [**Flash Install**](#install). - -::: - -### 1. Create a Workspace - -Create a new Flash workspace called `hello-flash`: - -```bash -flash init hello-flash -cd hello-flash -``` - -`flash init` scaffolds a ready-to-edit workspace. Take a moment to look around: - -``` -hello-flash/ -├── .env.example -├── AGENTS.md -├── CLAUDE.md -├── flash/ -│ ├── app.dart ← you'll edit this -│ └── brownfield_patch.dart -├── patterns/ -├── pubspec.yaml -├── references/ -└── tooling/ -``` - -You'll only touch `flash/app.dart` in this tutorial. - -### 2. Add your API key - -Copy the example environment file: - -```bash -cp .env.example .env -``` - -Edit `.env` and paste your FlutterFlow API key. You can get the API key from your [FlutterFlow Account](https://app.flutterflow.io/account) — look for the API Token section. - -```bash -FF_API_KEY=your-key-here -``` - -:::tip You can also pass your key at init -You can skip this step by passing `--api-key` when you run `flash init` in [**step 1**](#1-create-a-workspace): - -```bash -flash init hello-flash --api-key -``` - -Flash will set up the workspace with your key already in place, so you don't need to edit `.env` yourself. Useful for quick one-off workspaces. For anything you'll keep around, the `.env` approach is safer — it keeps the key out of your shell history. -::: - -Install Dart dependencies: - -```bash -dart pub get -``` - -:::caution[Keep your API key private] -Treat your API key like a password. Don't paste it into chat, commit it to source control, or share it in screenshots. `.env` should always be in `.gitignore`. - -If you think a key has been exposed, rotate it in FlutterFlow immediately. -::: - -### 3. Write the App - -Open `flash/app.dart` and replace the Scaffold widget with this: - -```dart -Scaffold( - appBar: AppBar(title: 'Flash Demo'), - body: Container( - padding: 24, - child: Column( - spacing: 16, - crossAxis: CrossAxis.start, - children: [ - Text('Build FlutterFlow apps with Dart', style: Styles.headlineSmall), - Text( - 'Flash makes FlutterFlow changes reviewable, repeatable, and agent-friendly.', - style: Styles.bodyMedium, - color: Colors.secondaryText, - ), - Button( - 'Show Snackbar', - width: double.infinity, - onTap: Snackbar('Flash is wired correctly.'), - ), - ], - ), - ), - ), -``` - -What's happening here: - -- `app.page` declares a page called `StarterPage` at route `/`, marked as the initial page. -- The `body` is a standard Flutter-like tree: `Scaffold` → `AppBar` + `Container` → `Column` of `Text`, `Text`, `Button`. -- `onTap: Snackbar(...)` wires the button to a FlutterFlow Snackbar action. - -If you've written Flutter before, this will feel familiar. If you've used FlutterFlow, every one of these elements maps to a widget you'd otherwise drag onto the canvas. - -### 4. Validate Locally - -Before pushing anything to FlutterFlow, run a dry run: - -```bash -flash validate flash/app.dart -``` - -Your Dart file is what Flash calls a DSL — short for "domain-specific language," which just means code written for one specific purpose (in this case, describing a FlutterFlow app). `flash validate` compiles your DSL, checks it against the FlutterFlow schema, and reports any errors. - -:::tip[Validate early, validate often] -`flash validate` is fast and free. Run it every time you change the DSL. If it fails, fix it before `flash run`. -::: - -### 5. Push to FlutterFlow - -Now create the real project in your FlutterFlow account: - -```bash -flash run flash/app.dart --project-name "Hello Flash" --commit-message "Create starter page" -``` - -Flash will compile your DSL, create a new FlutterFlow project named "Hello Flash", apply your page, theme, and font, and return the project ID and a URL to open it. - -### 6. Open it in FlutterFlow - -Open the URL from the `flash run` output, or go to your FlutterFlow dashboard and find the "Hello Flash" project. - -You'll see `StarterPage` in the page list, your theme colors applied, the `Text` + `Text` + `Button` column laid out in the canvas, and the button wired to a Snackbar action. - -Try running the project in FlutterFlow's preview. Tap the button. The snackbar you declared in Dart fires just like any other FlutterFlow action. - -Here's exactly how you do it: - -
- -
-

- -## Create New App with AI agent - -Flash workspaces are designed to hand off to AI agents. Here's the same tutorial from an agent's perspective: - -1. Complete [step 1](#1-create-a-workspace) and [step 2](#2-add-your-api-key) from the Create New App section. -2. You open the workspace in Claude Code (or any agent that can read `AGENTS.md`). -3. You prompt: *"Read AGENTS.md, then create a futurstic meditation app"* -4. The agent reads `AGENTS.md`, browses `references/` for similar DSLs, edits `flash/app.dart`, runs `flash validate`, and reports back. -5. You run `flash run` yourself. - -
- -
-

- -## Modify Existing App - -Let’s modify the existing FlutterFlow app with AI agents. Every Flash workspace ships with `AGENTS.md` and `CLAUDE.md` — briefing files that tell an agent what the environment is, where to read, where to write, and which commands are safe to run. - -**The key principle**: The agent drafts, the human ships. The agent can write DSL, validate it, and iterate on errors. You stay in control of `flash run` — the command that actually modifies your FlutterFlow project. - -### 1. Prepare the Workspace - -Pick a FlutterFlow project you're happy to change. Then set up a fresh workspace scoped to it: - -```bash -flash init agent-edits --project -cd agent-edits -cp .env.example .env -# edit .env and paste your FF_API_KEY -dart pub get -flash refresh-context -``` - -All the usual setup — nothing agent-specific yet. The important part is that you do this **before** the agent takes over, so the agent doesn't have to handle your API key. - -:::caution[Your API key stays with you] -Never paste your `FF_API_KEY` into the agent chat. Put it in `.env` yourself. The agent reads and writes files in the workspace; it doesn't need to see the key, and it shouldn't. -::: - -### 2. Open the Workspace in your Agent - -Open `agent-edits/` in Claude Code (or your agent of choice). You can also confirm that the agent can read and write files in the workspace directory. - -### 3. Point the Agent at AGENTS.md - -Open a conversation with the agent and start with something like: - -> Read `AGENTS.md` and `CLAUDE.md` in this workspace before doing anything else. Then browse `references/` and `patterns/` so you understand the DSL shape and the brownfield patterns available. Don't edit anything yet — just tell me what you understand about this workspace. -> - -Wait for the agent to respond. Read its summary. If it misunderstands something, correct it before proceeding. It's much cheaper to fix framing now than after the agent has written a patch against the wrong file. - -### 4. Give the Task - -Now describe the change in natural language. Some examples, in rough order of difficulty: - -- "Add a heading and a short description block to the top of the `HomePage` body. Text values: 'Welcome' as heading, 'Your dashboard at a glance.' as description." -- "On the `Products` page, add a search field above the existing product list." -- "Replace the primary theme color with `0xFF6750A4` and make sure any places that reference it explicitly still look correct." - -:::tip[Also add explicit rules, such as:] -- Inspect the target page with `flash inspect --page ` before writing anything. -- Write the patch in `flash/brownfield_patch.dart`. -- Run `flash validate flash/brownfield_patch.dart --project-id ` and iterate until it passes. -- Do NOT run `flash run`. I will review your changes and run it myself. -- If you hit an error you can't explain, stop and ask — don't guess. - -::: - -This prompt pattern: **Read context, do the work, stop before the irreversible step** — is the shape of a good agent handoff in Flash. - -### 5. Let the Agent Work - -The agent will go through a loop roughly like this: - -1. Run `flash inspect` to understand the target page's current shape. -2. Open one or more files in `references/` or `patterns/` to find the closest example. -3. Write a first draft of `flash/brownfield_patch.dart`. -4. Run `flash validate`. -5. Read the error (if any), adjust the DSL, and validate again. -6. Report back when validation passes. - -:::info[Things to Know] - -- **Thrashing on the same error:** If the agent fails validation the same way three times in a row, interrupt. The framing is likely wrong. Point it at a more specific reference DSL, or clarify the task. -- **Making changes you didn't ask for:** Agents sometimes "improve" things adjacent to the task. Tell it to stick to the task and revert any out-of-scope changes before continuing. - -::: - -### 6. Run it Yourself - -When you're satisfied with the patch, you run the final command: - -```bash -flash run flash/brownfield_patch.dart --project-id --commit-message "Agent: add welcome block to HomePage" -``` - -Open the project in FlutterFlow. Confirm the change is exactly what you intended. - -:::tip[Tips for longer agent sessions] - -- **Commit after every successful `flash run`.** Your git history becomes the project's change log. -- **Keep tasks small.** A single agent prompt should produce a single patch that does a single logical thing. "Refactor the whole app" is not a task — break it into ten of them. -- **When the agent gets stuck, check context first.** Run `flash context-check`. Stale context produces errors that look like agent confusion but are actually cache drift — see [**Project context and staleness**](#project-context-and-staleness). -- **Keep `flash run` to yourself for now.** Even once you trust the agent, the discipline of reviewing before running keeps the workflow honest. - -::: - -Here's exactly how you do it: - -
- -
-

- -## Flash Concepts - -This section covers the mental model you need to use Flash effectively. If you've completed tutorial “Create New App” and “Modify Existing App”, a lot of this will feel like names for things you've already seen. - -### Workspace Anatomy - -Every `flash init` produces the same workspace shape: - -``` -my-app/ -├── .env.example Template for your API key. Copy to .env. -├── AGENTS.md Instructions for AI agents. -├── CLAUDE.md Claude-specific agent instructions. -├── flash/ -│ ├── app.dart Entry point for building a NEW app (greenfield). -│ └── brownfield_patch.dart Entry point for editing an existing app. -├── patterns/ Copy-paste recipes for common brownfield changes. -├── pubspec.yaml Dart dependencies. -├── references/ Complete working DSLs to learn from. -├── tooling/ Wrapper scripts for common flows. -└── .flash/ Local run history, traces, and cached context. - (Created automatically on first run.) -``` - -A few of these deserve special attention: - -- **`flash/app.dart`** and **`flash/brownfield_patch.dart`** are the two places your DSL lives. You'll almost never have both active at once — see [Greenfield vs. brownfield](#greenfield-vs-brownfield). -- **`references/`** is your teacher. When you don't know how to express something in the DSL, open the most similar reference app and copy the pattern. This is the single most effective way to learn Flash. -- **`patterns/`** is more focused: short, named recipes like "add a search filter to an existing list page" that you adapt into your `brownfield_patch.dart`. -- **`AGENTS.md`** and **`CLAUDE.md`** are what make the workspace agent-friendly. An agent that reads these files gets a working understanding of the environment without needing you to explain it. -- **`.flash/`** is where Flash stores state: run history, traces, and a cached representation of the FlutterFlow project you're working on. Don't commit this folder — add it to `.gitignore`. - -### Greenfield vs. Brownfield - -Flash has two modes for two situations: - -- **Greenfield**: You're creating a new FlutterFlow project from scratch. You work in `flash/app.dart`. Your DSL describes the entire app. When you `flash run`, Flash creates a new project in your FlutterFlow account. - - ```bash - flash run flash/app.dart --project-name "My New App" --commit-message "Initial app" - ``` - -- **Brownfield**: A FlutterFlow project already exists and you want to change it. You work in `flash/brownfield_patch.dart`. Your DSL describes only the *changes* you want to make, not the whole app. When you `flash run`, Flash applies the patch to the existing project. - - ```bash - flash run flash/brownfield_patch.dart --project-id --commit-message "Add search filter" - ``` - -The rule of thumb: - -- **First-time push of a new app** > greenfield, `flash/app.dart`, `-project-name`. -- **Every subsequent change** > brownfield, `flash/brownfield_patch.dart`, `-project-id`. - -Once a project exists in FlutterFlow, you almost never go back to `flash/app.dart` for it — brownfield is the normal mode. - -### Validate vs. Run - -These two commands are your inner dev loop. - -**`flash validate `** is a dry run. It: - -- Compiles your DSL. -- Checks it against the FlutterFlow schema. -- Reports errors and warnings. -- Does **not** touch your FlutterFlow account. - -It's fast and free. Run it every time you change the DSL. - -**`flash run `** is the real thing. It validates first (same check as above), then serializes the result and pushes it to FlutterFlow. This creates or modifies an actual project in your account. - -The rhythm: - -``` -edit → flash validate → edit → flash validate → flash run → review in FlutterFlow → repeat -``` - -If `flash validate` fails, fix it before `flash run`. Running straight to `flash run` without validating is a common mistake that wastes time — `flash run` does the same validation internally, so you're just moving the error report later. - -### Project Context and Staleness - -For brownfield edits, Flash keeps a **local cached representation** of the FlutterFlow project under `.flash/`. This is called the project **context**. It's what lets `flash inspect` show you the project structure quickly and what Flash uses to reason about your patch. - -Context can go stale. This happens whenever the FlutterFlow project changes in a way Flash doesn't see: - -- Someone else edits the project in the visual builder. -- You yourself edit it in the visual builder between Flash runs. -- A teammate runs `flash run` from another workspace. - -Two commands manage context: - -- **`flash context-check`** : Tells you whether your local context matches the current state of the project. Run this before starting non-trivial brownfield work. -- **`flash refresh-context `**: Pulls a fresh copy of the project into your workspace. Run this whenever `context-check` reports drift, or as a habit at the start of a work session. - -Stale context usually shows up as confusing `flash validate` errors — Flash thinks a page exists when it doesn't, or misses a field that was added. If a brownfield validation fails for a reason that doesn't match what you see in the editor, refresh context first and try again. - -## FAQs - -
- -`flash run` fails with an authentication error - - -

-Confirm `FF_API_KEY` is set in `.env` and the key is valid. Try passing `--api-key ` directly to rule out env-loading issues. If the CLI flag works but `.env` doesn't, check that your shell is running `flash` from the same directory as the `.env` file — Flash loads `.env` from the current working directory. -

-
- - -
- -`flash doctor` says the validator is missing - - -

-Try running the `flash precache` to download it. -

-
- -
- -`flash validate` fails with a proto fingerprint mismatch - - -

-Your local validator is out of date with the Flash version you're running. Run `flash precache` to refresh it, or reinstall Flash with `dart pub global activate flutterflow_flash_beta`. -

-
- -
- -`flash validate --project-id ` fails saying a page or widget doesn't exist, but you can see it in FlutterFlow - - -

-This is often caused by stale local project context. Flash caches a local copy of your FlutterFlow project under `.flash/`, and when that cache is out of date, validation can fail in ways that look like logic bugs. - -Fix it by running: - -```bash -flash context-check -flash refresh-context -``` - -`context-check` tells you whether your local copy matches the current state of the project. `refresh-context` pulls a fresh copy. - -

-
- -
- -Validation passes locally but `flash run` reports conflicting state - - -

-This is usually caused by stale cached project context under `.flash/`. Refresh your local copy of the project: - -```bash -flash context-check -flash refresh-context -``` - -

-
- - -
- -Error messages reference widget keys or IDs you don't recognize - - -

-This is another common sign of stale local project context. Run: - -```bash -flash context-check -flash refresh-context -``` - -

-
- -
- -How can I prevent stale context issues? - - -

-Run `flash context-check` at the start of every brownfield work session. Run `flash refresh-context` whenever someone else has edited the project, or whenever you've edited it in the visual builder between Flash runs. In team environments, treat `refresh-context` like `git pull` — do it reflexively before starting work. -

-
diff --git a/docs/ff-concepts/advanced/imgs/flash-ff-builder-using-same-ff-app.avif b/docs/ff-concepts/advanced/imgs/flash-ff-builder-using-same-ff-app.avif deleted file mode 100644 index 524babb5b18a030e5c5fa8199aa1c5f9e3e74d99..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36631 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 V&YaSC8Q6DM!#S}z`li#9#UQnr`4|8I diff --git a/docs/testing-deployment-publishing/exporting-code/ff-cli.md b/docs/testing-deployment-publishing/exporting-code/ff-cli.md index 06aee5af..b1073381 100644 --- a/docs/testing-deployment-publishing/exporting-code/ff-cli.md +++ b/docs/testing-deployment-publishing/exporting-code/ff-cli.md @@ -9,8 +9,7 @@ keywords: [CLI, Collaboration, FlutterFlow, Projects, Local Management] # FlutterFlow CLI - -The [FlutterFlow CLI](https://pub.dev/packages/flutterflow_cli) tool allows you to quickly and easily download your project files directly from FlutterFlow to your local machine. +The [FlutterFlow CLI](https://pub.dev/packages/flutterflow_cli) lets you manage FlutterFlow projects from the command line. You can create new projects, modify existing ones using AI agents, and download them to your local machine. ## Installation @@ -20,7 +19,138 @@ To use the FlutterFlow CLI, you first need to install it globally using Dart's p dart pub global activate flutterflow_cli ``` -## Usage +### Get API Token +To use the CLI, you'll need to create an API token and use it in your requests. See the documentation [here on how to generate an API token.](../../accounts-billing/account-management.md#how-do-i-generate-an-api-token) + +## Build Projects +The FlutterFlow CLI lets you build and edit FlutterFlow apps in the terminal instead of in the visual builder. You can use it to create brand-new apps or for changes to ones you already have. It's designed for AI agents, so you can hand work off and review their changes like any other code. + +:::info[Remember] + +- **FF CLI is not a replacement for the visual builder.** FlutterFlow is still faster for most visual work. FF CLI is for precision, repeatability, and automation. +- **FF CLI doesn't execute your app.** It produces a FlutterFlow project, which you can test and run inside FlutterFlow visual builder. +::: + +A FlutterFlow project is the source of truth. FF CLI is how you create or change it from code. You can write an app in the terminal, open the result in FlutterFlow's visual editor, and keep going in either direction. Both paths give you the same FlutterFlow app. + +![ff-cli-ff-builder-using-same-ff-app.avif](imgs/ff-cli-ff-builder-using-same-ff-app.avif) + +### Create Projects + +Let’s walk through using the FlutterFlow CLI by building a simple meditation app: + +#### 1. Start the workspace setup + +Open your terminal in the folder where you want the workspace to live, then run: + +```bash +flutterflow ai init +``` + +This launches an interactive setup wizard. + +#### 2. Name your workspace + +The wizard will ask for a workspace name or path. Type a short, lowercase name with no spaces. This becomes the folder name for your project. + +``` +Workspace name or path +> mindfly +``` + +#### 3. Pick an environment + +Next you'll see a list of FlutterFlow environments to connect to. Use ↑ / ↓ to highlight your choice and press **Enter**. + + +#### 4. Paste your FlutterFlow API key + +The wizard will ask for your API key. Paste it and press **Enter**. + +``` +FlutterFlow API key +> your-api-key-here +``` + +#### 5. Choose: New app or Edit existing + +The wizard now asks whether you want to edit an existing FlutterFlow project or create a new one: + +``` +Existing project ID to edit (press Enter to create a new app) +> paste-your-project-id-here +``` + +Press **Enter** with no input to create a new app. (To edit an existing project instead, paste its project ID here.) + +#### 6. Confirm the setup + +The wizard prints a summary of what it's about to do: + +``` +Ready to create FlutterFlow AI workspace: + Workspace: /Users/.../projects/mindfly + Flow: Create a new app + Environment: beta + SDK: 0.1.6 (build aed0f835) + Base URL: https://api.flutterflow.io/v2-staging + +Proceed? [Y/n] +``` + +Review the workspace path, environment, and flow. If everything looks right, press **Y** and **Enter**. + + +#### 7. Move into the workspace and launch your agent + +Move into the new workspace folder and start your preferred coding agent. This example uses Claude Code: + +```bash +cd mindfly +``` +and then... +```bash +claude +``` + +#### 8. Approve the FlutterFlow AI MCP server + +The first time the agent opens the workspace, it will detect the new MCP server and ask for permission: + +``` +New MCP server found in .mcp.json: flutterflow_ai + +MCP servers may execute code or access system resources. +All tool calls require approval. + +> 1. Use this and all future MCP servers in this project + 2. Use this MCP server + 3. Continue without using this MCP server +``` + +Choose **option 1** to use the FlutterFlow AI MCP server (and any others added to this workspace later) without being asked again. Press **Enter** to confirm. + +> **Why approve?** Without the MCP server, the agent can edit local files but can't actually push changes to your FlutterFlow project. With it approved, the agent has the same tools you'd run yourself from the CLI. +> + +#### 9. Describe your app in plain English + +Claude Code is now connected to your workspace and the FlutterFlow AI MCP server. Type what you want to build at the prompt: + +``` +> create a minimalist meditation app +``` + +Press **Enter**. The agent will plan the app, generate the code, push it to FlutterFlow through the MCP server, and report back. + +#### 10. Verify the app in the FlutterFlow visual builder +Open FlutterFlow in your browser and navigate to your project. You’ll see the generated app reflected in the visual builder. From here, you can continue refining the app visually or iterate further using the AI agent. + +### Modify Projects +To modify an existing project, [paste your project ID](#5-choose-new-app-or-edit-existing) when prompted instead of pressing Enter. This connects the workspace to your current FlutterFlow app. Once set up, you can use the AI agent to make changes, and updates will be pushed directly to the existing project. + + +## Download Projects Follow the steps below to export your project. @@ -51,10 +181,8 @@ Follow the steps below to export your project.

-### API Token -To use the CLI, you'll need to create an API token and use it in your requests. See the documentation [here on how to generate an API token.](/accounts-billing/account-management) -### CLI command details +### Command Details - If you wish to exclude assets from the download, use `-no-include-assets` in your command. This will download the project code without the assets. For example: `flutterflow export-code --project your_project_id --dest path_to_output_folde --no-include-assets --token your_token` @@ -73,11 +201,11 @@ To use the CLI, you'll need to create an API token and use it in your requests. | --[no]-as-debug | Whether to generate the project with debug logging to be able to use FlutterFlow Debug Panel inside the DevTools. | False | | --project-environment | Which [development environment](../development-environments/development-environments.md) to be used. If empty, the current environment in the project will be downloaded. | Current environment | -## Filtered exports +### Filtered exports If you are updating an existing project and do not want certain files to be overwritten during a code export, you can create a `.flutterflowignore` file in the root of your project directory. This file should contain a list of files to be ignored using globbing syntax. -### Example: +#### Example: If your project is located at: ``` /Users/yourname/projects/my_flutterflow_app/ @@ -87,7 +215,7 @@ Then, place the `.flutterflowignore` file in: /Users/yourname/projects/.flutterflowignore ``` -### Example `.flutterflowignore` contents: +#### Example `.flutterflowignore` contents: ``` my_flutterflow_app/android/app/build.gradle # Prevents FlutterFlow from overwriting native Android build configuration my_flutterflow_app/ios/Runner/Info.plist # Keeps iOS app metadata unchanged diff --git a/docs/testing-deployment-publishing/exporting-code/imgs/ff-cli-ff-builder-using-same-ff-app.avif b/docs/testing-deployment-publishing/exporting-code/imgs/ff-cli-ff-builder-using-same-ff-app.avif new file mode 100644 index 0000000000000000000000000000000000000000..7292aacf3ab07fdbf36dcf9178fe2c523843b350 GIT binary patch literal 25913 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 Date: Tue, 28 Apr 2026 13:55:52 +0530 Subject: [PATCH 04/20] Moved to Advanced section --- .../advanced}/ff-cli.md | 2 +- .../imgs/ff-cli-ff-builder-using-same-ff-app.avif | Bin 2 files changed, 1 insertion(+), 1 deletion(-) rename docs/{testing-deployment-publishing/exporting-code => ff-concepts/advanced}/ff-cli.md (97%) rename docs/{testing-deployment-publishing/exporting-code => ff-concepts/advanced}/imgs/ff-cli-ff-builder-using-same-ff-app.avif (100%) diff --git a/docs/testing-deployment-publishing/exporting-code/ff-cli.md b/docs/ff-concepts/advanced/ff-cli.md similarity index 97% rename from docs/testing-deployment-publishing/exporting-code/ff-cli.md rename to docs/ff-concepts/advanced/ff-cli.md index b1073381..e02b725e 100644 --- a/docs/testing-deployment-publishing/exporting-code/ff-cli.md +++ b/docs/ff-concepts/advanced/ff-cli.md @@ -199,7 +199,7 @@ Follow the steps below to export your project. | --[no]-parent-folder | Option to download the code into a subfolder instead of directly into the directory. | False | | --[no]-as-module | Whether to generate the project as a Flutter module. | False | | --[no]-as-debug | Whether to generate the project with debug logging to be able to use FlutterFlow Debug Panel inside the DevTools. | False | -| --project-environment | Which [development environment](../development-environments/development-environments.md) to be used. If empty, the current environment in the project will be downloaded. | Current environment | +| --project-environment | Which [development environment](../../testing-deployment-publishing/development-environments/development-environments.md) to be used. If empty, the current environment in the project will be downloaded. | Current environment | ### Filtered exports diff --git a/docs/testing-deployment-publishing/exporting-code/imgs/ff-cli-ff-builder-using-same-ff-app.avif b/docs/ff-concepts/advanced/imgs/ff-cli-ff-builder-using-same-ff-app.avif similarity index 100% rename from docs/testing-deployment-publishing/exporting-code/imgs/ff-cli-ff-builder-using-same-ff-app.avif rename to docs/ff-concepts/advanced/imgs/ff-cli-ff-builder-using-same-ff-app.avif From 300b66e712aefb2818382e9bbae94b3bebfa9157 Mon Sep 17 00:00:00 2001 From: Pinkesh Date: Tue, 28 Apr 2026 14:07:44 +0530 Subject: [PATCH 05/20] Fix broken links --- docs/accounts-billing/account-management.md | 2 +- docs/ff-integrations/ads/admob.md | 2 +- docs/ff-integrations/firebase/app-check.md | 2 +- docs/ff-integrations/firebase/crashlytics.md | 2 +- docs/ff-integrations/payments/stripe.md | 2 +- docs/intro/ff-ui/toolbar.md | 2 +- docs/resources/projects/settings/general-settings.md | 4 ++-- .../running-your-app/automated-tests.md | 2 +- .../running-your-app/local-run.md | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/accounts-billing/account-management.md b/docs/accounts-billing/account-management.md index c0884fbe..4d80cb4d 100644 --- a/docs/accounts-billing/account-management.md +++ b/docs/accounts-billing/account-management.md @@ -76,7 +76,7 @@ Now, you are ready to log in with your new email address and password. ![update-email.png](imgs/update-email.png) ### How do I generate an API Token? -An API token is required to use the [CLI](../testing-deployment-publishing/exporting-code/ff-cli.md) and the [Visual Studio Code Extension](../ff-concepts/adding-customization/vscode-extension.md) +An API token is required to use the [CLI](../ff-concepts/advanced/ff-cli.md) and the [Visual Studio Code Extension](../ff-concepts/adding-customization/vscode-extension.md) . To create an API token tied to your account: diff --git a/docs/ff-integrations/ads/admob.md b/docs/ff-integrations/ads/admob.md index 18d3fb28..a2cee83e 100644 --- a/docs/ff-integrations/ads/admob.md +++ b/docs/ff-integrations/ads/admob.md @@ -159,7 +159,7 @@ While building your app, clicking on too many ads may cause your AdMob account t ### Testing AdBanner -Ads cannot be tested in Test or Run Mode. They can only be tested on a real device or emulator. To do this, you can use [Local run](../../testing-deployment-publishing/running-your-app/local-run.md) or [download the code](../../testing-deployment-publishing/exporting-code/ff-cli.md) and run it in your IDE. +Ads cannot be tested in Test or Run Mode. They can only be tested on a real device or emulator. To do this, you can use [Local run](../../testing-deployment-publishing/running-your-app/local-run.md) or [download the code](../../ff-concepts/advanced/ff-cli.md#download-projects) and run it in your IDE. ## Interstitial Ad diff --git a/docs/ff-integrations/firebase/app-check.md b/docs/ff-integrations/firebase/app-check.md index 02c90bd2..1c7e753e 100644 --- a/docs/ff-integrations/firebase/app-check.md +++ b/docs/ff-integrations/firebase/app-check.md @@ -180,7 +180,7 @@ To add *Firebase App Check* to your app: 5. You might want to see if it works on a real device or an emulator. To run on a real device, you can set the **Android Provider** to **Play Integrity** and to run on an emulator, set it to **Debug,** and then try checking it by downloading the APK. 1. If it doesn't work for *Play Integrity*, ensure you have enabled the Play Integrity API. See how to do it in step 2 [here](https://firebase.google.com/docs/app-check/android/play-integrity-provider?authuser=1&hl=en#project-setup). - 2. If it doesn't work for *Debug*, you can try [downloading the code](../../testing-deployment-publishing/exporting-code/ff-cli.md), following the instructions [here](https://firebase.google.com/docs/app-check/flutter/debug-provider#android), and running it locally. + 2. If it doesn't work for *Debug*, you can try [downloading the code](../../ff-concepts/advanced/ff-cli.md#download-projects), following the instructions [here](https://firebase.google.com/docs/app-check/flutter/debug-provider#android), and running it locally. :::tip To add the App Check on the app with the non-Firebase (i.e., your self-hosted) backend, follow the instructions [**here**](https://firebase.google.com/docs/app-check/flutter/custom-resource). diff --git a/docs/ff-integrations/firebase/crashlytics.md b/docs/ff-integrations/firebase/crashlytics.md index 38bfbd9c..751adae2 100644 --- a/docs/ff-integrations/firebase/crashlytics.md +++ b/docs/ff-integrations/firebase/crashlytics.md @@ -19,6 +19,6 @@ You can see all the logged errors/crashes inside the Crashlytics dashboard of yo ![Crashlytics dashboard](imgs/crashlytics-dashboard.avif) 1. Click on the issue name to see its details. -2. To test the crash on your app, [download the app](../../testing-deployment-publishing/exporting-code/ff-cli.md), add a code that throws an error, and run it on a mobile device or emulator with an active internet connection. +2. To test the crash on your app, [download the app](../../ff-concepts/advanced/ff-cli.md#download-projects), add a code that throws an error, and run it on a mobile device or emulator with an active internet connection. ![Test crash](imgs/test-crash.avif) \ No newline at end of file diff --git a/docs/ff-integrations/payments/stripe.md b/docs/ff-integrations/payments/stripe.md index 0d5c6e1d..871972b8 100644 --- a/docs/ff-integrations/payments/stripe.md +++ b/docs/ff-integrations/payments/stripe.md @@ -241,7 +241,7 @@ You can test Stripe payments on mobile and the Web before deployment. To do that 1. Go to the FlutterFlow project and navigate to **Settings and Integrations** > **In App Purchases & Subscriptions** > **Stripe**. 2. Make sure the **Is Production** is disabled. 3. Make sure you have entered the correct **Test Credentials,** such as **Publishable Key** and **Secret Key**. -4. [Download](../../testing-deployment-publishing/exporting-code/ff-cli.md) and [run](../../testing-deployment-publishing/running-your-app/run-your-app.md) your project.. +4. [Download](../../ff-concepts/advanced/ff-cli.md#download-projects) and [run](../../testing-deployment-publishing/running-your-app/run-your-app.md) your project.. 5. To test the purchase, you can use any of these [basic test card numbers](https://stripe.com/docs/testing#cards). ### 5. Releasing to Production diff --git a/docs/intro/ff-ui/toolbar.md b/docs/intro/ff-ui/toolbar.md index 4119ffd6..ea91376a 100644 --- a/docs/intro/ff-ui/toolbar.md +++ b/docs/intro/ff-ui/toolbar.md @@ -102,7 +102,7 @@ The Developer Menu provides developers with access to tools such as code viewing 4. **Download APK**: Use this to generate a release build of your Android app. It will automatically download the `.apk` file after the building process is complete. -5. **FlutterFlow CLI**: You can also download the code using *[FlutterFlow CLI](https://pub.dev/packages/flutterflow_cli)*. See instructions [here](../../testing-deployment-publishing/exporting-code/ff-cli.md). +5. **FlutterFlow CLI**: You can also download the code using *[FlutterFlow CLI](https://pub.dev/packages/flutterflow_cli)*. See instructions [here](../../ff-concepts/advanced/ff-cli.md#download-projects). :::note _Connect GitHub Repo_, _Download Code_, and _Download APK_ features requires a [**paid plan**](https://flutterflow.io/pricing). diff --git a/docs/resources/projects/settings/general-settings.md b/docs/resources/projects/settings/general-settings.md index 1569444f..4c45d307 100644 --- a/docs/resources/projects/settings/general-settings.md +++ b/docs/resources/projects/settings/general-settings.md @@ -132,7 +132,7 @@ To add the app launcher icon: 2. Under the **General** section, select **App Assets**. 3. Under the **Launcher Icon** section, click on the **Upload Image** button. 4. By clicking on the **Unset** dropdown menu, you can also select from the already uploaded images to the Project Media/Assets. -5. [Download the project](../../../testing-deployment-publishing/exporting-code/ff-cli.md) and run the following command in your terminal to generate the launcher icon: +5. [Download the project](../../../ff-concepts/advanced/ff-cli.md#download-projects) and run the following command in your terminal to generate the launcher icon: `flutter pub run flutter_launcher_icons:main` @@ -151,7 +151,7 @@ Here are the steps to add adaptive icons: 2. Return to FlutterFlow and navigate to **Setting and Integrations > General** > **App Assets > Android Adaptive Icon.** 1. Upload the **Foreground Icon**. If you use the online tool, you'll find it inside the `IconKitchen-Output > android > res > mipmap-xxxhdpi > ic_launcher_foreground.png`. 2. For **Background Type**, you can either set the **Color** or **Image**. It's recommended to use a color that aligns with your app's branding for a cohesive look. -3. [Download the project](../../../testing-deployment-publishing/exporting-code/ff-cli.md) and run the following command in your terminal to generate the launcher icon: +3. [Download the project](../../../ff-concepts/advanced/ff-cli.md#download-projects) and run the following command in your terminal to generate the launcher icon: `flutter pub run flutter_launcher_icons:main` diff --git a/docs/testing-deployment-publishing/running-your-app/automated-tests.md b/docs/testing-deployment-publishing/running-your-app/automated-tests.md index 09cdc734..c54395f9 100644 --- a/docs/testing-deployment-publishing/running-your-app/automated-tests.md +++ b/docs/testing-deployment-publishing/running-your-app/automated-tests.md @@ -164,7 +164,7 @@ You can run tests on local devices or use the services like [Firebase Test Lab]( To run the tests locally: -1. [Download the project code](../exporting-code/ff-cli.md). +1. [Download the project code](../../ff-concepts/advanced/ff-cli.md#download-projects). 2. Go to `your_project/integration_test/test.dart`. 3. To run a specific test, click the play button next to it. To execute all tests at once, double-click the play button next to `void main`. 4. Alternatively, you can use the terminal and enter the command: `flutter test integration_test/test.dart`." diff --git a/docs/testing-deployment-publishing/running-your-app/local-run.md b/docs/testing-deployment-publishing/running-your-app/local-run.md index 65a68616..c8af301e 100644 --- a/docs/testing-deployment-publishing/running-your-app/local-run.md +++ b/docs/testing-deployment-publishing/running-your-app/local-run.md @@ -212,7 +212,7 @@ Here’s how you do it: To download your app code, you have two options: -- Use the [FlutterFlow CLI](../exporting-code/ff-cli.md). (Recommended) +- Use the [FlutterFlow CLI](../../ff-concepts/advanced/ff-cli.md#download-projects). (Recommended) - Alternatively, from the **Toolbar**, click on the **Developer Menu** > **Download Code**. This will download the *.zip* file. Extract the *.zip* file to view the contents of the project. ### 2. Setup Flutter SDK From bf38e5491e7253952099384021c306a23dc735a3 Mon Sep 17 00:00:00 2001 From: PoojaB26 Date: Tue, 28 Apr 2026 16:47:48 +0530 Subject: [PATCH 06/20] move around the files and split the section into pages --- docs/ff-concepts/advanced/ff-cli.md | 239 ------------------ .../advanced/flutterflow-cli/_category_.json | 4 + .../flutterflow-cli/exporting-projects.md | 97 +++++++ .../flutterflow-cli/flutterflow-mcp.md | 137 ++++++++++ .../advanced/flutterflow-cli/overview.md | 36 +++ 5 files changed, 274 insertions(+), 239 deletions(-) delete mode 100644 docs/ff-concepts/advanced/ff-cli.md create mode 100644 docs/ff-concepts/advanced/flutterflow-cli/_category_.json create mode 100644 docs/ff-concepts/advanced/flutterflow-cli/exporting-projects.md create mode 100644 docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md create mode 100644 docs/ff-concepts/advanced/flutterflow-cli/overview.md diff --git a/docs/ff-concepts/advanced/ff-cli.md b/docs/ff-concepts/advanced/ff-cli.md deleted file mode 100644 index e02b725e..00000000 --- a/docs/ff-concepts/advanced/ff-cli.md +++ /dev/null @@ -1,239 +0,0 @@ ---- -slug: /exporting/ff-cli -title: FlutterFlow CLI -description: Learn how to download and manage your FlutterFlow projects locally using the FlutterFlow CLI. -tags: [CLI, Collaboration, FlutterFlow] -sidebar_position: 1 -keywords: [CLI, Collaboration, FlutterFlow, Projects, Local Management] ---- - - -# FlutterFlow CLI -The [FlutterFlow CLI](https://pub.dev/packages/flutterflow_cli) lets you manage FlutterFlow projects from the command line. You can create new projects, modify existing ones using AI agents, and download them to your local machine. - -## Installation - -To use the FlutterFlow CLI, you first need to install it globally using Dart's package manager with the following command: - -``` -dart pub global activate flutterflow_cli -``` - -### Get API Token -To use the CLI, you'll need to create an API token and use it in your requests. See the documentation [here on how to generate an API token.](../../accounts-billing/account-management.md#how-do-i-generate-an-api-token) - -## Build Projects -The FlutterFlow CLI lets you build and edit FlutterFlow apps in the terminal instead of in the visual builder. You can use it to create brand-new apps or for changes to ones you already have. It's designed for AI agents, so you can hand work off and review their changes like any other code. - -:::info[Remember] - -- **FF CLI is not a replacement for the visual builder.** FlutterFlow is still faster for most visual work. FF CLI is for precision, repeatability, and automation. -- **FF CLI doesn't execute your app.** It produces a FlutterFlow project, which you can test and run inside FlutterFlow visual builder. -::: - -A FlutterFlow project is the source of truth. FF CLI is how you create or change it from code. You can write an app in the terminal, open the result in FlutterFlow's visual editor, and keep going in either direction. Both paths give you the same FlutterFlow app. - -![ff-cli-ff-builder-using-same-ff-app.avif](imgs/ff-cli-ff-builder-using-same-ff-app.avif) - -### Create Projects - -Let’s walk through using the FlutterFlow CLI by building a simple meditation app: - -#### 1. Start the workspace setup - -Open your terminal in the folder where you want the workspace to live, then run: - -```bash -flutterflow ai init -``` - -This launches an interactive setup wizard. - -#### 2. Name your workspace - -The wizard will ask for a workspace name or path. Type a short, lowercase name with no spaces. This becomes the folder name for your project. - -``` -Workspace name or path -> mindfly -``` - -#### 3. Pick an environment - -Next you'll see a list of FlutterFlow environments to connect to. Use ↑ / ↓ to highlight your choice and press **Enter**. - - -#### 4. Paste your FlutterFlow API key - -The wizard will ask for your API key. Paste it and press **Enter**. - -``` -FlutterFlow API key -> your-api-key-here -``` - -#### 5. Choose: New app or Edit existing - -The wizard now asks whether you want to edit an existing FlutterFlow project or create a new one: - -``` -Existing project ID to edit (press Enter to create a new app) -> paste-your-project-id-here -``` - -Press **Enter** with no input to create a new app. (To edit an existing project instead, paste its project ID here.) - -#### 6. Confirm the setup - -The wizard prints a summary of what it's about to do: - -``` -Ready to create FlutterFlow AI workspace: - Workspace: /Users/.../projects/mindfly - Flow: Create a new app - Environment: beta - SDK: 0.1.6 (build aed0f835) - Base URL: https://api.flutterflow.io/v2-staging - -Proceed? [Y/n] -``` - -Review the workspace path, environment, and flow. If everything looks right, press **Y** and **Enter**. - - -#### 7. Move into the workspace and launch your agent - -Move into the new workspace folder and start your preferred coding agent. This example uses Claude Code: - -```bash -cd mindfly -``` -and then... -```bash -claude -``` - -#### 8. Approve the FlutterFlow AI MCP server - -The first time the agent opens the workspace, it will detect the new MCP server and ask for permission: - -``` -New MCP server found in .mcp.json: flutterflow_ai - -MCP servers may execute code or access system resources. -All tool calls require approval. - -> 1. Use this and all future MCP servers in this project - 2. Use this MCP server - 3. Continue without using this MCP server -``` - -Choose **option 1** to use the FlutterFlow AI MCP server (and any others added to this workspace later) without being asked again. Press **Enter** to confirm. - -> **Why approve?** Without the MCP server, the agent can edit local files but can't actually push changes to your FlutterFlow project. With it approved, the agent has the same tools you'd run yourself from the CLI. -> - -#### 9. Describe your app in plain English - -Claude Code is now connected to your workspace and the FlutterFlow AI MCP server. Type what you want to build at the prompt: - -``` -> create a minimalist meditation app -``` - -Press **Enter**. The agent will plan the app, generate the code, push it to FlutterFlow through the MCP server, and report back. - -#### 10. Verify the app in the FlutterFlow visual builder -Open FlutterFlow in your browser and navigate to your project. You’ll see the generated app reflected in the visual builder. From here, you can continue refining the app visually or iterate further using the AI agent. - -### Modify Projects -To modify an existing project, [paste your project ID](#5-choose-new-app-or-edit-existing) when prompted instead of pressing Enter. This connects the workspace to your current FlutterFlow app. Once set up, you can use the AI agent to make changes, and updates will be pushed directly to the existing project. - - -## Download Projects - -Follow the steps below to export your project. - -
- -
-

- - -### Command Details - -- If you wish to exclude assets from the download, use `-no-include-assets` in your command. This will download the project code without the assets. For example: `flutterflow export-code --project your_project_id --dest path_to_output_folde --no-include-assets --token your_token` - -- You can download code from a specific branch by switching to that branch and using the toolbar command, or by including the `-branch-name` or `-b` flag in your command and specifying the branch you wish to download from. - -#### All supported command options - -| Flag | Behavior | Default | -| --- | --- | --- | -| --dest / -d | Specifies a destination folder other than the current directory. | Current directory | -| --[no]-include-assets | Option to download assets (images, GIFs). Useful for consecutive code exports if the assets folder hasn't changed. | False | -| --branch-name / -b | Downloads from a specific branch. | Main | -| --[no]-fix | Option to run dart fix on the code after downloading. | False | -| --[no]-parent-folder | Option to download the code into a subfolder instead of directly into the directory. | False | -| --[no]-as-module | Whether to generate the project as a Flutter module. | False | -| --[no]-as-debug | Whether to generate the project with debug logging to be able to use FlutterFlow Debug Panel inside the DevTools. | False | -| --project-environment | Which [development environment](../../testing-deployment-publishing/development-environments/development-environments.md) to be used. If empty, the current environment in the project will be downloaded. | Current environment | - -### Filtered exports - -If you are updating an existing project and do not want certain files to be overwritten during a code export, you can create a `.flutterflowignore` file in the root of your project directory. This file should contain a list of files to be ignored using globbing syntax. - -#### Example: -If your project is located at: -``` -/Users/yourname/projects/my_flutterflow_app/ -``` -Then, place the `.flutterflowignore` file in: -``` -/Users/yourname/projects/.flutterflowignore -``` - -#### Example `.flutterflowignore` contents: -``` -my_flutterflow_app/android/app/build.gradle # Prevents FlutterFlow from overwriting native Android build configuration -my_flutterflow_app/ios/Runner/Info.plist # Keeps iOS app metadata unchanged -my_flutterflow_app/web/index.html # Ensures custom modifications to the web entry file are retained -``` -This ensures that the specified files and directories are not overwritten during code export. - -For more details on globbing syntax, refer to [this guide](https://pub.dev/packages/glob#syntax). - - -## FAQ -
-I am getting an error as FormatException: Missing argument for… -

-This error likely indicates that you haven't correctly entered the command option along with its value. Double-check that all required information has been entered. If everything is correct and you're still encountering the error, it might be due to using an outdated version of the FlutterFlow CLI. To resolve this, you can update to the latest version by running the installation command: -``` -dart pub global activate flutterflow_cli -``` -This should update the CLI and fix the issue. -

-
diff --git a/docs/ff-concepts/advanced/flutterflow-cli/_category_.json b/docs/ff-concepts/advanced/flutterflow-cli/_category_.json new file mode 100644 index 00000000..4ffe689c --- /dev/null +++ b/docs/ff-concepts/advanced/flutterflow-cli/_category_.json @@ -0,0 +1,4 @@ +{ + "label": "FlutterFlow CLI", + "position": 1 +} \ No newline at end of file diff --git a/docs/ff-concepts/advanced/flutterflow-cli/exporting-projects.md b/docs/ff-concepts/advanced/flutterflow-cli/exporting-projects.md new file mode 100644 index 00000000..74d09980 --- /dev/null +++ b/docs/ff-concepts/advanced/flutterflow-cli/exporting-projects.md @@ -0,0 +1,97 @@ +--- +slug: /flutterflow-cli/exporting +title: Exporting Projects +description: Learn how to download and manage your FlutterFlow projects locally using the FlutterFlow CLI. +tags: [CLI, Collaboration, FlutterFlow] +sidebar_position: 2 +keywords: [CLI, Collaboration, FlutterFlow, Projects, Local Management] +--- + + +# Download Projects with FlutterFlow CLI + +Follow the steps below to export your project. + +
+ +
+

+ + +### Command Details + +- If you wish to exclude assets from the download, use `-no-include-assets` in your command. This will download the project code without the assets. For example: `flutterflow export-code --project your_project_id --dest path_to_output_folde --no-include-assets --token your_token` + +- You can download code from a specific branch by switching to that branch and using the toolbar command, or by including the `-branch-name` or `-b` flag in your command and specifying the branch you wish to download from. + +#### All supported command options + +| Flag | Behavior | Default | +| --- | --- | --- | +| --dest / -d | Specifies a destination folder other than the current directory. | Current directory | +| --[no]-include-assets | Option to download assets (images, GIFs). Useful for consecutive code exports if the assets folder hasn't changed. | False | +| --branch-name / -b | Downloads from a specific branch. | Main | +| --[no]-fix | Option to run dart fix on the code after downloading. | False | +| --[no]-parent-folder | Option to download the code into a subfolder instead of directly into the directory. | False | +| --[no]-as-module | Whether to generate the project as a Flutter module. | False | +| --[no]-as-debug | Whether to generate the project with debug logging to be able to use FlutterFlow Debug Panel inside the DevTools. | False | +| --project-environment | Which [development environment](../../../testing-deployment-publishing/development-environments/development-environments.md) to be used. If empty, the current environment in the project will be downloaded. | Current environment | + +### Filtered exports + +If you are updating an existing project and do not want certain files to be overwritten during a code export, you can create a `.flutterflowignore` file in the root of your project directory. This file should contain a list of files to be ignored using globbing syntax. + +#### Example: +If your project is located at: +``` +/Users/yourname/projects/my_flutterflow_app/ +``` +Then, place the `.flutterflowignore` file in: +``` +/Users/yourname/projects/.flutterflowignore +``` + +#### Example `.flutterflowignore` contents: +``` +my_flutterflow_app/android/app/build.gradle # Prevents FlutterFlow from overwriting native Android build configuration +my_flutterflow_app/ios/Runner/Info.plist # Keeps iOS app metadata unchanged +my_flutterflow_app/web/index.html # Ensures custom modifications to the web entry file are retained +``` +This ensures that the specified files and directories are not overwritten during code export. + +For more details on globbing syntax, refer to [this guide](https://pub.dev/packages/glob#syntax). + + +## FAQ +
+I am getting an error as FormatException: Missing argument for… +

+This error likely indicates that you haven't correctly entered the command option along with its value. Double-check that all required information has been entered. If everything is correct and you're still encountering the error, it might be due to using an outdated version of the FlutterFlow CLI. To resolve this, you can update to the latest version by running the installation command: +``` +dart pub global activate flutterflow_cli +``` +This should update the CLI and fix the issue. +

+
diff --git a/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md b/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md new file mode 100644 index 00000000..dfd2527e --- /dev/null +++ b/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md @@ -0,0 +1,137 @@ +--- +slug: /flutterflow-cli/mcp +title: Build with AI Agents +description: Learn how to created and edit FlutterFlow projects with your own agents. +tags: [CLI, AI, MCP] +sidebar_position: 3 +keywords: [CLI, Agentic AI, Projects, Local Management, MCP] +--- + + +# Build with AI Agents +The FlutterFlow CLI lets you build and edit FlutterFlow apps in the terminal instead of in the visual builder. You can use it to create brand-new apps or for changes to ones you already have. It's designed for AI agents, so you can hand work off and review their changes like any other code. + +:::info[Remember] + +- **FF CLI is not a replacement for the visual builder.** FlutterFlow is still faster for most visual work. FF CLI is for precision, repeatability, and automation. +- **FF CLI doesn't execute your app.** It produces a FlutterFlow project, which you can test and run inside FlutterFlow visual builder. +::: + +A FlutterFlow project is the source of truth. FF CLI is how you create or change it from code. You can write an app in the terminal, open the result in FlutterFlow's visual editor, and keep going in either direction. Both paths give you the same FlutterFlow app. + +![ff-cli-ff-builder-using-same-ff-app.avif](../imgs/ff-cli-ff-builder-using-same-ff-app.avif) + +### Create Projects + +Let’s walk through using the FlutterFlow CLI by building a simple meditation app: + +#### 1. Start the workspace setup + +Open your terminal in the folder where you want the workspace to live, then run: + +```bash +flutterflow ai init +``` + +This launches an interactive setup wizard. + +#### 2. Name your workspace + +The wizard will ask for a workspace name or path. Type a short, lowercase name with no spaces. This becomes the folder name for your project. + +``` +Workspace name or path +> mindfly +``` + +#### 3. Pick an environment + +Next you'll see a list of FlutterFlow environments to connect to. Use ↑ / ↓ to highlight your choice and press **Enter**. + + +#### 4. Paste your FlutterFlow API key + +The wizard will ask for your API key. Paste it and press **Enter**. + +``` +FlutterFlow API key +> your-api-key-here +``` + +#### 5. Choose: New app or Edit existing + +The wizard now asks whether you want to edit an existing FlutterFlow project or create a new one: + +``` +Existing project ID to edit (press Enter to create a new app) +> paste-your-project-id-here +``` + +Press **Enter** with no input to create a new app. (To edit an existing project instead, paste its project ID here.) + +#### 6. Confirm the setup + +The wizard prints a summary of what it's about to do: + +``` +Ready to create FlutterFlow AI workspace: + Workspace: /Users/.../projects/mindfly + Flow: Create a new app + Environment: beta + SDK: 0.1.6 (build aed0f835) + Base URL: https://api.flutterflow.io/v2-staging + +Proceed? [Y/n] +``` + +Review the workspace path, environment, and flow. If everything looks right, press **Y** and **Enter**. + + +#### 7. Move into the workspace and launch your agent + +Move into the new workspace folder and start your preferred coding agent. This example uses Claude Code: + +```bash +cd mindfly +``` +and then... +```bash +claude +``` + +#### 8. Approve the FlutterFlow AI MCP server + +The first time the agent opens the workspace, it will detect the new MCP server and ask for permission: + +``` +New MCP server found in .mcp.json: flutterflow_ai + +MCP servers may execute code or access system resources. +All tool calls require approval. + +> 1. Use this and all future MCP servers in this project + 2. Use this MCP server + 3. Continue without using this MCP server +``` + +Choose **option 1** to use the FlutterFlow AI MCP server (and any others added to this workspace later) without being asked again. Press **Enter** to confirm. + +> **Why approve?** Without the MCP server, the agent can edit local files but can't actually push changes to your FlutterFlow project. With it approved, the agent has the same tools you'd run yourself from the CLI. +> + +#### 9. Describe your app in plain English + +Claude Code is now connected to your workspace and the FlutterFlow AI MCP server. Type what you want to build at the prompt: + +``` +> create a minimalist meditation app +``` + +Press **Enter**. The agent will plan the app, generate the code, push it to FlutterFlow through the MCP server, and report back. + +#### 10. Verify the app in the FlutterFlow visual builder +Open FlutterFlow in your browser and navigate to your project. You’ll see the generated app reflected in the visual builder. From here, you can continue refining the app visually or iterate further using the AI agent. + +### Modify Projects +To modify an existing project, [paste your project ID](#5-choose-new-app-or-edit-existing) when prompted instead of pressing Enter. This connects the workspace to your current FlutterFlow app. Once set up, you can use the AI agent to make changes, and updates will be pushed directly to the existing project. + diff --git a/docs/ff-concepts/advanced/flutterflow-cli/overview.md b/docs/ff-concepts/advanced/flutterflow-cli/overview.md new file mode 100644 index 00000000..9ea33eba --- /dev/null +++ b/docs/ff-concepts/advanced/flutterflow-cli/overview.md @@ -0,0 +1,36 @@ +--- +slug: /flutterflow-cli +title: Installation +description: Learn how to download and manage your FlutterFlow projects locally using the FlutterFlow CLI. +tags: [CLI, Collaboration, FlutterFlow] +sidebar_position: 1 +keywords: [CLI, Collaboration, FlutterFlow, Projects, Local Management] +--- + + +# FlutterFlow CLI +The [FlutterFlow CLI](https://pub.dev/packages/flutterflow_cli) lets you manage FlutterFlow projects from the command line. You can create new projects, modify existing ones using AI agents, and download them to your local machine. + +## Installation + +To use the FlutterFlow CLI, you first need to install it globally using Dart's package manager with the following command: + +``` +dart pub global activate flutterflow_cli +``` + +### Get API Token +To use the CLI, you'll need to create an API token and use it in your requests. See the documentation [here on how to generate an API token.](../../../accounts-billing/account-management.md#how-do-i-generate-an-api-token) + + +## FAQ +
+I am getting an error as FormatException: Missing argument for… +

+This error likely indicates that you haven't correctly entered the command option along with its value. Double-check that all required information has been entered. If everything is correct and you're still encountering the error, it might be due to using an outdated version of the FlutterFlow CLI. To resolve this, you can update to the latest version by running the installation command: +``` +dart pub global activate flutterflow_cli +``` +This should update the CLI and fix the issue. +

+
From 17198337d65e9f5e906202964c452a7c4bab93d7 Mon Sep 17 00:00:00 2001 From: PoojaB26 Date: Tue, 28 Apr 2026 19:45:02 +0530 Subject: [PATCH 07/20] Update FlutterFlow CLI documentation: rename 'Download Projects' to 'Exporting Projects' and enhance 'Build with AI Agents' section with more info about the mcp tool --- .../flutterflow-cli/exporting-projects.md | 3 +- .../flutterflow-cli/flutterflow-mcp.md | 221 ++++++++++++------ 2 files changed, 150 insertions(+), 74 deletions(-) diff --git a/docs/ff-concepts/advanced/flutterflow-cli/exporting-projects.md b/docs/ff-concepts/advanced/flutterflow-cli/exporting-projects.md index 74d09980..d48ecba3 100644 --- a/docs/ff-concepts/advanced/flutterflow-cli/exporting-projects.md +++ b/docs/ff-concepts/advanced/flutterflow-cli/exporting-projects.md @@ -8,8 +8,7 @@ keywords: [CLI, Collaboration, FlutterFlow, Projects, Local Management] --- -# Download Projects with FlutterFlow CLI - +# Exporting Projects Follow the steps below to export your project.
mindfly + ``` +2. **Environment.** Use ↑ / ↓ to highlight the FlutterFlow environment you want this workspace to target, then press **Enter**. +3. **Link to an existing FlutterFlow project?** Press **Enter** (default `N`) to create a new app. Answer `y` to bind the workspace to an existing project — the wizard will then ask for the project ID. + ``` + Link to an existing FlutterFlow project? [y/N] + ``` +4. **FlutterFlow API key.** Paste your API key and press **Enter**. Input is masked. +5. **Register MCP server with detected coding CLIs.** The wizard scans your `PATH` and offers to register the FlutterFlow AI MCP server with each agent it finds (Claude Code, Gemini CLI, Codex). Answer `Y` (default) for each one you plan to use. + ``` + Register FlutterFlow AI MCP server with coding CLIs + Detected: claude, gemini, codex + Register with claude? [Y/n] + ``` +6. **Confirm.** The wizard prints a summary. Review it and press **Enter** (default `Y`) to proceed. + ``` + Ready to create: + Workspace: mindfly + Project ID: (none — unlinked) + API key: set (***abcd) + Base URL: https://api.flutterflow.io (built-in for prod) + MCP CLIs: claude, gemini, codex + + Proceed? [Y/n] + ``` + +When the wizard finishes, you'll have a workspace folder ready for your agent. Depending on which CLIs you registered, the folder will contain one or more of: + +- `.mcp.json` — for Claude Code +- `.gemini/settings.json` — for Gemini CLI +- `.codex/config.toml` — for Codex + +Each file points the corresponding agent at the FlutterFlow AI MCP server. + +## Launch your Agent + +Move into the workspace and start your agent. The example below uses Claude Code; the same pattern applies to any agent you registered in the wizard — `cd` into the workspace and launch the agent's CLI. -#### 2. Name your workspace +```bash +cd mindfly +claude +``` -The wizard will ask for a workspace name or path. Type a short, lowercase name with no spaces. This becomes the folder name for your project. +The first time the agent opens the workspace, it detects the new MCP server and asks you to approve it. The exact prompt varies by agent — Claude Code's looks like this: ``` -Workspace name or path -> mindfly -``` +New MCP server found in .mcp.json: flutterflow_ai -#### 3. Pick an environment +MCP servers may execute code or access system resources. +All tool calls require approval. -Next you'll see a list of FlutterFlow environments to connect to. Use ↑ / ↓ to highlight your choice and press **Enter**. +> 1. Use this and all future MCP servers in this project + 2. Use this MCP server + 3. Continue without using this MCP server +``` + +Choose **option 1** to approve the FlutterFlow AI MCP server (and any others added to this workspace later) without being asked again. +> **Why approve?** Without the MCP server, the agent can edit local files but can't push changes to your FlutterFlow project. With it approved, the agent has the same tools you'd run yourself from the CLI. -#### 4. Paste your FlutterFlow API key +## Generate a New App -The wizard will ask for your API key. Paste it and press **Enter**. +With the agent connected, describe the app you want at the prompt: ``` -FlutterFlow API key -> your-api-key-here +> create a minimalist meditation app ``` -#### 5. Choose: New app or Edit existing +Phrase it however you like — `a recipe-sharing app with a social feed`, `a habit tracker with streaks`, `a tip calculator for restaurants`. The agent plans the app, generates the changes, pushes them to FlutterFlow through the MCP server, and reports back. Open FlutterFlow in your browser and navigate to the project — the generated app will be reflected in the visual builder. From there you can keep refining visually or send another prompt to the agent. -The wizard now asks whether you want to edit an existing FlutterFlow project or create a new one: +Once the app exists, the workspace is bound to it. Follow-up prompts in the same session are treated as edits, not new generations, you'll see the agent acknowledge the switch with something like: ``` -Existing project ID to edit (press Enter to create a new app) -> paste-your-project-id-here +The project is bound, so I'll switch to edit mode. +Let me check the workspace and read the edit template. ``` -Press **Enter** with no input to create a new app. (To edit an existing project instead, paste its project ID here.) +From that point on, the same rules apply as when [editing an existing project](#edit-an-existing-project) - concurrency, branches, scope, and refreshing context. -#### 6. Confirm the setup +## Edit an Existing Project -The wizard prints a summary of what it's about to do: +:::info[Prerequisite] +Have your **project ID** ready. Open the project in the FlutterFlow editor. The project ID is the path segment after `/project/` in the URL. +::: -``` -Ready to create FlutterFlow AI workspace: - Workspace: /Users/.../projects/mindfly - Flow: Create a new app - Environment: beta - SDK: 0.1.6 (build aed0f835) - Base URL: https://api.flutterflow.io/v2-staging - -Proceed? [Y/n] +Editing an existing project follows the same flow as [creating a new one](#set-up-a-workspace) — you run `flutterflow ai init` to scaffold a workspace, then drive changes from your agent. The only difference is one step in the wizard: when it asks **Link to an existing FlutterFlow project?**, answer `y` and paste your project ID: + +```dart +Link to an existing FlutterFlow project? [y/N] y +Project ID +> my-meditation-app-x7k2p9 ``` -Review the workspace path, environment, and flow. If everything looks right, press **Y** and **Enter**. +The workspace is now bound to that project. `cd` into the workspace folder, [launch your agent](#launch-your-agent), and describe the changes you want — "add a profile screen", "switch the primary color to teal", "wire up the login form to Firebase Auth". The agent reads the current project, plans the change, and pushes it through the MCP server. Open FlutterFlow in your browser to verify. +### Concurrent Edits with Builder -#### 7. Move into the workspace and launch your agent +You can edit visually while an agent is working, but writes use **optimistic concurrency**: when the agent pushes, the server checks the project's last-modified timestamp against the agent's snapshot. If anyone else (you in the visual builder, a teammate, or another agent) modified the project in between, the push is rejected. The agent will re-read the latest state and retry — which may also mean re-planning, if your change conflicts with what it was about to do. -Move into the new workspace folder and start your preferred coding agent. This example uses Claude Code: +So nothing gets silently overwritten, but expect occasional retries when you and the agent are editing the same project at once. -```bash -cd mindfly -``` -and then... -```bash -claude -``` +## Branches and Rollback -#### 8. Approve the FlutterFlow AI MCP server +:::warning[Agents commit to main] +Workspaces always target the project's **main branch**. There's no flag to point them at a feature branch. Every successful push creates a commit on main, so for high-stakes projects, work on a clone, make sure version history is enabled, or coordinate with your team before letting an agent run. +::: -The first time the agent opens the workspace, it will detect the new MCP server and ask for permission: +To roll back, use FlutterFlow's project version history in the visual builder — the same mechanism you'd use for visual edits. Each agent push lands as a commit there with whatever commit message the agent supplied. -``` -New MCP server found in .mcp.json: flutterflow_ai +## Refreshing Stale Context -MCP servers may execute code or access system resources. -All tool calls require approval. +If you've made visual edits since the agent last read the project, the agent's local snapshot is stale. Two ways to fix it: -> 1. Use this and all future MCP servers in this project - 2. Use this MCP server - 3. Continue without using this MCP server -``` +- **Ask the agent to refresh.** Most agents call the MCP `refreshContext` tool on their own when they detect drift, but you can prompt explicitly: "refresh the project context." +- **Run it from the CLI.** `flutterflow ai context-check` reports whether the local snapshot is behind, and `flutterflow ai refresh-context ` pulls the latest. -Choose **option 1** to use the FlutterFlow AI MCP server (and any others added to this workspace later) without being asked again. Press **Enter** to confirm. +## Switching Projects -> **Why approve?** Without the MCP server, the agent can edit local files but can't actually push changes to your FlutterFlow project. With it approved, the agent has the same tools you'd run yourself from the CLI. -> +A workspace is bound to one project. To work on a different project, run `flutterflow ai init` in a **new** folder and link it to the new project ID. `init` refuses to run in a non-empty directory, so it won't re-bind an existing workspace. -#### 9. Describe your app in plain English +## Agent edit scope -Claude Code is now connected to your workspace and the FlutterFlow AI MCP server. Type what you want to build at the prompt: +**In scope** -``` -> create a minimalist meditation app -``` +- Pages, components, app state, theme, navigation, action blocks, app events +- Custom functions, actions, widgets, classes, and enums +- API endpoints, queries, custom data types and enums +- Pub and library dependencies, design tokens, GenUI catalog, Firebase Auth wiring + +**Out of scope** + +- A few DSL gaps that may close over time — shaders, and parameter types like `Document`, `SQLiteRow`, `WidgetBuilder`, `ChildSlotParam`, `ApiResponse`, `TimestampRange`, `GooglePlace`, `RevenueCat` types, `CustomCloudFunctionResponse`, and `ResponseStreamMessage`. +- Anything outside the FlutterFlow project itself — running the app, deploying it, creating Firebase projects, managing secrets, App Store submissions. + +## MCP server tools + +Once approved, the FlutterFlow AI MCP server gives your agent the following tools. + +**Core actions** -Press **Enter**. The agent will plan the app, generate the code, push it to FlutterFlow through the MCP server, and report back. +| Tool | What it does | +| --- | --- | +| `run` | Applies a planned set of changes to your FlutterFlow project. This is how edits get pushed. | +| `validate` | Dry-runs a change without pushing it, so the agent can catch errors before committing. | +| `inspect` | Reads project structure — either a whole-project summary or a scoped view. | +| `resources` | Lists reusable project and library resources (components, custom code, etc.). | +| `init` | Scaffolds a new FlutterFlow AI workspace. | -#### 10. Verify the app in the FlutterFlow visual builder -Open FlutterFlow in your browser and navigate to your project. You’ll see the generated app reflected in the visual builder. From here, you can continue refining the app visually or iterate further using the AI agent. +**Supporting** -### Modify Projects -To modify an existing project, [paste your project ID](#5-choose-new-app-or-edit-existing) when prompted instead of pressing Enter. This connects the workspace to your current FlutterFlow app. Once set up, you can use the AI agent to make changes, and updates will be pushed directly to the existing project. +`status`, `search`, `refreshContext`, `contextCheck`, `docs`, `history` — used by the agent for project metadata, searching, refreshing its context, looking up FlutterFlow documentation, and reviewing prior tool calls. +The agent calls these tools on your behalf based on your prompts. Every tool call is subject to your agent's approval rules. From 50723ee3e7f0034a73a9db7f7c24c1a34e3b5ef7 Mon Sep 17 00:00:00 2001 From: PoojaB26 Date: Tue, 28 Apr 2026 19:46:53 +0530 Subject: [PATCH 08/20] remove redundant info box and clarify workspace description --- .../advanced/flutterflow-cli/flutterflow-mcp.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md b/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md index 4b3cc5b6..3a85b4c6 100644 --- a/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md +++ b/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md @@ -13,11 +13,6 @@ The FlutterFlow CLI lets you create and edit FlutterFlow apps from the terminal A FlutterFlow project is the source of truth. The CLI is how you create or edit it from your local workspace. -:::info[Remember] -- **FF CLI is not a replacement for the visual builder.** FlutterFlow is still faster for most visual work. FF CLI is for precision, repeatability, and automation. -- **FF CLI doesn't execute your app.** It produces a FlutterFlow project, which you can test and run inside the FlutterFlow visual builder. -::: - ![ff-cli-ff-builder-using-same-ff-app.avif](../imgs/ff-cli-ff-builder-using-same-ff-app.avif) ## Architecture @@ -29,12 +24,17 @@ A FlutterFlow project is the source of truth. The CLI is how you create or edit 3. The MCP server applies those changes to your FlutterFlow project. 4. You verify the result in the FlutterFlow visual builder. -The workspace is just a folder on your disk. The actual project lives in FlutterFlow. +The workspace is just a folder on your disk. The actual project lives in FlutterFlow server. :::tip[What is MCP?] The [Model Context Protocol](https://modelcontextprotocol.io) is an open standard that lets AI agents call external tools. The FlutterFlow AI MCP server exposes FlutterFlow's project APIs to your agent so it can read and modify your project on your behalf. ::: +:::info[Remember] +- **FF CLI is not a replacement for the visual builder.** FlutterFlow is still faster for most visual work. FF CLI is for precision, repeatability, and automation. +- **FF CLI doesn't execute your app.** It produces a FlutterFlow project, which you can test and run inside the FlutterFlow visual builder. +::: + :::info[Prerequisites] Before you start, make sure you have: From f8b61c6a60543f7aa522a6fe74ef7a6b6f6f7967 Mon Sep 17 00:00:00 2001 From: PoojaB26 Date: Tue, 28 Apr 2026 19:48:27 +0530 Subject: [PATCH 09/20] Remove outdated DSL gaps --- docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md b/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md index 3a85b4c6..e2fb2472 100644 --- a/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md +++ b/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md @@ -190,7 +190,6 @@ A workspace is bound to one project. To work on a different project, run `flutte **Out of scope** -- A few DSL gaps that may close over time — shaders, and parameter types like `Document`, `SQLiteRow`, `WidgetBuilder`, `ChildSlotParam`, `ApiResponse`, `TimestampRange`, `GooglePlace`, `RevenueCat` types, `CustomCloudFunctionResponse`, and `ResponseStreamMessage`. - Anything outside the FlutterFlow project itself — running the app, deploying it, creating Firebase projects, managing secrets, App Store submissions. ## MCP server tools From 238669733bb1bd099098ea2a8c4511d626a72553 Mon Sep 17 00:00:00 2001 From: Pinkesh Date: Tue, 28 Apr 2026 22:58:16 +0530 Subject: [PATCH 10/20] address review comments --- .../advanced/flutterflow-cli/flutterflow-mcp.md | 14 +++++++------- .../ff-cli-ff-builder-using-same-ff-app.avif | Bin 25913 -> 0 bytes ...lutterflow-ff-builder-using-same-ff-app.avif | Bin 0 -> 30672 bytes 3 files changed, 7 insertions(+), 7 deletions(-) delete mode 100644 docs/ff-concepts/advanced/imgs/ff-cli-ff-builder-using-same-ff-app.avif create mode 100644 docs/ff-concepts/advanced/imgs/flutterflow-ff-builder-using-same-ff-app.avif diff --git a/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md b/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md index e2fb2472..e87d982c 100644 --- a/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md +++ b/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md @@ -13,7 +13,7 @@ The FlutterFlow CLI lets you create and edit FlutterFlow apps from the terminal A FlutterFlow project is the source of truth. The CLI is how you create or edit it from your local workspace. -![ff-cli-ff-builder-using-same-ff-app.avif](../imgs/ff-cli-ff-builder-using-same-ff-app.avif) +![flutterflow-cli-ff-builder-using-same-ff-app](../imgs/flutterflow-ff-builder-using-same-ff-app.avif) ## Architecture @@ -27,21 +27,21 @@ A FlutterFlow project is the source of truth. The CLI is how you create or edit The workspace is just a folder on your disk. The actual project lives in FlutterFlow server. :::tip[What is MCP?] -The [Model Context Protocol](https://modelcontextprotocol.io) is an open standard that lets AI agents call external tools. The FlutterFlow AI MCP server exposes FlutterFlow's project APIs to your agent so it can read and modify your project on your behalf. +The [**Model Context Protocol**](https://modelcontextprotocol.io) is an open standard that lets AI agents call external tools. The FlutterFlow AI MCP server exposes FlutterFlow's project APIs to your agent so it can read and modify your project on your behalf. ::: :::info[Remember] -- **FF CLI is not a replacement for the visual builder.** FlutterFlow is still faster for most visual work. FF CLI is for precision, repeatability, and automation. -- **FF CLI doesn't execute your app.** It produces a FlutterFlow project, which you can test and run inside the FlutterFlow visual builder. +- **FlutterFlow CLI is not a replacement for the visual builder.** FlutterFlow is still faster for most visual work. FlutterFlow CLI is for precision, repeatability, and automation. +- **FlutterFlow CLI doesn't execute your app.** It produces a FlutterFlow project, which you can test and run inside the FlutterFlow visual builder. ::: :::info[Prerequisites] Before you start, make sure you have: -- **FlutterFlow CLI installed.** See [Installation](./overview.md). -- **A FlutterFlow API key.** See [generating an API token](../../../accounts-billing/account-management.md#how-do-i-generate-an-api-token). -- **An MCP-compatible AI agent installed locally** — for example, [Claude Code](https://www.claude.com/product/claude-code), [Gemini CLI](https://github.com/google-gemini/gemini-cli), or [Codex](https://github.com/openai/codex). +- **FlutterFlow CLI installed.** See [**Installation**](./overview.md). +- **A FlutterFlow API key.** See [**generating an API token**](../../../accounts-billing/account-management.md#how-do-i-generate-an-api-token). +- **An MCP-compatible AI agent installed locally** — for example, [**Claude Code**](https://www.claude.com/product/claude-code), [**Gemini CLI**](https://github.com/google-gemini/gemini-cli), or [**Codex**](https://github.com/openai/codex). - **A FlutterFlow project ID** (only if you're editing an existing project). ::: diff --git a/docs/ff-concepts/advanced/imgs/ff-cli-ff-builder-using-same-ff-app.avif b/docs/ff-concepts/advanced/imgs/ff-cli-ff-builder-using-same-ff-app.avif deleted file mode 100644 index 7292aacf3ab07fdbf36dcf9178fe2c523843b350..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25913 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 literal 0 HcmV?d00001 From 90903cf64ce6ff152b24d13686891c9219506197 Mon Sep 17 00:00:00 2001 From: Pinkesh Date: Tue, 28 Apr 2026 23:20:06 +0530 Subject: [PATCH 11/20] Fix broken links --- docs/accounts-billing/account-management.md | 2 +- .../advanced/flutterflow-cli/flutterflow-mcp.md | 2 +- docs/ff-integrations/ads/admob.md | 2 +- docs/ff-integrations/firebase/app-check.md | 2 +- docs/ff-integrations/firebase/crashlytics.md | 2 +- docs/ff-integrations/payments/stripe.md | 2 +- docs/intro/ff-ui/toolbar.md | 2 +- docs/resources/projects/settings/general-settings.md | 4 ++-- .../exporting-code/push-to-github.md | 2 +- .../running-your-app/automated-tests.md | 2 +- .../running-your-app/local-run.md | 2 +- firebase.json | 10 ++++++++++ 12 files changed, 22 insertions(+), 12 deletions(-) diff --git a/docs/accounts-billing/account-management.md b/docs/accounts-billing/account-management.md index 4d80cb4d..d963b6e7 100644 --- a/docs/accounts-billing/account-management.md +++ b/docs/accounts-billing/account-management.md @@ -76,7 +76,7 @@ Now, you are ready to log in with your new email address and password. ![update-email.png](imgs/update-email.png) ### How do I generate an API Token? -An API token is required to use the [CLI](../ff-concepts/advanced/ff-cli.md) and the [Visual Studio Code Extension](../ff-concepts/adding-customization/vscode-extension.md) +An API token is required to use the [CLI](../ff-concepts/advanced/flutterflow-cli/overview.md) and the [Visual Studio Code Extension](../ff-concepts/adding-customization/vscode-extension.md) . To create an API token tied to your account: diff --git a/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md b/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md index e87d982c..8342fd52 100644 --- a/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md +++ b/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md @@ -144,7 +144,7 @@ From that point on, the same rules apply as when [editing an existing project](# Have your **project ID** ready. Open the project in the FlutterFlow editor. The project ID is the path segment after `/project/` in the URL. ::: -Editing an existing project follows the same flow as [creating a new one](#set-up-a-workspace) — you run `flutterflow ai init` to scaffold a workspace, then drive changes from your agent. The only difference is one step in the wizard: when it asks **Link to an existing FlutterFlow project?**, answer `y` and paste your project ID: +Editing an existing project follows the same flow as [creating a new one](#setup-workspace) — you run `flutterflow ai init` to scaffold a workspace, then drive changes from your agent. The only difference is one step in the wizard: when it asks **Link to an existing FlutterFlow project?**, answer `y` and paste your project ID: ```dart Link to an existing FlutterFlow project? [y/N] y diff --git a/docs/ff-integrations/ads/admob.md b/docs/ff-integrations/ads/admob.md index a2cee83e..988376a7 100644 --- a/docs/ff-integrations/ads/admob.md +++ b/docs/ff-integrations/ads/admob.md @@ -159,7 +159,7 @@ While building your app, clicking on too many ads may cause your AdMob account t ### Testing AdBanner -Ads cannot be tested in Test or Run Mode. They can only be tested on a real device or emulator. To do this, you can use [Local run](../../testing-deployment-publishing/running-your-app/local-run.md) or [download the code](../../ff-concepts/advanced/ff-cli.md#download-projects) and run it in your IDE. +Ads cannot be tested in Test or Run Mode. They can only be tested on a real device or emulator. To do this, you can use [Local run](../../testing-deployment-publishing/running-your-app/local-run.md) or [download the code](../../ff-concepts/advanced/flutterflow-cli/exporting-projects.md) and run it in your IDE. ## Interstitial Ad diff --git a/docs/ff-integrations/firebase/app-check.md b/docs/ff-integrations/firebase/app-check.md index 1c7e753e..6010f6ef 100644 --- a/docs/ff-integrations/firebase/app-check.md +++ b/docs/ff-integrations/firebase/app-check.md @@ -180,7 +180,7 @@ To add *Firebase App Check* to your app: 5. You might want to see if it works on a real device or an emulator. To run on a real device, you can set the **Android Provider** to **Play Integrity** and to run on an emulator, set it to **Debug,** and then try checking it by downloading the APK. 1. If it doesn't work for *Play Integrity*, ensure you have enabled the Play Integrity API. See how to do it in step 2 [here](https://firebase.google.com/docs/app-check/android/play-integrity-provider?authuser=1&hl=en#project-setup). - 2. If it doesn't work for *Debug*, you can try [downloading the code](../../ff-concepts/advanced/ff-cli.md#download-projects), following the instructions [here](https://firebase.google.com/docs/app-check/flutter/debug-provider#android), and running it locally. + 2. If it doesn't work for *Debug*, you can try [downloading the code](../../ff-concepts/advanced/flutterflow-cli/exporting-projects.md), following the instructions [here](https://firebase.google.com/docs/app-check/flutter/debug-provider#android), and running it locally. :::tip To add the App Check on the app with the non-Firebase (i.e., your self-hosted) backend, follow the instructions [**here**](https://firebase.google.com/docs/app-check/flutter/custom-resource). diff --git a/docs/ff-integrations/firebase/crashlytics.md b/docs/ff-integrations/firebase/crashlytics.md index 751adae2..9da8caf0 100644 --- a/docs/ff-integrations/firebase/crashlytics.md +++ b/docs/ff-integrations/firebase/crashlytics.md @@ -19,6 +19,6 @@ You can see all the logged errors/crashes inside the Crashlytics dashboard of yo ![Crashlytics dashboard](imgs/crashlytics-dashboard.avif) 1. Click on the issue name to see its details. -2. To test the crash on your app, [download the app](../../ff-concepts/advanced/ff-cli.md#download-projects), add a code that throws an error, and run it on a mobile device or emulator with an active internet connection. +2. To test the crash on your app, [download the app](../../ff-concepts/advanced/flutterflow-cli/exporting-projects.md), add a code that throws an error, and run it on a mobile device or emulator with an active internet connection. ![Test crash](imgs/test-crash.avif) \ No newline at end of file diff --git a/docs/ff-integrations/payments/stripe.md b/docs/ff-integrations/payments/stripe.md index 871972b8..05ad0255 100644 --- a/docs/ff-integrations/payments/stripe.md +++ b/docs/ff-integrations/payments/stripe.md @@ -241,7 +241,7 @@ You can test Stripe payments on mobile and the Web before deployment. To do that 1. Go to the FlutterFlow project and navigate to **Settings and Integrations** > **In App Purchases & Subscriptions** > **Stripe**. 2. Make sure the **Is Production** is disabled. 3. Make sure you have entered the correct **Test Credentials,** such as **Publishable Key** and **Secret Key**. -4. [Download](../../ff-concepts/advanced/ff-cli.md#download-projects) and [run](../../testing-deployment-publishing/running-your-app/run-your-app.md) your project.. +4. [Download](../../ff-concepts/advanced/flutterflow-cli/exporting-projects.md) and [run](../../testing-deployment-publishing/running-your-app/run-your-app.md) your project.. 5. To test the purchase, you can use any of these [basic test card numbers](https://stripe.com/docs/testing#cards). ### 5. Releasing to Production diff --git a/docs/intro/ff-ui/toolbar.md b/docs/intro/ff-ui/toolbar.md index ea91376a..78028992 100644 --- a/docs/intro/ff-ui/toolbar.md +++ b/docs/intro/ff-ui/toolbar.md @@ -102,7 +102,7 @@ The Developer Menu provides developers with access to tools such as code viewing 4. **Download APK**: Use this to generate a release build of your Android app. It will automatically download the `.apk` file after the building process is complete. -5. **FlutterFlow CLI**: You can also download the code using *[FlutterFlow CLI](https://pub.dev/packages/flutterflow_cli)*. See instructions [here](../../ff-concepts/advanced/ff-cli.md#download-projects). +5. **FlutterFlow CLI**: You can also download the code using *[FlutterFlow CLI](https://pub.dev/packages/flutterflow_cli)*. See instructions [here](../../ff-concepts/advanced/flutterflow-cli/exporting-projects.md). :::note _Connect GitHub Repo_, _Download Code_, and _Download APK_ features requires a [**paid plan**](https://flutterflow.io/pricing). diff --git a/docs/resources/projects/settings/general-settings.md b/docs/resources/projects/settings/general-settings.md index 4c45d307..e4367d24 100644 --- a/docs/resources/projects/settings/general-settings.md +++ b/docs/resources/projects/settings/general-settings.md @@ -132,7 +132,7 @@ To add the app launcher icon: 2. Under the **General** section, select **App Assets**. 3. Under the **Launcher Icon** section, click on the **Upload Image** button. 4. By clicking on the **Unset** dropdown menu, you can also select from the already uploaded images to the Project Media/Assets. -5. [Download the project](../../../ff-concepts/advanced/ff-cli.md#download-projects) and run the following command in your terminal to generate the launcher icon: +5. [Download the project](../../../ff-concepts/advanced/flutterflow-cli/exporting-projects.md) and run the following command in your terminal to generate the launcher icon: `flutter pub run flutter_launcher_icons:main` @@ -151,7 +151,7 @@ Here are the steps to add adaptive icons: 2. Return to FlutterFlow and navigate to **Setting and Integrations > General** > **App Assets > Android Adaptive Icon.** 1. Upload the **Foreground Icon**. If you use the online tool, you'll find it inside the `IconKitchen-Output > android > res > mipmap-xxxhdpi > ic_launcher_foreground.png`. 2. For **Background Type**, you can either set the **Color** or **Image**. It's recommended to use a color that aligns with your app's branding for a cohesive look. -3. [Download the project](../../../ff-concepts/advanced/ff-cli.md#download-projects) and run the following command in your terminal to generate the launcher icon: +3. [Download the project](../../../ff-concepts/advanced/flutterflow-cli/exporting-projects.md) and run the following command in your terminal to generate the launcher icon: `flutter pub run flutter_launcher_icons:main` diff --git a/docs/testing-deployment-publishing/exporting-code/push-to-github.md b/docs/testing-deployment-publishing/exporting-code/push-to-github.md index 9ae3af48..5f5b5bc4 100644 --- a/docs/testing-deployment-publishing/exporting-code/push-to-github.md +++ b/docs/testing-deployment-publishing/exporting-code/push-to-github.md @@ -152,5 +152,5 @@ After testing the changes in `develop`: 2. Once reviewed and merged, deploy your application from the `main` branch using FlutterFlow’s deployment features. :::tip -Also, see how you can download the code using [**FlutterFlow CLI**](ff-cli) and [**Local Run**](../running-your-app/local-run.md). +Also, see how you can download the code using [**FlutterFlow CLI**](../../ff-concepts/advanced/flutterflow-cli/overview.md) and [**Local Run**](../running-your-app/local-run.md). ::: \ No newline at end of file diff --git a/docs/testing-deployment-publishing/running-your-app/automated-tests.md b/docs/testing-deployment-publishing/running-your-app/automated-tests.md index c54395f9..ce4813a7 100644 --- a/docs/testing-deployment-publishing/running-your-app/automated-tests.md +++ b/docs/testing-deployment-publishing/running-your-app/automated-tests.md @@ -164,7 +164,7 @@ You can run tests on local devices or use the services like [Firebase Test Lab]( To run the tests locally: -1. [Download the project code](../../ff-concepts/advanced/ff-cli.md#download-projects). +1. [Download the project code](../../ff-concepts/advanced/flutterflow-cli/exporting-projects.md). 2. Go to `your_project/integration_test/test.dart`. 3. To run a specific test, click the play button next to it. To execute all tests at once, double-click the play button next to `void main`. 4. Alternatively, you can use the terminal and enter the command: `flutter test integration_test/test.dart`." diff --git a/docs/testing-deployment-publishing/running-your-app/local-run.md b/docs/testing-deployment-publishing/running-your-app/local-run.md index c8af301e..46e59307 100644 --- a/docs/testing-deployment-publishing/running-your-app/local-run.md +++ b/docs/testing-deployment-publishing/running-your-app/local-run.md @@ -212,7 +212,7 @@ Here’s how you do it: To download your app code, you have two options: -- Use the [FlutterFlow CLI](../../ff-concepts/advanced/ff-cli.md#download-projects). (Recommended) +- Use the [FlutterFlow CLI](../../ff-concepts/advanced/flutterflow-cli/exporting-projects.md). (Recommended) - Alternatively, from the **Toolbar**, click on the **Developer Menu** > **Download Code**. This will download the *.zip* file. Extract the *.zip* file to view the contents of the project. ### 2. Setup Flutter SDK diff --git a/firebase.json b/firebase.json index 6b362e43..268c7c27 100644 --- a/firebase.json +++ b/firebase.json @@ -2447,6 +2447,16 @@ "source": "/resources/projects/settings/mcp-server", "destination": "/", "type": 301 + }, + { + "source": "/exporting/ff-cli", + "destination": "/flutterflow-cli", + "type": 301 + }, + { + "source": "/exporting/ff-cli#usage", + "destination": "/flutterflow-cli/exporting", + "type": 301 } ] } From 16459b3ba395596e109a2d7493e7f4eb09cf604d Mon Sep 17 00:00:00 2001 From: Pinkesh Date: Wed, 29 Apr 2026 09:40:52 +0530 Subject: [PATCH 12/20] nit fixes --- docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md b/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md index 8342fd52..24a2aef8 100644 --- a/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md +++ b/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md @@ -179,7 +179,7 @@ If you've made visual edits since the agent last read the project, the agent's l A workspace is bound to one project. To work on a different project, run `flutterflow ai init` in a **new** folder and link it to the new project ID. `init` refuses to run in a non-empty directory, so it won't re-bind an existing workspace. -## Agent edit scope +## Agent Edit Scope **In scope** @@ -192,7 +192,7 @@ A workspace is bound to one project. To work on a different project, run `flutte - Anything outside the FlutterFlow project itself — running the app, deploying it, creating Firebase projects, managing secrets, App Store submissions. -## MCP server tools +## MCP Server Tools Once approved, the FlutterFlow AI MCP server gives your agent the following tools. From 8fd957ba8df6d501e14d3a0b1206860845065ae7 Mon Sep 17 00:00:00 2001 From: PoojaB26 Date: Wed, 29 Apr 2026 09:43:51 +0530 Subject: [PATCH 13/20] reorganize sections on agent edit scope, branches, and rollback, and clarify project switching process. --- .../flutterflow-cli/flutterflow-mcp.md | 44 ++++++++++--------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md b/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md index 24a2aef8..a0a6014d 100644 --- a/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md +++ b/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md @@ -160,39 +160,43 @@ You can edit visually while an agent is working, but writes use **optimistic con So nothing gets silently overwritten, but expect occasional retries when you and the agent are editing the same project at once. -## Branches and Rollback -:::warning[Agents commit to main] -Workspaces always target the project's **main branch**. There's no flag to point them at a feature branch. Every successful push creates a commit on main, so for high-stakes projects, work on a clone, make sure version history is enabled, or coordinate with your team before letting an agent run. -::: +### Agent Edit Scope -To roll back, use FlutterFlow's project version history in the visual builder — the same mechanism you'd use for visual edits. Each agent push lands as a commit there with whatever commit message the agent supplied. +**In scope** + +- Pages, components, app state, theme, navigation, action blocks, app events +- Custom functions, actions, widgets, classes, and enums +- API endpoints, queries, custom data types and enums +- Pub and library dependencies, design tokens, GenUI catalog, Firebase Auth wiring -## Refreshing Stale Context +**Out of scope** + +- Anything outside the FlutterFlow project itself — running the app, deploying it, creating Firebase projects, managing secrets, App Store submissions. + +## MCP Server Tools + +### Refreshing Stale Context If you've made visual edits since the agent last read the project, the agent's local snapshot is stale. Two ways to fix it: - **Ask the agent to refresh.** Most agents call the MCP `refreshContext` tool on their own when they detect drift, but you can prompt explicitly: "refresh the project context." - **Run it from the CLI.** `flutterflow ai context-check` reports whether the local snapshot is behind, and `flutterflow ai refresh-context ` pulls the latest. -## Switching Projects +## Branches and Rollback -A workspace is bound to one project. To work on a different project, run `flutterflow ai init` in a **new** folder and link it to the new project ID. `init` refuses to run in a non-empty directory, so it won't re-bind an existing workspace. +:::warning[Agents commit to main] +Workspaces always target the project's **main branch**. There's no flag to point them at a feature branch. Every successful push creates a commit on main, so for high-stakes projects, work on a clone, make sure version history is enabled, or coordinate with your team before letting an agent run. +::: -## Agent Edit Scope +To roll back, use FlutterFlow's project version history in the visual builder — the same mechanism you'd use for visual edits. Each agent push lands as a commit there with whatever commit message the agent supplied. -**In scope** -- Pages, components, app state, theme, navigation, action blocks, app events -- Custom functions, actions, widgets, classes, and enums -- API endpoints, queries, custom data types and enums -- Pub and library dependencies, design tokens, GenUI catalog, Firebase Auth wiring - -**Out of scope** +## Switching Projects -- Anything outside the FlutterFlow project itself — running the app, deploying it, creating Firebase projects, managing secrets, App Store submissions. +A workspace is bound to one project. To work on a different project, run `flutterflow ai init` in a **new** folder and link it to the new project ID. `init` refuses to run in a non-empty directory, so it won't re-bind an existing workspace. -## MCP Server Tools +## MCP server tools Once approved, the FlutterFlow AI MCP server gives your agent the following tools. @@ -202,12 +206,12 @@ Once approved, the FlutterFlow AI MCP server gives your agent the following tool | --- | --- | | `run` | Applies a planned set of changes to your FlutterFlow project. This is how edits get pushed. | | `validate` | Dry-runs a change without pushing it, so the agent can catch errors before committing. | -| `inspect` | Reads project structure — either a whole-project summary or a scoped view. | +| `inspect` | Reads project structure either a whole-project summary or a scoped view. | | `resources` | Lists reusable project and library resources (components, custom code, etc.). | | `init` | Scaffolds a new FlutterFlow AI workspace. | **Supporting** -`status`, `search`, `refreshContext`, `contextCheck`, `docs`, `history` — used by the agent for project metadata, searching, refreshing its context, looking up FlutterFlow documentation, and reviewing prior tool calls. +`status`, `search`, `refreshContext`, `contextCheck`, `docs`, `history` used by the agent for project metadata, searching, refreshing its context, looking up FlutterFlow documentation, and reviewing prior tool calls. The agent calls these tools on your behalf based on your prompts. Every tool call is subject to your agent's approval rules. From b5b012d9868e29da83fe322ca0fea10d17e03310 Mon Sep 17 00:00:00 2001 From: PoojaB26 Date: Wed, 29 Apr 2026 09:44:21 +0530 Subject: [PATCH 14/20] Add Makefile for staging deployment and update README with usage instructions --- Makefile | 35 +++++++++++++++++++++++++++++++++++ README.md | 15 +++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 Makefile diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..c0e64382 --- /dev/null +++ b/Makefile @@ -0,0 +1,35 @@ +# Usage: +# make staging # channel = current git branch, expires in 7d +# make staging CHANNEL=my-channel # custom channel name +# make staging CHANNEL=my-channel EXPIRES=14d +# make build # just build the site +# make deploy-staging # deploy without rebuilding + +SHELL := /usr/bin/env bash +.SHELLFLAGS := -eu -o pipefail -c + +BRANCH := $(shell git rev-parse --abbrev-ref HEAD) +CHANNEL ?= $(BRANCH) +EXPIRES ?= 7d + +# Firebase channel IDs must match [a-zA-Z0-9_-] +SAFE_CHANNEL := $(shell echo "$(CHANNEL)" | tr '/' '-' | tr -c 'a-zA-Z0-9_-' '-' | sed 's/-\+/-/g; s/^-//; s/-$$//') + +.PHONY: staging build deploy-staging check-firebase + +staging: build deploy-staging + +build: + npm run build + +deploy-staging: check-firebase + @echo "Branch: $(BRANCH)" + @echo "Channel: $(SAFE_CHANNEL)" + @echo "Expires: $(EXPIRES)" + firebase hosting:channel:deploy "$(SAFE_CHANNEL)" --expires "$(EXPIRES)" + +check-firebase: + @command -v firebase >/dev/null 2>&1 || { \ + echo "firebase CLI not found. Install with: npm install -g firebase-tools" >&2; \ + exit 1; \ + } diff --git a/README.md b/README.md index 9f1b7836..196c1549 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,21 @@ You may want to run the docs site locally to test and visualize changes you are 1. **Install Dependencies:** Run **`npm install`** in your terminal to install the necessary dependencies. 2. **Preview Changes:** To see your changes in real-time as you edit the files, you can run a local development server. This server will host your website and reflect the latest changes. Use the command **`npm run start`**. +## Deploying a Staging Preview +To share your branch with reviewers before merging, deploy it to a Firebase Hosting preview channel. This builds the site and publishes it to a temporary URL (defaults to a 7-day expiry). + +```bash +make staging # channel name = current git branch +make staging CHANNEL=my-channel # custom channel name +make staging CHANNEL=my-channel EXPIRES=14d +``` + +Other targets: +- `make build` — build the site only +- `make deploy-staging` — deploy without rebuilding + +Requires the Firebase CLI (`npm install -g firebase-tools`) and access to the `flutterflow-docs-82026` Firebase project. + ## Ready to Contribute? Your contributions are vital to keeping FlutterFlow's documentation clear, up-to-date, and helpful. We look forward to seeing your pull requests and are excited to welcome you into our community of contributors! From 902461af9eaefca0cd9612f234de586023331f95 Mon Sep 17 00:00:00 2001 From: Pinkesh Date: Wed, 29 Apr 2026 12:28:36 +0530 Subject: [PATCH 15/20] added visuals --- .../flutterflow-cli/flutterflow-mcp.md | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md b/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md index a0a6014d..bcbbd36c 100644 --- a/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md +++ b/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md @@ -93,6 +93,32 @@ When the wizard finishes, you'll have a workspace folder ready for your agent. D Each file points the corresponding agent at the FlutterFlow AI MCP server. +
+ +
+

+ ## Launch your Agent Move into the workspace and start your agent. The example below uses Claude Code; the same pattern applies to any agent you registered in the wizard — `cd` into the workspace and launch the agent's CLI. @@ -119,6 +145,32 @@ Choose **option 1** to approve the FlutterFlow AI MCP server (and any others add > **Why approve?** Without the MCP server, the agent can edit local files but can't push changes to your FlutterFlow project. With it approved, the agent has the same tools you'd run yourself from the CLI. +
+ +
+

+ ## Generate a New App With the agent connected, describe the app you want at the prompt: @@ -138,6 +190,32 @@ Let me check the workspace and read the edit template. From that point on, the same rules apply as when [editing an existing project](#edit-an-existing-project) - concurrency, branches, scope, and refreshing context. +
+ +
+

+ ## Edit an Existing Project :::info[Prerequisite] @@ -154,6 +232,33 @@ Project ID The workspace is now bound to that project. `cd` into the workspace folder, [launch your agent](#launch-your-agent), and describe the changes you want — "add a profile screen", "switch the primary color to teal", "wire up the login form to Firebase Auth". The agent reads the current project, plans the change, and pushes it through the MCP server. Open FlutterFlow in your browser to verify. + +
+ +
+

+ ### Concurrent Edits with Builder You can edit visually while an agent is working, but writes use **optimistic concurrency**: when the agent pushes, the server checks the project's last-modified timestamp against the agent's snapshot. If anyone else (you in the visual builder, a teammate, or another agent) modified the project in between, the push is rejected. The agent will re-read the latest state and retry — which may also mean re-planning, if your change conflicts with what it was about to do. From c60a29d2163648968f364150f122b9bb770257bc Mon Sep 17 00:00:00 2001 From: Pinkesh Date: Wed, 29 Apr 2026 12:33:14 +0530 Subject: [PATCH 16/20] nit fix --- docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md b/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md index bcbbd36c..c77137c9 100644 --- a/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md +++ b/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md @@ -227,7 +227,7 @@ Editing an existing project follows the same flow as [creating a new one](#setup ```dart Link to an existing FlutterFlow project? [y/N] y Project ID -> my-meditation-app-x7k2p9 +> mindfly-c9lbgr ``` The workspace is now bound to that project. `cd` into the workspace folder, [launch your agent](#launch-your-agent), and describe the changes you want — "add a profile screen", "switch the primary color to teal", "wire up the login form to Firebase Auth". The agent reads the current project, plans the change, and pushes it through the MCP server. Open FlutterFlow in your browser to verify. From 91365ec1602b86f5a48a06d5583d03860a4800dd Mon Sep 17 00:00:00 2001 From: PoojaB26 Date: Wed, 29 Apr 2026 14:58:57 +0530 Subject: [PATCH 17/20] reorganizing MCP server tools into categories --- .../flutterflow-cli/flutterflow-mcp.md | 46 +++++++++++-------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md b/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md index c77137c9..76efddc4 100644 --- a/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md +++ b/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md @@ -9,7 +9,7 @@ keywords: [CLI, Agentic AI, Projects, Local Management, MCP] # Build with AI Agents -The FlutterFlow CLI lets you create and edit FlutterFlow apps from the terminal using your own AI coding agent — Claude Code, Gemini CLI, Codex, or any MCP-compatible client. You describe what you want in plain English, the agent plans and applies the changes, and the result lands as a real FlutterFlow project you can open in the visual builder. +The [FlutterFlow CLI](https://pub.dev/packages/flutterflow_cli) lets you create and edit FlutterFlow apps from the terminal using your own AI coding agent — Claude Code, Gemini CLI, Codex, or any MCP-compatible client. You describe what you want in plain English, the agent plans and applies the changes, and the result lands as a real FlutterFlow project you can open in the visual builder. A FlutterFlow project is the source of truth. The CLI is how you create or edit it from your local workspace. @@ -301,22 +301,28 @@ To roll back, use FlutterFlow's project version history in the visual builder A workspace is bound to one project. To work on a different project, run `flutterflow ai init` in a **new** folder and link it to the new project ID. `init` refuses to run in a non-empty directory, so it won't re-bind an existing workspace. -## MCP server tools - -Once approved, the FlutterFlow AI MCP server gives your agent the following tools. - -**Core actions** - -| Tool | What it does | -| --- | --- | -| `run` | Applies a planned set of changes to your FlutterFlow project. This is how edits get pushed. | -| `validate` | Dry-runs a change without pushing it, so the agent can catch errors before committing. | -| `inspect` | Reads project structure either a whole-project summary or a scoped view. | -| `resources` | Lists reusable project and library resources (components, custom code, etc.). | -| `init` | Scaffolds a new FlutterFlow AI workspace. | - -**Supporting** - -`status`, `search`, `refreshContext`, `contextCheck`, `docs`, `history` used by the agent for project metadata, searching, refreshing its context, looking up FlutterFlow documentation, and reviewing prior tool calls. - -The agent calls these tools on your behalf based on your prompts. Every tool call is subject to your agent's approval rules. +## MCP tools + +Run these from inside a FlutterFlow AI workspace. Your agent calls them via the MCP server; you can also run them directly in the terminal. + +| Category | Command | What it does | +| --- | --- | --- | +| **Build** | `run` | Apply changes to your FlutterFlow project. | +| | `validate` | Dry-run a change without pushing it. | +| **Explore** | `inspect` | Whole-project summary or a scoped view of structure. | +| | `resources` | List reusable project and library resources. | +| | `search` | Search the project for a name or identifier. | +| | `status` | Show workspace and project state. | +| **AI integration** | `mcp` | Register the FlutterFlow MCP server with Claude Code, Codex, Gemini CLI, Cursor, Copilot, and other MCP-aware clients. | +| **Plan & audit** | `plan` | Capture intent before a run. | +| | `trace` | Replay a prior run. | +| | `history` | List prior commands and outcomes. | +| **Diagnose** | `doctor` | Check for common workspace problems. | +| | `context-check` | Report whether the local snapshot is behind the live project. | +| | `precache` | Pre-load project context. | +| **Stay current** | `upgrade` | Update the FlutterFlow CLI tooling. | +| | `refresh-workspace` | Refresh the workspace's local config. | +| | `refresh-context` | Pull the latest project state into the local snapshot. | +| **Learn** | `docs [topic]` | Open FlutterFlow AI documentation for a topic. | + +Run `flutterflow ai --help` from inside a workspace for the full command list and per-command flags. When the agent invokes a command via MCP, every call is subject to your agent's approval rules. From 593d0726040791a28957d37b80d76623251f23e3 Mon Sep 17 00:00:00 2001 From: PoojaB26 Date: Wed, 29 Apr 2026 14:59:09 +0530 Subject: [PATCH 18/20] Update Google Analytics configuration to conditionally set tracking ID based on environment --- docusaurus.config.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docusaurus.config.ts b/docusaurus.config.ts index 104780f6..4feec30f 100644 --- a/docusaurus.config.ts +++ b/docusaurus.config.ts @@ -45,10 +45,10 @@ const config: Config = { // blogSidebarTitle: 'FlutterFlow Blog', // blogSidebarCount: 'ALL' // }, - gtag: { + gtag: process.env.NODE_ENV === 'production' ? { trackingID: 'G-LC4SC6JY70', anonymizeIP: true, - }, + } : undefined, theme: { customCss: './src/css/custom.css', }, From 06aa04b29ff719c2f8bb39cd069a051d113a71e0 Mon Sep 17 00:00:00 2001 From: PoojaB26 Date: Wed, 29 Apr 2026 14:59:54 +0530 Subject: [PATCH 19/20] nit fix --- docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md b/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md index 76efddc4..90ca4811 100644 --- a/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md +++ b/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md @@ -30,7 +30,7 @@ The workspace is just a folder on your disk. The actual project lives in Flutter The [**Model Context Protocol**](https://modelcontextprotocol.io) is an open standard that lets AI agents call external tools. The FlutterFlow AI MCP server exposes FlutterFlow's project APIs to your agent so it can read and modify your project on your behalf. ::: -:::info[Remember] +:::note[Remember] - **FlutterFlow CLI is not a replacement for the visual builder.** FlutterFlow is still faster for most visual work. FlutterFlow CLI is for precision, repeatability, and automation. - **FlutterFlow CLI doesn't execute your app.** It produces a FlutterFlow project, which you can test and run inside the FlutterFlow visual builder. ::: From 10911315f4206f876792f5ff2fe23cdb9bff9b36 Mon Sep 17 00:00:00 2001 From: PoojaB26 Date: Wed, 29 Apr 2026 15:03:22 +0530 Subject: [PATCH 20/20] [bugfix] wrong step name for existing project id --- .../advanced/flutterflow-cli/flutterflow-mcp.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md b/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md index 90ca4811..f3c639d4 100644 --- a/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md +++ b/docs/ff-concepts/advanced/flutterflow-cli/flutterflow-mcp.md @@ -62,9 +62,10 @@ This launches an interactive setup wizard. Walk through the prompts: > mindfly ``` 2. **Environment.** Use ↑ / ↓ to highlight the FlutterFlow environment you want this workspace to target, then press **Enter**. -3. **Link to an existing FlutterFlow project?** Press **Enter** (default `N`) to create a new app. Answer `y` to bind the workspace to an existing project — the wizard will then ask for the project ID. +3. **Existing project ID.** Press **Enter** with no input to create a new app, or paste an existing project ID to bind the workspace to it. ``` - Link to an existing FlutterFlow project? [y/N] + Existing project ID to edit (press Enter to create a new app) + > ``` 4. **FlutterFlow API key.** Paste your API key and press **Enter**. Input is masked. 5. **Register MCP server with detected coding CLIs.** The wizard scans your `PATH` and offers to register the FlutterFlow AI MCP server with each agent it finds (Claude Code, Gemini CLI, Codex). Answer `Y` (default) for each one you plan to use. @@ -222,11 +223,10 @@ From that point on, the same rules apply as when [editing an existing project](# Have your **project ID** ready. Open the project in the FlutterFlow editor. The project ID is the path segment after `/project/` in the URL. ::: -Editing an existing project follows the same flow as [creating a new one](#setup-workspace) — you run `flutterflow ai init` to scaffold a workspace, then drive changes from your agent. The only difference is one step in the wizard: when it asks **Link to an existing FlutterFlow project?**, answer `y` and paste your project ID: +Editing an existing project follows the same flow as [creating a new one](#setup-workspace) — you run `flutterflow ai init` to scaffold a workspace, then drive changes from your agent. The only difference is one step in the wizard: when it asks for an **existing project ID**, paste yours instead of pressing Enter: -```dart -Link to an existing FlutterFlow project? [y/N] y -Project ID +``` +Existing project ID to edit (press Enter to create a new app) > mindfly-c9lbgr ```