.cursor/skills/trace/SKILL.md
Trace references to a FileMaker object across the entire solution. Supports usage reports ("where is this field used?"), impact analysis ("what breaks if I rename this?"), and dead object scans ("show unused fields/scripts"). Use when the developer says "trace", "find references", "where is X used", "impact of renaming", "unused fields/scripts", "dead code", "what references X", or "is X used anywhere".
npx skillsauth add petrowsky/agentic-fm traceInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This skill traces references to FileMaker objects (fields, scripts, custom functions, layouts, value lists) across an entire solution. It combines a deterministic Python engine (agent/scripts/trace.py) for fast, exhaustive scanning with agentic correlation for edge cases that require judgment.
trace.py)Scans all solution data sources and builds agent/context/{solution}/xref.index — a compact cross-reference index. Supports three commands:
python3 agent/scripts/trace.py build -s "Solution Name" # build xref.index
python3 agent/scripts/trace.py query -s "Solution Name" -t TYPE -n "Name" # query refs
python3 agent/scripts/trace.py dead -s "Solution Name" -t TYPE # find unused objects
Query types: field, script, layout, value_list, custom_func, table_occurrence
Dead types: fields, scripts, custom_functions, layouts, value_lists
The query and dead commands read from the pre-built xref.index file — they do not re-scan source files. This means queries are fast (single file read) and the expensive build step only needs to run once per schema change.
Adds judgment for things static analysis cannot handle: ExecuteSQL strings, dynamic references, ambiguity resolution, severity classification, and false positive filtering.
| Source | What it finds |
|--------|---------------|
| fields.index — auto-enter and calc columns | Field-to-field references, custom function calls in calcs |
| scripts_sanitized/*.txt | Field refs (Set Field, Set Variable, If, etc.), layout refs (Go to Layout), script refs (Perform Script), CF calls |
| custom_functions_sanitized/*.txt | TO::Field refs, CF-to-CF calls |
| context/{solution}/layouts/*.json | Field placements and button scripts on layouts |
| relationships.index | Join field references |
| value_lists/*.xml | Field-based value list sources |
All field references are normalized to canonical form (BaseTable::FieldName) using table_occurrences.index for TO resolution. The original TO is preserved in the reference context.
Run all of these checks in a single parallel batch — they are independent:
# 1a. Discover solutions
ls agent/context/
# 1b. Check xref.index existence and age
stat agent/context/{solution}/xref.index
# 1c. Check layout summaries exist
ls agent/context/{solution}/layouts/ 2>/dev/null | head -1
# 1d. Check webviewer status (for later visualization offer)
curl -s http://localhost:8765/webviewer/status
Solution resolution:
fmcontext.sh.xref.index caching — avoid unnecessary rebuilds:
xref.index exists and the developer has not mentioned schema changes (new fields, renamed tables, new scripts, etc.), use it directly — skip the build. This is the single biggest time saver.xref.index is missing, build it: python3 agent/scripts/trace.py build -s "{solution}"python3 agent/scripts/trace.py build -s "{solution}"Layout summary dependency: If agent/context/{solution}/layouts/ is empty or missing, warn and suggest:
python3 agent/scripts/layout_to_summary.py --solution "{solution}"
Then rebuild xref.index.
Save the webviewer status result for Step 5b — do not check again later.
| Request pattern | Mode | Action |
|----------------|------|--------|
| "Where is X used?" / "Find references to X" / "Trace X" | Usage | Run query for the named object |
| "What breaks if I rename X?" / "Impact of changing X" | Impact | Run query for the object + agentic severity analysis |
| "Show unused fields" / "Dead code" / "Unused scripts" | Dead | Run dead for the specified type |
| "What does X reference?" / "Dependencies of X" | Outbound | Run query --direction outbound |
The engine query and the agentic grep passes are independent — run them in the same parallel batch. This is the core optimization: instead of query-then-grep sequentially, issue all calls simultaneously.
Run all of these in a single message with parallel tool calls:
# 3a. Deterministic query
python3 agent/scripts/trace.py query -s "{solution}" -t {type} -n "{name}"
# 3b. ExecuteSQL string scan (agentic — only for field/table traces)
grep -rl "ExecuteSQL" "agent/xml_parsed/scripts_sanitized/{solution}/" --include="*.txt"
# 3c. Dynamic reference scan (agentic — only for field/script traces)
grep -rn "GetField\|GetFieldName\|Evaluate\|Perform Script by Name" "agent/xml_parsed/scripts_sanitized/{solution}/" --include="*.txt"
Skip 3b/3c when they are not relevant to the object type (e.g., skip ExecuteSQL scan when tracing a layout).
python3 agent/scripts/trace.py dead -s "{solution}" -t {type}
Add --verbose to include low-confidence results (system fields, globals, summaries). No parallel agentic grep needed — false positive filtering (Step 4e) uses the dead output directly.
For a table rename or broad impact analysis, run all queries in parallel:
# 3a. Query the primary object
python3 agent/scripts/trace.py query -s "{solution}" -t {type} -n "{name}"
# 3b. Query related objects (e.g., table as TO for table renames)
python3 agent/scripts/trace.py query -s "{solution}" -t table_occurrence -n "{table_name}"
# 3c. ExecuteSQL scan
grep -rl "ExecuteSQL" "agent/xml_parsed/scripts_sanitized/{solution}/" --include="*.txt"
# 3d. Dynamic reference scan
grep -rn "GetField\|GetFieldName\|Evaluate" "agent/xml_parsed/scripts_sanitized/{solution}/" --include="*.txt"
For a table rename affecting many fields, run one query per affected field — all in parallel.
python3 agent/scripts/trace.py query -s "{solution}" -t {type} -n "{name}" --direction outbound
Analyze the results gathered in Step 3. All grep output is already available — this step is pure analysis, no additional tool calls needed unless a specific ExecuteSQL script needs closer reading.
From the grep results (3b), for each script containing ExecuteSQL:
fields.indexBatch reads: If multiple scripts matched, read the relevant sections in parallel.
From the grep results (3c), flag any script step using:
Note the variable source so the developer can trace manually. These cannot be resolved statically.
When the same field name exists in multiple tables (e.g., Status in Clients, Invoices, and Products), unqualified references in calcs are ambiguous. Use layout context and TO context to disambiguate where possible.
| Severity | Meaning | Examples | |----------|---------|----------| | BREAK | Direct reference that will error | Set Field, Set Variable, If condition referencing the renamed object | | WARN | Indirect reference that may fail | ExecuteSQL string literal, GetField with concatenated name | | INFO | FM auto-updates on rename | Layout field placements, relationship graph join fields |
Review dead object results and filter:
Self (active even with no external refs)Format the combined results as a structured report appropriate to the mode:
Usage mode: Group by source type (field calcs, scripts, layouts, relationships, etc.) with counts.
Impact mode: Group by severity (BREAK, WARN, INFO) with specific locations and explanations.
Dead mode: Group by confidence (HIGH, MEDIUM, LOW) with counts and summary.
Use the webviewer status captured in Step 1d (do not re-check).
If "running": true, prompt the developer:
The webviewer is running. Would you like a visual diagram of these references?
If yes, generate a Mermaid diagram appropriate to the mode and push it:
Generate a flowchart LR centered on the target object, with subgraphs grouping referencing objects by type. For impact mode, color nodes by severity (red = BREAK, yellow = WARN, green = INFO).
flowchart LR
subgraph Fields
F1["Invoices::Client Name<br/>(calc)"]
end
subgraph Scripts
S1["Print Invoice<br/>(line 22: Set Field)"]
end
subgraph Layouts
L1["Clients Details"]
L2["Clients List"]
end
F1 -->|calc ref| TARGET["Clients::Name"]
S1 -->|Set Field| TARGET
L1 -->|field placement| TARGET
L2 -->|field placement| TARGET
style TARGET fill:#e74c3c,color:#fff
pie title Field Usage — Solution Name
"Referenced" : 94
"Unused (high)" : 4
"Unused (medium)" : 2
curl -s -X POST http://localhost:8765/webviewer/push \
-H "Content-Type: application/json" \
-d '{"type": "diagram", "content": "<mermaid source>", "repo_path": "<project root>"}'
Pipe-delimited, one line per reference:
# SourceType|SourceName|SourceLocation|RefType|RefName|RefContext
| Column | Description |
|--------|-------------|
| SourceType | field_calc, field_auto, script, layout, custom_func, relationship, value_list |
| SourceName | Canonical ID: Invoices::Client Name, Print Invoice (ID 158) |
| SourceLocation | Where: calc:Clients Primary::Name, line 14: Set Field, field placement |
| RefType | field, script, layout, value_list, custom_func, table_occurrence |
| RefName | Canonical (base table for fields): Clients::Name |
| RefContext | Detail: via TO "Clients Primary", same table, left side, empty |
Target tool calls from invocation to results presented:
| Mode | Without cache | With xref.index cached | |------|---------------|------------------------| | Usage | 3 (preflight + build, query+grep, report) | 2 (preflight+query+grep, report) | | Dead | 3 (preflight + build, dead, report) | 2 (preflight+dead, report) | | Impact | 4 (preflight + build, parallel queries+grep, reads, report) | 3 (preflight+queries+grep, reads, report) |
The key savings come from: (1) skipping build when xref.index exists, (2) running the deterministic query and agentic grep passes in the same parallel batch, (3) batching all preflight checks together, (4) caching the webviewer status from preflight instead of checking it after analysis.
Developer: "Where is Clients::Name used?"
ls agent/context/, stat xref.index, curl webviewer/status -- xref.index exists, skip buildtrace.py query -t field -n "Clients::Name" + grep -rl "ExecuteSQL" scripts_sanitized/ + grep -rn "GetField" scripts_sanitized/ -- all in one batchTool calls: 2 (preflight batch, query+grep batch) + report presentation
Developer: "Show me all unused fields"
ls agent/context/, stat xref.index, trace.py dead -t fields -- xref.index exists, run dead immediately alongside preflightInvoices::FoundCount and Line Items::FoundCount are unstored calcs for Get(FoundCount) — used only at runtime on layouts with the field presentTool calls: 1-2 (preflight+dead batch, optional layout check) + report presentation
Developer: "What breaks if I rename the Clients table to Companies?"
trace.py query -t field -n "Clients::*" for each field (or grep xref.index directly for all Clients:: refs)trace.py query -t table_occurrence -n "Clients"grep -rl "ExecuteSQL" scripts_sanitized/Clients table referencesTool calls: 3 (preflight, parallel queries+grep, parallel script reads) + report presentation
development
Generate a complete web application inside a FileMaker Web Viewer — self-contained HTML/CSS/JS styled with the FM theme, plus companion FM bridge scripts for bidirectional data flow. Use when the developer says "web viewer", "webviewer app", "HTML in FileMaker", "build web viewer", or when the layout-design skill delegates to the web-first output path. Recommended for modern, responsive UI, complex interactions (drag-and-drop, charts, rich text), or solutions considering future migration off FileMaker.
development
Analyze a FileMaker solution and produce a structured profile covering data model, business logic, UI layer, integrations, and health metrics. Uses on-disk pre-processing to handle solutions of any size without sending raw XML through the agent. Use when the developer says "analyze solution", "solution overview", "solution analysis", "solution profile", "solution spec", "what does this solution do", "solution summary", or wants a high-level understanding of an entire FileMaker solution.
development
Interactive setup wizard for agentic-fm. Detects what's already configured, walks the user through each remaining step, and verifies completion before proceeding. Use when the developer says "help me set up", "setup", "get started", "onboard", "first time setup", "install agentic-fm", "configure agentic-fm", or is clearly new to the project and needs guidance.
development
Generate a companion verification script that exercises a target script with known inputs and asserts expected outputs. Uses the fm-debug infrastructure to report pass/fail results back to the agent. At Tier 1 the developer runs the test script manually. At Tier 3 the agent deploys, runs, and reads results autonomously. Triggers on phrases like "test this script", "write a test", "verification script", "assert results", or "prove this works".