Skip to content

docs-site

Recipe card from the charly-tools plugin (Images — the deployable catalog).

docs-site — build the opencharly.ai site inside a box

Section titled “docs-site — build the opencharly.ai site inside a box”

Audience: this page describes maintenance the charly repository performs on itself. docs-site builds this documentation site, so every task … command below names a gate this project runs over its own sources from a charly checkout — never a step a reader runs. They are named because the candy’s contract is what keeps the published site honest, not because you invoke them.

Property Value
Requires nodejs
Packages git (fedora section)
Builds into /srv/docs (source), /srv/docs/dist (built site)
Consumed by the docs-site-app box → the check-docs bed

docs-site clones the published opencharly/docs repository, runs npm ci against its committed lockfile, and runs the production Astro build. A build failure — a bad frontmatter scalar, a Starlight config a version bump invalidated, a page whose markdown will not parse — fails the image build, from the same input Cloudflare Pages builds, so the box catches it before a deploy can.

The docs repo is standalone — charly no longer carries it as a submodule — and the candy cannot read another directory even if it did. The escapes are closed by design:

  • copy: rejects ..copy: "../../docs/x" may not contain .. (no traversal) at validate.
  • There is no field for pointing a candy at another directory. (An older revision of /charly-image:layer documented a directory: field for exactly this; that field does not exist in spec/schema/candy.cue, in the generated spec types, or in the loader, and charly box validate rejects it as field not allowed.)

Cloning the published repo is the schema-legal path, and it tests the more useful thing: the exact source Cloudflare builds.

Ordering consequence. The candy fetches an IMMUTABLE COMMIT, never a branch, so DOCS_REF must be re-pinned to each new docs merge before this box — and the check-docs bed above it — prove the new content. task docs:pin fails when DOCS_REF is not the docs repo’s current main head (it fetches ls-remote and compares — charly has no docs gitlink anymore: the docs repo is standalone, and this candy’s pin is the only thing that fixes what the bed tests). That re-pin is a CONFIG edit and changes the landing’s gate and attribution tier — see /charly-internals:git-workflow (B6a step 4, and B2 “the derivation stops at the gitlink” for the general rule), which owns landing mechanics.

The pin is TWO occurrences, and both are asserted. The sha appears once as DOCS_REF (the clone’s cache key) and once as a LITERAL in the docs-site-pinned-commit check’s contains: matcher. The duplication is deliberate and cannot be collapsed: a check step’s substitution does not resolve a candy var:, so writing ${DOCS_REF} in the matcher makes charly SKIP the step with “unresolved variables: DOCS_REF” — turning the anti-staleness guard into a non-event while the bed still reports PASS, which is the exact failure the guard exists to catch. task docs:pin therefore asserts BOTH: it compares DOCS_REF against the docs repo’s current main head AND requires the sha to occur at least twice in the file, so a re-pin that updates only one of them fails the gate instead of leaving the check asserting a commit nobody builds. Re-pinning means editing both.

A branch name here is a correctness bug, not a convenience: var: values are emitted as ENV above the steps, so with main the clone layer’s cache key never moves and the bed silently rebuilds whatever commit that layer first captured. That shipped once, and every run passed while proving stale content until review caught it.

Var Default
DOCS_REPO https://github.com/opencharly/docs.git
DOCS_REF the docs repo commit this bed tests — an immutable commit, never a branch (see above)

Every check is build-context, so charly check box docs-site-app proves the whole site builds and has the right shape without deploying anything.

Check Asserts
docs-site-node-present node reports a parseable major version
docs-site-index-built /srv/docs/dist/index.html exists
docs-site-cli-page a generated CLI reference page rendered
docs-site-candy-acceptance-plan a candy page publishes its plan: as an acceptance spec
docs-site-recipe-card a recipe card rendered with its cross-references rewritten to site links
docs-site-runtime-plugin-page the load-bearing one — see below
docs-site-provider-index the provider cross-index rendered

docs-site-runtime-plugin-page reads the page of plugin-cdp, which is not in compiled_plugins: — it loads out-of-process over gRPC — and asserts both its rendered placement and its CUE parameter schema.

That step is what fails if the generator ever narrows to documenting only the default-active set (the binary’s own command model, or the enabled-boxes list). It is deliberately the assertion that breaks first, because silently omitting everything that is not compiled in is the most plausible way for this catalog to go quietly wrong.

Terminal window
charly check run check-docs

A disposable: true pod deploy of docs-site-app. Reaching steady state proves the box builds, starts and stays up; the shape assertions already ran at image build.

The generator’s own cross-reference integrity gate (an unresolvable /charly-<plugin>:<skill> reference fails generation) is covered by the plugin’s Go tests — this bed covers the artifact those produce. The committed content’s staleness against the pinned charly is gated by the docs repo’s own deploy workflow, not here.

Symptom Cause
docs-site-pinned-commit FAILS the clone layer is stale, or DOCS_REF was re-pinned without rebuilding
task docs:pin fails DOCS_REF (or the check’s literal sha) is not the docs repo’s current main head — bump it in a charly PR
fetch fails upload-pack: not our ref <sha> DOCS_REF names a commit not reachable from ANY ref in the docs repo — never pushed, or garbage-collected
fetch fails couldn't find remote ref <x> DOCS_REF is not a FULL 40-hex sha — either a ref name (which the pinned-commit contract forbids) or an abbreviated sha, which git fetch rejects even when the commit exists
npm ci fails on a lockfile mismatch package.json and package-lock.json disagree — regenerate the lockfile in the docs repo
a shape check fails but index.html exists the generator emitted a different tree layout; regenerate in the docs repo (its deploy workflow) and check the diff in a docs PR

Invoke when working with the docs-site candy, the docs-site-app box, the check-docs bed, or when the documentation site fails to build.