Plugin Development

Plugins let Cdocs extend the build pipeline without touching the engine. The contract is external process + JSON file exchange: the builder fires hooks at key points, invokes your script (any language), and the script participates by reading/writing JSON. Zero DLL, zero deps, failures are isolated automatically.

#Directory layout

.Cdocs/plugins/<plugin-name>/
├── plugin.json        # Plugin manifest (required)
└── (script)           # A script or executable in any language

#plugin.json — manifest

{
  "name": "build-report",
  "hooks": {
    "on_done": { "cmd": "python report.py", "timeout": 30 }
  }
}
Field Meaning
name Plugin name (must match the directory name)
hooks Hook table: { hookName: { "cmd": command, "timeout": seconds } }
cmd Command to run. The builder chdirs into the plugin dir first: <cmd> <ctx.json abs path> <out.json abs path>
timeout Timeout in seconds (default 30). On timeout the process is killed and marked failed (exit 124), build continues

#Hooks & context

The builder broadcasts 4 hooks. Each receives a context JSON (ctx.json):

Hook When Key ctx fields
on_config after config loaded engine / source / dest
on_page_collected after pages collected count, pages[] (file/title/draft/tags)
on_page_rendered after each page written file / locale / path (absolute)
on_done after all output generated engine / source / dest
setup Cdocs deploy --setup source (project root, not the docs dir) / engine

setup is a non-build hook triggered only by Cdocs deploy --setup — used to generate platform deployment files (.github/workflows/*.yml, vercel.json…). Plugins write to ctx.source (project root), idempotent (skips if identical). Built-in deploy plugins: github-pages, vercel.

All path fields are absolute (the builder chdirs into the plugin dir, so relative paths would resolve wrongly).

#Output protocol

The script writes the result to out.json (the second argument, absolute path):

{ "ok": true, "message": "Footer injected" }
Field Meaning
ok true success / false business failure
message Text shown in the build log ([plugin <name>] <message>)

#Failure isolation

Plugins never block the build:

In every case Cdocs build continues and exits 0.

#Full example (Python)

A plugin that appends a footer to every page and reports total dist size at the end:

import json, os, sys

ctx_path, out_path = sys.argv[1], sys.argv[2]
ctx = json.load(open(ctx_path, encoding="utf-8"))

def done(result):
    json.dump(result, open(out_path, "w", encoding="utf-8"))

# Page-level hook: inject footer (idempotent marker prevents double injection)
if "path" in ctx:
    p = ctx["path"]
    text = open(p, encoding="utf-8").read()
    marker = "<!-- footer-by-plugin -->"
    if marker not in text:
        text = text.replace("</main>", marker + "\n<p>Injected by plugin</p>\n</main>", 1)
        open(p, "w", encoding="utf-8").write(text)
    done({"ok": True, "message": "Footer injected"})
else:
    # Site-level hook: sum dist size
    total = sum(os.path.getsize(os.path.join(root, f))
                for root, _, files in os.walk(ctx["dest"]) for f in files)
    done({"ok": True, "message": f"dist total {total//1024} KB"})

#Built-in vs plugins

These features are built into the engine (convention over configuration, no plugin needed): giscus comments (center.comments), versioned docs (docs-* snapshot auto-detection), RSS/PWA/sitemap/SEO, image & code compression. Plugins best fit site-specific finishing work: deploy push (gh-pages), custom analytics, alerting, content validation, and so on.

Last updated: 2026-08-02 20:10 · About 4 min read (657 words)