## link
```bash
mercemur link --store acme.mercemur.com
```
Writes `.mercemur.json` so every command in this directory knows which store it acts on, **after
checking** that the store answers and the key works.
The check is the point. Writing a config that turns out to be wrong moves the failure to the next
command, where the message is about that command rather than about the link.
## env pull
```bash
mercemur env pull
mercemur env pull --force # replace values already set
```
Fills `.env.local` with what the CLI can prove: the store id, the API base, the storefront URL and
the default locale.
**It cannot supply a publishable key.** Keys are minted from the dashboard and are not on the
public API, so the file records the variable with a note rather than leaving a name you discover
from a stack trace. Run `mercemur open apikeys`.
Existing values are kept unless you pass `--force`: a local override is usually deliberate.
Unrelated variables and key order are preserved, so a pull is a small diff rather than a rewrite.
## translations
```bash
mercemur translations locales
mercemur translations export -o strings.csv
mercemur translations export -o fr.csv --locale fr --resource-type product
mercemur translations import strings.csv --dry-run
mercemur translations import strings.csv
```
Columns are `locale, resource_type, resource_id, field, value`, with the value last because it is
the only one a translator edits.
The API scopes a translation list to **one resource** on purpose, so an export walks them and
reports how many reads that took. A store with ten thousand products should see what the export
costs before it is surprised by it. Reading `product` requires `read_products`, and so on for
each type walked.
Import sends only the values that **differ**, so re-importing an unchanged export writes nothing.
Leading and trailing space is preserved: it belongs to the translator, and stripping it changes the
rendered copy.
## redirects
```bash
mercemur redirects export -o redirects.csv
mercemur redirects import redirects.csv --dry-run
mercemur redirects import redirects.csv
```
Columns are `from_path, to_path, status_code`. A status must be 301, 302, 307 or 308; anything else
is refused rather than guessed at.
**Import only adds and updates.** A redirect missing from the file is left alone, because a
shorter file is far more often a partial export than an instruction to delete the rest, and
removing a live redirect breaks a URL somebody has indexed.
A file that redirects the same path twice is refused, naming both rows: that is a merge accident,
and applying both silently leaves whichever landed last.
## seo
```bash
mercemur seo list
mercemur seo audit
```
`audit` reports the mistakes a search result makes visible: a duplicate title across two pages, a
description too long to survive truncation, one too short to say anything.
It audits **what is set**, not what is missing. A resource with no override falls back to its own
catalogue title, which is usually correct, and reporting every one of those would bury the findings
that matter.
Exits non-zero on a duplicate title, which is the one finding here that is unambiguously wrong: two
pages competing for the same query is a decision nobody made. Length findings are warnings, because
those limits are conventions that move.
## metafields
```bash
mercemur metafields definitions
mercemur metafields export -o metafields.jsonl
mercemur metafields import metafields.jsonl --dry-run
mercemur metafields import metafields.jsonl
```
One JSON object per line, not CSV.
**A metafield's value is typed by its definition**: a number, a boolean, an object, a list of
references. CSV stringifies all of it, so `420` comes back as `"420"` and nothing reports it
until a template renders the quotes. JSONL keeps the type and still gives a diff of one line per
field.
Values are compared as **canonical JSON**, so the same object with its keys in another order is
the same value and a reformatted file is not mistaken for a store-wide edit.
A line with no `definition_id` is refused rather than guessed at: the definition is what decides
the value's type, and writing one without it stores a shape the storefront cannot read. Run
`mercemur metafields definitions` to see them.
A malformed line names its own line number, because "invalid character" in a file of several
thousand is a search rather than a fix.
## A header with no rows
Every import here treats a header-only CSV as zero rows rather than an error. That file is exactly
what an export of a store with none of these produces, and erroring on it would break the round
trip at its emptiest point. A file with no header at all names no columns and is refused.