Skip to content
FMScriptBridge

Specification · FMScriptBridge 0.9.26 · grammar 1.113 · spec build 0a8ff664

This page renders the spec of FMScriptBridge 0.9.26, the current public build: the document that build's FMSB_CopyAISpec function copies. An AI agent should fetch it as text: /spec.md (served as plain text), /spec.txt (the same bytes), or /llms-full.txt (with the site index). Writing for another build? Each published build's own spec is archived at /spec/v<version>.md (this one: https://fmscriptbridge.com/spec/v0.9.26.md) and linked from the release notes.

FMScriptBridge — script text: the writing rules

Grammar version: 1.113 · spec build: 0a8ff664

Which version you need: a plug-in accepts text written to its own grammar version and to every earlier one. A form introduced in a later version is refused at its line, never pasted wrong. To match the installed plug-in exactly, use its FMSB_CopyAISpec function: the copy it makes carries that plug-in's own version in these first lines.

This document defines the text form FileMaker script steps are written in. It is a rulebook: what you may write, and what refuses. You read and write ONLY this text — never FileMaker XML.

1. Absolute rules

  1. Return raw script text only. No prose before or after the script. The script text carries no fence of its own around it: the only backtick fences inside it are the calc and comment fences defined in §2, and a fence line (three or more backticks alone) anywhere else refuses the whole push. When you deliver the script through an interface that renders markdown (a chat window), put the ENTIRE script inside one outer fence that is LONGER than any backtick run inside the script (four backticks when the script's own fences are three), opener and closer on their own lines: the longer outer fence keeps the script's own fences visible as text, and the copy button returns them intact. On push, a backtick wrapper around the whole text is removed whatever its length, nested wrappers included, and so is a stray fence pair sitting between two complete steps; the longer one is still what renders the script correctly in the chat.
  2. Never edit inside a >>> preserved-fmxml block. Any change inside this block corrupts the step — copy the whole block byte-for-byte, fence lines included. Delete the whole step only if the user asked for that step to be removed.
  3. Never invent a name or spelling. Step names, option labels and enum values must be spelled exactly as in this document or in text you were given. The same for field, table, layout and script names: write only names the user gave you; any other name pastes broken.
  4. When a step or option is not covered by this document or the text you were given, do not guess it. Write this comment step instead, and say so in your reply channel if you have one: # TODO: <step name> - add by hand in FileMaker
  5. Fence every multi-line calculation. A [ … ] bracket body may never simply continue onto the next line: either keep the calculation on ONE line, or write it inside a fence (the fenced forms in §2 — opener on its own line after the label: header, the closing fence line carrying the step's ]). On push, a calculation that does run on past its line is still read when it closes unambiguously at the step's ]; the fenced form is what you write.
  6. Never alter a fence or its body. The closing fence repeats the opening fence's backtick run exactly — the same number of backticks — followed by a space and the ] when the fence ends a step's bracket (``` ]); a closer with a different number of backticks never closes the fence. Never shorten, lengthen or move a fence you were given, and never reflow, re-indent or re-wrap the lines between the fences — fence-body lines are data, byte for byte. Open a NEW fence with exactly three backticks (more only when the body itself contains a three-backtick run). In a ```cr fence, keep every line exactly as given; never open a cr fence yourself. Fence lines may be indented: the opener, the closer and the body may all sit at the step's indentation; a body line that starts with the opener line's leading whitespace loses exactly that much, and any other leading whitespace on a body line is data — to write intentional leading whitespace on a fence-body line of your own, put it beyond the opener's. Indentation on ordinary STEP lines, by contrast, is free — write any; 4 spaces per If/Loop level is the convention.
  7. Keep inline [ … ] items in the order shown for that step — the shown order is always safe; no reordering. Text after a calculation or path slot is part of that value — never place an item after such a slot except in the exact shapes this document shows with one (Set Field By Name's second slot, Show Custom Dialog's message, Perform Script on Server's wait item). Option lines directly inside a BLOCK step's bracket may be written in any order; lines inside a { … } sub-block and find-request criteria keep their order — order is data there.
  8. Never replace #!#REDACTED#!#. It marks a redacted secret in text you were given — leave it exactly as it is.
  9. Write real FileMaker calculation syntax — real function names, real signatures. A calculation that does not compile is pasted commented out as /*…*/.
  10. Return the COMPLETE script. Every step you were given must appear in your answer, in order. Never abbreviate, elide or summarise a run of steps. # ... rest unchanged ... is a legal comment step, so it is accepted silently and the steps you left out are simply GONE from the user's script — this is the one mistake here that destroys work rather than refusing.
  11. A step line ends at its closing ]. There are no end-of-line comments. Put the note on its own line ABOVE the step as # note. A note left after the ] usually refuses the line — but do not rely on that: an inline value slot runs to the line's TERMINAL ], so a note that itself contains a ] supplies a new terminal one and is ABSORBED INTO THE VALUE instead. Set Variable [ $x ; Value: 1 ] // note] is accepted, with the value silently becoming 1 ] // note. Beware also that // is not a comment marker here even though FileMaker calculations use it as one — a line STARTING with // means that step is DISABLED (§2 disabled). Inside a calculation, by contrast, // is ordinary calculation text and is kept.
  12. The item separator is ; — one space on each side, exactly. Not ;, not ;, not ; , not ; . This is what tells an item separator apart from a semicolon that is calculation DATA: plug-in calls such as MBS("Dyna.Save"; $pdf; "out.pdf") separate their own arguments with ; , and those must stay inside the value. Just inside the brackets, [ $x … ] and [$x … ] both read — but that is the only latitude: extra padding ([ $x … ]) refuses, exactly as a mis-spaced separator does. Copy the spacing you were given.

If an edit cannot be expressed within these rules, say so and leave the step unchanged.

2. Line grammar

(* The text is line-oriented: a sequence of step lines (and optional           *)
(* whole-script wrappers). Item separators and labels are LITERAL — note the   *)
(* surrounding spaces. W3C-style EBNF: concatenation is juxtaposition. Where   *)
(* this grammar and a worked example could be read differently, the example    *)
(* is authoritative.                                                           *)

snippet        = { rendering } ;
rendering      = step-rendering | whole-script ;
step-rendering = comment | disabled | preserve | step ;

step           = bare-step | inline-step | block-step | predicate-step
               | trailing-fence-step ;
bare-step      = step-name
               | step-name " [ " toggle " ]" ;            (* bare On/Off toggle *)
inline-step    = step-name " [ " bracket-body " ]" ;
block-step     = step-name " [" NEWLINE { block-item } NEWLINE "]" ; (* block-in-brackets *)
(* Find-query family (Perform Find, Constrain / Extend Found Set, Enter Find    *)
(* Mode): an inline-step FOLLOWED on the next line by a standalone "{ }" block *)
(* of find requests — a separate line group, unlike block-step's bracket.       *)
predicate-step = inline-step NEWLINE "{" NEWLINE { request-block } NEWLINE "}" ;
request-block  = "  " request-label ":" NEWLINE { criterion } ;   (* Include: / Omit: *)
criterion      = "    " field-ref " → " operator-value ;   (* "→" delimits find *)
(* criteria here and sort items inside a SortList sub-block ("field → Ascending") *)

bracket-body   = item { " ; " item } ;
item           = positional-item | label ": " value | label " = " value
               | inline-calc-field ;
(* A POSITIONAL item carries no label — it is the step's subject (the field    *)
(* being set, the script being called). HOW MANY a step takes, and whether it  *)
(* takes any, is per-step and is NOT derivable from this grammar. Copy the     *)
(* shape from that same step in text you were given or an example here.        *)
positional-item = value ;
(* A block-item is one logical item; items are separated by a trailing " ;" on  *)
(* the last line of the item (mirroring bracket-body's " ; ").                   *)
(* A sub-block groups nested items under a labeled brace.                       *)
block-item     = ( "  " item ) | fenced-calc | sub-block ;
sub-block      = "  " sub-label " {" NEWLINE { block-item } NEWLINE "  }" ;
(* sub-label is per-step (e.g. "Target fields", "SortList(value=1)", a Query);   *)
(* its inner item grammar is per-step — copy it from an example.                 *)

(* An inline calc/value slot is OPAQUE: it runs to the line's TERMINAL "]".    *)
(* Any " ; ", "]", "{" or "}" INSIDE it is literal calc data — you may write  *)
(* them freely there. Never place an option item AFTER such a slot: text       *)
(* there is part of the value.                                                 *)
inline-calc-field = label ": " calc-text-to-terminal-bracket ;

fenced-calc    = label ":" NEWLINE open-fence NEWLINE calc-body NEWLINE close-fence ;
(* When a multi-line calc is one item of an INLINE bracket body, the step does *)
(* NOT become a block: the header line keeps every earlier item and ends in    *)
(* the calc's label when the calc has one in the one-line form ("Set Variable  *)
(* [ $x ; Value:") or in " ;" when it has none ("Set Field [ T::F ;"); the     *)
(* fence opens on the NEXT line, and the CLOSING fence line carries the        *)
(* step's terminal " ]". Set Variable without "Value:" is accepted too.        *)
trailing-fence-step = step-name " [ " { item " ; " } label ":" NEWLINE
                      open-fence NEWLINE calc-body NEWLINE close-fence " ]"
                    | step-name " [ " { item " ; " } NEWLINE
                      open-fence NEWLINE calc-body NEWLINE close-fence " ]" ;
(* First form: a LABELED calc (Set Variable's Value:) — the label ENDS the      *)
(* header line, on that SAME line, never on a line of its own. Second form:    *)
(* an UNLABELED calc (Set Field) — the header ends in " ;".                    *)
(* WRONG: a bare close-fence with the "]" on its own next line — that refuses. *)
(* RIGHT: the closer line IS "``` ]".                                     *)
(*     Set Field [ T::F ;          Set Field [ T::F ;                          *)
(*     ```                          ```                                  *)
(*     $x & "!"                    $x & "!"                                    *)
(*     ```          <- WRONG        ``` ]        <- RIGHT                *)
(*     ]                                                                       *)
(* WRONG: the label on a line of its own.  RIGHT: the label ends the header.  *)
(*     Set Variable [ $x ;                 Set Variable [ $x ; Value:          *)
(*     Value:                              ```                                 *)
(*     ```                                $x & "!"                             *)
(*     $x & "!"                            ``` ]                               *)
(*     ``` ]                                                                 *)
(* A fence is THREE OR MORE backticks; the closer repeats the opener's run     *)
(* exactly — never shorten or lengthen a fence you were given. The cr marker   *)
(* appears ONLY on the opener; a "```cr" closer refuses. Fences exist     *)
(* only in the two positions above (after a "label:" header / after a lone     *)
(* "#"). A bare fence line anywhere else refuses.                              *)
open-fence     = backtick-run [ "cr" ] ;   (* cr fences: copy only, rule 6 *)
close-fence    = backtick-run ;
backtick-run   = "```" { "`" } ;

comment        = "# " text                                (* single line *)
               | "#" NEWLINE open-fence NEWLINE text NEWLINE close-fence ;
(* A multi-line comment uses the PLAIN fence; "#" followed by a ```cr     *)
(* opener refuses. Write the space after "#". A comment body may itself start  *)
(* with "#" — "# ##### section #####" is one line and is safe to write.        *)
disabled       = "// " ( comment | step ) ;               (* a step the user turned off *)

preserve       = [ step-name "  " not-yet-pretty-marker NEWLINE ] preserve-block ;
(* Both forms occur: a header line above the block, or the bare block alone.   *)
preserve-block = ">>> preserved-fmxml" NEWLINE raw-fm-xml NEWLINE "<<<" ;

(* Whole-script wrappers. The flag suffix is BRACKETED and " ; "-separated     *)
(* (the labels below are the complete set; every flag may be written On or     *)
(* Off, and omitted flags may simply be left out). The opening "{" always      *)
(* stands ALONE on the line AFTER the header — never on the header line; "}"   *)
(* alone on a line closes the body. A Script body holds step renderings only   *)
(* (wrappers never nest inside a Script); a Folder body holds Scripts, nested  *)
(* Folders, and bare preserve-blocks.                                          *)
whole-script   = script-block | folder-block | preserve-block ;
script-block   = "Script " quoted-name [ script-flags ]
                 NEWLINE "{" NEWLINE { step-rendering } NEWLINE "}" ;
folder-block   = "Folder " quoted-name [ folder-flags ]
                 NEWLINE "{" NEWLINE { script-block | folder-block | preserve-block }
                 NEWLINE "}" ;
script-flags   = " [ " script-flag { " ; " script-flag } " ]" ;
script-flag    = ( "in menu" | "Siri visible" | "full access" ) ": " toggle ;
folder-flags   = " [ " folder-flag { " ; " folder-flag } " ]" ;
folder-flag    = ( "in menu" | "collapsed" ) ": " toggle ;

toggle         = "On" | "Off" ;
step-name      = catalog-name ;    (* an exact catalog name; see the list below *)

(* Opaque nonterminals — their content is calc/reference DATA or is per-step    *)
(* by example, so they are not expanded here: catalog-name, label, sub-label,   *)
(* request-label, field-ref, operator-value, value, text, quoted-name,          *)
(* calc-body, raw-fm-xml, calc-text-to-terminal-bracket,                        *)
(* not-yet-pretty-marker. One quoted-name rule: an embedded quote is escaped    *)
(* BACKSLASH-style — Script "Say \"Hi\"" — and a literal backslash as \\.     *)
(* SQL-style doubling of the quote character refuses.                           *)

Step names

A step name must match this list exactly; any other name refuses. Names are separated by ·; a line break also separates — no name spans a line break. The 216 names:

# (comment) · AVPlayer Play · AVPlayer Set Options
AVPlayer Set Playback State · Add Account · Adjust Window
Allow Formatting Bar · Allow User Abort · Append PDF · Arrange All Windows
Beep · Cancel PDF · Change Password · Check Found Set · Check Record
Check Selection · Clear · Close Data File · Close File · Close PDF
Close Popover · Close Window · Commit Records/Requests · Commit Transaction
Configure AI Account · Configure Local Notification
Configure Machine Learning Model · Configure NFC Reading
Configure Persistent Data · Configure Prompt Template
Configure RAG Account · Configure Region Monitor Script
Configure Regression Model · Constrain Found Set · Convert File · Copy
Copy All Records/Requests · Copy Record/Request · Correct Word
Create Data File · Create PDF · Cut · Delete Account · Delete All Records
Delete File · Delete Portal Row · Delete Record/Request · Dial Phone
Duplicate Record/Request · Edit User Dictionary · Else · Else If
Enable Account · Enable Touch Keyboard · End If · End Loop
Enter Browse Mode · Enter Find Mode · Enter Preview Mode
Execute FileMaker Data API · Execute SQL · Exit Application · Exit Loop If
Exit Script · Export Field Contents · Export Records · Extend Found Set
Find Matching Records · Fine-Tune Model · Flush Cache to Disk
Flush Web Viewer Cookies · Freeze Window · Generate Response from Model
Get Data File Position · Get File Exists · Get File Size · Get Folder Path
Go to Field · Go to Layout · Go to List of Records · Go to Next Field
Go to Object · Go to Portal Row · Go to Previous Field
Go to Record/Request/Page · Go to Related Record · Halt Script · If
Import Records · Insert Audio/Video · Insert Calculated Result
Insert Current Date · Insert Current Time · Insert Current User Name
Insert Embedding · Insert Embedding in Found Set · Insert File
Insert Image Caption · Insert Image Captions in Found Set · Insert PDF
Insert Picture · Insert Text · Insert from Device · Insert from Index
Insert from Last Visited · Insert from URL · Install Menu Set
Install OnTimer Script · Install Plug-In File · Loop · Modify Last Find
Move/Resize Window · New File · New Record/Request · New Window
Omit Multiple Records · Omit Record · Open Data File · Open Edit Saved Finds
Open Favorites · Open File · Open File Options · Open Find/Replace
Open Help · Open Hosts · Open Manage Containers · Open Manage Data Sources
Open Manage Database · Open Manage Layouts · Open Manage Themes
Open Manage Value Lists · Open PDF · Open Record/Request
Open Script Workspace · Open Settings · Open Sharing · Open Transaction
Open URL · Open Upload to Host · Paste · Pause/Resume Script
Perform AppleScript · Perform Find · Perform Find by Natural Language
Perform Find/Replace · Perform JavaScript in Web Viewer · Perform Quick Find
Perform RAG Action · Perform SQL Query by Natural Language · Perform Script
Perform Script on Server · Perform Script on Server with Callback
Perform Semantic Find · Print · Print PDF · Print Setup · Re-Login
Read from Data File · Recover File · Refresh Object · Refresh Portal
Refresh Window · Relookup Field Contents · Rename File
Replace Field Contents · Reset Account Password · Revert Record/Request
Revert Transaction · Save Records as Excel · Save Records as JSONL
Save Records as PDF · Save Records as Snapshot Link · Save a Copy as
Save a Copy as Add-on Package · Save a Copy as XML · Scroll Window
Select All · Select Dictionaries · Select Window · Send DDE Execute
Send Event · Send Mail · Set AI Call Logging · Set Data File Position
Set Dictionary · Set Error Capture · Set Error Logging · Set Field
Set Field By Name · Set Layout Object Animation · Set Multi-User
Set Next Serial Value · Set Revert Transaction on Error · Set Selection
Set Session Identifier · Set Use System Formats · Set Variable
Set Web Viewer · Set Window Title · Set Zoom Level · Show All Records
Show Custom Dialog · Show Omitted Only · Show/Hide Menubar
Show/Hide Text Ruler · Show/Hide Toolbars · Sort Records
Sort Records by Field · Speak · Spelling Options
Trigger Claris Connect Flow · Truncate Table · Undo/Redo · Unsort Records
View As · Write to Data File

3. Reserved tokens

Each literal below is grammar, never field or calc data:

TokenMeaning
```calc / preserve fence delimiter (the ```cr opener marks a copy-only fence — rule 6)
>>> preserved-fmxmlopens a preserve-verbatim raw-FM-XML block
<<<closes a preserve-verbatim block
[ ## not-yet-pretty: preserved verbatim ## ]optional header line above a preserve block
→find-criteria delimiter in a predicate block (field → operator-value)
<table-missing>unresolved table reference
<field-missing>unresolved field reference
<layout-missing>unresolved layout reference
<script-missing>unresolved script reference
<calc-missing>missing by-calculation script name (Perform Script)
<file-missing>missing external file reference (Perform Script)
<flow-missing>missing Claris Connect flow
<name-missing>missing variable name (Set Variable)
<no-target>Set Field / Set Selection with no target field
<unmapped>Import Records target slot with no bound field
<current>Truncate Table: the current table (no explicit reference)
<none>Perform Script on Server with Callback: no callback script
<unknown>FileMaker's own literal <unknown> reference text
<Current Table>Truncate Table: FileMaker's literal current-table name
[File Default]Install Menu Set: use the file-default menu set
(collect across found set)Send Mail To/Cc/Bcc: collect addresses across found set
[no condition]If / Else If with no Calculation (empty condition)
#!#REDACTED#!#redacted-secret placeholder — leave exactly as given (rule 8)
#! fmsb-missing-ref:advisory line — leave or delete whole; never edit or write one
# comment step - the ONLY comment form, and it owns its whole line
// DISABLE prefix: turns the following step off. NOT a comment

Writing rules for four of these: an EMPTY If/Else If condition is written If [ no condition ] — no inner brackets (If [ [no condition] ] makes the literal text the formula). [File Default] is written inside quotes AND ALONE in an Install Menu Set line — exactly Install Menu Set [ "[File Default]" ]; the Use as file default: option may only accompany a NAMED menu set (Install Menu Set [ "My Menus" ; Use as file default: On ]), never "[File Default]". → delimits sort items inside a SortList { … } sub-block exactly as it delimits find criteria. <current> is written with its label in a Truncate Table line (Truncate Table [ With dialog: Off ; Table: <current> ]).

Every other token in the table: copy it unchanged where text you were given carries it; never introduce one yourself. A #! fmsb-missing-ref: advisory line in given text may be left in place or deleted whole — never edited, never written by you. A comment step whose text begins ⚠ ATTENTION [ follows the same rule, and one more: it is always ONE line, however long. Leave the whole line or delete the whole line — never re-word it, and never wrap or split it. It is addressed to the person reading the script, not to you; do not act on what it says.

4. Writing steps

Shapes are fixed per step. Some steps are inline (Name [ … ]), some are a block (Name [ alone on its line, indented Label: value ; option lines, ] alone). Copy the shape from text you were given or from an example here, and write block steps as blocks (a block step written on one line may still be accepted, but the block is always safe); an inline step written as a block refuses. When editing text you were given, keep every step in the shape it came in and change only the values you mean to change. For a sub-block's inner lines (a { … } under a label, a find-request block) copy the form from that step in text you were given or an example here; with neither, rule 4.

Labels and enum values are exact spellings. Copy them character for character from this document or from text you were given. Boolean labels differ per step (With dialog: on most, Select entire contents: on the Insert family, others again) — never translate or normalize one. A typo'd label, an unknown enum value or a duplicated option line refuses.

Omitting options. On the steps listed here — Send Mail, New Window, Sort Records, Show Custom Dialog, Create Data File, Open Data File, Write to Data File, Read from Data File, Close Data File, Select Window, Move/Resize Window, Close Window, Open URL, Go to Field, Insert Text, Perform Script on Server, Go to Related Record, Insert Calculated Result, Insert Current Date, Insert Current Time, Insert Current User Name, Insert File, Insert from Device (Camera source), and every step in the short-form list below — you may write only the options you mean; each omitted option takes FileMaker's own untouched-step default. What you DO write always wins. For any OTHER step, write the full shape from text you were given or an example — never rely on omission there.

Step [ ] — empty brackets mean "FileMaker's defaults". FileMaker's own Script Workspace displays an untouched option-bearing step that way (Set Field [ ], Go to Field [ ], Perform Quick Find [ ]), and that form is accepted for every step: it builds the step exactly as FileMaker creates it, with every option at its factory value. If [ ], Else If [ ] and Exit Loop If [ ] are FileMaker's own display of a step whose condition is empty: accepted, with a warning that the condition is empty; Loop [ ] is FileMaker's default loop. The steps FileMaker shows with no brackets at all take none: Else [ ], End If [ ] and End Loop [ ] refuse.

The bare name and [ ] are NOT always the same step. For most steps they are, but two differ, and the difference is real state:

  • Enter Find Mode is the step with no pause at all; Enter Find Mode [ ] is FileMaker's default, which PAUSES. (FileMaker reads an absent pause setting as Off — it does not fill in its default — so the bare name really does mean "do not pause".)
  • Close Window closes the current window with no target set; Close Window [ ] is FileMaker's default, which limits to windows of the current file.

Write the bare name when you mean the minimal step, [ ] when you mean "however FileMaker would have made it". If you are unsure, write the options out.

Short forms that parse (write them exactly like this):

  • Perform Find · Show All Records · Omit Record · Exit Script · Constrain Found Set · Extend Found Set · Enter Find Mode · Close Window: the bare name alone. Other steps bare-name only if you have seen them written bare in given text; otherwise rule 4.
  • Commit Records/Requests [ With dialog: Off ]
  • Enter Find Mode [ Pause: Off ]
  • Go to Layout [ "Name" ]
  • Go to Record/Request/Page [ First ] (also Last, Previous, and Next ; Exit after last: On)
  • Set Variable [ $x ; Value: … ]
  • Set Field [ Table::Field ; <calc> ] — the calculation is POSITIONAL: no Value: label here (that label belongs to Set Variable; written here it becomes part of the formula).
  • Set Field By Name [ <name-calc> ; <value-calc> ] — the two calc slots split at the top-level ;; separators inside parentheses or quotes are data.
  • Perform Script [ "Name" ; Parameter: … ]
  • Exit Script [ Result: … ] — and with no result, bare Exit Script or Exit Script [ Text Result: ].
  • Show Custom Dialog [ <title-calc> ; <message-calc> ] — the two-item positional dialog (default buttons). The same two items, one per line, are also accepted as a block on push (the message may run on to more lines). For buttons and input fields use the labeled block form in the examples.
  • Open URL [ "https://…" ] — and the browser checkbox is FileMaker's own In external browser token: write it when the box is checked, omit it entirely when it is not (Open URL [ With dialog: On ; In external browser ; "https://…" ]).
  • Go to Field [ Table::Field ]
  • Pause/Resume Script [ Duration (seconds): 2 ]
  • Select Window [ Current window ] / Select Window [ by name: "Name" ]
  • Perform Script on Server [ "Name" ; Parameter: … ; Wait for completion: Off ] — the wait item may sit first or last; omitted means On.
  • An EMPTY Parameter: means no parameter at all, on the whole Perform Script family — it is FileMaker's own display for an unset one. Write Parameter: "…" when you mean a parameter that is literally blank.
  • Perform Script on Server with Callback [ Server script: "Name" ] — the one-line form; Wait for callback: and Callback: may be omitted and take FileMaker's fresh-step state (Continue / <none>).
  • The whole If / Else If / Else / End If / Loop / End Loop family, with the condition inline: If [ Get ( FoundCount ) > 0 ].

FileMaker's own display spellings that are also accepted: Exit Script [ Text Result: … ] · New Window's Name: / Style: / Using layout: labels · Current Window capital-W on the window steps · Duration (seconds): on Pause/Resume Script · a bare Select token ALONE in the brackets on the select-family steps (= Select entire contents: On; in any longer item list write the full label instead — except Insert Calculated Result, where the calc may follow it: [ Select ; <calc> ]) · a Specified: From list item on the Perform Script family · Send Mail's Send via E-mail Client line (do not combine it with Via SMTP: On or Via OAuth: On) · a dialog-only sort written inline (Sort Records [ With dialog: On ]) · the positional display forms Speak [ <calc> ], Perform Quick Find [ <calc> ], Set Selection [ <field> ], Set Next Serial Value [ <field> ; <calc> ], Omit Multiple Records [ With dialog: On/Off ; <count> ] and Go to Object [ Object Name: <calc> ] · Install OnTimer Script's own line, which puts the quoted script name FIRST with no label and Interval: LAST (Install OnTimer Script [ "Name" ; Parameter: <calc> ; Interval: <calc> ]) — omit Parameter: entirely when there is none, as an empty Parameter: is refused on this step, and Install OnTimer Script [ Interval: <calc> ] is accepted with no name · Select Window's Name: label with an optional bare Current file token (write the token for On, omit it for Off: Select Window [ Name: <calc> ; Current file ]) · a quoted NAME may use the curly double quotation marks “ ” in place of the straight " — Perform Script [ “Load Saxon” ]. Both ends must match: a name opened with one and closed with the other is refused. It is the outer pair only that may be curly; whatever sits between them is kept exactly as written, so Perform Script [ ““Saxon”” ] names the script “Saxon”, and only that pair of characters is accepted. The steps that take it are Perform Script, Perform Script on Server, Perform Script on Server with Callback, Go to Layout, Install Menu Set and Truncate Table, in the one-line form, plus the names after from file:, Server script:, Callback: and Table:, the block form of the steps that HAVE one (Perform Script, Perform Script on Server, Perform Script on Server with Callback), and the Script "Name" / Folder "Name" wrapper headers.

Nowhere else. In every OTHER name slot a curly mark is literal text and becomes part of the name: Set Variable [ “$x” ; Value: 1 ] names the variable “$x”, not $x. A calculation is the same — Parameter: and every other calculation slot take a straight " as FileMaker's own string delimiter, and a curly mark inside one is data.

NOTE where escaping applies. In the Script "Name" / Folder "Name" wrapper headers, and on a block-form name line, a straight quotation mark inside the name is written \" and a literal backslash \\. In the ONE-LINE bracket forms the straight border is taken LITERALLY: everything between the outer pair is the name exactly as written, so write Perform Script [ "S"p" ], not Perform Script [ "S\"p" ], and a backslash there is part of the name. In a curly border the mark is always written plainly.

Every option label is FileMaker's own word, and the same underlying flag can be named differently on different steps. Three that a generator gets wrong by analogy:

  • Open File [ Open hidden: On|Off ; file: "…" ; path: <path> ] — the flag is shown in BOTH states. Write the file: label, the quoted name and the path: item whenever you have the path; a file reference binds by NAME, and the path is what lets FileMaker add a data source it does not already have. The name ALONE is also accepted, with or without the label and with or without the flag (Open File [ Open hidden: On ; "Name" ], Open File [ "Name" ]), and binds to an existing data source of that name; an omitted Open hidden: is Off, FileMaker's own default. Close File carries no flag (Close File [ file: "…" ; path: <path> ]); Re-Login puts the reference after its own With dialog: On|Off; and Perform Script's from file: takes the same path: item.
  • Constrain Found Set [ Restore ; Find without indexes ] — both are BARE tokens, written only when on, and Restore comes first.
  • Perform Find [ Restore ] — the bare token, never Restore: On; on this step the saved find's { … } request block must follow on the next lines. Write bare Perform Find when there is no saved find.

The rest of the vocabulary follows the same rule. Write the word FileMaker's own line or dialog shows, never a tag name:

  • Flags that FileMaker shows only when on are BARE tokens, written only when on and omitted when off: Verify SSL Certificates, Do not automatically encode URL, Skip Indexes, Allow Folder Creation, Expire password, No style, Stream, Agentic mode, Table, Delete, Match case, Match whole words only, Skip auto-enter options. Convert File's Open File is such a token too (write it to open the file after conversion). Flags FileMaker shows in both states keep On|Off: Current file only:, Lock:, and Set Error Logging's own [ On ] / [ Off ].
  • A Parameters: item on Insert Embedding, Perform Find by Natural Language, Perform SQL Query by Natural Language and Generate Response from Model IS the Parameters checkbox: write it (empty or with the calc) to tick the box, omit it to clear it. Likewise the Print PDF items Password:, Save print options to: and Use print options from:, written inside its Print settings: { … } block, are their own checkboxes — present means on.
  • Popup choices are the popup's words: Sort Records by Field [ Descending ] (or Ascending / Associated value list), Find Matching Records [ Constrain ] (Replace / Extend), Configure Regression Model [ Action: Save Model ; Algorithm: Random Forest ], Configure Region Monitor Script [ Monitor: Geofence ], Set Zoom Level [ Lock: Off ; Zoom In ] (or a percentage such as 150%), Training Data: File on Fine-Tune Model, and Authenticate via: Google on Add Account (the popup's entries; Microsoft Entra ID (Group) / Custom OAuth (Group) for the Group radio). Any other spelling is refused, not guessed.
  • Perform Find/Replace [ With dialog: On ; Find Next ] is the whole line for a fresh step (Replace / Replace All / Replace & Find are the other Perform words). The dialog's other settings appear only when they differ from the fresh step: Match case, Match whole words only, Search across: Current record/request, Search within: Current field, Direction: Backward or Direction: All.
  • Replace Field Contents with serial numbers: Serial numbers alone means the field's entry options; add ( Initial value: 1 ; Increment by: 1 ) for custom values and Update serial number in Entry Options inside the same parentheses to tick that box; the separate Skip auto-enter options token means auto-enter is NOT performed (FileMaker's own default for this dialog).

New Window / Go to Related Record / Go to List of Records window options are WORDS. The Dim parent:, Toolbars: and Menu bar: lines carry the window's real state; write Yes/No. A Styles: line holding a raw number appears only where a window carries a setting the words cannot express — copy it through untouched if you see one, and never invent one.

Other rules:

  • Finish every block you open. A step written in the block form must reach its closing ] on its own line (or ``` ] when the body ends in a fenced calculation). A block left unclosed is refused outright rather than guessed at — if your answer is cut off mid-step, the whole push is rejected, not half-applied.
  • To disable a step, prefix ONLY its first line with // — a block step's inner lines and closer stay unprefixed.
  • Quote literal text values with "…" (FileMaker calc syntax; backslash escapes for embedded quotes). Field references and variables are bare.
  • text: on Insert Text is LITERAL text — no quotes, not a calculation. A multi-line literal is fenced exactly like a multi-line calculation (rule 5): text: alone, the fence, the lines, the closing fence.

5. Examples

Each block below is exact:

Inline step (bracket body, ;-separated items)

Set Variable [ $total ; Value: $x + 1 ]

Inline calc is opaque to the terminal ] (embedded ; is data)

Set Variable [ $v ; Value: List ( 1 ; 2 ; 3 ) ]

Fenced multi-line calc (``` opener; body verbatim, block-in-brackets)

If [
```
a
and b
``` ]

Fenced multi-line calc as ONE ITEM of an inline body (the common shape)

Set Field [ Invoice::Total ;
```
Let ( [
  base = 1 ;
  tax = base * 2
] ;
  base + tax
)
``` ]

Comment — single line (the multi-line form uses a plain fence after a lone #)

# set up the loop

Disabled step (// prefix)

// Perform Script [ "Child" ; Parameter: "param" ]

Whole-script wrapper (Script "name" { … })

Script "MyScript"
{
    # set up
    Set Variable [ $i ; Value: 1 ]
}

Preserve-verbatim block (copy byte-for-byte; never edit inside)

Some Future Step  [ ## not-yet-pretty: preserved verbatim ## ]
>>> preserved-fmxml
<Step enable="True" id="99999" name="Some Future Step"><MysteryChild weird="1">data</MysteryChild></Step>
<<<

Minimal generation forms

Write these shapes exactly:

Send Mail — recipient/subject/message is enough (e-mail client mode; configure the account in FileMaker)

Send Mail [
  To: "ops@example.com" ;
  Subject: "Nightly import" ;
  Message: "See attached"
]

New Window — name and layout are enough (Document style, standard controls)

New Window [
  Layout: "Orders" ;
  Window Name: "Report"
]

Set Window Title — the current window and the new name; the file flag at its factory value

Set Window Title [ Current window ; new name: "Invoices" ; Current file only: On ]

Sort Records — the sort order is enough (no dialog, order restored)

Sort Records [
  SortList {
    Orders::Customer → Ascending
    Orders::Total → Descending
  }
]

Show Custom Dialog — block form, any Button 1..3 subset

Show Custom Dialog [
  Title: "Delete?" ;
  Message: "This cannot be undone" ;
  Button 1 (commit): "Delete" ;
  Button 2: "Cancel"
]

Show Custom Dialog — input fields: the target on the Input N: line, the label on the next line, (password) for a masked input, (empty) for an unused slot

Show Custom Dialog [
  Title: "Sign in" ;
  Message: "Enter your account" ;
  Button 1 (commit): "OK" ;
  Button 2: "Cancel" ;
  Input 1: $account
    Label: "Account" ;
  Input 2 (password): $password
    Label: "Password" ;
  Input 3: (empty)
]

Data files — one omitted option each (Create folders / Write as / Read as take factory values); Open Data File is a block

Create Data File [ Target file: $path ]
Open Data File [
  Source file: $path ;
  Target: $fileID
]
Write to Data File [ File ID: $fileID ; Data source: $text ]
Read from Data File [ File ID: $fileID ; Target: $out ]
Close Data File [ File ID: $fileID ]

Export Records — BLOCK form; the four flags at their factory values plus the target file (a variable holding a path, or a filemac:/… path)

Export Records [
  With dialog: Off ;
  Create folders: On ;
  Auto-open: Off ;
  Create email: Off ;
  Target file: $path
]

Control flow — conditions inline, bodies indented 4 per level

If [ Get ( FoundCount ) > 0 ]
    Loop [ Flush: Always ]
        Set Field [ Invoices::Status ; "Overdue" ]
        Go to Record/Request/Page [ Next ; Exit after last: On ]
    End Loop
End If

Find pattern — enter find mode, set criteria as data, perform

Enter Find Mode [ Pause: Off ]
Set Field [ Invoices::Status ; "Open" ]
Set Field [ Invoices::Due_Date ; "<" & Get ( CurrentDate ) ]
Perform Find
Go to Related Record [
  From table: "Items" ;
  Using layout: "Items"
]
Go to Related Record [
  Show only related records ;
  Match current record only ;
  From table: "Items" ;
  Using layout: "Items"
]

Subscripts and results

Perform Script [ "Refresh_Tokens" ; Parameter: "force" ]
If [ Get ( ScriptResult ) = -1 ]
    Exit Script [ Result: -1 ]
End If

Everyday one-liners — the URL / field target / duration slot is enough (omitted options take factory values)

Open URL [ "https://status.example.com" ]
Go to Field [ Invoices::Status ]
Pause/Resume Script [ Duration (seconds): 2 ]

Windows — select by name, resize with just the dimensions you mean (Current window is the factory target)

Select Window [ by name: "Reports" ]
Move/Resize Window [
  Height: 600 ;
  Width: 900
]

Perform Script on Server — FileMaker's own display order; omit the wait item for the factory On

Perform Script on Server [ "Nightly Rebuild" ; Parameter: "full" ; Wait for completion: Off ]

Insert Text — BLOCK form; text: is LITERAL text (no quotes, not a calculation), Target: is a field or variable

Insert Text [
  text: Reviewed - do not edit ;
  Target: Orders::Note
]

6. If the user relays a message

  • A refusal naming one line (push failed at line N: …): fix that line and resubmit — everything before it was fine. (A Script body opens with { alone on the line after the header and closes with } alone; there is no End Script.)
  • A warning (line N was understood differently / line N is not in the converted result / near line N the result carries an extra line / push-verify: line N - …): the text WAS converted, but line N may not mean what you intended — recheck it against §4 and correct it if so.
  • A refusal naming no line (push refused — the converted XML did not survive …): not a problem with your text; tell the user to report it as a bug. Your text is unchanged.

It is always better to leave a step alone than to write text you are unsure of. When text you were given disagrees in shape with this document, copy the given text's shape.