Skip to content
CADCAMFUN
Docs

Documentation

Documentation site operations

Run the Astro site, maintain API and search content, export Markdown, configure assistant bindings, and understand the local Studio boundary.

Site architecture

packages/web is an Astro server-output application with the Cloudflare adapter. Documentation articles declare prerendering and become static HTML assets. Server routes handle Markdown export, documentation assistant requests, artifact viewing/raw content, and the production Studio fallback. This deployment is separate from the CAD/CAM sidecar.

The documentation site describes application behavior and supplies generated reference content. It does not inherit a visitor's projects, local application bearer token, provider credentials, or paired desktop connection. Its assistant uses documentation excerpts rather than silently operating the CAD/CAM workspace.

The local Studio is an additional Bun process because it uses bun:sqlite. Vite proxies its development API requests to loopback port 4396. A deployed Cloudflare Worker cannot open that local database; the production Studio API deliberately explains this with HTTP 503.

Local commands

From the repository root
bun run --filter @cadcamfun/web start
bun run --filter @cadcamfun/web dev
bun run --filter @cadcamfun/web studio
bun test packages/web/test
bun run --filter @cadcamfun/web typecheck
bun run --filter @cadcamfun/web build
CommandProcess or output
startAstro development server only. Use the address printed in the terminal.
devStudio Bun process plus Astro. Its launcher stops the child processes when the main development process exits.
studioOnly the local Studio API on loopback port 4396.
typecheckTypeScript and content integrity checks configured in this workspace.
buildProduction Worker output and prerendered assets under packages/web/dist.

Use Astro alone for article editing when Studio is unnecessary. Production compilation validates template generation and route output but does not call a real model backend, publish artifacts, or verify a deployed Cloudflare account.

Content and API generation

Articles live in src/pages/docs and share DocsLayout.astro. The sidebar in src/data/docsSidebar.ts is the documentation route inventory. docsIndex.ts adds per-route summaries and keywords for retrieval. A public page should have both a navigation entry and accurate retrieval copy; an unlinked article does not become discoverable merely because its file exists.

The API reference combines a generated contract snapshot with curated resource grouping in src/data/apiGroups.ts. src/lib/apiReference.ts selects every operation, resolves named schemas, and supplies the resource templates. The snapshot is generated from the composed application HttpApi using its installed Effect implementation.

Inside packages/web
bun run generate:api-reference
bun run check:api-reference
bun run check:docs-index
bun test test

Regeneration writes the current schema contract; it does not write domain guidance or prove that a remote application is on the same version. Handwritten pages explain business validation, side effects, permissions, recovery, and implementation limits. Keep those explanations tied to the actual handlers and services.

Source-reading notes can be prepared under packages/web/.tmp/content. They are temporary editorial material, excluded from publication. Move finished explanations into article pages and update navigation/retrieval; do not use a temporary note as the only documentation for an operation.

Markdown export

GET /llm lists known documentation pages as Markdown links. With path, it fetches the corresponding rendered article and converts it to GitHub-flavored Markdown. Adding format=prompt wraps that content in an instruction prompt that includes its canonical source.

Replace DOCS_ORIGIN with the running site
curl "$DOCS_ORIGIN/llm"
curl "$DOCS_ORIGIN/llm?path=/docs/cam"
curl "$DOCS_ORIGIN/llm?path=/docs/api/projects&format=prompt"

The pipeline reads only the article marked data-llm-document. It removes excluded content, scripts, styles, SVG decoration, and buttons so navigation and copy controls do not become answer context. It converts code blocks, headings, tables, and links rather than maintain a second handwritten Markdown corpus.

Only known documentation paths are admitted. Unknown paths return 404. A page-loading failure returns 502; another conversion failure returns 500. The response is Markdown with permissive read CORS and a public five-minute cache policy with stale-while-revalidate. These exported public articles do not contain local project credentials.

On Cloudflare, the helper prefers the ASSETS binding for prerendered pages. This keeps the read within the Worker deployment. Development can fall back to live fetching when the existing asset build does not contain a page. A stale local dist tree and a current source tree can therefore be different inputs while editing.

Documentation assistant

POST /api/docs-assistant accepts conversation messages, an optional documentation path, and an optional backend session identifier. It keeps only user/assistant messages, trims each message to 1,200 characters, retains the most recent 12 valid messages, and requires a user question.

Retrieval first scores the current question and earlier user questions against titles, routes, keywords, and summaries. The current known page is retained. When a Workers AI binding is available, an optional tool-call planner can select relevant documentation routes; invalid selections or planner failures fall back to lexical retrieval.

