footprint always ran its dry run with the default 60 second limit, so macro.run with timeLimit 5 could run for over two minutes (a dry run, then another after a shift) and fail with "ran longer than 60 seconds". footprint now takes the run's clock and limit. make_way starts the run's clock before the dry runs, so the checks and the run share one limit, and macro.check takes timeLimit too.
7.3 KiB
Macros
Last updated: 2026-10-21 · Change: minor (running and checking macros:
macro.run,macro.check)
GridCraft macros are typed, declarative lists of commands, not VBA. Every step runs a GridCraft
command (the same ids the ribbon, CLI and MCP use) or one of three bounded control steps. A macro
declares the inputs it works on, runs as one undo step, rolls everything back on an error, checks
where its results will land before it writes them, and does not touch files without permission.
Agents run macros with macro.run like any other command.
This page describes the macro format, its tokens, and running and checking macros. The engine has no macro debugger, recorder or management commands in this version, and no macro interface.
A macro
{
"name": "Totals",
"description": "Adds a total next to the amounts",
"inputs": [{"name": "Input", "header": true, "cols": [2, 2], "colTypes": ["text", "number"]}],
"output": {"anchor": "Input.right(2).cell(1,2)", "onConflict": "ask"},
"steps": [
{"type": "command", "id": "cell.set", "params": {"cell": "Output", "input": "Total"}},
{"type": "command", "id": "cell.set", "params": {"cell": "Output.offset(1,0)", "input": "=SUM({{Input.data.col(2)}})"}},
{"type": "repeat", "over": "Input.data", "of": "rows", "max": 1000, "body": [
{"type": "if", "cell": "Row.cell(1,2)", "op": "gt", "value": 100,
"then": [{"type": "command", "id": "home.bold", "params": {"range": "Row"}}]}
]},
{"type": "stop", "message": "Done."}
],
"permissions": []
}
- Steps:
command(id,params),repeat(each row or column ofover, at mostmaxtimes),if(cellcompared withvaluebyeq,ne,gt,ge,lt,le,empty,notEmptyorcontains;thenandelselists) andstop(message;rollback: trueundoes the run). Every step can carryenabled,breakpointandnote. The short form{"command": "cell.set", "params": {…}}is accepted for a command step. - Inputs:
kind(cellorrange),rowsandcolsas[min, max](0 for no maximum; rows exclude the header),header,colTypes(number,text,date,bool,any),nonEmptyanddefaultRef. A run binds each input to the range it is given, its default, or (for the first input) the selection, and refuses with messages that name the cells: "Input column 2 (Amount) must hold numbers; C4 holds text." - Limits: 1,000 macros a workbook, 10,000 steps a macro, Repeat and If nested 4 deep,
100,000 steps executed per run, and 60 seconds a run, footprint checks included (
timeLimitto change; the web build has no clock, so there only the step limit applies).
Tokens
References in step parameters can be tokens, worked out when the step runs:
| Token | Means |
|---|---|
Input, or another input's name |
the range the input is bound to |
Output |
the output rule's anchor |
Row, Column |
the current row or column of the Repeat around the step |
Name:Total |
a defined name, or a table's data |
Methods narrow or move a range and chain: col(2) or col("Amount"), row(1), cols(2..3),
rows(2..), cell(r,c) (relative to the top-left cell; cell(0,1) is the cell above),
offset(r,c), resize(h,w), data (without the header row), below(n) and right(n).
col("Amount") looks the name up in an input's header row, directly or after data; on a range
without a header row it is refused. A defined name can hold periods: Name:Sales.Q1 is the name
Sales.Q1, and Name:Sales.Q1.cell(1,1) its first cell, because the longest name or table that
exists is used and methods follow it.
Write a token as the whole value of a reference parameter (cell, range, target, keys ending
in Cell or Range…), as {"$ref": "Input.col(2)"} anywhere, or as {{Input.col(2)}} inside
any string, such as a formula. Plain A1 references stay absolute; a Name: anchor follows
inserted rows. A reference with a sheet name is never a token, so Output!A1 is a cell on a sheet
called Output, even when a token or input has that name.
Running
macro.run {name, inputs?, onConflict?, overwrite?, approve?, timeLimit?}:
- Policy. File, app, window, automate and macro commands, and Undo and Redo, never run in a
macro. Reading or writing a file (
data.getData,data.fromTextCsv,insert.pictureorpageLayout.backgroundwith apath, or an export or print with apath) needs the command in the macro'spermissions. Anypathother thannullcounts, including a blank one and a token, and the policy is checked again on the parameters as they are when the step runs. A macro that touches files, or that came with a workbook opened from a file, runs once the person approves it: the call fails withapprove: …and runs withapprove: true. Approval lasts for the session, until the macro changes. - Footprint. The macro first runs in dry-run mode on the real workbook, and everything is put
back. Cells it would write outside its inputs that hold data, and sheets and objects it would
delete, are conflicts, handled by
onConflict(or the macro'soutput.onConflict):ask(the call fails withconfirm: …;overwrite: trueanswers it),fail,overwrite,shiftDownorshiftRight(Insert Cells makes room, then the footprint is checked again). Steps that touch files, and Solver, end the dry run early; the footprint then says it is partial, and unless the rule isoverwrite, the run checks every step as it goes. A step that writes over cells, sheets or objects that held data when the run started stops the run and rolls the workbook back (a file already written stays): it asks (confirm: …) underaskand fails otherwise, since shifting can't make room that late. - Run. One undo step, "Run Macro: Totals". Any error rolls the whole run back and names the
step:
Step 3.1 (cell.set): …(paths are 1-based;2.1is inside a Repeat,4.then.1inside an If).
macro.check {name, inputs?, timeLimit?} reports the bound inputs, the output anchor, any
approval needed and the footprint, without changing anything.
Storage
Macros are saved in the workbook: as a field in GridCraft's JSON format, and in xlsx as hidden
defined names (_gc_macro_<n>_<k>, the macro's JSON split into string literals within Excel's
limits), which other spreadsheet applications keep but do not run.
Each macro carries its format version, v (1 in this version; a missing v reads as 1). When a
file is opened, a macro that is damaged, over the limits or in a newer format (a v above 1) is
left out with one warning, and the rest of the workbook and its other macros open. A newer
macro is never read in part, so a save can't write it back with its newer fields missing; a
macro that was left out is not in the saved file.
Automate scripts and VBA
Automate scripts (automate.recordActions, newScript, allScripts, runScript,
deleteScript) are an older, separate feature. They keep their commands, parameters, storage
(_sc_scripts) and results, and View › Macros (view.macros) still lists them. Macros neither
read nor change them; a workbook can hold a script and a macro with the same name.
A VBA project in an .xlsm or .xltm file is preserved on save and never run. GridCraft macros
are stored apart from it.