ZDDC/CLAUDE.md
ZDDC adb6904397 docs: rewrite for embedded + cascade install model
Updates every repo doc to reflect the simplified install model:

  - Local install is just a download from /releases/.
  - Server install is just running zddc-server (current-stable HTMLs
    embedded at compile time).
  - Customize via .zddc apps: cascade entries (channel/version/URL/path,
    with default + per-app composition); editor at /.profile/zddc/.

Removes references to the old install scripts, level-1/level-2 stubs,
admin UI at /.profile/apps, SHA-256 verification, TOFU writes, refresh
worker, and ZDDC_APPS_* env vars.

zddc/README.md: replaces "Landing Page and Tool Install" section with
"Apps: virtual tool HTMLs" — covers the folder-name availability rules,
the resolution chain (real-file override / cascade / embedded), spec
syntax cheat sheet, cache layout under <ZDDC_ROOT>/_app/, the ?v=
cache-only override, and the X-ZDDC-Source response header.

ARCHITECTURE.md: install-distribution-model section rewritten to
describe the embed-first / cascade-override model with one canonical
example.

AGENTS.md, CLAUDE.md: short-form summaries pointing at the same model.

README.md: install bullet rewritten.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-01 15:25:57 -05:00

7.1 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Authoritative docs — read these first

This repo already has two thorough agent-facing references. Always consult them before working — they cover details intentionally omitted here:

  • AGENTS.md — commands, build-system rules, per-tool parser quirks, testing gotchas, git/worktree workflow, release process, zddc-server notes
  • ARCHITECTURE.md — single-file HTML pattern rationale, JS module/state patterns, per-tool architecture, security model

If something in this CLAUDE.md conflicts with those, those win — and please update them rather than letting drift accumulate.

Repo shape

This is a monorepo of independent tools, not one application:

  • archive/, transmittal/, classifier/, mdedit/, landing/ — five self-contained HTML tools, each compiled to a single inlined HTML file in its own dist/. Naming: the first four output dist/tool.html; landing/ outputs dist/index.html (it's the project picker served at the root of zddc-server).
  • zddc/ — Go HTTP server (separate sub-project; Go 1.24+). Serves ZDDC_ROOT/index.html at GET / as the landing page; Accept: application/json on / returns the ACL-filtered project list. Stable releases ship as cross-compiled binaries on Codeberg release assets; the helm/ charts in this repo build from source at deploy time.
  • shared/base.css plus shared JS modules (zddc.js, hash.js, zddc-filter.js, theme.js, help.js) included by every tool's build, build-lib.sh (POSIX sh helpers sourced by every tool's build.sh), and publish-codeberg-release.sh (used by zddc/release.sh to upload zddc-server binaries — HTML tools no longer use it).
  • website/ — committed static site: index.html (root URL, hand-edited intro), releases/<tool>_v<X.Y.Z>.html (immutable per-version archives), releases/<tool>_v<X.Y>.html and _v<X>.html (symlinks), releases/<tool>_{stable,beta,alpha}.html (channel mirrors), releases/index.html (regenerated by build.sh). Install model: local use is a download from /releases/. Server use is zddc-server, which has the current-stable build of all five tools baked in via //go:embed (compile-time default). Tools auto-served at folder-name-driven paths: archive everywhere, classifier in Incoming/Working/Staging subtrees, mdedit in Working subtrees, transmittal in Staging subtrees, landing only at root. Override via .zddc apps: cascade entry (channel/version/URL/path) — fetched once, cached at <ZDDC_ROOT>/_app/. Drop a real .html file at any path to override.
  • helm/ — example Helm charts for zddc-server (zddc-server-prod/, zddc-server-dev/). Both compile from source via init container. Operators copy values.yaml.example and customize. No secrets in repo.
  • tests/ — Playwright specs (Chromium only, requires File System Access API). tests/schema.spec.js validates transmittal.schema.json against canonical fixtures via ajv (only dev dep besides Playwright)

