Rewrite CLAUDE.md — document three-shell model and workflow
This commit is contained in:
300
CLAUDE.md
300
CLAUDE.md
@@ -1,28 +1,171 @@
|
|||||||
# 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
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 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 PM2 as root** — always as otivm user
|
||||||
- **Never run Python outside the venv** — /home/otivm/venv always
|
- **Never run Python outside the venv** — /home/otivm/venv always
|
||||||
- **Never commit secrets** — no tokens, no keys, no passwords in any file
|
- **Never commit secrets** — no tokens, no keys, no passwords in any file
|
||||||
- **Never push to main without testing** — test locally on port 3000 first
|
- **Never push to main without building** — npm run build must pass first
|
||||||
- **One screen, one loop** — do not add complexity without explicit instruction
|
- **No database** — JSON flat files only
|
||||||
- **No database** — JSON flat files only, consistent with TheRON design principles
|
- **H3 IDs on every location** — never a coordinate pair or string name alone
|
||||||
|
- **One change confirmed before the next** — no batching steps
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Container Facts
|
## PM2 Commands (always as otivm user)
|
||||||
|
|
||||||
| 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
|
|
||||||
|
|
||||||
```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
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 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
|
## Design Notes
|
||||||
|
|
||||||
The game carries quiet atmospheric references to Mesolithic cultures
|
The game carries quiet atmospheric references to Mesolithic cultures
|
||||||
(Maglemosian, Ertebølle, Sauveterrian, Azilian) through trade goods,
|
(Maglemosian, Ertebølle, Sauveterrian, Azilian) through trade goods, place names,
|
||||||
place names, and merchant journal entries. These are never labelled
|
and merchant journal entries. These are never labelled academically — they are
|
||||||
academically — they are atmosphere only. The amber road, the northern
|
atmosphere only. The amber road, the northern forests, the flint from the
|
||||||
forests, the flint from the Pyrenean foothills.
|
Pyrenean foothills.
|
||||||
|
|
||||||
The Roman merchant's journey: Ostia → Capua → Brundisium → Carthago → Alexandria.
|
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
|
## Current Development State — updated 2026-04-25
|
||||||
|
|
||||||
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 `<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°E–38°E / 28°N–48°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.*
|
||||||
|
|||||||
Reference in New Issue
Block a user