From 1f41ff408f1407a6831f3a7f4aceb3dda5c18fd3 Mon Sep 17 00:00:00 2001 From: Rohan Suresh Date: Thu, 4 Jun 2026 16:20:45 -0400 Subject: [PATCH] Gate retool-import skills on the deterministic compatibility policy Run import-policy.mjs as a Compatibility gate in both the generic retool-import skill and the lovable specialization, before any discovery or handoff. hard_no app types are blocked locally with parity copy; Next.js (soft_no) gets a best-effort confirm; supported apps proceed. Reconcile the prereq framework note (next/gatsby/expo) with the gate, which is now authoritative on app-type support. Retool's R2 agent remains the fallback for the non-skills path. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../skills/retool-import-lovable/SKILL.md | 23 ++++++- .../skills/retool-import/SKILL.md | 61 +++++++++++++++---- 2 files changed, 71 insertions(+), 13 deletions(-) diff --git a/plugins/retool-import/skills/retool-import-lovable/SKILL.md b/plugins/retool-import/skills/retool-import-lovable/SKILL.md index 26f24ad..566f7a9 100644 --- a/plugins/retool-import/skills/retool-import-lovable/SKILL.md +++ b/plugins/retool-import/skills/retool-import-lovable/SKILL.md @@ -31,14 +31,14 @@ Lovable began emitting **TanStack Start** projects (with `@tanstack/react-start` The skill runs these steps sequentially. Each has a fixed input, a fixed output, and a fixed exit condition. -1. Prerequisites check — confirm React repo + MCP tools. +1. Prerequisites check — confirm React repo + MCP tools, then run the deterministic compatibility gate (a `hard_no` app type is blocked locally; Next.js gets a best-effort confirm). 2. Lovable signal validation — confirm Lovable signals are present; offer the no-prep fallback for TanStack / non-standard shapes. 3. Pre-fill — populate the structural facts table from the known Lovable layout (no discovery scan). 4. Targeted HITL — one prompt per Supabase edge function, one combined prompt per migration directory, one prompt for Supabase Auth if used. 5. Produce artifacts — cleaned source tree (shared filter + Lovable-specific drops) plus pre-populated IMPORT_PLAN.md. 6. Handoff — `retool_start_prepared_import` with the plan, PUT a zip of the cleaned tree to the returned upload URL, then `retool_finalize_prepared_import` — falling back to inline `retool_submit_prepared_import` only if a step errors. -Do NOT skip steps. Do NOT pause for user input outside step 4. +Do NOT skip steps. Do NOT pause for user input outside step 4 and the compatibility gate's soft-no confirm. ## 1. Prerequisites check @@ -47,6 +47,24 @@ Same as the generic skill. Verify and stop with a clear error if either fails: 1. **React repo.** Read `package.json` at the repo root. The `dependencies` (or `devDependencies`) must include `react`. If not, stop and tell the user this skill targets React apps. 2. **Required MCP tools.** `retool_list_resources` plus the import tools gated by the `mcpServerRetoolImportEnabled` flag. The preferred handoff uses `retool_start_prepared_import` + `retool_finalize_prepared_import`; if those aren't visible but `retool_submit_prepared_import` is, the skill uses the inline submit instead (see [Handoff](#6-handoff)). If none of the import tools are visible, stop with: "The retool-import-lovable skill requires the Retool import tools, gated by the `mcpServerRetoolImportEnabled` flag. Ask your Retool admin to enable that flag for your org." +### Compatibility gate + +After the two checks above pass, run the SAME deterministic compatibility gate as the generic `retool-import` skill, before signal validation or any handoff. It enforces Retool's app-type policy LOCALLY using the shared `references/import-policy.mjs` mirror of Retool's `appImportClassifier` (`rules.ts` / `classifier.ts`). + +A legacy-Vite Lovable project (Vite + React + Supabase) is `supported` and passes instantly, so this gate is mostly a guardrail — but run it anyway, since this skill is directly invocable and may be pointed at a repo that isn't actually a supported shape. + +``` +node /../../references/import-policy.mjs +``` + +It prints `{ "verdict": "hard_no" | "soft_no" | "supported", "identifiedAs": "", "reasons": [...] }` from manifest files only (never source code). Act on `verdict`: + +- **`hard_no`** — STOP. Tell the user verbatim, substituting `identifiedAs`: "Your app uses ``, which isn't supported by Retool's React app import yet. See supported frameworks: https://docs.retool.com/build/apps/guides/import". Do NOT run any further step. +- **`soft_no`** (Next.js carve-out) — prompt once and WAIT: "`` imports are not supported. We'll attempt the build, but the result may need some cleanup. Attempt a best-effort import anyway? (y/n)". On anything not affirmative, STOP. On `y`, continue and note the best-effort approval under **Open questions / known gaps** in step 5b. (A genuine Lovable project never hits this branch.) +- **`supported`** — continue to signal validation with no prompt. + +This gate is about Retool's app-type policy (mobile / non-JS backend / non-React frontend → blocked). It is orthogonal to the [TanStack guard](#tanstack-guard) below, which is about whether *this skill's structural pre-fill* applies. A TanStack Lovable app passes the gate (`supported`) but still routes to the [Unsupported-shape fallback](#unsupported-shape-fallback). If `node` is unavailable or the script errors, tell the user the local check couldn't run and proceed only on their confirm — Retool's R2 agent re-validates compatibility as a fallback. + ## 2. Lovable signal validation ### Lovable signal present @@ -361,6 +379,7 @@ Surface any terminal error verbatim and stop — an error from the submit fallba ## Hard rules / safety +- Run the [Compatibility gate](#compatibility-gate) before any other step. Never bypass a `hard_no` verdict, and never hand a `soft_no` app to Retool without the user's explicit best-effort confirm. The gate (app-type policy) is separate from the TanStack guard (pre-fill applicability) — both can apply. The policy lives in the shared `references/import-policy.mjs`; keep it in sync with Retool's upstream `appImportClassifier` rather than editing rules inline. - Never read `.env` or `.env.local`. Only `.env.example` is safe. - Never auto-apply `supabase/migrations/*.sql` against any database — always surface the SQL and tell the user to apply manually. - Never auto-resolve a Retool resource pick without HITL, even when there's exactly one candidate of the matching type. diff --git a/plugins/retool-import/skills/retool-import/SKILL.md b/plugins/retool-import/skills/retool-import/SKILL.md index ac98bf5..a206809 100644 --- a/plugins/retool-import/skills/retool-import/SKILL.md +++ b/plugins/retool-import/skills/retool-import/SKILL.md @@ -9,25 +9,63 @@ This skill prepares a user's app for being imported into Retool via MCP. The ski ## State machine overview -The skill runs these phases sequentially. Each phase has a fixed input, a fixed output, and a fixed exit condition. Do NOT skip phases — except that Phase 0 may delegate to a sibling skill, in which case this skill stops entirely and the sibling owns the rest of the flow. Do NOT pause for user input outside of Phase 4 (HITL). +The skill runs these phases sequentially. Each phase has a fixed input, a fixed output, and a fixed exit condition. Do NOT skip phases — except that Phase 0 may delegate to a sibling skill, in which case this skill stops entirely and the sibling owns the rest of the flow. Do NOT pause for user input outside of Phase 4 (HITL) and the compatibility gate's soft-no confirm. 1. Prerequisites check — confirm we are in a React repo and that the required MCP tools are available. -2. Phase 0 — Source-tool detection. Look for known source-tool signals (e.g. `lovable-tagger`, `.lovable/`). On a positive match, delegate to the matching sibling skill via the Skill tool and STOP. On no match, proceed to Phase 1. -3. Phase 1 — Recon. Read a tight set of files and emit a structured summary of the workspace shape. -4. Phase 2 — Discovery scan. Fan out vendor-agnostic discovery subagents against the directory tree. -5. Phase 3 — Resource matching. For each discovered service, call `retool_list_resources` for compatible types and rank candidates. -6. Phase 4 — HITL. One prompt per distinct service. User picks a resource by number or `USE_MOCK_DATA`. Summarize the resolutions back for final confirm. -7. Phase 5 — Produce artifacts. Walk the repo with the zip filter to build a cleaned source tree, and fill in `IMPORT_PLAN.template.md`. -8. Phase 6 — Handoff. `retool_start_prepared_import` with the plan, PUT a zip of the cleaned tree to the returned upload URL, then `retool_finalize_prepared_import` — falling back to inline `retool_submit_prepared_import` only if a step errors. Stream progress. Surface the editor URL. +2. Compatibility gate — run the deterministic `import-policy` classifier. A `hard_no` app type is blocked locally before any work is done; `soft_no` (Next.js) asks the user to confirm a best-effort import; `supported` proceeds. +3. Phase 0 — Source-tool detection. Look for known source-tool signals (e.g. `lovable-tagger`, `.lovable/`). On a positive match, delegate to the matching sibling skill via the Skill tool and STOP. On no match, proceed to Phase 1. +4. Phase 1 — Recon. Read a tight set of files and emit a structured summary of the workspace shape. +5. Phase 2 — Discovery scan. Fan out vendor-agnostic discovery subagents against the directory tree. +6. Phase 3 — Resource matching. For each discovered service, call `retool_list_resources` for compatible types and rank candidates. +7. Phase 4 — HITL. One prompt per distinct service. User picks a resource by number or `USE_MOCK_DATA`. Summarize the resolutions back for final confirm. +8. Phase 5 — Produce artifacts. Walk the repo with the zip filter to build a cleaned source tree, and fill in `IMPORT_PLAN.template.md`. +9. Phase 6 — Handoff. `retool_start_prepared_import` with the plan, PUT a zip of the cleaned tree to the returned upload URL, then `retool_finalize_prepared_import` — falling back to inline `retool_submit_prepared_import` only if a step errors. Stream progress. Surface the editor URL. ## Prerequisites check Before Phase 1, verify two things and stop with a clear error if either fails: -1. **React repo.** Read `package.json` at the repo root. If absent, look for a single clearly-identifiable client subdirectory (`packages//package.json` or `apps//package.json`) and use that as the client root. In either case, the `dependencies` (or `devDependencies`) must include one of: `react`, `react-dom`, `next`, `vite`, `gatsby`, `expo`. If none is present, stop and tell the user this skill targets React apps. +1. **JS/React-family repo.** Read `package.json` at the repo root. If absent, look for a single clearly-identifiable client subdirectory (`packages//package.json` or `apps//package.json`) and use that as the client root. In either case, the `dependencies` (or `devDependencies`) must include one of: `react`, `react-dom`, `next`, `vite`, `gatsby`, `expo`. If none is present, stop and tell the user this skill targets React apps. This check only confirms the repo is a JS frontend project at all — it is intentionally permissive. Whether the specific app *type* is importable (e.g. `next`/`gatsby`/`expo` are NOT supported targets) is decided authoritatively by the Compatibility gate below, not here. 2. **Required MCP tools.** The skill needs `retool_list_resources` (existing) plus the import tools gated by the `mcpServerRetoolImportEnabled` flag. The preferred handoff uses `retool_start_prepared_import` + `retool_finalize_prepared_import`; if those aren't visible but `retool_submit_prepared_import` is, the skill uses the inline submit instead (see Phase 6). If none of the import tools are visible, stop and tell the user: "The retool-import skill requires the Retool import tools, gated by the `mcpServerRetoolImportEnabled` flag. Ask your Retool admin to enable that flag for your org." -If both checks pass, proceed to Phase 0. +If both checks pass, proceed to the Compatibility gate. + +## Compatibility gate + +Retool's React app import supports a specific set of app types. This gate runs the SAME deterministic policy as Retool's browser-based import (the pre-agent classifier in `appImportClassifier/`), but LOCALLY — so an unsupported app type is blocked here, before any discovery work or any handoff to Retool's R2 agent. The policy is mirrored in `references/import-policy.mjs`; keep that file in sync with the upstream `rules.ts` / `classifier.ts`. + +Run the classifier against the client root (the directory whose `package.json` you found in the prerequisites check — pass the repo root for a single-package repo): + +``` +node /../../references/import-policy.mjs +``` + +It prints one line of JSON: `{ "verdict": "hard_no" | "soft_no" | "supported", "identifiedAs": "", "reasons": [...] }`. The classifier looks ONLY at manifest files (`package.json` deps, `app.json` shape, config-file presence) — never at source code — and ignores `node_modules`, build output, etc. Act on `verdict`: + +- **`hard_no`** — STOP. The app type is not supported. Tell the user verbatim, substituting `identifiedAs`: + + ``` + Your app uses , which isn't supported by Retool's React app import yet. + See supported frameworks: https://docs.retool.com/build/apps/guides/import + ``` + + Do NOT run discovery, build artifacts, or call any import tool. The skill ends here. + +- **`soft_no`** — this is the Next.js carve-out. Best-effort is possible but the result may need cleanup. Prompt the user once and WAIT for an answer: + + ``` + imports are not supported. + We're still learning how to handle . We'll attempt the build, + but the result may need some cleanup. + + Attempt a best-effort import anyway? (y/n) + ``` + + On `n` (or anything not affirmative), STOP — no discovery, no handoff. On `y`, proceed to Phase 0, and in Phase 5 record under **Open questions / known gaps**: "Best-effort import of a `` app the user explicitly approved; the result may need cleanup." + +- **`supported`** — proceed to Phase 0 with no prompt. + +If `node` is unavailable or the script errors (non-zero exit), do NOT silently skip the gate: tell the user the local compatibility check couldn't run, and proceed only if they confirm — Retool's R2 agent will re-validate compatibility on its side as a fallback (its `evaluate_app_compatibility` tool), so an unsupported app may still be rejected after handoff. ## Phase 0 — Source-tool detection @@ -291,10 +329,11 @@ Surface any terminal error verbatim and stop — an error from the submit fallba - Never write outside the user's repo without asking. The skill's only outputs are the in-terminal prompts and the import handoff (the `retool_start_prepared_import` / upload PUT / `retool_finalize_prepared_import` flow, or the `retool_submit_prepared_import` fallback). - Never read `.env` or `.env.local`. Only `.env.example` is safe. +- The Compatibility gate is authoritative on app-type support and runs BEFORE any discovery or handoff. Never bypass a `hard_no` verdict, and never hand a `soft_no` app to Retool without the user's explicit best-effort confirm. `references/import-policy.mjs` mirrors Retool's upstream `appImportClassifier` (`rules.ts` / `classifier.ts`) — when the upstream policy changes, update that file rather than editing the rules inline in this skill. - If discovery finds a service the user did not acknowledge in Phase 4, do NOT silently skip — surface it as an open question in the plan. - If none of the import tools (`retool_start_prepared_import`, `retool_finalize_prepared_import`, `retool_submit_prepared_import`) are available as MCP tools, stop at Phase 5 and tell the user to enable `mcpServerRetoolImportEnabled` for their org. - Phase 2 (discovery) is LLM-driven against the closed category taxonomy. Vendor is a free-text string. Do NOT add vendor-specific code paths in Phase 2 — the same discovery pass must work on Supabase, Firebase, Prisma, hand-rolled REST, etc. Phase 0 is the only place vendor-specific knowledge is encoded, and it operates on signal files alone (never on code behavior). ## Summary for the user -This skill recons your React repo, fans out parallel discovery subagents to find every external service your code talks to (databases, auth, storage, realtime, HTTP APIs, payments, etc.), looks up matching Retool resources for each one, asks you to pick the right resource (or `USE_MOCK_DATA`) per service in the terminal, packages your source tree with secrets and large files stripped out, builds a partially-populated `IMPORT_PLAN.md`, and hands it all to Retool's React app sandbox agent. Retool finishes classification and execution; you end up with a working Retool app whose editor URL is printed at the end. +This skill first runs a deterministic compatibility gate that blocks app types Retool can't import (mobile, non-JS backends, non-React frontends) locally before any work happens — Next.js gets a best-effort confirm. For a supported app it then recons your React repo, fans out parallel discovery subagents to find every external service your code talks to (databases, auth, storage, realtime, HTTP APIs, payments, etc.), looks up matching Retool resources for each one, asks you to pick the right resource (or `USE_MOCK_DATA`) per service in the terminal, packages your source tree with secrets and large files stripped out, builds a partially-populated `IMPORT_PLAN.md`, and hands it all to Retool's React app sandbox agent. Retool finishes classification and execution; you end up with a working Retool app whose editor URL is printed at the end.