FF Orbit Command Reference
Complete reference for all Orbit MCP commands. The primary MCP tool is orbit():
orbit({ cmd: "<command>", args?: {}, snapshot?: "<id>", format?: "json"|"explain" })
Supporting tools: orbit_policy_get(), orbit_policy_set(), orbit_export_changeset()
Architecture
Orbit is snapshot-first:
- Snapshot: Local point-in-time copy of project files (cached in SQLite)
- Index: Symbols and edges extracted from snapshot for fast search
- Changeset: Draft edits with preview, validation, and apply lifecycle
Prefer deterministic first-class commands over exploratory probing. Use help when command shape is unclear.
Discovery Commands
| Command |
Purpose |
Example Args |
help |
List all commands or get help for specific command |
{ cmd: "widget.create" } |
api.capabilities |
Check FlutterFlow API connectivity |
— |
projects.list |
List accessible FlutterFlow projects |
— |
Snapshot Commands
| Command |
Purpose |
Key Args |
snapshots.create |
Create snapshot from a project |
{ projectId: "..." } |
snapshots.refresh |
Update snapshot with latest files |
{ mode, fetchStrategy, maxFetch, concurrency, sleepMs } |
snapshots.refreshSlow |
Throttled refresh for rate-limited scenarios |
{ passes, maxFetch, concurrency, sleepMs, pauseMs } |
snapshots.ensureFresh |
Refresh only if older than threshold |
— |
snapshots.info |
Show snapshot metadata |
— |
snapshots.ls |
List all snapshots |
— |
Refresh Strategies
| Scenario |
Args |
| Normal incremental |
{ mode: "incremental", fetchStrategy: "auto", maxFetch: 25, concurrency: 1, sleepMs: 250 } |
| Heavy rate limiting |
{ mode: "incremental", fetchStrategy: "file", maxFetch: 5, concurrency: 1, sleepMs: 1000 } |
| Full sync |
{ mode: "full", fetchStrategy: "bulk" } |
| Chunked full fallback |
{ mode: "full", fetchStrategy: "file", maxFetch: 5 } |
Page Commands
| Command |
Purpose |
Key Args |
pages.list |
List all pages |
{ includeDeleted?, strictSnapshot? } |
page.get |
Get full page details (widget tree) |
{ nameOrId } |
page.create |
Create a new blank page |
{ name, apply? } |
page.scaffold |
Generate page from built-in recipe |
{ recipe, name, apply? } |
page.update |
Update page properties |
{ nameOrId, key, value, apply? } |
page.clone |
Duplicate a page |
{ nameOrId, newName, apply? } |
page.preflightDelete |
Check what would break before deleting |
{ nameOrId } |
page.remove |
Safe delete with checks |
{ nameOrId, apply? } |
page.delete |
Low-level delete (no safety checks) |
{ nameOrId, apply? } |
Built-In Page Recipes
| Recipe |
Description |
auth.login |
Login page with email/password fields |
auth.signup |
Signup page with registration fields |
settings.basic |
Settings page with toggles and list tiles |
list.cards.search |
List with search bar and card items |
detail.basic |
Detail page with header and content |
Examples
# Create page
orbit({ cmd: "page.create", args: { name: "SplashScreen", apply: true } })
# Rename page
orbit({ cmd: "page.update", args: { nameOrId: "SplashScreen", key: "name", value: "Splash", apply: true } })
# Safe delete
orbit({ cmd: "page.remove", args: { nameOrId: "OldPage", apply: true } })
# Scaffold from recipe
orbit({ cmd: "page.scaffold", args: { recipe: "auth.login", name: "LoginPage", apply: true } })
Widget Commands — Read
| Command |
Purpose |
Key Args |
widgets.list |
List widgets on a page |
{ nameOrId, type?, include? } |
widgets.find |
Search by type, text, or properties |
{ nameOrId, ... } |
widgets.findText |
Search widgets containing text |
{ nameOrId, text } |
textfields.list |
List all text field widgets |
{ nameOrId } |
widget.get |
Get single widget by node ID |
{ nameOrId, nodeId } |
widget.getMany |
Get multiple widgets |
{ nameOrId, nodeIds: [...] } |
Widget Commands — Write
| Command |
Purpose |
Key Args |
widget.create |
Create a new widget |
{ nameOrId, type, parentNodeId?, apply? } |
widget.insert |
Insert at specific position |
{ nameOrId, type, parentNodeId, beforeNodeId?, afterNodeId?, apply? } |
widget.set |
Update widget properties |
{ nameOrId, nodeId, text?, props?, apply? } |
widget.delete |
Delete a widget |
{ nameOrId, nodeId, apply? } |
widget.deleteSubtree |
Delete widget and all children |
{ nameOrId, nodeId, apply? } |
widget.duplicate |
Duplicate a widget |
{ nameOrId, nodeId, count?, apply? } |
Widget Commands — Structure
| Command |
Purpose |
Key Args |
widget.wrap |
Wrap widget in new parent |
{ nameOrId, nodeId, wrapperType, apply? } |
widget.unwrap |
Remove wrapper, promote children |
{ nameOrId, nodeId, apply? } |
widget.move |
Move to new parent |
{ nameOrId, nodeId, newParentNodeId, apply? } |
widget.moveMany |
Move multiple widgets |
{ nameOrId, nodeIds, newParentNodeId, apply? } |
widget.reorder |
Change position among siblings |
{ nameOrId, nodeId, position, apply? } |
widget.replaceType |
Change widget type in place |
{ nameOrId, nodeId, newType, apply? } |
widget.removeChildren |
Remove all children |
{ nameOrId, nodeId, apply? } |
Widget Commands — Batch
| Command |
Purpose |
Key Args |
widgets.updateMany |
Batch update matching widgets |
{ nameOrId, filter, updates, apply? } |
widgets.copyPaste |
Copy widgets between locations |
{ ... } |
Widget Actions & Data Binding
| Command |
Purpose |
Key Args |
widget.action.list |
List actions on a widget |
{ nameOrId, nodeId } |
widget.action.get |
Get specific action by trigger |
{ nameOrId, nodeId, trigger } |
widget.bindAction |
Bind action to widget trigger |
{ nameOrId, nodeId, trigger, action, apply? } |
widget.bindData |
Bind data to widget property |
{ nameOrId, nodeId, property, binding, apply? } |
Component Commands
| Command |
Purpose |
Key Args |
component.get |
Get component details |
{ nameOrId } |
component.instance.insert |
Insert component instance |
{ nameOrId, componentId, parentNodeId, apply? } |
component.extractFromWidget |
Extract widget into component |
{ nameOrId, nodeId, componentName, apply? } |
Widget Tree Commands
| Command |
Purpose |
Key Args |
tree.locate |
Find widget position in tree |
{ nameOrId, nodeId } |
tree.subtree |
Get subtree rooted at widget |
{ nameOrId, nodeId } |
tree.find |
Search tree (alias for locate) |
{ nameOrId, ... } |
tree.validate |
Check tree integrity |
{ nameOrId } |
tree.repair |
Fix tree issues |
{ nameOrId, apply? } |
Navigation & Routes
| Command |
Purpose |
Key Args |
routes.list |
List all routes |
— |
routes.listByPage |
Routes for a specific page |
{ nameOrId } |
routes.validate |
Validate routes |
{ nameOrId } |
routes.upsert |
Create or update route |
{ from, to, trigger?, apply? } |
routes.delete |
Delete a route |
{ routeId, apply? } |
graph.nav |
Query navigation graph |
{ ... } |
graph.usage |
Query component usage graph |
{ ... } |
Search & Utility
| Command |
Purpose |
Key Args |
search |
Full-text search across snapshot |
{ query } |
selection.get |
Get current sticky selection |
— |
selection.clear |
Clear sticky selection |
— |
intent.run |
Natural language → command |
{ text: "..." } |
settings.get |
Get project settings |
— |
Summaries
| Command |
Purpose |
Key Args |
summarize.page |
Human-readable page summary |
{ nameOrId } |
summarize.component |
Component summary |
{ nameOrId } |
summarize.project |
Project overview |
— |
Changeset Commands
The changeset pipeline ensures safe writes:
| Command |
Purpose |
Key Args |
changeset.new |
Create draft changeset |
— |
changeset.add |
Add patch to changeset |
{ changesetId, patches } |
changeset.preview |
Generate diffs and risk score |
{ changesetId } |
changeset.validate |
Validate YAML + policy |
{ changesetId } |
changeset.apply |
Apply changeset to FlutterFlow |
{ changesetId, confirm } |
changeset.applySafe |
Apply with rate-limit retry |
{ changesetId, confirm, rateLimitRetries?, rateLimitBaseMs?, rateLimitMaxWaitMs? } |
changeset.rollback |
Undo most recent changeset |
{ changesetId } |
changeset.revert |
Revert snapshot to pre-changeset |
{ changesetId } |
changeset.drop |
Discard draft changeset |
{ changesetId } |
Safe Write Workflow
1. orbit({ cmd: "changeset.new" }) → get changesetId
2. orbit({ cmd: "changeset.add", args: { changesetId, patches: [...] } })
3. orbit({ cmd: "changeset.preview", args: { changesetId } }) → review diffs
4. orbit({ cmd: "changeset.validate", args: { changesetId } }) → check structure
5. orbit({ cmd: "changeset.applySafe", args: { changesetId, confirm: true } })
Rate-Limited Apply
orbit({ cmd: "changeset.applySafe", args: {
changesetId: "chg_...",
confirm: true,
rateLimitRetries: 3,
rateLimitBaseMs: 1500,
rateLimitMaxWaitMs: 90000
}})
Schema Knowledge Base
| Command |
Purpose |
Key Args |
schema.search |
Search built-in docs and snippets |
{ query } |
schema.read |
Read specific doc by ID |
{ id } |
schema.snippet |
Get code snippet by ID |
{ id } |
Use only for unfamiliar patterns or advanced debugging — not for routine operations.
Prompt-to-Command Quick Map
| User Says |
Command |
| "List pages" |
pages.list |
| "Show widgets on login" |
widgets.list { nameOrId: "login" } |
| "All text fields on login" |
textfields.list { nameOrId: "login" } |
| "Get this widget" |
widget.get { nameOrId, nodeId } |
| "Change text on widget" |
widget.set { nameOrId, nodeId, text: "..." } |
| "Create a button under container" |
widget.insert { nameOrId, type, parentNodeId } |
| "Remove widget" |
widget.delete { nameOrId, nodeId } |
| "Rename page X to Y" |
page.update { nameOrId, key: "name", value: "Y" } |
| "Refresh from FlutterFlow" |
snapshots.refresh { mode: "incremental" } |
| "Wrap in column" |
widget.wrap { nameOrId, nodeId, wrapperType: "Column" } |
| "Move widget under X" |
widget.move { nameOrId, nodeId, newParentNodeId } |
| "Duplicate widget" |
widget.duplicate { nameOrId, nodeId } |
| "Safe apply" |
changeset.applySafe { changesetId, confirm: true } |
Always return resolved IDs (snapshotId, pageId, nodeId, fileKey) in responses.