Tutorial: a guided editing session¶
This tutorial walks one document, end to end. You'll attach to a live Word instance, inspect it, read a section, make a polite edit, batch several edits into a single undo, suggest changes instead of overwriting them, and finally verify exactly what you changed — each step building on the last.
It's deliberately different from the other pages:
- Getting started is the 60-second quickstart — the smallest possible read and write, each standing alone.
- The Cookbook is random-access how-to — "I have problem X, here's the recipe."
- This tutorial is a single continuous session. By the end you'll have felt the four ideas that shape every wordlive API — politeness, semantic anchors, atomic undo, and structured I/O — because you used them in order, not because you read a list. Budget about 15 minutes.
Every step is reversible with Ctrl-Z, and nothing moves your cursor unless it says so.
Before you start¶
You need Windows, Microsoft Word, and wordlive installed — see Getting started → Install if you haven't yet.
Get the sample document¶
The tutorial drives a short status report. Get it whichever way suits you:
Grab
quarterly-report.docx
from examples/sample/ and open it in Word.
Regenerate it from the committed script (so the binary stays reviewable):
Any document works if it has four Heading-1 sections named Introduction, Risks, Budget, and Next Steps, with a three-column table under Budget. The IDs printed below will differ, but every step still applies.
Open the sample in Word now. Everything below attaches to that
already-running instance — wordlive never launches Word behind your back when you
use attach().
Step 1 — Attach and see the structure¶
Start by asking the document what's in it. outline() returns every heading,
each tagged with the anchor id wordlive (and an LLM) uses to address it.
Either way you get the four sections:
Why heading:3, not heading:1?
Heading ids share one index space with every paragraph: the title is
para:1, the subtitle para:2, so the Introduction heading is para:3 —
and therefore heading:3. The numbers are paragraph positions, not "the Nth
heading." That's the whole addressing scheme: anchor ids are stable, visible
handles you pass back in. See Anchor IDs.
From here on, address sections by name (doc.heading("Risks")) or by the id you
just saw (heading:6) — they're interchangeable.
Step 2 — Take a checkpoint¶
Before touching anything, fingerprint the document. This is a pure read — it changes nothing — but it lets you prove, at the end, exactly what your session did. Stash the token somewhere (a variable, a file, an agent's state).
We'll come back to this in Step 7.
Step 3 — Read one section¶
You rarely want the whole document — you want one part. Address the Risks heading and pull its body (everything down to the next same-or-higher heading).
The single biggest risk this quarter is schedule slip on the integration milestone.
The vendor has promised the updated components as soon as possible.
Mitigation owners are assigned but not yet confirmed.
That's the skim cheap, drill precisely loop: outline to find the anchor, then
read just that anchor. For a whole-document, token-budgeted digest instead, see
Cookbook §20.
Step 4 — Your first polite edit¶
Now change something — and watch wordlive keep your place. Add a scope note right after the Introduction heading.
with wl.attach() as word:
doc = word.documents.active
before = doc.selection.info() # where the user's cursor is
with doc.edit("Add scope note to introduction"):
doc.heading("Introduction").insert_paragraph_after(
"Scope: integration milestone and Q2 budget.",
style="Body Text",
)
after = doc.selection.info()
assert before["start"] == after["start"] # cursor never moved
Two things happened that the code doesn't spell out:
doc.edit("…")opened a WordUndoRecord. One Ctrl-Z removes the whole edit, labelled "Add scope note to introduction" in Word's undo dropdown.- Your cursor and scroll position were snapshotted and restored. The
assertproves it:info()reports the same start offset before and after. The script edited the document without stealing your place in it — that's the politeness contract, and it's the default for every write.
Step 5 — Batch several edits under one Ctrl-Z¶
Real edits come in groups. Revise the budget: correct a figure, add a contingency row, and stamp a generated-on line — as one user-visible intent, so one Ctrl-Z reverts all three.
Three mutations, one undo step. That's the third invariant —
atomic undo: a batch maps to a single intent, so the
user reverts it the way they think about it, not op by op. The exec form is the
same batch the MCP and LLM tool-use loops send.
Step 6 — Suggest, don't overwrite¶
The most agent-shaped edits don't rewrite the user's text — they propose. Flag a vague deadline with a comment, and soften some wording as a tracked change the human can accept or reject. Neither destroys anything.
First locate the phrase to comment on (read-only), then attach the comment to exactly that span:
with wl.attach() as word:
doc = word.documents.active
hit = doc.find("as soon as possible")[0] # {'anchor_id': 'range:413-432', …}
with doc.edit("Flag vague deadline"):
doc.comments.add(
doc.anchor_by_id(hit["anchor_id"]),
"Can we commit to a concrete date?",
author="ReviewBot",
)
# And soften wording *visibly*, as a revision:
with doc.tracked_changes(), doc.edit("Plainer wording"):
doc.find_replace("utilise", "use", all=True)
# Locate the span (read-only), then comment on it.
wordlive find --text "as soon as possible"
# → [{"anchor_id": "range:413-432", "start": 413, "end": 432, "text": "as soon as possible"}]
wordlive comment add --anchor-id range:413-432 \
--text "Can we commit to a concrete date?" --author ReviewBot
# Soften wording as a tracked change (prior Track-Changes state is restored).
wordlive exec --script - <<'JSON'
{
"label": "Plainer wording",
"tracked": true,
"ops": [{"op": "find_replace", "find": "utilise", "text": "use", "all": true}]
}
JSON
The comment hangs off the exact range: span find returned — no character of
the document changed. The utilise → use swap lands in Word's review pane as a
revision: the human accepts or rejects it. doc.tracked_changes() turns Track
Changes on for just that scope and restores the prior setting on exit.
Step 7 — Verify what you changed¶
Word emits no "content changed" event, so the reliable way to answer "what did I just do?" — and for an agent to confirm its edits actually landed — is to diff against the checkpoint from Step 2.
insert para:4 'Scope: integration milestone and Q2 budget.'
replace para:6 'We use a weekly status cadence to keep stakehol…'
replace para:27 '$5,000'
insert para:37 'Report generated for Q2 review.'
… (table-row inserts omitted)
Every change is structured data, not a string you scrape — op,
anchor_id, the new text. That's the fourth invariant,
structured I/O: reads come back as objects with
deterministic shapes, so a script (or an LLM) can branch on them. Alignment is by
paragraph content, so a para:N that renumbered when you inserted text still
lines up. (Comments and tracked changes are tracked separately — this diff covers
content edits.)
What you just learned¶
You drove a real document through a complete session — and in doing so used each of wordlive's four invariants exactly once:
| Step | What you did | The idea behind it |
|---|---|---|
| 1, 3 | Addressed sections by heading:N / name |
Semantic anchors & anchor IDs |
| 4 | Edited without moving the cursor | Politeness |
| 5 | Three writes, one Ctrl-Z | Atomic undo |
| 2, 7 | Checkpointed and diffed as objects | Structured I/O |
| 6 | Suggested via comment + tracked change | Politeness, taken to non-destructive edits |
Where to next¶
- Advanced — the sequel session: the power features (digest reads, durable pins, charts, vision snapshots, house-style linting) on this same document.
- Concepts — the same four ideas, explained rather than walked.
- Cookbook — 22 random-access recipes, including the full LLM tool-use loop (§5).
- Examples — runnable Python and PowerShell scripts.
- Python API · CLI — the complete reference for every verb you used above.
- Wiring up an agent? Agents & LLM tools connects it (skills,
MCP, the one-drop
.mcpb); Agent patterns is how to drive it well.