Skip to content

Commit cb315ab

Browse files
committed
flutterflow: exact-once CLI, direct MCP launch
Make CLI invocations exact-once and launch MCP servers directly. Set FF_AI_AGENT_CLIENT default to codex, remove the exit-254 retry/re-run in flutterflow-cli.sh to avoid accidentally re-executing state-mutating commands, and add a test for that behavior. Change the MCP launcher to run the workspace's vendored server with `dart run` (and update mcp.example.json) to prevent pub/shim status text from contaminating JSON-RPC stdout; add a test for the helper. Update CI to run all helper-script tests and JSON validation. Bump plugin metadata and update README, SKILL.md, and CHANGELOG to document workspace-scoped MCP, exact-once execution, attribution, and revised onboarding/auth guidance.
1 parent f431abf commit cb315ab

10 files changed

Lines changed: 439 additions & 198 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,12 @@ jobs:
2020
sh -n "$f"
2121
done
2222
23-
- name: Run clipboard hand-off tests
24-
run: bash plugins/flutterflow/scripts/store-key-from-clipboard.test.sh
23+
- name: Run helper-script tests
24+
run: |
25+
for f in plugins/flutterflow/scripts/*.test.sh; do
26+
echo "test: $f"
27+
bash "$f"
28+
done
2529
2630
- name: Validate JSON configs
2731
run: |

‎CHANGELOG.md‎

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,21 @@ The base version follows [semantic versioning](https://semver.org). The
1414
fall-through path, so setting `FLUTTERFLOW_CLI_DIR` without a usable Dart
1515
toolchain correctly falls back to the globally installed `flutterflow` binary
1616
(and prints the intended diagnostics on total failure).
17-
- `flutterflow-cli.sh`: the exit-254 retry now fires only when the package config
18-
pre-existed (a genuine stale-config case), so a command — including a
19-
state-mutating one — is never silently re-run after an application-level error.
20-
- `flutterflow-mcp.sh`: the helper is now invoked via `sh`, so a distribution that
21-
dropped the executable bit no longer fails with an opaque "Permission denied".
22-
- `SKILL.md`: aligned the create/edit flow with the FlutterFlow CLI's own
23-
guidance — iterate on `run` (which validates internally and only pushes on
24-
success) instead of always running `validate` first, and use the documented
25-
`--project-name`/`--commit-message` create form with `--find-or-create` reserved
26-
for recovery.
17+
- `flutterflow-cli.sh`: removed the post-execution exit-254 retry. Every CLI
18+
command now runs exactly once, so an application or network failure cannot
19+
silently repeat a state-mutating operation.
20+
- `flutterflow-mcp.sh` and `mcp.example.json`: launch the workspace's vendored
21+
MCP server directly with Dart, preventing pub/shim output from corrupting
22+
JSON-RPC stdout.
23+
- Auth guidance now distinguishes machine-level onboarding credentials from the
24+
initialized workspace's private `.flutterflow/.env`.
25+
- `SKILL.md`: documents the real `run` failure boundary—validation failures do
26+
not push, while later create, conflict, network, push, and post-push failures
27+
can have remote side effects.
2728
- Credential guidance (`SKILL.md`, `README.md`): note that an inline
2829
`FF_API_KEY=<key> ...` prefix still lands in shell history and the process
2930
environment, and that `--api-key` persists the key to both
30-
`~/.flutterflow/credentials.json` and the workspace `.env`.
31-
- `mcp.example.json`: use an absolute command path and an explicit
32-
`FLUTTERFLOW_AI_WORKSPACE` instead of a relative command/cwd that resolved
33-
against the host's working directory.
31+
`~/.flutterflow/credentials.json` and `.flutterflow/.env`.
3432
- `plugin.json`: corrected the license identifier to the SPDX id `BUSL-1.1`.
3533
- `README.md`: documented GitHub marketplace installation as the primary path,
3634
with local `marketplace add .` reserved for repo-root development installs.
@@ -40,12 +38,20 @@ The base version follows [semantic versioning](https://semver.org). The
4038

4139
### Added
4240

41+
- CLI 0.0.38 onboarding guidance: bare `flutterflow ai` for the interactive
42+
project picker, and `init ... --yes` for deterministic agent automation.
43+
- Version-matched workflow guidance: read generated `AGENTS.md`, inspect the
44+
typed project SDK, use generated Flutter code as read-only runtime truth,
45+
confirm branch state, and run `flutterflow ai test` before pushes.
46+
- Codex attribution for direct CLI calls via `FF_AI_AGENT_CLIENT`, while
47+
preserving explicit caller overrides.
48+
- Exact-once CLI and direct MCP-launch regression tests.
4349
- `store-key-from-clipboard.sh`: secure one-shot FlutterFlow API-key hand-off
4450
from the OS clipboard to `~/.config/flutterflow/codex-env.sh`, with validation,
4551
symlink protections, live clipboard clearing, and leak-freedom tests.
4652
- `SKILL.md` and `README.md`: documented the no-chat clipboard flow, fixed retry
4753
wording, unavailable fallback, and hard rules against bare clipboard reads.
48-
- `.github/workflows/ci.yml`: shellcheck, POSIX syntax check, clipboard hand-off
54+
- `.github/workflows/ci.yml`: shellcheck, POSIX syntax checks, all helper-script
4955
tests, and JSON validation.
5056
- `.gitignore` entries for `.env`, `.env.*`, and `credentials.json`.
5157
- This changelog.

‎README.md‎

Lines changed: 48 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,20 @@
22

33
Build and edit [FlutterFlow](https://flutterflow.io) apps from
44
[Codex](https://developers.openai.com/codex) — describe what you want in plain
5-
language and the agent drives the FlutterFlow CLI to scaffold workspaces, author
6-
changes as Dart DSL, validate them, and apply them.
5+
language and the agent drives the FlutterFlow CLI and project-scoped MCP to
6+
scaffold workspaces, understand typed project context, test changes, and apply
7+
them safely.
78

89
This repo ships one plugin, `flutterflow`, which adds:
910

10-
- A **skill** that teaches Codex the FlutterFlow AI workflow — workspace setup,
11-
inspection, validating and running Dart DSL edits, diagnostics, and code export.
11+
- A **skill** that handles secure onboarding, then follows each workspace's
12+
version-matched `AGENTS.md` for typed SDK, branch-aware editing, testing,
13+
diagnostics, and code export.
1214
- **Helper scripts** that resolve a globally installed `flutterflow` CLI (or a
1315
local `flutterflow_cli` source checkout), plus a secure clipboard hand-off
1416
script for FlutterFlow API keys.
15-
- An **optional MCP example** for workspace-bound setups. MCP is not registered
16-
or started by default.
17+
- A **workspace-bound MCP example** that launches the vendored server directly.
18+
Current CLI onboarding also writes project-scoped agent configuration.
1719

1820
## Prerequisites
1921

@@ -53,7 +55,7 @@ codex plugin marketplace add .
5355
codex plugin add flutterflow@flutterflow
5456
```
5557

56-
Start a new Codex thread so the skill loads. (A public Plugin Directory listing
58+
Start a new Codex task so the skill loads. (A public Plugin Directory listing
5759
is coming soon; until then, install from GitHub or a local clone.)
5860

5961
## Use it
@@ -66,18 +68,22 @@ Once installed, just ask Codex in plain language:
6668
6769
> Export my FlutterFlow project to Flutter code.
6870
69-
The skill walks through auth, workspace setup, validation, and applying the
70-
change for you.
71+
The skill walks through auth and workspace setup, then follows the generated
72+
workspace contract for the installed FlutterFlow AI SDK.
7173

7274
### Use the CLI directly (optional)
7375

7476
You can also run the FlutterFlow CLI yourself:
7577

78+
For interactive human onboarding, bare `flutterflow ai` opens a searchable
79+
project picker with a create-new option. For deterministic automation:
80+
7681
```bash
77-
flutterflow ai init my-app # new workspace
78-
flutterflow ai init my-app --project <id> # bind to an existing project
79-
flutterflow ai status <project-id> # inspect
80-
flutterflow ai run <file.dart> # apply a Dart DSL change
82+
flutterflow ai init my-app --yes # new workspace
83+
flutterflow ai init my-app --project <id> --yes # existing project
84+
cd my-app && flutterflow ai branch current # confirm push target
85+
flutterflow ai test # workspace test gate
86+
flutterflow ai run <file.dart> --commit-message "<why>" # apply a change
8187
```
8288

8389
If `flutterflow` isn't on your PATH, the plugin bundles a helper. Its own
@@ -88,10 +94,16 @@ give an absolute path:
8894
/absolute/path/to/plugins/flutterflow/scripts/flutterflow-cli.sh ai --help
8995
```
9096

97+
The helper preserves the caller's directory, invokes the CLI exactly once, and
98+
defaults direct-command attribution to Codex unless `FF_AI_AGENT_CLIENT` is
99+
already set.
100+
91101
## Authentication
92102

93-
- `flutterflow ai` uses `FF_API_KEY` or the credential store created by
94-
`flutterflow ai init`. `export-code` and `deploy-firebase` use
103+
- Onboarding can use `FF_API_KEY` or the per-machine store at
104+
`~/.flutterflow/credentials.json`. Ordinary initialized-workspace commands use
105+
the process environment, workspace `.env`, and `.flutterflow/.env`; the latter
106+
is the generated private store. `export-code` and `deploy-firebase` use
95107
`FLUTTERFLOW_API_TOKEN`.
96108
- **Recommended in Codex:** use the bundled secure clipboard hand-off. Open
97109
[your FlutterFlow account](https://app.flutterflow.io/account), copy the API
@@ -110,35 +122,42 @@ fi
110122
flutterflow ai status <project-id>
111123
```
112124

113-
- You can also run `flutterflow ai init` once in a terminal — it prompts for your
114-
key and saves it to `~/.flutterflow/credentials.json` (mode `0600`) for later
115-
commands.
125+
- You can also run bare `flutterflow ai` in a terminal; the onboarding wizard
126+
prompts for the key, stores machine-level onboarding credentials, and creates
127+
or binds a workspace with its own private env file.
116128
- Avoid the `--api-key` flag: it puts the secret on the process argument list and
117-
persists it to disk (both the credential store and the workspace `.env`).
129+
persists it to disk (both the credential store and `.flutterflow/.env`).
118130
- Never commit tokens. This repo's `.gitignore` covers `.env`, `.env.*`, and
119-
`credentials.json`; keep any workspace `.env` out of version control too.
131+
`credentials.json`; keep workspace env files out of version control too.
132+
133+
## MCP
120134

121-
## MCP (optional)
135+
FlutterFlow MCP is project-scoped. Current `flutterflow ai init` and intentional
136+
`refresh-workspace` flows register the workspace's vendored server with supported
137+
agents, including project-scoped Codex configuration at `.codex/config.toml`.
138+
Open a new Codex task from that workspace after registration so the new tools
139+
load.
122140

123-
This plugin does not auto-register an MCP server — `flutterflow ai mcp` needs one
124-
concrete workspace, while the plugin should work from any Codex thread. For a
125-
workspace-bound setup, copy
126-
[mcp.example.json](plugins/flutterflow/mcp.example.json), fill in absolute paths,
127-
and point `FLUTTERFLOW_AI_WORKSPACE` at your workspace. Smoke-test the launcher:
141+
For a manual setup, copy
142+
[mcp.example.json](plugins/flutterflow/mcp.example.json) and fill in the absolute
143+
workspace paths. The example and helper both launch
144+
`.flutterflow/sdk/flutterflow_ai/mcp/server.dart` directly; this keeps pub/shim
145+
status text out of MCP's JSON-RPC stdout. Smoke-test the helper with:
128146

129147
```bash
130148
FLUTTERFLOW_AI_WORKSPACE=/absolute/path/to/workspace \
131149
/absolute/path/to/plugins/flutterflow/scripts/flutterflow-mcp.sh
132150
```
133151

134-
Don't rename `mcp.example.json` to `.mcp.json` unless you want Codex to start MCP
135-
for every thread where this plugin is enabled.
152+
The helper chooses the workspace from `FLUTTERFLOW_AI_WORKSPACE`, then
153+
`CODEX_WORKSPACE_ROOT`, then the current directory.
136154

137155
## Development
138156

139157
The plugin's runtime surface is shell scripts plus the skill and configs. CI
140158
([.github/workflows/ci.yml](.github/workflows/ci.yml)) runs `shellcheck`, syntax
141-
checks, clipboard hand-off tests, and JSON validation on every push.
159+
checks, exact-once CLI tests, direct MCP-launch tests, clipboard hand-off tests,
160+
and JSON validation on every push.
142161

143162
> The validation and cachebuster helpers below ship with Codex under
144163
> `~/.codex/skills/.system/plugin-creator/` (installed by Codex's plugin-creator,

‎plugins/flutterflow/.codex-plugin/plugin.json‎

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "flutterflow",
3-
"version": "0.1.0+codex.20260702205233",
4-
"description": "Use the FlutterFlow CLI from Codex, with optional workspace-bound MCP setup.",
3+
"version": "0.1.0+codex.20260714211821",
4+
"description": "Build and edit FlutterFlow projects from Codex with the CLI and workspace-bound MCP.",
55
"author": {
66
"name": "FlutterFlow",
77
"email": "support@flutterflow.io",
@@ -20,13 +20,15 @@
2020
"skills": "./skills/",
2121
"interface": {
2222
"displayName": "FlutterFlow",
23-
"shortDescription": "Build and edit FlutterFlow apps with the CLI.",
24-
"longDescription": "Adds FlutterFlow AI guidance for CLI-first workflows. Use it to initialize workspaces, inspect projects, plan changes, validate Dart DSL edits, apply updates, refresh workspace context, run diagnostics, and export code through the FlutterFlow CLI. MCP is documented as an optional workspace-bound setup, not started by default.",
23+
"shortDescription": "Build and edit FlutterFlow apps from Codex.",
24+
"longDescription": "Adds secure FlutterFlow AI onboarding and version-matched workspace guidance for typed project context, branch-aware editing, workspace tests, CLI pushes, diagnostics, code export, and project-scoped MCP. Current FlutterFlow workspaces can auto-register their vendored MCP server with Codex.",
2525
"developerName": "FlutterFlow",
2626
"category": "Developer Tools",
2727
"capabilities": [
2828
"CLI",
2929
"Project editing",
30+
"Project-scoped MCP",
31+
"Branch-aware workflows",
3032
"Workspace diagnostics"
3133
],
3234
"defaultPrompt": [
Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
{
22
"mcpServers": {
33
"flutterflow": {
4-
"command": "/absolute/path/to/plugins/flutterflow/scripts/flutterflow-mcp.sh",
5-
"args": [],
6-
"env": {
7-
"FLUTTERFLOW_AI_WORKSPACE": "/absolute/path/to/flutterflow-ai-workspace"
8-
}
4+
"command": "dart",
5+
"args": [
6+
"run",
7+
"/absolute/path/to/flutterflow-ai-workspace/.flutterflow/sdk/flutterflow_ai/mcp/server.dart",
8+
"--dir",
9+
"/absolute/path/to/flutterflow-ai-workspace"
10+
]
911
}
1012
}
1113
}

‎plugins/flutterflow/scripts/flutterflow-cli.sh‎

Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
#!/bin/sh
22
set -eu
33

4+
# The upstream CLI cannot currently infer Codex from Codex's environment.
5+
# Preserve an explicit caller override; otherwise identify direct plugin-driven
6+
# CLI traffic as Codex for attribution.
7+
: "${FF_AI_AGENT_CLIENT:=codex}"
8+
export FF_AI_AGENT_CLIENT
9+
410
# Resolve the FlutterFlow CLI without changing the caller's working directory.
511
# `flutterflow ai` discovers `.flutterflow/config.yaml` from the current
612
# workspace for commands such as validate, run, and upgrade, so this wrapper
@@ -16,39 +22,18 @@ run_source_cli() {
1622
command -v dart >/dev/null 2>&1 || return 1
1723

1824
package_config="$cli_dir/.dart_tool/package_config.json"
19-
# Track whether the package config already existed. A 254 exit is only treated
20-
# as a stale-config problem worth retrying when the config pre-existed; if we
21-
# just resolved it below, a 254 is an application error and must not be re-run.
22-
pkg_config_preexisting=1
2325
if [ ! -f "$package_config" ]; then
24-
pkg_config_preexisting=0
2526
echo "Resolving FlutterFlow CLI dependencies in $cli_dir..." >&2
2627
if ! (cd "$cli_dir" && dart pub get >/dev/null); then
2728
echo "Failed to run dart pub get in $cli_dir." >&2
2829
return 1
2930
fi
3031
fi
3132

32-
if dart --packages="$package_config" "$cli_dir/bin/flutterflow_cli.dart" "$@"; then
33-
exit 0
34-
else
35-
status=$?
36-
fi
37-
38-
# Exit 254 is Dart's general error code: it can mean the CLI couldn't resolve
39-
# packages (a stale package config after a pubspec or branch change) OR that the
40-
# `flutterflow ai` command itself threw (network/API/app error). Only re-resolve
41-
# and retry when the package config pre-existed — i.e. it may be stale. If we
42-
# freshly resolved it above, or the status is anything else, propagate unchanged
43-
# so a command (including a state-mutating one) is never silently run twice.
44-
if [ "$status" -eq 254 ] && [ "$pkg_config_preexisting" -eq 1 ]; then
45-
echo "Re-resolving FlutterFlow CLI dependencies in $cli_dir (stale package config)..." >&2
46-
if (cd "$cli_dir" && dart pub get >/dev/null); then
47-
exec dart --packages="$package_config" "$cli_dir/bin/flutterflow_cli.dart" "$@"
48-
fi
49-
fi
50-
51-
exit "$status"
33+
# Invoke exactly once. Exit 254 is Dart's general error code and can represent
34+
# an application, network, or package-resolution failure. Retrying here could
35+
# execute a state-mutating command twice, so propagate every CLI exit unchanged.
36+
exec dart --packages="$package_config" "$cli_dir/bin/flutterflow_cli.dart" "$@"
5237
}
5338

5439
# 1. Explicit source checkout via FLUTTERFLOW_CLI_DIR (for local CLI development).

0 commit comments

Comments
 (0)