Configuration

Site configuration lives in the content root.

Supported config entry files:

When multiple files exist, mdorigin prefers .ts, then .mjs, then .js, then .json.

Useful fields:

Code Config

Use mdorigin.config.ts when you want code-based customization instead of pure static settings.

Example:

import { defineConfig } from "mdorigin";

export default defineConfig({
  siteTitle: "My Site",
  plugins: [
    {
      name: "custom-layout",
      renderPage(page, _context, next) {
        if (page.kind !== "listing") {
          return next(page);
        }

        const title = escapeHtml(page.title);
        return [
          "<!doctype html>",
          "<html><body>",
          `<main class="custom-listing"><h1>${title}</h1>${page.bodyHtml}</main>`,
          "</body></html>",
        ].join("");
      },
    },
  ],
});

function escapeHtml(value: string): string {
  return value
    .replaceAll("&", "&amp;")
    .replaceAll("<", "&lt;")
    .replaceAll(">", "&gt;")
    .replaceAll('"', "&quot;")
    .replaceAll("'", "&#39;");
}

defineConfig is optional. A plain default export object also works.

Current stable plugin hooks:

The design boundary is:

Site Metadata

Navigation

Branding

Example:

{
  "siteUrl": "https://example.com",
  "favicon": "/favicon.svg",
  "socialImage": "/og.svg",
  "logo": {
    "src": "/logo.svg",
    "alt": "Example"
  }
}

RSS

mdorigin can emit a built-in RSS feed at /feed.xml.

Rules:

Optional overrides:

{
  "rss": {
    "title": "Example Feed",
    "description": "Latest updates from Example",
    "author": "editor@example.com",
    "maxItems": 20
  }
}

Supported fields:

Footer

mdorigin supports a small set of explicit footer settings:

Example:

{
  "footerNav": [
    { "label": "GitHub", "href": "https://github.com/example/repo" }
  ],
  "footerText": "Built with mdorigin.",
  "socialLinks": [
    { "icon": "github", "label": "GitHub", "href": "https://github.com/example/repo" }
  ],
  "editLink": {
    "baseUrl": "https://github.com/example/repo/edit/main/docs/"
  }
}

Built-in social icons currently include:

footerText has no implicit default. If you omit it, mdorigin does not render footer copy on its own.

Default Presentation

mdorigin ships one built-in presentation.

When a page contains a managed index block, the default renderer turns article entries into a structured listing and supports incremental Load more batches. You can tune that listing behavior with:

{
  "listingInitialPostCount": 10,
  "listingLoadMoreStep": 10
}

Rules:

Search Profile

When a site exposes a search bundle through mdorigin dev --search ... or a deployed search API, mdorigin can apply a site-level search profile.

Example:

{
  "search": {
    "topK": 10,
    "mode": "hybrid",
    "minScore": 0.05,
    "reranker": {
      "kind": "embedding-v1",
      "candidatePoolSize": 25
    },
    "scoreAdjustment": {
      "metadataNumericMultiplier": "directory_weight"
    }
  }
}

Supported fields:

Rules:

Example query-aware policy:

{
  "search": {
    "mode": "hybrid",
    "topK": 10,
    "minScore": 0.02,
    "policy": {
      "shortQuery": {
        "maxChars": 6,
        "minScore": 0.02,
        "reranker": null
      },
      "longQuery": {
        "minChars": 12,
        "reranker": {
          "kind": "heuristic-v1",
          "candidatePoolSize": 20
        }
      }
    }
  }
}

Directory Type

Directory homepage files may declare a content type in frontmatter:

---
title: Projects
type: page
---
---
title: Why mdorigin exists
type: post
---

Rules:

Order

Markdown frontmatter may define order:

---
title: Getting Started
order: 10
---

Rules:

Rendering Flags

Aliases

Markdown frontmatter may define old URLs that should redirect to the current canonical route:

---
title: Hello
aliases:
  - /hello-world
  - /old/hello
---

Rules: