Rewrite CLAUDE.md — document three-shell model and workflow

This commit is contained in:
otivm
2026-04-25 19:15:14 +00:00
parent 01dd2ea778
commit 03d2f49f8c

276
CLAUDE.md
View File

@@ -1,46 +1,160 @@
# CLAUDE.md — OTIVM Project # CLAUDE.md — OTIVM Project
This file is read automatically by Claude Code at the start of every session. 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 ## What OTIVM Is
A browser-based Roman merchant idle game. One screen, one resource loop. A browser-based Roman merchant idle game. The narrative unfolds through trade
The narrative unfolds through trade goods and journal entries. goods and journal entries. It is a standalone light-hearted project under TheRON,
It is a standalone light-hearted project — not part of CIVICVS or TESSERA infrastructure. 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 **Live URL:** https://otium.civicus.us
**Repo:** https://gitea.barternetwork.us/TheRON/OTIVM (branch: main) **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 ## Stack
- React 19 + Vite frontend - React 19 + Vite 8 frontend
- Node.js v22 - 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) - PM2 under otivm user (never root)
- Python venv at /home/otivm/venv (never run Python outside venv) - No database — JSON flat files in data/saves/ for player state
- No database — JSON flat files for any local state
---
## Ground Rules — Do Not Violate
- **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
--- ---
## Container Facts ## Container Facts
| Property | Value | | Property | Value |
|----------|-------| |-------------|---------------------|
| Hostname | otivm-dev | | Hostname | otivm-dev |
| LAN IP | 10.0.0.23 | | LAN IP | 10.0.0.23 |
| WireGuard | 10.110.0.18 | | WireGuard | 10.110.0.18 |
@@ -51,16 +165,28 @@ It is a standalone light-hearted project — not part of CIVICVS or TESSERA infr
| Python venv | /home/otivm/venv | | Python venv | /home/otivm/venv |
| PM2 home | /home/otivm/.pm2 | | PM2 home | /home/otivm/.pm2 |
| Repo path | /home/otivm/OTIVM | | Repo path | /home/otivm/OTIVM |
| Node path | /usr/bin/node |
--- ---
## PM2 Commands ## Ground Rules — Do Not Violate
- **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 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
---
## PM2 Commands (always as otivm user)
```bash ```bash
# Always as otivm user
pm2 start ecosystem.config.js
pm2 restart otivm pm2 restart otivm
pm2 logs otivm pm2 list
pm2 logs otivm --lines 30 --nostream
pm2 save pm2 save
``` ```
@@ -69,80 +195,62 @@ pm2 save
## Git Workflow ## Git Workflow
```bash ```bash
git pull origin main
git add <files> git add <files>
git commit -m "imperative mood, under 72 chars" git commit -m "imperative mood, under 72 chars"
git push origin main git push origin main
``` ```
Commit messages: imperative mood, present tense, under 72 characters. 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 ## TheRON Infrastructure Context
- **wg-pk** (198.58.111.109) — Linode hub, Nginx proxy, WireGuard hub - **wg-pk** (198.58.111.109) — Linode hub, Nginx proxy, WireGuard hub
- **srv-a** (10.0.0.11) — dev Proxmox host, runs this container - **srv-a** (10.0.0.11) — dev Proxmox host, runs LXC 1105 (this container)
- **mcp.civicus.us** — gitea-mcp server, gives Claude chat read access to this repo - **mcp.civicus.us** — gitea-mcp server, gives Claude chat read-only access
- **Gitea** — https://gitea.barternetwork.us (owner: TheRON) - **Gitea** — https://gitea.barternetwork.us (owner: TheRON)
- **TESSERA** — H3-based physical world model, same grid OTIVM uses for waypoints
---
## 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.
The Roman merchant's journey: Ostia → Capua → Brundisium → Carthago → Alexandria.
Five chapters. Five trade routes. Five journal entries.
---
## 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 ## Aliases
| Location | Alias | Effect | | Location | Alias | Effect |
|----------|-------|--------| |---------------------------|------------|------------------------|
| root@otivm-dev ~/.bashrc | webmin-on | systemctl start webmin | | root@otivm-dev ~/.bashrc | webmin-on | systemctl start webmin |
| root@otivm-dev ~/.bashrc | webmin-off | systemctl stop webmin | | root@otivm-dev ~/.bashrc | webmin-off | systemctl stop webmin |
| otivm@otivm-dev ~/.bashrc | work | cd ~/OTIVM && claude | | otivm@otivm-dev ~/.bashrc | work | cd ~/OTIVM && claude |
--- ---
*CLAUDE.md — OTIVM — TheRON* ## 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.
The Roman merchant's journey: Ostia → Capua → Brundisium → Carthago → Alexandria.
Five chapters. Five trade routes. Releases OTIVM-I through OTIVM-X build on this
foundation — see docs/roadmap.md.
--- ---
## Session workflow — paste-and-commit ## Current Development State — updated 2026-04-25
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 `<path>` exactly as given, then commit with message `<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
### OTIVM-I — complete ### OTIVM-I — complete
- Fastify backend serving dist/ and save API on port 3000 - 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 - Game.jsx renamed to src/screens/Ledger.jsx
- App.jsx manages screen state — ledger and map - App.jsx manages screen state — ledger and map
- Both screens stay mounted — no state lost on switch - Both screens stay mounted — no state lost on switch
- Map screen shows placeholder — ready for OTIVM-II work
### OTIVM-II — next ### OTIVM-II — complete
- src/screens/Map.jsx to be created - src/screens/Map.jsx created and committed
- Mediterranean rendered using H3 geometry - Mediterranean SVG map, equirectangular projection, bounding box 5°E38°E / 28°N48°N
- Five waypoints plotted using confirmed H3 res-5 IDs - Five waypoints plotted at hardcoded H3 res-5 cell centres
- Route lines drawn between waypoints - Route lines between waypoints — gold when unlocked, muted dashed when locked
- No interactivity required in first Map commit — visual only - 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 ### Architecture decisions locked
- H3 IDs on all waypoints — permanent, TESSERA-compatible - H3 IDs on all waypoints — permanent, TESSERA-compatible
- constants.js / gameState.js / api.js separation — permanent - constants.js / gameState.js / api.js separation — permanent
- Virtual screens via display:none — state preserved in browser - Virtual screens via display:none — state preserved in browser
- Save on meaningful events only — not on every tick - 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.*