Metadata mutations
Add, edit and move share --title <TITLE>, --tags a,b, repeated --set <KEY=VALUE>, repeated --set-json <KEY=JSON> and repeated --unset <KEY>. Set assigns literal strings; set-json parses exactly one JSON value, including nested values. Neither executes shell or YAML expressions. Shell quoting is the caller's responsibility. Unknown fields use the same supported value model as frontmatter.
A key may be mentioned by only one operation, once. Empty/control-containing keys, assignments to reserved created/updated, invalid JSON and conflicts fail before any publication. Reserved dates have one repair exception: --unset created or --unset updated may remove an existing invalid value; valid or absent dates stay reserved. An actual repair counts as a change, so updated can be generated automatically. Use bs edit <ID> --unset updated (or created) for this repair. Dedicated title/tags flags conflict with generic operations on those fields. Empty title is invalid; unset title removes it. Empty tags gives an empty list; unset tags removes the field. Removing an absent field is a no-op. Required fields and tag rules are checked on the complete final candidate.
A move from project:a to project:b uses bs move a/name b --tags project:b. Mutations apply to a candidate in memory and only destination rules validate that candidate; the source is never temporarily edited. Body and unrelated nested metadata are preserved. Expiration is unchanged unless explicitly set/unset (subject to destination requirements); moving never invents expiration. A plain move preserves dates. User metadata changes stamp updated using the command-local timestamp contract. Editor-draft date edits follow the separately documented explicit-date policy.