*Epic CLI Manual — [index](../MANUAL.md)*

# 12. `--derivatives=PACKAGE`

```
java -jar java-epic-cli.jar --derivatives=W2302N-DerivativeBatch.zip --output=out/ [--request=FILE]
```

Generates master derivatives from a **derivative-batch package** — the bundle EpicERP builds
for the Illustrator operator flow: the master's source package (PDF + `Fonts/`) with a
sidecar XML at the root (same basename as the PDF, Adobe variable-data dialect, `ha:out` per
dataset). ZIP or directory.

Per dataset, two PDFs land in the output directory (default: alongside the package):

| File | Content |
|---|---|
| `<ha:out>.pdf` | Working / customer-facing — `PRODUCTION_ONLY` layer hidden, artboard refit to the remaining visible ink. |
| `<ha:out>_production.pdf` | All layers, artboard fit to all visible ink. |

## Binding semantics (parity with CreateDerivatives.jsx v8)

- A variable binds to the text frame whose full content **exactly equals** its
  `ha:placeholder`. Exactly one match binds; zero or several **skips with a warning, never a
  guess**.
- An **empty** dataset value **hides** the bound frame (and the artboard shrinks around the
  remaining ink).
- Every text frame is converted to outlines; outputs carry no fonts.
- `ha:out` is echoed back verbatim, never derived.

## Engines and flavors

Flavor is auto-detected from the master. A request JSON in the package
(`<Base>.request.json` / `request.json`) is the authoritative `lab` marker; only when the
package ships none does the sniff fall back to the PDF (a PieceInfo dict ⇒ `ai`). The
fallback alone is not trustworthy for synthesized packages: placed artwork that began life
as an AI upload can carry its PieceInfo dict into a compiled master, which would
misclassify it as `ai` and fault the envelope engine.

- **`lab`** — a synthesized design-lab master (live-text PDF + `ha:placeholder` bindings).
- **`ai`** — a real Illustrator master with envelope private data. The ai engine recovers
  envelope warp meshes from the AI private data, warps replacement text through them, and
  splices the master's outlined text out whole-path. A dataset it cannot fulfill safely
  (changed variable with no envelope mesh, mirrored mesh, zero or multiple package fonts, no
  master ink matching the default text) reports `failed` and routes to manual fulfillment.

**Compile engine** (primary path for lab masters): when the original `--compile` request JSON
is supplied — `--request=FILE`, or auto-detected at the package root as
`<Base>.request.json` / `request.json` — each dataset is produced by **re-compiling the
request** with the bound text layers swapped: the identical pipeline that built the master.
This handles what PDF rewriting cannot: warped text layers re-render through the same warp
math with the new text, and every replacement is uniformly scaled (exactly, via font size —
layout is linear in size) so its ink box fits the placeholder layer's ink box,
center-anchored. `live_text` is forced off for derivative compiles — both saves are fully
outlined, so production never depends on font resolution. `--request` with a non-lab package
is a usage error; an auto-detected request in an ai package is ignored.

## Result contract — partial-batch fulfillment

Exactly one JSON object:

```json
{"status":"ok","master":"...","flavor":"lab"|"ai",
 "engine":"compile"|"livetext"|"envelope",
 "datasets":[
   {"ha_out":"...","status":"ok"|"failed","reason":"...",
    "pdf":"...","production_pdf":"...","colors_used":[...],"warnings":[...]}]}
```

**A failed dataset never fails the batch** — it reports `"failed"` with a reason and the
caller routes just that dataset to manual fulfillment. Exit 0 = request processed (even with
failed datasets); 1 = usage error; 2 = hard fault (unreadable package/sidecar).
