Page layout
Orientation and paper size, separate sections, a different header or footer for each section, columns, page borders and multi-level lists. Every example is a list of operations: save it as ops.json and run it with batch, or pass it as operations to execute_batch in the MCP server, or to executeBatch in the library. All three give the same file.
Concepts
- A section is a run of pages with its own page setup. Orientation, paper size, margins, columns, border, header and footer belong to a section, not to the whole file.
- A section break ends a section. In the file it is a property of the last paragraph of that section.
- Sections are numbered from 1, in reading order, wherever an operation takes
sectionIndex. ForpageSetup, leaving it out applies the change to every section. - Sections are read from the file. If an edit adds, deletes or moves a break, ASTra rebuilds its section list from the file, so it always agrees with what Word shows.
- Node IDs last for one session. An ID you give a new paragraph works for the rest of that batch. In a later command, read IDs again with
inspectorsearch.
Orientation and paper size
Landscape for the whole document:
[{ "action": "pageSetup", "orientation": "landscape" }]A4, portrait, with narrower side margins. Margins are in twentieths of a point; 1440 is one inch.
[{ "action": "pageSetup", "paperSize": "A4", "orientation": "portrait", "marginLeft": 1080, "marginRight": 1080 }]paperSize is A4, Letter, Legal or A3. Landscape swaps the page width and height and keeps the margins. One section only:
[{ "action": "pageSetup", "sectionIndex": 2, "orientation": "landscape" }]Sections
Insert a break after a paragraph. breakType is nextPage or continuous. anchor: "end" adds to the end of the document. Set each section's page setup after you create it, with sectionIndex.
[
{ "action": "insert", "type": "paragraph", "anchor": "end", "position": "after", "text": "Cover page", "id": "cover" },
{ "action": "insert", "type": "sectionBreak", "anchor": "cover", "position": "after", "breakType": "nextPage" },
{ "action": "insert", "type": "paragraph", "anchor": "end", "position": "after", "text": "Wide table section", "id": "wide" }
]Headers and footers
[
{ "action": "headerFooter", "operation": "set", "targetType": "header", "sectionIndex": 1, "text": "Quarterly report" },
{ "action": "headerFooter", "operation": "set", "targetType": "footer", "sectionIndex": 3, "text": "Page {PAGE} of {NUMPAGES}" }
]{PAGE}is the current page and{NUMPAGES}the total. They are stored as real Word fields, so they update in Word.- A section without its own header or footer shows the one from the section before it, as in Word. Above, sections 2 and 3 show “Quarterly report”, and only section 3 has the footer.
- To give a section no header of its own again, use
"operation": "remove"with the sametargetTypeandsectionIndex.
Columns and page borders
[
{ "action": "section", "operation": "setColumns", "sectionIndex": 3, "columns": 2, "separator": true },
{ "action": "pageBorder", "sectionIndex": 1, "style": "double", "sz": 12, "color": "1F4E79" }
]spacing is the gap between columns (default 720, half an inch). pageBorder takes style (single, double, dashed, triple), sz in eighths of a point, color as hex without #, and marginOffset (page or text).
Lists
Make a paragraph a list item with list / create, and add items with continue at a level from 1 (top) to 9. This produces 1. Prepare, a. Check, 2. Ship.
[
{ "action": "insert", "type": "paragraph", "anchor": "end", "position": "after", "text": "Prepare", "id": "s1" },
{ "action": "insert", "type": "paragraph", "anchor": "s1", "position": "after", "text": "Check", "id": "s2" },
{ "action": "insert", "type": "paragraph", "anchor": "s2", "position": "after", "text": "Ship", "id": "s3" },
{ "action": "list", "operation": "create", "target": "s1", "listType": "numbered" },
{ "action": "list", "operation": "continue", "target": "s2", "previousNodeId": "s1", "level": 2 },
{ "action": "list", "operation": "continue", "target": "s3", "previousNodeId": "s2", "level": 1 }
]- Bullets use a different mark at each level (• ◦ ▪ and so on) down to level 9.
- Numbers run 1. a. i. and repeat that pattern through nine levels.
changeLevelmoves an item with"level": 3or"delta": 1. Level 0 takes it out of the list, and so doesremove.
Deleting a section break
Delete the break paragraph by its ID. It is the last paragraph of its section, so in the output of inspect it is the usually empty row just before the next section starts.
[{ "action": "delete", "target": "<ID of the break paragraph>" }]- The two sections merge. The text before the deleted break takes the page setup of the section after it, as in Word. A landscape section merged into a portrait one turns portrait.
- The deleted section’s header and footer are removed from the file, not only hidden: their text, relationships and pictures used only by them are gone. A header that something else still uses is kept.
- ASTra prints a warning saying how many sections the document had and now has.
- If a later operation in the same batch fails, the whole batch is undone and the file is not written.
- A delete with an ID that does not exist is not an error: it is listed under
skippedIdsandappliedCountis0. CheckappliedCountin scripts.
Putting it together
The second batch needs the sections the first one creates, which is why they are two files.
npx -y @attentionform/astra create report.docx --template blank --force
npx -y @attentionform/astra batch report.docx build.json --out report.docx --force # insert and list operations
npx -y @attentionform/astra batch report.docx layout.json --out report.docx --force # header, footer, page setup, columns, border
npx -y @attentionform/astra validate report.docx
npx -y @attentionform/astra visual report.docx --page 2 --out page2.pngKnown limits
.docxonly.- Checked automatically with the Open XML SDK and LibreOffice, not with Word. Fifteen sample documents covering sections, headers and footers, lists, a chart and other content were also opened by hand in desktop Word and opened without a repair prompt; the chart stayed editable. Equations and comments were not confirmed separately.
- PDF export and page images need LibreOffice and Poppler installed.
- Version 0.x: interfaces may change before 1.0. Node.js 22.19 or later.
- Node IDs last for one session; read them again after you reopen a file.
- A batch takes at most 500 operations and 200 MB of document data; over that it stops with
E_QUOTA. - Deleting a section break merges the sections, and the text takes the next section’s page setup.
- Landscape swaps width and height and keeps the margins; change margins separately.
- Revision history is off until you turn it on (
history <file> --init).