v0.2.0 — Mutating core: agents can drive a backlog
0.2.0 - 2026-05-08 — Mutating core: agents can drive a backlog
The "agents can drive a backlog" milestone — v0.1's read-only core
- safe-mutations gain the full mutation surface (item lifecycle,
update mutations, workspace lifecycle, board lifecycle, board
columns + groups). One breaking change vs v0.1 (see below);
everything else is purely additive. Built incrementally across
M8–M18.
Breaking changes vs 0.1.0
monday update list no longer populates replies: [] by
default. Pass --with-replies to restore the v0.1 behaviour.
- Why: Monday charges complexity for the nested
updates(...) { replies { ... } }selection, and most agent
flows don't need the thread expansion. v0.1 silently paid the
charge on every call; v0.2 makes the nested selection opt-in. - Migration: agents that consume
update.repliesshould pass
--with-repliesexplicitly. The output shape stays
byte-identical when the flag is set; only the default changed. - Detection: a v0.1 caller looking for
replies[*].bodywill
see an empty array post-upgrade. There's no error envelope —
the field is present and shaped correctly, just empty unless
--with-repliesis set.
This is the only breaking change. All other v0.2 work is
additive.
Surface
Five reader nouns + ~75 commands shipped (was 35 in v0.1). No
new nouns; ~30 new verbs spread across the existing 5 mutation-
receiving nouns plus workspace / board / update / item lifecycles.
Item lifecycle (M9–M12) — item create (top-level + classic-
only subitem; single round-trip; optional --position before|after --relative-to <iid>); item archive / delete /
duplicate (duplicate two-leg live with --with-updates +
duplicated_from_id echo); item move (same-board via
--to-group <gid>, cross-board via --to-group <gid> --to-board <bid> + --columns-mapping); item upsert (idempotency via
--match-by <col>[,<col>...] routing 0/1/2+ matches to
create_item / update_item / ambiguous_match); bulk item clear --where.
Update mutations (M13) — update reply / edit / delete /
like / unlike / pin / unpin / clear-all. The
clear-all verb introduced the partial-success envelope:
ok: true whenever dispatch ran; per-target outcomes in
data.results: [{ update_id, ok, error? }].
Workspace lifecycle (M14) — workspace create / update /
delete / add-users / remove-users. add-users /
remove-users reuse the M13 partial-success envelope with
resolver-fronted dispatch (mixed numeric IDs + emails).
Board lifecycle (M15) — board create / update /
archive / delete / duplicate / add-users. board duplicate introduced the wrapped envelope: data: { board: <projection>, is_async } because Monday's BoardDuplication
carries an is_async slot the projection schema doesn't model.
board update is per-attribute fan-out across Monday's
update_board(board_attribute, new_value) surface with a
force-live final read leg.
Board columns (M16) — board column-create / column-update
/ column-delete. column-create adds the
noncanonical_column_type warning for non-allowlisted column
types with per-category suggested_write_path. M16 also shipped
the §8 eager-invalidation contract: every board-structure
mutation calls invalidateBoard(boardId) post-success so a
same-process board describe sees fresh state without TTL
eviction. Six call sites adopted (M16's three column verbs +
M15's three retrofitted board update / archive / delete).
Board groups (M17) — board group-create / group-update /
group-archive / group-duplicate / group-delete.
group-update is per-attribute fan-out (no force-live final
read — Monday's update_group returns the full Group projection
post-mutation, distinguishing it from board-update). Group-
create + group-update validate --color against the pinned
Monday-supported palette in src/api/group-color.ts.
Writer expansion (M8) — --set-raw <col>=<json> escape
hatch for non-allowlisted column types (gated against
read-only-forever and files-shaped types) plus three new firm
friendly translators: link (pipe-form link=<url>|<text>),
email (pipe-form email=<email>|<text>), and phone
(pipe-form phone=<phone>|<country> with ISO 3166-1 alpha-2
country code).
NDJSON streaming (M7 → M18) — --output ndjson for item list (M7), item search (M18), and update list (M18). Trailer
shape pinned to {"_meta":{...}} per cli-design §6.3 (no
warnings slot — agents read warnings from JSON envelopes, not
NDJSON streams).
Output contract additions
27th error code: ambiguous_match (M12). Reserved on the
v0.1 registry, now active on item upsert when --match-by
resolves to 2+ items. Agents key off error.code to retry with
a tighter match; the message names the matched IDs.
Three envelope shape variants joined the contract:
- Partial-success envelope (M13) —
ok: truewith
data.results: [...]per-target outcomes. Used byupdate clear-all,workspace add-users/remove-users,board add-users. Top-levelok: falseonly on whole-call failure. - Wrapped envelope (M15) —
data: { board: <projection>, is_async }forboard duplicate(Monday-side async-rebuild
slot the projection doesn't model). - Bulk mutation envelope (M12) —
data: { summary, items }for bulkitem update --where/item clear --wherewith
summary.matched_count+summary.applied_count.
resolved_ids echo (cli-design §6.4) on every column-
mutation envelope (item set / clear / update), including
the empty {} when no --set token resolved. Agents capture
once and skip subsequent metadata lookups.
Upgrade notes
-
unsupported_column_typedeferred_to: "v0.2"resolves
for the M8 firm row (link/email/phoneshipped) and
slips to"v0.3"for the tentative row (tags/
board_relation/dependency— friendly translators land in
v0.3 once the per-account directory + linked-board enumeration
design clears). Agents using these types via--set-raw
continue to work; the runtime hint surfaces--set-rawas the
current path. -
The error-code registry expanded from 26 to 27. New code:
ambiguous_match(M12) onitem upsertwith 2+ matches.
Existing codes' shapes are unchanged. -
Cache-invalidation discipline tightened. M16's §8 contract
means a same-processboard describeafterboard column-*/
group-*/update/archive/deletemutations now sees
fresh state. v0.1 callers that read post-mutation state see
less stale data than before — purely an improvement, but
a behavioural shift worth flagging for any agent that timed
reads against TTL eviction (none should have, but flagging
for completeness).
Internals worth highlighting
-
R-class refactors shipped during v0.2 — the R20–R52 register
consolidates per-noun + cross-cutting boilerplate as the surface
grew. Highlights: R29 destructive-gate helper (initially lifted
at five consumers in M14; later milestones grew its consumer
count further as M15-M17 destructive verbs adopted),
R37/R39/R43/R45/R48 per-noun mutation projection helpers
(Update / Workspace / Board / Column / Group), R40 partial-
success-fan-out helper, R46 §8 eager-invalidation wrappers,
R51findBoardChildOrThrowhelper, R52startNdjsonStream
lift (M18 — ships streaming parity acrossitem list/
item search/update list). R42 / R44 / R49 / R50 stayed
deferred to v0.3 at v0.2.0 close. Full R-class register lives
indocs/v0.2-plan.md§22 with shipped
commit SHAs. -
Two-AI review (cli-design pre-flight + implementation review)
ran for every milestone M8–M18. Catches contract drift before
it reachesmainand projection bugs before they reach a
release; the cumulative finding count across the v0.2 arc is in
the per-milestone post-mortems indocs/v0.2-plan.md§10–§26.
Tests + quality gates
- 2280 unit/integration + 38 E2E tests at the v0.2.0 tag (was
1408+37 = 1445 in v0.1). All green on Node 22 + 24. - Branch coverage ratchet from 95% (v0.1 floor) to 95.5%
(v0.2 floor; project's actual branches at v0.2.0 is 95.51%).
Other thresholds held at 95%. Thevitest.config.tsfloor
enforces. The §3 M18 exit aimed for 96 — the actual M13–M18
branch-coverage delta was smaller (~0.5pp) because the new
code shipped at 100% per-file but the denominator grew
alongside the numerator. Net effect is "held + small raise"
per the §3 M18 "held or raised" exit gate. - 92 envelope-shape snapshots (was 60 in v0.1) — every
shipped command pinned for byte-shape regressions. - Five test layers held: unit, integration (in-process
FixtureTransport), E2E (subprocess against fixture server),
envelope-shape snapshot suite (extended at M18), published-
tarball E2E.
Documentation
docs/v0.2-plan.mdnew — the v0.2
active plan with M8–M18 milestones, decisions log, R-class
register (R20–R52), per-milestone post-mortems (§10–§26), and
the §13 deferral roadmap.docs/cli-design.md§4.3 grew
~30 new verb entries; §6.4 added the partial-success +
wrapped + bulk envelope variants; §8 added the eager-
invalidation contract.docs/output-shapes.md— every
shipped v0.2 command has a per-section data shape entry,
snapshot-backed.- README.md quickstart expanded with
item create+item upsertexamples (the two verbs that change the "drive a
backlog" story most).