Deploy and operate the examiner
Publish the guide, deploy the private engine, and verify the exact release while preserving existing jobs and reports.
Prerequisites
You need repository access and operator access to GitHub Actions, Cloudflare, and Coolify. Read the repository’s AGENTS.md before changing a running service.
For a local documentation build, install mdBook 0.5.4, Python 3.11 or newer, and Node.js 22 or newer. For engine checks, install Python 3.12 or newer and uv.
These are two deployments:
| Component | Platform | Contents |
|---|---|---|
| Documentation | Coolify on the owner’s VPS | Public guides, agent exports, and fictional teaching examples |
| Examination engine | Coolify on the owner’s VPS | Private case PDFs, model credentials, durable jobs, and authenticated MCP |
The documentation does not proxy examination credentials or private reports. Testers connect to the engine using their own configured pilot key.
Publish a documentation change
-
Update the affected Markdown chapters, navigation, examples, and media in
docs-site/. Keep the default mdBook theme. -
From the repository root, build and check Worker packaging:
cd docs-site npm ci npm run build npm run deploy:dry-runExpected result: mdBook builds every chapter, the Markdown exports exist in
out/, and Wrangler’s packaging check exits zero. -
Preview with
npm run dev. Check the changed workflow, search, links, images, and downloads. Save browser evidence for visible changes. -
After an authorized push, wait for the
Verify field guideworkflow to build that Git revision and upload its checked static artifact. -
Deploy the same revision in Coolify using the Dockerfile configuration below, then run the published-documentation verifier and save its report.
The workflow installs checksum-verified mdBook 0.5.4 and frozen npm dependencies. It checks the book and preserves the static artifact without deploying to Cloudflare. After the Coolify release, compare the live chapters, search assets, diagrams, downloads, and agent exports with the exact deployed build.
The retained Worker commands support an authorized rollback. Regular documentation releases use Coolify.
Verify the published documentation
From docs-site/, after building the exact revision you deployed:
VERIFIED_COMMIT="$(git rev-parse HEAD)" \
DOCS_PUBLIC_URL="https://title-examiner-docs.ayushworks.com" \
python3 scripts/verify_docs.py
Success: the command exits zero and ci-results/docs-deployment.json has state: "verified" with the expected published commit. Inspect the rendered site too; byte comparisons do not prove that a procedure is understandable.
A mismatched revision means the live site has not been verified against your checkout. A 404 or content mismatch on a known guide requires investigation before calling the release complete.
Host the documentation in Coolify
Use the Dockerfile build pack with base directory /docs-site, Dockerfile /Dockerfile, and container port 3000. Set the build arguments VERIFIED_COMMIT to the full source Git SHA and DOCS_PUBLIC_URL to the intended HTTPS origin. The image installs checksum-verified mdBook 0.5.4 and mdbook-mermaid 0.17.1, then builds and checks the guide. Its build stage requires Docker’s Linux AMD64 support.
The Node server reuses the same Worker routing for Markdown negotiation, legacy paths, discovery headers, and missing pages. It serves only the generated public book. No engine credentials, cases, or runtime volumes are needed.
Build a candidate locally from the repository root, replacing the public origin:
docker build -f docs-site/Dockerfile \
--build-arg VERIFIED_COMMIT="$(git rev-parse HEAD)" \
--build-arg DOCS_PUBLIC_URL=https://your-guide-host \
-t title-examiner-docs docs-site
After deploying the candidate behind HTTPS, run the same published-documentation verifier against its origin and exact build. Check the rendered book and save browser evidence. Change the public route only after those checks pass, and keep the GitHub workflow limited to verification and artifacts. Keep the previous deployment available for recovery until the cutover is verified.
Deploy the private engine
The tracked deployment manifest is deploy/coolify-mcp.git.compose.yml. It describes the current GitHub App-backed Coolify application with Raw Compose Deployment enabled. The manifest’s build context is the repository root.
The manifest configures:
- An unprivileged container and a read-only input mount.
- External output and job-state volumes, so a rebuild does not replace saved jobs.
- An HTTPS proxy route, with no directly published host port.
- Bearer authentication, one active examination, and the hosted
bfsrestriction. - Browser sourcing and purchase host gates set to
0.
The container’s TCP healthcheck proves that a socket listens. It does not verify credentials, MCP calls, or report retrieval.
Check before cutover
- Inspect queued and running jobs through operator-side records. The public tools have no job-list operation. Arrange a maintenance window if work is active.
- Record the current source SHA, image, Compose configuration, and durable volume names. Retain the previous image and a verified backup for recovery.
- Confirm the candidate uses the intended hostname and proxy route. For a rehearsal, use separate external output/job volumes.
- Confirm protected provider credentials and the MCP key exist on the host. Build steps do not need provider secrets. Runtime startup requires the bearer key.
- Preserve the original volumes during cutover. Run one worker-owning deployment against the production job volume.
Set MCP_PUBLIC_HOST, MCP_HOST_DATA_DIR, and MCP_HOST_ENV_FILE in the deployment environment. Coolify requires the simple ${MCP_HOST_DATA_DIR} form in volume sources. Configure this variable before deploying and verify that it resolves to the intended private directory. A Compose extension checks that it is set, so a missing or empty value fails before Docker can substitute the working directory. The legacy prebuilt-image examples also require MCP_IMAGE. Before deploying the configurable registry, install the operator’s surveys.local.json inside the mounted data directory. Check that list_surveys returns the expected cases; an empty registry is a valid new installation, not evidence that migration succeeded.
The runtime env_file supplies host secrets. An empty environment entry in Compose overrides an inherited value, so do not add blank provider keys. The manifest permits the build helper to skip the absent host file through required: false; this does not make runtime authentication optional.
Verify the automatic deployment
The Verify and deploy MCP workflow runs on the deployment branch. It checks locked dependencies, lint, regressions, ownership and sourcing boundaries, and the runtime image before deployment.
The helper scripts/deploy_mcp.py requests the exact verified source commit, waits for Coolify’s terminal deployment result, checks its source SHA, and performs authenticated protocol smoke checks.
Success: both workflow jobs pass, and mcp-deployment-<commit>/mcp-deployment.json records the verified deployment and public checks. A queued request or healthy socket is insufficient.
Coolify’s automatic push deployment is disabled for this application so the checked workflow controls the release. Preserve that arrangement when changing its configuration.
Check the public MCP boundary manually
With the operator’s endpoint and MCP_HTTP_API_KEY in the protected root environment, replace the endpoint placeholder and run from the repository root:
uv run --extra mcp python scripts/smoke_mcp.py \
--url https://your-examiner-host/mcp
This check initializes MCP, discovers tools, and lists surveys. It does not start a paid job. Use --job-id for an existing job when checking preserved state; add --artifact to read an available report.
Verify unauthorized requests are rejected and hosted agent requests are refused. The deployment helper performs these checks without launching an examination. Keep its safe result report; detailed provider failures belong in protected host logs.
Configure automation access
| Workflow | Protected secrets | Non-secret configuration |
|---|---|---|
| Documentation | CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID | DOCS_PUBLIC_URL |
| Engine | COOLIFY_TOKEN, MCP_SMOKE_BEARER | COOLIFY_URL, COOLIFY_APPLICATION_UUID, MCP_PUBLIC_URL |
Use a Cloudflare token scoped to the intended account’s Workers deployment and a Coolify token with the required read, write, and deploy permissions. Track credential expiry in the operator’s private access inventory and replace the Actions secrets before expiry.
The smoke helper makes no paid start, but MCP_SMOKE_BEARER is the same shared credential that can authorize billable examinations. Treat it accordingly. Provider keys remain on the host.
Recover from a failed release
- Stop the candidate or managed application through the operator’s deployment controls. Preserve its durable volumes and private records.
- Restore the retained exact prior image and configuration with the original output/job volumes.
- Start one service against that job state. Check authentication, tool discovery, and saved job/artifact access.
- Record the restored source revision and the checks that passed. Investigate the failed candidate before retrying deployment.
Rollback restores runtime code. It does not reverse provider charges or erase completed jobs. Backup restoration is a separate operation that requires checking which saved work would be replaced.
Maintain the release
Update guides in the same change as tools, setup, output formats, limits, or deployment behavior. At each pilot handoff, review setup instructions and credentials’ expiry. Use the pilot feedback format to collect documentation failures.
For worker failures, inspect the protected job log and distinguish provider quota, memory, routing, and code errors. Use Troubleshooting for the safe messages testers can report.