Skip to main content

The knowledge base — publishing the docs

Audience: developers & AI agents · Scope: the published site at kb.betacalco.com — what it is, how content flows there, and the two deploy channels that must stay separate · Last reviewed: 2026-08-27

TL;DR — Everything under docs/ and admin-guide/ is published as a searchable site at https://kb.betacalco.com, with a docs assistant and an MCP endpoint on top. It is built by a separate repo (beta-calco/documentation) from the GitHub mirror of this one, and it deploys through a separate channel from the website: publishing docs never deploys code, and deploying code never publishes docs. To publish docs now: tools/kb-publish.sh.

Two channels, on purpose

The websiteThe knowledge base
Whatdocroot/ — the Joomla/ConfigBox sitedocs/ + admin-guide/ rendered by Docusaurus
Source of truthbranches for_live / for_staging on the bare SSH reposbranch master on the GitHub mirror beta-calco/betacalco-site
Triggergit push live master:for_live (post-receive hook rsyncs docroot/)tools/kb-publish.sh, a daily sync, or a push to the mirror (see below)
Where it runsthe live/staging EC2 serversAWS account 770497312327, us-east-1: S3 + CloudFront + one Lambda
Docconfigbox/environment.mdthis page, and DEPLOYING.md in the KB repo

A future CI/CD pipeline for the website belongs on the left column and changes nothing on the right.

How a doc gets to the site

docs/, admin-guide/ on master
│ git push github master ← tools/kb-publish.sh step 1 (nothing deploys from the mirror)

beta-calco/betacalco-site (GitHub mirror)
│ workflow_dispatch (ref=<sha>) ← step 2; also: daily 06:00 UTC, or .github/workflows/kb-publish.yml

beta-calco/documentation · .github/workflows/deploy.yml
├─ build: sync the two trees from the mirror → rewrite links → Docusaurus build
├─ deploy: S3 sync + CloudFront invalidation → https://kb.betacalco.com
└─ publish-mcp: arm64 image → ECR → Lambda → /mcp (MCP server) and /chat (assistant)

The sync (scripts/sync-docs.mjs in the KB repo) is where the repo-shaped docs become site-shaped:

  • Relative links between docs stay relative; links across the two trees become site routes.
  • Links into code (docroot/…, tools/…) become GitHub URLs — there is no page for them.
  • _-prefixed planning docs (_known-issues.md, _todo.md) are not published; links to them become GitHub URLs too, so a doc may cite a known issue without breaking the build.
  • .html companion pages are served from the site's static/ at the same path.
  • Frontmatter is completed, never overwritten: every page gets a title and a "View source" link.

The build runs with onBrokenLinks: throw: a link that resolves in the repo but not on the site fails the run, and the site keeps serving the previous build. gh run view <id> --repo beta-calco/documentation --log-failed lists exactly which links.

Publishing

Now: commit, then

tools/kb-publish.sh # push master to the mirror, build + deploy that commit, wait, print the URL
tools/kb-publish.sh --no-wait # same, don't wait
tools/kb-publish.sh --dry-run # show what would happen

It refuses to run off master or with uncommitted changes under docs//admin-guide/, and needs only the github remote and a logged-in gh. The push carries the whole of master (code included) to the private mirror — that is what the mirror is for; nothing deploys from it.

Automatically: .github/workflows/kb-publish.yml runs on the mirror on every push to master that touches docs/** or admin-guide/** and dispatches the KB build for that commit. It needs one secret on the mirror repo, KB_DISPATCH_TOKEN (fine-grained PAT, Actions: read & write on beta-calco/documentation, nothing else); until that exists it exits with a notice.

Fallback: the KB syncs the mirror every day at 06:00 UTC regardless.

What is on the site

  • Both trees, as two sidebars: Developer Docs (docs/) and Admin Guide (admin-guide/).
  • The docs assistant (right rail, "Ask the docs"): grounded answers with citations, over the same corpus, via /chat (streaming) on the Lambda. Its model key lives in Secrets Manager, not in any repo.
  • The MCP endpoint at https://kb.betacalco.com/mcp for tools that want to search the docs; it needs a bearer token (MCP_API_TOKENS in the same secret).
  • The site is public-by-obscurity: no login, X-Robots-Tag: noindex. Deciding on real access control is an open item in the KB repo's TODO.md.

Where the pieces live

PieceWhere
Site source, sync script, Terraform, workflow, runbook~/PhpstormProjects/betacalco-docs · GitHub beta-calco/documentation (main)
Go-live runbook, account facts, the gotchas met on the wayDEPLOYING.md in that repo
InfrastructureTerraform in infra/ — S3 betacalco-docs-prod-site, CloudFront E1X9Q25CGD6GPB, Lambda betacalco-docs-prod-mcp, ECR, the GitHub-OIDC deploy role; DNS record in the betacalco.com zone (account 752918619438)
Credentials the pipeline readsGitHub secrets on beta-calco/documentation: DOCS_SOURCE_TOKEN (reads this repo), AWS_DEPLOY_ROLE_ARN; runtime keys in AWS Secrets Manager