Verbs
Every mutation to a noggin's state flows through a verb. Ten built-in verbs (push, add, move, goto, done, pop, edit, show, note, delete) plus one two-noggin verb (copy), all bundled as the verbs singleton and exposed as bound methods on every noggin.
verbs— the singleton +Verbsinterface. Each verb reads current state via the noggin's accessors, composes a list ofAtomicOps, callsnoggin.apply(ops)once, and returns the resulting view (or aDeleteResult/CopyResult).- Verb options — one interface per verb (
PushOptions,AddOptions,MoveOptions, ...) plus theCloseOptionsmixin shared by the closing verbs and theGotoOptionmixin for the--gotofollow-up flag. bindNogginVerbs— attach bound verb methods onto a noggin instance. Providers call this in their constructors so consumers can use the ergonomicnoggin.push(opts)form.VerbContext— optional per-call context for verbs that stamp timestamps (mostly anowclock override for deterministic tests).CopyResult— thecopyverb's return shape (mapping of source-key → dest-key, plus a count).
Keys, not paths
Verbs take path strings (/1/2, ., ..) for user ergonomics, but the UI-facing intent surface (@noggin/ui's NogginActions) uses opaque item keys. Both funnel into the same verb calls; the key vs path distinction is where the caller draws the line between "human-friendly coordinate" and "stable identifier".
Bound methods vs free functions
noggin.push(opts) and verbs.push(noggin, opts) do the same thing. Bound methods exist for ergonomics; free functions exist so the CLI, MCP server, and RPC layer can take a noggin as a parameter. UI code prefers the bound form; in-tree tooling prefers the free form. Both call the exact same implementation.