# unipress

**Compile a directory of markdown into a document — typeset PDF, EPUB, Word, Excel, Paged.js HTML, Typst source — using a foundation that knows the conventions of the kind of document you're writing.**

You already write in markdown, and you keep it organized — a folder of files, numbered for order, maybe a `README` and some assets. That's good structure. But turning it into one polished, shareable document usually means pandoc incantations, a LaTeX toolchain, or a pile of glue scripts.

unipress does it in one command.

## Quick start: markdown you already have → a PDF

Point it at your folder:

```bash
cd my-docs        # a folder of .md files
unipress compile .
```

There's no project to set up. The first time, unipress sees there's no config, offers to create a small `document.yml` for you, and produces the PDF — a clean, single-column **article**: A4, typeset prose, an inline title block, no chapters. Numbered filenames (`01-intro.md`, `02-overview.md`) set the section order; `README.md` and draft files (`_notes.md`) are left out.

Prefer no prompts? `--yes` takes the defaults — the A4 article, PDF output:

```bash
unipress compile . --yes
unipress compile . --yes --format epub      # or any format the foundation emits
```

The generated `document.yml` is yours to keep and edit — it holds the title, reading order, and output format. Re-run compile whenever the content changes.

### A4 or US Letter?

The default page size is **A4**. In the US and Canada you'll want **Letter** — open the generated `document.yml` and change `book.trim` from `a4` to `letter`:

```yaml
book:
  kind: article
  trim: letter      # 8.5 × 11 in  (was: a4)
```

Then re-run `unipress compile .`. A couple of other one-line tweaks live in the same `book:` block — numbered sections (`structure: { numberHeadings: true }`) and a table of contents (`structure: { toc: true }`). See the [`article` guide](./docs/templates/article.md) for the full list.

## Starting from scratch

No content yet? Scaffold a starter from a template:

```bash
unipress create my-book --template book --title "My Book" --author "Your Name"
cd my-book && unipress compile .
```

