diff --git a/CLAUDE.md b/CLAUDE.md index 48259eb..56e1c2e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,28 +1,171 @@ # CLAUDE.md — OTIVM Project This file is read automatically by Claude Code at the start of every session. -Read it completely before doing anything else. +Read it completely before doing anything else. It describes not just the project +but exactly how the development process works — including how Claude chat, Claude +Code, and the human work together. A new assistant who skips this file will +immediately make mistakes that waste the session. --- ## What OTIVM Is -A browser-based Roman merchant idle game. One screen, one resource loop. -The narrative unfolds through trade goods and journal entries. -It is a standalone light-hearted project — not part of CIVICVS or TESSERA infrastructure. +A browser-based Roman merchant idle game. The narrative unfolds through trade +goods and journal entries. It is a standalone light-hearted project under TheRON, +but it is built on the same H3/TESSERA substrate as the CIVICVS Mesolithic +Simulator. Every architectural decision is permanent and load-bearing for future +releases up to OTIVM-X. **Live URL:** https://otium.civicus.us **Repo:** https://gitea.barternetwork.us/TheRON/OTIVM (branch: main) +**Roadmap:** docs/roadmap.md — read it to understand where this is going + +--- + +## The Three-Shell Model — Read This First + +Development always uses three terminal shells simultaneously. Each shell has one +fixed role and must never be used for another role's work. + +### Shell 1 — Claude Code shell (otivm user) +- Started by typing `work` at the otivm prompt +- `work` is an alias for: `cd ~/OTIVM && claude` +- This shell runs Claude Code continuously for the entire session +- Claude Code reads CLAUDE.md on startup, checks git status, checks pm2 list +- All file writes, git commits, and git pushes happen here and nowhere else +- Do not use this shell for npm commands, pm2 restarts, or manual file edits + +### Shell 2 — otivm shell (otivm user) +- A second terminal logged in as otivm, in ~/OTIVM +- Used for: npm install, npm run build, pm2 restart, curl tests, git pull +- The Proxmox console drops the otivm user directly into ~/OTIVM with venv active +- Treat every Proxmox console visit as a fresh terminal — no scroll-back history + +### Shell 3 — root shell (root user) +- Used only for: vzdump backups, pct commands, chown fixes, systemctl for PM2 +- Never run pm2 as root — PM2 belongs to the otivm user +- Never modify /opt/civicvs or /opt/civmap from this shell + +--- + +## How Claude Chat and Claude Code Divide Responsibilities + +These are two different Claude instances with different roles. +Confusing them is the most common source of wasted sessions. + +### Claude chat (claude.ai in the browser) +- Reads the repo via Gitea MCP (read-only access to gitea.barternetwork.us) +- Discusses architecture, makes decisions, designs files +- Produces one file at a time as a downloadable attachment +- Each file has a Claude Code instruction header at the top, followed by the + file content that Claude Code writes to disk +- Claude chat does NOT write to disk, does NOT commit, does NOT push + +### Claude Code (running in Shell 1 on the container) +- Receives one file at a time — the human downloads it from Claude chat and pastes it +- Reads the instruction header at the top of the file +- Writes the content below the instructions to the path specified in the header +- Commits and pushes to Gitea +- Does NOT design, does NOT make architectural decisions +- Does NOT modify content — writes exactly what is given +- Confirms what it did in one sentence — does not reprint file contents + +### The human +- Downloads the file from Claude chat +- Pastes it into Claude Code (Shell 1) +- Runs build and test commands in Shell 2 (otivm shell) +- Runs backup commands in Shell 3 (root shell) +- Confirms results before the next step begins + +--- + +## The Exact Workflow — Step by Step + +Every change to the codebase follows this sequence without exception: + +1. Claude chat discusses the change and produces one downloadable file +2. The file header contains the Claude Code instruction (path, commit message) +3. The file body contains the exact content to write to disk +4. Human downloads the file from Claude chat +5. Human pastes the file into Claude Code (Shell 1) +6. Claude Code reads the instruction header, writes the content to the specified path +7. Claude Code commits and pushes to main +8. Human runs `npm run build` in the otivm shell (Shell 2) +9. Human runs `pm2 restart otivm` in Shell 2 +10. Human confirms the result in the browser at https://otium.civicus.us +11. Human reports the result back to Claude chat +12. Claude chat proceeds to the next step + +**One file. One step. One confirmation. Never batch.** + +--- + +## What Claude Code Must Never Do + +- Never modify file contents — write exactly what is given +- Never reformat code — indentation, spacing, structure are intentional +- Never add imports, exports, or dependencies not in the instruction +- Never run npm install without explicit instruction +- Never run pm2 as root +- Never commit without explicit instruction to commit +- Never push to any branch other than main +- Never reprint long file contents back into chat — confirm with one sentence + +--- + +## What Claude Chat Must Never Do + +- Never print file contents or code blocks in the chat window +- All files and instructions are produced as downloadable attachments only +- Printing code in chat wastes context window and shortens the session +- Never make assumptions about what is on disk — always read from Gitea MCP first + +--- + +## Deployment Facts — Do Not Guess These + +These facts were learned during initial deployment. They are not in any tutorial. + +- PM2 ecosystem file must be named `.cjs` not `.js` — Vite sets `"type": "module"` + in package.json which breaks CommonJS `module.exports` +- PM2 ecosystem file uses absolute path `/usr/bin/node` for the script field +- Always run `pm2 start ecosystem.config.cjs` from `~/OTIVM`, not from `~` +- PM2 startup is configured via systemd unit `pm2-otivm.service` — do not run + `pm2 startup` again +- `pm2 save` must be run after any change to the process list +- Nginx for `otium.civicus.us` lives on wg-pk (198.58.111.109), not on this + container — do not look for a vhost here +- The app is proxied from wg-pk to this container at `10.110.0.18:3000` +- The Proxmox console loses scroll history on every container switch — treat + every shell session as fresh --- ## Stack -- React 19 + Vite frontend -- Node.js v22 +- React 19 + Vite 8 frontend +- Fastify backend (server/index.js) — serves dist/ and save API on port 3000 +- Node.js v22 at /usr/bin/node - PM2 under otivm user (never root) -- Python venv at /home/otivm/venv (never run Python outside venv) -- No database — JSON flat files for any local state +- No database — JSON flat files in data/saves/ for player state + +--- + +## Container Facts + +| Property | Value | +|-------------|---------------------| +| Hostname | otivm-dev | +| LAN IP | 10.0.0.23 | +| WireGuard | 10.110.0.18 | +| Cores | 4 | +| RAM | 2048 MB | +| App user | otivm | +| App port | 3000 | +| Python venv | /home/otivm/venv | +| PM2 home | /home/otivm/.pm2 | +| Repo path | /home/otivm/OTIVM | +| Node path | /usr/bin/node | --- @@ -31,36 +174,19 @@ It is a standalone light-hearted project — not part of CIVICVS or TESSERA infr - **Never run PM2 as root** — always as otivm user - **Never run Python outside the venv** — /home/otivm/venv always - **Never commit secrets** — no tokens, no keys, no passwords in any file -- **Never push to main without testing** — test locally on port 3000 first -- **One screen, one loop** — do not add complexity without explicit instruction -- **No database** — JSON flat files only, consistent with TheRON design principles +- **Never push to main without building** — npm run build must pass first +- **No database** — JSON flat files only +- **H3 IDs on every location** — never a coordinate pair or string name alone +- **One change confirmed before the next** — no batching steps --- -## Container Facts - -| Property | Value | -|----------|-------| -| Hostname | otivm-dev | -| LAN IP | 10.0.0.23 | -| WireGuard | 10.110.0.18 | -| Cores | 4 | -| RAM | 2048 MB | -| App user | otivm | -| App port | 3000 | -| Python venv | /home/otivm/venv | -| PM2 home | /home/otivm/.pm2 | -| Repo path | /home/otivm/OTIVM | - ---- - -## PM2 Commands +## PM2 Commands (always as otivm user) ```bash -# Always as otivm user -pm2 start ecosystem.config.js pm2 restart otivm -pm2 logs otivm +pm2 list +pm2 logs otivm --lines 30 --nostream pm2 save ``` @@ -69,80 +195,62 @@ pm2 save ## Git Workflow ```bash +git pull origin main git add git commit -m "imperative mood, under 72 chars" git push origin main ``` Commit messages: imperative mood, present tense, under 72 characters. -Example: `Add trade route unlock mechanic` not `Added trade routes`. +Example: `Add Mediterranean SVG map to Map screen` not `Added map`. + +--- + +## Session Start Checklist (Claude Code) + +1. Read this file completely ✓ +2. Run `git log --oneline -5` — know what was last committed +3. Run `git status` — confirm working tree is clean +4. Run `pm2 list` — confirm otivm is online +5. Wait for instruction from the human — do not act until instructed --- ## TheRON Infrastructure Context - **wg-pk** (198.58.111.109) — Linode hub, Nginx proxy, WireGuard hub -- **srv-a** (10.0.0.11) — dev Proxmox host, runs this container -- **mcp.civicus.us** — gitea-mcp server, gives Claude chat read access to this repo +- **srv-a** (10.0.0.11) — dev Proxmox host, runs LXC 1105 (this container) +- **mcp.civicus.us** — gitea-mcp server, gives Claude chat read-only access - **Gitea** — https://gitea.barternetwork.us (owner: TheRON) +- **TESSERA** — H3-based physical world model, same grid OTIVM uses for waypoints + +--- + +## Aliases + +| Location | Alias | Effect | +|---------------------------|------------|------------------------| +| root@otivm-dev ~/.bashrc | webmin-on | systemctl start webmin | +| root@otivm-dev ~/.bashrc | webmin-off | systemctl stop webmin | +| otivm@otivm-dev ~/.bashrc | work | cd ~/OTIVM && claude | --- ## Design Notes The game carries quiet atmospheric references to Mesolithic cultures -(Maglemosian, Ertebølle, Sauveterrian, Azilian) through trade goods, -place names, and merchant journal entries. These are never labelled -academically — they are atmosphere only. The amber road, the northern -forests, the flint from the Pyrenean foothills. +(Maglemosian, Ertebølle, Sauveterrian, Azilian) through trade goods, place names, +and merchant journal entries. These are never labelled academically — they are +atmosphere only. The amber road, the northern forests, the flint from the +Pyrenean foothills. The Roman merchant's journey: Ostia → Capua → Brundisium → Carthago → Alexandria. -Five chapters. Five trade routes. Five journal entries. +Five chapters. Five trade routes. Releases OTIVM-I through OTIVM-X build on this +foundation — see docs/roadmap.md. --- -## Session Start Checklist - -1. Read this file ✓ -2. Check `git status` and `git log --oneline -5` -3. Check `pm2 list` (as otivm user) -4. Proceed with the task - ---- - -## Aliases - -| Location | Alias | Effect | -|----------|-------|--------| -| root@otivm-dev ~/.bashrc | webmin-on | systemctl start webmin | -| root@otivm-dev ~/.bashrc | webmin-off | systemctl stop webmin | -| otivm@otivm-dev ~/.bashrc | work | cd ~/OTIVM && claude | - ---- - -*CLAUDE.md — OTIVM — TheRON* - ---- - -## Session workflow — paste-and-commit - -Each development step follows this exact sequence: - -1. The design discussion happens in Claude chat (not here) -2. Claude chat produces one file or one change at a time -3. That content is pasted into this Claude Code session as a prompt -4. Claude Code writes the file to disk exactly as given, then commits and pushes -5. The human confirms it works before the next step begins - -**When a file is pasted into this prompt**, the instruction will say: - -> Write this to `` exactly as given, then commit with message `` and push to main. - -Do not modify the content. Do not reformat. Do not add imports or change structure. Write it exactly as given. - -**When a shell command result is pasted**, it is for context only — no action unless explicitly instructed. - -## Current development state — updated 2026-04-25 +## Current Development State — updated 2026-04-25 ### OTIVM-I — complete - Fastify backend serving dist/ and save API on port 3000 @@ -158,17 +266,31 @@ Do not modify the content. Do not reformat. Do not add imports or change structu - Game.jsx renamed to src/screens/Ledger.jsx - App.jsx manages screen state — ledger and map - Both screens stay mounted — no state lost on switch -- Map screen shows placeholder — ready for OTIVM-II work -### OTIVM-II — next -- src/screens/Map.jsx to be created -- Mediterranean rendered using H3 geometry -- Five waypoints plotted using confirmed H3 res-5 IDs -- Route lines drawn between waypoints -- No interactivity required in first Map commit — visual only +### OTIVM-II — complete +- src/screens/Map.jsx created and committed +- Mediterranean SVG map, equirectangular projection, bounding box 5°E–38°E / 28°N–48°N +- Five waypoints plotted at hardcoded H3 res-5 cell centres +- Route lines between waypoints — gold when unlocked, muted dashed when locked +- Current chapter waypoint highlighted in gold, reached waypoints in green +- Land outline is a rough placeholder polygon — replaced in a later release +- App.jsx updated to import and render Map component +- Map screen CSS added to App.css +- **Build and PM2 restart still required on container** — code is committed but + dist/ has not been rebuilt yet ### Architecture decisions locked - H3 IDs on all waypoints — permanent, TESSERA-compatible - constants.js / gameState.js / api.js separation — permanent - Virtual screens via display:none — state preserved in browser - Save on meaningful events only — not on every tick +- H3 cell centre coordinates hardcoded in Map.jsx — h3-js is server-side only +- Mediterranean map replaced in a later release (Azgaar bridge planned OTIVM-VII) + +### OTIVM-III — not yet defined +- To be discussed in Claude chat before any code is written + +--- + +*CLAUDE.md — OTIVM — TheRON* +*Claude Code implements. Claude chat designs. The human decides.*