# Batch editing
`tix bulk` does the same work over many issues with one preview and one
confirmation. It is the same plan, the same typed patch and the same apply the
single-issue path uses — there is no second implementation, on any surface.
```bash
# What would change? Nothing is written.
tix bulk edit --filter 'status:todo label:bug' --priority high
# Do it.
tix bulk edit --filter 'status:todo label:bug' --priority high --apply
# Link every selected issue to one target.
tix bulk link --select 1,2,3 --target 42 --type blocks --apply
```
## Selecting
Name **exactly one** of three grammars. They are different languages, so a bulk
operation will not guess which issues you meant:
| `--select 1,2,3` | explicit: numbers, filename fragments or title fragments, comma-separated |
| `--filter 'status:todo label:bug'` | the same structured filter the filter modal builds |
| `--search 'fix crash'` | the same search the search box runs |
`--scope` chooses `active` (default), `all` (active and archived) or `archived`.
## What can change
Nine fields, and the list is closed: `status`, `priority`, `assignee`, `labels`,
`start-date`, `due-date`, `estimate`, `cycles`, `milestones`.
`--clear <field>` empties one of them — anything except `status`, because a batch
that empties a column has no target column. One per invocation; a second is
refused rather than quietly dropped.
**A blank flag value means *unchanged*, not empty.** `--estimate ""` leaves the
estimate alone. To empty a field, name it in `--clear`. This is the single most
common surprise, and it is deliberate: the alternative makes it impossible to
clear a field with a flag and impossible to tell "I left it blank on purpose" from
"I did not mention it".
`title` and `body` are deliberately **not** in the list. A batch title rewrite is
the one bulk operation nobody has asked for and everybody would regret, and a
closed list is what makes "what can a batch do" a single answer.
## Preview, apply, and what a partial batch means
Preview is the default; `--apply` writes. A preview touches no file — not the
issue, not its History, not a relationship — and cancelling one changes nothing,
because the only write in the whole path is the apply.
Each selected issue is processed **independently**. A refused or failed item is
reported and does not roll back the successful ones; there is no all-or-nothing
mode. Every selected issue gets exactly one outcome line:
| `applied` | the requested state was written |
| `no-op` | it was already in that state — nothing written, nothing appended |
| `rejected` | refused at plan time; nothing was attempted |
| `failed` | the write failed; whatever succeeded before it stands |
Re-running is idempotent, and says so: a second run reports `no-op` rather than
repeating the work or quietly succeeding.
A **partial** batch exits non-zero. Zero means everything requested happened, and
the output does not claim otherwise.
## Pairs and archive
`tix bulk link` / `unlink` need `--target` and `--type`. The type is the
relationship service's own vocabulary — there is no default kind, so an untyped
pair is never created by accident — and each selected issue becomes its own pair
with the target.
`tix bulk archive` is **not available**. Single-issue archive and restore exist
([archiving](archiving.md)); doing it to a *selection*, with a preview and per-item
outcomes, is a separate mission's scope, and a second archive implementation is
exactly what this tool does not want. The request is refused by name, per selected
issue, so you can see what it would have archived.
## The TUI and MCP
`B` opens the batch surface on the board; `space` marks a card, `x` unmarks it,
`X` clears the selection. `p` previews, `y` arms, `y` again writes, `esc`
cancels. A batch is bounded at 200 selected issues, and the bound is in the header
so you can see where you are.
Over MCP the same work is three tools — `bulk_preview` (read-only),
`bulk_apply` (requires `confirm: true`) and `bulk_capabilities` (what this build
supports). The schema is generated from the same whitelist the CLI and the docs
above are generated from, so a field cannot be advertised on one surface and
ignored on another.