C.W.K.
Stream
Lesson 03 of 05 · published

One Cmd+Z Should Undo the Whole Thing

~10 min · undo, single-action, pasteboard, ux

Level 0Unlit
0 XP0/36 lessons0/12 achievements
0/100 XP to next level100 XP to go0% complete
"A dictation you can't cleanly undo is a dictation you're afraid to make."

Undo Is Part of the Product

When Firekeeper drops text into your document, the very next thing you might do is regret it — wrong window, misheard sentence, changed your mind. The quality of that undo is a real feature, not an afterthought. The goal is simple and strict: one Cmd+Z in the target app should undo the entire insertion in a single step, restoring exactly the state before you dictated.

Why Single-Action Insertion

Undo quality falls directly out of how you insert. A single paste or a single Accessibility replacement registers in the target app as one undoable action — so one Cmd+Z takes it all back. Character-by-character insertion is the opposite: each synthesized keystroke can become its own undo step, so undoing a sentence means mashing Cmd+Z twenty times, and some apps coalesce unpredictably. This is a concrete reason the ladder prefers paste and AX replace over key events wherever it can: not just speed, but undo integrity.

Single paste / AX replace  ->  1 undo step   -> one Cmd+Z restores prior state
Character-by-character     ->  N undo steps  -> Cmd+Z mashing, unpredictable

# The insertion method you choose IS the undo experience you ship.

The Deliberate Exception

There's exactly one place Firekeeper accepts worse undo on purpose: the terminal profile. Long terminal dictations are sometimes inserted in chunks or line-by-line so the text stays visible and editable instead of arriving as one hidden block. Chunked insertion fragments undo — that's a real cost — but in a terminal, visibility and the ability to edit before running are worth more than a clean single undo. The point is that the tradeoff is chosen and scoped, not stumbled into: everywhere except the terminal profile, single-action insertion protects undo.

The mechanism of an action determines the quality of its undo. If you want an operation to be undoable in one step, perform it as one atomic action, not a stream of small ones. Undo integrity isn't a separate feature you add later — it's a property that falls out of how you chose to make the change in the first place.
Make undo-degrading tradeoffs explicit and narrow. When you must accept worse undo (chunked terminal insertion), confine it to exactly the case that needs it and know why. A tradeoff you named and scoped is a design decision; the same tradeoff applied everywhere by accident is a bug you'll rediscover as an angry user report.

Code

Prefer atomic insertion; accept chunking only where it's chosen·swift
// Default: one atomic action so Cmd+Z undoes the whole dictation.
func insertAtomic(_ text: String, into t: TargetSnapshot) async -> Bool {
    if t.category.axReliable { return await axReplace(text, in: t.focusedElement) }
    return await pasteInsert(text, into: t)   // single paste = single undo
}

// Terminal profile ONLY: chunked/line-by-line for visibility,
// knowingly trading clean undo for the ability to see and edit first.
func insertTerminal(_ text: String, into t: TargetSnapshot) async {
    for line in text.split(whole: true) {
        await keyEventInsert(line, into: t)   // fragments undo -- accepted here
    }
    // Never auto-press Enter unless the user explicitly asked.
}

External links

Exercise

Think of a tool that makes a bulk change to your work (a find-and-replace, a bulk import, an auto-formatter). Does one undo take back the whole change, or do you have to undo piece by piece? Describe how the tool's implementation choice created that undo experience — and which one makes you trust the tool more.
Hint
Bulk operations that register as a single undoable action feel safe — you experiment freely because one Cmd+Z bails you out. Ones that fragment undo make you cautious, because reverting is tedious and uncertain. The trust difference traces directly back to whether the change was made as one atomic action or a stream of small ones.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.