From 35501a581e747b479f9bf017a71f622448448d92 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 31 May 2026 19:04:40 +0000 Subject: [PATCH 1/5] docs: strip README to project intro, defer to CONTRIBUTING --- README.md | 117 +++--------------------------------------------------- 1 file changed, 5 insertions(+), 112 deletions(-) diff --git a/README.md b/README.md index c9ea9de..d919151 100644 --- a/README.md +++ b/README.md @@ -1,116 +1,9 @@ -# mundane +# Mundane Backend -No dragons. No spells. Just Tuesday. +The backend service for Mundane. -Two households face off. The engine is a **referee**: a whole game is a fold over a stream of -*actions*, and one function — `apply_action(state, action)` — validates each action against the -current state and then transitions it. Illegal moves are rejected (the state is left untouched), not -crashed on. The HTTP API is a thin shell that translates requests into engine actions; all the rules -live in the engine. +See [CONTRIBUTING.md](.github/CONTRIBUTING.md) for development setup and guidelines. -The rules and card catalog live in the [`mundane`](https://github.com/letsbuilda/mundane) meta/spec -repo: +## License -- The rules, in human-readable form: - [`game-docs/SPEC.md`](https://github.com/letsbuilda/mundane/blob/main/game-docs/SPEC.md) -- The card catalog: - [`game-docs/CARDS.md`](https://github.com/letsbuilda/mundane/blob/main/game-docs/CARDS.md) - -## Layout - -``` -src/mundane/ - engine/ # the game, with no HTTP knowledge - state.py # Card, CardType, Player, StackItem, GameState - actions.py # PlayCard, CastInstant, PassPriority, IllegalAction - rules.py # apply_action + helpers — the one door - cards.py # CARD_LIBRARY (id -> Card) + effect functions - serialize.py # state/action -> JSON-ready data - game.py # Game: state + action log + submit() / export() - api/ - app.py # Litestar app, in-memory store, exception handler - schemas.py # action JSON (tagged union) -> action dataclasses -examples/ - demo.py # runnable scenario (python examples/demo.py) -``` - -## Requirements - -- Python **3.14+** and [`uv`](https://docs.astral.sh/uv/). -- Litestar 3 is still in development; it is tracked from `main` and pinned to a commit SHA in - `uv.lock`, so builds are reproducible. - -## Setup - -```bash -uv sync --group tests --group dev # create the venv and install everything -``` - -## Run the demo - -Watch Steve's house party get shut down by Alex's noise complaint: - -```bash -uv run python examples/demo.py -``` - -## Run the API - -```bash -uv run uvicorn mundane.api.app:app --reload -``` - -Interactive OpenAPI docs are served at `http://localhost:8000/schema`. - -### Endpoints - -| Method | Path | Purpose | -|--------|----------------------------|----------------------------------------| -| POST | `/games` | create a game | -| GET | `/games/{id}` | read current state | -| POST | `/games/{id}/actions` | submit a move (422 if illegal) | -| GET | `/games/{id}/export` | download the game log + final state | - -### Exercise it - -```bash -# create a game and capture its id -GID=$(curl -s -X POST localhost:8000/games | python -c 'import sys,json; print(json.load(sys.stdin)["game_id"])') - -# read the current state -curl -s localhost:8000/games/$GID - -# submit a move (the tagged-union body carries a "type" discriminator) -curl -s -X POST localhost:8000/games/$GID/actions \ - -H 'content-type: application/json' \ - -d '{"type": "play_card", "player": 0, "hand_index": 0}' - -# an illegal move is rejected with 422; the stored game is unchanged -curl -s -o /dev/null -w '%{http_code}\n' -X POST localhost:8000/games/$GID/actions \ - -H 'content-type: application/json' \ - -d '{"type": "cast_instant", "player": 1, "hand_index": 9}' - -# download the game log (saves to mundane-game-$GID.json) -curl -s -OJ localhost:8000/games/$GID/export -``` - -The action body is a tagged union — every action carries a `type`: - -| `type` | fields | -|-----------------|-------------------------------------------------| -| `play_card` | `player`, `hand_index` | -| `cast_instant` | `player`, `hand_index`, optional `target_id` | -| `pass_priority` | `player` | - -### A note on the store - -The game store is an **in-memory dict**, so games are **volatile** — they are lost when the process -restarts. It lives behind a small `GameStore` interface (`create` / `get` / `save`), so swapping it -for Redis or SQLite later is a localised change. Persistence beyond memory is out of scope for the MVP. - -## Develop - -```bash -uv run pytest # tests -uv run nox -s lints # ruff format + ruff check + mypy + ty -``` +This project is licensed under the MIT License. From d895cd7ca477857340dd54be60bab908ba24a9d3 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 31 May 2026 19:05:09 +0000 Subject: [PATCH 2/5] docs: correct README to real intro and CONTRIBUTING path --- README.md | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d919151..cdee4e0 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,38 @@ -# Mundane Backend +# mundane -The backend service for Mundane. +No dragons. No spells. Just Tuesday. -See [CONTRIBUTING.md](.github/CONTRIBUTING.md) for development setup and guidelines. +Two households face off. The engine is a **referee**: a whole game is a fold over a stream of +*actions*, and one function — `apply_action(state, action)` — validates each action against the +current state and then transitions it. Illegal moves are rejected (the state is left untouched), not +crashed on. The HTTP API is a thin shell that translates requests into engine actions; all the rules +live in the engine. -## License +The rules and card catalog live in the [`mundane`](https://github.com/letsbuilda/mundane) meta/spec +repo: -This project is licensed under the MIT License. +- The rules, in human-readable form: + [`game-docs/SPEC.md`](https://github.com/letsbuilda/mundane/blob/main/game-docs/SPEC.md) +- The card catalog: + [`game-docs/CARDS.md`](https://github.com/letsbuilda/mundane/blob/main/game-docs/CARDS.md) + +## Layout + +``` +src/mundane/ + engine/ # the game, with no HTTP knowledge + state.py # Card, CardType, Player, StackItem, GameState + actions.py # PlayCard, CastInstant, PassPriority, IllegalAction + rules.py # apply_action + helpers — the one door + cards.py # CARD_LIBRARY (id -> Card) + effect functions + serialize.py # state/action -> JSON-ready data + game.py # Game: state + action log + submit() / export() + api/ + app.py # Litestar app, in-memory store, exception handler + schemas.py # action JSON (tagged union) -> action dataclasses +examples/ + demo.py # runnable scenario (python examples/demo.py) +``` + +See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, running the demo and API, and the development +workflow. From 578be7d1e5b64e77e303ac9b21c2df679eb38982 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 31 May 2026 19:09:05 +0000 Subject: [PATCH 3/5] docs: move API endpoint and curl reference into docs/api.rst --- CONTRIBUTING.md | 2 +- docs/api.rst | 70 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 docs/api.rst diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 085b93a..e2ac887 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,7 +33,7 @@ uv run python examples/demo.py # run the demo scenario uv run uvicorn mundane.api.app:app --reload # serve the API; OpenAPI docs at /schema ``` -The README has the endpoint table and `curl` examples for exercising the API. +The [API docs](docs/api.rst) have the endpoint table and `curl` examples for exercising the API. ## Development workflow diff --git a/docs/api.rst b/docs/api.rst new file mode 100644 index 0000000..700e6a7 --- /dev/null +++ b/docs/api.rst @@ -0,0 +1,70 @@ +API +=== + +Serve the API locally: + +.. code-block:: bash + + uv run uvicorn mundane.api.app:app --reload + +Interactive OpenAPI docs are served at ``http://localhost:8000/schema``. + +Endpoints +--------- + +.. list-table:: + :header-rows: 1 + + * - Method + - Path + - Purpose + * - POST + - ``/games`` + - create a game + * - GET + - ``/games/{id}`` + - read current state + * - POST + - ``/games/{id}/actions`` + - submit a move (422 if illegal) + * - GET + - ``/games/{id}/export`` + - download the game log + final state + +Exercise it +----------- + +.. code-block:: bash + + # create a game and capture its id + GID=$(curl -s -X POST localhost:8000/games | python -c 'import sys,json; print(json.load(sys.stdin)["game_id"])') + + # read the current state + curl -s localhost:8000/games/$GID + + # submit a move (the tagged-union body carries a "type" discriminator) + curl -s -X POST localhost:8000/games/$GID/actions \ + -H 'content-type: application/json' \ + -d '{"type": "play_card", "player": 0, "hand_index": 0}' + + # an illegal move is rejected with 422; the stored game is unchanged + curl -s -o /dev/null -w '%{http_code}\n' -X POST localhost:8000/games/$GID/actions \ + -H 'content-type: application/json' \ + -d '{"type": "cast_instant", "player": 1, "hand_index": 9}' + + # download the game log (saves to mundane-game-$GID.json) + curl -s -OJ localhost:8000/games/$GID/export + +The action body is a tagged union — every action carries a ``type``: + +.. list-table:: + :header-rows: 1 + + * - ``type`` + - fields + * - ``play_card`` + - ``player``, ``hand_index`` + * - ``cast_instant`` + - ``player``, ``hand_index``, optional ``target_id`` + * - ``pass_priority`` + - ``player`` From 029f5eb5063d7bbfdc6b89c38c986d1bdf0bef44 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 31 May 2026 19:09:26 +0000 Subject: [PATCH 4/5] docs: link API page into the doc tree --- docs/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/index.rst b/docs/index.rst index a262372..4f2f616 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -68,6 +68,7 @@ The full module reference is generated from the source. .. toctree:: :maxdepth: 1 + api autoapi/index .. toctree:: From 724642cd1e0ab6bfb986311815571dbf15970ade Mon Sep 17 00:00:00 2001 From: Bradley Reynolds Date: Sun, 31 May 2026 14:11:51 -0500 Subject: [PATCH 5/5] Revise README for project name and content Updated project name and removed outdated sections. Signed-off-by: Bradley Reynolds --- README.md | 33 +++------------------------------ 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index cdee4e0..9de6cc8 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ -# mundane +# Mundane, backened + +*Part of https://github.com/letsbuilda/mundane* No dragons. No spells. Just Tuesday. @@ -7,32 +9,3 @@ Two households face off. The engine is a **referee**: a whole game is a fold ove current state and then transitions it. Illegal moves are rejected (the state is left untouched), not crashed on. The HTTP API is a thin shell that translates requests into engine actions; all the rules live in the engine. - -The rules and card catalog live in the [`mundane`](https://github.com/letsbuilda/mundane) meta/spec -repo: - -- The rules, in human-readable form: - [`game-docs/SPEC.md`](https://github.com/letsbuilda/mundane/blob/main/game-docs/SPEC.md) -- The card catalog: - [`game-docs/CARDS.md`](https://github.com/letsbuilda/mundane/blob/main/game-docs/CARDS.md) - -## Layout - -``` -src/mundane/ - engine/ # the game, with no HTTP knowledge - state.py # Card, CardType, Player, StackItem, GameState - actions.py # PlayCard, CastInstant, PassPriority, IllegalAction - rules.py # apply_action + helpers — the one door - cards.py # CARD_LIBRARY (id -> Card) + effect functions - serialize.py # state/action -> JSON-ready data - game.py # Game: state + action log + submit() / export() - api/ - app.py # Litestar app, in-memory store, exception handler - schemas.py # action JSON (tagged union) -> action dataclasses -examples/ - demo.py # runnable scenario (python examples/demo.py) -``` - -See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, running the demo and API, and the development -workflow.