# Clavitor Website — clavitor.com ## Foundation First — No Mediocrity. Ever. The rule is simple: do it right, or say something. Johan is an architect. Architects do not patch cracks in a bad foundation — they rebuild. Every agent on this team operates the same way. **What this means in practice:** - If you need three fixes for one problem, stop. Something fundamental is wrong. Name it, surface it — we fix that, not the symptom. - If the code is spaghetti, say so. Do not add another workaround. The workaround is the problem now. - Quick fixes are not fixes. A "temporary" hack that ships is permanent. If it is not the right solution, it is the wrong solution. - Foundation > speed. A solid base makes everything downstream easy. A shaky base makes everything downstream a nightmare. We build bases. **The restart rule:** When the foundation is wrong: start over. Not "refactor slightly." Not "add an abstraction layer on top." Start over. This applies to code, infrastructure, design, encryption schemes, and written work alike. **Q&D is research, not output:** Exploratory/throwaway work has its place — but it stays in research. Nothing Q&D ships. Nothing Q&D becomes the production path. If a spike reveals the right direction, rebuild it properly before it counts. **When you hit a bad foundation:** Call it out. Do not work around it. Bad foundations are not your fault — but silently building on them is. Surface the problem, we work on it together. The bar is high. The support is real. These rules apply to you now. ## Architecture - Go web server (`main.go`) with `go:embed` for templates, CSS, SVGs, PNGs - Templates in `templates/*.tmpl`, single CSS in `clavitor.css` - SQLite DB: `clavitor.db` (pops, telemetry, uptime, incidents, accounts, vaults, sessions) - Dev mode: auto-detected when `templates/` dir exists on disk — reloads templates per request, but CSS/SVGs require rebuild (`go:embed`) - Port 8099 - License: Elastic License 2.0 (NOT MIT) ## Deployment ### Dev (forge = 192.168.1.16, Florida — dev.clavitor.ai) ``` make dev # build + restart locally make deploy-dev # same thing ``` Dev runs on forge (localhost). `dev.clavitor.ai` DNS points to home IP. ### Prod (Zürich — clavitor.ai — clavitor.ai) ``` make deploy-prod # cross-compile amd64, scp to Zürich, restart systemd ``` Prod runs at `/opt/clavitor-web/` as systemd service `clavitor-web`. Caddy reverse proxies `clavitor.ai`, `clavitor.com`, `www.clavitor.ai`, `www.clavitor.com` → `localhost:8099`. ### First-time setup (already done) ``` make setup-prod # creates /opt/clavitor-web, systemd service, uploads binary+db ``` Then manually update `/etc/caddy/Caddyfile` to reverse_proxy. ### SSH - Prod: `ssh root@clavitor.ai` - Tailscale: `zurich` (100.70.148.118) — SSH may be blocked via Tailscale ## Build & Run ``` CGO_ENABLED=1 go build -o clavitor-web . ./clavitor-web ``` CSS and SVG changes require rebuild (embedded at compile time). Template changes reload in dev mode. ## Brand & Design - Light mode only. Single source of truth: `clavitor.css` - Logo: the black square (`#0A0A0A`). favicon.svg = black square - Colors: black `#0A0A0A` (brand), red `#DC2626` (accent), light red `#F5B7B7` (planned/secondary), grayscale - No purple. No green (except inherited SVG diagrams). Red is the only accent. - Square shapes for permanent UI elements. Circles only for transient animations (pulses, "You" dot) - Fonts: Figtree (body), JetBrains Mono (code/monospace) - No inline styles, no CSS in templates. Everything in clavitor.css. - Always capitalize "Clavitor" in prose. Lowercase in code/paths/commands. ## Encryption Terminology - **Vault Encryption** — whole vault at rest - **Credential Encryption** — per-field, server-side (AI agents can read via CLI) - **Identity Encryption** — per-field, client-side via WebAuthn PRF (Touch ID only, server cannot decrypt) - Never use "sealed fields", "agent fields", "L1", "L2", "L3" - Agents use CLI, NOT MCP (MCP exposes plaintext; CLI is scoped) ## POPs (Points of Presence) - Stored in `pops` table in clavitor.db — the single source of truth - Map on /hosted is generated dynamically from DB via JavaScript - Zürich = HQ, black dot, larger (11×11). Live POPs = red. Planned = light red. - "You" visitor dot = circle (not square — "you" is not clavitor) ## Key URLs - `/hosted` — hosted product page with dynamic world map - `/glass` — looking glass (latency from user's browser) - `/noc?pin=250365` — NOC dashboard (telemetry, read-only, hardcoded PIN) - `/telemetry` — POST endpoint for POP agent heartbeats (no auth) - `/ping` — server-side TCP ping (for diagnostics) ## Vault Binary - Source: `~/dev/clavitor/clovis/clovis-vault/` - Build for ARM64: `cd ~/dev/clavitor/clovis/clovis-vault && GOOS=linux GOARCH=arm64 CGO_ENABLED=0 go build -o clavitor-linux-arm64 ./cmd/clavitor` - All POPs are ARM64 (AWS t4g.micro) - Vault runs on port 1984 with TLS - Has `/ping` endpoint (11 bytes, no DB, CORS via middleware) for looking glass - Has `/health` endpoint (heavier, queries DB) ## Providers - AWS: most POPs (free tier t4g.micro) - LightNode: Santiago, Bogotá, Manila, Dhaka - ishosting: Istanbul, Almaty - HostAfrica: Lagos, Nairobi - Rackmill: Perth