Skip to content
FMScriptBridge
Lossless round-trip · through FileMaker 2026

Bring AI to your FileMaker scripts without handing over your file.

Copy steps out as readable text, flag secrets for review before you share, work in any editor or AI, and paste back losslessly. The conversion runs locally, and you stay the gate on what your AI ever sees.

order-approval.txt · readable
Set Variable [ $orderTotal ;
    Value: Sum ( LineItems::amount ) ]
If [ $orderTotal > 1000 ]
    Set Variable [ $status ;
        Value: "needs approval" ]
Else
    Set Variable [ $status ;
        Value: "approved" ]
End If
verified lossless · pastes back identical, by name
copy steps out secrets redacted edit anywhere references checked paste back losslessly
01 / Trust

What leaves your machine, and what never does

A tool that rewrites your scripts has to earn it. The tool uploads nothing, you choose what reaches your AI, and every step is verified lossless before it goes back.

Lossless by name

Every step pastes back exactly the way FileMaker resolves it by name. Current through FileMaker 2026: new steps render as clean text, and anything it doesn't yet recognize is preserved exactly rather than guessed at. Unknown means untouched.

Local conversion, sends nothing

The conversion runs on your machine, inside FileMaker. The tool uploads no script content; the only network traffic is licensing (your license key and a one-way machine ID, or just those IDs for the single call that starts a free trial) plus a daily anonymous check for a newer version, which you can switch off. Some alternative tools send your schema or scripts to a server to do their work. FMSB does not.

You are the gate

You copy out only the steps you choose and review every AI edit as plain text before it touches FileMaker. You decide what reaches your AI, and a copy that contains likely secrets stops for your decision before it ever reaches the clipboard.

One-click redaction

Every copy is scanned for likely secrets and PII. On a hit the copy stops: redact in one click (placeholders replace the values), copy unchanged, or cancel. Or set it to redact automatically. An aid to your care, not a replacement for it.

Catches broken references

Surfaces fields, scripts and layouts that won't resolve, and test-parses every calculation with FileMaker's own engine, so a renamed field or a calculation that won't compile doesn't silently break on paste.

No telemetry

No analytics in the tool. Bug reports are opt-in, redaction is applied to them, and you review what is in them before anything is sent.

02 / Proof

A FileMaker script as text, and back again

Real engine output, not a mockup. The clean text you edit, and the clipboard XML it came from and pastes back to, identical the way FileMaker resolves references by name. Anyone can prettify XML; coming back perfectly is the hard part. New to the problem? Start with how to copy a FileMaker script as text, and paste it back.

Order approval

Pastes back identical, by name
Readable text (what you edit)
Set Variable [ $orderTotal ; Value: Sum ( LineItems::amount ) ]
If [ $orderTotal > 1000 ]
    Set Variable [ $status ; Value: "needs approval" ]
    Exit Script [ Result: $status ]
Else
    Set Variable [ $status ; Value: "approved" ]
End If
Clipboard XML (in and out of FileMaker)
<fmxmlsnippet type="FMObjectList">
  <Step enable="True" id="141" name="Set Variable">
    <Value>
      <Calculation><![CDATA[Sum ( LineItems::amount )]]></Calculation>
    </Value>
    <Repetition>
      <Calculation><![CDATA[1]]></Calculation>
    </Repetition>
    <Name>$orderTotal</Name>
  </Step>
  <Step enable="True" id="68" name="If">
    <Restore state="False"/>
    <Calculation><![CDATA[$orderTotal > 1000]]></Calculation>
  </Step>
  <Step enable="True" id="141" name="Set Variable">
    <Value>
      <Calculation><![CDATA["needs approval"]]></Calculation>
    </Value>
    <Repetition>
      <Calculation><![CDATA[1]]></Calculation>
    </Repetition>
    <Name>$status</Name>
  </Step>
  <Step enable="True" id="103" name="Exit Script">
    <Calculation><![CDATA[$status]]></Calculation>
  </Step>
  <Step enable="True" id="69" name="Else">
    <Restore state="False"/>
  </Step>
  <Step enable="True" id="141" name="Set Variable">
    <Value>
      <Calculation><![CDATA["approved"]]></Calculation>
    </Value>
    <Repetition>
      <Calculation><![CDATA[1]]></Calculation>
    </Repetition>
    <Name>$status</Name>
  </Step>
  <Step enable="True" id="70" name="End If"/>
</fmxmlsnippet>
03 / Guardrails

What gets caught, both ways

Two directions, two checks. Both on by default, each with its own switch.

To AI : Secrets and PII are caught before a copy ever reaches your clipboard.