Up to three pages are loaded. Each is condensed to a 5,000-character budget by retaining its introduction and matching sections. A long API resource page is therefore not automatically supplied in full to the model. Link the user to the relevant operation when the excerpt does not contain enough detail.

Loaded Markdown is cached separately for 30 minutes when the Worker cache is available. A source edit can require cache refresh in an already-running deployment. If no selected page can be loaded, the route returns 502. If no Workers AI binding or complete nikcli backend configuration exists, it returns 503 before generation.

A single assistant request may carry at most 12 conversation messages, and a question is limited to 1,200 characters (MAX_MESSAGES and MAX_QUESTION_CHARS in src/lib/docsAssistant.ts).

Models and rate limits

Binding or settingRole
AIWorkers AI model execution for planning, answers, and optional richer guide rendering.
DOCS_ASSISTANT_MODELAnswer/planning model; defaults to @cf/meta/llama-3.1-8b-instruct-fast in the route.
DOCS_ASSISTANT_ARTIFACT_MODELGuide rendering model; defaults to @cf/openai/gpt-oss-20b.
SESSIONSOptional KV namespace used for best-effort per-IP hourly counters.
DOCS_ASSISTANT_RATE_LIMITConfigured hourly cap; route fallback is 20.
CADCAMFUN_DOCS_SERVER and CADCAMFUN_DOCS_TOKENBoth are needed to select the alternative nikcli session backend.
CADCAMFUN_DOCS_AGENT, CADCAMFUN_DOCS_DIRECTORYOptional agent and directory for that remote backend.

The nikcli path creates or reuses a remote session, subscribes to its stream before sending the message, and applies a 90-second turn timeout. This is documentation support on a configured backend; its token is separate from the CAD/CAM application's bridge or provider credentials.

The rate limiter requires the optional KV binding and a client IP header. Its read/increment/write sequence is best-effort rather than an atomic security quota, and KV failures are allowed through. Without the binding there is no enforced per-IP cap. Do not present it as a guaranteed allocation or rely on historical model pricing claims.

Local adapter configuration disables remote bindings. The model has no local implementation in this site. A normal local article preview can work while assistant requests return 503. Configure a reachable backend or validate model behavior in the intended deployment environment.

Generated guide artifacts

A request for a guide, checklist, reference, or similar reusable page can produce an artifact draft. With ARTIFACTS R2 storage, the helper normalizes it to an HTML document and writes content plus metadata. A normalized empty document or one larger than 256 KiB is not published.

The returned link carries a ?key= read capability. Anyone with that complete link can read the artifact. The bare identifier is not sufficient; there is no owner-account login gate for these anonymous guides. Treat the key as a share credential and avoid putting private project data into a publicly shared guide.

The viewer uses a private, non-cached shell and an iframe sandbox allowing scripts and popups without same-origin permission. The raw HTML route applies a content policy that allows inline scripts/styles and embedded data/blob images but blocks external network fetches and external font/style/script loads. Generated guides must be self-contained; their layout cannot depend on the site's current DOM or local storage.

The current publishing helper writes version 1 and a new random capability. The raw route can select a valid stored version with v; an invalid or out-of-range version falls back to the latest stored version. That retrieval support does not establish a public edit/version-management API.

ARTIFACT_PUBLIC_ORIGIN can select the canonical share-link origin for non-local deployments. Missing storage returns 503 on artifact access. Missing content returns 404, and a rejected read capability returns 401. Keep generated guide storage and public documentation assets separate.

Local Studio

Studio chooses CADCAMFUN_DB, then DATABASE_URL after stripping an initial file prefix, then the repository's data/cadcamfun.db. It only opens an existing file. This selection differs from the DB package CLI's process-relative default and the native desktop's application data directory.

Login checks an existing user's stored password with Bun's password verifier. It writes a seven-day session to the application Session table and sets an HTTP-only, SameSite=Lax cookie for the local Studio. No user-registration or initial-password bootstrap is implemented by that local server. A native local profile without a password does not acquire a Studio password automatically.

Authenticated overview queries count users, projects, drawings, and toolpaths across the selected installation, then return the eight most recently updated projects. It is a local installation overview rather than a per-project ownership-filtered dashboard. Use an appropriate local database and account; opening Studio is not a reason to point it at an unrelated user's file.

