Files
Peter Schilling 10553fe632 Add, remove, and set flags for project teams, labels, and initiatives
project update could only replace a project's teams and labels, and could
not change initiatives at all: project create accepts --initiative, but
after creation the only route was a hand-written mutation. Every
collection field an update command can change should offer the same three
operations, following the pattern issue update already has for labels:
--team/--label/--initiative replace the whole set, --add-* appends,
--remove-* detaches, all repeatable, and a replace flag cannot be combined
with its add/remove flags.

Linear's ProjectUpdateInput only takes a full teamIds/labelIds list, so
add and remove read the project's current connection, following every
page, compute the new set, and send it. Removing something the project
does not have is an error that lists what it does have, rather than a
silent no-op, and removing the last team errors up front because Linear
rejects an empty teamIds. Initiatives have no input field: membership is
an InitiativeToProject join row, so all three initiative flags diff the
desired set against the current rows and run initiativeToProjectDelete
then initiativeToProjectCreate. Deletes go first because a project may
appear only once in an initiative hierarchy, so moving it to a parent or
child initiative is rejected while the old link still exists; that is
also why a UUID-shaped initiative is confirmed to exist before any link
is touched, since the shared resolver passes UUIDs through unchecked.
Those mutations are not transactional, so a failure part-way reports what
was applied, including the already-committed project fields, and what is
still pending, with the remaining flags given by initiative ID because
names are not unique, instead of implying a rollback.

The survey of issue update and initiative update found no other
replace-only collection flag: IssueUpdateInput's releaseIds and
subscriberIds and InitiativeUpdateInput's labelIds are not exposed by
either command.

Claude-Session: https://claude.ai/code/session_01A9qEGri4p2HZMQSuYsBmub
2026-09-05 08:56:36 -07:00
..