Without redaction, this is what copies to your clipboard

Set Variable [ $apiKey ; Value: "demo-key-not-a-real-secret-9f8e7d" ]
Set Variable [ $endpoint ; Value: "https://api.billing.example/v1/charge" ]
Set Variable [ $notifyTo ; Value: "[email protected]" ]
If [ $orderTotal > 1000 ]
    Set Variable [ $authHeader ; Value: "Bearer " & $apiKey ]
End If

With FMSB, this is what reaches your AI

Set Variable [ $apiKey ; Value: "#!#REDACTED#!#" ]
Set Variable [ $endpoint ; Value: "https://api.billing.example/v1/charge" ]
Set Variable [ $notifyTo ; Value: "#!#REDACTED#!#" ]
If [ $orderTotal > 1000 ]
    Set Variable [ $authHeader ; Value: "Bearer " & $apiKey ]
End If

FMSB also adds a short warning line above the text, naming what it replaced (here: 1 secret variable value, 1 email address) and noting it is not safe to paste back as is.

From AI : References and calculations are checked before anything pastes into your file.

Without guardrails you see this in FileMaker

Set Field [ Invoices::<Field Missing> ; 0 ]
Set Field [ <Table Missing> ; 0 ]
Perform Script [ “<unknown>” ; Specified: From list ; Parameter: "mode=full" ]
Set Variable [ $revenue ; Value: /*Customers::Loyalty_Tier * 12*/ ]
If [ /*$asd &*/ ]
  Show Custom Dialog [ "Over target" ]
End If

With FMSB you are informed where the problem is

# ⚠ ATTENTION [fmsb-missing-ref]: field "Invoices::Discount_Rate" not found in "Invoices"
Set Field [ Invoices::<Field Missing> ; 0 ]
# ⚠ ATTENTION [fmsb-missing-ref]: field "Archive::Total" not found in "Invoices"
Set Field [ <Table Missing> ; 0 ]
# ⚠ ATTENTION [fmsb-missing-ref]: script "Nightly Sync" not found in "Invoices"
Perform Script [ “<unknown>” ; Specified: From list ; Parameter: "mode=full" ]
# ⚠ ATTENTION [fmsb-missing-ref]: field "Customers::Loyalty_Tier" (in calculation) not found in "Invoices" → FileMaker disables this entire calculation (/*…*/) on paste
Set Variable [ $revenue ; Value: /*Customers::Loyalty_Tier * 12*/ ]
# ⚠ ATTENTION [fmsb-missing-ref]: calculation does not compile (FileMaker error 1204: syntax error) → FileMaker disables this entire calculation (/*…*/) on paste
If [ /*$asd &*/ ]
  Show Custom Dialog [ "Over target" ]
End If
04 / Savings

Up to 77% lighter than clipboard XML for your AI

When you do share with an AI, the clean text is far smaller than FileMaker's clipboard XML. More of your script fits in the model's context, replies come back faster, and you spend fewer tokens. Measured on real captured scripts, conservatively.

Short clip26 steps
77% smaller
Clipboard XML2,631 ch · ~658 tok
Readable text596 ch · ~149 tok
Mid-size script321 steps
53% smaller
Clipboard XML47,804 ch · ~11,951 tok
Readable text22,325 ch · ~5,581 tok
Large real script945 steps
51% smaller
Clipboard XML1.83M ch · ~457K tok
Readable text894K ch · ~223K tok

Real engine output, not a mockup. Token counts are approximate (about 4 characters each); sizes are measured against the compact clipboard XML.

And your AI learns to write it back

One calculation function, FMSB_CopyAISpec, puts the complete writing guide for this text format on your clipboard. Paste it into your AI chat once and the AI writes push-ready scripts. Field-tested: 44 of 44 blind-authored scripts from different AI assistants pushed back clean.

Bonus

Work with JSON a lot? Two functions do the typing for you.

FMSB adds a couple of calculation functions that have nothing to do with converting scripts. They write FileMaker calc and script code for you, straight from a JSON sample. Real output below, not a mockup.

FMSB_JSONToSetElement ( json ) docs →

Give it JSON and get the JSONSetElement expression that rebuilds it, every leaf a paste-ready [ path ; value ; type ] row, nested objects and arrays included.

You give it

{"orderId":1001,"customer":{"name":"Acme Corp","email":"[email protected]"},"total":249.5,"lines":[{"sku":"A1","qty":2}]}

It returns, paste-ready