The production fallback under /studio/api/* is HTTP 503. Deploying the public docs does not upload SQLite contents or turn this local tool into a hosted database service.

Deployment

wrangler.toml declares the Worker entry, static asset directory, custom domains under cadcam.fun, Workers AI, session and assistant-rate-limit KV namespaces, and the R2 artifact bucket. Wrangler provisions dedicated resources and binds them to the deployment. Configure secrets through the target Cloudflare environment. A binding name in a TypeScript interface is not proof the resource exists in the account.

The deploy script builds Astro, writes dist/.assetsignore so the Worker entry is excluded from static assets, and invokes Wrangler deployment. Deployment is a publishing operation; normal documentation verification should use build and local checks without running it.

Before publishing, validate static routes and API snapshot freshness, confirm intended bindings, verify assistant failure behavior without its backend, and check artifact capability access if storage is enabled. After publishing, inspect the resulting deployment and configured backend rather than treat a local build as evidence of a live service.

Operational diagnosis

FindingCheck
Assistant 400Valid JSON body and at least one non-empty user message after parsing/trimming.
Assistant 429The optional configured per-IP counter and current hourly bucket.
Assistant 502Whether the selected article paths can be loaded and converted in the deployment.
Assistant 503Workers AI binding or complete nikcli backend URL/token configuration.
Markdown 404The requested route must be in the navigation inventory, not an arbitrary URL.
Artifact 401Use the complete capability link including its key.
Studio 503 locallyThe selected existing SQLite file and running Bun Studio API.
Studio 503 in productionExpected fallback behavior; the deployed Worker is not the local Bun process.

Implementation sources: astro.config.mjs, wrangler.toml, script/dev.ts, script/deploy.ts, script/studio-server.ts, src/lib/docsMarkdown.ts, docsRetrieval.ts, nikcliDocsSession.ts, docsArtifact.ts, and the route handlers under src/pages.

Scripts of the docs package

ScriptRunsUse it to
devbun script/dev.tsStart the site for local editing
startastro devPlain Astro dev server
studiobun script/studio-server.tsLocal Studio against CADCAMFUN_DB, DATABASE_URL or data/cadcamfun.db
build / previewastro build / astro previewProduce and serve the production build
deploybun script/deploy.tsPublish to Cloudflare
check:freshnesscheck:docs-index then check:api-referenceFail when the search index or API reference is stale
typecheckbun check -p tsconfig.json, then check:freshnessType errors plus both freshness checks
generate:api-referencescript/generate-api-reference.mjsRegenerate the reference after a contract change

Writing a page

  1. Create src/pages/docs/<slug>.astro using DocsLayout with title, subtitle, description and a toc array whose hrefs match section ids.
  2. Write each section as <section id="…" class="doc-section"> with one <h2>.
  3. Use DocCode (language, title) for code, DocCallout (type info, warn or note) for warnings, DocCard for link grids, DocRelated at the end, and DocViewer3D for 3D previews.
  4. Escape literal braces in text as &#123; and &#125;; put code inside an expression such as {String.raw`…`}.
  5. Add the page to the sidebar data and run bun run typecheck, which also rebuilds and checks the search index.
Minimal page
---
export const prerender = true
import DocsLayout from "../../layouts/DocsLayout.astro"
import DocCode from "../../components/docs/DocCode.astro"
const toc = [{ title: "Overview", href: "#overview" }]
---
<DocsLayout title="Example" subtitle="One line." description="For search engines." toc={toc}>
  <section id="overview" class="doc-section">
    <h2>Overview</h2>
    <p>Text with an escaped brace: &#123;</p>
    <DocCode language="bash" title="Run">{`bun run typecheck`}</DocCode>
  </section>
</DocsLayout>

Verify every fact

Only document behaviour you can point to in the code, and run examples before pasting their output. The API reference is generated; hand-written pages are not.

3D previews

PropTypeMeaning
title, captionstringHeading and explanation under the canvas
solidsarraybox (size), extrude (profile, holes, height) or cylinder (radius, height), each with optional at, color, opacity
pathsarrayPolylines with points as [x, y, z], rapid (dashed) and color
heightnumberCanvas height in pixels
animatebooleanDraw paths progressively and show a replay button

The component uses three.js with Z up, mounts only when scrolled into view and shows a text fallback without WebGL. Feed it real output, such as kernel moves, rather than hand-drawn coordinates.

In 3D

Where the docs site sits: web depends only on db Drag to orbit · scroll to zoom · right-drag to pan
All 13 workspace packages from their package.json files; each line is a workspace:* dependency (17 in total). Rows are dependency depth: packages with no workspace dependencies at the front, the sidecar, which depends on 8 of them, at the back. Orange boxes are apps.