Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -134,4 +134,6 @@ dist
.pnp.*

dist
.output/
.vercel/
examples/frontier
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Chronicle

Config-driven documentation framework built on Next.js, Fumadocs, and Apsara UI.
Config-driven documentation framework built on Vite, Nitro, and Apsara UI.

## Features

Expand Down Expand Up @@ -75,7 +75,7 @@ bun install
3. Run the dev server

```bash
cd docs && bun ../packages/chronicle/bin/chronicle.js dev
bun run dev:docs
```

Open [http://localhost:3000](http://localhost:3000) to see the docs site.
Expand Down
2 changes: 1 addition & 1 deletion bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions docs/chronicle.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
title: Chronicle
description: Config-driven documentation framework
content: .

theme:
name: paper
Expand Down
37 changes: 25 additions & 12 deletions docs/cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Chronicle provides a CLI to initialize, develop, build, and serve your documenta

## init

Initialize a new Chronicle project. Must be run before other commands.
Initialize a new Chronicle project.

```bash
chronicle init [options]
Expand All @@ -23,32 +23,38 @@ chronicle init [options]
This creates:
- `chronicle.yaml` — site configuration
- `content/` (or custom name) — content directory with a sample `index.mdx`
- `package.json` — with `@raystack/chronicle` dependency (if not exists)
- `.chronicle/` — scaffolded build directory
- `.gitignore` — with `.chronicle` entry
- `.gitignore` — with `node_modules`, `dist`, `.output` entries

If the content directory already exists and has files, the sample `index.mdx` is skipped.

## dev

Start the development server with hot reload. Requires `chronicle init` first.
Start the development server with hot reload.

```bash
chronicle dev [options]
```

| Flag | Description | Default |
|------|-------------|---------|
| `--content <path>` | Content directory | `content` |
| `--config <path>` | Path to `chronicle.yaml` | `./chronicle.yaml` |
| `-p, --port <port>` | Port number | `3000` |

## build

Build the site for production. Requires `chronicle init` first.
Build the site for production.

```bash
chronicle build
chronicle build [options]
```

| Flag | Description | Default |
|------|-------------|---------|
| `--content <path>` | Content directory | `content` |
| `--config <path>` | Path to `chronicle.yaml` | `./chronicle.yaml` |
| `--preset <preset>` | Deploy preset (`vercel`, `cloudflare`, `node-server`) | — |

## start

Start the production server. Requires a prior `chronicle build`.
Expand All @@ -59,23 +65,30 @@ chronicle start [options]

| Flag | Description | Default |
|------|-------------|---------|
| `--content <path>` | Content directory | `content` |
| `-p, --port <port>` | Port number | `3000` |

## serve

Build and start the production server in one step. Requires `chronicle init` first.
Build and start the production server in one step.

```bash
chronicle serve [options]
```

| Flag | Description | Default |
|------|-------------|---------|
| `--content <path>` | Content directory | `content` |
| `--config <path>` | Path to `chronicle.yaml` | `./chronicle.yaml` |
| `-p, --port <port>` | Port number | `3000` |
| `--preset <preset>` | Deploy preset (`vercel`, `cloudflare`, `node-server`) | — |

## Config Resolution
## Resolution Order

`chronicle.yaml` is resolved in this order:
CLI flags take precedence over `chronicle.yaml` values, which take precedence over defaults.

1. Current working directory
2. Content directory
| Option | CLI flag | Config field | Default |
|--------|----------|-------------|---------|
| Content directory | `--content` | `content` | `content` |
| Deploy preset | `--preset` | `preset` | — |
| Config path | `--config` | — | `./chronicle.yaml` |
6 changes: 3 additions & 3 deletions docs/components.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ Images support both local and external sources:
![External image](https://example.com/image.png)
```

- **Local images** — Rendered with Next.js `Image` component (optimized, default 800x400)
- **Local images** — Rendered with optimized `Image` component (default 800x400)
- **External images** — Rendered with standard `<img>` tag

## Links
Expand All @@ -171,7 +171,7 @@ Links are automatically handled:
[Anchor link](#section)
```

- **Internal links** — Use Next.js client-side navigation
- **Internal links** — Use client-side navigation
- **External links** — Open in a new tab automatically
- **Anchor links** — Smooth scroll to the section

Expand Down Expand Up @@ -203,7 +203,7 @@ Chronicle overrides these HTML elements with styled components:
| HTML Element | Chronicle Component | Notes |
|-------------|-------------------|-------|
| `<p>` | `MdxParagraph` | Auto-converts to `<div>` when containing block elements |
| `<img>` | `Image` | Next.js optimized for local, standard for external |
| `<img>` | `Image` | Optimized for local, standard for external |
| `<a>` | `Link` | Smart routing with external link detection |
| `<code>` | `MdxCode` | Inline code styling |
| `<pre>` | `MdxPre` | Code blocks with optional title header |
Expand Down
66 changes: 65 additions & 1 deletion docs/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@ order: 3

# Configuration

All site configuration lives in a single `chronicle.yaml` file in your content directory.
All site configuration lives in a single `chronicle.yaml` file in your project root. The config is validated using Zod — invalid fields will produce clear error messages at startup.

## Full Example

```yaml
title: My Project Docs
description: Documentation for My Project
url: https://docs.example.com
content: docs
preset: vercel

logo:
light: ./logo-light.png
Expand Down Expand Up @@ -51,6 +54,14 @@ api:
type: apiKey
header: Authorization
placeholder: "Bearer token"

llms:
enabled: true

analytics:
enabled: true
googleAnalytics:
measurementId: G-XXXXXXXXXX
```

## Reference
Expand All @@ -63,6 +74,30 @@ api:
title: My Documentation
```

### url

Optional site URL. Used for SEO metadata, sitemap, and canonical URLs.

```yaml
url: https://docs.example.com
```

### content

Optional content directory path. Can be overridden by the `--content` CLI flag.

```yaml
content: docs
```

### preset

Optional deploy preset. Can be overridden by the `--preset` CLI flag.

```yaml
preset: vercel # vercel, cloudflare, or node-server
```

### description

Optional meta description for SEO.
Expand Down Expand Up @@ -203,6 +238,35 @@ Each entry in the `api` array creates a section of API documentation.

API pages include a "Try it out" panel that uses the configured server URL and auth settings.

### llms

Configuration for LLM-friendly content generation. When enabled, Chronicle generates `/llms.txt` and `/llms-full.txt` endpoints.

```yaml
llms:
enabled: true
```

| Field | Type | Description | Default |
|-------|------|-------------|---------|
| `enabled` | `boolean` | Enable/disable LLM content endpoints | `false` |

### analytics

Analytics integration for tracking page views.

```yaml
analytics:
enabled: true
googleAnalytics:
measurementId: G-XXXXXXXXXX
```

| Field | Type | Description | Default |
|-------|------|-------------|---------|
| `enabled` | `boolean` | Enable/disable analytics | `false` |
| `googleAnalytics.measurementId` | `string` | Google Analytics measurement ID | — |

## Defaults

If `chronicle.yaml` is missing or fields are omitted, these defaults apply:
Expand Down
8 changes: 8 additions & 0 deletions docs/frontmatter.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ icon: rectangle-stack
| `method-delete` | HTTP DELETE badge |
| `method-patch` | HTTP PATCH badge |

### lastModified

Optional date string indicating when the page was last updated.

```yaml
lastModified: "2026-03-30"
```

## Navigation Ordering

Sidebar navigation is determined by:
Expand Down
9 changes: 4 additions & 5 deletions docs/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ order: 1

# Getting Started

Chronicle is a config-driven documentation framework built on Next.js 15, Fumadocs, and Apsara UI components. Write MDX content, configure with a single YAML file, and get a fully themed documentation site.
Chronicle is a config-driven documentation framework built on Vite, Nitro, and Apsara UI components. Write MDX content, configure with a single YAML file, and get a fully themed documentation site.

## Installation

Expand All @@ -25,8 +25,7 @@ chronicle init
This creates:
- `chronicle.yaml` — your site configuration
- `content/` — content directory with a sample `index.mdx`
- `package.json` — with `@raystack/chronicle` dependency
- `.chronicle/` — scaffolded build directory (gitignored)
- `.gitignore` — with `node_modules`, `dist`, `.output` entries

To use an existing directory as content (e.g. `docs/`):

Expand Down Expand Up @@ -55,7 +54,7 @@ my-docs/
│ └── guides/
│ ├── installation.mdx
│ └── configuration.mdx
└── .chronicle/ # generated, gitignored
└── .output/ # build output, gitignored
```

### 4. Build for production
Expand All @@ -82,7 +81,7 @@ my-docs/
│ ├── index.mdx # Home page
│ └── guides/
│ └── setup.mdx # Nested page at /guides/setup
└── .chronicle/ # Generated by init, gitignored
└── .output/ # Build output, gitignored
```

All configuration is done through `chronicle.yaml`. No additional config files needed.
Expand Down
1 change: 1 addition & 0 deletions docs/themes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,4 @@ theme:
- Minimal, distraction-free design
- Reading progress tracking
- Optimized typography for long content
- Light mode only (dark mode toggle is disabled)
10 changes: 9 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
{
"name": "chronicle",
"private": true,
"workspaces": ["packages/*", "examples/*"],
"workspaces": [
"packages/*",
"examples/*"
],
"engines": {
"node": ">=22"
},
"scripts": {
"build:cli": "bun run --filter @raystack/chronicle build:cli",
"dev:docs": "./packages/chronicle/bin/chronicle.js dev --config docs/chronicle.yaml",
"build:docs": "./packages/chronicle/bin/chronicle.js build --config docs/chronicle.yaml"
}
}
2 changes: 1 addition & 1 deletion packages/chronicle/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
"lodash": "^4.17.23",
"mermaid": "^11.13.0",
"minisearch": "^7.2.0",
"nitro": "latest",
"nitro": "3.0.260311-beta",
"openapi-types": "^12.1.3",
"react": "^19.0.0",
"react-dom": "^19.0.0",
Expand Down
6 changes: 3 additions & 3 deletions packages/chronicle/src/cli/utils/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ function validateConfig(raw: string, configPath: string): ChronicleConfig {
return result.data;
}

export function resolveContentDir(config: ChronicleConfig, contentFlag?: string): string {
export function resolveContentDir(config: ChronicleConfig, configPath: string, contentFlag?: string): string {
if (contentFlag) return path.resolve(contentFlag);
if (config.content) return path.resolve(config.content);
if (config.content) return path.resolve(path.dirname(configPath), config.content);
return path.resolve('content');
}

Expand All @@ -64,7 +64,7 @@ export async function loadCLIConfig(

const raw = await readConfig(resolvedConfigPath);
const config = validateConfig(raw, resolvedConfigPath);
const contentDir = resolveContentDir(config, options?.content);
const contentDir = resolveContentDir(config, resolvedConfigPath, options?.content);
const preset = resolvePreset(config, options?.preset);

return { config, configPath: resolvedConfigPath, contentDir, preset };
Expand Down
5 changes: 5 additions & 0 deletions vercel.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"installCommand": "bun install",
"buildCommand": "bun run build:cli && bun run build:docs -- --preset vercel",
"outputDirectory": ".vercel/output"
}