# AGENTS.md — ZDDC ## Commands ```bash # ── ./build subcommands ──────────────────────────────────────────────────── # `./build` (no arg) is a source-side dev build only — assembles tool/dist/ # + cross-compiles zddc-server. dist/release-output/ and the live site are # left alone. Channel + release subcommands produce a complete release # bundle in dist/release-output/ (gitignored). Run `./deploy` to publish. # Workflow: alpha = active dev → beta = ready for testing → release = ship. ./build # dev build (no release bundle) ./build alpha # cut alpha (cascades nothing) ./build beta # cut beta (cascades alpha → beta) ./build release # cut stable, coordinated next version # (cascades alpha + beta → new stable; tags all seven) ./build release 1.2.0 # cut stable at explicit version ./build help # ── ./deploy subcommands ──────────────────────────────────────────────────── # rsync the build output and content repo to /srv/zddc/ (Caddy's bind-mount). # --delete-after — the live tree exactly mirrors source. ./deploy # full sync (content + releases) ./deploy --content # only ~/src/zddc-website/ → /srv/zddc/ ./deploy --releases # only dist/release-output/ → /srv/zddc/releases/ # Single-tool dev build for testing (does NOT touch dist/release-output/): sh tool/build.sh # archive|transmittal|classifier|mdedit|landing|form # Single-tool release (rare; prefer ./build alpha|beta|release so versions # don't drift between tools). Same flag form as before. sh tool/build.sh --release [|alpha|beta] ./freshen-channel # rebuild one tool's alpha/beta from its current stable tag # Test all tools npm test # Test single tool npx playwright test tool # archive | transmittal | classifier | mdedit | form-safety # Dev server (cache-busting HTTP, on port 8000) ./dev-server start ./dev-server stop ``` No lint, typecheck, or format commands exist — the project is plain sh + vanilla JS. Channel/release cuts seed `dist/release-output/` from the current `/srv/zddc/releases/` (preserving symlinks) before running per-tool promote, then mutate the channels being cut on top. The bundle is therefore always a complete intended-live snapshot, not a sparse diff. The build ends with a **channel-link verifier** that asserts every `_{stable,beta,alpha}.html` (and zddc-server's per-platform binary mirrors + stub pages) resolves. Build fails if any link is dangling — because the bundle is complete, dangling-link errors mean a real bug. **Nothing is pushed automatically.** Run `./deploy` to publish; commit + push source changes to `main` separately. ## Architecture Six independent single-file HTML tools (`archive`, `transmittal`, `classifier`, `mdedit`, `landing`, `form`). Each compiles to one self-contained `.html` in `dist/` with all CSS and JS inlined — most name their output `dist/tool.html`; `landing` writes `dist/index.html` (served at `/` by `zddc-server`). Tools share a small set of canonical helpers in `shared/` (filename parsing, ZDDC filter UI, theme, help) — see "Shared modules" below. The sixth tool, `form`, is the schema-driven renderer used by zddc-server's form-data system; see "Form-data system" below. ``` tool/ css/ source stylesheets (concatenated in order) js/ vanilla JS IIFEs (concatenated in order) template.html placeholder markers: {{CSS_PLACEHOLDER}}, {{JS_PLACEHOLDER}}, {{BUILD_LABEL}} build.sh assembles dist/tool.html dist/tool.html generated output — committed with `git add -f` shared/ base.css CSS tokens and primitives included first by every tool's CSS build zddc.js canonical filename/folder/revision parsers, formatters, status validation zddc-filter.js shared ZDDC project/status filter UI module theme.js light/dark theme switcher help.js shared help dialog module build-lib.sh POSIX sh helpers (ensure_exists, concat_files, build_timestamp) sourced by every tool's build.sh via: . "$root_dir/../shared/build-lib.sh" # Hand-edited website content lives in a SEPARATE Codeberg repo # (codeberg.org/VARASYS/ZDDC-website), typically cloned at # ~/src/zddc-website/. Just content — no releases, no LFS: # index.html, reference.html, css/, js/, img/ hand-edited content # README.md, LICENSE repo housekeeping # # This repo's ./build produces a release bundle in dist/release-output/ # (gitignored, local-only). ./deploy rsyncs both into /srv/zddc/ on # the deploy host (Caddy's bind-mount): # /srv/zddc/ # index.html, reference.html, css/, js/, img/ ← from ~/src/zddc-website # releases/ # index.html regenerated by `./build` # _v.html per-version (immutable) # _v.html -> ... symlink chain # _stable.html -> ... channel mirror, follows latest stable # _{beta,alpha}.html -> ... channels (cascade to stable when idle) # zddc-server_v_ per-platform binary (raw bytes, no LFS) # zddc-server__ channel binary mirror (symlink) # zddc-server_.html stub page surfacing 4 platform DLs helm/ zddc-server-prod/ production-shaped Helm chart (compiles from source via init container) zddc-server-dev/ dev-shaped variant (tracks main HEAD; debug-level logging; faster probes) README.md chart design rationale + quick-start ``` **Critical:** `dist/` files are gitignored. `tool/dist/.html` is the canonical built artifact for testing and the source for `--release` writes into `dist/release-output/`. `dist/release-output/` is the local-only release bundle. Neither is in git. Never edit them directly. **Two-repo + deploy-host model.** Source code lives here (`codeberg.org/VARASYS/ZDDC`); hand-edited website content lives in a separate repo (`codeberg.org/VARASYS/ZDDC-website`, typically cloned at `~/src/zddc-website/`). The live site at `zddc.varasys.io` is `/srv/zddc/` on the deploy host (Caddy bind-mount), populated by `./deploy`. Release artifacts are NOT in git — they're produced by `./build alpha|beta|release` into `dist/release-output/` and rsync'd to `/srv/zddc/releases/` by `./deploy --releases`. Per-version files (HTML and zddc-server binaries) are real immutable bytes; partial-version pins (`_v`, `_v`) and channel mirrors (`_stable`, `_beta`, `_alpha`) are symlinks. `shared/build-lib.sh` provides `promote_release` (HTML tools) and `promote_zddc_server` (binaries + matching stub pages); the top-level `./build` seeds from live state, then calls them in lockstep. Older releases are reproducible from any `-vX.Y.Z` tag in this repo (`git checkout zddc-server-v0.0.8 && ./build release 0.0.8`). No Codeberg release assets, no LFS. ## Shared CSS (`shared/base.css`) Included as the **first** positional arg to every tool's `concat_files` CSS call. Provides: - `:root` CSS custom properties — `--primary`, `--bg`, `--text`, `--border`, `--font`, etc. - Brand color: `--primary: #2a5a8a` (matches zddc.varasys.io) - Button primitive: `.btn`, `.btn-primary`, `.btn-secondary`, `.btn-sm`, `.btn-lg`, `.btn-link` - `.app-header` + `.app-header__title` chrome rules - `.build-timestamp`, `.hidden`, `.truncate`, webkit scrollbars **Do not** define these in any tool's own CSS — they come from shared. **Toast CSS** lives in `classifier/css/base.css` only (classifier is the only tool that uses toasts). ## Transmittal CSS quirks - `transmittal/css/base.css` overrides `html { font-size: 16px }` inside `@media screen` — this must stay. `shared/base.css` sets `14px`; transmittal's floating labels are rem-based and were designed for 16px. - The floating label position is defined in `transmittal/css/forms.css`, not Tailwind classes. If adding new Tailwind classes to `template.html`, add them to `transmittal/css/utilities.css` too — there is no Tailwind build step. ## Build system rules - Every `build.sh` sources `shared/build-lib.sh` first (provides `ensure_exists`, `concat_files`, `build_timestamp`). Set `root_dir` before sourcing. - Build scripts use **POSIX sh** (`#!/bin/sh` with `set -eu`), not bash. - `concat_files` accepts **positional args only** (not array names). - `awk` processes `template.html`, replacing `{{PLACEHOLDER}}` markers and stripping CDN `