JSONSetElement ( "{}" ;
  [ "orderId" ; 1001 ; JSONNumber ] ;
  [ "customer.name" ; "Acme Corp" ; JSONString ] ;
  [ "customer.email" ; "[email protected]" ; JSONString ] ;
  [ "total" ; 249.5 ; JSONNumber ] ;
  [ "lines[0].sku" ; "A1" ; JSONString ] ;
  [ "lines[0].qty" ; 2 ; JSONNumber ]
)
FMSB_JSONToLoopSteps ( json ) docs →

Give it the same JSON and get a complete, readable script that loops your records and composes it back. A nested array ("lines" here) makes the script call itself once per child record to walk into a related table.

You give it

{"orderId":1001,"customer":{"name":"Acme Corp","email":"[email protected]"},"total":249.5,"lines":[{"sku":"A1","qty":2}]}

It returns: wire in your fields and run it

# ===== START HERE - this is a template, not a finished script =====
# 1) dotted keys (a.b) read the CURRENT record; arrays walk a child layout, found by the parent key
# 2) this script is RECURSIVE - give it a unique name
# 3) Fill in every SET THIS block.
# 4) Set the gate below to True when ready.
# 5) Run from the initial parent record without parameter - result returns via Get ( ScriptResult )
# ===== sample structure =====
# { orderId: number, customer: { name: text, email: text }, total: number, lines: [ 1 x { sku: text, qty: number } ] }
If [ False ]
    Set Error Capture [ On ]
    Freeze Window
    Set Variable [ $fmsb.home ; Value: Get ( LayoutName ) ]
    Set Variable [ $fmsb.collection ; Value: JSONGetElement ( Get ( ScriptParameter ) ; "collection" ) ]
    Set Variable [ $fmsb.parentKey ; Value: JSONGetElement ( Get ( ScriptParameter ) ; "parentKey" ) ]
    If [ IsEmpty ( Get ( ScriptParameter ) ) ]
        # ===== TOP LEVEL - this part runs when there is no script parameter =====
        # RUN THIS FROM THE PARENT RECORD YOU WANT TO EXPORT - wrong record = blank JSON, no error
        # ############################################
        # ##### SET THIS - one field per key #####
        # ############################################
        # $orderId_value - your field for "orderId". Sample: 1001
        Set Variable [ $orderId_value ; Value: "SET VALUE" ]
        # $customer_name_value - your field for "customer.name". Sample: "Acme Corp"
        Set Variable [ $customer_name_value ; Value: "SET VALUE" ]
        # $customer_email_value - your field for "customer.email". Sample: "[email protected]"
        Set Variable [ $customer_email_value ; Value: "SET VALUE" ]
        # $total_value - your field for "total". Sample: 249.5
        Set Variable [ $total_value ; Value: "SET VALUE" ]
        # $lines_parent_key - the key field on THIS record that "lines" rows point back to
        #   unquoted field - the VALUE, not the field's name
        Set Variable [ $lines_parent_key ; Value: "SET VALUE" ]
        # ############################################
        # ##### END SET THIS #####
        # ############################################
        Set Variable [ $fmsb.json ; Value:
        ```
        JSONSetElement ( "{}" ;
          [ "orderId" ; $orderId_value ; JSONNumber ] ;
          [ "customer.name" ; $customer_name_value ; JSONString ] ;
          [ "customer.email" ; $customer_email_value ; JSONString ] ;
          [ "total" ; $total_value ; JSONNumber ] ;
          [ "lines" ; "[]" ; JSONArray ]
        )
        ``` ]
        # "lines" - this same script fills it in, one call per record.
        Set Variable [ $fmsb.thisKey ; Value: $lines_parent_key ]
        Perform Script [ by name: Get ( ScriptName ) ; Parameter: JSONSetElement ( "{}" ; [ "collection" ; "lines" ; JSONString ] ; [ "parentKey" ; $fmsb.thisKey ; JSONString ] ) ]
        If [ Left ( Get ( ScriptResult ) ; 6 ) = "!FMSB:" ]
            # Error handling block. Passing message instead of "?"
            Exit Script [ Result: Get ( ScriptResult ) ]
        End If
        Set Variable [ $fmsb.json ; Value: JSONSetElement ( $fmsb.json ; "lines" ; Get ( ScriptResult ) ; JSONArray ) ]
        Exit Script [ Result: $fmsb.json ]
    Else If [ $fmsb.collection = "lines" ]
        # ===== "lines" - one record becomes one element of this list =====
        # Your sample had 1 element. Keys: sku, qty
        # needs its OWN table occurrence + layout
        # ############################################
        # ##### SET THIS - find the "lines" records #####
        # ############################################
        # $lines_layout - layout of these records, quoted. Example: "Lines_list"
        Set Variable [ $lines_layout ; Value: "SET VALUE" ]
        # $lines_find_field - FK field on the child table, quoted. Example: "Lines::parent_id"
        Set Variable [ $lines_find_field ; Value: "SET VALUE" ]
        # ############################################
        # ##### END SET THIS #####
        # ############################################
        # $lines_find_value - pre-wired: exact match on the parent key - drop the "==" for begins-with
        Set Variable [ $lines_find_value ; Value: "==" & $fmsb.parentKey ]
        If [ IsEmpty ( $fmsb.parentKey ) ]
            Exit Script [ Result: "!FMSB: the parent key was empty - there is nothing to find the child records with" ]
        End If
        Go to Layout [ by name: $lines_layout ]
        If [ Get ( LayoutName ) <> $lines_layout or PatternCount ( List ( $lines_find_field ; $lines_find_value ) ; "SET VALUE" ) ]
            Go to Layout [ by name: $fmsb.home ]
            Exit Script [ Result: "!FMSB: check the SET THIS block above - the layout name is wrong, or a line still says SET VALUE" ]
        End If
        Enter Find Mode [ Pause: Off ]
        # find operators ( @ * # ? ! = < > " ~ .. ) inside key data need \ escaping
        Set Field By Name [
          Target name: $lines_find_field ;
          Value: $lines_find_value
        ]
        Perform Find
        If [ Get ( LastError ) = 400 ]
            # The find ran with no criteria (FileMaker error 400) - the field name above is blank or not a field on this layout's table
            Go to Layout [ by name: $fmsb.home ]
            Exit Script [ Result: "!FMSB: the find had no criteria - check the field name and the value in the SET THIS block above" ]
        End If
        Set Variable [ $fmsb.n ; Value: Get ( FoundCount ) ]
        Set Variable [ $fmsb.rows ; Value: "" ]
        Set Variable [ $fmsb.i ; Value: 1 ]
        Loop [ Flush: Always ]
            Exit Loop If [ $fmsb.i > $fmsb.n ]
            Go to Record/Request/Page [ With dialog: Off ; $fmsb.i ]
            # ############################################
            # ##### SET THIS - one field per key #####
            # ############################################
            # read once per record - keep inside the loop
            # $sku_value - your field for "sku". Sample: "A1"
            Set Variable [ $sku_value ; Value: "SET VALUE" ]
            # $qty_value - your field for "qty". Sample: 2
            Set Variable [ $qty_value ; Value: "SET VALUE" ]
            # ############################################
            # ##### END SET THIS #####
            # ############################################
            Set Variable [ $fmsb.row ; Value:
            ```
            JSONSetElement ( "{}" ;
              [ "sku" ; $sku_value ; JSONString ] ;
              [ "qty" ; $qty_value ; JSONNumber ]
            )
            ``` ]
            Set Variable [ $fmsb.rows ; Value: List ( $fmsb.rows ; $fmsb.row ) ]
            Set Variable [ $fmsb.i ; Value: $fmsb.i + 1 ]
        End Loop
        Go to Layout [ by name: $fmsb.home ]
        Exit Script [ Result: If ( IsEmpty ( $fmsb.rows ) ; "[]" ; JSONMakeArray ( $fmsb.rows ; "¶" ; JSONRaw ) ) ]
    Else
        # unknown collection
        Exit Script [ Result: "!FMSB: no branch for this collection" ]
    End If
