diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..9e6a27b --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,181 @@ +# Contributing to Claude Kingdoms + +Welcome. Claude Kingdoms is built by its community (PRD §"Design +Pillars" #4). This doc covers the **four contribution paths**, the +test-ownership rules, the PR process, and how to find a `good first +issue`. + +## The four contribution paths + +You can contribute to any one of these without touching the others. +Pick the one that matches your interest. + +### 1. Bridge (Python, async, no game engine knowledge required) + +The bridge is the scoring + persistence layer. It ingests Claude Code +hook events, classifies session state, computes per-turn rewards, and +writes the save exchange that the Unciv mod reads. + +Files: `bridge/`, `bridge/tests/`. Entry point: +`python -m bridge.daemon`. + +What lives here: +- `session_state.py` — `Session` and `SessionState` dataclasses +- `scoring.py` — `ScoringEngine` + `SimpleScoringStrategy` +- `hook_listener.py` — Claude Code event ingestion → state mutations +- `bridge_loop.py` — turn pump +- `save_exchange.py` — atomic JSON file I/O +- `audit_log.py` — append-only event log (JSONL) +- `daemon.py` — production CLI entrypoint + +Good for you if: you like clean Python, async, and dataclass-based +state machines. Type hints are appreciated. + +### 2. TUI (Python, Textual) + +The TUI is the player's window into the bridge. It shows live session +state, supports manual event injection (PRD §BR-11), and walks new +players through the onboarding emotional contract. + +Files: `tui/`, `tui/tests/`. Entry point: `python run_tui.py`. + +What lives here: +- `app.py` — `MainApp`, `KingdomView`, `TurnEstimatePanel`, + `EventLogPanel` +- `onboarding.py` — `OnboardingScreen` + `OnboardingState` +- `medieval_voice.py` — flavor strings + state-change translator + +Good for you if: you've used Textual or want to learn it; you have +opinions on accessibility, color contrast, or keyboard ergonomics. + +### 3. Unciv mod (JSON + Lua) + +The mod side is the actual game. It defines The Operators civ, the +Session Forge building, tutorials, and the Lua hook that reads the +bridge's save exchange and applies per-city rewards at turn boundary. + +Files: `mod/ClaudeKingdoms/`. Install instructions: +`mod/ClaudeKingdoms/README.md`. + +What lives here: +- `jsons/Nations.json` — The Operators civilization +- `jsons/Buildings.json` — Session Forge + Charter Hall +- `jsons/Tutorials.json` — six tutorials including the no-decay promise +- `jsons/Beliefs.json` — pantheon for theme +- `mod.lua` — runtime hook reading `kingdom_save.json` +- `ModOptions.json` — Unciv mod metadata + +Good for you if: you've modded Unciv or another Civ-like, you read +Lua fluently, or you want to author medieval-flavor content. + +### 4. Documentation (Markdown, no code) + +Documentation is a first-class deliverable (PRD acceptance #12). The +docs ARE the contract for parallel contributors. + +Files: `docs/`, top-level Markdown files (`README.md`, this file, +`mod/ClaudeKingdoms/README.md`). + +What lives here: +- `docs/prd/ClaudeKingdomsPRD.md` — the source of truth +- `docs/adr/` — architectural decision records (ADR-001..003) +- `docs/bridge-tui-schema.md` — the binding contract for paths 1 + 2 +- `docs/hooks-setup.md` — wiring Claude Code hooks to the bridge +- `docs/audit-2026-05-08.md` — CTO audit (snapshot, supersede on update) + +Good for you if: you write clearly, think about onboarding, or just +notice when an instruction doesn't match the code. + +## Test ownership matrix (from PRD §"Test Ownership Matrix") + +| Layer | Owner | Test type | +|-------|-------|-----------| +| Bridge session state machine | Bridge contributor | Unit | +| Bridge scoring / reward calculation | Bridge contributor | Unit | +| Hook event parsing | Bridge contributor | Unit | +| Bridge → TUI schema compliance | Shared (Bridge + TUI) | Contract (`bridge/tests/test_prd_schema.py`) | +| Save exchange write/read round-trip | Bridge contributor | Integration | +| TUI state rendering from bridge payload | TUI contributor | Unit | +| Mod JSON / Lua | Mod contributor | Smoke (`bridge/tests/test_mod_jsons.py`) | +| End-to-end vertical slice | Shared | Integration (`bridge/tests/test_e2e_vertical_slice.py`) | + +CI threshold per PRD: **80%** coverage for bridge scoring + session +state modules. CI runs `pytest -q` on every push and PR (see +`.github/workflows/tests.yml`). + +## PR process + +1. **Branch** from `main`. Use `feat/` for new features, + `fix/` for bug fixes, `docs/` for doc-only changes, + `test/` for test-only changes. +2. **TDD when feasible** (PRD design pillar #5). Add the failing test + first; write the minimum change that makes it pass; layer in + enrichment. +3. **Run `pytest -q` locally** — green or you don't push. +4. **Open a PR** with: + - One-line summary + - "Closes / Toward kanban: t_…" line if it maps to a kanban task + - "Test plan" checklist + - PRD section reference if the change closes a requirement + (BR-x / BS-x / CL-x / GM-x / TU-x / acceptance #x) +5. **Wait for CI** (GitHub Actions). PRs with failing CI do not merge. +6. **Reviewer + merge** — the merger runs `gh pr merge --merge + --delete-branch` once review approves. + +### Safety rules (project-wide) + +- No `git push --force` to `main`. +- No `--no-verify` / `--no-gpg-sign` — fix the underlying issue. +- No third-party deploy commands without explicit approval (this + project doesn't deploy anywhere yet, but the rule is on the books). + +## Finding a `good first issue` + +Acceptance criterion #13: "New contributor completes a `good first +issue` without asking for help." We label issues that fit this +description with `good first issue` on GitHub. + +Some standing options if no labeled issues are open: + +- **Bridge**: write a unit test for an edge case in `SimpleScoringStrategy` + that isn't covered yet — e.g., what happens if `momentum` goes negative, + what happens with extremely large token counts, etc. +- **TUI**: improve `EventLogPanel` rendering — currently caps at 8 lines, + could scroll, or could highlight the most recent event. +- **Mod**: add a fourth medieval city name to The Operators' city list, + with a one-line in-character description in `Tutorials.json`. +- **Docs**: pick any spot in the codebase where a function comment is + missing or stale and write a clear one. Or notice when an old kanban + task title or PR ref is wrong and fix it. + +## Code style + +- Python: 4-space indent, type hints on public APIs, docstrings on + every module and every public class/function. No `# noqa` without + explanation. +- Markdown: 80-col soft limit, ATX headers (`#`), prefer tables for + status lists, fenced code blocks with language tags. +- Lua: 4-space indent, `local` for everything by default, no globals + outside an explicit `mod` table. +- JSON: 2-space indent, trailing commas NOT allowed (Unciv parses + with strict JSON). + +## Communication + +- **Bug reports / feature requests**: GitHub Issues +- **Design questions / RFCs**: GitHub Discussions (when enabled) +- **Architectural decisions**: ADR PR against `docs/adr/` +- **Quick questions**: comment on the relevant PR or kanban task + +The kanban board (Hermes-managed at `http://127.0.0.1:9119/kanban` +locally) is internal coordination — external contributors interact +through GitHub Issues / PRs. + +## License + +MIT. By contributing, you agree your contribution is MIT-licensed. + +--- + +*This document is acceptance criterion #12 from the PRD. If something +here is unclear or wrong, fixing it is itself a `good first issue`.* diff --git a/README.md b/README.md index b9a7efb..d81bde2 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ An open-source medieval grand strategy game powered by Claude Code session activity. +> **GIF placeholder** — `docs/media/session-to-reward-loop.gif` (PRD acceptance criterion #11). To be recorded after the M4 tutorial map is in place; capture target is a 30-second loop showing: (1) bridge daemon running, (2) Claude Code session active, (3) plan + goal events firing, (4) end-turn in Unciv, (5) per-city resource increase landing on the map. See `docs/media/README.md` for the recording protocol. + ## Vision Turn your real Claude Code sessions into an empire. Every plan created, every goal completed, and every active session grows your kingdom. Idle hands stir nothing; active minds stir empires. The kingdom never decays when you step away — but it only grows when you return. diff --git a/docs/media/README.md b/docs/media/README.md new file mode 100644 index 0000000..fe9aebf --- /dev/null +++ b/docs/media/README.md @@ -0,0 +1,62 @@ +# `docs/media/` — recorded assets for the README and launch posts + +This folder holds video / GIF / screenshot assets referenced from the +top-level README and PRD-driven launch material. + +## Required asset for V1 launch + +Per PRD acceptance criterion #11: *"README includes working GIF of the +session-to-turn reward loop."* + +**Target file**: `docs/media/session-to-reward-loop.gif` + +### Recording protocol + +A reproducible 30-second capture should show, in order: + +1. **(0:00–0:05)** `python -m bridge.daemon` running in one pane, + `python run_tui.py` in another. The TUI's KingdomView shows a + single ACTIVE session; net turn estimate is non-zero. +2. **(0:05–0:12)** Claude Code session in a third pane: a real prompt + submitted; the TUI EventLogPanel scrolls a "rises to action" + medieval-voice line via the listener's on_change → `voice_for_change`. +3. **(0:12–0:18)** A `SubagentStart type=Plan` event fires; EventLogPanel + shows "A new charter is drafted for 'Royal Court'." TurnEstimatePanel + bumps by `+15` (PRD §BR-6). +4. **(0:18–0:24)** A `TaskCompleted` event fires twice. EventLogPanel + shows "completed 1 goal", momentum increments, TurnEstimatePanel + reflects the goal bonus. +5. **(0:24–0:30)** End turn in Unciv — the per-city rewards land on + the city tile; gold/science/production tickers visibly increment. + +### Recording tools + +Recommended (cross-platform): +- **OBS Studio** (free) for screen capture, encode at 30fps, export + to MP4 +- **gifski** or **ffmpeg** for MP4 → GIF conversion at 12fps and + 640px width to keep file size reasonable for GitHub README rendering + (target <5MB) + +Sample ffmpeg + gifski pipeline: + +```bash +# Capture with OBS to capture.mp4, then: +ffmpeg -i capture.mp4 -vf "fps=12,scale=640:-1:flags=lanczos" -c:v ppm -f image2pipe - \ + | gifski -o session-to-reward-loop.gif --fps 12 - +``` + +### Why this is a placeholder + +The GIF can't be authored until M4 is in place — the campaign map and +the tutorial flow need to render Unciv-side resource changes for the +final five seconds of the recording to be meaningful. Until then, the +README links to this folder as the planned location. + +## Other assets (when added) + +- Screenshots used in launch posts (r/Unciv, r/ClaudeCode, Hacker News, + ModDB per PRD §M5) should live here too, named with the platform tag, + e.g. `launch-hn-screenshot.png`. +- Any subsequent demo recordings (a longer "live coding for an hour → + empire grows over a real Pomodoro" video) similarly.