name: fmlint description: "Lint FileMaker scripts in fmxmlsnippet XML or human-readable format. Validates structure, naming conventions, references, best practices, and calculations. Tier 3 validates calculations against a live FM engine via AGFMEvaluation. Triggers on phrases like 'lint this', 'validate script', 'check conventions', 'run fmlint', or automatically after script generation." compatibility: "Tier 1 always available. Tier 2 requires CONTEXT.json. Tier 3 requires OData connectivity to a hosted FM solution."
FMLint — FileMaker Code Linter
Validate FileMaker scripts for structural correctness, naming conventions, reference integrity, best practices, and calculation validity.
Step 1: Determine what to lint
Identify the target:
- Just-generated script — lint the file in
agent/sandbox/that was most recently written - Specific file — lint a file the developer names explicitly
- All sandbox files — lint everything in
agent/sandbox/ - HR script text — lint human-readable script content directly (from webviewer or clipboard)
Step 2: Run FMLint
Run the linter from the project root:
# Lint a specific file
python3 -m agent.fmlint agent/sandbox/MyScript.xml
# Lint all sandbox XML files
python3 -m agent.fmlint agent/sandbox/
# JSON output (for programmatic use)
python3 -m agent.fmlint --format json agent/sandbox/MyScript.xml
# Force tier or disable rules
python3 -m agent.fmlint --tier 2 --disable N003,D002 agent/sandbox/
The linter auto-detects:
- Format (XML vs HR) from file content
- Tier from available context (CONTEXT.json → tier 2, OData → tier 3)
Step 3: Interpret results
Severity levels
| Level | Meaning | Action |
|---|---|---|
| ERROR | Will break in FileMaker | Must fix before deployment |
| WARNING | Likely bug or convention violation | Should fix |
| INFO | Style suggestion | Optional improvement |
| HINT | Minor recommendation | Informational only |
Rule categories
| Prefix | Category | Tier | Examples |
|---|---|---|---|
| S | Structure | 1 | Block pairing, XML well-formedness, step attributes |
| N | Naming | 1 | Unicode operators, variable naming, hard tabs |
| D | Documentation | 1 | PURPOSE comment, $README block |
| B | Best Practices | 1 | Error capture pairing, commit before nav |
| C | Calculations | 1/3 | Unclosed strings, unbalanced parens, live eval |
| R | References | 2 | Field/layout/script existence, ID matching |
Step 4: Fix issues
For each ERROR or WARNING:
- Read the diagnostic message and rule ID
- Apply the fix (the
fix_hintfield suggests how) - Re-run the linter to verify the fix
Common fixes:
- S005 (paired blocks): Add missing End If / End Loop / Commit Transaction
- N001 (operators): Replace
<>with≠,<=with≤,>=with≥ - N002 (variable naming): Use
$camelCase,$$ALL_CAPS,~camelCase - N004 (hard tabs): Replace leading spaces with tab characters in CDATA calculations
- D001 (purpose): Add
# PURPOSE: descriptionas the first step
Step 5: Tier 3 — Live calculation validation (optional)
When OData is configured in agent/config/automation.json and the developer approves:
- The linter extracts all calculation expressions from the script
- Calls AGFMEvaluation via OData for each unique expression
- Reports C004 errors for calculations that fail in the FM engine
Important: Always confirm with the developer before triggering OData calls:
FMLint found N calculations to validate against the live FM engine. Proceed?
This catches issues that offline analysis cannot — invalid field references, nonexistent custom functions, context-dependent calculation failures.
Step 6: Integration with script creation workflow
When used as part of the standard script creation workflow (CLAUDE.md steps 6-7):
- After writing fmxmlsnippet to
agent/sandbox/, run:python3 -m agent.fmlint agent/sandbox/<script_name> - Fix any ERROR-level diagnostics before deployment
- Review WARNING-level diagnostics with the developer
- Proceed to
deploy.pyonly after errors are resolved
The linter replaces validate_snippet.py as the primary validation tool while maintaining backward compatibility — validate_snippet.py continues to work for its original XML-only checks.