End If

Full reference for every function: Function help.

05 / Pricing

Pay once, no subscription

$199 one-time · $149 if you join the beta

Buy it once and it is yours. No subscription, no annual renewal, no seat to manage.

Join the beta
One-time · nothing is charged during the beta
  • Copy from and paste back into FileMaker. The full lossless round trip
  • One-click secret and PII redaction: placeholders replace values before they leave FileMaker
  • Broken-reference detection before you paste
  • Whole-script and comment handling, with folders and separators
  • Works with any editor or AI: Claude, ChatGPT, Cursor, no extra setup
  • One license covers 2 of your machines (your desktop and laptop), transferable anytime.
  • 1 year of updates included, counted from the day you activate: every new FileMaker release in that window.
  • After that, an optional one-time $39 update pass adds another 1 year of new builds and stacks on any time you have left. Never a subscription, never charged automatically.
  • A 14-day free trial of the whole tool, no card. Activating takes one online call, once; after that it works offline.
06 / FAQ
Launching 2026 · Mac + Windows

Questions FileMaker developers ask first

FileMaker 2026 is adding AI. Do I still need this?
More than ever. In-product AI is powerful, but it can reach straight into your solution. FMScriptBridge keeps you at the gate: you copy out only the steps you want, edit them with any AI, and paste back only the changes you've reviewed, with secrets flagged for your review, broken references surfaced, and every step verified lossless. You get modern AI leverage without handing an agent open access to your code. It's up to you how you use it.
Does my file or data ever leave my machine?
No. Licensing is what needs a connection: one online call to activate a license or start the free trial, and after that the plugin works offline. The conversion runs locally, inside FileMaker. The whole point is that you then choose what to share with an AI: paste in only the steps you want, with secrets and PII flagged for you to review first, so you control exactly what it sees. Some alternative tools send your schema or scripts to a server to do their work. FMSB does not.
Does FMScriptBridge use AI on my code?
No. FMScriptBridge does not generate code or run AI on your scripts. It locally converts your steps to clean text and lets you gate what reaches the AI you choose. You bring the AI; the tool keeps you in control of what it sees.
What does “lossless round-trip” actually guarantee?
Every step pastes back exactly the way FileMaker resolves it, matched by name. A step is only converted to clean text if the engine can reproduce it exactly; if it can't, it leaves that step exactly as it was rather than guess. Equivalence is verified on FileMaker's own name-based canonical form before anything is handed back, so a bad conversion is caught and refused instead of pasted.
Which AI tools does it work with?
Any of them. You copy readable text out and paste it into Claude, ChatGPT, Cursor, or a local model. That's the whole point of clean, readable text: paste a converted script into any AI tool to explain, refactor, or document it, then convert the edited text back to paste-ready FileMaker. FMScriptBridge never talks to an AI itself; you bring the AI, and the tool keeps you in control of what it sees. It also teaches your AI to write scripts back: the FMSB_CopyAISpec calculation function copies the complete writing guide for the text format to your clipboard, so after pasting it into your chat once, the AI produces push-ready scripts.
What is FMSB? Is it the same as FMScriptBridge?
Yes. FMSB is the short handle for FMScriptBridge: the same plug-in for Mac and Windows, and the prefix on every calculation function it adds to FileMaker (FMSB_LastError, FMSB_LastWarnings, FMSB_JSONToSetElement, FMSB_JSONToLoopSteps, FMSB_CopyAISpec). If you have seen "FMSB plugin", "FMSB for FileMaker" or an FMSB_ function name, this is it. The text format it converts scripts into is published for AI agents at fmscriptbridge.com/spec.md.
How is it different from other FileMaker AI tools?
Different approach. Some alternative tools convert your script on a server, so it leaves your machine. Others are AI plugins that read your live file and can change it for you. FMScriptBridge does neither: the conversion runs entirely on your machine, and it never runs AI on your file or edits it on its own. You copy out only what you choose, edit it with whatever AI you already use, and paste it back losslessly. You stay the gate, and it is a one-time purchase, not a subscription.
What happens to secrets and passwords in my scripts?
Every copy is scanned for likely secrets: API keys, passwords, tokens. On a hit the copy STOPS and offers one-click Redact & copy: the secret values are replaced with placeholders before the text ever reaches your clipboard (you can also copy unchanged, cancel, or make redaction automatic in settings). Redacted text even pastes back safely, as a marked skeleton you fill in inside FileMaker. The scan is heuristic, an aid to your own care, not a guarantee it catches everything.
Which FileMaker versions are supported?
Built and tested from FileMaker 2025 onward, current through FileMaker 2026 including the new script steps captured so far. Any step it doesn't yet recognize is left exactly as it is rather than guessed at. It does not load on FileMaker 2024 or older. The beta is Mac today (macOS 14 or newer); the Windows build is in progress for launch. Every purchase includes 12 months of updates from activation as new FileMaker releases ship; after that, an optional one-time update pass adds another 12 months of new builds, never a subscription.
Is it a subscription?
No. It is a one-time purchase of $199 covering 2 machines; you buy the license once and the version you have keeps working forever, online or offline. (Joining the beta locks a $149 founding price before launch.) Every purchase includes 12 months of updates from activation as new FileMaker releases ship; after that, an optional one-time $39 update pass adds another 12 months of new builds whenever you want it, never a subscription, and your build never stops working either way. There is a 14-day free trial of the whole tool to start, and you already manage enough FileMaker subscriptions.

More: how to copy a FileMaker script as text, and paste it back · where your script goes with each tool · the functions FMSB adds.

Join the Mac beta

The Mac beta is live. Join and we'll email you the build and the install guide, usually within a day. Joining locks the founding price of $149 for launch; Windows is in progress. No card today.

Beta emails while you test, plus one launch email. Nothing else, unsubscribe anytime. See our privacy notice.

Know another FileMaker dev who'd want this? Forward it →