Most-used commands

sh build.sh                                 # build all five HTML tools (dist/ only) + regen website/releases/index.html
sh tool/build.sh                            # build one (archive|transmittal|classifier|mdedit|landing)
sh tool/build.sh --release [version]        # cut stable; write website/releases/<tool>_v<X.Y.Z>.html, refresh 5 symlinks, tag <tool>-vX.Y.Z
sh tool/build.sh --release alpha|beta       # cut channel; overwrite website/releases/<tool>_<channel>.html in place. No tag (channel URLs are stable URLs by design)
./freshen-channel <tool> <channel>          # rebuild alpha/beta from current stable tag (run after every stable release if you want to advance the channel mirror)
npm test                                    # all Playwright specs (build first!)
npx playwright test <tool>                  # one spec
./dev-server start  # ./dev-server stop     # cache-busting HTTP on :8000

# zddc/ Go server (separate sub-project, not part of sh build.sh)
(cd zddc && go test ./...)                  # unit tests (Go 1.24+)
sh zddc/release.sh [<version>]              # cut stable zddc-server release; tags + cross-compiles binaries + uploads to Codeberg. Stable-only (no alpha/beta channel for binaries).

No lint/typecheck/format commands exist for the HTML tools — vanilla JS + POSIX sh by design.

Things that bite if you forget

  • dist/ is gitignored. tool/dist/<tool>.html is the canonical built artifact for testing and as the source for --release writes. Never hand-edit a dist/ file.
  • website/releases/ is committed. Per-version files (<tool>_v<X.Y.Z>.html) are real immutable files; partial-version pins (<tool>_v<X.Y>.html, <tool>_v<X>.html) and channels (<tool>_<channel>.html) are checked-in symlinks. Stable cuts write the new versioned file + refresh the 5 symlinks (cascade rule: stable cut → beta + alpha both reset to the new stable). Beta/alpha cuts overwrite their channel mirror in place; on a beta cut, alpha cascades to point at beta.
  • No tags for alpha/beta. Channel URLs are stable URLs by design — appending counter tags would defeat the purpose. The on-page label encodes <date> · <sha> for traceability. Stable cuts still get clean <tool>-vX.Y.Z tags.
  • Pre-release semver in the on-page label. Plain dev builds and --release alpha|beta cuts embed vX.Y.Z-{alpha,beta} in {{BUILD_LABEL}} where X.Y.Z is the next-stable target (patch+1 from latest clean <tool>-vX.Y.Z tag). Plain dev adds a full timestamp + -dirty marker; --release alpha|beta is date-only.
  • Plain sh tool/build.sh is a dev build. Writes dist/<tool>.html only; no website/releases/ side-effect. To publish, re-run with --release alpha.
  • Always build before running tests — Playwright opens dist/tool.html via file://.
  • </ in JS string/template literals breaks inline <script> embedding. shared/build-lib.sh provides escape_js_close_tags; every tool's build.sh runs JS through it before inlining.
  • All ZDDC parsing/formatting/hashing goes through window.zddc (from shared/zddc.js + shared/hash.js + shared/zddc-filter.js). API: parseFilename, parseFolder, parseRevision, formatFilename, formatFolder, compareRevisions, isValidStatus, splitExtension, joinExtension, crypto.{sha256Hex, sha256String, sha256File, bytesToHex}, filter.{parse, matches}. File objects across tools use trackingNumber (string) and extension (string, no leading dot — use zddc.joinExtension(name, ext) to build a filename). Add edge cases to tests/zddc.spec.js, not per-tool tests.
  • Two globals only: window.app (per-tool app state + modules) and window.zddc (shared library). No others — anything that crosses tool boundaries goes through one of these.
  • Worktrees live at ~/src/zddc-<branch>. Check git worktree list before starting a feature branch; never git checkout/switch inside a worktree another agent might be using.
  • Build scripts are POSIX sh with set -eu, not bash. concat_files takes positional args only.