`create` writes a content-only directory — markdown, a `document.yml`, optional `theme.yml` and `assets/`; no `package.json`, no `node_modules`. Pick the template that matches your document (see [Pick a template](#pick-a-template)) — it carries the typography and structure so a book reads like a book and a directory like a directory.

> **Planning to publish?** There's a full author's guide that takes a book from your folder all the way to Amazon and print — [Publishing your book](./docs/publishing/README.md).

## What it makes

| Format | What it's for |
|---|---|
| **PDF** | The finished, typeset document. Real typography, real pagination, ready to print or share. Built on [Typst](https://typst.app), the modern typesetting system. |
| **EPUB** | The format Kindles and other ebook readers use. |
| **Word (`.docx`)** | When a journal, committee, or collaborator needs a Word file. |
| **Excel (`.xlsx`)** | When the document is structured data — a directory, a dataset, a registry — rather than prose. |
| **Paged.js HTML** | Browser-paginated HTML you can print to PDF or post on the web. |
| **Typst source** | The `.typ` files unipress feeds the compiler. Useful if you want to take the typesetting further yourself, or hand off to a designer. |

Equations work in the standard LaTeX style — `$E = mc^2$` for inline, `$$...$$` for displayed. Tables, lists, footnotes, code blocks, and images all behave the way you'd expect from markdown.

## Publishing your book

Making the files is half the job; getting your book onto Amazon, Apple Books, and print-on-demand is the other half. The **[Publishing your book](./docs/publishing/README.md)** guide is an end-to-end walkthrough written for authors — the proof → final workflow, covers and images, trim sizes, EPUB validation, print-on-demand, ISBNs, and metadata — with links to every store and service.

## Two ways to use it

**For authors.** unipress is a tool. Pick a template, write markdown, compile. The template knows the conventions for its kind of document — typography, structure, the bits that make a book look like a book and a directory look like a directory. You handle the content; the template handles everything else.

**For developers.** unipress is an engine. A *foundation* you write declares what section types exist (`type: Chapter`, `type: Bibliography`), where their data comes from (markdown content, file-based or API-backed collections, [Loom](https://github.com/uniweb/loom) expressions templating against hierarchical data), and what output formats it can emit (`outputs: { docx, xlsx, pdf, custom-format }`). Authors mix prose with structured records and computed values in the same document; unipress runs your foundation against their content and produces whatever your foundation declares — typeset book, accessible EPUB, regulatory report, structured data feed. The same foundation can also drive a [Uniweb](https://uniweb.io) website, so the work is never single-purpose.

Foundations consume [@uniweb/press](https://github.com/uniweb/press) for the bytes-emitting work. Press is the output layer (Word, Excel, Typst today; more formats shipping); the foundation is your vocabulary.

→ For the deeper pitch — mixed prose-and-data, Loom templating, custom output adapters — see [docs/for-developers.md](./docs/for-developers.md).

## Install

**Homebrew (macOS and Linux — recommended).** No Node, no manual download:

```bash
brew install uniweb/unipress/unipress
```

Updates land via `brew upgrade unipress`. On recent Homebrew (6.x), the first `install` or `upgrade` may refuse the tap until you trust it once — run `brew trust uniweb/unipress`, then re-run the command. The macOS binary is signed with the Proximify Inc. Developer ID and Apple-notarized — no Gatekeeper warnings.

**Manual download (Windows, or any platform without Homebrew).** Grab the asset for your platform from [the releases page](https://github.com/uniweb/unipress/releases), make it executable (Unix), and put it somewhere on your `PATH`. On macOS and Linux, `/usr/local/bin/unipress` is a common location.

**npm.** If you already have Node ≥ 20.19:

```bash
npm i -g @uniweb/unipress
```

## Pick a template

Built-in templates ship with the binary. Run `unipress list-templates` for the picker.

| Template | Foundation | Outputs | Use case |
|---|---|---|---|
| `article` | `@uniweb/book` | pdf, typst, pagedjs, epub | Single-column paper (A4/Letter, no chapters) — the default for a loose folder of markdown |
| `book` | `@uniweb/book` | pdf, typst, pagedjs, epub | Trade book, long-form prose with chapters |
| `monograph` | `@uniweb/book` | pdf, typst, pagedjs, epub | Scholarly monograph (royal-octavo, classical typography) |
| `report` | `@uniweb/book` | pdf, typst, pagedjs, epub | Technical report (trade-7x10, block paragraphs) |
| `data-report` | `@uniweb/data` | xlsx, docx | Aggregate metrics across structured records |
| `directory` | `@uniweb/data` | xlsx, docx | Flat records listing with a filterable surface |

`article` and `book`/`monograph`/`report` are one foundation, two genres: `article` is single-column and chapter-less (LaTeX's `article`), the others are chaptered with a title page and TOC. Switch by setting `book.kind`.

Per-template guides: [docs/templates/](./docs/templates/).

More templates land as more foundations ship — `cv`, `resume`, `thesis` are on the roadmap for upcoming releases.

## Custom foundations

Any foundation that declares an `outputs: { … }` map on its default export can drive unipress. Point `document.yml`'s `foundation:` at:

- a registry ref: `@<namespace>/<name>@<version>` — fetched from the Uniweb registry, cached locally,
- a URL: `https://…/entry.js`,
- a local filesystem path: `./foundation`, `/abs/path`, etc.

The local-path form is the everyday dev loop — point unipress at a foundation directory you're iterating on, no publish step needed:

```bash
unipress compile my-doc --foundation ../my-foundation
```

For the foundation contract — the `outputs:` map, the `getOptions(website, hostHints)` function, what bytes a foundation can emit — see the [foundation authors' guide](https://github.com/uniweb/docs/blob/main/reference/foundation-config.md#document-outputs). Foundations are distributed via the [Uniweb registry](https://uniweb.io), not npm.

---

Below this point is reference material — useful when you want to do something beyond the basics, or when something doesn't behave as expected.

## CLI reference

```text
unipress compile <dir> [options]
  --format <fmt>      Output format (pdf | typst | docx | xlsx | pagedjs | epub).
                      Overrides the format: field in document.yml.
  --foundation <ref>  Override document.yml's foundation. Accepts:
                        - registry ref:  @<namespace>/<name>@<version>
                        - URL:           https://…/entry.js
                        - path:          ./foundation, /abs/path, …
  --out <path>        Output file (default: ./<dir-basename>.<ext>).
  --variant <name>    Build an alternate top-level config <name>.yml inside <dir>
                      (e.g. --variant document-book → document-book.yml) instead of the
                      default document.yml. Lets one manuscript hold several cuts —
                      an A4 article and a trade book — side by side. The name is used
                      as given (a .yml extension is assumed if omitted).
  --config <path>     Explicit config file (default: <dir>/unipress.config.js).
  --typst-binary <p>  Path to a typst binary (skips the managed download).
  --keep-temp         On typst-compile failure, keep the temp dir for inspection.
  --yes               If no document.yml exists, generate one from the folder's
                      markdown without prompting (book foundation by default;
                      honors --foundation/--format).
  --verbose           Per-step progress to stderr + stack traces on errors.

unipress create <dir> [options]
  --template <id>     Template to scaffold (interactive picker if omitted).
                      Run `unipress list-templates` to see available ids.
  --title <str>       Document title (prompts if omitted).
  --author <str>      Document author (prompts if omitted).
  --force             Overwrite non-empty <dir>.
  --yes               Skip prompts (requires --template).

unipress list-templates
  List the templates available, one per line, with description, outputs,
  the foundation each pins, and the source URL where the foundation lives.

unipress inspect <dir> [options]
  Dump the parsed content as JSON (debugging aid).
  --full              Include web-only fields (assets, icons, etc.).
  --summary           Replace pages[] with route strings only.
  --page <route>      Keep only the page matching <route>.
  --depth <n>         Truncate nested values beyond depth n.
  --foundation <ref>  Override document.yml's foundation.
  --no-orchestrate    Skip running the foundation; show only the parsed content.

unipress --help
unipress --version
```

Exit codes: `0` success, `1` user-addressable error, `2` internal error (re-run with `--verbose` for a stack trace).

## Configuration

### `document.yml`

The content-directory-level config. Fields unipress reads:

| Field | Purpose |
|---|---|
| `name` | Document name (used as a title fallback). |
| `foundation` | Registry ref (`@ns/name@ver`), URL, or local path to the foundation. |
| `format` | Default output format. Overridable by CLI `--format` or `unipress.config.js`. |
| `content:` | Reading order — chapter names with any numeric prefix stripped (`00-intro.md` → `intro`). `pages:` is accepted as an alias. |
| `paths:` | Content-directory overrides. `paths: { pages: . }` reads markdown loose at the project root instead of a `content/` subfolder. |
| `book:`, `report:`, `collections:` … | Foundation-specific config blocks. The foundation's `getOptions` reads these. |

`site.yml` is also accepted as a fallback for compatibility with existing Uniweb site directories.

#### Several cuts of one manuscript

Keep more than one top-level config beside your content and pick one per build with
`--variant`. The same chapters can ship as an A4 article and a trade book:

```text
my-book/
  document.yml         # A4 article (the default: unipress compile .)
  document-book.yml    # trade 6×9 with covers
  assets/front.png
  01-intro.md  02-…

unipress compile .                          # → article (document.yml)
unipress compile . --variant document-book  # → book (document-book.yml)
```

`--variant <name>` reads `<name>.yml` from the content directory — the name is used as
given (no prefixing) with `.yml` assumed when omitted. Config-declared assets —
`book.covers.front`, banners, logos — are resolved from the config the build reads, so
**covers must live in the config unipress reads** (the `--variant` file or the default
`document.yml`), not in a `unipress.config.js` `--config` override, whose asset paths
aren't scanned.

### `unipress.config.js`

Optional ESM file for things awkward in YAML — imports, computed values, format-specific overrides. Auto-discovered at `<dir>/unipress.config.js` or explicit via `--config <path>`.

```js
import { defineUnipressConfig } from '@uniweb/unipress'

export default defineUnipressConfig({
  out: './dist/my-book.pdf',           // overrides --out default
  format: 'pdf',                        // overrides document.yml format

  typst: {
    version: '0.14.2',                  // override the pinned Typst version
    binary: '/usr/local/bin/typst',     // skip the managed download
  },
})
```

Plain `export default { … }` works equally well; `defineUnipressConfig` is an identity wrapper for editor autocomplete.

Relative paths in the config (`out`, `foundation`, `typst.binary`) resolve against the **config file's directory** — matching Vite / Astro convention.

### Precedence chain

```
CLI flags > unipress.config.js > document.yml > defaults
```

Applied per-field.

## Typst binary

`--format pdf` requires a Typst binary. unipress pins `0.14.2` and manages the download:

- **Cache location:** `$UNIPRESS_CACHE_DIR` > `$XDG_CACHE_HOME/unipress` > `~/Library/Caches/unipress` (macOS) > `~/.cache/unipress` (fallback). Binary path: `<cache>/typst/<version>/typst`.
- **Override:** pass `--typst-binary <path>` or set `typst.binary` in `unipress.config.js`.
- **Checksum verified:** each download is SHA-256-checked against the digest pinned in `src/typst/versions.js`.

## Where things stand

unipress is **pre-1.0**. The CLI is stable enough to write real documents with — the `book` template, in particular, is well-tested. Future versions may change small things, but `document.yml` files and project folders from today should keep working: scaffolded projects pin a specific foundation version, and registry artifacts are immutable.

**Foundations are fetched on first use.** The bundled templates pin foundations served from `https://uniweb.github.io/unipress/foundations/…`; the first compile downloads and caches the one your `document.yml` names (alongside the Typst binary). To iterate on a foundation locally, pass `--foundation <path>` pointing at a built foundation directory; to point at a different registry, set `UNIWEB_REGISTRY_URL`.

## Documentation

- **[Publishing your book](./docs/publishing/README.md)** — the end-to-end guide for authors: the proof → final workflow, covers and images, trim sizes, EPUB, print-on-demand, ISBNs, and metadata.
- **Template guides** — conventions and settings per document kind: [article](./docs/templates/article.md), [book](./docs/templates/book.md), [monograph](./docs/templates/monograph.md), [report](./docs/templates/report.md), [data-report](./docs/templates/data-report.md), [directory](./docs/templates/directory.md).
- **[Troubleshooting](./docs/troubleshooting.md)** — common errors and fixes; every named error class maps to a cause and a concrete next step.
- **[For developers](./docs/for-developers.md)** — building a foundation: section types, data sources, and custom output formats.

## See also

- [@uniweb/press](https://github.com/uniweb/press) — the output layer foundations consume to produce Word/Excel/Typst/EPUB. Foundation authors interact with it directly.
- [@uniweb/build](https://github.com/uniweb/build) — the framework's content-collection pipeline. unipress consumes the sharp-free `/content` entry.
- [Uniweb](https://uniweb.io) — the larger framework. Foundations originate here; unipress brings them to the command line.

## License

Apache-2.0 — see [LICENSE](./LICENSE).
