# Tome --- ## Authentication The API playground supports several authentication methods. Users can enter credentials that are included in test requests. ## Configuration Add auth settings to your API config: ```javascript export default { api: { spec: "./openapi.yaml", playground: true, auth: { type: "bearer", // "bearer", "apiKey", or "basic" }, }, }; ``` ## Bearer token The most common pattern for modern APIs. A token input appears in the playground header: ```javascript auth: { type: "bearer", } ``` Requests include the header: ``` Authorization: Bearer ``` ## API key For APIs that use key-based authentication: ```javascript auth: { type: "apiKey", name: "X-API-Key", // Header name in: "header", // "header" or "query" } ``` When `in` is `"query"`, the key is appended as a URL parameter instead. ## Basic auth For username/password authentication: ```javascript auth: { type: "basic", } ``` The playground shows username and password fields. The value is sent as a Base64-encoded `Authorization: Basic` header. ## OpenAPI security schemes If your OpenAPI spec defines security schemes, Tome reads them automatically: ```yaml components: securitySchemes: BearerAuth: type: http scheme: bearer ApiKeyAuth: type: apiKey in: header name: X-API-Key ``` When security schemes are defined in the spec, Tome uses them instead of the manual config. You don't need to configure `auth` separately. ## Security notes - Credentials entered in the playground are stored only in browser memory for the current session - Credentials are never sent to Tome's servers — requests go directly from the browser to your API - CORS must be enabled on your API server for playground requests to work - For production APIs, consider providing a sandbox environment URL through the `baseUrl` config --- ## Endpoints Tome renders each API operation from your OpenAPI spec as a structured endpoint section with method badges, parameter tables, request/response schemas, and an optional interactive playground. ## Endpoint layout Each endpoint displays: 1. **Method badge** — Color-coded (GET, POST, PUT, DELETE, PATCH) 2. **Path** — The endpoint URL with path parameters highlighted 3. **Description** — From the operation's `summary` and `description` fields 4. **Parameters** — Path, query, and header parameters in a table 5. **Request body** — Schema rendered with types and descriptions 6. **Responses** — Status codes with response schemas ## Tag grouping Endpoints are organized by their OpenAPI tags. Each tag becomes a section heading: ```yaml paths: /users: get: tags: [Users] summary: List all users /users/{id}: get: tags: [Users] summary: Get user by ID /projects: get: tags: [Projects] summary: List projects ``` This generates two groups: "Users" with two endpoints and "Projects" with one. ## Parameter rendering Parameters are rendered in a table with type information: | Name | Type | In | Required | Description | |------|------|----|----------|-------------| | `id` | string | path | yes | The user ID | | `limit` | integer | query | no | Max results (default: 20) | | `offset` | integer | query | no | Pagination offset | ## Schema display Request and response schemas are rendered recursively. Nested objects show their properties with types: ``` UserResponse { id: string — Unique identifier name: string — Display name email: string — Email address created_at: string — ISO 8601 timestamp settings: { theme: string — "light" or "dark" locale: string — Language code } } ``` Arrays, enums, and `oneOf`/`anyOf` unions are all supported. ## Interactive playground When `playground` is true in your config, each endpoint gets a "Try it" section where users can: - Fill in path and query parameters - Edit the request body as JSON - Set authentication headers - Send the request and view the response ```javascript api: { spec: "./openapi.yaml", playground: true, baseUrl: "https://api.example.com", // Override base URL }, ``` The playground uses `fetch` directly from the browser. CORS must be enabled on your API for cross-origin requests. --- ## Overview Tome generates a complete API reference from an OpenAPI 3.x specification. Point it at a spec file and get rendered endpoint documentation with an interactive playground — no manual writing required. ## Setup Add the `api` section to your `tome.config.js`: ```javascript export default { name: "My API Docs", api: { spec: "./openapi.yaml", // Path to your OpenAPI spec playground: true, // Enable interactive playground }, }; ``` Tome parses the spec at build time and generates: - Endpoint listing organized by tags - Request/response schema documentation - Parameter tables with types and descriptions - An interactive playground for testing endpoints ## Supported formats | Format | Extension | |--------|-----------| | OpenAPI 3.0 | `.json`, `.yaml`, `.yml` | | OpenAPI 3.1 | `.json`, `.yaml`, `.yml` | Swagger 2.x specs are not directly supported. Convert them first using tools like `swagger2openapi`. ## What gets generated From a single spec file, Tome creates: - **Endpoint pages** — Each operation (GET, POST, PUT, DELETE) gets its own section with method, path, description, and parameters. - **Schema documentation** — Request bodies and response objects are rendered with type information. - **Tag grouping** — Operations are organized by their OpenAPI tags. - **Try it** — The playground lets users send real requests with custom parameters and see responses. ## Spec organization For the best results, make sure your OpenAPI spec includes: - Descriptive `summary` and `description` fields on each operation - Tags to group related endpoints - Schema definitions with `description` fields - Example values for parameters and request bodies ## Next steps - **[Endpoints](api-endpoints)** for details on how endpoints are rendered - **[Authentication](api-auth)** for configuring auth in the playground --- ## CLI Reference The `tome` CLI is the primary interface for creating, developing, building, and deploying documentation sites. ## Installation ```bash npm install -D @tomehq/cli # or globally npm install -g @tomehq/cli ``` ## Commands ### `tome init [name]` Create a new Tome documentation project. ```bash tome init my-docs ``` | Argument | Default | Description | |----------|---------|-------------| | `name` | `my-docs` | Project directory name | | Flag | Default | Description | |------|---------|-------------| | `-t, --template ` | `default` | Starter template | Creates `tome.config.js`, `package.json`, `index.html`, `.tome/entry.tsx`, starter pages in `pages/`, and `public/` and `styles/` directories. --- ### `tome dev` Start the development server with hot reloading. ```bash tome dev tome dev -p 4000 tome dev --host ``` | Flag | Default | Description | |------|---------|-------------| | `-p, --port ` | `3000` | Server port | | `--host` | `false` | Expose to network (bind `0.0.0.0`) | Watches `pages/` for file changes and reloads automatically. Config changes trigger a full reload. --- ### `tome build` Build the documentation site for production. ```bash tome build tome build -o dist ``` | Flag | Default | Description | |------|---------|-------------| | `-o, --outDir ` | `out` | Output directory | Produces a static site and runs Pagefind to build the search index. --- ### `tome deploy` Deploy the site to Tome Cloud. Requires `tome login` first. ```bash tome deploy ``` Builds, collects output files, and uploads using hash-based deduplication. --- ### `tome login` Authenticate with Tome Cloud. ```bash tome login ``` Prompts for email and sends a magic link. Stores the API token locally. --- ### `tome domains:add ` Add a custom domain. Returns DNS records to configure. ```bash tome domains:add docs.example.com ``` ### `tome domains:verify ` Verify DNS configuration for a custom domain. ```bash tome domains:verify docs.example.com ``` ### `tome domains:list` List all custom domains for the current project. ### `tome domains:remove ` Remove a custom domain. --- ### `tome algolia:init` Initialize an Algolia DocSearch index. Prompts for credentials and creates a crawler configuration. --- ### `tome typedoc ` Generate API reference documentation from TypeScript source files. ```bash tome typedoc src/index.ts tome typedoc src/index.ts src/utils.ts ``` Parses exported functions, interfaces, and type aliases using the TypeScript compiler API. Generates a Markdown page per export with signatures, parameters, return types, and JSDoc descriptions. --- ### `tome mcp` Start the MCP (Model Context Protocol) stdio server for AI tool integration. Exposes documentation content as MCP resources and tools. --- ## Architecture Tome is built on Vite and React. Understanding the architecture helps when debugging build issues or building advanced customizations. ## Overview A Tome site is a Vite application with a custom plugin that handles page discovery, routing, and content processing. The theme package provides the React UI shell. ```mermaid flowchart LR A["tome.config.js"] --> B["Vite Plugin"] B --> C["Virtual Modules"] C --> D["Theme Shell"] D --> E["Static Site"] ``` ## Vite plugin The core of Tome is `vite-plugin-tome` in `@tomehq/core`. It has three responsibilities: **1. Page discovery** — On startup, the plugin scans `pages/` for `.md` and `.mdx` files, extracts frontmatter, and builds a route table. It watches for file changes during development and triggers hot reloads. **2. Virtual modules** — The plugin exposes content through Vite's virtual module system: | Module | Contents | |--------|----------| | `virtual:tome/config` | The resolved config as JSON | | `virtual:tome/routes` | Route table with IDs, URLs, and frontmatter | | `virtual:tome/page/:id` | Processed page content | | `virtual:tome/api` | Parsed OpenAPI manifest | | `virtual:tome/analytics` | Analytics provider settings | **3. Build-time generation** — During builds, the plugin injects analytics scripts, JSON-LD schema markup, and generates machine-readable files (`mcp.json`, `llms.txt`, `skill.md`, `robots.txt`, `search.json`). ## Theme system The theme package (`@tomehq/theme`) provides the React shell: - **Shell component** — Header, sidebar, content area, footer - **Preset system** — Color tokens and CSS variables per preset - **Search integration** — Pagefind or Algolia, loaded dynamically - **AI chat** — Optional floating widget The entry point (`.tome/entry.tsx`) bootstraps the shell by importing `@tomehq/theme/entry`. ## Content pipeline ```mermaid flowchart TD A["pages/*.md"] --> B["gray-matter"] B --> C["Frontmatter"] B --> D["Markdown body"] D --> E["remark + rehype"] E --> F["Shiki highlighting"] F --> G["DOMPurify sanitize"] G --> H["HTML + headings"] I["pages/*.mdx"] --> J["Extract frontmatter"] J --> K["@mdx-js/rollup"] K --> L["React component"] ``` ### Markdown (`.md`) 1. Frontmatter extracted via `gray-matter` 2. Markdown processed through remark (GFM, math) and rehype (slugs, autolink headings) 3. Code blocks highlighted with Shiki (mermaid blocks converted to client-side placeholders) 4. HTML sanitized with DOMPurify, headings extracted for table of contents 5. HTML + headings + frontmatter served as virtual module ### MDX (`.mdx`) 1. Frontmatter and headings extracted from raw source 2. Custom remark plugins transform `mermaid` and `math` code blocks into JSX placeholder elements 3. File passed to `@mdx-js/rollup` for JSX compilation 4. Virtual module re-exports the compiled React component + metadata 5. Client-side: mermaid and KaTeX render the placeholders (same as `.md` files) ## Build output ```text out/ ├── index.html # SPA entry with JSON-LD schema ├── assets/ │ ├── index-[hash].js # Application bundle │ └── index-[hash].css # Styles ├── [page]/index.html # Per-page HTML shells (SEO + Pagefind) ├── _pagefind/ # Search index ├── mcp.json # MCP manifest ├── llms.txt # AI-readable page index ├── llms-full.txt # Full page content for LLMs ├── skill.md # Agent capability file ├── robots.txt # Crawler directives (AI-friendly) ├── search.json # Structured page index (JSON API) ├── og/ # Auto-generated Open Graph images └── 404.html # Error page ``` The output is a single-page application with per-page HTML shells for SEO and search indexing. Each page shell contains the content in a `data-pagefind-body` div for Pagefind and a `TechArticle` JSON-LD schema in the ``. Six machine-readable files are auto-generated at build time to make your docs discoverable by AI tools, search engines, and language models — no configuration needed. ## Package structure | Package | Purpose | |---------|---------| | `@tomehq/cli` | CLI commands (init, dev, build, deploy, mcp, typedoc) | | `@tomehq/core` | Config, routing, Vite plugin, markdown processing, MCP server | | `@tomehq/theme` | Shell UI, presets, search, AI chat | | `@tomehq/components` | MDX components (Callout, Tabs, Card, etc.) | | `@tomehq/landing` | Marketing landing page | | `@tomehq/dashboard` | Tome Cloud dashboard | --- ## File-System Routing Every `.md` or `.mdx` file in the `pages/` directory becomes a page. The file path determines the URL. ## Basic routing | File path | URL | |-----------|-----| | `pages/index.md` | `/` | | `pages/quickstart.md` | `/quickstart` | | `pages/guides/deployment.md` | `/guides/deployment` | | `pages/api/endpoints.md` | `/api/endpoints` | | `pages/api/index.md` | `/api` | **Rules:** - `index.md` serves at the directory's root path - File extensions are stripped from the URL - Directory nesting maps directly to URL segments ## Page IDs Each page has an ID derived from its path relative to `pages/`: | File | Page ID | |------|---------| | `pages/index.md` | `index` | | `pages/quickstart.md` | `quickstart` | | `pages/guides/deployment.md` | `guides/deployment` | Page IDs are used in `navigation` config to control sidebar order. ## Navigation vs. routing All pages in `pages/` are routable regardless of whether they appear in `navigation`. Navigation only controls the sidebar. Pages can be hidden from the sidebar using `hidden: true` in frontmatter while remaining accessible at their URL. ## i18n routing When multiple locales are configured, organize pages by locale subdirectory: ```text pages/ ├── en/ # Default locale │ ├── index.md │ └── quickstart.md ├── es/ # Spanish │ ├── index.md │ └── quickstart.md ``` | File | URL | |------|-----| | `pages/en/index.md` | `/` (default — no prefix) | | `pages/es/index.md` | `/es/` | | `pages/es/quickstart.md` | `/es/quickstart` | The default locale serves at the root without a prefix. When `fallback: true` and a page doesn't exist in a non-default locale, the default version is used. ## Versioned routing When versioning is configured: ```text pages/ ├── current/ # Latest version │ ├── index.md │ └── api.md ├── v1.0/ │ ├── index.md │ └── api.md ``` | File | URL | |------|-----| | `pages/current/index.md` | `/` | | `pages/v1.0/index.md` | `/v1.0/` | | `pages/v1.0/api.md` | `/v1.0/api` | The `current` directory serves at the root. Older versions are prefixed. ## File discovery Tome discovers pages by scanning `pages/` for `**/*.{md,mdx}` files. Discovery runs at startup and again whenever files are added, removed, or renamed during development. --- ## AI Search AI search adds an LLM-powered answer card above your standard Pagefind search results. When a reader searches your docs, the AI reads the top matching pages and synthesizes a concise answer. ## Requirements AI search requires two config options to be set: 1. `search.ai` must be `true` 2. `ai.enabled` must be `true` (this configures the AI provider and API key) ```js // tome.config.js export default { name: "My Docs", search: { ai: true, }, ai: { enabled: true, provider: "anthropic", // or "openai" apiKeyEnv: "TOME_AI_KEY", }, }; ``` ## How it works 1. The reader types a query in the search modal (`Ctrl+K` / `Cmd+K`) 2. Pagefind runs its standard keyword search and returns matching pages 3. The top 5 results are sent as context to the configured LLM 4. The AI generates a 2-3 sentence answer based on the documentation content 5. The answer appears in a highlighted card above the keyword results The keyword results remain fully functional. The AI answer is an addition, not a replacement. ## Bring your own key (BYOK) AI search uses the same API key and provider as [AI Chat](/v3/guides/ai-chat). Set your API key in the environment variable specified by `apiKeyEnv` (default: `TOME_AI_KEY`): ```bash TOME_AI_KEY=sk-ant-... npx @tomehq/cli dev ``` Supported providers: | Provider | `provider` value | Models | |----------|-----------------|--------| | Anthropic | `"anthropic"` | Claude (default) | | OpenAI | `"openai"` | GPT-4o (default) | ## Privacy The API key is injected at build time and used client-side. Search queries and page content are sent directly from the reader's browser to the AI provider. Tome does not proxy or store these requests. ## Disabling AI search Remove `search.ai` or set it to `false`: ```js search: { ai: false, }, ``` Standard Pagefind keyword search continues to work without any AI features. --- ## API Diff The `api:diff` command compares two OpenAPI specifications and reports what changed between them. It detects breaking changes, additions, deprecations, and documentation updates. ## Usage ```bash npx @tomehq/cli api:diff ``` Both arguments are paths to OpenAPI spec files (JSON or YAML): ```bash npx @tomehq/cli api:diff openapi-v1.yaml openapi-v2.yaml ``` The output is a Keep-a-Changelog formatted markdown summary. ## What gets detected ### Breaking changes - Removed endpoints - Removed required parameters - Parameter type changes (e.g., `string` to `integer`) - Parameter made required (was optional) - Removed request body - Request body content type changed - Request body made required (was optional) - Removed success responses (2xx status codes) ### Non-breaking changes - Added endpoints - Added optional parameters - Parameter made optional (was required) - Added responses - Removed non-success responses ### Deprecations - Endpoints marked as deprecated ### Documentation-only changes - Updated summary or description text (not included in the changelog output) ## Output formats ### Markdown (default) The default output is a changelog entry in Keep-a-Changelog format: ``` ## [2.0.0] - 2026-04-02 ### Breaking Changes - Removed GET /users/{id}/legacy - Parameter `filter` type changed from `string` to `integer` on GET /users ### Added - Added POST /users/bulk ### Deprecated - Deprecated GET /users/search ``` ### JSON Use the `--json` flag to get structured output for programmatic use: ```bash npx @tomehq/cli api:diff old.yaml new.yaml --json ``` Returns a JSON object with `changes` (array of change objects), `summary` (counts by severity), `hasBreaking`, `oldVersion`, and `newVersion`. ## CI integration ### Fail on breaking changes Use `--fail-on-breaking` to exit with code 1 when breaking changes are detected: ```bash npx @tomehq/cli api:diff old.yaml new.yaml --fail-on-breaking ``` This is useful in CI pipelines to block merges that introduce breaking API changes. ### Example GitHub Actions step ```yaml - name: Check for breaking API changes run: npx @tomehq/cli api:diff api/v1.yaml api/v2.yaml --fail-on-breaking ``` ## Combining both flags ```bash npx @tomehq/cli api:diff old.yaml new.yaml --json --fail-on-breaking ``` Outputs JSON and exits with code 1 if any breaking change is found. The JSON `hasBreaking` field indicates whether breaking changes exist. --- ## API Reference Setup Tome can generate a full API reference from an OpenAPI 3.x specification. The reference includes endpoint documentation, request/response schemas, and an interactive playground for testing endpoints. ## 1. Add your OpenAPI spec Place your OpenAPI spec file (JSON or YAML) in your project: ```text my-docs/ ├── openapi.yaml # Your API spec ├── tome.config.js └── pages/ ``` ## 2. Configure Tome Add the `api` section to your config: ```javascript export default { name: "My API Docs", api: { spec: "./openapi.yaml", playground: true, baseUrl: "https://api.example.com", auth: { type: "bearer", header: "Authorization", }, }, }; ``` ### Options | Field | Type | Default | Description | |-------|------|---------|-------------| | `spec` | string | — | Path to your OpenAPI spec file (required) | | `playground` | boolean | `true` | Enable the interactive API playground | | `baseUrl` | string | — | Base URL for playground requests | | `auth.type` | string | — | Auth type: `"bearer"`, `"apiKey"`, or `"oauth2"` | | `auth.header` | string | — | Header name for the auth token | ## 3. View the reference Start the dev server and navigate to `/api`. Tome parses the spec and renders: - **Endpoint groups** organized by OpenAPI tags - **Request parameters** with types, descriptions, and required markers - **Response schemas** with expandable nested objects - **Code examples** for `curl`, JavaScript, and Python ## 4. Interactive playground When `playground: true`, each endpoint includes a "Try It" panel where users can: - Set path parameters and query strings - Edit the request body with JSON validation - Add authentication headers - Send requests and view formatted responses The playground sends requests directly from the browser, so CORS must be configured on your API server. ## Supported spec formats Tome supports OpenAPI 3.0 and 3.1 specifications in JSON or YAML format. Swagger 2.x specs are not supported — convert them with tools like `swagger2openapi`. --- ## AsyncAPI Reference Tome can generate documentation from AsyncAPI specifications, covering WebSocket, MQTT, Kafka, AMQP, and other event-driven protocols. This works alongside or independently of OpenAPI. ## Configuration Point your config to an AsyncAPI spec file: ```js // tome.config.js export default { name: "My Docs", api: { asyncSpec: "./asyncapi.yaml", }, }; ``` Both JSON and YAML formats are supported. The spec must be AsyncAPI version 2.x. ## Coexisting with OpenAPI You can document both REST and event-driven APIs on the same site: ```js api: { spec: "./openapi.yaml", asyncSpec: "./asyncapi.yaml", }, ``` Both specs are parsed and rendered on the API reference page. ## What gets documented Tome extracts and renders the following from your AsyncAPI spec: ### Servers Each server entry is displayed with its URL, protocol, and description. ### Channels Channels are the core of an AsyncAPI spec. Each channel is documented with: - **Channel path** (e.g., `user/signedup`) - **Description** - **Parameters** with types and descriptions - **Publish operation** (messages the client can send) - **Subscribe operation** (messages the client can receive) - **Protocol bindings** (if specified) ### Messages Each operation's message is documented with: - Name and description - Content type - Payload schema (rendered as a structured table) - Example payloads (if provided in the spec) ### Protocol badges Channels display protocol badges based on the server protocol: | Protocol | Badge | |----------|-------| | `ws` / `wss` | WebSocket | | `mqtt` / `mqtts` | MQTT | | `kafka` | Kafka | | `amqp` / `amqps` | AMQP | ### Code samples Tome auto-generates code samples for each channel based on the server protocol. For example, a WebSocket channel produces a JavaScript snippet showing how to connect, send, and receive messages: ```js const ws = new WebSocket("wss://api.example.com/user/signedup"); ws.onopen = () => { console.log("Connected to user/signedup"); }; ws.onmessage = (event) => { const data = JSON.parse(event.data); console.log("Received:", data); }; ``` Code samples are generated for WebSocket, MQTT, Kafka, and AMQP protocols. ## Supported features - AsyncAPI 2.x (JSON and YAML) - `$ref` resolution (internal references only) - Server definitions with protocol detection - Channel parameters - Publish and subscribe operations - Message schemas and examples - Tag-based grouping --- ## Code Blocks Tome uses [Shiki](https://shiki.style) for syntax highlighting. All standard fenced code blocks work out of the box with no configuration. This guide covers the additional features available on top of basic highlighting. ## Syntax highlighting Use a language identifier after the opening fence: ```javascript const greeting = "hello"; console.log(greeting); ``` Shiki supports [200+ languages](https://shiki.style/languages). Common identifiers: `javascript`, `typescript`, `python`, `go`, `rust`, `bash`, `json`, `yaml`, `sql`, `graphql`, `html`, `css`. ## Code block titles Add a `title` attribute to show a filename or label above the code block: ```javascript title="tome.config.js" export default { name: "My Docs", }; ``` The title renders as a label bar above the code, styled to match your theme. ## Line highlighting Highlight specific lines using curly braces after the language: ```javascript {2,4} const a = 1; const b = 2; // highlighted const c = 3; const d = 4; // highlighted ``` Use ranges for consecutive lines: ```javascript {1,3-5} import { config } from "./config"; // highlighted export function init() { // highlighted config.load(); // highlighted config.validate(); // highlighted } ``` Highlighted lines receive a subtle background color that works in both light and dark mode. ## Line numbers Show line numbers in the gutter with `showLineNumbers`: ```typescript showLineNumbers interface User { id: string; name: string; email: string; } ``` You can also use `lineNumbers` as an alias. ## Combining features All meta attributes can be combined on a single code fence: ```typescript title="types.ts" showLineNumbers {3-4} interface Config { name: string; theme: ThemeOptions; // highlighted plugins: Plugin[]; // highlighted } ``` ## Twoslash (TypeScript hover types) Twoslash renders TypeScript type information inline — the same hover popups you see in VS Code, but rendered statically in your docs. This is powerful for documenting TypeScript APIs where seeing inferred types matters. ````markdown ```ts twoslash const user = { name: "Alice", age: 30, }; user.name; // ^? ``` ```` The `^?` marker tells Twoslash to show the inferred type at that position. In the rendered output, hovering over `user.name` displays `(property) name: string`. ### Setup Twoslash requires an optional peer dependency: ```bash npm install @shikijs/twoslash ``` If the package is not installed, Tome logs a warning and renders the code block without type annotations — your build won't break. ### Twoslash features | Syntax | Effect | |--------|--------| | `// ^?` | Show type at cursor position | | `// @errors: 2304` | Expect and display a TypeScript error | | `// @noErrors` | Suppress all TypeScript errors | | `// ---cut---` | Hide code above this line (setup code) | Example with hidden setup code: ````markdown ```ts twoslash interface User { id: string; name: string; } // ---cut--- function greet(user: User) { return `Hello, ${user.name}`; } // ^? ``` ```` Only the code below `---cut---` is shown in the rendered output, but the `User` type is still available for inference. ## Copy button Every code block includes a copy-to-clipboard button in the top-right corner. This is automatic — no configuration or markup needed. ## Diff highlighting Show added and removed lines in code blocks using inline markers: ```javascript const config = { name: "My Docs", // [!code --] name: "Acme Docs", // [!code ++] }; ``` Lines marked with `// [!code --]` are styled with a red background, and `// [!code ++]` with a green background. The markers are stripped from the rendered output. --- ## Content Negotiation Every page in your Tome site is available as raw markdown, with no extra configuration. This makes your documentation accessible to AI agents, CLI tools, and any client that prefers plain text over HTML. ## Accessing markdown There are two ways to get the raw markdown for any page: ### Append `.md` to the URL Add `.md` to any page URL to get the raw markdown source: ``` https://docs.example.com/quickstart → HTML page https://docs.example.com/quickstart.md → Raw markdown ``` ### Send an `Accept` header Request any page URL with `Accept: text/markdown` or `Accept: text/plain`: ```bash curl -H "Accept: text/markdown" https://docs.example.com/quickstart ``` Both approaches return the original markdown source with `Content-Type: text/markdown; charset=utf-8`. ## HTML discovery Every HTML page includes a `` tag so clients can discover the markdown alternative: ```html ``` ## llms.txt Tome auto-generates an `llms.txt` file at your site root. This follows the emerging standard for LLM-friendly site indexes: ``` https://docs.example.com/llms.txt ``` The file contains your site name, a one-line description, and a list of all pages with their titles, descriptions, and URLs. Hidden and draft pages are excluded. ## llms-full.txt For agents that want the complete content, `llms-full.txt` concatenates the raw markdown of every page into a single file: ``` https://docs.example.com/llms-full.txt ``` Pages are separated by `---` dividers. MDX pages and the API reference page are excluded since they contain JSX that is not useful as raw text. ## Additional machine-readable files Tome also generates these files automatically during every build: | File | Description | |------|-------------| | `search.json` | Structured page index with titles, headings, and word counts | | `mcp.json` | Machine-readable metadata for MCP-compatible agents | | `skill.md` | Agent capabilities document describing how to use the site | | `robots.txt` | Crawler directives with AI agent permissions | | `sitemap.xml` | Standard sitemap for search engines | No configuration is needed. All files are generated at build time and included in the output. --- ## Content Sources Content sources let you pull documentation from external services — GitHub repos, Notion databases, or custom APIs — and merge them with your local pages at build time. Remote pages are treated exactly like local files: they appear in navigation, search, and the route manifest. ## Configuration Add content sources to the `contentSources` array in your config: ```javascript import { githubSource, notionSource } from "@tomehq/core/content-source"; export default { name: "My Docs", contentSources: [ githubSource({ owner: "acme", repo: "sdk-docs", path: "docs", }), ], }; ``` ## GitHub source Pull `.md` and `.mdx` files from a GitHub repository: ```javascript import { githubSource } from "@tomehq/core/content-source"; githubSource({ owner: "acme", // GitHub org or user repo: "sdk-docs", // Repository name branch: "main", // Branch to pull from (default: "main") path: "docs", // Directory within the repo (default: "docs") token: process.env.GH_TOKEN, // Optional — required for private repos }) ``` The source fetches the repo tree via the GitHub API, then downloads each `.md` / `.mdx` file from the specified path. File paths within the directory become page IDs — `docs/getting-started.md` becomes the page ID `getting-started`. ### Private repositories For private repos, pass a GitHub personal access token (classic or fine-grained) with `contents:read` permission: ```javascript githubSource({ owner: "acme", repo: "internal-docs", token: process.env.GH_TOKEN, }) ``` ## Notion source Pull pages from a Notion database: ```javascript import { notionSource } from "@tomehq/core/content-source"; notionSource({ databaseId: "abc123...", // Notion database ID apiKey: process.env.NOTION_TOKEN, // Notion integration token }) ``` Each page in the database is converted to Markdown: - The page title becomes the `title` frontmatter field - Headings, paragraphs, lists, code blocks, quotes, and dividers are converted - Bold, italic, code, and link annotations are preserved - The title is slugified to create the page ID (`Getting Started` becomes `getting-started`) ### Setting up the Notion integration 1. Go to [notion.so/my-integrations](https://www.notion.so/my-integrations) and create a new integration 2. Copy the integration token 3. Share your database with the integration (click "..." on the database, then "Connections") ## Custom content sources Use `defineContentSource` to create your own source with full type checking: ```javascript import { defineContentSource } from "@tomehq/core/content-source"; const apiSource = defineContentSource({ name: "my-api", async fetchPages() { const res = await fetch("https://api.example.com/docs"); const data = await res.json(); return data.pages.map((page) => ({ id: page.slug, content: `---\ntitle: ${page.title}\n---\n\n${page.body}`, format: "md", lastModified: page.updatedAt, })); }, }); ``` Each page must return: | Field | Type | Description | |-------|------|-------------| | `id` | `string` | Page identifier (used for URL and navigation) | | `content` | `string` | Raw Markdown/MDX including frontmatter | | `format` | `"md"` or `"mdx"` | File format | | `lastModified` | `string?` | ISO 8601 date (optional) | Custom sources can also implement an optional `watch` method for development mode — return a cleanup function to stop watching: ```javascript defineContentSource({ name: "polling-api", async fetchPages() { /* ... */ }, watch(onChange) { const interval = setInterval(async () => { const pages = await this.fetchPages(); onChange(pages); }, 30000); // Poll every 30 seconds return () => clearInterval(interval); }, }); ``` ## Using multiple sources You can combine any number of content sources. Remote pages are merged with local files — if a remote page has the same ID as a local page, the local page takes priority. ```javascript import { githubSource, notionSource } from "@tomehq/core/content-source"; export default { name: "My Docs", contentSources: [ githubSource({ owner: "acme", repo: "sdk-docs", path: "docs" }), notionSource({ databaseId: "abc123", apiKey: process.env.NOTION_TOKEN }), ], }; ``` Content is fetched once at build time (and on startup in dev mode). Failed sources log a warning but don't block the build — your local pages will still work. ## External group in the sidebar When you use an explicit `navigation` array in your config, remote pages that are **not** listed in the navigation will automatically appear under an "External" group at the bottom of the sidebar. This ensures fetched content is always accessible even if you haven't manually added every remote page to your navigation config. If you want full control over placement, add the remote page IDs to your `navigation` array and they will appear in the specified group instead. --- ## Custom Theme Tome ships with two theme presets and extensive customization options. Every visual aspect — colors, fonts, spacing — can be adjusted through configuration or CSS variables. ## Presets Choose between two built-in presets: ### Amber (default) A warm, approachable aesthetic with golden accent tones. Good for developer documentation and technical guides. ```javascript theme: { preset: "amber", } ``` ### Editorial A refined, high-contrast aesthetic inspired by Swiss poster design and literary magazines. Features serif headings and a more dramatic visual presence. ```javascript theme: { preset: "editorial", } ``` See [Theme presets reference](reference/theme-presets) for the exact color values. ## Accent color Override the preset's accent color with any hex value: ```javascript theme: { preset: "amber", accent: "#2563eb", // Blue accent instead of amber } ``` Tome derives tint and dim variants automatically from your accent color. ## Color mode Control dark/light mode behavior: | Value | Behavior | |-------|----------| | `"auto"` | Follows system preference (default) | | `"light"` | Always light mode | | `"dark"` | Always dark mode | Users can toggle the mode using the theme switch in the header. ## Custom fonts Override any font family. Make sure to add the appropriate `` tag to `index.html` if using custom Google Fonts. ```javascript theme: { fonts: { heading: "Playfair Display", body: "Source Sans Pro", code: "Fira Code", }, } ``` ## CSS variables For fine-grained control, override CSS variables in a custom stylesheet. The key variables are: | Variable | Description | |----------|-------------| | `--ac` | Accent color | | `--acD` | Accent dark variant | | `--acT` | Accent tint | | `--bg` | Page background | | `--sf` | Surface (cards, sidebar) | | `--sfH` | Surface hover state | | `--bd` | Border color | | `--tx` | Primary text | | `--tx2` | Secondary text | | `--txM` | Muted text | See the [Theme presets reference](reference/theme-presets) for the complete variable list with values per preset. ## Border radius Adjust the global border radius: ```javascript theme: { radius: "4px", // Sharper corners radius: "12px", // Rounder corners } ``` --- ## Draft Pages Tome supports draft pages — content that is visible during local development but automatically excluded from production builds. This is useful for work-in-progress content, internal notes, or pages you want to preview before publishing. ## Marking a page as a draft Add `draft: true` to the page's frontmatter: ```markdown --- title: Upcoming Feature draft: true --- This page is a work in progress. It won't appear in production. ``` That's it. No other configuration is needed. ## How drafts behave ### Development (`tome dev`) Draft pages are **included** in development. They appear in the sidebar navigation and are fully routable. A yellow banner is shown at the top of the page: > Draft — This page is only visible in development This makes it easy to tell at a glance which pages are drafts while you work. ### Production (`tome build`) Draft pages are **excluded** from production builds: - Removed from the sidebar navigation - Removed from the route manifest (no URL is generated) - Excluded from `llms.txt` and `search.json` - Not included in the page loader bundle If someone navigates to a draft page's URL in production, they'll get a 404. ## Use cases **Work-in-progress content.** Start writing a new guide and set `draft: true`. Preview it locally, share the dev URL with teammates, then remove the flag when it's ready. **Internal notes.** Keep internal-only pages (runbooks, architecture decisions) as permanent drafts so they never leak into the public site. **Staged launches.** Write docs for an upcoming feature ahead of time. When the feature ships, remove `draft: true` from all related pages and redeploy. ## Combining with `hidden` Drafts and hidden pages are different: | Frontmatter | Dev sidebar | Dev URL | Prod sidebar | Prod URL | |-------------|-------------|---------|-------------- |----------| | *(default)* | Visible | Works | Visible | Works | | `hidden: true` | Hidden | Works | Hidden | Works | | `draft: true` | Visible | Works | Hidden | 404 | Use `hidden` for pages that should exist in production but not appear in navigation (e.g., linked from other pages). Use `draft` for pages that should not exist in production at all. --- ## WYSIWYG Editor # WYSIWYG Editor Edit documentation pages directly in your browser. The editor renders a visual editing experience with live formatting, MDX component insertion, and one-click publishing. ## Accessing the editor Navigate to your project in the dashboard, then click "Edit in Editor" to open the visual editor. The editor URL follows this pattern: ``` https://tome.center/dashboard/project/{your-project}/editor ``` ## Editing pages The editor has two panels: - **Left sidebar**: page tree showing all pages with their status (draft or published) - **Main area**: the visual editor with formatting toolbar Select a page from the sidebar to load it. Changes auto-save every 2 seconds. ## Formatting toolbar The toolbar provides quick access to common formatting: | Button | Action | Shortcut | |--------|--------|----------| | **B** | Bold | Cmd+B | | *I* | Italic | Cmd+I | | `` | Inline code | Cmd+E | | H1-H4 | Headings | — | | • | Bullet list | — | | 1. | Numbered list | — | | " | Blockquote | — | | — | Horizontal rule | — | | ↩ | Undo | Cmd+Z | | ↪ | Redo | Cmd+Shift+Z | ## Slash commands Type `/` at the start of a line to open the command menu. Available commands: - `/heading1`, `/heading2`, `/heading3` — insert headings - `/bulletList`, `/orderedList` — insert lists - `/codeBlock` — insert a fenced code block - `/blockquote` — insert a quote - `/divider` — insert a horizontal rule - `/callout` — insert an info/warning/tip callout - `/tabs` — insert tabbed content sections - `/steps` — insert a step-by-step guide - `/accordion` — insert a collapsible section - `/card` — insert a feature card ## Keyboard shortcuts | Shortcut | Action | |----------|--------| | Cmd+S | Save draft | | Cmd+Shift+P | Publish page | | Cmd+B | Bold | | Cmd+I | Italic | | Cmd+E | Inline code | | Cmd+Z | Undo | | Cmd+Shift+Z | Redo | ## Creating pages Click "New Page" in the sidebar. Enter a path (e.g. `guides/getting-started`) and title. The page starts as a draft. ## Publishing Click the "Publish" button to deploy the page to your live documentation site. If your project has a connected GitHub repository, the editor also commits the markdown file to your repo. The publish flow: 1. Saves the current draft 2. Writes the markdown file to cloud storage 3. If GitHub connected: creates a commit in your repository 4. Page is immediately live at your documentation URL ## Draft vs published Pages have two states: - **Draft**: saved in the editor, not visible on your live site - **Published**: deployed to your documentation URL The sidebar shows status badges for each page. ## Frontmatter The editor includes fields for page metadata: - **Title**: the page heading (maps to `title` in frontmatter) - **Description**: page description for SEO and search Additional frontmatter fields (icon, tags, access) can be set by editing the markdown source directly. ## Security The editor sanitizes all content before saving. Raw JavaScript expressions (`{expression}`) are stripped from the output. Only known MDX components (Callout, Tabs, Card, etc.) are preserved. This prevents code injection during server-side rendering. ## Markdown source of truth The editor reads and writes standard markdown. No proprietary format. You can edit the same pages in your code editor, push via Git, and the changes appear in the visual editor on next load. --- ## Feedback Widget Tome includes a feedback widget at the bottom of every documentation page. Readers can rate pages with a thumbs up or thumbs down, helping you identify content that needs improvement. ## Default behavior The feedback widget is **enabled by default**. No configuration is needed. Every page displays a "Was this page helpful?" prompt with thumbs up and thumbs down buttons. ## Configuration Customize the feedback widget in `tome.config.js`: ```js export default { name: "My Docs", feedback: { enabled: true, textInput: true, }, }; ``` ### Options | Option | Type | Default | Description | |--------|------|---------|-------------| | `enabled` | `boolean` | `true` | Show or hide the feedback widget | | `textInput` | `boolean` | `false` | Show a text input for additional comments after rating | ### Disabling feedback ```js feedback: { enabled: false, } ``` ## Text input mode When `textInput` is `true`, clicking a thumb button reveals a text field where the reader can leave an optional comment. The reader can submit the comment or skip it. ## Analytics integration Feedback events are automatically tracked when [analytics](/v3/guides/search-analytics) is configured. Each feedback event includes: - **Page ID** identifying which page was rated - **Rating** (`up` or `down`) - **Comment** (if text input is enabled and the reader provided one) The feedback widget calls `window.__tome.trackFeedback(pageId, rating, comment)` to send events to your analytics endpoint. ## Persistence Feedback state is stored in `localStorage` per page. If a reader has already rated a page, they see a "Thanks for your feedback!" message instead of the rating buttons on subsequent visits. This prevents duplicate submissions from the same browser. --- ## Migrate from GitBook or Mintlify Tome provides automated migration from GitBook and Mintlify. The CLI handles navigation restructuring, component syntax conversion, redirect mapping, and asset copying. ## Migrate from GitBook ```bash npx @tomehq/cli migrate gitbook ./path-to-gitbook-project ``` ### What gets converted | GitBook | Tome | |---------|------| | `SUMMARY.md` navigation | `tome.config.js` navigation array | | `.gitbook.yaml` config | `tome.config.js` settings | | `{% hint style="info" %}` | `` | | `{% hint style="warning" %}` | `` | | `{% hint style="danger" %}` | `` | | `{% hint style="success" %}` | `` | | `{% tabs %}` / `{% tab %}` | `` / `` | | `{% code title="file.js" %}` | Fenced code block with title | | `{% embed url="..." %}` | Plain markdown link | | `.gitbook.yaml` redirects | `tome.config.js` redirects | | Images / assets | Copied to `public/` | ### Options ```bash # Output to a specific directory npx @tomehq/cli migrate gitbook ./gitbook-docs --out ./my-new-docs # Preview without writing files npx @tomehq/cli migrate gitbook ./gitbook-docs --dry-run ``` ### How it works 1. Reads `SUMMARY.md` for navigation structure and `.gitbook.yaml` for project settings 2. Walks all Markdown files and converts GitBook-specific syntax to Tome MDX components 3. Files containing converted JSX components are renamed from `.md` to `.mdx` 4. Copies static assets (images, `.gitbook/assets/`) to `public/` 5. Generates `tome.config.js` with navigation, redirects, and project name 6. Reports a summary of pages converted, redirects created, and any warnings --- ## Migrate from Mintlify ```bash npx @tomehq/cli migrate mintlify ./path-to-mintlify-project ``` Both `docs.json` (Mintlify's current config format) and `mint.json` (deprecated) are supported. The migration tool automatically detects which file is present, preferring `docs.json` if both exist. ### What gets converted | Mintlify | Tome | |----------|------| | `docs.json` / `mint.json` navigation | `tome.config.js` navigation array | | `docs.json` / `mint.json` colors | `tome.config.js` theme accent | | `docs.json` / `mint.json` logo / favicon | `tome.config.js` logo / favicon | | `docs.json` / `mint.json` topbar links | `tome.config.js` topNav | | `docs.json` / `mint.json` redirects | `tome.config.js` redirects | | `docs.json` / `mint.json` openapi | `tome.config.js` api.spec | | `` / `` | `` | | `` | `` | | `` / `` | `` | | `` | `` wrapper | | `` | Removed (individual `` kept) | | `` | Removed (content preserved) | | `` | Inlined file content | Components that are already compatible (``, ``, ``, ``, ``) are kept as-is. ### Options ```bash # Output to a specific directory npx @tomehq/cli migrate mintlify ./mintlify-docs --out ./my-new-docs # Preview without writing files npx @tomehq/cli migrate mintlify ./mintlify-docs --dry-run ``` --- ## After migration ### Review redirects Both migration tools automatically extract redirects from the source project and add them to `tome.config.js`. Check the generated config to verify redirect paths are correct: ```js export default defineConfig({ redirects: [ { from: "/old-page", to: "/new-page" }, ], }); ``` See the [Redirects guide](guides/redirects) for more on how redirects work. ### Start the dev server ```bash cd my-new-docs npm install npm run dev ``` Open [localhost:3000](http://localhost:3000) and review the converted pages. Some manual adjustments may be needed for complex custom components or layouts that don't have a direct Tome equivalent. ### Deploy Once everything looks good, deploy to Tome Cloud: ```bash npx @tomehq/cli login npx @tomehq/cli deploy ``` Or push to your git repository — if you scaffold with `tome init`, a GitHub Actions workflow is included that deploys automatically on push to `main`. --- ## Password Protection Password protection adds a login screen to your Tome Cloud site, requiring visitors to enter a password before they can view any page. This is useful for internal documentation, pre-release content, or client-facing docs that should not be publicly accessible. ## Setting a password Use the `tome protect` command to enable password protection: ```bash npx @tomehq/cli protect ``` You will be prompted to enter a password. The password is hashed locally before being sent to the server. The plaintext password is never transmitted or stored. ## Removing password protection To make your site publicly accessible again: ```bash npx @tomehq/cli protect --remove ``` ## How it works When password protection is enabled: 1. Visitors who navigate to your site are redirected to a branded password page 2. After entering the correct password, a session cookie (`tome_site_session`) is set 3. The cookie is valid for **24 hours**, after which the visitor must re-enter the password 4. The cookie is `HttpOnly` and `SameSite=Lax` for security ## Requirements - Your site must be deployed to Tome Cloud (`tome deploy`) - You must be authenticated (`tome login`) - The project slug is read from your local `.tome/` config ## Notes - Password protection applies to the entire site. You cannot protect individual pages with this feature. For page-level access control, see [RBAC](/v3/guides/rbac). - The password is hashed with a secure one-way hash. There is no way to recover a forgotten password. Use `tome protect` to set a new one. - Search engines and AI agents cannot access password-protected sites. --- ## Plugin System Tome's plugin system lets you hook into the build lifecycle to modify configuration, transform routes, inject HTML tags, and run custom logic at build time. ## Defining a plugin A plugin is an object with a `name` and a `hooks` object. Add plugins to the `tomePlugins` array in your config: ```javascript // tome.config.js export default { name: "My Docs", tomePlugins: [ { name: "my-plugin", hooks: { buildStart() { console.log("Build starting..."); }, }, }, ], }; ``` ## Available hooks Plugins can define any combination of these hooks: | Hook | When it runs | Arguments | Return | |------|-------------|-----------|--------| | `configResolved` | After config is loaded and validated | `config` | Modified config or `void` | | `routesResolved` | After all pages are discovered | `routes[]` | Modified routes or `void` | | `headTags` | When generating the HTML shell | *(none)* | Array of HTML strings | | `buildStart` | Before the build begins | *(none)* | `void` or `Promise` | | `buildEnd` | After the build completes | `outputDir` | `void` or `Promise` | ### `configResolved` Runs after the config file is loaded and validated. Return a modified config object to change settings programmatically: ```javascript { name: "env-config", hooks: { configResolved(config) { return { ...config, baseUrl: process.env.DOCS_URL || config.baseUrl, }; }, }, } ``` ### `routesResolved` Runs after all pages are discovered from the filesystem. Return a modified routes array to add, remove, or transform pages: ```javascript { name: "sort-routes", hooks: { routesResolved(routes) { // Add a "weight" sort based on frontmatter return routes.sort((a, b) => { const wa = a.frontmatter.weight ?? 100; const wb = b.frontmatter.weight ?? 100; return wa - wb; }); }, }, } ``` Each route object includes `id`, `filePath`, `absolutePath`, `urlPath`, `frontmatter`, and `isMdx`. ### `headTags` Return an array of HTML strings to inject into the `` of every page: ```javascript { name: "analytics", hooks: { headTags() { return [ '', '', ]; }, }, } ``` ### `buildStart` / `buildEnd` Run custom logic before or after the build. Both hooks support async functions: ```javascript { name: "notify", hooks: { async buildStart() { console.log("Build started at", new Date().toISOString()); }, async buildEnd(outputDir) { console.log(`Build complete. Output: ${outputDir}`); // e.g., upload to S3, notify Slack, run a validator }, }, } ``` ## Full example: analytics plugin ```javascript // plugins/analytics.js export function analyticsPlugin(trackingId) { return { name: "analytics", hooks: { headTags() { return [ ``, ]; }, buildEnd(outputDir) { console.log(`Analytics tracking ID: ${trackingId}`); }, }, }; } ``` ```javascript // tome.config.js import { analyticsPlugin } from "./plugins/analytics.js"; export default { name: "My Docs", tomePlugins: [ analyticsPlugin("UA-123456"), ], }; ``` ## Full example: route filter plugin ```javascript // tome.config.js export default { name: "My Docs", tomePlugins: [ { name: "hide-internal", hooks: { routesResolved(routes) { // Remove pages with "internal" tag from the site return routes.filter( (r) => !r.frontmatter.tags?.includes("internal") ); }, }, }, ], }; ``` ## Plugin execution order When multiple plugins are registered, hooks run in array order. If a hook returns a value (like `configResolved` or `routesResolved`), that value is passed to the next plugin's hook. --- ## Role-Based Access Control RBAC lets you control which pages are visible to which users based on their assigned role. This is useful for sites where some content is restricted to editors, admins, or specific teams. ## Requirements - Your site must be deployed to Tome Cloud - [SSO](/v3/guides/sso) must be enabled (RBAC uses the authenticated email to look up roles) ## Role hierarchy Tome defines four roles in ascending order of privilege: | Role | Level | Description | |------|-------|-------------| | `viewer` | 1 | Can view pages gated at `viewer` level or below | | `editor` | 2 | Can view pages gated at `editor` level or below | | `admin` | 3 | Can view all pages, manage roles | | `owner` | 4 | Full access, project owner | A user with a higher-level role automatically has access to pages gated at lower levels. An `admin` can see `editor` and `viewer` pages. ## Page-level access Add an `access` field to a page's frontmatter to restrict who can view it: ```markdown --- title: Internal Architecture access: editor --- This page is only visible to users with the `editor` role or higher. ``` Pages without an `access` field are visible to any authenticated user (if SSO is enabled) or to everyone (if SSO is not enabled). ## Assigning roles Use the Tome Cloud API to assign roles to email addresses: ### Add or update a role ```bash curl -X POST https://api.tome.center/api/roles \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "projectSlug": "my-docs", "email": "alice@example.com", "role": "editor" }' ``` If the email already has a role, it is updated to the new value. ### List roles for a project ```bash curl https://api.tome.center/api/roles/my-docs \ -H "Authorization: Bearer " ``` Returns all role assignments with email, role, and creation date. ### Remove a role ```bash curl -X DELETE https://api.tome.center/api/roles \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "projectSlug": "my-docs", "email": "alice@example.com" }' ``` ## Who can manage roles Only project owners and users with the `admin` role can assign, list, or remove roles. The project owner (the account that created the project) always has full access regardless of role assignments. ## How access checks work When a visitor requests a page with an `access` field: 1. Tome reads the visitor's email from the SSO session cookie 2. It looks up the visitor's role in the project's role table 3. If the visitor's role meets or exceeds the page's `access` requirement, the page is served 4. Otherwise, access is denied If the visitor has no role entry at all, access is denied for any page that has an `access` field. --- ## Redirects Tome supports URL redirects at two levels: global config and per-page frontmatter. Redirects return a 301 (permanent) status in development and generate static redirect files for production builds. ## Config-level redirects Add a `redirects` array to `tome.config.js`: ```js import { defineConfig } from "@tomehq/core"; export default defineConfig({ name: "My Docs", redirects: [ { from: "/old-page", to: "/new-page" }, { from: "/docs/setup", to: "/docs/getting-started" }, { from: "/api", to: "/docs/reference/api" }, ], }); ``` Each entry needs a `from` path (the old URL) and a `to` path (the new URL). ## Frontmatter redirects Add `redirect_from` to a page's frontmatter to redirect old URLs to that page: ```md --- title: Getting Started redirect_from: - /docs/setup - /docs/installation - /quickstart --- Welcome to the getting started guide. ``` Any request to `/docs/setup`, `/docs/installation`, or `/quickstart` will redirect to this page. ## How redirects work ### Development The dev server intercepts requests and returns a `301 Moved Permanently` response for any matched redirect path. Both config-level and frontmatter redirects are active during development. ### Production builds During `tome build`, Tome emits two types of redirect outputs to ensure compatibility across hosting platforms: 1. **`_redirects` file** — A Netlify/Vercel-compatible redirects file in the build output root. Each line maps a source path to a destination with a 301 status code. 2. **Meta-refresh HTML files** — For each redirect source path, Tome generates a small HTML file with a `` tag. This ensures redirects work on any static hosting platform, including S3 and GitHub Pages. ## Migration redirects When migrating from GitBook or Mintlify, the migration tools automatically extract redirects from the source project configuration and add them to your `tome.config.js`. See the [Migration guide](guides/migration) for details. --- ## Search and Feedback Analytics When analytics is configured, Tome automatically tracks search queries and feedback events alongside page views. This helps you understand what readers are looking for and which pages need improvement. ## Setup Search and feedback analytics work automatically when you have analytics configured: ```js // tome.config.js export default { name: "My Docs", analytics: { provider: "posthog", // or "plausible", "custom" key: "your-key", }, }; ``` No additional configuration is needed. The analytics script (< 1KB, no cookies) exposes tracking functions on `window.__tome` that the search modal and feedback widget call automatically. ## What gets tracked ### Search events Every search query is recorded with: | Field | Description | |-------|-------------| | `query` | The search term entered by the reader | | `resultsCount` | Number of results returned | | `timestamp` | When the search occurred | | `sessionId` | Anonymous session identifier (no cookies) | ### Zero-result queries Searches that return zero results are flagged separately in aggregation. This is the most actionable metric. It tells you what readers expect to find but cannot. ### Feedback events Every feedback interaction is recorded with: | Field | Description | |-------|-------------| | `pageId` | The page that was rated | | `rating` | `up` or `down` | | `comment` | Optional text feedback (when `feedback.textInput` is enabled) | | `timestamp` | When the feedback was submitted | ## Client-side API The analytics script exposes two functions on `window.__tome`: ### `trackSearch(query, resultsCount)` Called automatically by the search modal after each search. You can also call it from custom search integrations: ```js window.__tome.trackSearch("authentication", 5); ``` ### `trackFeedback(pageId, rating, comment?)` Called automatically by the feedback widget. You can also call it programmatically: ```js window.__tome.trackFeedback("/quickstart", "up"); window.__tome.trackFeedback("/api-reference", "down", "Missing examples"); ``` ## Aggregated metrics The analytics backend aggregates events into these summary metrics: - **Top search queries** ranked by frequency - **Zero-result queries** ranked by frequency - **Total searches** count - **Total feedback** count - **Feedback by rating** (up vs. down) - **Top pages** by view count - **Unique visitors** by session - **Views by day** time series ## Privacy The analytics script uses no cookies. Session IDs are generated from a daily hash of the date and user agent, which provides approximate unique visitor counts without tracking individuals across days. All data is first-party and stays on your analytics provider. --- ## Search Tome includes search out of the box. No configuration is needed for the default experience — Pagefind indexes your site at build time and provides fast, client-side search with zero external dependencies. ## Built-in search (Pagefind) Pagefind is the default search provider. It runs automatically during `tome build`: 1. Tome builds your static site to `out/` 2. Pagefind indexes all HTML pages 3. The search index is placed in `out/_pagefind/` 4. The search UI loads the index on demand (< 1KB initial JS) No configuration required. Search is available on every page via the header search bar or the `Ctrl+K` / `Cmd+K` keyboard shortcut. ```javascript // Default — can be omitted entirely search: { provider: "local", } ``` ## Algolia DocSearch For larger documentation sites, you can use Algolia DocSearch as an alternative: ```javascript search: { provider: "algolia", appId: "YOUR_APP_ID", apiKey: "YOUR_SEARCH_API_KEY", indexName: "your-index-name", } ``` ### Initialize the Algolia index Tome includes a helper command to set up your Algolia index: ```bash npx @tomehq/cli algolia:init ``` This creates a crawler configuration optimized for Tome's HTML structure. ### When to use Algolia | Feature | Pagefind | Algolia | |---------|----------|---------| | Setup | Zero config | Requires account | | Cost | Free | Free tier available | | Index size | Unlimited | 10K records free | | Typo tolerance | Basic | Advanced | | Analytics | No | Yes | | Real-time indexing | At build time | Crawler-based | For most documentation sites, Pagefind is sufficient. Consider Algolia if you need search analytics, advanced typo tolerance, or real-time indexing. ## Structured search API (`search.json`) Every build also generates a `search.json` file — a structured JSON index of all pages. This is useful for AI agents and programmatic tools that need to search your docs without loading JavaScript. ```json { "siteName": "My Docs", "generatedAt": "2026-03-14T...", "searchEndpoint": "/_pagefind/pagefind.js", "pages": [ { "id": "quickstart", "title": "Quickstart", "description": "Get started in 30 seconds", "url": "/quickstart", "headings": ["Prerequisites", "Installation", "First page"], "wordCount": 342, "tags": [] } ] } ``` No configuration is needed — `search.json` is generated automatically alongside `llms.txt`, `skill.md`, and other agent-friendly files. --- ## Snippets Snippets let you define a block of markdown once and include it in multiple pages. This is useful for shared warnings, installation steps, or any content that appears in more than one place. ## Basic usage Use the `::snippet` directive to include a file: ```markdown ::snippet{file="shared-warning.md"} ``` Tome resolves snippet files from the configured snippets directory (default: `snippets/` at your project root). If you have a file at `snippets/shared-warning.md`, the directive above will inline its content at that position in the page. ## Variable substitution Snippets support `{{variable}}` placeholders that you can fill in per-usage: ```markdown Install version **{{version}}** with: \`\`\`bash npm install @acme/sdk@{{version}} \`\`\` ``` Then reference it with variables: ```markdown ::snippet{file="install-note.md" version="2.4.0"} ``` The `{{version}}` placeholders are replaced with `2.4.0` in the output. Any unmatched placeholders are left as-is. ## Configuration The default snippets directory is `snippets/`. You can change it in `tome.config.js`: ```js export default { name: "My Docs", snippetsDir: "content/shared", }; ``` All snippet file paths are resolved relative to this directory. ## Nested snippets Snippets can include other snippets. Tome resolves them recursively up to a maximum depth of 5 to prevent infinite loops. ```markdown ::snippet{file="prereqs.md"} Then run the installer: ... ``` ## Frontmatter stripping If a snippet file contains YAML frontmatter, it is automatically stripped before inclusion. This means you can keep metadata in your snippet files without it leaking into the output. ```markdown --- description: Internal note about this snippet --- This content will be included. The frontmatter above will not. ``` ## Variable inheritance When snippets are nested, variables from the parent are passed down to child snippets. Variables defined at the snippet call site override inherited values: ```markdown ::snippet{file="outer.md" version="3.0"} ::snippet{file="inner.md" platform="linux"} Supported on {{platform}} for version {{version}}. ``` --- ## Single Sign-On (SSO) SSO lets you restrict access to your hosted documentation site to members of your organization. Visitors authenticate through your identity provider (IdP) before they can view any page. ## Supported protocols | Protocol | Standard | Use case | |----------|----------|----------| | SAML 2.0 | XML-based | Enterprise IdPs (Okta, Azure AD, OneLogin) | | OIDC | OAuth 2.0 + JWT | Modern IdPs (Auth0, Google Workspace, Keycloak) | ## Requirements - Your site must be deployed to Tome Cloud - A Team plan is required for SSO - You need admin access to your identity provider to configure the integration ## Configuring SAML 2.0 ### 1. Get your SP metadata Tome exposes a Service Provider metadata endpoint for your site: ``` https://api.tome.center/api/sso/sites//metadata ``` Provide this URL to your IdP when creating a new SAML application. The metadata includes: - **Entity ID**: Your site's unique identifier - **ACS URL**: The Assertion Consumer Service endpoint where SAML responses are sent - **NameID format**: Email address ### 2. Configure your IdP In your IdP, create a new SAML application and set: - **ACS URL**: `https://api.tome.center/api/sso/sites//saml/acs` - **Entity ID**: `https://api.tome.center/api/sso/sites//metadata` - **NameID format**: Email - **Attributes**: Map `email` (required), `name` (optional), `groups` (optional) ### 3. Save the SSO config Use the Tome Cloud API to save your SAML configuration: ```bash curl -X POST https://api.tome.center/api/sso/config \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "projectSlug": "my-docs", "ssoType": "saml", "samlIdpSsoUrl": "https://idp.example.com/sso/saml", "samlIdpCertificate": "-----BEGIN CERTIFICATE-----\n...", "allowedDomains": ["example.com"] }' ``` ## Configuring OIDC ### 1. Register a client In your IdP, create a new OIDC application with: - **Redirect URI**: `https://api.tome.center/api/sso/sites//oidc/callback` - **Scopes**: `openid email profile` - **Grant type**: Authorization Code with PKCE ### 2. Save the SSO config ```bash curl -X POST https://api.tome.center/api/sso/config \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "projectSlug": "my-docs", "ssoType": "oidc", "oidcIssuer": "https://idp.example.com", "oidcClientId": "your-client-id", "oidcClientSecret": "your-client-secret", "allowedDomains": ["example.com"] }' ``` Tome uses OIDC Discovery (`/.well-known/openid-configuration`) to auto-detect your IdP's authorization, token, userinfo, and JWKS endpoints. ## Allowed email domains The `allowedDomains` field restricts which email addresses can authenticate. If a user's email domain is not in the list, access is denied after authentication. ```json "allowedDomains": ["example.com", "contractor.example.com"] ``` Omit `allowedDomains` or pass an empty array to allow any email that successfully authenticates with your IdP. ## Session management After successful authentication, Tome sets an `HttpOnly` session cookie (`tome_sso_session`) that is valid for **8 hours**. The session is a signed JWT (HMAC-SHA256) containing the user's email and group memberships. When the session expires, the visitor is redirected to your IdP to re-authenticate. ## Managing SSO config | Action | Method | Endpoint | |--------|--------|----------| | Create | `POST` | `/api/sso/config` | | Read | `GET` | `/api/sso/config/:slug` | | Delete | `DELETE` | `/api/sso/config/:slug` | All management endpoints require a Bearer token from `tome login`. ## Combining with RBAC SSO authenticates the visitor. For page-level access control based on roles, see [RBAC](/v3/guides/rbac). RBAC uses the email and groups from the SSO session to determine which pages a visitor can access. --- ## Third-Party Analytics # Third-Party Analytics Tome includes built-in privacy-first analytics, but you can add any third-party analytics provider using the plugin `headTags` hook. This injects script tags into the `` of every page. ## Setup Add a plugin to your `tome.config.js` that returns the analytics script tags: ```js import { defineConfig } from "@tomehq/core/config"; export default defineConfig({ name: "My Docs", tomePlugins: [ { name: "analytics", hooks: { headTags: () => [ // Add your analytics scripts here ], }, }, ], }); ``` ## Google Analytics 4 ```js headTags: () => [ ``, ``, ], ``` ## Google Tag Manager ```js headTags: () => [ ``, ], ``` ## Plausible (Hosted) ```js headTags: () => [ ``, ], ``` ## Fathom ```js headTags: () => [ ``, ], ``` ## Amplitude ```js headTags: () => [ ``, ``, ], ``` ## Mixpanel ```js headTags: () => [ ``, ], ``` ## Segment ```js headTags: () => [ ``, ], ``` ## Hotjar ```js headTags: () => [ ``, ], ``` ## Microsoft Clarity ```js headTags: () => [ ``, ], ``` ## Heap ```js headTags: () => [ ``, ], ``` ## Multiple Providers You can combine multiple providers in a single plugin: ```js headTags: () => [ // Google Analytics ``, ``, // Plausible ``, ], ``` These scripts work alongside Tome's built-in analytics. The built-in analytics remain privacy-first (no cookies, <1KB) while third-party providers operate independently. --- ## TypeDoc Generation Tome includes a built-in TypeDoc integration that generates Markdown API reference pages from your TypeScript source code. It extracts exported functions, interfaces, types, classes, enums, and constants — along with their JSDoc comments — and outputs standard `.md` files that integrate directly with your docs. ## Quick start ```bash npx @tomehq/cli typedoc --entry src/index.ts ``` This generates Markdown files in `pages/api/` by default, one per exported declaration, plus an `index.md` with a summary table. ## CLI flags | Flag | Default | Description | |------|---------|-------------| | `--entry` | *(required)* | TypeScript entry point file(s) to document | | `--out` | `pages/api` | Output directory for generated `.md` files | | `--tsconfig` | `tsconfig.json` | Path to your `tsconfig.json` | You can pass multiple entry points: ```bash npx @tomehq/cli typedoc --entry src/client.ts --entry src/server.ts --out pages/api ``` ## What gets extracted The generator processes all `export`ed declarations in your entry point files: | Kind | What's documented | |------|-------------------| | Functions | Name, parameters (name, type, optional), return type, JSDoc description | | Interfaces | Name, properties (name, type, optional), JSDoc on each member | | Type aliases | Name, full type signature, object members if applicable | | Classes | Name, properties, methods, JSDoc | | Enums | Name, values, JSDoc on each member | | Constants / variables | Name, type or initializer, JSDoc | Non-exported declarations are skipped. ## Writing good JSDoc The generator reads standard JSDoc comments. Use `@param` for parameter descriptions and `@returns` for return values: ```typescript /** * Create a new project with the given configuration. * @param name The project name (must be unique) * @param options Additional project settings * @returns The created project object */ export function createProject( name: string, options?: ProjectOptions ): Project { // ... } ``` This produces a Markdown page with: - A heading showing the full function signature - The description paragraph - A parameters table with name, type, required/optional, and description columns - A return type section ## Generated output For each exported declaration, the generator creates a file named `.md`. For example, exporting `createProject` and `ProjectOptions` produces: ```text pages/api/ ├── index.md # Summary table linking to each page ├── createproject.md # Function documentation └── projectoptions.md # Interface documentation ``` The index page groups declarations by kind (Functions, Interfaces, Types, etc.) with links to each detail page. ## Adding to navigation The generated pages are standard Markdown files. Add them to your navigation like any other pages: ```javascript // tome.config.js export default { name: "My Docs", navigation: [ { group: "Guides", pages: ["quickstart", "configuration"] }, { group: "API Reference", pages: ["api/index", "api/createproject", "api/projectoptions"], }, ], }; ``` ## Regenerating docs Run the `typedoc` command whenever your TypeScript API changes. The output files are regular `.md` files checked into your repo — they don't regenerate automatically during `tome build`. A typical workflow: ```bash # Regenerate API docs, then rebuild the site npx @tomehq/cli typedoc --entry src/index.ts npx @tomehq/cli build ``` You can add this to a CI step or a `package.json` script: ```json { "scripts": { "docs:api": "tome typedoc --entry src/index.ts", "docs:build": "npm run docs:api && tome build" } } ``` --- ## Multi-Version Docs Tome supports maintaining multiple versions of your documentation side by side. This is useful for libraries and APIs that need to document breaking changes across major versions. ## Directory structure Organize your pages by version using subdirectories: ```text pages/ ├── current/ # Latest version │ ├── index.md │ ├── quickstart.md │ └── api.md ├── v1.0/ # Previous version │ ├── index.md │ ├── quickstart.md │ └── api.md └── v0.9/ # Older version ├── index.md └── api.md ``` ## Configuration Add the `versioning` section to your config: ```javascript export default { name: "My Docs", versioning: { current: "v2.0", versions: ["v2.0", "v1.0", "v0.9"], }, }; ``` | Field | Type | Description | |-------|------|-------------| | `current` | string | The label for the current (latest) version | | `versions` | string[] | All available versions, newest first | ## URL mapping | Directory | URL | |-----------|-----| | `pages/current/index.md` | `/` | | `pages/current/api.md` | `/api` | | `pages/v1.0/index.md` | `/v1.0/` | | `pages/v1.0/api.md` | `/v1.0/api` | The `current` directory always serves at the root — no version prefix. Older versions are prefixed with their version string. ## Version switcher When versioning is configured, Tome automatically adds a version dropdown to the header. Users can switch between versions, and the URL updates to reflect the selected version. If the current page exists in the target version, the user stays on that page. Otherwise, they're redirected to the version's index page. ## Best practices - Keep the `current` directory as your working copy - Copy `current` to a versioned directory (e.g., `v2.0`) when you cut a release - Remove pages from old versions that no longer apply rather than leaving stale content - Use the same page IDs across versions so the version switcher can navigate between them --- ## White Labeling By default, Tome includes subtle branding in generated metadata and machine-readable files. You can disable this to present your docs under your own brand. ## Configuration Set `branding.powered` to `false` in your config: ```js // tome.config.js export default { name: "My Docs", branding: { powered: false, }, }; ``` ## What changes When branding is disabled, the following are affected: | Item | With branding (default) | Without branding | |------|------------------------|------------------| | `llms.txt` description | "Documentation site powered by Tome" | "My Docs documentation" | | JSON-LD `WebSite` schema | References Tome | References your site name only | | OG metadata description | Mentions Tome | Uses your site name only | The visual appearance of your site (header, sidebar, footer) is not affected by this setting. Branding control applies to metadata and machine-readable outputs only. ## When to use This is intended for organizations that need full brand control over their public documentation. It is available on all plans. --- ## Pages & Routing Every `.md` or `.mdx` file in the `pages/` directory becomes a page. The file path determines the URL. ## Basic routing | File path | URL | |-----------|-----| | `pages/index.md` | `/` | | `pages/quickstart.md` | `/quickstart` | | `pages/guides/deployment.md` | `/guides/deployment` | | `pages/api/endpoints.md` | `/api/endpoints` | | `pages/api/index.md` | `/api` | **Rules:** - `index.md` serves at the directory's root path - File extensions are stripped from the URL - Directory nesting maps directly to URL segments - Both `.md` and `.mdx` files are supported ## Page IDs Each page has an ID derived from its path relative to `pages/`: | File | Page ID | |------|---------| | `pages/index.md` | `index` | | `pages/quickstart.md` | `quickstart` | | `pages/guides/deployment.md` | `guides/deployment` | Page IDs are used in `navigation` config to control sidebar order. ## Navigation vs. routing All pages in `pages/` are routable regardless of whether they appear in `navigation`. Navigation only controls the sidebar. Pages can be hidden from the sidebar using `hidden: true` in frontmatter while remaining accessible at their URL. ## Frontmatter Every page can include YAML frontmatter at the top of the file: ```markdown --- title: My Page description: A brief description for SEO and navigation. icon: book sidebarTitle: Short Title hidden: false tags: [guide, setup] --- # My Page Content starts here. ``` | Field | Type | Description | |-------|------|-------------| | `title` | string | Page title (falls back to first `#` heading) | | `description` | string | Description for metadata and navigation | | `icon` | string | Icon identifier shown in the sidebar | | `sidebarTitle` | string | Override title shown in the sidebar | | `hidden` | boolean | Hide page from sidebar (still accessible via URL) | | `tags` | string[] | Tags for categorization and search | ## i18n routing When multiple locales are configured, organize pages by locale subdirectory: ```text pages/ ├── en/ # Default locale │ ├── index.md │ └── quickstart.md ├── es/ # Spanish │ ├── index.md │ └── quickstart.md ``` | File | URL | |------|-----| | `pages/en/index.md` | `/` (default — no prefix) | | `pages/es/index.md` | `/es/` | | `pages/es/quickstart.md` | `/es/quickstart` | The default locale serves at the root without a prefix. When `fallback: true` and a page doesn't exist in a non-default locale, the default version is used. ## Versioned routing When versioning is configured: ```text pages/ ├── current/ # Latest version │ ├── index.md │ └── api.md ├── v1.0/ │ ├── index.md │ └── api.md ``` | File | URL | |------|-----| | `pages/current/index.md` | `/` | | `pages/v1.0/index.md` | `/v1.0/` | | `pages/v1.0/api.md` | `/v1.0/api` | The `current` directory serves at the root. Older versions are prefixed with their version string. ## File discovery Tome discovers pages by scanning `pages/` for `**/*.{md,mdx}` files. Discovery runs at startup and again whenever files are added, removed, or renamed during development. Changes to existing files trigger a hot reload. --- ## Quickstart Get a working documentation site in three commands. ## Create a new project ```bash npx @tomehq/cli init my-docs ``` This scaffolds a complete documentation project with starter pages, configuration, and build scripts. ## Install and run ```bash cd my-docs npm install npm run dev ``` Open `http://localhost:3000`. You should see your documentation site with a sidebar, search, and starter content. ## Edit your first page Open `pages/index.md` in your editor. Change the title and save — the browser reloads automatically. ```markdown --- title: My Project description: Documentation for my project. --- # My Project Welcome to the docs. ``` Every `.md` or `.mdx` file in `pages/` becomes a page on your site. Subdirectories create nested routes: | File | URL | |------|-----| | `pages/index.md` | `/` | | `pages/tutorials/getting-started.md` | `/tutorials/getting-started` | | `pages/guides/configuration.md` | `/guides/configuration` | | `pages/reference/cli.md` | `/reference/cli` | ## Add navigation Open `tome.config.js` to customize your sidebar. The scaffold uses the [Diataxis framework](https://diataxis.fr/) by default: ```javascript export default { name: "My Project", navigation: [ { group: "Overview", pages: ["index"] }, { group: "Tutorials", pages: ["tutorials/getting-started", "tutorials/deploy"] }, { group: "Guides", pages: ["guides/components", "guides/configuration"] }, { group: "Reference", pages: ["reference/config", "reference/components", "reference/cli"] }, { group: "Concepts", pages: ["concepts/how-tome-works", "concepts/file-routing"] }, ], }; ``` ## Build for production ```bash npm run build ``` This outputs a static site to `out/` ready to deploy to any hosting provider — Vercel, Netlify, Cloudflare Pages, or Tome Cloud. ## Next steps - **[Installation](installation)** for detailed setup and prerequisites - **[Configuration](configuration)** to customize your site - **[Components](components)** to use tabs, callouts, and other interactive elements --- ## CLI Reference The `tome` CLI is the primary interface for creating, developing, building, and deploying documentation sites. ## Installation ```bash npm install -D @tomehq/cli # or globally npm install -g @tomehq/cli ``` ## Commands ### `tome init [name]` Create a new Tome documentation project. ```bash tome init my-docs ``` | Argument | Default | Description | |----------|---------|-------------| | `name` | `my-docs` | Project directory name | | Flag | Default | Description | |------|---------|-------------| | `-t, --template ` | `default` | Starter template | Creates `tome.config.js`, `package.json`, `index.html`, `.tome/entry.tsx`, starter pages in `pages/`, `public/` and `styles/` directories, and a `.github/workflows/deploy.yml` GitHub Actions workflow for automatic deploys. --- ### `tome dev` Start the development server with hot reloading. ```bash tome dev tome dev -p 4000 tome dev --host ``` | Flag | Default | Description | |------|---------|-------------| | `-p, --port ` | `3000` | Server port | | `--host` | `false` | Expose to network (bind `0.0.0.0`) | Watches `pages/` for file changes and reloads automatically. Config changes trigger a full reload. --- ### `tome build` Build the documentation site for production. ```bash tome build tome build -o dist ``` | Flag | Default | Description | |------|---------|-------------| | `-o, --outDir ` | `out` | Output directory | Produces a static site and runs Pagefind to build the search index. --- ### `tome deploy` Deploy the site to Tome Cloud. Requires `tome login` first. ```bash tome deploy tome deploy --preview --branch feature/auth ``` | Flag | Default | Description | |------|---------|-------------| | `--preview` | `false` | Deploy as a preview (branch-based URL) | | `--branch ` | auto-detect | Git branch name for preview | | `--expires ` | `7` | Preview expiry in days | Builds, collects output files, and uploads using hash-based deduplication. With `--preview`, deploys to a branch-specific URL (e.g., `feature-auth.preview.my-docs.tome.center`) and injects a preview banner. --- ### `tome lint` Lint documentation content for common issues. ```bash tome lint tome lint --strict tome lint --banned-words "simply,obviously" ``` | Flag | Default | Description | |------|---------|-------------| | `--max-paragraph ` | `300` | Max words per paragraph | | `--no-heading-increment` | — | Disable heading increment check | | `--no-image-alt` | — | Disable missing alt text check | | `--no-single-h1` | — | Disable single H1 check | | `--no-empty-links` | — | Disable empty link check | | `--banned-words ` | — | Comma-separated list of banned words | | `--strict` | `false` | Treat warnings as errors | Checks all pages for heading hierarchy issues, missing image alt text, overly long paragraphs, duplicate H1 tags, empty links, and banned words. --- ### `tome login` Authenticate with Tome Cloud. ```bash tome login ``` Prompts for email and sends a magic link. Stores the API token locally. --- ### `tome domains:add ` Add a custom domain. Returns DNS records to configure. ```bash tome domains:add docs.example.com ``` ### `tome domains:verify ` Verify DNS configuration for a custom domain. ```bash tome domains:verify docs.example.com ``` ### `tome domains:list` List all custom domains for the current project. ### `tome domains:remove ` Remove a custom domain. --- ### `tome migrate gitbook ` Migrate a GitBook documentation project to Tome. ```bash tome migrate gitbook ./my-gitbook-docs tome migrate gitbook ./my-gitbook-docs --out ./converted tome migrate gitbook ./my-gitbook-docs --dry-run ``` | Flag | Default | Description | |------|---------|-------------| | `--out ` | `.` (current directory) | Output directory for converted project | | `--dry-run` | `false` | Preview changes without writing files | Reads `SUMMARY.md` for navigation structure and `.gitbook.yaml` for configuration. Converts GitBook-specific syntax to Tome components: - `{% hint %}` blocks → `` components - `{% tabs %}` blocks → `` / `` components - `{% code title="..." %}` → fenced code blocks with titles - `{% embed %}` → plain links - Redirects from `.gitbook.yaml` → Tome `redirects` config Files are copied to `pages/` preserving directory structure. Files containing converted JSX components are renamed from `.md` to `.mdx`. Static assets are copied to `public/`. --- ### `tome migrate mintlify ` Migrate a Mintlify documentation project to Tome. ```bash tome migrate mintlify ./my-mintlify-docs tome migrate mintlify ./my-mintlify-docs --out ./converted tome migrate mintlify ./my-mintlify-docs --dry-run ``` | Flag | Default | Description | |------|---------|-------------| | `--out ` | `.` (current directory) | Output directory for converted project | | `--dry-run` | `false` | Preview changes without writing files | Reads `mint.json` for configuration and navigation. Converts Mintlify-specific syntax to Tome components: - ``, ``, ``, ``, `` → `` components - `` → `` wrapper - `` → stripped (individual `` components kept) - `` → stripped (content preserved) - `` → inlined file content Maps `mint.json` settings to `tome.config.js`: colors, logo, favicon, navigation, redirects, topbar links, and OpenAPI configuration. --- ### `tome algolia:init` Initialize an Algolia DocSearch index. Prompts for credentials and creates a crawler configuration. --- ### `tome typedoc ` Generate API reference documentation from TypeScript source files. ```bash tome typedoc src/index.ts tome typedoc src/index.ts src/utils.ts ``` Parses exported functions, interfaces, and type aliases using the TypeScript compiler API. Generates a Markdown page per export with signatures, parameters, return types, and JSDoc descriptions. --- ### `tome mcp` Start the MCP (Model Context Protocol) stdio server for AI tool integration. Exposes documentation content as MCP resources and tools. --- ## Components Tome includes built-in components available in any `.mdx` file without imports. ## Callout Draw attention to important information. ```mdx This is an informational callout. ``` | Prop | Type | Default | Description | |------|------|---------|-------------| | `type` | `"info" \| "tip" \| "warning" \| "danger"` | `"info"` | Visual style and icon | | `title` | `string` | — | Optional heading text | Types: `info` (blue), `tip` (green), `warning` (amber), `danger` (red). --- ## Tabs Present content variants — useful for multiple languages or platform-specific instructions. ```mdx
npm install @tomehq/cli
yarn add @tomehq/cli
pnpm add @tomehq/cli
``` | Prop | Type | Description | |------|------|-------------| | `items` | `string[]` | Tab labels (required) | Each child `
` maps to a tab in order. --- ## Card A linked or static content card. ```mdx Set up your first project in minutes. ``` | Prop | Type | Description | |------|------|-------------| | `title` | `string` | Card heading (required) | | `icon` | `string` | Emoji or icon name | | `href` | `string` | Link URL (makes the card clickable) | --- ## CardGroup Arranges cards in a responsive grid. ```mdx Step 1 Step 2 Step 3 ``` | Prop | Type | Default | Description | |------|------|---------|-------------| | `cols` | `number` | `2` | Number of columns | --- ## Steps Sequential instructions with numbered indicators. ```mdx
**Create a project** Run `tome init my-docs`.
**Install dependencies** Run `npm install`.
``` Each child `
` becomes a numbered step. Use bold text on the first line for the step title. --- ## Accordion Collapsible content sections for FAQs or optional details. ```mdx Run `tome build` then upload the `out/` directory. ``` | Prop | Type | Description | |------|------|-------------| | `title` | `string` | Clickable header text (required) | --- ## API components When an OpenAPI spec is configured, additional components are auto-generated: - **ApiEndpoint** — Renders an API endpoint with parameters and responses - **ApiPlayground** — Interactive request builder - **ApiResponse** — Formatted response viewer See the [API reference guide](guides/api-reference) for setup. --- ## `.md` vs `.mdx` Components are only available in `.mdx` files. Rename `.md` to `.mdx` to use them — no other changes needed. --- ## Config Reference The config file (`tome.config.js`, `.mjs`, or `.ts`) is validated at startup. Invalid values produce clear error messages with the field path and expected type. ## Top-level fields | Field | Type | Default | Description | |-------|------|---------|-------------| | `name` | `string` | `"My Docs"` | Site name shown in the header and browser tab | | `logo` | `string` | — | Path to logo image, relative to `public/` | | `favicon` | `string` | — | Path to favicon, relative to `public/` | | `baseUrl` | `string` | — | Full URL where the site is hosted (for analytics, canonical links) | | `basePath` | `string` | — | URL subpath prefix (e.g., `"/docs/"`) — sets Vite's `base` option | | `theme` | `ThemeConfig` | `{}` | Theme configuration (see below) | | `navigation` | `NavigationGroup[]` | `[]` | Sidebar navigation structure | | `topNav` | `TopNavItem[]` | — | Header navigation links | | `search` | `SearchConfig` | `{ provider: "local" }` | Search provider configuration | | `api` | `ApiConfig` | — | OpenAPI spec and playground settings | | `ai` | `AiConfig` | — | AI chat widget configuration | | `mcp` | `McpConfig` | `{ enabled: true }` | MCP server manifest generation | | `i18n` | `I18nConfig` | — | Internationalization settings | | `versioning` | `VersioningConfig` | — | Multi-version documentation | | `analytics` | `AnalyticsConfig` | — | Analytics provider settings | | `banner` | `BannerConfig` | — | Announcement banner at the top of every page | | `math` | `boolean` | `false` | Enable `$` inline and `$$` display math in `.md` files | | `webhooks` | `WebhookConfig[]` | — | Webhook notifications for deploy events | | `socialLinks` | `SocialLink[]` | — | Social media icons in the header | | `overrides` | `OverridesConfig` | — | Custom React components to replace default UI sections | | `tomePlugins` | `TomePlugin[]` | — | Plugins that hook into the build lifecycle | | `contentSources` | `ContentSource[]` | — | Remote content sources (GitHub, Notion) | ## ThemeConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `preset` | `"amber" \| "editorial" \| "cipher" \| "mint"` | `"amber"` | Base theme preset | | `accent` | `string` | — | Custom accent color (hex, e.g., `"#ff6b4a"`) | | `mode` | `"light" \| "dark" \| "auto"` | `"auto"` | Color mode | | `fonts.heading` | `string` | — | Heading font family | | `fonts.body` | `string` | — | Body font family | | `fonts.code` | `string` | — | Code font family | | `radius` | `string` | — | Border radius (e.g., `"8px"`) | ## NavigationGroup ```typescript { group: string; pages: Array; } ``` Page IDs are filenames without extensions, relative to `pages/`. Nested groups are supported. ## SearchConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `provider` | `"local" \| "algolia"` | `"local"` | Search provider | | `appId` | `string` | — | Algolia application ID | | `apiKey` | `string` | — | Algolia search-only API key | | `indexName` | `string` | — | Algolia index name | ## ApiConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `spec` | `string` | — | Path to OpenAPI spec file (required) | | `playground` | `boolean` | `true` | Enable interactive API playground | | `baseUrl` | `string` | — | Base URL for playground requests | | `auth.type` | `"bearer" \| "apiKey" \| "oauth2"` | — | Authentication type | | `auth.header` | `string` | — | Auth header name | ## AiConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `enabled` | `boolean` | `false` | Enable AI chat widget | | `provider` | `"openai" \| "anthropic" \| "custom"` | `"anthropic"` | AI provider | | `model` | `string` | — | Model identifier | | `apiKeyEnv` | `string` | `"TOME_AI_KEY"` | Environment variable for API key | ## McpConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `enabled` | `boolean` | `true` | Generate `mcp.json` manifest at build time | | `server` | `boolean` | `false` | Enable MCP stdio server | | `includeContent` | `boolean` | `true` | Include page content in the manifest | | `excludePages` | `string[]` | `[]` | Page IDs to exclude | ## I18nConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `defaultLocale` | `string` | `"en"` | Default locale code | | `locales` | `string[]` | `["en"]` | All available locale codes | | `localeNames` | `Record` | — | Display names (e.g., `{ en: "English" }`) | | `fallback` | `boolean` | `true` | Fall back to default locale for missing translations | | `localeDirs` | `Record` | — | Text direction per locale (e.g., `{ ar: "rtl", he: "rtl" }`) | ## VersioningConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `current` | `string` | — | Label for the current version (required) | | `versions` | `string[]` | — | All version labels, newest first (required) | ## AnalyticsConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `provider` | `"plausible" \| "posthog" \| "custom"` | — | Analytics provider | | `key` | `string` | — | Site ID or API key | ## BannerConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `text` | `string` | — | Banner message text (required) | | `link` | `string` | — | URL to navigate to when clicked | | `dismissible` | `boolean` | `true` | Show a close button | When a user dismisses the banner, it stays hidden until the `text` value changes. Updating the text resets dismissal for all users. ## WebhookConfig Send notifications to Slack, Discord, or generic HTTP endpoints when deploy events occur. ```js webhooks: [ { url: "https://hooks.slack.com/services/T.../B.../...", channel: "slack", events: ["deploy.succeeded", "deploy.failed"], }, { url: "https://discord.com/api/webhooks/...", channel: "discord", }, { url: "https://example.com/webhook", channel: "http", secret: "my-hmac-secret", }, ] ``` | Field | Type | Default | Description | |-------|------|---------|-------------| | `url` | `string` | — | Webhook endpoint URL (required) | | `channel` | `"slack" \| "discord" \| "http"` | — | Notification format (required) | | `events` | `WebhookEventType[]` | all | Filter which events trigger the webhook | | `secret` | `string` | — | HMAC-SHA256 secret for HTTP signature (`X-Tome-Signature` header) | **Event types:** `deploy.succeeded`, `deploy.failed`, `preview.deployed`, `domain.verified` ## SocialLinksConfig Add social media icons to the site header. Each entry specifies a platform and URL. ```js socialLinks: [ { platform: "github", url: "https://github.com/my-org/my-repo" }, { platform: "discord", url: "https://discord.gg/my-server" }, { platform: "twitter", url: "https://x.com/my-handle" }, { platform: "custom", url: "https://mastodon.social/@me", icon: "mastodon" }, ] ``` | Field | Type | Default | Description | |-------|------|---------|-------------| | `platform` | `"github" \| "twitter" \| "discord" \| "slack" \| "linkedin" \| "youtube" \| "custom"` | — | Social platform (required) | | `url` | `string` | — | Link URL (required) | | `icon` | `string` | — | Custom icon identifier (only used when `platform` is `"custom"`) | ## OverridesConfig Replace default UI sections with your own React components. Each field accepts a file path (relative to the project root) that exports a default React component. ```js overrides: { Header: "./components/MyHeader.tsx", Footer: "./components/MyFooter.tsx", } ``` | Field | Type | Default | Description | |-------|------|---------|-------------| | `Header` | `string` | — | Path to a React component that replaces the default site header | | `Footer` | `string` | — | Path to a React component that replaces the default site footer | | `Sidebar` | `string` | — | Path to a React component that replaces the default sidebar | | `Toc` | `string` | — | Path to a React component that replaces the default table of contents | | `PageFooter` | `string` | — | Path to a React component that replaces the default page footer | --- ## Frontmatter Every Tome page can include YAML frontmatter at the top of the file. Frontmatter controls metadata like the page title, description, sidebar behavior, and search tags. ## Syntax ```markdown --- title: My Page Title description: A brief summary of the page content. --- # My Page Title Page content starts here. ``` ## Fields | Field | Type | Default | Description | |-------|------|---------|-------------| | `title` | `string` | First `#` heading | Page title for sidebar, browser tab, and search | | `description` | `string` | — | Short summary for SEO and search results | | `icon` | `string` | — | Icon identifier shown in the sidebar | | `sidebarTitle` | `string` | `title` | Override the title shown in sidebar navigation | | `hidden` | `boolean` | `false` | Hide this page from sidebar navigation | | `tags` | `string[]` | — | Tags for search indexing and categorization | | `ogImage` | `string` | auto-generated | Custom OpenGraph image URL or path | | `draft` | `boolean` | `false` | Mark as draft — visible in dev, excluded from production builds | | `badge` | `string \| { text: string; variant?: "default" \| "outline" \| "info" \| "warning" \| "success" \| "danger" }` | — | Badge shown next to the page title in sidebar navigation | ## Title resolution If `title` is not set in frontmatter, Tome uses the first `# Heading` in the page content. If neither exists, the page is titled "Untitled". The `sidebarTitle` field lets you show a shorter name in the sidebar: ```markdown --- title: Configuring Authentication with OAuth 2.0 sidebarTitle: Authentication --- ``` ## Hidden pages Pages with `hidden: true` are excluded from sidebar navigation but remain accessible at their URL. Useful for: - Landing pages that shouldn't appear in the sidebar - Internal reference pages linked from other content - Pages shared only via direct link Note that hidden pages still exist in production and can be reached by anyone with the URL. To fully exclude a page from production, use `draft: true` instead. ## Draft pages Pages with `draft: true` are completely removed from production builds. Unlike `hidden`, drafts don't exist at all in production — not even via direct URL. In dev mode, draft pages are still visible so you can preview them, and they display a "DRAFT" banner at the top of the page to remind you they won't be published. ```markdown --- title: Upcoming Feature draft: true --- This page is only visible during local development. ``` ## Badges The `badge` field adds a colored pill next to the page title in sidebar navigation. This is useful for marking pages as new, beta, deprecated, and so on. A simple string value creates a badge with the default style: ```markdown --- title: Streaming API badge: "New" --- ``` For more control, pass an object with `text` and an optional `variant`: ```markdown --- title: Legacy Auth badge: text: "Beta" variant: "warning" --- ``` Available variants: `default`, `outline`, `info`, `warning`, `success`, `danger`. Each variant applies a different background and text color that matches the current theme. ## Tags Tags improve search results by adding keywords that may not appear in the page content: ```markdown --- title: Deployment tags: [hosting, vercel, netlify, cloudflare, static] --- ``` Tags are indexed by both Pagefind and Algolia (when configured) and appear in MCP manifest output. ## Icons The `icon` field accepts identifiers displayed in the sidebar. Common values: `rocket`, `gear`, `code`, `terminal`, `puzzle`, `search`, `layers`, `cloud`, `file-text`, `palette`. ## OpenGraph images By default, Tome auto-generates OG images for every page at build time. Use `ogImage` to override with a custom image: ```markdown --- title: Getting Started ogImage: /images/custom-og.png --- ``` The value can be a relative path (resolved from your site root) or a full URL. Pages with a custom `ogImage` skip auto-generation. --- ## Theme Presets Tome ships with four theme presets. Each defines color tokens for dark and light modes plus font families. All presets are WCAG 2.1 AA compliant. ## Amber The default preset. Warm, approachable tones with a golden accent. ### Dark mode | Variable | Value | Description | |----------|-------|-------------| | `--bg` | `#09090b` | Page background | | `--sf` | `#111114` | Surface | | `--sfH` | `#18181c` | Surface hover | | `--bd` | `#1e1e24` | Border | | `--tx` | `#e4e4e7` | Primary text | | `--tx2` | `#a1a1aa` | Secondary text | | `--txM` | `#919199` | Muted text | | `--ac` | `#e8a845` | Accent | | `--acD` | `rgba(232,168,69,0.12)` | Accent dim | | `--acT` | `#fbbf24` | Accent hover | | `--cdBg` | `#0c0c0f` | Code background | | `--cdTx` | `#c4c4cc` | Code text | | `--sbBg` | `#0c0c0e` | Sidebar background | | `--hdBg` | `rgba(9,9,11,0.85)` | Header background | ### Light mode | Variable | Value | Description | |----------|-------|-------------| | `--bg` | `#fafaf9` | Page background | | `--sf` | `#ffffff` | Surface | | `--sfH` | `#f5f5f4` | Surface hover | | `--bd` | `#e7e5e4` | Border | | `--tx` | `#1c1917` | Primary text | | `--tx2` | `#57534e` | Secondary text | | `--txM` | `#706b66` | Muted text | | `--ac` | `#96640a` | Accent | | `--acD` | `rgba(150,100,10,0.08)` | Accent dim | | `--acT` | `#7a5208` | Accent hover | | `--cdBg` | `#f5f3f0` | Code background | | `--cdTx` | `#2c2520` | Code text | | `--sbBg` | `#f5f5f3` | Sidebar background | | `--hdBg` | `rgba(250,250,249,0.85)` | Header background | ### Fonts | Variable | Value | |----------|-------| | `--font-heading` | `'Instrument Serif', serif` | | `--font-body` | `'DM Sans', sans-serif` | | `--font-code` | `'JetBrains Mono', monospace` | --- ## Editorial A refined preset inspired by Swiss poster design. Deep navy dark mode with a coral accent. ### Dark mode | Variable | Value | Description | |----------|-------|-------------| | `--bg` | `#080c1f` | Page background | | `--sf` | `#0e1333` | Surface | | `--sfH` | `#141940` | Surface hover | | `--bd` | `#1a2050` | Border | | `--tx` | `#e8e6f0` | Primary text | | `--tx2` | `#b5b1c8` | Secondary text | | `--txM` | `#9490ae` | Muted text | | `--ac` | `#ff6b4a` | Accent (coral) | | `--acD` | `rgba(255,107,74,0.1)` | Accent dim | | `--acT` | `#ff8a70` | Accent hover | | `--cdBg` | `#0a0e27` | Code background | | `--cdTx` | `#b8b4cc` | Code text | | `--sbBg` | `#0a0e27` | Sidebar background | | `--hdBg` | `rgba(8,12,31,0.9)` | Header background | ### Light mode | Variable | Value | Description | |----------|-------|-------------| | `--bg` | `#f6f4f0` | Page background | | `--sf` | `#ffffff` | Surface | | `--sfH` | `#eeece6` | Surface hover | | `--bd` | `#ddd9d0` | Border | | `--tx` | `#1a1716` | Primary text | | `--tx2` | `#4a443e` | Secondary text | | `--txM` | `#706960` | Muted text | | `--ac` | `#b83d22` | Accent (rust) | | `--acD` | `rgba(184,61,34,0.07)` | Accent dim | | `--acT` | `#9c3019` | Accent hover | | `--cdBg` | `#edeae4` | Code background | | `--cdTx` | `#3a3530` | Code text | | `--sbBg` | `#f0ede8` | Sidebar background | | `--hdBg` | `rgba(246,244,240,0.92)` | Header background | ### Fonts | Variable | Value | |----------|-------| | `--font-heading` | `'Cormorant Garamond', serif` | | `--font-body` | `'Bricolage Grotesque', sans-serif` | | `--font-code` | `'Fira Code', monospace` | --- ## Cipher A cyberpunk aesthetic with acid yellow-green text and vibrant blue accents. ### Dark mode | Variable | Value | Description | |----------|-------|-------------| | `--bg` | `#050508` | Page background | | `--sf` | `#0c0c12` | Surface | | `--sfH` | `#12121a` | Surface hover | | `--bd` | `#1a1a25` | Border | | `--tx` | `#d4ff00` | Primary text (acid yellow-green) | | `--tx2` | `#8a90a0` | Secondary text | | `--txM` | `#6a7080` | Muted text | | `--ac` | `#6666ff` | Accent (vibrant blue) | | `--acD` | `rgba(102,102,255,0.10)` | Accent dim | | `--acT` | `#8080ff` | Accent hover | | `--cdBg` | `#08080e` | Code background | | `--cdTx` | `#b0c870` | Code text | | `--sbBg` | `#08080d` | Sidebar background | | `--hdBg` | `rgba(5,5,8,0.88)` | Header background | ### Light mode | Variable | Value | Description | |----------|-------|-------------| | `--bg` | `#f0f2f5` | Page background | | `--sf` | `#ffffff` | Surface | | `--sfH` | `#e8eaef` | Surface hover | | `--bd` | `#d0d4db` | Border | | `--tx` | `#0f1219` | Primary text | | `--tx2` | `#4a5060` | Secondary text | | `--txM` | `#6a7080` | Muted text | | `--ac` | `#2020cc` | Accent (deep blue) | | `--acD` | `rgba(32,32,204,0.08)` | Accent dim | | `--acT` | `#1a1aa8` | Accent hover | | `--cdBg` | `#e6e9ef` | Code background | | `--cdTx` | `#2a3520` | Code text | | `--sbBg` | `#ebedf2` | Sidebar background | | `--hdBg` | `rgba(240,242,245,0.90)` | Header background | ### Fonts | Variable | Value | |----------|-------| | `--font-heading` | `'Bodoni Moda', serif` | | `--font-body` | `'Space Grotesk', sans-serif` | | `--font-code` | `'Source Code Pro', monospace` | --- ## Mint A Mintlify-inspired preset with emerald green accents and clean Inter typography. ### Dark mode | Variable | Value | Description | |----------|-------|-------------| | `--bg` | `#0d1117` | Page background | | `--sf` | `#161b22` | Surface | | `--sfH` | `#1c2129` | Surface hover | | `--bd` | `#21262d` | Border | | `--tx` | `#e6edf3` | Primary text | | `--tx2` | `#8b949e` | Secondary text | | `--txM` | `#6e7681` | Muted text | | `--ac` | `#0ea371` | Accent (emerald green) | | `--acD` | `rgba(14,163,113,0.10)` | Accent dim | | `--acT` | `#2dd4a0` | Accent hover | | `--cdBg` | `#0a0e14` | Code background | | `--cdTx` | `#adbac7` | Code text | | `--sbBg` | `#0d1117` | Sidebar background | | `--hdBg` | `rgba(13,17,23,0.88)` | Header background | ### Light mode | Variable | Value | Description | |----------|-------|-------------| | `--bg` | `#ffffff` | Page background | | `--sf` | `#f6f8fa` | Surface | | `--sfH` | `#eef1f5` | Surface hover | | `--bd` | `#d8dee4` | Border | | `--tx` | `#1f2328` | Primary text | | `--tx2` | `#59636e` | Secondary text | | `--txM` | `#6e7681` | Muted text | | `--ac` | `#0a7b53` | Accent (darker emerald) | | `--acD` | `rgba(10,123,83,0.07)` | Accent dim | | `--acT` | `#087a50` | Accent hover | | `--cdBg` | `#f0f3f6` | Code background | | `--cdTx` | `#24292f` | Code text | | `--sbBg` | `#f6f8fa` | Sidebar background | | `--hdBg` | `rgba(255,255,255,0.90)` | Header background | ### Fonts | Variable | Value | |----------|-------| | `--font-heading` | `'Inter', sans-serif` | | `--font-body` | `'Inter', sans-serif` | | `--font-code` | `'Fira Code', monospace` | --- ## Theming Tome ships with four theme presets and extensive customization options. Every visual aspect — colors, fonts, spacing — can be adjusted through configuration or CSS variables. ## Presets ### Amber (default) A warm, golden aesthetic with serif headings. Clean and approachable. ```javascript theme: { preset: "amber", } ``` ### Editorial Swiss poster-inspired design with a coral accent, grotesque typography, and deep navy dark mode. ```javascript theme: { preset: "editorial", } ``` ### Cipher Cyberpunk aesthetic with acid yellow-green text, vibrant blue accents, and high-contrast serif display headings. ```javascript theme: { preset: "cipher", } ``` ### Mint Mintlify-inspired design with emerald green accents, Inter typography, and a clean SaaS-docs feel. ```javascript theme: { preset: "mint", } ``` ## Custom accent color Override the default accent color with any hex value: ```javascript theme: { preset: "amber", accent: "#2563eb", // Blue accent } ``` Tome derives tint and dim variants automatically from your accent color. ## Dark mode Control the color scheme: ```javascript theme: { mode: "auto", // Follows system preference (default) // mode: "light", // Always light // mode: "dark", // Always dark } ``` When set to `auto`, a theme toggle appears in the sidebar. The default fallback is light mode when system preference is unavailable. ## Custom fonts Override any of the three font families: ```javascript theme: { fonts: { heading: "Playfair Display", body: "Inter", code: "JetBrains Mono", }, } ``` Load your fonts via Google Fonts in `index.html` or self-host them. ## Border radius Control the roundness of UI elements: ```javascript theme: { radius: 8, // pixels, default varies by preset } ``` ## CSS variables For fine-grained control, override CSS variables directly. Add a ` ``` ### Variable reference | Variable | Purpose | |----------|---------| | `--ac` | Accent color (links, highlights) | | `--acD` | Accent dim (callout backgrounds, subtle tints) | | `--acT` | Accent hover (transition state) | | `--bg` | Page background | | `--sf` / `--sfH` | Surface and surface hover | | `--tx` / `--tx2` / `--txM` | Text primary, secondary, muted | | `--bd` | Borders | | `--cdBg` / `--cdTx` | Code block background and text | | `--sbBg` | Sidebar background | | `--hdBg` | Header background | | `--font-heading` | Heading font family | | `--font-body` | Body font family | | `--font-code` | Code font family | --- ## Deploy to Tome Cloud Tome Cloud hosts your documentation site on a global CDN with automatic SSL, custom domains, and analytics. This tutorial covers the full deployment flow. ## Prerequisites - A Tome documentation project (see [Create your first site](tutorials/first-site)) - Node.js 22.22.2+ ## 1. Authenticate Log in to your Tome Cloud account: ```bash npx @tomehq/cli login ``` Enter your email address. You'll receive a magic link — click it to authenticate. Your API token is stored locally for future deployments. ## 2. Deploy From your project directory: ```bash npx @tomehq/cli deploy ``` Tome builds your site, collects the output files, and uploads them using hash-based deduplication. Only changed files are transferred, making subsequent deploys fast. After deployment, your site is live at: ``` https://your-project.tome.center ``` ## 3. Add a custom domain Register a custom domain for your docs: ```bash npx @tomehq/cli domains:add docs.example.com ``` Tome returns DNS records you need to configure with your domain registrar: ```text Type: CNAME Name: docs Value: your-project.tome.center ``` After configuring DNS, verify the domain: ```bash npx @tomehq/cli domains:verify docs.example.com ``` SSL is provisioned automatically once DNS propagates. ## 4. Manage domains List all domains attached to your project: ```bash npx @tomehq/cli domains:list ``` Remove a domain: ```bash npx @tomehq/cli domains:remove docs.example.com ``` ## 5. Automatic deploys with CI/CD Projects created with `tome init` include a GitHub Actions workflow (`.github/workflows/deploy.yml`) that deploys automatically: - **Push to main** → production deploy - **Pull requests** → preview deploy with a unique URL ### Setup 1. Generate a deploy token by running `npx @tomehq/cli login`, then copy the token from `~/.tome/config` 2. In your GitHub repository, go to **Settings → Secrets and variables → Actions** 3. Create a secret named `TOME_TOKEN` with your deploy token That's it — every push to `main` triggers a production deploy, and every PR gets a preview URL. ### GitLab CI Create `.gitlab-ci.yml`: ```yaml deploy: image: node:20 script: - npm ci - npm run build - npx @tomehq/cli deploy only: - main variables: TOME_TOKEN: $TOME_TOKEN ``` Add `TOME_TOKEN` in **Settings → CI/CD → Variables**. ### Bitbucket Pipelines Add to `bitbucket-pipelines.yml`: ```yaml pipelines: branches: main: - step: name: Deploy docs image: node:20 script: - npm ci - npm run build - npx @tomehq/cli deploy ``` Add `TOME_TOKEN` in **Repository settings → Pipelines → Variables**. ## Deployment details Each deploy creates an immutable snapshot. You can view deployment history and analytics in the Tome Dashboard. | Detail | Value | |--------|-------| | CDN | Cloudflare R2 (global edge) | | SSL | Automatic via Cloudflare | | Deduplication | Content-hash based | | Rollback | Deploy any previous snapshot | ## Next steps - **[Configuration guide](guides/configuration)** to customize your site before deploying - **[CLI reference](reference/cli)** for the full list of deployment commands --- ## Create Your First Site This tutorial walks you through creating a Tome documentation site from scratch. By the end, you'll have a working docs site running locally with custom pages and navigation. ## Prerequisites You need **Node.js 22.22.2+** and a package manager (`npm`, `yarn`, or `pnpm`). ## 1. Scaffold the project Run the init command to create a new project: ```bash npx @tomehq/cli init my-docs ``` This creates a directory with the following structure: ```text my-docs/ ├── tome.config.js # Site configuration ├── package.json # Dependencies and scripts ├── index.html # Vite entry point ├── .tome/entry.tsx # Theme bootstrap (don't edit) ├── pages/ # Your documentation pages │ ├── index.md │ ├── tutorials/ │ │ ├── getting-started.md │ │ └── deploy.md │ ├── guides/ │ │ ├── components.mdx │ │ └── configuration.md │ ├── reference/ │ │ ├── cli.md │ │ ├── components.md │ │ └── config.md │ └── concepts/ │ ├── how-tome-works.md │ └── file-routing.md ├── public/ # Static assets └── styles/ # Custom CSS (optional) ``` Pages are organized using the [Diataxis framework](https://diataxis.fr/) — tutorials, guides, reference, and concepts. ## 2. Install dependencies ```bash cd my-docs npm install ``` ## 3. Start the dev server ```bash npm run dev ``` Open `http://localhost:3000`. You should see the starter documentation site. Every time you save a file, the page reloads automatically. ## 4. Add a new page Create `pages/guides/deployment.md`: ```markdown --- title: Deployment Guide description: How to deploy your Tome site to production. --- # Deployment Guide Run `npm run build` to produce static files in the `out/` directory. Upload this directory to any static hosting provider. ``` The page is immediately available at `/guides/deployment` in the dev server. ## 5. Configure navigation Open `tome.config.js` and add your new page to the sidebar: ```javascript export default { name: "my-docs", theme: { preset: "amber", mode: "auto", }, navigation: [ { group: "Overview", pages: ["index"] }, { group: "Tutorials", pages: ["tutorials/getting-started", "tutorials/deploy"], }, { group: "Guides", pages: ["guides/components", "guides/configuration", "guides/deployment"], }, { group: "Reference", pages: ["reference/config", "reference/components", "reference/cli"], }, { group: "Concepts", pages: ["concepts/how-tome-works", "concepts/file-routing"], }, ], }; ``` The sidebar updates to reflect the new structure. ## 6. Customize the theme Change the preset to `editorial` and set a custom accent color: ```javascript theme: { preset: "editorial", accent: "#ff6b4a", mode: "auto", }, ``` The entire site switches to the editorial aesthetic with your accent color. ## 7. Build for production ```bash npm run build ``` This outputs a static site to `out/` with a pre-built search index. The output is ready to deploy to any hosting provider. ## Next steps - **[Deploy to Tome Cloud](tutorials/deploy-to-cloud)** to publish with a single command - **[Configuration guide](guides/configuration)** for all available options - **[Components reference](reference/components)** for the full list of MDX components --- ## Authentication The API playground supports several authentication methods. Users can enter credentials that are included in test requests. ## Configuration Add auth settings to your API config: ```javascript export default { api: { spec: "./openapi.yaml", playground: { enabled: true, auth: { type: "bearer", // "bearer", "apiKey", or "basic" }, }, }, }; ``` ## Bearer token The most common pattern for modern APIs. A token input appears in the playground header: ```javascript auth: { type: "bearer", } ``` Requests include the header: ``` Authorization: Bearer ``` ## API key For APIs that use key-based authentication: ```javascript auth: { type: "apiKey", name: "X-API-Key", // Header name in: "header", // "header" or "query" } ``` When `in` is `"query"`, the key is appended as a URL parameter instead. ## Basic auth For username/password authentication: ```javascript auth: { type: "basic", } ``` The playground shows username and password fields. The value is sent as a Base64-encoded `Authorization: Basic` header. ## OpenAPI security schemes If your OpenAPI spec defines security schemes, Tome reads them automatically: ```yaml components: securitySchemes: BearerAuth: type: http scheme: bearer ApiKeyAuth: type: apiKey in: header name: X-API-Key ``` When security schemes are defined in the spec, Tome uses them instead of the manual config. You don't need to configure `auth` separately. ## Security notes - Credentials entered in the playground are stored only in browser memory for the current session - Credentials are never sent to Tome's servers — requests go directly from the browser to your API - CORS must be enabled on your API server for playground requests to work - For production APIs, consider providing a sandbox environment URL through the `baseUrl` config --- ## Endpoints Tome renders each API operation from your OpenAPI spec as a structured endpoint section with method badges, parameter tables, request/response schemas, and an optional interactive playground. ## Endpoint layout Each endpoint displays: 1. **Method badge** — Color-coded (GET, POST, PUT, DELETE, PATCH) 2. **Path** — The endpoint URL with path parameters highlighted 3. **Description** — From the operation's `summary` and `description` fields 4. **Parameters** — Path, query, and header parameters in a table 5. **Request body** — Schema rendered with types and descriptions 6. **Responses** — Status codes with response schemas ## Tag grouping Endpoints are organized by their OpenAPI tags. Each tag becomes a section heading: ```yaml paths: /users: get: tags: [Users] summary: List all users /users/{id}: get: tags: [Users] summary: Get user by ID /projects: get: tags: [Projects] summary: List projects ``` This generates two groups: "Users" with two endpoints and "Projects" with one. ## Parameter rendering Parameters are rendered in a table with type information: | Name | Type | In | Required | Description | |------|------|----|----------|-------------| | `id` | string | path | yes | The user ID | | `limit` | integer | query | no | Max results (default: 20) | | `offset` | integer | query | no | Pagination offset | ## Schema display Request and response schemas are rendered recursively. Nested objects show their properties with types: ``` UserResponse { id: string — Unique identifier name: string — Display name email: string — Email address created_at: string — ISO 8601 timestamp settings: { theme: string — "light" or "dark" locale: string — Language code } } ``` Arrays, enums, and `oneOf`/`anyOf` unions are all supported. ## Interactive playground When `playground.enabled` is true in your config, each endpoint gets a "Try it" section where users can: - Fill in path and query parameters - Edit the request body as JSON - Set authentication headers - Send the request and view the response ```javascript api: { spec: "./openapi.yaml", playground: { enabled: true, baseUrl: "https://api.example.com", // Override base URL }, }, ``` The playground uses `fetch` directly from the browser. CORS must be enabled on your API for cross-origin requests. --- ## Overview Tome generates a complete API reference from an OpenAPI 3.x specification. Point it at a spec file and get rendered endpoint documentation with an interactive playground — no manual writing required. ## Setup Add the `api` section to your `tome.config.js`: ```javascript export default { name: "My API Docs", api: { spec: "./openapi.yaml", // Path to your OpenAPI spec playground: { enabled: true, // Enable interactive playground }, }, }; ``` Tome parses the spec at build time and generates: - Endpoint listing organized by tags - Request/response schema documentation - Parameter tables with types and descriptions - An interactive playground for testing endpoints ## Supported formats | Format | Extension | |--------|-----------| | OpenAPI 3.0 | `.json`, `.yaml`, `.yml` | | OpenAPI 3.1 | `.json`, `.yaml`, `.yml` | Swagger 2.x specs are not directly supported. Convert them first using tools like `swagger2openapi`. ## What gets generated From a single spec file, Tome creates: - **Endpoint pages** — Each operation (GET, POST, PUT, DELETE) gets its own section with method, path, description, and parameters. - **Schema documentation** — Request bodies and response objects are rendered with type information. - **Tag grouping** — Operations are organized by their OpenAPI tags. - **Try it** — The playground lets users send real requests with custom parameters and see responses. ## Spec organization For the best results, make sure your OpenAPI spec includes: - Descriptive `summary` and `description` fields on each operation - Tags to group related endpoints - Schema definitions with `description` fields - Example values for parameters and request bodies ## Next steps - **[Endpoints](v2/api-endpoints)** for details on how endpoints are rendered - **[Authentication](v2/api-auth)** for configuring auth in the playground --- ## CLI Reference The `tome` CLI is the primary interface for creating, developing, building, and deploying documentation sites. ## Installation ```bash npm install -D @tomehq/cli # or globally npm install -g @tomehq/cli ``` ## Commands ### `tome init [name]` Create a new Tome documentation project. ```bash tome init my-docs ``` | Argument | Default | Description | |----------|---------|-------------| | `name` | `my-docs` | Project directory name | | Flag | Default | Description | |------|---------|-------------| | `-t, --template ` | `default` | Starter template | Creates `tome.config.js`, `package.json`, `index.html`, `.tome/entry.tsx`, starter pages in `pages/`, and `public/` and `styles/` directories. --- ### `tome dev` Start the development server with hot reloading. ```bash tome dev tome dev -p 4000 tome dev --host ``` | Flag | Default | Description | |------|---------|-------------| | `-p, --port ` | `3000` | Server port | | `--host` | `false` | Expose to network (bind `0.0.0.0`) | Watches `pages/` for file changes and reloads automatically. Config changes trigger a full reload. --- ### `tome build` Build the documentation site for production. ```bash tome build tome build -o dist ``` | Flag | Default | Description | |------|---------|-------------| | `-o, --outDir ` | `out` | Output directory | Produces a static site and runs Pagefind to build the search index. --- ### `tome deploy` Deploy the site to Tome Cloud. Requires `tome login` first. ```bash tome deploy ``` Builds, collects output files, and uploads using hash-based deduplication. --- ### `tome login` Authenticate with Tome Cloud. ```bash tome login ``` Prompts for email and sends a magic link. Stores the API token locally. --- ### `tome domains:add ` Add a custom domain. Returns DNS records to configure. ```bash tome domains:add docs.example.com ``` ### `tome domains:verify ` Verify DNS configuration for a custom domain. ```bash tome domains:verify docs.example.com ``` ### `tome domains:list` List all custom domains for the current project. ### `tome domains:remove ` Remove a custom domain. --- ### `tome algolia:init` Initialize an Algolia DocSearch index. Prompts for credentials and creates a crawler configuration. --- ### `tome mcp` Start the MCP (Model Context Protocol) stdio server for AI tool integration. Exposes documentation content as MCP resources and tools. --- ## Architecture Tome is built on Vite and React. Understanding the architecture helps when debugging build issues or building advanced customizations. ## Overview A Tome site is a Vite application with a custom plugin that handles page discovery, routing, and content processing. The theme package provides the React UI shell. ```mermaid flowchart LR A["tome.config.js"] --> B["Vite Plugin"] B --> C["Virtual Modules"] C --> D["Theme Shell"] D --> E["Static Site"] ``` ## Vite plugin The core of Tome is `vite-plugin-tome` in `@tomehq/core`. It has three responsibilities: **1. Page discovery** — On startup, the plugin scans `pages/` for `.md` and `.mdx` files, extracts frontmatter, and builds a route table. It watches for file changes during development and triggers hot reloads. **2. Virtual modules** — The plugin exposes content through Vite's virtual module system: | Module | Contents | |--------|----------| | `virtual:tome/config` | The resolved config as JSON | | `virtual:tome/routes` | Route table with IDs, URLs, and frontmatter | | `virtual:tome/page/:id` | Processed page content | | `virtual:tome/api` | Parsed OpenAPI manifest | | `virtual:tome/analytics` | Analytics provider settings | **3. Build-time generation** — During builds, the plugin injects analytics scripts and generates the `mcp.json` manifest. ## Theme system The theme package (`@tomehq/theme`) provides the React shell: - **Shell component** — Header, sidebar, content area, footer - **Preset system** — Color tokens and CSS variables per preset - **Search integration** — Pagefind or Algolia, loaded dynamically - **AI chat** — Optional floating widget The entry point (`.tome/entry.tsx`) bootstraps the shell by importing `@tomehq/theme/entry`. ## Content pipeline ```mermaid flowchart TD A["pages/*.md"] --> B["gray-matter"] B --> C["Frontmatter"] B --> D["Markdown body"] D --> E["remark + rehype"] E --> F["Shiki highlighting"] F --> G["DOMPurify sanitize"] G --> H["HTML + headings"] I["pages/*.mdx"] --> J["Extract frontmatter"] J --> K["@mdx-js/rollup"] K --> L["React component"] ``` ### Markdown (`.md`) 1. Frontmatter extracted via `gray-matter` 2. Markdown processed through remark (GFM, math) and rehype (slugs, autolink headings) 3. Code blocks highlighted with Shiki (mermaid blocks converted to client-side placeholders) 4. HTML sanitized with DOMPurify, headings extracted for table of contents 5. HTML + headings + frontmatter served as virtual module ### MDX (`.mdx`) 1. Frontmatter and headings extracted from raw source 2. File passed to `@mdx-js/rollup` for JSX compilation 3. Virtual module re-exports the compiled React component + metadata ## Build output ```text out/ ├── index.html # SPA entry ├── assets/ │ ├── index-[hash].js # Application bundle │ └── index-[hash].css # Styles ├── _pagefind/ # Search index ├── mcp.json # MCP manifest ├── llms.txt # AI-readable page index ├── llms-full.txt # Full page content for LLMs └── 404.html # Error page ``` The output is a single-page application. Search is fully static. The `llms.txt` and `llms-full.txt` files are auto-generated at build time to make your documentation discoverable by AI tools and language models. ## Package structure | Package | Purpose | |---------|---------| | `@tomehq/cli` | CLI commands (init, dev, build, deploy, mcp, typedoc) | | `@tomehq/core` | Config, routing, Vite plugin, markdown processing, MCP server | | `@tomehq/theme` | Shell UI, presets, search, AI chat | | `@tomehq/components` | MDX components (Callout, Tabs, Card, etc.) | | `@tomehq/landing` | Marketing landing page | | `@tomehq/dashboard` | Tome Cloud dashboard | --- ## File-System Routing Every `.md` or `.mdx` file in the `pages/` directory becomes a page. The file path determines the URL. ## Basic routing | File path | URL | |-----------|-----| | `pages/index.md` | `/` | | `pages/quickstart.md` | `/quickstart` | | `pages/guides/deployment.md` | `/guides/deployment` | | `pages/api/endpoints.md` | `/api/endpoints` | | `pages/api/index.md` | `/api` | **Rules:** - `index.md` serves at the directory's root path - File extensions are stripped from the URL - Directory nesting maps directly to URL segments ## Page IDs Each page has an ID derived from its path relative to `pages/`: | File | Page ID | |------|---------| | `pages/index.md` | `index` | | `pages/quickstart.md` | `quickstart` | | `pages/guides/deployment.md` | `guides/deployment` | Page IDs are used in `navigation` config to control sidebar order. ## Navigation vs. routing All pages in `pages/` are routable regardless of whether they appear in `navigation`. Navigation only controls the sidebar. Pages can be hidden from the sidebar using `hidden: true` in frontmatter while remaining accessible at their URL. ## i18n routing When multiple locales are configured, organize pages by locale subdirectory: ```text pages/ ├── en/ # Default locale │ ├── index.md │ └── quickstart.md ├── es/ # Spanish │ ├── index.md │ └── quickstart.md ``` | File | URL | |------|-----| | `pages/en/index.md` | `/` (default — no prefix) | | `pages/es/index.md` | `/es/` | | `pages/es/quickstart.md` | `/es/quickstart` | The default locale serves at the root without a prefix. When `fallback: true` and a page doesn't exist in a non-default locale, the default version is used. ## Versioned routing When versioning is configured: ```text pages/ ├── current/ # Latest version │ ├── index.md │ └── api.md ├── v1.0/ │ ├── index.md │ └── api.md ``` | File | URL | |------|-----| | `pages/current/index.md` | `/` | | `pages/v1.0/index.md` | `/v1.0/` | | `pages/v1.0/api.md` | `/v1.0/api` | The `current` directory serves at the root. Older versions are prefixed. ## File discovery Tome discovers pages by scanning `pages/` for `**/*.{md,mdx}` files. Discovery runs at startup and again whenever files are added, removed, or renamed during development. --- ## Configuration All site configuration lives in `tome.config.js` (or `.mjs` / `.ts`) at your project root. Tome validates the config with Zod and provides clear error messages if anything is wrong. ## Minimal config ```javascript export default { name: "My Docs", }; ``` This is all you need. Tome uses sensible defaults for everything else. ## Site metadata ```javascript export default { name: "My Docs", logo: "/logo.svg", // Path relative to public/ favicon: "/favicon.ico", // Path relative to public/ baseUrl: "https://docs.example.com", }; ``` `baseUrl` is used for generating canonical URLs and analytics endpoints. It should be the full URL where your site is hosted. ## Navigation The `navigation` array defines your sidebar structure. Each group has a label and a list of page IDs (filenames without extensions): ```javascript navigation: [ { group: "Getting Started", pages: ["index", "quickstart"], }, { group: "API", pages: ["api/authentication", "api/endpoints", "api/errors"], }, ], ``` Pages not listed in navigation still exist at their URL — they're just hidden from the sidebar. ### Nested groups Groups can be nested for complex documentation structures: ```javascript navigation: [ { group: "SDK", pages: [ "sdk/overview", { group: "Languages", pages: ["sdk/javascript", "sdk/python", "sdk/go"], }, ], }, ], ``` ## Top navigation Add links to the header bar: ```javascript topNav: [ { label: "Blog", href: "https://blog.example.com" }, { label: "Changelog", href: "/changelog" }, ], ``` ## Theme ```javascript theme: { preset: "editorial", // "amber" or "editorial" accent: "#ff6b4a", // Custom accent color (hex) mode: "auto", // "light", "dark", or "auto" fonts: { heading: "Playfair Display", body: "Source Sans Pro", code: "Fira Code", }, }, ``` See **[Theming](v2/theming)** for full customization details. ## Base path If your docs are served under a subpath (e.g., `example.com/docs/`), set `basePath`: ```javascript basePath: "/docs/", ``` This configures Vite's `base` option so all asset paths resolve correctly. ## Search Pagefind is enabled by default with no configuration. To use Algolia DocSearch instead: ```javascript search: { provider: "algolia", appId: "YOUR_APP_ID", apiKey: "YOUR_SEARCH_KEY", indexName: "your-index", }, ``` ## Banner Display an announcement banner at the top of every page: ```javascript banner: { text: "v2.0 is now available!", link: "/changelog", // Optional — makes the text a link dismissible: true, // Default: true — shows a close button }, ``` When a user dismisses the banner, it stays hidden until you change the text. Updating the `text` value automatically shows the banner again for all users. ## Math rendering Enable LaTeX math support with KaTeX: ```javascript math: true, ``` Once enabled, you can use inline math with `$E = mc^2$` and display math with `$$` blocks in your Markdown pages. Requires `remark-math`, `rehype-katex`, and `katex` as peer dependencies: ```bash npm install remark-math rehype-katex katex ``` ## Mermaid diagrams Mermaid diagrams work out of the box with no configuration. Use a `mermaid` code fence in any `.md` or `.mdx` file: ````markdown ```mermaid flowchart LR A["Start"] --> B["Process"] B --> C["End"] ``` ```` Diagrams are rendered client-side and automatically adapt to your site's light/dark theme. ## AI discoverability Tome automatically generates two files at build time to make your docs accessible to AI tools: - **`llms.txt`** — A page index with titles, descriptions, and URLs - **`llms-full.txt`** — Full raw Markdown content of all non-hidden pages These are always generated — no configuration needed. Hidden pages (with `hidden: true` in frontmatter) are excluded. ## Full example ```javascript export default { name: "Acme Docs", logo: "/acme-logo.svg", favicon: "/favicon.ico", baseUrl: "https://docs.acme.com", theme: { preset: "editorial", accent: "#2563eb", mode: "auto", }, navigation: [ { group: "Overview", pages: ["index", "quickstart"] }, { group: "Guides", pages: ["guides/auth", "guides/deploy"] }, { group: "API", pages: ["api/rest", "api/webhooks"] }, ], topNav: [ { label: "Changelog", href: "/changelog" }, ], search: { provider: "local" }, banner: { text: "v2.0 is now available!", link: "/changelog", dismissible: true, }, math: true, }; ``` --- ## API Reference Setup Tome can generate a full API reference from an OpenAPI 3.x specification. The reference includes endpoint documentation, request/response schemas, and an interactive playground for testing endpoints. ## 1. Add your OpenAPI spec Place your OpenAPI spec file (JSON or YAML) in your project: ```text my-docs/ ├── openapi.yaml # Your API spec ├── tome.config.js └── pages/ ``` ## 2. Configure Tome Add the `api` section to your config: ```javascript export default { name: "My API Docs", api: { spec: "./openapi.yaml", playground: true, baseUrl: "https://api.example.com", auth: { type: "bearer", header: "Authorization", }, }, }; ``` ### Options | Field | Type | Default | Description | |-------|------|---------|-------------| | `spec` | string | — | Path to your OpenAPI spec file (required) | | `playground` | boolean | `true` | Enable the interactive API playground | | `baseUrl` | string | — | Base URL for playground requests | | `auth.type` | string | — | Auth type: `"bearer"`, `"apiKey"`, or `"oauth2"` | | `auth.header` | string | — | Header name for the auth token | ## 3. View the reference Start the dev server and navigate to `/api`. Tome parses the spec and renders: - **Endpoint groups** organized by OpenAPI tags - **Request parameters** with types, descriptions, and required markers - **Response schemas** with expandable nested objects - **Code examples** for `curl`, JavaScript, and Python ## 4. Interactive playground When `playground: true`, each endpoint includes a "Try It" panel where users can: - Set path parameters and query strings - Edit the request body with JSON validation - Add authentication headers - Send requests and view formatted responses The playground sends requests directly from the browser, so CORS must be configured on your API server. ## Supported spec formats Tome supports OpenAPI 3.0 and 3.1 specifications in JSON or YAML format. Swagger 2.x specs are not supported — convert them with tools like `swagger2openapi`. --- ## Configuration All site configuration lives in `tome.config.js` (or `.mjs` / `.ts`) at your project root. Tome validates the config with Zod and provides clear error messages if anything is wrong. ## Minimal config ```javascript export default { name: "My Docs", }; ``` This is all you need. Tome uses sensible defaults for everything else. ## Site metadata ```javascript export default { name: "My Docs", logo: "/logo.svg", // Path relative to public/ favicon: "/favicon.ico", // Path relative to public/ baseUrl: "https://docs.example.com", }; ``` `baseUrl` is used for generating canonical URLs and analytics endpoints. It should be the full URL where your site is hosted. ## Navigation The `navigation` array defines your sidebar structure. Each group has a label and a list of page IDs (filenames without extensions): ```javascript navigation: [ { group: "Getting Started", pages: ["index", "quickstart"], }, { group: "API", pages: ["api/authentication", "api/endpoints", "api/errors"], }, ], ``` Pages not listed in navigation still exist at their URL — they're just hidden from the sidebar. ### Nested groups Groups can be nested for complex documentation structures: ```javascript navigation: [ { group: "SDK", pages: [ "sdk/overview", { group: "Languages", pages: ["sdk/javascript", "sdk/python", "sdk/go"], }, ], }, ], ``` ## Top navigation Add links to the header bar: ```javascript topNav: [ { label: "Blog", href: "https://blog.example.com" }, { label: "GitHub", href: "https://github.com/example/docs" }, ], ``` ## Theme See the [Custom theme guide](/docs/guides/custom-theme) for full details. ```javascript theme: { preset: "editorial", // "amber" or "editorial" accent: "#ff6b4a", // Custom accent color (hex) mode: "auto", // "light", "dark", or "auto" fonts: { heading: "Playfair Display", body: "Source Sans Pro", code: "Fira Code", }, }, ``` ## Base path If your docs are served under a subpath (e.g., `example.com/docs/`), set `basePath`: ```javascript basePath: "/docs/", ``` This configures Vite's `base` option so all asset paths resolve correctly. ## Banner Show an announcement at the top of every page: ```javascript banner: { text: "We just launched v2.0!", link: "/changelog", // Optional — wraps text in a link dismissible: true, // Default true — shows close button }, ``` The banner uses your accent color as its background. When a user dismisses it, a hash of the text is saved to localStorage. Change the text to show the banner again for all users. ## Math / KaTeX Enable LaTeX math rendering with: ```javascript math: true, ``` Then install the peer dependencies: ```bash npm install remark-math rehype-katex katex ``` Use `$...$` for inline math and `$$...$$` for display blocks in your Markdown pages. ## Mermaid diagrams Mermaid diagrams require no configuration. Use a `mermaid` code fence in any page: ````markdown ```mermaid flowchart LR A["Input"] --> B["Process"] --> C["Output"] ``` ```` Mermaid is loaded from a CDN on demand — no install needed. Diagrams adapt to your light/dark theme automatically. ## AI discoverability (llms.txt) At build time, Tome automatically generates: - **`llms.txt`** — Page index with titles, descriptions, and URLs - **`llms-full.txt`** — Complete Markdown content of every non-hidden page No configuration needed. Hidden pages (frontmatter `hidden: true`) are excluded. These files help AI assistants and language models understand your documentation. ## Full example ```javascript export default { name: "Acme Docs", logo: "/acme-logo.svg", favicon: "/favicon.ico", baseUrl: "https://docs.acme.com", theme: { preset: "editorial", accent: "#2563eb", mode: "auto", }, navigation: [ { group: "Overview", pages: ["index", "quickstart"] }, { group: "Guides", pages: ["guides/auth", "guides/deploy"] }, { group: "API", pages: ["api/rest", "api/webhooks"] }, ], topNav: [ { label: "GitHub", href: "https://github.com/acme/docs" }, ], search: { provider: "local" }, }; ``` See the [Config reference](/docs/reference/config) for every available field. --- ## Custom Theme Tome ships with two theme presets and extensive customization options. Every visual aspect — colors, fonts, spacing — can be adjusted through configuration or CSS variables. ## Presets Choose between two built-in presets: ### Amber (default) A warm, approachable aesthetic with golden accent tones. Good for developer documentation and technical guides. ```javascript theme: { preset: "amber", } ``` ### Editorial A refined, high-contrast aesthetic inspired by Swiss poster design and literary magazines. Features serif headings and a more dramatic visual presence. ```javascript theme: { preset: "editorial", } ``` See [Theme presets reference](/docs/reference/theme-presets) for the exact color values. ## Accent color Override the preset's accent color with any hex value: ```javascript theme: { preset: "amber", accent: "#2563eb", // Blue accent instead of amber } ``` Tome derives tint and dim variants automatically from your accent color. ## Color mode Control dark/light mode behavior: | Value | Behavior | |-------|----------| | `"auto"` | Follows system preference (default) | | `"light"` | Always light mode | | `"dark"` | Always dark mode | Users can toggle the mode using the theme switch in the header. ## Custom fonts Override any font family. Make sure to add the appropriate `` tag to `index.html` if using custom Google Fonts. ```javascript theme: { fonts: { heading: "Playfair Display", body: "Source Sans Pro", code: "Fira Code", }, } ``` ## CSS variables For fine-grained control, override CSS variables in a custom stylesheet. The key variables are: | Variable | Description | |----------|-------------| | `--ac` | Accent color | | `--acD` | Accent dark variant | | `--acT` | Accent tint | | `--bg` | Page background | | `--sf` | Surface (cards, sidebar) | | `--sfH` | Surface hover state | | `--bd` | Border color | | `--tx` | Primary text | | `--tx2` | Secondary text | | `--txM` | Muted text | See the [Theme presets reference](/docs/reference/theme-presets) for the complete variable list with values per preset. ## Border radius Adjust the global border radius: ```javascript theme: { radius: "4px", // Sharper corners radius: "12px", // Rounder corners } ``` --- ## Migrate from GitBook or Mintlify Tome provides automated migration from GitBook and Mintlify. The CLI handles navigation restructuring, component syntax conversion, redirect mapping, and asset copying. ## Migrate from GitBook ```bash npx @tomehq/cli migrate gitbook ./path-to-gitbook-project ``` ### What gets converted | GitBook | Tome | |---------|------| | `SUMMARY.md` navigation | `tome.config.js` navigation array | | `.gitbook.yaml` config | `tome.config.js` settings | | `{% hint style="info" %}` | `` | | `{% hint style="warning" %}` | `` | | `{% hint style="danger" %}` | `` | | `{% hint style="success" %}` | `` | | `{% tabs %}` / `{% tab %}` | `` / `` | | `{% code title="file.js" %}` | Fenced code block with title | | `{% embed url="..." %}` | Plain markdown link | | `.gitbook.yaml` redirects | `tome.config.js` redirects | | Images / assets | Copied to `public/` | ### Options ```bash # Output to a specific directory npx @tomehq/cli migrate gitbook ./gitbook-docs --out ./my-new-docs # Preview without writing files npx @tomehq/cli migrate gitbook ./gitbook-docs --dry-run ``` ### How it works 1. Reads `SUMMARY.md` for navigation structure and `.gitbook.yaml` for project settings 2. Walks all Markdown files and converts GitBook-specific syntax to Tome MDX components 3. Files containing converted JSX components are renamed from `.md` to `.mdx` 4. Copies static assets (images, `.gitbook/assets/`) to `public/` 5. Generates `tome.config.js` with navigation, redirects, and project name 6. Reports a summary of pages converted, redirects created, and any warnings --- ## Migrate from Mintlify ```bash npx @tomehq/cli migrate mintlify ./path-to-mintlify-project ``` ### What gets converted | Mintlify | Tome | |----------|------| | `mint.json` navigation | `tome.config.js` navigation array | | `mint.json` colors | `tome.config.js` theme accent | | `mint.json` logo / favicon | `tome.config.js` logo / favicon | | `mint.json` topbar links | `tome.config.js` topNav | | `mint.json` redirects | `tome.config.js` redirects | | `mint.json` openapi | `tome.config.js` api.spec | | `` / `` | `` | | `` | `` | | `` / `` | `` | | `` | `` wrapper | | `` | Removed (individual `` kept) | | `` | Removed (content preserved) | | `` | Inlined file content | Components that are already compatible (``, ``, ``, ``, ``) are kept as-is. ### Options ```bash # Output to a specific directory npx @tomehq/cli migrate mintlify ./mintlify-docs --out ./my-new-docs # Preview without writing files npx @tomehq/cli migrate mintlify ./mintlify-docs --dry-run ``` --- ## After migration ### Review redirects Both migration tools automatically extract redirects from the source project and add them to `tome.config.js`. Check the generated config to verify redirect paths are correct: ```js export default defineConfig({ redirects: [ { from: "/old-page", to: "/new-page" }, ], }); ``` See the [Redirects guide](/docs/guides/redirects) for more on how redirects work. ### Start the dev server ```bash cd my-new-docs npm install npm run dev ``` Open [localhost:3000](http://localhost:3000) and review the converted pages. Some manual adjustments may be needed for complex custom components or layouts that don't have a direct Tome equivalent. ### Deploy Once everything looks good, deploy to Tome Cloud: ```bash npx @tomehq/cli login npx @tomehq/cli deploy ``` Or push to your git repository — if you scaffold with `tome init`, a GitHub Actions workflow is included that deploys automatically on push to `main`. --- ## Redirects Tome supports URL redirects at two levels: global config and per-page frontmatter. Redirects return a 301 (permanent) status in development and generate static redirect files for production builds. ## Config-level redirects Add a `redirects` array to `tome.config.js`: ```js import { defineConfig } from "@tomehq/core"; export default defineConfig({ name: "My Docs", redirects: [ { from: "/old-page", to: "/new-page" }, { from: "/docs/setup", to: "/docs/getting-started" }, { from: "/api", to: "/docs/reference/api" }, ], }); ``` Each entry needs a `from` path (the old URL) and a `to` path (the new URL). ## Frontmatter redirects Add `redirect_from` to a page's frontmatter to redirect old URLs to that page: ```md --- title: Getting Started redirect_from: - /docs/setup - /docs/installation - /quickstart --- Welcome to the getting started guide. ``` Any request to `/docs/setup`, `/docs/installation`, or `/quickstart` will redirect to this page. ## How redirects work ### Development The dev server intercepts requests and returns a `301 Moved Permanently` response for any matched redirect path. Both config-level and frontmatter redirects are active during development. ### Production builds During `tome build`, Tome emits two types of redirect outputs to ensure compatibility across hosting platforms: 1. **`_redirects` file** — A Netlify/Vercel-compatible redirects file in the build output root. Each line maps a source path to a destination with a 301 status code. 2. **Meta-refresh HTML files** — For each redirect source path, Tome generates a small HTML file with a `` tag. This ensures redirects work on any static hosting platform, including S3 and GitHub Pages. ## Migration redirects When migrating from GitBook or Mintlify, the migration tools automatically extract redirects from the source project configuration and add them to your `tome.config.js`. See the [Migration guide](/docs/guides/migration) for details. --- ## Search Tome includes search out of the box. No configuration is needed for the default experience — Pagefind indexes your site at build time and provides fast, client-side search with zero external dependencies. ## Built-in search (Pagefind) Pagefind is the default search provider. It runs automatically during `tome build`: 1. Tome builds your static site to `out/` 2. Pagefind indexes all HTML pages 3. The search index is placed in `out/_pagefind/` 4. The search UI loads the index on demand (< 1KB initial JS) No configuration required. Search is available on every page via the header search bar or the `Ctrl+K` / `Cmd+K` keyboard shortcut. ```javascript // Default — can be omitted entirely search: { provider: "local", } ``` ## Algolia DocSearch For larger documentation sites, you can use Algolia DocSearch as an alternative: ```javascript search: { provider: "algolia", appId: "YOUR_APP_ID", apiKey: "YOUR_SEARCH_API_KEY", indexName: "your-index-name", } ``` ### Initialize the Algolia index Tome includes a helper command to set up your Algolia index: ```bash npx @tomehq/cli algolia:init ``` This creates a crawler configuration optimized for Tome's HTML structure. ### When to use Algolia | Feature | Pagefind | Algolia | |---------|----------|---------| | Setup | Zero config | Requires account | | Cost | Free | Free tier available | | Index size | Unlimited | 10K records free | | Typo tolerance | Basic | Advanced | | Analytics | No | Yes | | Real-time indexing | At build time | Crawler-based | For most documentation sites, Pagefind is sufficient. Consider Algolia if you need search analytics, advanced typo tolerance, or real-time indexing. --- ## Multi-Version Docs Tome supports maintaining multiple versions of your documentation side by side. This is useful for libraries and APIs that need to document breaking changes across major versions. ## Directory structure Organize your pages by version using subdirectories: ```text pages/ ├── current/ # Latest version │ ├── index.md │ ├── quickstart.md │ └── api.md ├── v1.0/ # Previous version │ ├── index.md │ ├── quickstart.md │ └── api.md └── v0.9/ # Older version ├── index.md └── api.md ``` ## Configuration Add the `versioning` section to your config: ```javascript export default { name: "My Docs", versioning: { current: "v2.0", versions: ["v2.0", "v1.0", "v0.9"], }, }; ``` | Field | Type | Description | |-------|------|-------------| | `current` | string | The label for the current (latest) version | | `versions` | string[] | All available versions, newest first | ## URL mapping | Directory | URL | |-----------|-----| | `pages/current/index.md` | `/` | | `pages/current/api.md` | `/api` | | `pages/v1.0/index.md` | `/v1.0/` | | `pages/v1.0/api.md` | `/v1.0/api` | The `current` directory always serves at the root — no version prefix. Older versions are prefixed with their version string. ## Version switcher When versioning is configured, Tome automatically adds a version dropdown to the header. Users can switch between versions, and the URL updates to reflect the selected version. If the current page exists in the target version, the user stays on that page. Otherwise, they're redirected to the version's index page. ## Best practices - Keep the `current` directory as your working copy - Copy `current` to a versioned directory (e.g., `v2.0`) when you cut a release - Remove pages from old versions that no longer apply rather than leaving stale content - Use the same page IDs across versions so the version switcher can navigate between them --- ## Introduction # Tome Welcome to Tome — beautiful documentation, zero vendor lock-in. --- Tome is an open-source documentation platform built for developers who believe great docs shouldn't cost $250/month. Write in Markdown or MDX, deploy anywhere, and own your content forever. ## What is Tome? Tome transforms your Markdown and MDX files into stunning, fully-searchable documentation sites. It handles navigation, theming, API references, code highlighting, and versioning — all from a simple folder of `.md` and `.mdx` files. > **OPEN SOURCE FOREVER** > > Tome is MIT licensed. No vendor lock-in, no surprise pricing changes, no feature gates. Your docs are yours. ## Why Tome? Documentation platforms have become unreasonably expensive. Most charge hundreds per month for features that should be table stakes. Want custom domains? Pay more. Need versioning? Upgrade your plan. Multiple projects? That'll be $250/month — per project. We built Tome because we thought that was absurd. Every developer and team deserves polished, professional documentation without paying a premium for basic functionality. Tome gives you everything you need for free when self-hosted, or at a fraction of the cost on our cloud. ```bash # Get started in 30 seconds npx @tomehq/cli init my-docs cd my-docs && npm install && npm run dev ``` ## Features - **Markdown and MDX** — Write docs in `.md` or use `.mdx` for interactive components like tabs, callouts, and code playgrounds. - **File-system routing** — Drop files into `pages/` and they become pages. No router config, no manifest files. - **Built-in components** — Callouts, tabs, cards, steps, accordions, and API playgrounds work out of the box. - **Two theme presets** — Ship with a warm amber aesthetic or an editorial brutalist look. Both support dark mode. - **Search included** — Pagefind indexes your site at build time. No external service required. - **API reference** — Point Tome at an OpenAPI spec and get a rendered reference with an interactive playground. - **Versioning** — Maintain multiple documentation versions side by side with a version switcher. - **i18n** — Serve docs in multiple languages with locale-based routing. - **Deploy anywhere** — Static output works on Vercel, Netlify, Cloudflare Pages, or Tome Cloud. ## Learn more - **[Quickstart](v2/quickstart)** — Get a docs site running in under a minute. - **[Installation](v2/installation)** — Detailed setup instructions and prerequisites. - **[Configuration](v2/configuration)** — Customize your site name, navigation, theme, and more. - **[CLI Reference](v2/cli)** — Every command and flag available in the `tome` CLI. --- ## Pages & Routing Every `.md` or `.mdx` file in the `pages/` directory becomes a page. The file path determines the URL. ## Basic routing | File path | URL | |-----------|-----| | `pages/index.md` | `/` | | `pages/quickstart.md` | `/quickstart` | | `pages/guides/deployment.md` | `/guides/deployment` | | `pages/api/endpoints.md` | `/api/endpoints` | | `pages/api/index.md` | `/api` | **Rules:** - `index.md` serves at the directory's root path - File extensions are stripped from the URL - Directory nesting maps directly to URL segments - Both `.md` and `.mdx` files are supported ## Page IDs Each page has an ID derived from its path relative to `pages/`: | File | Page ID | |------|---------| | `pages/index.md` | `index` | | `pages/quickstart.md` | `quickstart` | | `pages/guides/deployment.md` | `guides/deployment` | Page IDs are used in `navigation` config to control sidebar order. ## Navigation vs. routing All pages in `pages/` are routable regardless of whether they appear in `navigation`. Navigation only controls the sidebar. Pages can be hidden from the sidebar using `hidden: true` in frontmatter while remaining accessible at their URL. ## Frontmatter Every page can include YAML frontmatter at the top of the file: ```markdown --- title: My Page description: A brief description for SEO and navigation. icon: book sidebarTitle: Short Title hidden: false tags: [guide, setup] --- # My Page Content starts here. ``` | Field | Type | Description | |-------|------|-------------| | `title` | string | Page title (falls back to first `#` heading) | | `description` | string | Description for metadata and navigation | | `icon` | string | Icon identifier shown in the sidebar | | `sidebarTitle` | string | Override title shown in the sidebar | | `hidden` | boolean | Hide page from sidebar (still accessible via URL) | | `tags` | string[] | Tags for categorization and search | ## i18n routing When multiple locales are configured, organize pages by locale subdirectory: ```text pages/ ├── en/ # Default locale │ ├── index.md │ └── quickstart.md ├── es/ # Spanish │ ├── index.md │ └── quickstart.md ``` | File | URL | |------|-----| | `pages/en/index.md` | `/` (default — no prefix) | | `pages/es/index.md` | `/es/` | | `pages/es/quickstart.md` | `/es/quickstart` | The default locale serves at the root without a prefix. When `fallback: true` and a page doesn't exist in a non-default locale, the default version is used. ## Versioned routing When versioning is configured: ```text pages/ ├── current/ # Latest version │ ├── index.md │ └── api.md ├── v1.0/ │ ├── index.md │ └── api.md ``` | File | URL | |------|-----| | `pages/current/index.md` | `/` | | `pages/v1.0/index.md` | `/v1.0/` | | `pages/v1.0/api.md` | `/v1.0/api` | The `current` directory serves at the root. Older versions are prefixed with their version string. ## File discovery Tome discovers pages by scanning `pages/` for `**/*.{md,mdx}` files. Discovery runs at startup and again whenever files are added, removed, or renamed during development. Changes to existing files trigger a hot reload. --- ## Quickstart Get a working documentation site in three commands. ## Create a new project ```bash npx @tomehq/cli init my-docs ``` This scaffolds a complete documentation project with starter pages, configuration, and build scripts. ## Install and run ```bash cd my-docs npm install npm run dev ``` Open `http://localhost:3000`. You should see your documentation site with a sidebar, search, and starter content. ## Edit your first page Open `pages/index.md` in your editor. Change the title and save — the browser reloads automatically. ```markdown --- title: My Project description: Documentation for my project. --- # My Project Welcome to the docs. ``` Every `.md` or `.mdx` file in `pages/` becomes a page on your site. Subdirectories create nested routes: | File | URL | |------|-----| | `pages/index.md` | `/` | | `pages/quickstart.md` | `/quickstart` | | `pages/guides/setup.md` | `/guides/setup` | ## Add navigation Open `tome.config.js` and define your sidebar: ```javascript export default { name: "My Project", navigation: [ { group: "Getting Started", pages: ["index", "quickstart"], }, { group: "Guides", pages: ["guides/setup"], }, ], }; ``` ## Build for production ```bash npm run build ``` This outputs a static site to `out/` ready to deploy to any hosting provider — Vercel, Netlify, Cloudflare Pages, or Tome Cloud. ## Next steps - **[Installation](v2/installation)** for detailed setup and prerequisites - **[Configuration](v2/configuration)** to customize your site - **[Components](v2/components)** to use tabs, callouts, and other interactive elements --- ## CLI Reference The `tome` CLI is the primary interface for creating, developing, building, and deploying documentation sites. ## Installation ```bash npm install -D @tomehq/cli # or globally npm install -g @tomehq/cli ``` ## Commands ### `tome init [name]` Create a new Tome documentation project. ```bash tome init my-docs ``` | Argument | Default | Description | |----------|---------|-------------| | `name` | `my-docs` | Project directory name | | Flag | Default | Description | |------|---------|-------------| | `-t, --template ` | `default` | Starter template | Creates `tome.config.js`, `package.json`, `index.html`, `.tome/entry.tsx`, starter pages in `pages/`, `public/` and `styles/` directories, and a `.github/workflows/deploy.yml` GitHub Actions workflow for automatic deploys. --- ### `tome dev` Start the development server with hot reloading. ```bash tome dev tome dev -p 4000 tome dev --host ``` | Flag | Default | Description | |------|---------|-------------| | `-p, --port ` | `3000` | Server port | | `--host` | `false` | Expose to network (bind `0.0.0.0`) | Watches `pages/` for file changes and reloads automatically. Config changes trigger a full reload. --- ### `tome build` Build the documentation site for production. ```bash tome build tome build -o dist ``` | Flag | Default | Description | |------|---------|-------------| | `-o, --outDir ` | `out` | Output directory | Produces a static site and runs Pagefind to build the search index. --- ### `tome deploy` Deploy the site to Tome Cloud. Requires `tome login` first. ```bash tome deploy tome deploy --preview --branch feature/auth ``` | Flag | Default | Description | |------|---------|-------------| | `--preview` | `false` | Deploy as a preview (branch-based URL) | | `--branch ` | auto-detect | Git branch name for preview | | `--expires ` | `7` | Preview expiry in days | Builds, collects output files, and uploads using hash-based deduplication. With `--preview`, deploys to a branch-specific URL (e.g., `feature-auth.preview.my-docs.tome.center`) and injects a preview banner. --- ### `tome lint` Lint documentation content for common issues. ```bash tome lint tome lint --strict tome lint --banned-words "simply,obviously" ``` | Flag | Default | Description | |------|---------|-------------| | `--max-paragraph ` | `300` | Max words per paragraph | | `--no-heading-increment` | — | Disable heading increment check | | `--no-image-alt` | — | Disable missing alt text check | | `--no-single-h1` | — | Disable single H1 check | | `--no-empty-links` | — | Disable empty link check | | `--banned-words ` | — | Comma-separated list of banned words | | `--strict` | `false` | Treat warnings as errors | Checks all pages for heading hierarchy issues, missing image alt text, overly long paragraphs, duplicate H1 tags, empty links, and banned words. --- ### `tome login` Authenticate with Tome Cloud. ```bash tome login ``` Prompts for email and sends a magic link. Stores the API token locally. --- ### `tome domains:add ` Add a custom domain. Returns DNS records to configure. ```bash tome domains:add docs.example.com ``` ### `tome domains:verify ` Verify DNS configuration for a custom domain. ```bash tome domains:verify docs.example.com ``` ### `tome domains:list` List all custom domains for the current project. ### `tome domains:remove ` Remove a custom domain. --- ### `tome migrate gitbook ` Migrate a GitBook documentation project to Tome. ```bash tome migrate gitbook ./my-gitbook-docs tome migrate gitbook ./my-gitbook-docs --out ./converted tome migrate gitbook ./my-gitbook-docs --dry-run ``` | Flag | Default | Description | |------|---------|-------------| | `--out ` | `.` (current directory) | Output directory for converted project | | `--dry-run` | `false` | Preview changes without writing files | Reads `SUMMARY.md` for navigation structure and `.gitbook.yaml` for configuration. Converts GitBook-specific syntax to Tome components: - `{% hint %}` blocks → `` components - `{% tabs %}` blocks → `` / `` components - `{% code title="..." %}` → fenced code blocks with titles - `{% embed %}` → plain links - Redirects from `.gitbook.yaml` → Tome `redirects` config Files are copied to `pages/` preserving directory structure. Files containing converted JSX components are renamed from `.md` to `.mdx`. Static assets are copied to `public/`. --- ### `tome migrate mintlify ` Migrate a Mintlify documentation project to Tome. ```bash tome migrate mintlify ./my-mintlify-docs tome migrate mintlify ./my-mintlify-docs --out ./converted tome migrate mintlify ./my-mintlify-docs --dry-run ``` | Flag | Default | Description | |------|---------|-------------| | `--out ` | `.` (current directory) | Output directory for converted project | | `--dry-run` | `false` | Preview changes without writing files | Reads `mint.json` for configuration and navigation. Converts Mintlify-specific syntax to Tome components: - ``, ``, ``, ``, `` → `` components - `` → `` wrapper - `` → stripped (individual `` components kept) - `` → stripped (content preserved) - `` → inlined file content Maps `mint.json` settings to `tome.config.js`: colors, logo, favicon, navigation, redirects, topbar links, and OpenAPI configuration. --- ### `tome algolia:init` Initialize an Algolia DocSearch index. Prompts for credentials and creates a crawler configuration. --- ### `tome mcp` Start the MCP (Model Context Protocol) stdio server for AI tool integration. Exposes documentation content as MCP resources and tools. --- ## Components Tome includes built-in components available in any `.mdx` file without imports. ## Callout Draw attention to important information. ```mdx This is an informational callout. ``` | Prop | Type | Default | Description | |------|------|---------|-------------| | `type` | `"info" \| "tip" \| "warning" \| "danger"` | `"info"` | Visual style and icon | | `title` | `string` | — | Optional heading text | Types: `info` (blue), `tip` (green), `warning` (amber), `danger` (red). --- ## Tabs Present content variants — useful for multiple languages or platform-specific instructions. ```mdx
npm install @tomehq/cli
yarn add @tomehq/cli
pnpm add @tomehq/cli
``` | Prop | Type | Description | |------|------|-------------| | `items` | `string[]` | Tab labels (required) | Each child `
` maps to a tab in order. --- ## Card A linked or static content card. ```mdx Set up your first project in minutes. ``` | Prop | Type | Description | |------|------|-------------| | `title` | `string` | Card heading (required) | | `icon` | `string` | Emoji or icon name | | `href` | `string` | Link URL (makes the card clickable) | --- ## CardGroup Arranges cards in a responsive grid. ```mdx Step 1 Step 2 Step 3 ``` | Prop | Type | Default | Description | |------|------|---------|-------------| | `cols` | `number` | `2` | Number of columns | --- ## Steps Sequential instructions with numbered indicators. ```mdx
**Create a project** Run `tome init my-docs`.
**Install dependencies** Run `npm install`.
``` Each child `
` becomes a numbered step. Use bold text on the first line for the step title. --- ## Accordion Collapsible content sections for FAQs or optional details. ```mdx Run `tome build` then upload the `out/` directory. ``` | Prop | Type | Description | |------|------|-------------| | `title` | `string` | Clickable header text (required) | --- ## API components When an OpenAPI spec is configured, additional components are auto-generated: - **ApiEndpoint** — Renders an API endpoint with parameters and responses - **ApiPlayground** — Interactive request builder - **ApiResponse** — Formatted response viewer See the [API reference guide](/docs/guides/api-reference) for setup. --- ## `.md` vs `.mdx` Components are only available in `.mdx` files. Rename `.md` to `.mdx` to use them — no other changes needed. --- ## Config Reference The config file (`tome.config.js`, `.mjs`, or `.ts`) is validated at startup. Invalid values produce clear error messages with the field path and expected type. ## Top-level fields | Field | Type | Default | Description | |-------|------|---------|-------------| | `name` | `string` | `"My Docs"` | Site name shown in the header and browser tab | | `logo` | `string` | — | Path to logo image, relative to `public/` | | `favicon` | `string` | — | Path to favicon, relative to `public/` | | `baseUrl` | `string` | — | Full URL where the site is hosted (for analytics, canonical links) | | `basePath` | `string` | — | URL subpath prefix (e.g., `"/docs/"`) — sets Vite's `base` option | | `theme` | `ThemeConfig` | `{}` | Theme configuration (see below) | | `navigation` | `NavigationGroup[]` | `[]` | Sidebar navigation structure | | `topNav` | `TopNavItem[]` | — | Header navigation links | | `search` | `SearchConfig` | `{ provider: "local" }` | Search provider configuration | | `api` | `ApiConfig` | — | OpenAPI spec and playground settings | | `ai` | `AiConfig` | — | AI chat widget configuration | | `mcp` | `McpConfig` | `{ enabled: true }` | MCP server manifest generation | | `i18n` | `I18nConfig` | — | Internationalization settings | | `versioning` | `VersioningConfig` | — | Multi-version documentation | | `analytics` | `AnalyticsConfig` | — | Analytics provider settings | | `webhooks` | `WebhookConfig[]` | — | Webhook notifications for deploy events | ## ThemeConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `preset` | `"amber" \| "editorial"` | `"amber"` | Base theme preset | | `accent` | `string` | — | Custom accent color (hex, e.g., `"#ff6b4a"`) | | `mode` | `"light" \| "dark" \| "auto"` | `"auto"` | Color mode | | `fonts.heading` | `string` | — | Heading font family | | `fonts.body` | `string` | — | Body font family | | `fonts.code` | `string` | — | Code font family | | `radius` | `string` | — | Border radius (e.g., `"8px"`) | ## NavigationGroup ```typescript { group: string; pages: Array; } ``` Page IDs are filenames without extensions, relative to `pages/`. Nested groups are supported. ## SearchConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `provider` | `"local" \| "algolia"` | `"local"` | Search provider | | `appId` | `string` | — | Algolia application ID | | `apiKey` | `string` | — | Algolia search-only API key | | `indexName` | `string` | — | Algolia index name | ## ApiConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `spec` | `string` | — | Path to OpenAPI spec file (required) | | `playground` | `boolean` | `true` | Enable interactive API playground | | `baseUrl` | `string` | — | Base URL for playground requests | | `auth.type` | `"bearer" \| "apiKey" \| "oauth2"` | — | Authentication type | | `auth.header` | `string` | — | Auth header name | ## AiConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `enabled` | `boolean` | `false` | Enable AI chat widget | | `provider` | `"openai" \| "anthropic" \| "custom"` | `"anthropic"` | AI provider | | `model` | `string` | — | Model identifier | | `apiKeyEnv` | `string` | `"TOME_AI_KEY"` | Environment variable for API key | ## McpConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `enabled` | `boolean` | `true` | Generate `mcp.json` manifest at build time | | `server` | `boolean` | `false` | Enable MCP stdio server | | `includeContent` | `boolean` | `true` | Include page content in the manifest | | `excludePages` | `string[]` | `[]` | Page IDs to exclude | ## I18nConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `defaultLocale` | `string` | `"en"` | Default locale code | | `locales` | `string[]` | `["en"]` | All available locale codes | | `localeNames` | `Record` | — | Display names (e.g., `{ en: "English" }`) | | `fallback` | `boolean` | `true` | Fall back to default locale for missing translations | ## VersioningConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `current` | `string` | — | Label for the current version (required) | | `versions` | `string[]` | — | All version labels, newest first (required) | ## AnalyticsConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `provider` | `"plausible" \| "posthog" \| "custom"` | — | Analytics provider | | `key` | `string` | — | Site ID or API key | ## WebhookConfig Send notifications to Slack, Discord, or generic HTTP endpoints when deploy events occur. ```js webhooks: [ { url: "https://hooks.slack.com/services/T.../B.../...", channel: "slack", events: ["deploy.succeeded", "deploy.failed"], }, { url: "https://discord.com/api/webhooks/...", channel: "discord", }, { url: "https://example.com/webhook", channel: "http", secret: "my-hmac-secret", }, ] ``` | Field | Type | Default | Description | |-------|------|---------|-------------| | `url` | `string` | — | Webhook endpoint URL (required) | | `channel` | `"slack" \| "discord" \| "http"` | — | Notification format (required) | | `events` | `WebhookEventType[]` | all | Filter which events trigger the webhook | | `secret` | `string` | — | HMAC-SHA256 secret for HTTP signature (`X-Tome-Signature` header) | **Event types:** `deploy.succeeded`, `deploy.failed`, `preview.deployed`, `domain.verified` --- ## Frontmatter Every Tome page can include YAML frontmatter at the top of the file. Frontmatter controls metadata like the page title, description, sidebar behavior, and search tags. ## Syntax ```markdown --- title: My Page Title description: A brief summary of the page content. --- # My Page Title Page content starts here. ``` ## Fields | Field | Type | Default | Description | |-------|------|---------|-------------| | `title` | `string` | First `#` heading | Page title for sidebar, browser tab, and search | | `description` | `string` | — | Short summary for SEO and search results | | `icon` | `string` | — | Icon identifier shown in the sidebar | | `sidebarTitle` | `string` | `title` | Override the title shown in sidebar navigation | | `hidden` | `boolean` | `false` | Hide this page from sidebar navigation | | `tags` | `string[]` | — | Tags for search indexing and categorization | | `ogImage` | `string` | auto-generated | Custom OpenGraph image URL or path | ## Title resolution If `title` is not set in frontmatter, Tome uses the first `# Heading` in the page content. If neither exists, the page is titled "Untitled". The `sidebarTitle` field lets you show a shorter name in the sidebar: ```markdown --- title: Configuring Authentication with OAuth 2.0 sidebarTitle: Authentication --- ``` ## Hidden pages Pages with `hidden: true` are excluded from sidebar navigation but remain accessible at their URL. Useful for: - Landing pages that shouldn't appear in the sidebar - Draft pages shared via direct link - Internal reference pages linked from other content ## Tags Tags improve search results by adding keywords that may not appear in the page content: ```markdown --- title: Deployment tags: [hosting, vercel, netlify, cloudflare, static] --- ``` Tags are indexed by both Pagefind and Algolia (when configured) and appear in MCP manifest output. ## Icons The `icon` field accepts identifiers displayed in the sidebar. Common values: `rocket`, `gear`, `code`, `terminal`, `puzzle`, `search`, `layers`, `cloud`, `file-text`, `palette`. ## OpenGraph images By default, Tome auto-generates OG images for every page at build time. Use `ogImage` to override with a custom image: ```markdown --- title: Getting Started ogImage: /images/custom-og.png --- ``` The value can be a relative path (resolved from your site root) or a full URL. Pages with a custom `ogImage` skip auto-generation. --- ## Theme Presets Tome ships with two theme presets. Each defines color tokens for dark and light modes plus font families. ## Amber The default preset. Warm, approachable tones with a golden accent. ### Dark mode | Variable | Value | Description | |----------|-------|-------------| | `--bg` | `#1a1a1a` | Page background | | `--sf` | `#242424` | Surface (cards, sidebar) | | `--sfH` | `#2e2e2e` | Surface hover | | `--bd` | `#333333` | Border | | `--tx` | `#e5e5e5` | Primary text | | `--tx2` | `#999999` | Secondary text | | `--txM` | `#666666` | Muted text | | `--ac` | `#e8a845` | Accent | | `--acD` | `#d4922e` | Accent dark | | `--acT` | `#2a2318` | Accent tint | ### Light mode | Variable | Value | Description | |----------|-------|-------------| | `--bg` | `#fafaf9` | Page background | | `--sf` | `#f5f5f4` | Surface | | `--sfH` | `#e7e5e4` | Surface hover | | `--bd` | `#d6d3d1` | Border | | `--tx` | `#1c1917` | Primary text | | `--tx2` | `#57534e` | Secondary text | | `--txM` | `#a8a29e` | Muted text | | `--ac` | `#d97706` | Accent | | `--acD` | `#b45309` | Accent dark | | `--acT` | `#fef3c7` | Accent tint | ### Fonts | Variable | Value | |----------|-------| | `--font-heading` | `'Instrument Serif', serif` | | `--font-body` | `'DM Sans', sans-serif` | | `--font-code` | `'JetBrains Mono', monospace` | --- ## Editorial A refined, high-contrast preset inspired by Swiss poster design. ### Dark mode | Variable | Value | Description | |----------|-------|-------------| | `--bg` | `#0f0f0f` | Page background | | `--sf` | `#1a1a1a` | Surface | | `--sfH` | `#252525` | Surface hover | | `--bd` | `#2a2a2a` | Border | | `--tx` | `#f0f0f0` | Primary text | | `--tx2` | `#888888` | Secondary text | | `--txM` | `#555555` | Muted text | | `--ac` | `#ff6b4a` | Accent (coral) | | `--acD` | `#e85a3a` | Accent dark | | `--acT` | `#1f1512` | Accent tint | ### Light mode | Variable | Value | Description | |----------|-------|-------------| | `--bg` | `#faf9f7` | Page background | | `--sf` | `#f2f0ed` | Surface | | `--sfH` | `#e8e5e1` | Surface hover | | `--bd` | `#d8d4cf` | Border | | `--tx` | `#1a1a1a` | Primary text | | `--tx2` | `#6b6560` | Secondary text | | `--txM` | `#a09890` | Muted text | | `--ac` | `#e85a3a` | Accent (coral) | | `--acD` | `#d04a2a` | Accent dark | | `--acT` | `#fef0ec` | Accent tint | ### Fonts | Variable | Value | |----------|-------| | `--font-heading` | `'Cormorant Garamond', serif` | | `--font-body` | `'Bricolage Grotesque', sans-serif` | | `--font-code` | `'Fira Code', monospace` | --- ## Additional variables Both presets also define: | Variable | Description | |----------|-------------| | `--cdBg` | Code block background | | `--cdTx` | Code block text | | `--sbBg` | Sidebar background | | `--hdBg` | Header background | Override any variable in custom CSS to fine-tune the theme. --- ## Theming Tome ships with two theme presets and extensive customization options. Every visual aspect — colors, fonts, spacing — can be adjusted through configuration or CSS variables. ## Presets ### Amber (default) A warm, golden aesthetic with serif headings. Clean and approachable. ```javascript theme: { preset: "amber", } ``` ### Editorial Swiss poster-inspired design with a brutalist edge. Coral accent color, grotesque typography. ```javascript theme: { preset: "editorial", } ``` ## Custom accent color Override the default accent color with any hex value: ```javascript theme: { preset: "amber", accent: "#2563eb", // Blue accent } ``` Tome derives tint and dim variants automatically from your accent color. ## Dark mode Control the color scheme: ```javascript theme: { mode: "auto", // Follows system preference // mode: "light", // Always light // mode: "dark", // Always dark } ``` When set to `auto`, a theme toggle appears in the header. ## Custom fonts Override any of the three font families: ```javascript theme: { fonts: { heading: "Playfair Display", body: "Inter", code: "JetBrains Mono", }, } ``` Load your fonts via Google Fonts in `index.html` or self-host them. ## Border radius Control the roundness of UI elements: ```javascript theme: { radius: 8, // pixels, default varies by preset } ``` ## CSS variables For fine-grained control, override CSS variables directly. Add a ` ``` ### Variable reference | Variable | Purpose | |----------|---------| | `--ac` | Accent color (links, highlights) | | `--acD` | Accent dim (callout backgrounds) | | `--acT` | Accent dark (hover states) | | `--bg` | Page background | | `--sf` / `--sfH` | Surface and surface hover | | `--tx` / `--tx2` / `--txM` | Text primary, secondary, muted | | `--bd` | Borders | | `--cdBg` / `--cdTx` | Code block background and text | | `--sbBg` | Sidebar background | | `--hdBg` | Header background | | `--font-heading` | Heading font family | | `--font-body` | Body font family | | `--font-code` | Code font family | --- ## Deploy to Tome Cloud Tome Cloud hosts your documentation site on a global CDN with automatic SSL, custom domains, and analytics. This tutorial covers the full deployment flow. ## Prerequisites - A Tome documentation project (see [Create your first site](/docs/tutorials/first-site)) - Node.js 22.22.2+ ## 1. Authenticate Log in to your Tome Cloud account: ```bash npx @tomehq/cli login ``` Enter your email address. You'll receive a magic link — click it to authenticate. Your API token is stored locally for future deployments. ## 2. Deploy From your project directory: ```bash npx @tomehq/cli deploy ``` Tome builds your site, collects the output files, and uploads them using hash-based deduplication. Only changed files are transferred, making subsequent deploys fast. After deployment, your site is live at: ``` https://your-project.tome.center ``` ## 3. Add a custom domain Register a custom domain for your docs: ```bash npx @tomehq/cli domains:add docs.example.com ``` Tome returns DNS records you need to configure with your domain registrar: ```text Type: CNAME Name: docs Value: your-project.tome.center ``` After configuring DNS, verify the domain: ```bash npx @tomehq/cli domains:verify docs.example.com ``` SSL is provisioned automatically once DNS propagates. ## 4. Manage domains List all domains attached to your project: ```bash npx @tomehq/cli domains:list ``` Remove a domain: ```bash npx @tomehq/cli domains:remove docs.example.com ``` ## 5. Automatic deploys with CI/CD Projects created with `tome init` include a GitHub Actions workflow (`.github/workflows/deploy.yml`) that deploys automatically: - **Push to main** → production deploy - **Pull requests** → preview deploy with a unique URL ### Setup 1. Generate a deploy token by running `npx @tomehq/cli login`, then copy the token from `~/.tome/config` 2. In your GitHub repository, go to **Settings → Secrets and variables → Actions** 3. Create a secret named `TOME_TOKEN` with your deploy token That's it — every push to `main` triggers a production deploy, and every PR gets a preview URL. ### GitLab CI Create `.gitlab-ci.yml`: ```yaml deploy: image: node:20 script: - npm ci - npm run build - npx @tomehq/cli deploy only: - main variables: TOME_TOKEN: $TOME_TOKEN ``` Add `TOME_TOKEN` in **Settings → CI/CD → Variables**. ### Bitbucket Pipelines Add to `bitbucket-pipelines.yml`: ```yaml pipelines: branches: main: - step: name: Deploy docs image: node:20 script: - npm ci - npm run build - npx @tomehq/cli deploy ``` Add `TOME_TOKEN` in **Repository settings → Pipelines → Variables**. ## Deployment details Each deploy creates an immutable snapshot. You can view deployment history and analytics in the Tome Dashboard. | Detail | Value | |--------|-------| | CDN | Cloudflare R2 (global edge) | | SSL | Automatic via Cloudflare | | Deduplication | Content-hash based | | Rollback | Deploy any previous snapshot | ## Next steps - **[Configuration guide](/docs/guides/configuration)** to customize your site before deploying - **[CLI reference](/docs/reference/cli)** for the full list of deployment commands --- ## Create Your First Site This tutorial walks you through creating a Tome documentation site from scratch. By the end, you'll have a working docs site running locally with custom pages and navigation. ## Prerequisites You need **Node.js 22.22.2+** and a package manager (`npm`, `yarn`, or `pnpm`). ## 1. Scaffold the project Run the init command to create a new project: ```bash npx @tomehq/cli init my-docs ``` This creates a directory with the following structure: ```text my-docs/ ├── tome.config.js # Site configuration ├── package.json # Dependencies and scripts ├── index.html # Vite entry point ├── .tome/entry.tsx # Theme bootstrap (don't edit) ├── pages/ # Your documentation pages │ ├── index.md │ ├── quickstart.md │ └── components.mdx ├── public/ # Static assets └── styles/ # Custom CSS (optional) ``` ## 2. Install dependencies ```bash cd my-docs npm install ``` ## 3. Start the dev server ```bash npm run dev ``` Open `http://localhost:3000`. You should see the starter documentation site. Every time you save a file, the page reloads automatically. ## 4. Add a new page Create `pages/guides/deployment.md`: ```markdown --- title: Deployment Guide description: How to deploy your Tome site to production. --- # Deployment Guide Run `npm run build` to produce static files in the `out/` directory. Upload this directory to any static hosting provider. ``` The page is immediately available at `/guides/deployment` in the dev server. ## 5. Configure navigation Open `tome.config.js` and add your new page to the sidebar: ```javascript export default { name: "my-docs", theme: { preset: "amber", mode: "auto", }, navigation: [ { group: "Getting Started", pages: ["index", "quickstart"], }, { group: "Guides", pages: ["guides/deployment"], }, { group: "Reference", pages: ["components"], }, ], }; ``` The sidebar updates to reflect the new structure. ## 6. Customize the theme Change the preset to `editorial` and set a custom accent color: ```javascript theme: { preset: "editorial", accent: "#ff6b4a", mode: "auto", }, ``` The entire site switches to the editorial aesthetic with your accent color. ## 7. Build for production ```bash npm run build ``` This outputs a static site to `out/` with a pre-built search index. The output is ready to deploy to any hosting provider. ## Next steps - **[Deploy to Tome Cloud](/docs/tutorials/deploy-to-cloud)** to publish with a single command - **[Configuration guide](/docs/guides/configuration)** for all available options - **[Components reference](/docs/reference/components)** for the full list of MDX components --- ## Authentication The API playground supports several authentication methods. Users can enter credentials that are included in test requests. ## Configuration Add auth settings to your API config: ```javascript export default { api: { spec: "./openapi.yaml", playground: { enabled: true, auth: { type: "bearer", // "bearer", "apiKey", or "basic" }, }, }, }; ``` ## Bearer token The most common pattern for modern APIs. A token input appears in the playground header: ```javascript auth: { type: "bearer", } ``` Requests include the header: ``` Authorization: Bearer ``` ## API key For APIs that use key-based authentication: ```javascript auth: { type: "apiKey", name: "X-API-Key", // Header name in: "header", // "header" or "query" } ``` When `in` is `"query"`, the key is appended as a URL parameter instead. ## Basic auth For username/password authentication: ```javascript auth: { type: "basic", } ``` The playground shows username and password fields. The value is sent as a Base64-encoded `Authorization: Basic` header. ## OpenAPI security schemes If your OpenAPI spec defines security schemes, Tome reads them automatically: ```yaml components: securitySchemes: BearerAuth: type: http scheme: bearer ApiKeyAuth: type: apiKey in: header name: X-API-Key ``` When security schemes are defined in the spec, Tome uses them instead of the manual config. You don't need to configure `auth` separately. ## Security notes - Credentials entered in the playground are stored only in browser memory for the current session - Credentials are never sent to Tome's servers — requests go directly from the browser to your API - CORS must be enabled on your API server for playground requests to work - For production APIs, consider providing a sandbox environment URL through the `baseUrl` config --- ## Endpoints Tome renders each API operation from your OpenAPI spec as a structured endpoint section with method badges, parameter tables, request/response schemas, and an optional interactive playground. ## Endpoint layout Each endpoint displays: 1. **Method badge** — Color-coded (GET, POST, PUT, DELETE, PATCH) 2. **Path** — The endpoint URL with path parameters highlighted 3. **Description** — From the operation's `summary` and `description` fields 4. **Parameters** — Path, query, and header parameters in a table 5. **Request body** — Schema rendered with types and descriptions 6. **Responses** — Status codes with response schemas ## Tag grouping Endpoints are organized by their OpenAPI tags. Each tag becomes a section heading: ```yaml paths: /users: get: tags: [Users] summary: List all users /users/{id}: get: tags: [Users] summary: Get user by ID /projects: get: tags: [Projects] summary: List projects ``` This generates two groups: "Users" with two endpoints and "Projects" with one. ## Parameter rendering Parameters are rendered in a table with type information: | Name | Type | In | Required | Description | |------|------|----|----------|-------------| | `id` | string | path | yes | The user ID | | `limit` | integer | query | no | Max results (default: 20) | | `offset` | integer | query | no | Pagination offset | ## Schema display Request and response schemas are rendered recursively. Nested objects show their properties with types: ``` UserResponse { id: string — Unique identifier name: string — Display name email: string — Email address created_at: string — ISO 8601 timestamp settings: { theme: string — "light" or "dark" locale: string — Language code } } ``` Arrays, enums, and `oneOf`/`anyOf` unions are all supported. ## Interactive playground When `playground.enabled` is true in your config, each endpoint gets a "Try it" section where users can: - Fill in path and query parameters - Edit the request body as JSON - Set authentication headers - Send the request and view the response ```javascript api: { spec: "./openapi.yaml", playground: { enabled: true, baseUrl: "https://api.example.com", // Override base URL }, }, ``` The playground uses `fetch` directly from the browser. CORS must be enabled on your API for cross-origin requests. --- ## Overview Tome generates a complete API reference from an OpenAPI 3.x specification. Point it at a spec file and get rendered endpoint documentation with an interactive playground — no manual writing required. ## Setup Add the `api` section to your `tome.config.js`: ```javascript export default { name: "My API Docs", api: { spec: "./openapi.yaml", // Path to your OpenAPI spec playground: { enabled: true, // Enable interactive playground }, }, }; ``` Tome parses the spec at build time and generates: - Endpoint listing organized by tags - Request/response schema documentation - Parameter tables with types and descriptions - An interactive playground for testing endpoints ## Supported formats | Format | Extension | |--------|-----------| | OpenAPI 3.0 | `.json`, `.yaml`, `.yml` | | OpenAPI 3.1 | `.json`, `.yaml`, `.yml` | Swagger 2.x specs are not directly supported. Convert them first using tools like `swagger2openapi`. ## What gets generated From a single spec file, Tome creates: - **Endpoint pages** — Each operation (GET, POST, PUT, DELETE) gets its own section with method, path, description, and parameters. - **Schema documentation** — Request bodies and response objects are rendered with type information. - **Tag grouping** — Operations are organized by their OpenAPI tags. - **Try it** — The playground lets users send real requests with custom parameters and see responses. ## Spec organization For the best results, make sure your OpenAPI spec includes: - Descriptive `summary` and `description` fields on each operation - Tags to group related endpoints - Schema definitions with `description` fields - Example values for parameters and request bodies ## Next steps - **[Endpoints](v1/api-endpoints)** for details on how endpoints are rendered - **[Authentication](v1/api-auth)** for configuring auth in the playground --- ## CLI Reference The `tome` CLI is the primary interface for creating, developing, building, and deploying documentation sites. ## Installation ```bash npm install -D @tomehq/cli # or globally npm install -g @tomehq/cli ``` ## Commands ### `tome init [name]` Create a new Tome documentation project. ```bash tome init my-docs ``` | Argument | Default | Description | |----------|---------|-------------| | `name` | `my-docs` | Project directory name | | Flag | Default | Description | |------|---------|-------------| | `-t, --template ` | `default` | Starter template | Creates `tome.config.js`, `package.json`, `index.html`, `.tome/entry.tsx`, starter pages in `pages/`, and `public/` and `styles/` directories. --- ### `tome dev` Start the development server with hot reloading. ```bash tome dev tome dev -p 4000 tome dev --host ``` | Flag | Default | Description | |------|---------|-------------| | `-p, --port ` | `3000` | Server port | | `--host` | `false` | Expose to network (bind `0.0.0.0`) | Watches `pages/` for file changes and reloads automatically. Config changes trigger a full reload. --- ### `tome build` Build the documentation site for production. ```bash tome build tome build -o dist ``` | Flag | Default | Description | |------|---------|-------------| | `-o, --outDir ` | `out` | Output directory | Produces a static site and runs Pagefind to build the search index. --- ### `tome deploy` Deploy the site to Tome Cloud. Requires `tome login` first. ```bash tome deploy ``` Builds, collects output files, and uploads using hash-based deduplication. --- ### `tome login` Authenticate with Tome Cloud. ```bash tome login ``` Prompts for email and sends a magic link. Stores the API token locally. --- ### `tome domains:add ` Add a custom domain. Returns DNS records to configure. ```bash tome domains:add docs.example.com ``` ### `tome domains:verify ` Verify DNS configuration for a custom domain. ```bash tome domains:verify docs.example.com ``` ### `tome domains:list` List all custom domains for the current project. ### `tome domains:remove ` Remove a custom domain. --- ### `tome algolia:init` Initialize an Algolia DocSearch index. Prompts for credentials and creates a crawler configuration. --- ### `tome mcp` Start the MCP (Model Context Protocol) stdio server for AI tool integration. Exposes documentation content as MCP resources and tools. --- ## Architecture Tome is built on Vite and React. Understanding the architecture helps when debugging build issues or building advanced customizations. ## Overview A Tome site is a Vite application with a custom plugin that handles page discovery, routing, and content processing. The theme package provides the React UI shell. ```mermaid flowchart LR A["tome.config.js"] --> B["Vite Plugin"] B --> C["Virtual Modules"] C --> D["Theme Shell"] D --> E["Static Site"] ``` ## Vite plugin The core of Tome is `vite-plugin-tome` in `@tomehq/core`. It has three responsibilities: **1. Page discovery** — On startup, the plugin scans `pages/` for `.md` and `.mdx` files, extracts frontmatter, and builds a route table. It watches for file changes during development and triggers hot reloads. **2. Virtual modules** — The plugin exposes content through Vite's virtual module system: | Module | Contents | |--------|----------| | `virtual:tome/config` | The resolved config as JSON | | `virtual:tome/routes` | Route table with IDs, URLs, and frontmatter | | `virtual:tome/page/:id` | Processed page content | | `virtual:tome/api` | Parsed OpenAPI manifest | | `virtual:tome/analytics` | Analytics provider settings | **3. Build-time generation** — During builds, the plugin injects analytics scripts and generates the `mcp.json` manifest. ## Theme system The theme package (`@tomehq/theme`) provides the React shell: - **Shell component** — Header, sidebar, content area, footer - **Preset system** — Color tokens and CSS variables per preset - **Search integration** — Pagefind or Algolia, loaded dynamically - **AI chat** — Optional floating widget The entry point (`.tome/entry.tsx`) bootstraps the shell by importing `@tomehq/theme/entry`. ## Content pipeline ```mermaid flowchart TD A["pages/*.md"] --> B["gray-matter"] B --> C["Frontmatter"] B --> D["Markdown body"] D --> E["remark + rehype"] E --> F["Shiki highlighting"] F --> G["DOMPurify sanitize"] G --> H["HTML + headings"] I["pages/*.mdx"] --> J["Extract frontmatter"] J --> K["@mdx-js/rollup"] K --> L["React component"] ``` ### Markdown (`.md`) 1. Frontmatter extracted via `gray-matter` 2. Markdown processed through remark (GFM, math) and rehype (slugs, autolink headings) 3. Code blocks highlighted with Shiki (mermaid blocks converted to client-side placeholders) 4. HTML sanitized with DOMPurify, headings extracted for table of contents 5. HTML + headings + frontmatter served as virtual module ### MDX (`.mdx`) 1. Frontmatter and headings extracted from raw source 2. File passed to `@mdx-js/rollup` for JSX compilation 3. Virtual module re-exports the compiled React component + metadata ## Build output ```text out/ ├── index.html # SPA entry ├── assets/ │ ├── index-[hash].js # Application bundle │ └── index-[hash].css # Styles ├── _pagefind/ # Search index ├── mcp.json # MCP manifest ├── llms.txt # AI-readable page index ├── llms-full.txt # Full page content for LLMs └── 404.html # Error page ``` The output is a single-page application. Search is fully static. The `llms.txt` and `llms-full.txt` files are auto-generated at build time to make your documentation discoverable by AI tools and language models. ## Package structure | Package | Purpose | |---------|---------| | `@tomehq/cli` | CLI commands (init, dev, build, deploy, mcp, typedoc) | | `@tomehq/core` | Config, routing, Vite plugin, markdown processing, MCP server | | `@tomehq/theme` | Shell UI, presets, search, AI chat | | `@tomehq/components` | MDX components (Callout, Tabs, Card, etc.) | | `@tomehq/landing` | Marketing landing page | | `@tomehq/dashboard` | Tome Cloud dashboard | --- ## File-System Routing Every `.md` or `.mdx` file in the `pages/` directory becomes a page. The file path determines the URL. ## Basic routing | File path | URL | |-----------|-----| | `pages/index.md` | `/` | | `pages/quickstart.md` | `/quickstart` | | `pages/guides/deployment.md` | `/guides/deployment` | | `pages/api/endpoints.md` | `/api/endpoints` | | `pages/api/index.md` | `/api` | **Rules:** - `index.md` serves at the directory's root path - File extensions are stripped from the URL - Directory nesting maps directly to URL segments ## Page IDs Each page has an ID derived from its path relative to `pages/`: | File | Page ID | |------|---------| | `pages/index.md` | `index` | | `pages/quickstart.md` | `quickstart` | | `pages/guides/deployment.md` | `guides/deployment` | Page IDs are used in `navigation` config to control sidebar order. ## Navigation vs. routing All pages in `pages/` are routable regardless of whether they appear in `navigation`. Navigation only controls the sidebar. Pages can be hidden from the sidebar using `hidden: true` in frontmatter while remaining accessible at their URL. ## i18n routing When multiple locales are configured, organize pages by locale subdirectory: ```text pages/ ├── en/ # Default locale │ ├── index.md │ └── quickstart.md ├── es/ # Spanish │ ├── index.md │ └── quickstart.md ``` | File | URL | |------|-----| | `pages/en/index.md` | `/` (default — no prefix) | | `pages/es/index.md` | `/es/` | | `pages/es/quickstart.md` | `/es/quickstart` | The default locale serves at the root without a prefix. When `fallback: true` and a page doesn't exist in a non-default locale, the default version is used. ## Versioned routing When versioning is configured: ```text pages/ ├── current/ # Latest version │ ├── index.md │ └── api.md ├── v1.0/ │ ├── index.md │ └── api.md ``` | File | URL | |------|-----| | `pages/current/index.md` | `/` | | `pages/v1.0/index.md` | `/v1.0/` | | `pages/v1.0/api.md` | `/v1.0/api` | The `current` directory serves at the root. Older versions are prefixed. ## File discovery Tome discovers pages by scanning `pages/` for `**/*.{md,mdx}` files. Discovery runs at startup and again whenever files are added, removed, or renamed during development. --- ## Configuration All site configuration lives in `tome.config.js` (or `.mjs` / `.ts`) at your project root. Tome validates the config with Zod and provides clear error messages if anything is wrong. ## Minimal config ```javascript export default { name: "My Docs", }; ``` This is all you need. Tome uses sensible defaults for everything else. ## Site metadata ```javascript export default { name: "My Docs", logo: "/logo.svg", // Path relative to public/ favicon: "/favicon.ico", // Path relative to public/ baseUrl: "https://docs.example.com", }; ``` `baseUrl` is used for generating canonical URLs and analytics endpoints. It should be the full URL where your site is hosted. ## Navigation The `navigation` array defines your sidebar structure. Each group has a label and a list of page IDs (filenames without extensions): ```javascript navigation: [ { group: "Getting Started", pages: ["index", "quickstart"], }, { group: "API", pages: ["api/authentication", "api/endpoints", "api/errors"], }, ], ``` Pages not listed in navigation still exist at their URL — they're just hidden from the sidebar. ### Nested groups Groups can be nested for complex documentation structures: ```javascript navigation: [ { group: "SDK", pages: [ "sdk/overview", { group: "Languages", pages: ["sdk/javascript", "sdk/python", "sdk/go"], }, ], }, ], ``` ## Top navigation Add links to the header bar: ```javascript topNav: [ { label: "Blog", href: "https://blog.example.com" }, { label: "Changelog", href: "/changelog" }, ], ``` ## Theme ```javascript theme: { preset: "editorial", // "amber" or "editorial" accent: "#ff6b4a", // Custom accent color (hex) mode: "auto", // "light", "dark", or "auto" fonts: { heading: "Playfair Display", body: "Source Sans Pro", code: "Fira Code", }, }, ``` See **[Theming](v1/theming)** for full customization details. ## Base path If your docs are served under a subpath (e.g., `example.com/docs/`), set `basePath`: ```javascript basePath: "/docs/", ``` This configures Vite's `base` option so all asset paths resolve correctly. ## Search Pagefind is enabled by default with no configuration. To use Algolia DocSearch instead: ```javascript search: { provider: "algolia", appId: "YOUR_APP_ID", apiKey: "YOUR_SEARCH_KEY", indexName: "your-index", }, ``` ## Banner Display an announcement banner at the top of every page: ```javascript banner: { text: "v2.0 is now available!", link: "/changelog", // Optional — makes the text a link dismissible: true, // Default: true — shows a close button }, ``` When a user dismisses the banner, it stays hidden until you change the text. Updating the `text` value automatically shows the banner again for all users. ## Math rendering Enable LaTeX math support with KaTeX: ```javascript math: true, ``` Once enabled, you can use inline math with `$E = mc^2$` and display math with `$$` blocks in your Markdown pages. Requires `remark-math`, `rehype-katex`, and `katex` as peer dependencies: ```bash npm install remark-math rehype-katex katex ``` ## Mermaid diagrams Mermaid diagrams work out of the box with no configuration. Use a `mermaid` code fence in any `.md` or `.mdx` file: ````markdown ```mermaid flowchart LR A["Start"] --> B["Process"] B --> C["End"] ``` ```` Diagrams are rendered client-side and automatically adapt to your site's light/dark theme. ## AI discoverability Tome automatically generates two files at build time to make your docs accessible to AI tools: - **`llms.txt`** — A page index with titles, descriptions, and URLs - **`llms-full.txt`** — Full raw Markdown content of all non-hidden pages These are always generated — no configuration needed. Hidden pages (with `hidden: true` in frontmatter) are excluded. ## Full example ```javascript export default { name: "Acme Docs", logo: "/acme-logo.svg", favicon: "/favicon.ico", baseUrl: "https://docs.acme.com", theme: { preset: "editorial", accent: "#2563eb", mode: "auto", }, navigation: [ { group: "Overview", pages: ["index", "quickstart"] }, { group: "Guides", pages: ["guides/auth", "guides/deploy"] }, { group: "API", pages: ["api/rest", "api/webhooks"] }, ], topNav: [ { label: "Changelog", href: "/changelog" }, ], search: { provider: "local" }, banner: { text: "v2.0 is now available!", link: "/changelog", dismissible: true, }, math: true, }; ``` --- ## API Reference Setup Tome can generate a full API reference from an OpenAPI 3.x specification. The reference includes endpoint documentation, request/response schemas, and an interactive playground for testing endpoints. ## 1. Add your OpenAPI spec Place your OpenAPI spec file (JSON or YAML) in your project: ```text my-docs/ ├── openapi.yaml # Your API spec ├── tome.config.js └── pages/ ``` ## 2. Configure Tome Add the `api` section to your config: ```javascript export default { name: "My API Docs", api: { spec: "./openapi.yaml", playground: true, baseUrl: "https://api.example.com", auth: { type: "bearer", header: "Authorization", }, }, }; ``` ### Options | Field | Type | Default | Description | |-------|------|---------|-------------| | `spec` | string | — | Path to your OpenAPI spec file (required) | | `playground` | boolean | `true` | Enable the interactive API playground | | `baseUrl` | string | — | Base URL for playground requests | | `auth.type` | string | — | Auth type: `"bearer"`, `"apiKey"`, or `"oauth2"` | | `auth.header` | string | — | Header name for the auth token | ## 3. View the reference Start the dev server and navigate to `/api`. Tome parses the spec and renders: - **Endpoint groups** organized by OpenAPI tags - **Request parameters** with types, descriptions, and required markers - **Response schemas** with expandable nested objects - **Code examples** for `curl`, JavaScript, and Python ## 4. Interactive playground When `playground: true`, each endpoint includes a "Try It" panel where users can: - Set path parameters and query strings - Edit the request body with JSON validation - Add authentication headers - Send requests and view formatted responses The playground sends requests directly from the browser, so CORS must be configured on your API server. ## Supported spec formats Tome supports OpenAPI 3.0 and 3.1 specifications in JSON or YAML format. Swagger 2.x specs are not supported — convert them with tools like `swagger2openapi`. --- ## Configuration All site configuration lives in `tome.config.js` (or `.mjs` / `.ts`) at your project root. Tome validates the config with Zod and provides clear error messages if anything is wrong. ## Minimal config ```javascript export default { name: "My Docs", }; ``` This is all you need. Tome uses sensible defaults for everything else. ## Site metadata ```javascript export default { name: "My Docs", logo: "/logo.svg", // Path relative to public/ favicon: "/favicon.ico", // Path relative to public/ baseUrl: "https://docs.example.com", }; ``` `baseUrl` is used for generating canonical URLs and analytics endpoints. It should be the full URL where your site is hosted. ## Navigation The `navigation` array defines your sidebar structure. Each group has a label and a list of page IDs (filenames without extensions): ```javascript navigation: [ { group: "Getting Started", pages: ["index", "quickstart"], }, { group: "API", pages: ["api/authentication", "api/endpoints", "api/errors"], }, ], ``` Pages not listed in navigation still exist at their URL — they're just hidden from the sidebar. ### Nested groups Groups can be nested for complex documentation structures: ```javascript navigation: [ { group: "SDK", pages: [ "sdk/overview", { group: "Languages", pages: ["sdk/javascript", "sdk/python", "sdk/go"], }, ], }, ], ``` ## Top navigation Add links to the header bar: ```javascript topNav: [ { label: "Blog", href: "https://blog.example.com" }, { label: "GitHub", href: "https://github.com/example/docs" }, ], ``` ## Theme See the [Custom theme guide](/docs/guides/custom-theme) for full details. ```javascript theme: { preset: "editorial", // "amber" or "editorial" accent: "#ff6b4a", // Custom accent color (hex) mode: "auto", // "light", "dark", or "auto" fonts: { heading: "Playfair Display", body: "Source Sans Pro", code: "Fira Code", }, }, ``` ## Base path If your docs are served under a subpath (e.g., `example.com/docs/`), set `basePath`: ```javascript basePath: "/docs/", ``` This configures Vite's `base` option so all asset paths resolve correctly. ## Banner Show an announcement at the top of every page: ```javascript banner: { text: "We just launched v2.0!", link: "/changelog", // Optional — wraps text in a link dismissible: true, // Default true — shows close button }, ``` The banner uses your accent color as its background. When a user dismisses it, a hash of the text is saved to localStorage. Change the text to show the banner again for all users. ## Math / KaTeX Enable LaTeX math rendering with: ```javascript math: true, ``` Then install the peer dependencies: ```bash npm install remark-math rehype-katex katex ``` Use `$...$` for inline math and `$$...$$` for display blocks in your Markdown pages. ## Mermaid diagrams Mermaid diagrams require no configuration. Use a `mermaid` code fence in any page: ````markdown ```mermaid flowchart LR A["Input"] --> B["Process"] --> C["Output"] ``` ```` Mermaid is loaded from a CDN on demand — no install needed. Diagrams adapt to your light/dark theme automatically. ## AI discoverability (llms.txt) At build time, Tome automatically generates: - **`llms.txt`** — Page index with titles, descriptions, and URLs - **`llms-full.txt`** — Complete Markdown content of every non-hidden page No configuration needed. Hidden pages (frontmatter `hidden: true`) are excluded. These files help AI assistants and language models understand your documentation. ## Full example ```javascript export default { name: "Acme Docs", logo: "/acme-logo.svg", favicon: "/favicon.ico", baseUrl: "https://docs.acme.com", theme: { preset: "editorial", accent: "#2563eb", mode: "auto", }, navigation: [ { group: "Overview", pages: ["index", "quickstart"] }, { group: "Guides", pages: ["guides/auth", "guides/deploy"] }, { group: "API", pages: ["api/rest", "api/webhooks"] }, ], topNav: [ { label: "GitHub", href: "https://github.com/acme/docs" }, ], search: { provider: "local" }, }; ``` See the [Config reference](/docs/reference/config) for every available field. --- ## Custom Theme Tome ships with two theme presets and extensive customization options. Every visual aspect — colors, fonts, spacing — can be adjusted through configuration or CSS variables. ## Presets Choose between two built-in presets: ### Amber (default) A warm, approachable aesthetic with golden accent tones. Good for developer documentation and technical guides. ```javascript theme: { preset: "amber", } ``` ### Editorial A refined, high-contrast aesthetic inspired by Swiss poster design and literary magazines. Features serif headings and a more dramatic visual presence. ```javascript theme: { preset: "editorial", } ``` See [Theme presets reference](/docs/reference/theme-presets) for the exact color values. ## Accent color Override the preset's accent color with any hex value: ```javascript theme: { preset: "amber", accent: "#2563eb", // Blue accent instead of amber } ``` Tome derives tint and dim variants automatically from your accent color. ## Color mode Control dark/light mode behavior: | Value | Behavior | |-------|----------| | `"auto"` | Follows system preference (default) | | `"light"` | Always light mode | | `"dark"` | Always dark mode | Users can toggle the mode using the theme switch in the header. ## Custom fonts Override any font family. Make sure to add the appropriate `` tag to `index.html` if using custom Google Fonts. ```javascript theme: { fonts: { heading: "Playfair Display", body: "Source Sans Pro", code: "Fira Code", }, } ``` ## CSS variables For fine-grained control, override CSS variables in a custom stylesheet. The key variables are: | Variable | Description | |----------|-------------| | `--ac` | Accent color | | `--acD` | Accent dark variant | | `--acT` | Accent tint | | `--bg` | Page background | | `--sf` | Surface (cards, sidebar) | | `--sfH` | Surface hover state | | `--bd` | Border color | | `--tx` | Primary text | | `--tx2` | Secondary text | | `--txM` | Muted text | See the [Theme presets reference](/docs/reference/theme-presets) for the complete variable list with values per preset. ## Border radius Adjust the global border radius: ```javascript theme: { radius: "4px", // Sharper corners radius: "12px", // Rounder corners } ``` --- ## Search Tome includes search out of the box. No configuration is needed for the default experience — Pagefind indexes your site at build time and provides fast, client-side search with zero external dependencies. ## Built-in search (Pagefind) Pagefind is the default search provider. It runs automatically during `tome build`: 1. Tome builds your static site to `out/` 2. Pagefind indexes all HTML pages 3. The search index is placed in `out/_pagefind/` 4. The search UI loads the index on demand (< 1KB initial JS) No configuration required. Search is available on every page via the header search bar or the `Ctrl+K` / `Cmd+K` keyboard shortcut. ```javascript // Default — can be omitted entirely search: { provider: "local", } ``` ## Algolia DocSearch For larger documentation sites, you can use Algolia DocSearch as an alternative: ```javascript search: { provider: "algolia", appId: "YOUR_APP_ID", apiKey: "YOUR_SEARCH_API_KEY", indexName: "your-index-name", } ``` ### Initialize the Algolia index Tome includes a helper command to set up your Algolia index: ```bash npx @tomehq/cli algolia:init ``` This creates a crawler configuration optimized for Tome's HTML structure. ### When to use Algolia | Feature | Pagefind | Algolia | |---------|----------|---------| | Setup | Zero config | Requires account | | Cost | Free | Free tier available | | Index size | Unlimited | 10K records free | | Typo tolerance | Basic | Advanced | | Analytics | No | Yes | | Real-time indexing | At build time | Crawler-based | For most documentation sites, Pagefind is sufficient. Consider Algolia if you need search analytics, advanced typo tolerance, or real-time indexing. --- ## Multi-Version Docs Tome supports maintaining multiple versions of your documentation side by side. This is useful for libraries and APIs that need to document breaking changes across major versions. ## Directory structure Organize your pages by version using subdirectories: ```text pages/ ├── current/ # Latest version │ ├── index.md │ ├── quickstart.md │ └── api.md ├── v1.0/ # Previous version │ ├── index.md │ ├── quickstart.md │ └── api.md └── v0.9/ # Older version ├── index.md └── api.md ``` ## Configuration Add the `versioning` section to your config: ```javascript export default { name: "My Docs", versioning: { current: "v2.0", versions: ["v2.0", "v1.0", "v0.9"], }, }; ``` | Field | Type | Description | |-------|------|-------------| | `current` | string | The label for the current (latest) version | | `versions` | string[] | All available versions, newest first | ## URL mapping | Directory | URL | |-----------|-----| | `pages/current/index.md` | `/` | | `pages/current/api.md` | `/api` | | `pages/v1.0/index.md` | `/v1.0/` | | `pages/v1.0/api.md` | `/v1.0/api` | The `current` directory always serves at the root — no version prefix. Older versions are prefixed with their version string. ## Version switcher When versioning is configured, Tome automatically adds a version dropdown to the header. Users can switch between versions, and the URL updates to reflect the selected version. If the current page exists in the target version, the user stays on that page. Otherwise, they're redirected to the version's index page. ## Best practices - Keep the `current` directory as your working copy - Copy `current` to a versioned directory (e.g., `v2.0`) when you cut a release - Remove pages from old versions that no longer apply rather than leaving stale content - Use the same page IDs across versions so the version switcher can navigate between them --- ## Introduction # Tome Welcome to Tome — beautiful documentation, zero vendor lock-in. --- Tome is an open-source documentation platform built for developers who believe great docs shouldn't cost $250/month. Write in Markdown or MDX, deploy anywhere, and own your content forever. ## What is Tome? Tome transforms your Markdown and MDX files into stunning, fully-searchable documentation sites. It handles navigation, theming, API references, code highlighting, and versioning — all from a simple folder of `.md` and `.mdx` files. > **OPEN SOURCE FOREVER** > > Tome is MIT licensed. No vendor lock-in, no surprise pricing changes, no feature gates. Your docs are yours. ## Why Tome? Documentation platforms have become unreasonably expensive. Most charge hundreds per month for features that should be table stakes. Want custom domains? Pay more. Need versioning? Upgrade your plan. Multiple projects? That'll be $250/month — per project. We built Tome because we thought that was absurd. Every developer and team deserves polished, professional documentation without paying a premium for basic functionality. Tome gives you everything you need for free when self-hosted, or at a fraction of the cost on our cloud. ```bash # Get started in 30 seconds npx @tomehq/cli init my-docs cd my-docs && npm install && npm run dev ``` ## Features - **Markdown and MDX** — Write docs in `.md` or use `.mdx` for interactive components like tabs, callouts, and code playgrounds. - **File-system routing** — Drop files into `pages/` and they become pages. No router config, no manifest files. - **Built-in components** — Callouts, tabs, cards, steps, accordions, and API playgrounds work out of the box. - **Two theme presets** — Ship with a warm amber aesthetic or an editorial brutalist look. Both support dark mode. - **Search included** — Pagefind indexes your site at build time. No external service required. - **API reference** — Point Tome at an OpenAPI spec and get a rendered reference with an interactive playground. - **Versioning** — Maintain multiple documentation versions side by side with a version switcher. - **i18n** — Serve docs in multiple languages with locale-based routing. - **Deploy anywhere** — Static output works on Vercel, Netlify, Cloudflare Pages, or Tome Cloud. ## Learn more - **[Quickstart](v1/quickstart)** — Get a docs site running in under a minute. - **[Installation](v1/installation)** — Detailed setup instructions and prerequisites. - **[Configuration](v1/configuration)** — Customize your site name, navigation, theme, and more. - **[CLI Reference](v1/cli)** — Every command and flag available in the `tome` CLI. --- ## Pages & Routing Every `.md` or `.mdx` file in the `pages/` directory becomes a page. The file path determines the URL. ## Basic routing | File path | URL | |-----------|-----| | `pages/index.md` | `/` | | `pages/quickstart.md` | `/quickstart` | | `pages/guides/deployment.md` | `/guides/deployment` | | `pages/api/endpoints.md` | `/api/endpoints` | | `pages/api/index.md` | `/api` | **Rules:** - `index.md` serves at the directory's root path - File extensions are stripped from the URL - Directory nesting maps directly to URL segments - Both `.md` and `.mdx` files are supported ## Page IDs Each page has an ID derived from its path relative to `pages/`: | File | Page ID | |------|---------| | `pages/index.md` | `index` | | `pages/quickstart.md` | `quickstart` | | `pages/guides/deployment.md` | `guides/deployment` | Page IDs are used in `navigation` config to control sidebar order. ## Navigation vs. routing All pages in `pages/` are routable regardless of whether they appear in `navigation`. Navigation only controls the sidebar. Pages can be hidden from the sidebar using `hidden: true` in frontmatter while remaining accessible at their URL. ## Frontmatter Every page can include YAML frontmatter at the top of the file: ```markdown --- title: My Page description: A brief description for SEO and navigation. icon: book sidebarTitle: Short Title hidden: false tags: [guide, setup] --- # My Page Content starts here. ``` | Field | Type | Description | |-------|------|-------------| | `title` | string | Page title (falls back to first `#` heading) | | `description` | string | Description for metadata and navigation | | `icon` | string | Icon identifier shown in the sidebar | | `sidebarTitle` | string | Override title shown in the sidebar | | `hidden` | boolean | Hide page from sidebar (still accessible via URL) | | `tags` | string[] | Tags for categorization and search | ## i18n routing When multiple locales are configured, organize pages by locale subdirectory: ```text pages/ ├── en/ # Default locale │ ├── index.md │ └── quickstart.md ├── es/ # Spanish │ ├── index.md │ └── quickstart.md ``` | File | URL | |------|-----| | `pages/en/index.md` | `/` (default — no prefix) | | `pages/es/index.md` | `/es/` | | `pages/es/quickstart.md` | `/es/quickstart` | The default locale serves at the root without a prefix. When `fallback: true` and a page doesn't exist in a non-default locale, the default version is used. ## Versioned routing When versioning is configured: ```text pages/ ├── current/ # Latest version │ ├── index.md │ └── api.md ├── v1.0/ │ ├── index.md │ └── api.md ``` | File | URL | |------|-----| | `pages/current/index.md` | `/` | | `pages/v1.0/index.md` | `/v1.0/` | | `pages/v1.0/api.md` | `/v1.0/api` | The `current` directory serves at the root. Older versions are prefixed with their version string. ## File discovery Tome discovers pages by scanning `pages/` for `**/*.{md,mdx}` files. Discovery runs at startup and again whenever files are added, removed, or renamed during development. Changes to existing files trigger a hot reload. --- ## Quickstart Get a working documentation site in three commands. ## Create a new project ```bash npx @tomehq/cli init my-docs ``` This scaffolds a complete documentation project with starter pages, configuration, and build scripts. ## Install and run ```bash cd my-docs npm install npm run dev ``` Open `http://localhost:3000`. You should see your documentation site with a sidebar, search, and starter content. ## Edit your first page Open `pages/index.md` in your editor. Change the title and save — the browser reloads automatically. ```markdown --- title: My Project description: Documentation for my project. --- # My Project Welcome to the docs. ``` Every `.md` or `.mdx` file in `pages/` becomes a page on your site. Subdirectories create nested routes: | File | URL | |------|-----| | `pages/index.md` | `/` | | `pages/quickstart.md` | `/quickstart` | | `pages/guides/setup.md` | `/guides/setup` | ## Add navigation Open `tome.config.js` and define your sidebar: ```javascript export default { name: "My Project", navigation: [ { group: "Getting Started", pages: ["index", "quickstart"], }, { group: "Guides", pages: ["guides/setup"], }, ], }; ``` ## Build for production ```bash npm run build ``` This outputs a static site to `out/` ready to deploy to any hosting provider — Vercel, Netlify, Cloudflare Pages, or Tome Cloud. ## Next steps - **[Installation](v1/installation)** for detailed setup and prerequisites - **[Configuration](v1/configuration)** to customize your site - **[Components](v1/components)** to use tabs, callouts, and other interactive elements --- ## CLI Reference The `tome` CLI is the primary interface for creating, developing, building, and deploying documentation sites. ## Installation ```bash npm install -D @tomehq/cli # or globally npm install -g @tomehq/cli ``` ## Commands ### `tome init [name]` Create a new Tome documentation project. ```bash tome init my-docs ``` | Argument | Default | Description | |----------|---------|-------------| | `name` | `my-docs` | Project directory name | | Flag | Default | Description | |------|---------|-------------| | `-t, --template ` | `default` | Starter template | Creates `tome.config.js`, `package.json`, `index.html`, `.tome/entry.tsx`, starter pages in `pages/`, and `public/` and `styles/` directories. --- ### `tome dev` Start the development server with hot reloading. ```bash tome dev tome dev -p 4000 tome dev --host ``` | Flag | Default | Description | |------|---------|-------------| | `-p, --port ` | `3000` | Server port | | `--host` | `false` | Expose to network (bind `0.0.0.0`) | Watches `pages/` for file changes and reloads automatically. Config changes trigger a full reload. --- ### `tome build` Build the documentation site for production. ```bash tome build tome build -o dist ``` | Flag | Default | Description | |------|---------|-------------| | `-o, --outDir ` | `out` | Output directory | Produces a static site and runs Pagefind to build the search index. --- ### `tome deploy` Deploy the site to Tome Cloud. Requires `tome login` first. ```bash tome deploy tome deploy --preview --branch feature/auth ``` | Flag | Default | Description | |------|---------|-------------| | `--preview` | `false` | Deploy as a preview (branch-based URL) | | `--branch ` | auto-detect | Git branch name for preview | | `--expires ` | `7` | Preview expiry in days | Builds, collects output files, and uploads using hash-based deduplication. With `--preview`, deploys to a branch-specific URL (e.g., `feature-auth.preview.my-docs.tome.center`) and injects a preview banner. --- ### `tome lint` Lint documentation content for common issues. ```bash tome lint tome lint --strict tome lint --banned-words "simply,obviously" ``` | Flag | Default | Description | |------|---------|-------------| | `--max-paragraph ` | `300` | Max words per paragraph | | `--no-heading-increment` | — | Disable heading increment check | | `--no-image-alt` | — | Disable missing alt text check | | `--no-single-h1` | — | Disable single H1 check | | `--no-empty-links` | — | Disable empty link check | | `--banned-words ` | — | Comma-separated list of banned words | | `--strict` | `false` | Treat warnings as errors | Checks all pages for heading hierarchy issues, missing image alt text, overly long paragraphs, duplicate H1 tags, empty links, and banned words. --- ### `tome login` Authenticate with Tome Cloud. ```bash tome login ``` Prompts for email and sends a magic link. Stores the API token locally. --- ### `tome domains:add ` Add a custom domain. Returns DNS records to configure. ```bash tome domains:add docs.example.com ``` ### `tome domains:verify ` Verify DNS configuration for a custom domain. ```bash tome domains:verify docs.example.com ``` ### `tome domains:list` List all custom domains for the current project. ### `tome domains:remove ` Remove a custom domain. --- ### `tome algolia:init` Initialize an Algolia DocSearch index. Prompts for credentials and creates a crawler configuration. --- ### `tome mcp` Start the MCP (Model Context Protocol) stdio server for AI tool integration. Exposes documentation content as MCP resources and tools. --- ## Components Tome includes built-in components available in any `.mdx` file without imports. ## Callout Draw attention to important information. ```mdx This is an informational callout. ``` | Prop | Type | Default | Description | |------|------|---------|-------------| | `type` | `"info" \| "tip" \| "warning" \| "danger"` | `"info"` | Visual style and icon | | `title` | `string` | — | Optional heading text | Types: `info` (blue), `tip` (green), `warning` (amber), `danger` (red). --- ## Tabs Present content variants — useful for multiple languages or platform-specific instructions. ```mdx
npm install @tomehq/cli
yarn add @tomehq/cli
pnpm add @tomehq/cli
``` | Prop | Type | Description | |------|------|-------------| | `items` | `string[]` | Tab labels (required) | Each child `
` maps to a tab in order. --- ## Card A linked or static content card. ```mdx Set up your first project in minutes. ``` | Prop | Type | Description | |------|------|-------------| | `title` | `string` | Card heading (required) | | `icon` | `string` | Emoji or icon name | | `href` | `string` | Link URL (makes the card clickable) | --- ## CardGroup Arranges cards in a responsive grid. ```mdx Step 1 Step 2 Step 3 ``` | Prop | Type | Default | Description | |------|------|---------|-------------| | `cols` | `number` | `2` | Number of columns | --- ## Steps Sequential instructions with numbered indicators. ```mdx
**Create a project** Run `tome init my-docs`.
**Install dependencies** Run `npm install`.
``` Each child `
` becomes a numbered step. Use bold text on the first line for the step title. --- ## Accordion Collapsible content sections for FAQs or optional details. ```mdx Run `tome build` then upload the `out/` directory. ``` | Prop | Type | Description | |------|------|-------------| | `title` | `string` | Clickable header text (required) | --- ## API components When an OpenAPI spec is configured, additional components are auto-generated: - **ApiEndpoint** — Renders an API endpoint with parameters and responses - **ApiPlayground** — Interactive request builder - **ApiResponse** — Formatted response viewer See the [API reference guide](/docs/guides/api-reference) for setup. --- ## `.md` vs `.mdx` Components are only available in `.mdx` files. Rename `.md` to `.mdx` to use them — no other changes needed. --- ## Config Reference The config file (`tome.config.js`, `.mjs`, or `.ts`) is validated at startup. Invalid values produce clear error messages with the field path and expected type. ## Top-level fields | Field | Type | Default | Description | |-------|------|---------|-------------| | `name` | `string` | `"My Docs"` | Site name shown in the header and browser tab | | `logo` | `string` | — | Path to logo image, relative to `public/` | | `favicon` | `string` | — | Path to favicon, relative to `public/` | | `baseUrl` | `string` | — | Full URL where the site is hosted (for analytics, canonical links) | | `basePath` | `string` | — | URL subpath prefix (e.g., `"/docs/"`) — sets Vite's `base` option | | `theme` | `ThemeConfig` | `{}` | Theme configuration (see below) | | `navigation` | `NavigationGroup[]` | `[]` | Sidebar navigation structure | | `topNav` | `TopNavItem[]` | — | Header navigation links | | `search` | `SearchConfig` | `{ provider: "local" }` | Search provider configuration | | `api` | `ApiConfig` | — | OpenAPI spec and playground settings | | `ai` | `AiConfig` | — | AI chat widget configuration | | `mcp` | `McpConfig` | `{ enabled: true }` | MCP server manifest generation | | `i18n` | `I18nConfig` | — | Internationalization settings | | `versioning` | `VersioningConfig` | — | Multi-version documentation | | `analytics` | `AnalyticsConfig` | — | Analytics provider settings | | `webhooks` | `WebhookConfig[]` | — | Webhook notifications for deploy events | ## ThemeConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `preset` | `"amber" \| "editorial"` | `"amber"` | Base theme preset | | `accent` | `string` | — | Custom accent color (hex, e.g., `"#ff6b4a"`) | | `mode` | `"light" \| "dark" \| "auto"` | `"auto"` | Color mode | | `fonts.heading` | `string` | — | Heading font family | | `fonts.body` | `string` | — | Body font family | | `fonts.code` | `string` | — | Code font family | | `radius` | `string` | — | Border radius (e.g., `"8px"`) | ## NavigationGroup ```typescript { group: string; pages: Array; } ``` Page IDs are filenames without extensions, relative to `pages/`. Nested groups are supported. ## SearchConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `provider` | `"local" \| "algolia"` | `"local"` | Search provider | | `appId` | `string` | — | Algolia application ID | | `apiKey` | `string` | — | Algolia search-only API key | | `indexName` | `string` | — | Algolia index name | ## ApiConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `spec` | `string` | — | Path to OpenAPI spec file (required) | | `playground` | `boolean` | `true` | Enable interactive API playground | | `baseUrl` | `string` | — | Base URL for playground requests | | `auth.type` | `"bearer" \| "apiKey" \| "oauth2"` | — | Authentication type | | `auth.header` | `string` | — | Auth header name | ## AiConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `enabled` | `boolean` | `false` | Enable AI chat widget | | `provider` | `"openai" \| "anthropic" \| "custom"` | `"anthropic"` | AI provider | | `model` | `string` | — | Model identifier | | `apiKeyEnv` | `string` | `"TOME_AI_KEY"` | Environment variable for API key | ## McpConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `enabled` | `boolean` | `true` | Generate `mcp.json` manifest at build time | | `server` | `boolean` | `false` | Enable MCP stdio server | | `includeContent` | `boolean` | `true` | Include page content in the manifest | | `excludePages` | `string[]` | `[]` | Page IDs to exclude | ## I18nConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `defaultLocale` | `string` | `"en"` | Default locale code | | `locales` | `string[]` | `["en"]` | All available locale codes | | `localeNames` | `Record` | — | Display names (e.g., `{ en: "English" }`) | | `fallback` | `boolean` | `true` | Fall back to default locale for missing translations | ## VersioningConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `current` | `string` | — | Label for the current version (required) | | `versions` | `string[]` | — | All version labels, newest first (required) | ## AnalyticsConfig | Field | Type | Default | Description | |-------|------|---------|-------------| | `provider` | `"plausible" \| "posthog" \| "custom"` | — | Analytics provider | | `key` | `string` | — | Site ID or API key | ## WebhookConfig Send notifications to Slack, Discord, or generic HTTP endpoints when deploy events occur. ```js webhooks: [ { url: "https://hooks.slack.com/services/T.../B.../...", channel: "slack", events: ["deploy.succeeded", "deploy.failed"], }, { url: "https://discord.com/api/webhooks/...", channel: "discord", }, { url: "https://example.com/webhook", channel: "http", secret: "my-hmac-secret", }, ] ``` | Field | Type | Default | Description | |-------|------|---------|-------------| | `url` | `string` | — | Webhook endpoint URL (required) | | `channel` | `"slack" \| "discord" \| "http"` | — | Notification format (required) | | `events` | `WebhookEventType[]` | all | Filter which events trigger the webhook | | `secret` | `string` | — | HMAC-SHA256 secret for HTTP signature (`X-Tome-Signature` header) | **Event types:** `deploy.succeeded`, `deploy.failed`, `preview.deployed`, `domain.verified` --- ## Frontmatter Every Tome page can include YAML frontmatter at the top of the file. Frontmatter controls metadata like the page title, description, sidebar behavior, and search tags. ## Syntax ```markdown --- title: My Page Title description: A brief summary of the page content. --- # My Page Title Page content starts here. ``` ## Fields | Field | Type | Default | Description | |-------|------|---------|-------------| | `title` | `string` | First `#` heading | Page title for sidebar, browser tab, and search | | `description` | `string` | — | Short summary for SEO and search results | | `icon` | `string` | — | Icon identifier shown in the sidebar | | `sidebarTitle` | `string` | `title` | Override the title shown in sidebar navigation | | `hidden` | `boolean` | `false` | Hide this page from sidebar navigation | | `tags` | `string[]` | — | Tags for search indexing and categorization | | `ogImage` | `string` | auto-generated | Custom OpenGraph image URL or path | ## Title resolution If `title` is not set in frontmatter, Tome uses the first `# Heading` in the page content. If neither exists, the page is titled "Untitled". The `sidebarTitle` field lets you show a shorter name in the sidebar: ```markdown --- title: Configuring Authentication with OAuth 2.0 sidebarTitle: Authentication --- ``` ## Hidden pages Pages with `hidden: true` are excluded from sidebar navigation but remain accessible at their URL. Useful for: - Landing pages that shouldn't appear in the sidebar - Draft pages shared via direct link - Internal reference pages linked from other content ## Tags Tags improve search results by adding keywords that may not appear in the page content: ```markdown --- title: Deployment tags: [hosting, vercel, netlify, cloudflare, static] --- ``` Tags are indexed by both Pagefind and Algolia (when configured) and appear in MCP manifest output. ## Icons The `icon` field accepts identifiers displayed in the sidebar. Common values: `rocket`, `gear`, `code`, `terminal`, `puzzle`, `search`, `layers`, `cloud`, `file-text`, `palette`. ## OpenGraph images By default, Tome auto-generates OG images for every page at build time. Use `ogImage` to override with a custom image: ```markdown --- title: Getting Started ogImage: /images/custom-og.png --- ``` The value can be a relative path (resolved from your site root) or a full URL. Pages with a custom `ogImage` skip auto-generation. --- ## Theme Presets Tome ships with two theme presets. Each defines color tokens for dark and light modes plus font families. ## Amber The default preset. Warm, approachable tones with a golden accent. ### Dark mode | Variable | Value | Description | |----------|-------|-------------| | `--bg` | `#1a1a1a` | Page background | | `--sf` | `#242424` | Surface (cards, sidebar) | | `--sfH` | `#2e2e2e` | Surface hover | | `--bd` | `#333333` | Border | | `--tx` | `#e5e5e5` | Primary text | | `--tx2` | `#999999` | Secondary text | | `--txM` | `#666666` | Muted text | | `--ac` | `#e8a845` | Accent | | `--acD` | `#d4922e` | Accent dark | | `--acT` | `#2a2318` | Accent tint | ### Light mode | Variable | Value | Description | |----------|-------|-------------| | `--bg` | `#fafaf9` | Page background | | `--sf` | `#f5f5f4` | Surface | | `--sfH` | `#e7e5e4` | Surface hover | | `--bd` | `#d6d3d1` | Border | | `--tx` | `#1c1917` | Primary text | | `--tx2` | `#57534e` | Secondary text | | `--txM` | `#a8a29e` | Muted text | | `--ac` | `#d97706` | Accent | | `--acD` | `#b45309` | Accent dark | | `--acT` | `#fef3c7` | Accent tint | ### Fonts | Variable | Value | |----------|-------| | `--font-heading` | `'Instrument Serif', serif` | | `--font-body` | `'DM Sans', sans-serif` | | `--font-code` | `'JetBrains Mono', monospace` | --- ## Editorial A refined, high-contrast preset inspired by Swiss poster design. ### Dark mode | Variable | Value | Description | |----------|-------|-------------| | `--bg` | `#0f0f0f` | Page background | | `--sf` | `#1a1a1a` | Surface | | `--sfH` | `#252525` | Surface hover | | `--bd` | `#2a2a2a` | Border | | `--tx` | `#f0f0f0` | Primary text | | `--tx2` | `#888888` | Secondary text | | `--txM` | `#555555` | Muted text | | `--ac` | `#ff6b4a` | Accent (coral) | | `--acD` | `#e85a3a` | Accent dark | | `--acT` | `#1f1512` | Accent tint | ### Light mode | Variable | Value | Description | |----------|-------|-------------| | `--bg` | `#faf9f7` | Page background | | `--sf` | `#f2f0ed` | Surface | | `--sfH` | `#e8e5e1` | Surface hover | | `--bd` | `#d8d4cf` | Border | | `--tx` | `#1a1a1a` | Primary text | | `--tx2` | `#6b6560` | Secondary text | | `--txM` | `#a09890` | Muted text | | `--ac` | `#e85a3a` | Accent (coral) | | `--acD` | `#d04a2a` | Accent dark | | `--acT` | `#fef0ec` | Accent tint | ### Fonts | Variable | Value | |----------|-------| | `--font-heading` | `'Cormorant Garamond', serif` | | `--font-body` | `'Bricolage Grotesque', sans-serif` | | `--font-code` | `'Fira Code', monospace` | --- ## Additional variables Both presets also define: | Variable | Description | |----------|-------------| | `--cdBg` | Code block background | | `--cdTx` | Code block text | | `--sbBg` | Sidebar background | | `--hdBg` | Header background | Override any variable in custom CSS to fine-tune the theme. --- ## Theming Tome ships with two theme presets and extensive customization options. Every visual aspect — colors, fonts, spacing — can be adjusted through configuration or CSS variables. ## Presets ### Amber (default) A warm, golden aesthetic with serif headings. Clean and approachable. ```javascript theme: { preset: "amber", } ``` ### Editorial Swiss poster-inspired design with a brutalist edge. Coral accent color, grotesque typography. ```javascript theme: { preset: "editorial", } ``` ## Custom accent color Override the default accent color with any hex value: ```javascript theme: { preset: "amber", accent: "#2563eb", // Blue accent } ``` Tome derives tint and dim variants automatically from your accent color. ## Dark mode Control the color scheme: ```javascript theme: { mode: "auto", // Follows system preference // mode: "light", // Always light // mode: "dark", // Always dark } ``` When set to `auto`, a theme toggle appears in the header. ## Custom fonts Override any of the three font families: ```javascript theme: { fonts: { heading: "Playfair Display", body: "Inter", code: "JetBrains Mono", }, } ``` Load your fonts via Google Fonts in `index.html` or self-host them. ## Border radius Control the roundness of UI elements: ```javascript theme: { radius: 8, // pixels, default varies by preset } ``` ## CSS variables For fine-grained control, override CSS variables directly. Add a ` ``` ### Variable reference | Variable | Purpose | |----------|---------| | `--ac` | Accent color (links, highlights) | | `--acD` | Accent dim (callout backgrounds) | | `--acT` | Accent dark (hover states) | | `--bg` | Page background | | `--sf` / `--sfH` | Surface and surface hover | | `--tx` / `--tx2` / `--txM` | Text primary, secondary, muted | | `--bd` | Borders | | `--cdBg` / `--cdTx` | Code block background and text | | `--sbBg` | Sidebar background | | `--hdBg` | Header background | | `--font-heading` | Heading font family | | `--font-body` | Body font family | | `--font-code` | Code font family | --- ## Deploy to Tome Cloud Tome Cloud hosts your documentation site on a global CDN with automatic SSL, custom domains, and analytics. This tutorial covers the full deployment flow. ## Prerequisites - A Tome documentation project (see [Create your first site](/docs/tutorials/first-site)) - Node.js 22.22.2+ ## 1. Authenticate Log in to your Tome Cloud account: ```bash npx @tomehq/cli login ``` Enter your email address. You'll receive a magic link — click it to authenticate. Your API token is stored locally for future deployments. ## 2. Deploy From your project directory: ```bash npx @tomehq/cli deploy ``` Tome builds your site, collects the output files, and uploads them using hash-based deduplication. Only changed files are transferred, making subsequent deploys fast. After deployment, your site is live at: ``` https://your-project.tome.center ``` ## 3. Add a custom domain Register a custom domain for your docs: ```bash npx @tomehq/cli domains:add docs.example.com ``` Tome returns DNS records you need to configure with your domain registrar: ```text Type: CNAME Name: docs Value: your-project.tome.center ``` After configuring DNS, verify the domain: ```bash npx @tomehq/cli domains:verify docs.example.com ``` SSL is provisioned automatically once DNS propagates. ## 4. Manage domains List all domains attached to your project: ```bash npx @tomehq/cli domains:list ``` Remove a domain: ```bash npx @tomehq/cli domains:remove docs.example.com ``` ## Deployment details Each deploy creates an immutable snapshot. You can view deployment history and analytics in the Tome Dashboard. | Detail | Value | |--------|-------| | CDN | Cloudflare R2 (global edge) | | SSL | Automatic via Cloudflare | | Deduplication | Content-hash based | | Rollback | Deploy any previous snapshot | ## Next steps - **[Configuration guide](/docs/guides/configuration)** to customize your site before deploying - **[CLI reference](/docs/reference/cli)** for the full list of deployment commands --- ## Create Your First Site This tutorial walks you through creating a Tome documentation site from scratch. By the end, you'll have a working docs site running locally with custom pages and navigation. ## Prerequisites You need **Node.js 22.22.2+** and a package manager (`npm`, `yarn`, or `pnpm`). ## 1. Scaffold the project Run the init command to create a new project: ```bash npx @tomehq/cli init my-docs ``` This creates a directory with the following structure: ```text my-docs/ ├── tome.config.js # Site configuration ├── package.json # Dependencies and scripts ├── index.html # Vite entry point ├── .tome/entry.tsx # Theme bootstrap (don't edit) ├── pages/ # Your documentation pages │ ├── index.md │ ├── quickstart.md │ └── components.mdx ├── public/ # Static assets └── styles/ # Custom CSS (optional) ``` ## 2. Install dependencies ```bash cd my-docs npm install ``` ## 3. Start the dev server ```bash npm run dev ``` Open `http://localhost:3000`. You should see the starter documentation site. Every time you save a file, the page reloads automatically. ## 4. Add a new page Create `pages/guides/deployment.md`: ```markdown --- title: Deployment Guide description: How to deploy your Tome site to production. --- # Deployment Guide Run `npm run build` to produce static files in the `out/` directory. Upload this directory to any static hosting provider. ``` The page is immediately available at `/guides/deployment` in the dev server. ## 5. Configure navigation Open `tome.config.js` and add your new page to the sidebar: ```javascript export default { name: "my-docs", theme: { preset: "amber", mode: "auto", }, navigation: [ { group: "Getting Started", pages: ["index", "quickstart"], }, { group: "Guides", pages: ["guides/deployment"], }, { group: "Reference", pages: ["components"], }, ], }; ``` The sidebar updates to reflect the new structure. ## 6. Customize the theme Change the preset to `editorial` and set a custom accent color: ```javascript theme: { preset: "editorial", accent: "#ff6b4a", mode: "auto", }, ``` The entire site switches to the editorial aesthetic with your accent color. ## 7. Build for production ```bash npm run build ``` This outputs a static site to `out/` with a pre-built search index. The output is ready to deploy to any hosting provider. ## Next steps - **[Deploy to Tome Cloud](/docs/tutorials/deploy-to-cloud)** to publish with a single command - **[Configuration guide](/docs/guides/configuration)** for all available options - **[Components reference](/docs/reference/components)** for the full list of MDX components