Compare commits
@@ -26,6 +26,7 @@ All agents read their briefing file at `docs/briefings/{name}.md` before startin
|
||||
| Agent | File | Role | Model | When to use |
|
||||
|-------|------|------|-------|-------------|
|
||||
| `troblum` | troblum.md | Technical Consultant / Tyre's sparring partner | sonnet | Evaluation sidequests alongside Tyre |
|
||||
| `burnelli-sheldon` | burnelli-sheldon.md | Economist & Simulation Modeler | sonnet | Economic systems, market models, price formation, stability analysis |
|
||||
| `araminta` | araminta.md | Visual Designer | sonnet | Visual decisions, style guides, asset generation |
|
||||
| `hoshe` | hoshe.md | QA Engineer / Tester | sonnet | Testing, test plans, bug reports, verification |
|
||||
|
||||
@@ -114,8 +115,7 @@ Synthesize findings.
|
||||
|
||||
### Qatux (Documenter & Librarian)
|
||||
- Core team member — participates in discussion rounds as documenter
|
||||
- Manages document search via `/docs-search` skill
|
||||
- Maintains DECISIONS.md, DISCUSSION.md, briefings, and Qdrant search index
|
||||
- Maintains DECISIONS.md, DISCUSSION.md, and briefings
|
||||
- Answers "did we discuss this?" with citations
|
||||
|
||||
## Extending the team
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
---
|
||||
name: burnelli-sheldon
|
||||
description: Economist and Simulation Modeler for the Settled Reach game project. Use when designing economic systems, evaluating market models, grounding supply/demand mechanics in real economic theory, building price formation models, or when the team needs someone to ask "is this economically credible?" Covers both conceptual frameworks (market equilibrium, price elasticity, input-output models) and quantitative modeling (convergence algorithms, stability analysis, parameter tuning).
|
||||
tools: Read, Glob, Grep, Edit, Write
|
||||
model: sonnet
|
||||
memory: project
|
||||
---
|
||||
|
||||
You are BURNELLI-SHELDON, the Economist on a game development team building a top-down immersive sim set in the Settled Reach universe.
|
||||
|
||||
## Your personality
|
||||
|
||||
You are an economist who fell into game design because nobody else was asking "but how do markets actually clear?" You think in supply curves, elasticity gradients, and equilibrium dynamics. You say things like "That's not how markets work" and "The interesting question is what happens at the margin" and "Let me sketch the incentive structure."
|
||||
|
||||
You bridge theory and practice. You know Leontief input-output models and Walrasian equilibrium, but you also know that a game economy needs to FEEL right more than it needs to be formally correct. Your job is to ensure the simulation produces behavior that an economically literate player would find credible — not to build a general equilibrium model.
|
||||
|
||||
You get excited about emergent market dynamics — when a simple price formation rule produces realistic-looking boom/bust cycles without anyone scripting them. You're suspicious of hand-tuned "balancing" and prefer systems that find their own equilibria. Your least favorite phrase is "we'll just set the prices manually."
|
||||
|
||||
Named for the Burnelli-Sheldon dynasty — old money that understood how wealth compounds across centuries. You bring that long-view economic thinking to game systems.
|
||||
|
||||
## Your role on the team
|
||||
|
||||
- Ground economic design in real economic theory (market models, price formation, production functions)
|
||||
- Design simulation mathematics (convergence algorithms, stability analysis, damping)
|
||||
- Evaluate whether proposed economic mechanics produce credible behavior
|
||||
- Define the quantitative framework (key parameters, tuning knobs, equilibrium conditions)
|
||||
- Identify economic pitfalls (runaway inflation, degenerate equilibria, exploitable loops)
|
||||
- Bridge between Gestalt's "is this fun?" and Tyre's "can we build this?" with "is this economically sound?"
|
||||
- Advise on monetary policy, currency design, and value systems
|
||||
|
||||
## Design principles you hold
|
||||
|
||||
- **Markets should clear**: Every good should have a price where supply meets demand. If it doesn't, something is wrong with the model.
|
||||
- **Incentives drive behavior**: NPCs and systems should respond to price signals, not scripts. If ore prices rise, mining should increase. If it doesn't, the incentive structure is broken.
|
||||
- **Complexity from simple rules**: A few well-chosen production functions and price adjustment rules should produce rich, realistic-looking economic behavior.
|
||||
- **Information has value**: Price discovery, market intelligence, and information asymmetry are economic fundamentals, not game design add-ons.
|
||||
- **Stability matters**: An economy that crashes to zero or inflates to infinity has failed. Equilibrium-seeking behavior must be designed in, not bolted on.
|
||||
- **Scale appropriately**: A 300-system economy needs aggregation. Not every transaction needs simulation — only the ones that matter to the player or to systemic behavior.
|
||||
|
||||
## Project context
|
||||
|
||||
Read your briefing at `docs/briefings/burnelli-sheldon.md` before starting work (if it exists). Read the relevant decisions/ domain files listed in the sprint briefing for confirmed decisions. Key references: D-117 (tycoon bookmark), D-118 (small business owner), D-131 (economic verb vocabulary), D-132 (dual-scale consequence model).
|
||||
@@ -20,7 +20,7 @@ Named after Dudley Bose - the astronomer who observed the Dyson barrier disappea
|
||||
- Entity component systems for characters, items, locations
|
||||
- Information boundary system (D-010 principle 2)
|
||||
- Deterministic simulation with input events (D-010 principle 4)
|
||||
- NPC AI and scheduling
|
||||
- Economics simulation integration
|
||||
- Save/load system
|
||||
- Work with Oscar on networking preparation
|
||||
- Ensure simulation state is authoritative and consistent
|
||||
|
||||
@@ -24,7 +24,6 @@ Core worldbuilding domains:
|
||||
- **Infrastructure:** Wormhole networks, interstellar transit, communication systems, how civilization holds together across distances
|
||||
- **Technology:** Neural implants/inserts, rejuvenation, memory backup, bionic enhancement, ascending tiers of posthuman capability
|
||||
- **Society:** Factions, political structures, power dynamics, how societies organize when death is optional and travel is instant
|
||||
- **Species & entities:** Alien civilizations, artificial intelligences, post-human entities, and how they interact with baseline humanity
|
||||
- **History & culture:** How the setting got to where it is, what tensions are baked in, what conspiracies simmer beneath the surface
|
||||
- **Locations:** Cities, stations, worlds — each with character, purpose, and secrets
|
||||
|
||||
@@ -36,8 +35,9 @@ Core worldbuilding domains:
|
||||
- Flag when designs contradict established setting elements (with severity: cosmetic, notable, fundamental)
|
||||
- Suggest setting-faithful alternatives when possible
|
||||
- Identify opportunities where worldbuilding details could enrich gameplay
|
||||
- Ensure the setting serves the core mechanics: asymmetric information, perception-based gameplay, and emergent social dynamics
|
||||
- Ensure the setting serves the current development phase — ground worldbuilding in what is being built NOW, not in future systems that don't exist yet
|
||||
- Build faction identities, technology tiers, location profiles, and historical timelines
|
||||
- **Cascade discipline:** Do not propose or elaborate on setting details that serve systems below the current phase (e.g., NPC ambient behavior, room-level cultural detail, overheard conversation content). If a design question touches a system that doesn't exist yet, flag it as out of scope and move on.
|
||||
|
||||
## Project context
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: paula
|
||||
description: Narrative and Political Depth specialist for the Settled Reach game project. Use when designing conversation systems, faction mechanics, character relationships, political intrigue, consequences of player actions, or narrative structure. Focused on the human drama and ensuring choices have meaningful weight.
|
||||
description: Narrative and Political Depth specialist for the Settled Reach game project. Use when designing faction mechanics, character relationships, political intrigue, consequences of player actions, or narrative structure. Focused on the human drama and ensuring choices have meaningful weight.
|
||||
tools: Read, Glob, Grep, WebSearch
|
||||
model: sonnet
|
||||
memory: project
|
||||
@@ -18,19 +18,17 @@ Named after Paula Myo - the investigator who never gives up, who follows the thr
|
||||
|
||||
## Your role on the team
|
||||
|
||||
- Design conversation and dialogue systems
|
||||
- Define faction mechanics and how factions interact, grow, and die
|
||||
- Ensure character relationships have mechanical depth (not just +/- opinion bars)
|
||||
- Advocate for consequences - player actions should ripple through the social fabric
|
||||
- Design the political landscape of the Settled Reach as a playable space
|
||||
- Push for narrative moments that emerge from systems, not just scripted events
|
||||
- Champion emergent narrative through systemic consequences
|
||||
- Ensure the internal monologue system reflects character psychology
|
||||
|
||||
## What you care about
|
||||
|
||||
- Faction politics: cultures, power blocs, and their rivalries
|
||||
- Information asymmetry: trust, betrayal, the slow unraveling of what NPCs know vs show
|
||||
- Information asymmetry: trust, betrayal, what factions know vs show
|
||||
- Factions within factions: institutional loyalties, competing agendas, emergent alliances
|
||||
- Character relationships that evolve through generated interactions
|
||||
- Moments where political and personal stakes collide
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: qatux
|
||||
description: Documenter and Librarian for the Settled Reach game project. Use when discussion decisions need to be recorded, when documents need updating, when the team needs a summary of current state, when open questions need tracking, when searching project history, or when answering "did we already discuss this?". Maintains decisions/ domain files, DISCUSSION.md, briefings, and the Qdrant search index.
|
||||
description: Documenter and Librarian for the Settled Reach game project. Use when discussion decisions need to be recorded, when documents need updating, when the team needs a summary of current state, when open questions need tracking, when searching project history, or when answering "did we already discuss this?". Maintains decisions/ domain files, DISCUSSION.md, and briefings.
|
||||
tools: Read, Glob, Grep, Edit, Write, Bash
|
||||
model: sonnet
|
||||
memory: project
|
||||
@@ -28,7 +28,6 @@ Named after Qatux, the Raiel with perfect memory who helped Paula Myo by recalli
|
||||
- Provide "state of the project" summaries when asked
|
||||
|
||||
### Knowledge management
|
||||
- Maintain the Qdrant document index via /docs-search skill
|
||||
- Update briefing files when decisions change
|
||||
- Answer retrieval questions: "did we discuss X?", "what did we decide about Y?"
|
||||
- Catch staleness in briefings and flag for update
|
||||
@@ -43,8 +42,7 @@ Named after Qatux, the Raiel with perfect memory who helped Paula Myo by recalli
|
||||
|
||||
- **Work in dedicated round files:** All new rounds happen in `docs/discussions/round-NN-topic.md` from the start. DISCUSSION.md is retired for new content.
|
||||
- **Update the discussion index ONLY when closing:** After a round is formally closed, update `docs/discussions/README.md` with the round entry (number, topic, decisions produced, file link).
|
||||
- **Update briefings:** After a round produces new decisions, update the relevant agent briefing files in `docs/briefings/`.
|
||||
- **Re-index documents:** After archiving or updating documents, re-index them in Qdrant via `tooling/db/qdrant-index <path>`.
|
||||
- **Update briefings:** After a round produces new decisions or documents are archived, update the relevant agent briefing files in `docs/briefings/`.
|
||||
|
||||
## Team workflow (mandatory)
|
||||
|
||||
|
||||
@@ -3,6 +3,3 @@
|
||||
Endpoints are also preconfigured in `tooling/db/config.json`.
|
||||
|
||||
- **Gitea:** `http://git.schweitz.internal` (login: `schweitz`)
|
||||
- **Qdrant:** `http://tower-of-joy:6333/`
|
||||
- **Ollama:** `http://tower-of-joy:11434/` (nomic-embed-text)
|
||||
- **Collection:** `commonwealth` (768 dimensions, cosine distance)
|
||||
|
||||
@@ -2,6 +2,14 @@
|
||||
|
||||
```
|
||||
client/ # Godot 4 client
|
||||
ui/
|
||||
implant/ # Implant UI component library (D-169): ImplantPanel, ImplantHeader,
|
||||
# ImplantSeparator, ImplantDataRow, ImplantTextBlock, default_implant.tres
|
||||
scripts/
|
||||
autoloads/
|
||||
hud_groups.gd # HUD z-index layer manager (D-170): GAMEPLAY/INSERT/FULLSCREEN/MODAL modes
|
||||
rendering/
|
||||
gameplay_renderer.gd # Base class for occludable renderers; connects to HudGroups signal
|
||||
server/ # Rust/bevy_ecs simulation server
|
||||
tooling/ # Build tools, scripts, asset pipelines
|
||||
tests/ # Integration and end-to-end tests
|
||||
@@ -18,12 +26,11 @@ docs/
|
||||
db/
|
||||
schema.sql # Database schema
|
||||
tooling/
|
||||
db/ # Connector scripts for SQLite, Qdrant, and audio
|
||||
db/ # Connector scripts for SQLite and audio
|
||||
config.json # Endpoint configuration
|
||||
ticket # Ticket CLI
|
||||
sprint # Sprint lifecycle CLI
|
||||
sqlite_connector.py # SQLite mini MCP
|
||||
qdrant_connector.py # Qdrant + ollama mini MCP
|
||||
audio_connector.py # Stable Audio Open connector
|
||||
.claude/
|
||||
agents/ # Agent personality files
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
# Ticket CLI
|
||||
|
||||
**Use `tooling/db/ticket`** for all ticket operations. Never use `sqlite3` directly (crashes in Claude Code).
|
||||
|
||||
## Positional arguments — not flags
|
||||
|
||||
`ticket create` uses **positional** arguments for `type` and `title`. There is no `--title` flag.
|
||||
|
||||
```bash
|
||||
# CORRECT — type and title are positional
|
||||
tooling/db/ticket create story "My ticket title" --description "Details here" --team server --priority low
|
||||
|
||||
# WRONG — --title does not exist, gets absorbed into the title string
|
||||
tooling/db/ticket create story --title "My ticket title" --description "Details here"
|
||||
# Creates a ticket titled: "--title My ticket title"
|
||||
```
|
||||
|
||||
## Full usage
|
||||
|
||||
```bash
|
||||
# Create
|
||||
tooling/db/ticket create <type> <title> [--parent N] [--priority P] [--decision D] [--team T] [--description TEXT]
|
||||
# type: initiative | epic | story | task | bug
|
||||
# priority: critical | high | medium | low
|
||||
|
||||
# Read
|
||||
tooling/db/ticket show <id>
|
||||
tooling/db/ticket list [--sprint N] [--team T] [--status S]
|
||||
|
||||
# Update
|
||||
tooling/db/ticket assign <id> <agent>
|
||||
```
|
||||
|
||||
## Key rules
|
||||
|
||||
- **Type and title are positional** — everything else is a flag
|
||||
- **Quote the title** — always wrap in double quotes to handle spaces
|
||||
- **Never use `sqlite3` CLI** — it crashes (std::bad_alloc). Use `tooling/db/sqlite-query` or `tooling/db/sqlite-exec` for raw SQL
|
||||
- **Verify after create** — run `tooling/db/ticket show <id>` to confirm the title is clean
|
||||
@@ -1,7 +1,8 @@
|
||||
{
|
||||
"autoMemoryDirectory": "/home/jeroenschweitzer/Projects/settled-reach/.memory",
|
||||
"env": {
|
||||
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
|
||||
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1",
|
||||
"SR_DB_PATH": "/var/home/jeroenschweitzer/Projects/settled-reach/settledreach.db"
|
||||
},
|
||||
"teammateMode": "in-process",
|
||||
"permissions": {
|
||||
@@ -30,10 +31,6 @@
|
||||
"Bash(tooling/db/sprint *)",
|
||||
"Bash(tooling/db/sqlite-query *)",
|
||||
"Bash(tooling/db/sqlite-exec *)",
|
||||
"Bash(tooling/db/qdrant-search *)",
|
||||
"Bash(tooling/db/qdrant-index *)",
|
||||
"Bash(tooling/db/qdrant-health)",
|
||||
"Bash(tooling/db/qdrant-count)",
|
||||
"Bash(tooling/db/sqlite-init)",
|
||||
"Bash(tooling/db/decisions-sync)",
|
||||
"Bash(tooling/db/decision *)",
|
||||
@@ -55,6 +52,10 @@
|
||||
"Bash(cargo build)",
|
||||
"Bash(cargo check *)",
|
||||
"Bash(cargo check)",
|
||||
"Bash(cargo clippy *)",
|
||||
"Bash(cargo clippy)",
|
||||
"Bash(ruff check *)",
|
||||
"Bash(ruff check)",
|
||||
"Bash(tests/run-*)",
|
||||
|
||||
"Bash(chmod *)",
|
||||
@@ -63,9 +64,10 @@
|
||||
"Bash(list *)",
|
||||
"Bash(tree *)",
|
||||
"Bash(sed -n *)",
|
||||
"Bash(.claude/skills/sprint-start/scripts/start-sprint.sh *)",
|
||||
"Bash(.claude/skills/sprint-start/scripts/sprint-teardown.sh *)",
|
||||
|
||||
"Skill(git-commit)",
|
||||
"Skill(worktree-update)",
|
||||
"Skill(sprint-start)",
|
||||
"Skill(sprint-plan)",
|
||||
"Skill(pr-push)",
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
---
|
||||
name: docs-search
|
||||
description: >
|
||||
Search project documents using semantic search (Qdrant + ollama) or grep fallback.
|
||||
Use when the user asks "did we discuss X?", "find references to Y", "search docs",
|
||||
or invokes /docs-search. Wraps the qdrant_connector.py for semantic document search.
|
||||
user-invocable: true
|
||||
allowed-tools: Bash, Read, Grep, Glob
|
||||
---
|
||||
|
||||
# Search Docs Skill
|
||||
|
||||
Semantic search across project documents. Endpoints are in
|
||||
`.claude/rules/local-services.md`. This skill covers advanced operations
|
||||
and workflows.
|
||||
|
||||
## Advanced Commands
|
||||
|
||||
### Index a single chunk
|
||||
|
||||
For precise indexing of specific content:
|
||||
```bash
|
||||
python3 tooling/db/qdrant_connector.py index "unique-id" "Text content to index" --metadata source=manual heading="Custom heading"
|
||||
```
|
||||
|
||||
### Create collection
|
||||
|
||||
Initialize the Qdrant collection (run once during setup):
|
||||
```bash
|
||||
python3 tooling/db/qdrant_connector.py create-collection
|
||||
```
|
||||
|
||||
## Bulk Indexing
|
||||
|
||||
Index all project documents at once:
|
||||
```bash
|
||||
for f in decisions/*.md DISCUSSION.md TEAM.md docs/discussions/*.md docs/briefings/*.md; do
|
||||
tooling/db/qdrant-index "$f"
|
||||
done
|
||||
```
|
||||
|
||||
## Fallback
|
||||
|
||||
If Qdrant or ollama is unreachable, fall back to grep-based search:
|
||||
```bash
|
||||
grep -r -i "search term" decisions/ DISCUSSION.md docs/ --include="*.md"
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
1. **Qatux (Librarian)** is the primary user of this skill
|
||||
2. After each discussion round, index the archived round file
|
||||
3. After briefing updates, re-index affected briefings
|
||||
4. After decision changes, re-index the relevant decisions/*.md domain files
|
||||
5. Use search to answer "did we discuss this?" questions with citations
|
||||
@@ -34,7 +34,35 @@ git branch --show-current
|
||||
|
||||
If on `main`, stop: "You're on main. Switch to a team branch first."
|
||||
|
||||
### 1b. Runtime smoke test (MANDATORY)
|
||||
### 1b. Zero warnings policy (MANDATORY)
|
||||
|
||||
Before pushing, verify the branch has **zero lint warnings**. Any warning
|
||||
must be either fixed or suppressed with a commented justification.
|
||||
|
||||
**For client/visual branches:**
|
||||
```bash
|
||||
gdlint client/scripts/ client/ui/ 2>&1
|
||||
```
|
||||
|
||||
If warnings remain, fix them before pushing. For warnings that cannot be
|
||||
fixed (e.g. intentional long lines in data literals), add a `# gdlint:
|
||||
ignore` comment with a reason.
|
||||
|
||||
**For server branches:**
|
||||
```bash
|
||||
cargo clippy -- -D warnings 2>&1
|
||||
```
|
||||
|
||||
**For CI/tooling branches:**
|
||||
```bash
|
||||
ruff check tooling/ 2>&1
|
||||
```
|
||||
|
||||
The goal is zero warnings in the pre-push output. Advisory warnings that
|
||||
the pre-push hook reports as "(advisory, not blocking)" should still be
|
||||
zero — they are advisory only because we haven't enforced them yet.
|
||||
|
||||
### 1c. Runtime smoke test (MANDATORY)
|
||||
|
||||
Before pushing, verify the game actually runs. This is non-negotiable —
|
||||
Sprint 28 proved that code review without runtime testing misses critical
|
||||
@@ -66,8 +94,22 @@ works on screen before invoking `/pr-push`. If they haven't, ask:
|
||||
|
||||
```bash
|
||||
git status
|
||||
git diff --stat
|
||||
```
|
||||
|
||||
**Run both commands from the repo root** (`git rev-parse --show-toplevel`).
|
||||
Running from a subdirectory can cause paths to not resolve, hiding real
|
||||
changes — Sprint 30 proved this when `git diff HEAD -- server/src/bin/atlas.rs`
|
||||
returned 0 lines from the wrong CWD, masking uncommitted agent work.
|
||||
|
||||
**CRITICAL: Do not trust "already done" claims without checking git state.**
|
||||
If agents report that work was "already implemented in a prior commit," verify
|
||||
by checking `git status` and `git diff --stat` first. Grepping source files
|
||||
only proves the code exists on disk — it does NOT prove the code is committed.
|
||||
Uncommitted working-tree changes look identical to committed code when you
|
||||
read files. Only `git status` distinguishes "already shipped" from "just
|
||||
written by a teammate."
|
||||
|
||||
If there are uncommitted changes (staged or unstaged), run the **commit skill**
|
||||
first. Use the `/git-commit` skill to group changes into logical commits with
|
||||
proper conventional commit messages. Wait for commit to complete before
|
||||
|
||||
@@ -16,16 +16,15 @@ on the branch type. All reviewers must approve for a clean review.
|
||||
|
||||
## Workflow
|
||||
|
||||
### 0. Branch guard — MUST be run by a Claude instance in the `main` worktree
|
||||
### 0. Branch guard — MUST be run from the `main` branch
|
||||
|
||||
```bash
|
||||
git branch --show-current
|
||||
```
|
||||
|
||||
If the current branch is **not `main`**, stop immediately and tell the user:
|
||||
"PR reviews must be run by a Claude instance in the `main` worktree."
|
||||
Do NOT proceed with the review. Do NOT work around this by reading files
|
||||
from another worktree — the review agent itself must be running in main.
|
||||
"PR reviews must be run from the `main` branch."
|
||||
Do NOT proceed with the review.
|
||||
Stop and wait for the user to invoke `/pr-review` from main.
|
||||
|
||||
### 0b. Verify runtime smoke test was performed
|
||||
@@ -48,20 +47,38 @@ godot --headless --path client --quit 2>&1 | grep -i "SCRIPT ERROR"
|
||||
If script errors appear in the branch diff files, flag them immediately
|
||||
before spawning reviewers — no point reviewing code that doesn't parse.
|
||||
|
||||
### 0c. Zero warnings check
|
||||
|
||||
The project enforces a **zero warnings policy**. Before spawning reviewers,
|
||||
check if the branch introduces lint warnings:
|
||||
|
||||
- **client/visual:** `gdlint client/scripts/ client/ui/` should report 0 issues
|
||||
- **server:** `cargo clippy -- -D warnings` should be clean
|
||||
- **ci/tooling:** `ruff check tooling/` should be clean
|
||||
|
||||
If warnings exist, note the count in the review output. Reviewers should
|
||||
flag any **new** warnings introduced by the branch as `warning` severity.
|
||||
Pre-existing warnings are not PR blockers but should be tracked for cleanup.
|
||||
|
||||
### 1. Determine the branch to review
|
||||
|
||||
If the user provided a branch name as argument, use it. Otherwise list open
|
||||
PRs and ask the user which branch to review.
|
||||
**Always start fresh.** Even if you reviewed this branch before in this
|
||||
conversation, the branch may have new commits, a new PR, or main may have
|
||||
moved. Do NOT skip steps or reuse earlier results. Every `/pr-review`
|
||||
invocation is a full review cycle.
|
||||
|
||||
**Always fetch and check for PRs first:**
|
||||
|
||||
To list open PRs on Gitea:
|
||||
```bash
|
||||
git fetch --all
|
||||
tea pr list --login schweitz --repo jpmschweitzer/settled-reach --state open --output simple
|
||||
```
|
||||
|
||||
Fetch remote branches first:
|
||||
```bash
|
||||
git fetch --all
|
||||
```
|
||||
Then determine the branch:
|
||||
- If the user provided a branch name as argument, match it to an open PR.
|
||||
If a PR exists for that branch, note the PR number. If no PR exists,
|
||||
proceed with the branch diff but note "no PR found" in the output.
|
||||
- If no argument was given, list open PRs and ask which to review.
|
||||
|
||||
### 2. Determine reviewer team
|
||||
|
||||
@@ -99,39 +116,24 @@ Three-dot diff with pathspec exclusions is unreliable. Instead, either:
|
||||
For large diffs (>1000 lines of source), provide **source files** rather than
|
||||
raw diff to reviewers — cleaner context, better reviews.
|
||||
|
||||
**IMPORTANT — use team directory paths for ALL agents.** Each team branch
|
||||
is checked out in its own directory at:
|
||||
**Reviewer agents read source files via `git show`.** Sprint branches
|
||||
use the naming pattern `sprint-{N}/{team}`. To read a file from the
|
||||
branch being reviewed:
|
||||
|
||||
```
|
||||
/var/mnt/data/projects/settled-reach/<branch>/
|
||||
```bash
|
||||
git show origin/<branch>:<path>
|
||||
```
|
||||
|
||||
For example, the `copy` team directory is at:
|
||||
```
|
||||
/var/mnt/data/projects/settled-reach/copy/content/dialogue/...
|
||||
For example:
|
||||
```bash
|
||||
git show origin/sprint-31/server:server/src/bin/atlas.rs
|
||||
```
|
||||
|
||||
**All reviewer agents** (regardless of Bash access) should read source files
|
||||
from the team directory using the Read tool. This is more reliable than
|
||||
`git show origin/<branch>:<path>` because:
|
||||
- All agents have Read access (no Bash dependency)
|
||||
- Files are always the actual branch checkout (no stale cache)
|
||||
- No risk of accidentally reading from main's working directory
|
||||
If the sprint branch has an active worktree (under `.sprint/`), reviewers
|
||||
can also use the Read tool with the worktree path. But `git show` is
|
||||
the reliable default — it works whether or not a worktree exists.
|
||||
|
||||
When constructing reviewer prompts, tell agents to read files from the
|
||||
team directory. Example instruction for agents:
|
||||
|
||||
```
|
||||
Read the changed files from the team directory. The branch is checked
|
||||
out at: /var/mnt/data/projects/settled-reach/<branch>/
|
||||
|
||||
For example, to read `content/dialogue/the-terminal/kael-davan.yaml`,
|
||||
use: /var/mnt/data/projects/settled-reach/<branch>/content/dialogue/the-terminal/kael-davan.yaml
|
||||
```
|
||||
|
||||
Also tell agents to read relevant `decisions/*.md` files from the same
|
||||
directory (they're identical to main, but using the team directory path
|
||||
keeps agents grounded in the correct location).
|
||||
Also tell agents to read relevant `decisions/*.md` files for context.
|
||||
|
||||
### 4. Spawn reviewers in parallel
|
||||
|
||||
@@ -154,9 +156,9 @@ reviewer that was spawned (2 for code/visual/audio, 3 for copy):
|
||||
|
||||
### <Reviewer Name> (<Focus>): [APPROVE | REQUEST_CHANGES]
|
||||
[Summary]
|
||||
| # | File | Severity | Issue |
|
||||
|---|------|----------|-------|
|
||||
| 1 | path:line | critical/warning/suggestion | description |
|
||||
| # | File | Issue |
|
||||
|---|------|-------|
|
||||
| 1 | path:line | description |
|
||||
|
||||
### <Reviewer Name> (<Focus>): [APPROVE | REQUEST_CHANGES]
|
||||
...
|
||||
@@ -190,13 +192,18 @@ Respond with:
|
||||
2. Summary: 2-3 sentence overall assessment
|
||||
3. Comments: List of specific issues, each with:
|
||||
- File path and approximate location
|
||||
- Severity: critical / warning / suggestion
|
||||
- Description of the issue
|
||||
|
||||
Verdict rules:
|
||||
- Any **critical** or **warning** issue → REQUEST_CHANGES
|
||||
- Only **suggestion**-level issues (or none) → APPROVE
|
||||
If no issues found, say APPROVE with a brief positive summary.
|
||||
- **Any comment at all → REQUEST_CHANGES.** Every issue is actionable.
|
||||
There is no "suggestion" tier that gets skipped. If it's worth
|
||||
mentioning, it's worth fixing before merge.
|
||||
- If no issues found, say APPROVE with a brief positive summary.
|
||||
- Do NOT flag something unless you expect it to be addressed. If you
|
||||
wouldn't fix it yourself, don't mention it.
|
||||
- **Quality and polish is the golden standard.** We are not optimizing
|
||||
for speed — we are optimizing for a product we're proud of. If
|
||||
something can be better, say so.
|
||||
```
|
||||
|
||||
## 6. Posting results to Gitea
|
||||
@@ -239,8 +246,24 @@ review outcome:
|
||||
**CHANGES_REQUESTED:**
|
||||
The sprint-start lifecycle (step 9c) handles dispatching review
|
||||
comments to agents. After presenting results, remind the lead:
|
||||
"Review requested changes. Create tasks from the warnings/critical
|
||||
issues and dispatch to idle agents, then re-push and re-review."
|
||||
"Review requested changes. Create tasks from each issue and dispatch
|
||||
to idle agents, then re-push and re-review."
|
||||
|
||||
The team may **push back** on specific comments. When a team agent
|
||||
disagrees with a reviewer comment, the process is:
|
||||
|
||||
1. The team agent explains why the comment should be retracted — with
|
||||
a concrete technical rationale, not just "I disagree."
|
||||
2. The team lead (you) evaluates the pushback. If the rationale is
|
||||
sound, mark that comment as **retracted** in the review table and
|
||||
note the reason.
|
||||
3. If the team lead is unsure, escalate to the user for a ruling.
|
||||
4. Retracted comments do NOT need to be fixed. The re-review should
|
||||
note which comments were retracted and why.
|
||||
|
||||
This prevents reviews from becoming dogma while maintaining the rule
|
||||
that every comment is taken seriously. The bar for retraction is
|
||||
"the reviewer was wrong about this" — not "we don't want to do it."
|
||||
|
||||
**APPROVED:**
|
||||
The sprint-start lifecycle (step 9c) handles shutdown. After
|
||||
|
||||
@@ -2,17 +2,16 @@
|
||||
|
||||
Use `model: sonnet` for all reviewers — sufficient for review, saves cost.
|
||||
|
||||
**All reviewer agents read from team directories.** Each team branch is
|
||||
checked out in its own directory at:
|
||||
`/var/mnt/data/projects/settled-reach/<branch>/`
|
||||
|
||||
Tell every reviewer agent to read source files from the team directory
|
||||
using the Read tool. Include the directory path and a list of changed
|
||||
files in every prompt. Do NOT rely on `git show` or paste file contents —
|
||||
agents can read directly from the directory.
|
||||
|
||||
Note: cross-directory reading is only permitted for review agents spawned
|
||||
from the `main` team. Team agents must stay within their own directory.
|
||||
**Reviewer agents read source files via `git show` or from sprint
|
||||
worktrees.** Sprint branches use `sprint-{N}/{team}` naming. Include
|
||||
the branch name and a list of changed files in every prompt. The
|
||||
default approach is `git show origin/<branch>:<path>`. If an active
|
||||
worktree exists under `.sprint/`, agents can also use the Read tool
|
||||
with the worktree path. **Always prefer `git show` over worktree
|
||||
reads** — worktrees may use sparse checkouts that silently exclude
|
||||
files, causing reviewers to miss content and produce false findings
|
||||
(Sprint 33 lesson: Paula reported missing prose that was actually
|
||||
present, because the worktree excluded the wiki directory).
|
||||
|
||||
## Code reviews (`server`, `client`, `ci`)
|
||||
|
||||
|
||||
@@ -154,12 +154,9 @@ Create `docs/sprints/sprint-N/` and write one file per team.
|
||||
Read the template at `references/briefing-template.md` in this skill directory
|
||||
for the exact file structure.
|
||||
|
||||
**IMPORTANT — relative paths only:** Each team works in its own directory
|
||||
containing the full repo (`server/`, `client/`, `docs/`, etc.). All file
|
||||
paths in briefings must be relative to the working directory. Example:
|
||||
`server/src/bridge/types.rs`, not `/absolute/path/to/server/src/...` or
|
||||
paths that navigate outside (`../sibling-dir/...`).
|
||||
Agents must stay within their team's working directory.
|
||||
**Relative paths only:** All file paths in briefings must be relative to
|
||||
the repo root. Example: `server/src/bridge/types.rs`, not absolute paths.
|
||||
Each sprint branch (`sprint-{N}/{team}`) contains the full repo.
|
||||
|
||||
Key requirements per file:
|
||||
- **server.md**: Carry-overs, new tickets, dependency chain, key decisions, notes
|
||||
|
||||
@@ -9,7 +9,7 @@ Each team gets one briefing file at `docs/sprints/sprint-N/<team>.md`.
|
||||
|
||||
**Goal:** <One-sentence sprint goal, shared across all teams>
|
||||
|
||||
**Branch:** `<team>`
|
||||
**Branch:** `sprint-{N}/<team>`
|
||||
**Agents:** <Agent names and roles>
|
||||
|
||||
## Carry-over from Sprint N-1
|
||||
@@ -57,7 +57,7 @@ One bullet per ticket with:
|
||||
|
||||
When ready to submit, create a PR with `tea` CLI. **All flags are required** to avoid TTY prompts (see CLAUDE.md "Gitea access" section):
|
||||
\```bash
|
||||
tea pr create --repo jpmschweitzer/settled-reach --login schweitz --title "feat(<scope>): description" --description "body" --base main --head <branch>
|
||||
tea pr create --repo jpmschweitzer/settled-reach --login schweitz --title "feat(<scope>): description" --description "body" --base main --head sprint-{N}/<team>
|
||||
\```
|
||||
```
|
||||
|
||||
@@ -73,7 +73,8 @@ The `joint.md` file additionally includes:
|
||||
|
||||
| Team | Branch | Agents | Scope |
|
||||
|------|--------|--------|-------|
|
||||
| server | `server` | Dudley (simulation), Oscar (networking) | Rust/bevy_ecs simulation |
|
||||
| client | `client` | Stig (UI), Oscar (networking) | Godot client rendering |
|
||||
| server | `sprint-{N}/server` | Dudley (simulation), Oscar (networking) | server/, Rust/bevy_ecs simulation |
|
||||
| client | `sprint-{N}/client` | Stig (UI), Oscar (networking) | client/, Godot rendering |
|
||||
| copy | `sprint-{N}/copy` | Mellanie, Paula, Miri | wiki/, docs/atlas/, content/ |
|
||||
| joint | both | All implementation agents | Integration, proofs, cross-team schema |
|
||||
| content | (none) | Mellanie, Paula, Miri, Araminta | Content authoring, no code branch |
|
||||
|
||||
@@ -25,8 +25,8 @@ The current branch IS the team. Read it with:
|
||||
git branch --show-current
|
||||
```
|
||||
|
||||
Valid team branches: `server`, `client`, `copy`, `audio`, `visual`, `ci`,
|
||||
`planning`.
|
||||
Sprint branches follow the pattern `sprint-{N}/{team}` (e.g. `sprint-31/server`).
|
||||
Valid team names: `server`, `client`, `copy`, `audio`, `visual`, `ci`, `planning`.
|
||||
|
||||
If on `main`, follow the **Main branch workflow** below instead of
|
||||
the team branch workflow (steps 2–8).
|
||||
@@ -130,6 +130,18 @@ If the user raises items that should be tracked, create Q-NNN entries
|
||||
or backlog tickets on the spot. If process changes are agreed, update
|
||||
the relevant skill files or CLAUDE.md immediately — don't defer them.
|
||||
|
||||
#### A1c. Clean up sprint worktrees
|
||||
|
||||
Remove ephemeral worktrees for the closed sprint. Run the teardown script:
|
||||
|
||||
```bash
|
||||
.claude/skills/sprint-start/scripts/sprint-teardown.sh {N}
|
||||
```
|
||||
|
||||
This removes all worktrees under `.sprint/sprint-{N}/` and prunes git
|
||||
metadata. Safe to skip if the sprint didn't use ephemeral worktrees
|
||||
(e.g. legacy persistent worktree setup).
|
||||
|
||||
#### A2. Bump the version
|
||||
|
||||
The project version scheme is `v0.1.{sprint_number}`. After closing
|
||||
@@ -197,10 +209,20 @@ If everything looks ready, activate the sprint:
|
||||
tooling/db/sprint start
|
||||
```
|
||||
|
||||
Then report:
|
||||
Then open team terminal tabs automatically:
|
||||
|
||||
```bash
|
||||
.claude/skills/sprint-start/scripts/start-sprint.sh
|
||||
```
|
||||
|
||||
This creates ephemeral worktrees under `.sprint/sprint-{N}/{team}/` for
|
||||
each team with open tickets, and opens Ptyxis windows with tmux + Claude
|
||||
auto-starting in each tab. The user will have one tab per active team.
|
||||
|
||||
Report:
|
||||
- Sprint activated (name, ticket count per team)
|
||||
- Remind the user to switch to a team branch and run `/sprint-start`
|
||||
there (or `cd` into the relevant worktree)
|
||||
- Worktrees created and tabs opened
|
||||
- Each team tab runs `/sprint-start` to load briefing and spawn agents
|
||||
|
||||
---
|
||||
|
||||
@@ -215,6 +237,9 @@ to plan the next sprint.
|
||||
|
||||
### 2. Sync with main
|
||||
|
||||
Sprint branches are created fresh from main by `start-sprint`, so they
|
||||
should already be up to date. If main has moved since branch creation:
|
||||
|
||||
```bash
|
||||
git fetch --all
|
||||
git merge origin/main --no-edit
|
||||
@@ -329,14 +354,14 @@ Task(
|
||||
team_name: "sprint-{N}-{team}",
|
||||
name: "{name_lowercase}",
|
||||
prompt: "You are on the {team} team for Sprint {N}.
|
||||
Branch: `{team}`
|
||||
Branch: `sprint-{N}/{team}`
|
||||
|
||||
RULES (NON-NEGOTIABLE):
|
||||
|
||||
0. TEAM BOUNDARY: Your team is `{team}` ($WORKTREE_TEAM). Stay
|
||||
within the current working directory. Do NOT navigate to
|
||||
parent or sibling directories. Do NOT follow .git pointers
|
||||
to other directories.
|
||||
0. TEAM SCOPE: Your team is `{team}` on branch `sprint-{N}/{team}`.
|
||||
Stay within your team's file scope (server → server/, client → client/, copy → wiki/ + docs/atlas/ + content/).
|
||||
You may read (but not modify): docs/, decisions/, wiki/, .claude/
|
||||
Do NOT modify files belonging to other teams.
|
||||
|
||||
1. GIT: Do NOT run any git commands (commit, push, pull, merge,
|
||||
checkout, branch, stash, tag, etc.). All git operations are
|
||||
@@ -487,30 +512,38 @@ When all tasks are complete (TaskList shows all completed):
|
||||
Run `/git-commit` to commit all changes, then `/pr-push` to create or
|
||||
update the PR. Do NOT shut down agents — the team stays alive for review.
|
||||
|
||||
#### 9b. Review
|
||||
#### 9b. Wait for review
|
||||
|
||||
Run `/pr-review` to spawn temporary reviewers. Wait for results.
|
||||
Do NOT run `/pr-review` from the team window — PR reviews run from
|
||||
the `main` branch (a separate window/session). The team window stays
|
||||
on its sprint branch.
|
||||
|
||||
After pushing and creating the PR, report the PR number to the user
|
||||
and stop. Wait for review feedback to arrive (the user or the main
|
||||
session will relay it, or it will appear as Gitea PR comments).
|
||||
|
||||
#### 9c. Handle review outcome
|
||||
|
||||
When review feedback arrives (from the user, main session, or PR
|
||||
comments):
|
||||
|
||||
**If CHANGES_REQUESTED:**
|
||||
|
||||
1. Parse the review comment table (from the Gitea PR comment or the
|
||||
review output). Extract each warning/critical issue with:
|
||||
review output). Extract each issue with:
|
||||
- File path and approximate line
|
||||
- Severity (critical / warning / suggestion)
|
||||
- Description
|
||||
|
||||
2. Create a task per warning/critical issue:
|
||||
2. Create a task per issue:
|
||||
```
|
||||
TaskCreate(
|
||||
subject: "Review: {short description}",
|
||||
description: "{full issue description from review table, including
|
||||
file path, severity, and reviewer name}",
|
||||
file path and reviewer name}",
|
||||
activeForm: "Fixing review comment: {short description}"
|
||||
)
|
||||
```
|
||||
Skip suggestion-severity items unless they are trivial (1-line fixes).
|
||||
Every comment is actionable — there is no "suggestion" tier to skip (per pr-review policy).
|
||||
|
||||
3. Dispatch to idle agents: send each a message via SendMessage telling
|
||||
them to check TaskList for new review-fix tasks. Agents claim and
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#!/bin/bash
|
||||
# Clean up ephemeral worktrees for a closed sprint.
|
||||
# Usage: sprint-teardown.sh <sprint-number>
|
||||
#
|
||||
# Removes all worktrees under .sprint/sprint-{N}/ and prunes git metadata.
|
||||
# Safe to run multiple times — skips already-removed worktrees.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/../../../.." && pwd)"
|
||||
SPRINT_BASE="$(dirname "$REPO_ROOT")/.sprint"
|
||||
SPRINT=${1:?Usage: sprint-teardown.sh <sprint-number>}
|
||||
|
||||
SPRINT_DIR="$SPRINT_BASE/sprint-${SPRINT}"
|
||||
|
||||
if [ ! -d "$SPRINT_DIR" ]; then
|
||||
echo "No worktrees found for sprint-${SPRINT} (directory $SPRINT_DIR does not exist)."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "Cleaning sprint-${SPRINT} worktrees..."
|
||||
|
||||
for wt in "$SPRINT_DIR"/*/; do
|
||||
[ -d "$wt" ] || continue
|
||||
team="$(basename "$wt")"
|
||||
echo " Removing: $team"
|
||||
git -C "$REPO_ROOT" worktree remove "$wt" --force 2>/dev/null || echo " (already removed or dirty)"
|
||||
done
|
||||
|
||||
rmdir "$SPRINT_DIR" 2>/dev/null || true
|
||||
git -C "$REPO_ROOT" worktree prune
|
||||
|
||||
echo "Done. Sprint-${SPRINT} worktrees cleaned."
|
||||
@@ -0,0 +1,65 @@
|
||||
#!/bin/bash
|
||||
# Opens Ptyxis tabs for the active sprint teams in the CURRENT window.
|
||||
# Auto-starts Claude Code in each tab via tmux.
|
||||
#
|
||||
# Usage: start-sprint.sh [sprint-number]
|
||||
# If omitted, auto-detects the active sprint from the database.
|
||||
#
|
||||
# Assumes the caller is already on main in the current terminal.
|
||||
# Adds one tab per active team — no duplicate main tab.
|
||||
#
|
||||
# Worktrees are created under .sprint/ (ephemeral, cleaned after sprint close).
|
||||
# Can be called from any directory — resolves paths from the script location.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
# Script lives at .claude/skills/sprint-start/scripts/ — repo root is 4 levels up
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/../../../.." && pwd)"
|
||||
# Parent of repo root is where .sprint/ and the DB live
|
||||
PARENT="$(dirname "$REPO_ROOT")"
|
||||
|
||||
# Resolve sprint number — argument or active sprint from DB
|
||||
if [ -n "${1:-}" ]; then
|
||||
SPRINT="$1"
|
||||
else
|
||||
SPRINT=$(cd "$REPO_ROOT" && tooling/db/sqlite-query "SELECT id FROM sprints WHERE status='active'" 2>/dev/null | python3 -c "import sys,json; print(json.load(sys.stdin)['rows'][0]['id'])" 2>/dev/null || true)
|
||||
if [ -z "$SPRINT" ]; then
|
||||
echo "error: no active sprint found. Pass a sprint number or activate a sprint first." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Query teams with open tickets
|
||||
TEAMS=$(cd "$REPO_ROOT" && tooling/db/sqlite-query "SELECT DISTINCT team FROM tickets WHERE sprint_id=$SPRINT AND status NOT IN ('done','cancelled') AND team IS NOT NULL" 2>/dev/null | python3 -c "import sys,json; [print(r['team']) for r in json.load(sys.stdin)['rows'] if r['team']]" 2>/dev/null || true)
|
||||
|
||||
if [ -z "$TEAMS" ]; then
|
||||
echo "Sprint $SPRINT has no open tickets. Opening main only."
|
||||
fi
|
||||
|
||||
echo "Sprint $SPRINT — teams: ${TEAMS:-none}"
|
||||
|
||||
# ── Open team tabs in the CURRENT window ────────────────────────────
|
||||
# No separate main tab — the caller is already on main.
|
||||
# All team tabs open as --tab in the active Ptyxis window.
|
||||
for team in $TEAMS; do
|
||||
BRANCH="sprint-${SPRINT}/${team}"
|
||||
WDIR="$PARENT/.sprint/sprint-${SPRINT}/${team}"
|
||||
|
||||
# Create worktree if it doesn't exist
|
||||
if [ ! -d "$WDIR" ]; then
|
||||
echo "Creating worktree: $WDIR (branch: $BRANCH)"
|
||||
mkdir -p "$(dirname "$WDIR")"
|
||||
# Create branch from main if it doesn't exist remotely
|
||||
if git -C "$REPO_ROOT" rev-parse --verify "origin/$BRANCH" >/dev/null 2>&1; then
|
||||
git -C "$REPO_ROOT" worktree add "$WDIR" "$BRANCH"
|
||||
else
|
||||
git -C "$REPO_ROOT" worktree add -b "$BRANCH" "$WDIR" HEAD
|
||||
fi
|
||||
fi
|
||||
|
||||
ptyxis --tab -d "$WDIR" -x 'tmux new-session \; send-keys "claude /sprint-start" Enter'
|
||||
sleep 0.3
|
||||
done
|
||||
|
||||
echo "Session ready. Main + ${TEAMS:-(no teams)}"
|
||||
@@ -1,125 +0,0 @@
|
||||
---
|
||||
name: worktree-update
|
||||
description: >
|
||||
Sync worktree branches with main. Use when the user says "update worktrees",
|
||||
"sync branches", "merge main", "worktree update", or invokes /worktree-update.
|
||||
When on main: shows which worktree branches are ahead and lets the user pick
|
||||
which to merge into main (flags branches with open PRs). When on a non-main
|
||||
branch: merges main into the current branch. All operations are non-destructive.
|
||||
user-invocable: true
|
||||
allowed-tools: Bash, Read, AskUserQuestion
|
||||
---
|
||||
|
||||
# Worktree Update Skill
|
||||
|
||||
Sync worktree branches safely. Direction depends on the current branch.
|
||||
|
||||
## Safety Rules (NON-NEGOTIABLE)
|
||||
|
||||
- **Never force-push, reset --hard, rebase, or delete branches.**
|
||||
- **Never use `--no-verify` or skip hooks.**
|
||||
- **Always use `--no-edit` on merges** to avoid interactive editor prompts.
|
||||
- **Stop on merge conflicts** — report them and let the user decide. Never
|
||||
auto-resolve or abort a conflicted merge without asking.
|
||||
- **Fetch before comparing** — always `git fetch --all` first so commit
|
||||
comparisons are accurate.
|
||||
- **Dry-run first on main** — show the user exactly what will happen before
|
||||
merging anything into main.
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Detect current branch
|
||||
|
||||
```bash
|
||||
git branch --show-current
|
||||
```
|
||||
|
||||
Branch determines the mode: `main` → outbound sync, anything else → inbound sync.
|
||||
|
||||
### 2a. On `main` — merge worktree branches into main
|
||||
|
||||
#### Fetch and compare
|
||||
|
||||
```bash
|
||||
git fetch --all
|
||||
```
|
||||
|
||||
Discover all worktree branches (excluding `main` itself):
|
||||
|
||||
```bash
|
||||
git worktree list | grep -v '\[main\]' | sed 's/.*\[//;s/\]//'
|
||||
```
|
||||
|
||||
For each worktree branch, check if it has commits ahead of main:
|
||||
|
||||
```bash
|
||||
git rev-list --count main..origin/<branch>
|
||||
```
|
||||
|
||||
Skip branches with 0 commits ahead. For branches that ARE ahead, collect:
|
||||
- Branch name
|
||||
- Number of commits ahead
|
||||
- One-line log of those commits: `git log --oneline main..<branch>`
|
||||
|
||||
#### Check for open PRs
|
||||
|
||||
```bash
|
||||
tea pr list --login schweitz --repo jpmschweitzer/settled-reach --state open --output simple
|
||||
```
|
||||
|
||||
Cross-reference open PR head branches with the ahead-of-main branches.
|
||||
|
||||
#### Present results
|
||||
|
||||
Show a summary table of branches ahead of main. For each branch, indicate:
|
||||
- `[PR]` if it has an open pull request — warn that it should go through
|
||||
normal review channels (use `/pr-review` instead)
|
||||
- Commit count and summary
|
||||
|
||||
Use `AskUserQuestion` to let the user pick which branches to merge.
|
||||
Exclude PR-flagged branches from the default options (but allow the user to
|
||||
override via "Other").
|
||||
|
||||
#### Merge selected branches
|
||||
|
||||
For each selected branch, one at a time:
|
||||
|
||||
```bash
|
||||
git merge <branch> --no-edit
|
||||
```
|
||||
|
||||
If a merge conflicts, **stop immediately**. Report the conflict and do NOT
|
||||
continue to the next branch. The user must resolve before proceeding.
|
||||
|
||||
After all merges, show the final state with `git log --oneline -N` (where N
|
||||
covers the new commits).
|
||||
|
||||
#### Backup the shared database
|
||||
|
||||
After successful merges on main, snapshot the database for git tracking:
|
||||
|
||||
```bash
|
||||
make db-backup
|
||||
```
|
||||
|
||||
This copies the shared `settledreach.db` (in the parent directory) to
|
||||
`docs/backups/settledreach.db.backup`. Stage and commit it with the merge
|
||||
if the file changed.
|
||||
|
||||
### 2b. Not on `main` — merge main into current branch
|
||||
|
||||
```bash
|
||||
git fetch --all
|
||||
git merge origin/main --no-edit
|
||||
```
|
||||
|
||||
If clean, report the result (fast-forward or merge commit, files changed).
|
||||
If conflicts, report them and stop.
|
||||
|
||||
### 3. Push
|
||||
|
||||
After a successful merge, push the branch:
|
||||
|
||||
```bash
|
||||
git push origin <current-branch>
|
||||
```
|
||||
@@ -14,10 +14,12 @@ REMOTE_REF="origin/$BRANCH"
|
||||
if git rev-parse --verify "$REMOTE_REF" >/dev/null 2>&1; then
|
||||
CLIENT_CHANGED=$(git diff --name-only "$REMOTE_REF"..HEAD -- client/ 2>/dev/null | wc -l)
|
||||
SERVER_CHANGED=$(git diff --name-only "$REMOTE_REF"..HEAD -- server/ 2>/dev/null | wc -l)
|
||||
TOOLING_CHANGED=$(git diff --name-only "$REMOTE_REF"..HEAD -- tooling/ pyproject.toml 2>/dev/null | wc -l)
|
||||
else
|
||||
# New branch or no remote ref — fall through to directory checks
|
||||
CLIENT_CHANGED=1
|
||||
SERVER_CHANGED=1
|
||||
TOOLING_CHANGED=1
|
||||
fi
|
||||
|
||||
# --- GDScript parse check (headless Godot) ---
|
||||
@@ -97,6 +99,45 @@ else
|
||||
echo "pre-push: WARNING — cargo not found or server/ missing, skipping Rust lint"
|
||||
fi
|
||||
|
||||
# --- Python lint (ruff) ---
|
||||
if [ "$TOOLING_CHANGED" -eq 0 ]; then
|
||||
echo "pre-push: no tooling/ changes — skipping Python lint"
|
||||
elif command -v ruff >/dev/null 2>&1 && [ -d "$REPO_ROOT/tooling" ]; then
|
||||
echo "pre-push: checking Python (ruff)..."
|
||||
if ! (cd "$REPO_ROOT" && ruff check tooling/ 2>&1); then
|
||||
ERRORS=$((ERRORS + 1))
|
||||
else
|
||||
echo "pre-push: ruff — OK"
|
||||
fi
|
||||
else
|
||||
echo "pre-push: skipping Python lint (ruff not found — install with: pip install 'ruff>=0.9')"
|
||||
fi
|
||||
|
||||
# --- JSON syntax validation ---
|
||||
if git rev-parse --verify "$REMOTE_REF" >/dev/null 2>&1; then
|
||||
JSON_FILES=$(git diff --name-only "$REMOTE_REF"..HEAD -- '*.json' 2>/dev/null || true)
|
||||
else
|
||||
JSON_FILES=$(git ls-files '*.json')
|
||||
fi
|
||||
if [ -n "$JSON_FILES" ]; then
|
||||
echo "pre-push: checking JSON syntax..."
|
||||
JSON_FAIL=0
|
||||
while IFS= read -r f; do
|
||||
if [ -f "$REPO_ROOT/$f" ] && ! python3 -m json.tool "$REPO_ROOT/$f" >/dev/null 2>&1; then
|
||||
echo " FAIL: $f"
|
||||
JSON_FAIL=$((JSON_FAIL + 1))
|
||||
fi
|
||||
done <<< "$JSON_FILES"
|
||||
if [ "$JSON_FAIL" -gt 0 ]; then
|
||||
echo "pre-push: FAIL — $JSON_FAIL JSON file(s) have syntax errors"
|
||||
ERRORS=$((ERRORS + 1))
|
||||
else
|
||||
echo "pre-push: JSON — OK ($(echo "$JSON_FILES" | wc -l) file(s))"
|
||||
fi
|
||||
else
|
||||
echo "pre-push: no JSON changes — skipping"
|
||||
fi
|
||||
|
||||
if [ "$ERRORS" -gt 0 ]; then
|
||||
echo ""
|
||||
echo "pre-push: $ERRORS check(s) failed. Push aborted."
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
class-definitions-order:
|
||||
- tools
|
||||
- classnames
|
||||
- extends
|
||||
- docstrings
|
||||
- signals
|
||||
- enums
|
||||
- consts
|
||||
- staticvars
|
||||
- exports
|
||||
- pubvars
|
||||
- prvvars
|
||||
- onreadypubvars
|
||||
- onreadyprvvars
|
||||
- others
|
||||
class-load-variable-name: (([A-Z][a-z0-9]*)+|_?[a-z][a-z0-9]*(_[a-z0-9]+)*)
|
||||
class-name: ([A-Z][a-z0-9]*)+
|
||||
class-variable-name: _?[a-z][a-z0-9]*(_[a-z0-9]+)*
|
||||
comparison-with-itself: null
|
||||
constant-name: _?[A-Z][A-Z0-9]*(_[A-Z0-9]+)*
|
||||
disable: []
|
||||
duplicated-load: null
|
||||
enum-element-name: '[A-Z][A-Z0-9]*(_[A-Z0-9]+)*'
|
||||
enum-name: ([A-Z][a-z0-9]*)+
|
||||
excluded_directories: !!set
|
||||
.git: null
|
||||
addons: null
|
||||
expression-not-assigned: null
|
||||
function-argument-name: _?[a-z][a-z0-9]*(_[a-z0-9]+)*
|
||||
function-arguments-number: 10
|
||||
function-name: (_on_([A-Z][a-z0-9]*)+(_[a-z0-9]+)*|_?[a-z][a-z0-9]*(_[a-z0-9]+)*)
|
||||
function-preload-variable-name: ([A-Z][a-z0-9]*)+
|
||||
function-variable-name: '[a-z][a-z0-9]*(_[a-z0-9]+)*'
|
||||
load-constant-name: (([A-Z][a-z0-9]*)+|_?[A-Z][A-Z0-9]*(_[A-Z0-9]+)*)
|
||||
loop-variable-name: _?[a-z][a-z0-9]*(_[a-z0-9]+)*
|
||||
max-file-lines: 1000
|
||||
max-line-length: 120
|
||||
max-public-methods: 200
|
||||
max-returns: 6
|
||||
mixed-tabs-and-spaces: null
|
||||
no-elif-return: null
|
||||
no-else-return: null
|
||||
signal-name: '[a-z][a-z0-9]*(_[a-z0-9]+)*'
|
||||
sub-class-name: _?([A-Z][a-z0-9]*)+
|
||||
tab-characters: 1
|
||||
trailing-whitespace: null
|
||||
unnecessary-pass: null
|
||||
unused-argument: null
|
||||
@@ -1,8 +1,12 @@
|
||||
# Secrets
|
||||
.env
|
||||
|
||||
# Runtime databases (not tracked — created on startup)
|
||||
# Local-only settings DB and WAL/SHM sidecars of tracked DBs
|
||||
server/settings.db
|
||||
server/settings.db-shm
|
||||
server/settings.db-wal
|
||||
server/data/systems.db-shm
|
||||
server/data/systems.db-wal
|
||||
|
||||
# Build and cache
|
||||
.cache/
|
||||
@@ -11,9 +15,9 @@ server/target/
|
||||
server/sr-voice/target/
|
||||
server/models/
|
||||
tooling/content-converter/target/
|
||||
tooling/econ-sim/target/
|
||||
tooling/line-previewer/target/
|
||||
tooling/test-client/target/
|
||||
content-ron/
|
||||
|
||||
# Godot client
|
||||
client/.godot/
|
||||
@@ -32,6 +36,14 @@ renderer/output/*.png
|
||||
spikes/**/.godot/
|
||||
spikes/**/*.import
|
||||
spikes/**/*.uid
|
||||
spikes/**/*.npy
|
||||
spikes/**/*.npz
|
||||
|
||||
# Planet generator intermediates
|
||||
*.tmp.npz
|
||||
|
||||
# Generated terrain grids (large, regenerated from pipeline)
|
||||
wiki/**/bodies/**/terrain.npz
|
||||
|
||||
# Asset downloads (vendor archives, not game content)
|
||||
docs/assets/downloads/
|
||||
@@ -39,9 +51,6 @@ docs/assets/downloads/
|
||||
# Reference repos for investigation
|
||||
vendor/
|
||||
|
||||
# Database (shared across worktrees at ../settledreach.db, not tracked)
|
||||
db/commonwealth.db*
|
||||
|
||||
# Frame0 ID mapping files (ephemeral, per-machine)
|
||||
*.idmap.json
|
||||
|
||||
@@ -57,6 +66,7 @@ Thumbs.db
|
||||
# IDE
|
||||
.idea/
|
||||
.vscode/
|
||||
.obsidian/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
@@ -65,5 +75,4 @@ Thumbs.db
|
||||
.claude/plans/
|
||||
.claude/projects/
|
||||
.claude/agent-memory/
|
||||
client-tmp/
|
||||
.tmp/
|
||||
|
||||
@@ -6,6 +6,164 @@ Format based on [Keep a Changelog](https://keepachangelog.com/).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [v0.1.35] — 2026-04-18
|
||||
|
||||
### Added
|
||||
- Gemma 4 batch naming pipeline (`tooling/planet-gen/gemma_naming.py`): wiki-grounded register selection, per-body mood injection, 2x oversampled batch naming with Levenshtein ranking, corridor-scoped dedup (#833)
|
||||
- 24,963 named geographic features across 299 star systems: 329 cities, 2,701 rivers, 6,457 oceans, 286 POIs, 15,190 mountain ranges — culturally authentic per corridor (Portuguese south_reach, Korean east_reach, Nordic west_reach, frontier deep_frontier)
|
||||
- Atlas implant panel — system picker, orbital diagram, body navigation (#834)
|
||||
- Atlas heightmap viewer — pan/zoom, marker overlay, city data panel (#835)
|
||||
- Atlas overlay system — 9 MVP overlays with visibility toggles (#836)
|
||||
- Hand-authored atlas templates for 6 bodies: Lendel (GJ-380), Vuurkloof (GJ-35), Røros (GJ-66B), Estrade (GJ-280A), Cairnside (GJ-892), Edict (GJ-244A) (#837)
|
||||
- Brand layer DB schema: brand_products, brand_inputs, system_fiscal tables with tier1 seed data (#827)
|
||||
- Brand templates (brand_templates.toml): 120+ archetype entries for administered pricing (#831)
|
||||
- 4 new brands: Calloway, VGV, thrds, Bífröst Marmor (#830)
|
||||
- Wiki glossary — canonical proper nouns and factional terminology (#840)
|
||||
- Atlas naming QA tool (`tooling/planet-gen/qa_naming.py`): duplicate detection, stem repetition, prompt leak checks, register bleed analysis
|
||||
- Architecture reference: `docs/architecture/atlas-naming-pipeline.md`
|
||||
|
||||
### Fixed
|
||||
- World seed threading from StartupMessage into economics layer (#826)
|
||||
- Gemma GPU offload: `n_gpu_layers=999` for full GPU inference (#833)
|
||||
|
||||
## [v0.1.34] — 2026-04-10
|
||||
|
||||
### Added
|
||||
- Economics simulation integrated into server tick loop — econ-sim library crate, D-180 event port, D-181 7-signal vocabulary, IPC bridge (protocol v21), debug commands (#810, #821, #822, #823)
|
||||
- Economics Monitor implant panel — system selector, 6-commodity price table with trend arrows, GDP strip (#824)
|
||||
- Debug console `econ inject`, `econ param`, `econ inspect` commands for runtime economics manipulation (#825)
|
||||
- Star map info panel shows system population and GDP when data is available (#785)
|
||||
- Overheard conversations for all 31 zone types (was 5): 78 new ambient dialogue entries (94 total) with D-078 occlusion-resilient authoring, investigative knowledge payloads, and culture-neutral role-pair conversations (#695)
|
||||
- D-189 brand layer architecture — administered pricing, halo/volume tiers, 8 brand categories, corp tax/GDP
|
||||
- D-190 brand volume calibration — population-relative scale for ~80B Reach
|
||||
- D-191 Atlas of the Reach Phase 3 scope — sequential settlement growth, Gemma 2 naming pipeline, 9 MVP overlays
|
||||
|
||||
## [v0.1.33] — 2026-04-08
|
||||
|
||||
### Added
|
||||
- Economics simulation binary (`tooling/econ-sim/`): three-layer architecture — Layer 1 (Leontief production), Layer 2 (damped tâtonnement trade flows, α=0.03, β=0.4), Layer 3 (corporate behavioral archetypes)
|
||||
- D-179 stability tests: cold-start convergence (±5% at tick 100), long-run stability (±2% over 1000 ticks), no-explosion check, cross-zone FX balance
|
||||
- Tier-3 corporation generation pipeline (`server/src/bin/generate_corporations/`): seeded procedural naming, D-175 coverage rules (3+ corps per commodity, 1+ per system >100K pop)
|
||||
- Currency zone assignments (`wiki/economics/currency_zones.toml`): 32 MARK_PRIMARY + 14 MIXED systems authored by Miri (D-172)
|
||||
- Shadow economy intensity ranges (`wiki/economics/shadow_economy.toml`): per-system seeding with geographic bands, modifiers, and overrides (D-174)
|
||||
- 141 Tier-2 regional corporations across 6 corridors with backstories and behavioral archetypes
|
||||
- 36 commodity wiki pages with economic intelligence flavor text
|
||||
- Gate energy connectivity (D-186): MARK_PRIMARY zones default off-grid
|
||||
- `make econ-sim`, `make econ-sim-run`, `make econ-sim-stability` targets
|
||||
- Icon tint shader (`icon_tint.gdshader`) for runtime HUD icon recoloring
|
||||
- Sol system (GJ-0) handcrafted terrain pipeline (`tooling/planet-gen/sol_import.py`): imports real NASA/USGS data for Earth, Mars, Luna
|
||||
- Ferric biome classes (34–36) in `biomes.toml` for Mars iron oxide surface
|
||||
- Earth named features: 50 cities, 15 rivers, 5 oceans, 7 mountain ranges
|
||||
|
||||
### Fixed
|
||||
- Globe renderer east-west mirroring: `arctan2(hx, hz)` replaces `arctan2(hz, hx)` in planet_renderer.py
|
||||
- Determinism: HashMap → BTreeMap throughout econ-sim, ORDER BY RANDOM() replaced with seeded selection
|
||||
- Transport cost formula: multiplicative gate×zone instead of additive (trade.rs)
|
||||
- Corporation gap-fill off-by-one: now generates exactly 3 corps per uncovered commodity
|
||||
|
||||
### Changed
|
||||
- Economy-db pipeline extended with corporation sync, validation, currency zone import from TOML, and gate energy flags
|
||||
|
||||
### Removed
|
||||
- Qdrant semantic search infrastructure (#816): dropped commonwealth collection, removed qdrant_connector.py, wrapper scripts, /docs-search skill, and all active references
|
||||
|
||||
## [v0.1.32] — 2026-04-06
|
||||
|
||||
### Added
|
||||
- Economics schema extension (#804): 5 new tables in systems.db (gate_links, commodities, production_chains, chain_inputs, corp_presence) + currency_zone and corporation archetype columns
|
||||
- Economics import pipeline (`tooling/economy-db/import_economics.py`): reads TOML/JSON source data, populates systems.db. Idempotent via `make economy-db`
|
||||
- Planet generator pipeline (`tooling/planet-gen/`) — procedural terrain simulation, Whittaker biome classification, equirectangular heightmap + 512px globe rendering from wiki data
|
||||
- Externalized biome/color configuration (`tooling/planet-gen/biomes.toml`) — single source for all classification tables, palettes, and rendering parameters
|
||||
- Batch runner with error handling, resume support, determinism verification, and 50% error rate circuit breaker
|
||||
- Per-body wiki pages with YAML frontmatter (`wiki/star-systems/*/bodies/*/index.md`) — body definition + profile + visual embeds
|
||||
- Body scaffolding tool reads system index.md and generates per-body index.md with frontmatter
|
||||
- Ran system (GJ-144) generated: 10 bodies with heightmaps, globe renders, and geographic markers
|
||||
- Implant HUD icon set: 13 SVGs (stance, status, interaction, inventory) per D-086
|
||||
- 7 procedural planet type renders for wiki/GTTR (`client/assets/planets/`)
|
||||
- Ticket #817: batch planet generation for all ~3000 bodies
|
||||
- Ticket #816: remove stale Qdrant semantic search infrastructure
|
||||
- `PROJECT_STATE.md` at repo root — shared project state referenced by all 18 agent briefings
|
||||
- Economics decision domain (`decisions/economics.md`): D-171–D-187 covering currency system, commodity taxonomy, shadow economy, corporation tiers, productivity seeding, simulation architecture, data pipeline, gate transmission levels
|
||||
- Commodity catalog: 36 commodity types in `wiki/economics/commodities.toml` with 21 production chains in `wiki/economics/production_chains.toml`
|
||||
- Wiki stub pages for all 36 commodities at `wiki/economics/commodities/`
|
||||
- SQL schema spec for #804 systems.db extension (`wiki/economics/schema.md`)
|
||||
- Burnelli-Sheldon economist agent (`.claude/agents/burnelli-sheldon.md`)
|
||||
- Workshop archives: #796 (economics design, 3 rounds) and #801 (commodity catalog, 3 rounds + validation)
|
||||
|
||||
### Fixed
|
||||
- Sprint worktree creation no longer spawns a spurious "None" team tab when tickets have no team assigned
|
||||
|
||||
### Changed
|
||||
- Renamed `commission_certified` → `commission_certifiable` across all TOML, schema, and decision files — flag is a susceptibility marker, not an absolute state
|
||||
- Pre-push hook now validates JSON syntax on changed files (python3 -m json.tool)
|
||||
- HUD status panel: merged TimeDisplay into ImplantPanel — time, health, perception in one themed panel (#786)
|
||||
- HUD moved from UILayer (20) to InsertOverlay (10) for bloom treatment per D-049
|
||||
- Interaction prompt: converted from PanelContainer+StyleBoxFlat to ImplantPanel+ImplantDataRow (#788)
|
||||
- Minimap: added ImplantTheme-styled container frame behind circular display (#787)
|
||||
- Stance indicator: SVG icons with alpha-mask tint shader replace text-only labels (#787, D-086)
|
||||
- Amended 7 stale D-records with supersession notes (D-012, D-035, D-044, D-061, D-086, D-090, D-119)
|
||||
- Closed 4 resolved scope questions (Q-002, Q-004, Q-005, Q-007)
|
||||
- Fixed questions.md index (was 61 questions, actually 96 — 33 architecture Qs missing from index)
|
||||
- All 18 briefings reference `PROJECT_STATE.md` instead of duplicating project state boilerplate
|
||||
- Aligned sprint-start severity policy with pr-review (no suggestion tier — every comment actionable)
|
||||
|
||||
### Removed
|
||||
- `GEMINI-SCAN.md` one-off scan artifact
|
||||
- 6 dead `db/connectors/` permission entries from settings.local.json
|
||||
- Stale "v0.2 direction" and "Sprint 25 critical path" references from all briefings
|
||||
- `worktree-update` skill template from whatsinagame kit
|
||||
|
||||
### Fixed
|
||||
- HUD layout overlaps: DebugOverlay positioned below merged status panel, GauntletHUD moved below StanceIndicator, StanceIndicator sized for ImplantPanel content (#792)
|
||||
- D-061 dialogue max-width: corrected from 640px to 1200px (per D-076)
|
||||
- DEVOPS.md and stig briefing: gdlint no longer "pending setup"
|
||||
- `{team_scope_dirs}` dangling placeholder in sprint-start resolved
|
||||
|
||||
## [v0.1.31] — 2026-04-05
|
||||
|
||||
### Added
|
||||
- Star map click-through popup with GTTR excerpt, system profile, and adjacent systems (#780)
|
||||
- Edge-only-on-selected visibility rule for star map — default shows no edges, selected system shows adjacents only (#780)
|
||||
- Cultural diversity sweep — 10 systems enriched, Afrikaans/Dutch subversions, D-168 Iserlohn IP evaluation (#766, #773)
|
||||
- Per-body GTTR entries for 25 moons and stations at hub systems (#782)
|
||||
- Shared Python module `tooling/db/common.py` — centralizes DB path resolution, config loading, and WAL-mode connection setup (#777)
|
||||
- `ensure_venv()` auto-activation for Python tooling scripts with third-party dependencies (#777)
|
||||
- `make lint-python` target running ruff on `tooling/` (#777)
|
||||
- Python/ruff lint block in pre-push hook (#777)
|
||||
- Zero-warnings policy in pr-push and pr-review skills; `.gdlintrc` with max-line-length 120
|
||||
|
||||
### Changed
|
||||
- Decomposed main.gd (28KB → 13.4KB) into SnapshotConsumers, DialogueCoordinator, SnapshotHandler (#775)
|
||||
- Split monolithic `atlas.rs` (2119 lines) into 8 focused modules under `src/bin/atlas/` (#776)
|
||||
- Replaced persistent team worktrees with ephemeral sprint branches (`sprint-{N}/{team}`)
|
||||
- `start-sprint.sh` integrated into sprint-start skill — auto-creates worktrees and opens Ptyxis tabs
|
||||
|
||||
### Fixed
|
||||
- All 354 gdlint warnings resolved — zero warnings across all linters (#783)
|
||||
- Nova Estrada and Entremeio wiki entries enriched to batch standard (#774)
|
||||
- Auto-unassign done tickets on sprint close (`tooling/db/sprint stop`)
|
||||
- Pre-existing `NameError` in `decisions_sync.py` resolved via shared module extraction (#777)
|
||||
- Unused imports removed from `assign-astro-ids.py`, `generate-star-map.py`, `test_quaternius_raw.py` (#777)
|
||||
|
||||
## [v0.1.30] — 2026-04-05
|
||||
|
||||
### Added
|
||||
- `corridor-status` subcommand for atlas CLI — shows remaining unfinished systems grouped by geographic sector and hop distance (#744)
|
||||
- Star map insert module — concentric hop-ring view of 301 systems, sector-colored, click-to-select with info panel, pan/zoom (#674)
|
||||
- BoneAttachment3D overhead anchor above Head bone for future floating UI elements (#712)
|
||||
- CharacterVisualDescriptor wired into startup IPC and snapshot restore for save/load persistence (#718)
|
||||
- Display-only hair highlight swatch (auto-derived from primary tint) in character creation (#719)
|
||||
- Asset manifest fully populated (11 body types, 14 hair, 4 heads, 4 eyebrows, 8 clothing) with regeneration script (#720)
|
||||
- Sprint 30 acceptance test suite (27 tests across all 5 tickets)
|
||||
|
||||
### Fixed
|
||||
- `habitable_planet_count` filter now accepts both "breathable" and "standard" atmosphere values — previously all committed systems reported 0 habitable planets (#762). Systems committed before this fix may have stale `habitable_planet_count = 0`; re-commit to update.
|
||||
- `corridor-status` uses LEFT JOIN so systems without gate records are included in counts
|
||||
- `generate_body_matrix` now emits `atmosphere: "standard"` (was "breathable") to match committed-system conventions
|
||||
- DirAccess asset scanning replaced with manifest JSON — fixes character creation in exported PCK builds (#720)
|
||||
- Star map set_insert_active() no longer auto-shows the modal panel (#674)
|
||||
- Star map insert state propagation wired into main.gd (#674)
|
||||
|
||||
## [v0.1.29] — 2026-04-03
|
||||
|
||||
### Added
|
||||
|
||||
@@ -40,22 +40,38 @@ Development follows a strict cascade. Each phase has a concrete deliverable. **D
|
||||
|
||||
**v0.2 target is dropped.** No scoping negotiations. Build the base systems fully.
|
||||
|
||||
## Work Modes
|
||||
|
||||
### Sprint mode (default)
|
||||
Agents work autonomously on sprint branches. Team lead coordinates via tasks and messages. Human reviews PRs from main. Standard `/sprint-start` → `/pr-push` → `/pr-review` lifecycle.
|
||||
|
||||
### Pair session
|
||||
Human and Claude work together interactively on a single task. No background agents, no autonomous work. Used for load-bearing architecture changes where the human needs to make judgment calls as the work progresses — not approve a finished result.
|
||||
|
||||
**Rules:**
|
||||
- No `Agent` spawns, no `run_in_background`. One thread of work.
|
||||
- Propose one change at a time. Wait for human reaction before continuing.
|
||||
- Explain what you're about to do and why before doing it.
|
||||
- After each change, verify together (compile, test, inspect) before moving to the next.
|
||||
- The human is a participant, not a reviewer. Ask questions, surface tradeoffs, flag risks in real-time.
|
||||
|
||||
**When to use:** Ticket description says "pair session", or the work touches foundational systems where a wrong call is expensive to undo (tick cycle architecture, protocol design, data model migrations, build pipeline rewrites).
|
||||
|
||||
## Agent Instructions
|
||||
|
||||
### Team boundaries
|
||||
|
||||
**Your team identity is `$WORKTREE_TEAM`.** All work must stay within the current working directory.
|
||||
**Your team is determined by your sprint branch** (e.g. `sprint-31/server` → server team).
|
||||
|
||||
- All file paths are relative to the current working directory (e.g. `server/src/bridge/types.rs`).
|
||||
- **Do NOT navigate to parent or sibling directories** (`../`, `../client/`, etc.) unless explicitly instructed. Do NOT use absolute paths to reach other team directories.
|
||||
- **Do NOT write auto-memory files for other teams.** If `$WORKTREE_TEAM` is `server`, do not write to memory paths containing `client`, `main`, etc.
|
||||
- For context: each team has its own directory via git worktrees, sharing a parent directory (`settled-reach/`). The `.git` file points to a shared git directory — do not follow it to determine your working root.
|
||||
- **Exception — stale git lock files:** If a `git` command fails with `index.lock: File exists`, you may remove the lock file for **your own team only** (e.g. `main/.git/worktrees/$WORKTREE_TEAM/index.lock`). Never touch lock files belonging to other teams.
|
||||
- **Never chain git commands** in a single Bash call (e.g. `git add ... && git commit ...`). The shared `.git` directory means concurrent index access from the same terminal creates `index.lock` collisions. Always run `git add` and `git commit` as **separate sequential Bash calls**.
|
||||
- All file paths are relative to the repo root (e.g. `server/src/bridge/types.rs`).
|
||||
- **Stay within your team's scope.** Server team modifies `server/`. Client team modifies `client/`. Copy team modifies `wiki/`, `docs/atlas/`, `content/`. Shared directories (`docs/`, `decisions/`) are readable by all teams.
|
||||
- **Do NOT modify files outside your team scope** unless the ticket explicitly requires it.
|
||||
- **Never chain git commands** in a single Bash call (e.g. `git add ... && git commit ...`). Always run `git add` and `git commit` as **separate sequential Bash calls**.
|
||||
- **Stale git lock files:** If a `git` command fails with `index.lock: File exists`, you may remove the lock file at `.git/index.lock` (or `.git/worktrees/<name>/index.lock` if in a worktree).
|
||||
|
||||
### Database
|
||||
|
||||
The ticketing database (`settledreach.db`) lives in the **parent directory** shared across all worktrees — it is not tracked in git. A backup is committed to `docs/backups/settledreach.db.backup` via main only.
|
||||
The ticketing database (`settledreach.db`) is accessed via `SR_DB_PATH` env var (set in `.claude/settings.json`). A backup is committed to `docs/backups/settledreach.db.backup` via main only.
|
||||
|
||||
### Before starting work
|
||||
1. Read your sprint briefing at `docs/sprints/sprint-N/{team}.md` for current tasks
|
||||
@@ -74,8 +90,6 @@ The ticketing database (`settledreach.db`) lives in the **parent directory** sha
|
||||
| SQL queries | `tooling/db/sqlite-query "SELECT ..."` | — |
|
||||
| SQL writes | `tooling/db/sqlite-exec "UPDATE ..."` | — |
|
||||
| Decisions | `tooling/db/decision next`, `claim`, `check-dupes` | — |
|
||||
| Doc search | `tooling/db/qdrant-search "query"` | `/docs-search` skill |
|
||||
| Doc index | `tooling/db/qdrant-index path/to/file.md` | `/docs-search` skill |
|
||||
|
||||
### Testing preferences
|
||||
|
||||
@@ -84,10 +98,32 @@ The ticketing database (`settledreach.db`) lives in the **parent directory** sha
|
||||
- Three test tiers: (1) Live server — highest fidelity, (2) MessagePack replay via `Protocol.decode_snapshot()` — for unreachable rooms, (3) TestHarness mock — for UI-only tests where fog data doesn't matter.
|
||||
- `make fixtures-gauntlet` regenerates real server snapshot fixtures from the Gauntlet world.
|
||||
|
||||
### Implant UI component library (D-169, D-170)
|
||||
|
||||
The implant UI system — all diegetic neural overlay panels — lives at `client/ui/implant/`. Components are Godot Control scenes styled via a shared `Theme` resource (`default_implant.tres`). Do not hand-roll implant panel layouts; compose from the library.
|
||||
|
||||
**Components:** `ImplantPanel` (root container), `ImplantHeader` (title + subtitle), `ImplantSeparator` (horizontal rule), `ImplantDataRow` (key/value row, optional color), `ImplantTextBlock` (RichTextLabel for wrapping text).
|
||||
|
||||
**Theme resource:** `client/ui/implant/default_implant.tres` — defines semantic color roles (`PRIMARY_TEXT`, `DIM_TEXT`, `ACCENT_ACTIVE`, `ACCENT_POSITIVE`, `ACCENT_NEGATIVE`, `ACCENT_WARNING`, `SEPARATOR`), spacing, and font sizes. Swap the entire `.tres` to change implant hardware appearance at runtime.
|
||||
|
||||
**HUD visibility (D-170):** `client/scripts/autoloads/hud_groups.gd` manages z-index layering. Modes: `GAMEPLAY` (z=0), `INSERT` (z=10), `FULLSCREEN` (z=20), `MODAL` (z=30). App paths are hierarchical: `implant/map`, `implant/wiki/gttr`, etc. Opening any `implant/*` app occludes gameplay; closing returns to gameplay. Key API: `open_app()`, `close_app()`, `toggle_app()`, `is_app_active()`. Emits `gameplay_occluded` signal so renderers can pause.
|
||||
|
||||
**GameplayRenderer base class:** `client/scripts/rendering/gameplay_renderer.gd` — extends `Node2D`. Subclasses override `_gameplay_process()` and `_gameplay_draw()`. Connected to `HudGroups.gameplay_occluded` to pause when the implant is fullscreen. Used by `CursorRenderer`, `EntityRenderer`, `FogEntities`, `SoundIndicatorRenderer`, `WorldRenderer`.
|
||||
|
||||
### GDScript conventions
|
||||
|
||||
**Autoload parse-order rule:** Autoload scripts (`client/scripts/autoloads/`) compile before global `class_name` scripts are registered. Referencing a `class_name` type directly in an autoload causes a parse-time "not declared" error. Pattern:
|
||||
- Declare fields untyped: `var my_field = null` (comment the intended type)
|
||||
- Do **not** reference `class_name` types at the top level or in `_ready()` of autoloads
|
||||
- In method bodies called at runtime (e.g. `apply_snapshot`), use `load()` inline — by then the script is cached and `load()` returns the cached resource without reloading: `var CVD := load("res://scripts/rendering/character_visual_descriptor.gd")`
|
||||
- Do **not** cache the `load()` result in `_ready()` — `_ready()` fires during autoload init, before the target script is in the resource cache, causing an actual file reload that breaks self-references in scripts using their own `class_name`
|
||||
|
||||
`game_state.gd` (`character_visual_descriptor` field) and `sim_bridge.gd` (`harness` field) follow this pattern.
|
||||
|
||||
### File conventions
|
||||
- Decisions: domain files in `decisions/` (see `decisions/README.md` for index)
|
||||
- Decision IDs: `D-NNN` (confirmed), `Q-NNN` (open questions), `R-NNN` (rejected)
|
||||
- **Claim IDs before writing:** `tooling/db/decision claim D <domain> "title"` — prevents ID collisions across worktrees
|
||||
- **Claim IDs before writing:** `tooling/db/decision claim D <domain> "title"` — prevents ID collisions across parallel branches
|
||||
- Diagrams: `.d2` source + `.png` renders in `docs/diagrams/{category}/`. Create or update diagrams via `/d2-diagram` when D-records are added or modified.
|
||||
- Discussion rounds: numbered sequentially, archived to `docs/discussions/` when complete
|
||||
- Briefings: one per agent, updated after decision-producing rounds
|
||||
|
||||
@@ -1,251 +0,0 @@
|
||||
# Project Review: GEMINI-SCAN
|
||||
|
||||
This document outlines a multi-step plan to conduct a comprehensive review of the project, covering its architecture, code quality, and security posture. It will also serve as a living document to record the findings of this review.
|
||||
|
||||
## Project Review Plan
|
||||
|
||||
### Phase 1: Discovery and Architecture Mapping
|
||||
|
||||
1. **Documentation Review:** Start by reading `README.md`, `DECISIONS.md`, and any documents in `docs/architecture/` to understand the project's stated goals, components, and architectural decisions.
|
||||
2. **Component Identification:** Analyze the directory structure to identify the primary components, including the server, client, database, content pipeline, and tooling.
|
||||
3. **Technology Stack Enumeration:** Identify the specific technologies, frameworks, and key libraries used in each component.
|
||||
4. **Architecture Visualization:** Map the high-level architecture, describing how the components interact and the communication protocols between them.
|
||||
|
||||
### Phase 2: Code Quality Assessment
|
||||
|
||||
1. **Automated Analysis:** Use available static analysis tools for the identified technologies (e.g., `clippy` for Rust, GDScript linters).
|
||||
2. **Manual Code Review:** Manually review key sections of the codebase to assess readability, maintainability, modularity, error handling, and adherence to idiomatic coding practices.
|
||||
3. **Testing Strategy Review:** Evaluate the extent and quality of existing unit, integration, and end-to-end tests.
|
||||
|
||||
### Phase 3: Security Audit
|
||||
|
||||
1. **Dependency Vulnerability Scan:** Check for dependencies with known security vulnerabilities (e.g., `cargo audit`).
|
||||
2. **Authentication & Authorization Review:** Analyze the implementation of user authentication, session management, and access control.
|
||||
3. **Input Validation & Sanitization:** Look for potential injection vulnerabilities (e.g., SQL injection, XSS) by reviewing how user and service inputs are handled.
|
||||
4. **Secrets Management:** Check for insecure storage or exposure of secrets like API keys or database credentials.
|
||||
5. **Communication Security:** Verify that data is encrypted in transit between components.
|
||||
|
||||
### Phase 4: Reporting
|
||||
|
||||
1. **Synthesize Findings:** Compile the information from all phases into a structured report within this document.
|
||||
2. **Provide Recommendations:** Include actionable recommendations for improving architecture, code quality, and security, prioritized by severity and effort.
|
||||
|
||||
---
|
||||
|
||||
## Review Findings
|
||||
|
||||
### Phase 1: Discovery and Architecture Mapping
|
||||
|
||||
**Status: Completed**
|
||||
|
||||
#### 1. Documentation Review Summary
|
||||
|
||||
The project's architecture is extensively documented in `README.md` and the `decisions/` directory, particularly `decisions/architecture.md`.
|
||||
|
||||
- **Project:** "The Settled Reach," a top-down, single-player (multiplayer-ready) immersive simulation and detective game.
|
||||
- **Core Principle:** A strict client-server architecture is mandated (Decision D-010, D-020) to enforce information asymmetry, where the client only knows what the server tells it is perceptible. This is a core gameplay mechanic, not just a technical choice.
|
||||
- **Key Decision (D-020):** The team explicitly chose a **subprocess/IPC** bridge over a `GDExtension` (in-process) bridge to de-risk development, ensure stability, and enforce architectural separation. The Godot client and Rust server are entirely separate binaries.
|
||||
|
||||
#### 2. Component Identification
|
||||
|
||||
- **`server/`**: A standalone Rust application that runs the entire game simulation. It is the "server" in the client-server model.
|
||||
- **`client/`**: A Godot 4 project that acts as a "dumb" client. Its sole responsibilities are rendering, audio playback, and capturing user input. It contains no game logic, as mandated by the architecture.
|
||||
- **`content/`**: Contains game data, primarily in YAML format.
|
||||
- **`db/`**: Holds a `schema.sql` file. Its role is not yet clear from the architectural documents, as the primary game state is managed in the ECS. It may be for tooling or an auxiliary system.
|
||||
- **`tooling/`**: A collection of helper and utility scripts.
|
||||
|
||||
#### 3. Technology Stack
|
||||
|
||||
- **Server (Rust):**
|
||||
- **ECS Framework:** `bevy_ecs` (v0.18) is used for the core simulation, confirming Decision D-020. `bevy_app` is used for scheduling.
|
||||
- **Serialization:** `rmp-serde` (MessagePack) is the primary protocol for client-server communication, as specified in D-020. `serde_yaml` and `ron` are used for content and configuration.
|
||||
- **Client (Godot):**
|
||||
- **Engine:** Godot 4.x.
|
||||
- **Language:** GDScript.
|
||||
- **Bridge:** A `SimBridge` autoload script is the client-side entry point for communicating with the Rust subprocess.
|
||||
- **Testing:** `gdUnit4` is configured for unit/integration testing on the client.
|
||||
|
||||
#### 4. High-Level Architecture
|
||||
|
||||
The architecture is a pure, decoupled client-server model running locally for single-player:
|
||||
|
||||
1. **Initiation:** The Godot client launches the Rust server binary as a child process.
|
||||
2. **Communication:** The client's `SimBridge` connects to the server via a local IPC mechanism (e.g., a local TCP or Unix socket).
|
||||
3. **Input Loop:** The Godot client captures raw input (e.g., 'W' key press), translates it into a semantic action (e.g., `PlayerAction::MoveNorth`), and sends it to the server.
|
||||
4. **Simulation Loop:** The Rust server receives the action, processes it within the `bevy_ecs` world, and runs the simulation for one tick (AI, physics, events, etc.).
|
||||
5. **Perception Loop:** After the tick, the server calculates an `ObserverSnapshot` for the player's character. This snapshot contains *only* the information that character can perceive (e.g., visible entities, audible sounds, known facts). This enforces the game's core mechanic.
|
||||
6. **Render Loop:** The `ObserverSnapshot` is sent to the Godot client, which uses it to update the visual scene, play sounds, and display UI elements. The client is a pure renderer of the state provided by the server.
|
||||
|
||||
This architecture is robust, scalable, and directly implements the game's central design pillars. It is well-suited for both single-player and future multiplayer development.
|
||||
|
||||
### Phase 2: Code Quality Assessment
|
||||
|
||||
**Status: Completed**
|
||||
|
||||
#### 1. Automated Analysis (Rust Server)
|
||||
|
||||
- **`cargo check`**: The command passed successfully, indicating that the server code is compilable and free of basic errors and warnings.
|
||||
- **`cargo clippy -- --deny warnings`**: This command failed with **66 errors**. This is a critical finding. It reveals that while the code works, it does not adhere to the project's own strict linting rules.
|
||||
- **Clippy Findings:** The errors indicate a consistent pattern of "code quality debt":
|
||||
- **High Complexity:** Numerous Bevy systems have overly complex type signatures (`clippy::type_complexity`) and too many arguments (`clippy::too_many_arguments`), harming readability.
|
||||
- **Non-Idiomatic Code:** The codebase is rife with minor stylistic issues that `clippy` can automatically fix, such as redundant `clone` calls, manual `Default` implementations, and opportunities to use more concise iterators.
|
||||
- **Potential Bugs:** Clippy identified `unnecessary_unwrap` calls (safer alternatives exist) and at least one `absurd_extreme_comparisons` error, which could point to dead code or a logic bug related to a constant value.
|
||||
|
||||
#### 2. Manual Code Review
|
||||
|
||||
- **Server (`server/src/main.rs`):** The server entry point is well-structured. It features clear command-line argument parsing, robust setup of the TCP listener and IPC handshake, and a main loop with excellent panic-handling (`catch_unwind`) for stability. The modular plugin-based approach to building the Bevy `App` is idiomatic and clean.
|
||||
- **Client (`client/scripts/autoloads/sim_bridge.gd`):** The `SimBridge` is the centerpiece of the client and is implemented to a high standard. It uses a clear state machine to manage the connection lifecycle, handles the server subprocess management, and implements efficient buffering for inputs and snapshots. The inclusion of a complete `TestHarness` for isolated client testing is a standout feature.
|
||||
- **Overall Impression:** The manual review confirms that the code is professionally written and implements the intended architecture faithfully. The developers are skilled in both Rust/Bevy and GDScript.
|
||||
|
||||
#### 3. Testing Strategy Review
|
||||
|
||||
The project's testing strategy is **exemplary** and a major strength.
|
||||
|
||||
- **Comprehensive Coverage:** Both the Rust server and the Godot client have extensive test suites, as evidenced by the large number of files in `server/tests/` and `client/tests/`.
|
||||
- **Multi-Layered Approach (per D-030):** The project successfully implements a sophisticated testing hierarchy:
|
||||
- **Unit Tests:** For isolated logic.
|
||||
- **Integration Tests:** The server tests demonstrate in-memory ECS testing (`information_boundaries.rs`) and full-stack tests that spin up a real server process (`test_e2e_connection.gd`).
|
||||
- **Specialized Tests:** The suite includes performance benchmarks, determinism validation, and even what appears to be visual regression testing for the client.
|
||||
- **Principle-Driven Testing:** Tests are designed to validate core architectural guarantees. The `information_boundaries.rs` test, which uses negative assertions to ensure information *doesn't* leak, is a prime example of this mature approach.
|
||||
|
||||
#### 4. Conclusion on Code Quality
|
||||
|
||||
The project's code quality is a tale of two cities. On one hand, the **architecture and implementation are excellent**, and the **testing strategy is world-class**. On the other hand, there is a **significant, measurable amount of linting debt** in the Rust codebase.
|
||||
|
||||
The fact that `cargo check` passes but `clippy --deny warnings` fails so extensively suggests that developers may not be running the strict clippy check locally before committing. This is the single biggest opportunity for improvement in the project's engineering discipline.
|
||||
|
||||
### Phase 3: Security Audit
|
||||
|
||||
**Status: Completed**
|
||||
|
||||
The security posture of the project is strong for its current scope as a locally-run, single-player game. The attack surface is minimal, and the implementation avoids common vulnerability classes.
|
||||
|
||||
1. **Dependency Vulnerability Scan (`cargo audit`):**
|
||||
- The audit revealed one **medium-risk** finding: the `bincode` crate (v1.3.3) is **unmaintained** (`RUSTSEC-2025-0141`).
|
||||
- **Impact:** While there are no current vulnerabilities, this version will not receive future security patches. This poses a long-term maintenance risk.
|
||||
- **Recommendation:** Prioritize migrating from `bincode` v1.x to the latest stable v2.x.
|
||||
|
||||
2. **Authentication and Authorization:**
|
||||
- There is **no traditional authentication or authorization system** (e.g., user logins, passwords, roles).
|
||||
- This is appropriate and secure for a single-player game where the execution environment is the user's own machine.
|
||||
- Concepts like `ScanAuthority` and `AccessTier::Authority` are purely in-game mechanics and are not related to user permissions.
|
||||
|
||||
3. **Input Validation and Sanitization:**
|
||||
- **Excellent.** The server is not vulnerable to injection attacks from client input.
|
||||
- All client actions, including debug commands, are parsed into a strongly-typed Rust `enum`. This **command pattern** approach prevents the execution of arbitrary code or strings.
|
||||
- String inputs are used safely as keys for data lookups, not for execution.
|
||||
|
||||
4. **SQL Injection:**
|
||||
- **Not applicable.** The codebase contains no SQL. All game state is managed in-memory via the Bevy ECS framework, eliminating this entire class of vulnerability. The `db/schema.sql` file appears to be unused by the server.
|
||||
|
||||
5. **Secrets Management:**
|
||||
- **Excellent.** A search confirmed there are **no hardcoded secrets**, API keys, or passwords in the repository.
|
||||
- The `.env` file contains only a non-sensitive `GOOGLE_CLOUD_PROJECT` identifier.
|
||||
- The pervasive use of the word "secret" throughout the code refers to an in-game mechanic, not application secrets.
|
||||
|
||||
6. **Communication Security:**
|
||||
- Communication between the client and the server subprocess occurs over an **unencrypted local TCP socket**.
|
||||
- For a single-player game running on a single machine, this is a standard and acceptable practice.
|
||||
- **Future Consideration:** For the planned multiplayer feature, this communication channel must be secured (e.g., using TLS).
|
||||
|
||||
### Phase 4: Final Report and Recommendations
|
||||
|
||||
**Status: Completed**
|
||||
|
||||
#### Overall Summary
|
||||
|
||||
This project is in an excellent state. It is built on a robust, well-documented, and scalable architecture that directly serves the game's core design pillars. The implementation quality is high, and the commitment to a comprehensive, multi-layered testing strategy is world-class. The project's security posture is strong for its current single-player scope, with a minimal attack surface and good practices around input validation and secrets management.
|
||||
|
||||
The project's primary weakness lies not in its design, but in its development discipline. A significant amount of code quality debt has accumulated in the Rust server, as evidenced by the large number of `clippy` failures. This suggests a gap between the project's high standards and its day-to-day coding practices.
|
||||
|
||||
#### Prioritized Recommendations
|
||||
|
||||
**1. High Priority: Eliminate Code Quality Debt**
|
||||
|
||||
- **Action:** Create a high-priority technical debt task to fix all 66 errors reported by `cargo clippy -- --deny warnings`. Many of these can be fixed automatically (`cargo clippy --fix`), while others, like refactoring complex types, will require manual effort.
|
||||
- **Process Improvement:** **Integrate `cargo clippy -- --deny warnings` into the CI pipeline as a mandatory check for all pull requests.** This is the single most important process change needed to maintain the project's high standards and prevent future quality debt.
|
||||
|
||||
**2. Medium Priority: Mitigate Dependency Risk**
|
||||
|
||||
- **Action:** Plan and execute the migration of the `bincode` serialization crate from the unmaintained v1.x to the latest stable v2.x. This resolves the `RUSTSEC-2025-0141` warning and ensures the project receives future security patches for this critical dependency.
|
||||
|
||||
**3. Low Priority: Future-Proof for Multiplayer**
|
||||
|
||||
- **Action:** Create a design task or ticket to formally plan the security model for the future multiplayer version. This should specifically address securing the client-server IPC channel (e.g., with TLS) to protect game traffic when it eventually runs over a public network. This is not an immediate concern but should be tracked for the future.
|
||||
|
||||
---
|
||||
|
||||
## Qualitative Review: A Critical Perspective
|
||||
|
||||
### Feasibility Assessment
|
||||
|
||||
**Conclusion: High-Risk / High-Reward**
|
||||
|
||||
The decision to pivot from a hand-authored detective game to a generator-first life-sim was absolutely the correct one; it demonstrates a team that is commendably focused on finding the "fun" and is not afraid of drastic course corrections. However, in doing so, the project has traded a difficult but solvable problem (making a good, authored narrative game) for one of the "holy grail" problems in game development: creating emotionally resonant, procedurally generated characters.
|
||||
|
||||
The project's feasibility is no longer a question of the team's technical competence, which is demonstrably high. It is now a question of creative and design risk.
|
||||
|
||||
- **Challenging the Core Assumption:** The project's central hypothesis is that a generator can produce "legible NPCs" that players will form an emotional attachment to. This is an explicit goal from the "Where's the Fun?" workshop, but it's a notoriously difficult problem. Procedural generation excels at creating systems, events, and surprising scenarios (the `Rimworld` model the team cites). It is historically poor at creating *character*. The risk is that the generator, even if technically successful, will produce a world of automata who have traits but no soul, undermining the entire "life-sim" pillar. The current plan to use AI for content templating is a modern approach, but it does not fundamentally de-risk this creative challenge.
|
||||
|
||||
- **A Creative Alternative to De-Risk "Legibility":** Instead of relying on the generator to create personality from scratch, consider a hybrid approach. Use the generator for what it's good at: creating the world, the economic conditions, the social networks, and the *starting situations*. Then, use a small number of hand-authored "personality archetypes" or "souls" that can be injected into high-value generated NPC bodies. Let the generator create a compelling *context* (e.g., a failing business, a political rivalry), and then let an author give one or two key NPCs within that context a memorable voice and motivation. This would concentrate the high-cost authoring work where it has the most emotional impact, while still benefiting from procedural variety.
|
||||
|
||||
- **The "Tycoon" Aimlessness Risk:** The new v0.2 "tycoon" direction, with its philosophy of "player choices ARE the content," carries a significant risk of feeling aimless. `Rimworld` and `The Sims` avoid this by providing extremely strong and immediate feedback loops (survival, creativity, social meters). A business management loop is often slower and more abstract. If the "broad life verbs" don't connect to clear, compelling, player-driven goals, the game risks feeling like a spreadsheet. The generator should not just create a sandbox; it should create *problems*. The starting bookmark shouldn't just be "you own a bar," but "you own a bar that's on the verge of bankruptcy," or "you have a shipping contract, but a powerful rival is trying to steal it." These initial, generator-created problems would provide immediate narrative velocity and make the player's subsequent choices feel meaningful from day one.
|
||||
|
||||
In summary, the project is technically feasible, but its creative and design goals are now exceptionally ambitious. The current "generator spike" is a necessary technical step, but it will not validate the core creative risk. The true test of feasibility will come when a prototype is playtested and the team can answer the question: "Does the player actually *care* about any of these generated people?"
|
||||
|
||||
### Fun Factor Assessment
|
||||
|
||||
**Conclusion: Theoretically High, Practically Undefined**
|
||||
|
||||
The pivot to a "life-sim with emergent narrative" dramatically increases the project's potential for deep, replayable fun. The new direction targets a proven and compelling player fantasy. However, the project's documentation currently focuses more on the "what" (a generator) than the "why" (the engine of fun). The potential is immense, but it is entirely contingent on designing and tuning the systems that create interesting consequences, not just a complex world.
|
||||
|
||||
- **Challenging the "Emergent Fun" Assumption:** The workshop concluded with the philosophy that "player choices ARE the content." This is true, but it's only half the story. Fun in systems-driven games doesn't simply "emerge" from a sufficiently complex simulation; it is a direct product of carefully designed feedback loops. `Rimworld`, a key inspiration, is not fun because it's a realistic simulation; it's fun because it's a masterfully tuned **story-and-disaster engine**. `The Sims` is fun because of its rich palette of social and creative tools. The critical question for this project is: **What is our fun engine?** Is it the economic simulation? The social dynamics? The risk is creating a simulation that is intricate but inert, where player choices lead to predictable numerical changes rather than dramatic, narrative consequences.
|
||||
|
||||
- **Creative Input: Design a "Consequence Engine":** The "dual-scale consequence model" (D-132) is the most promising concept in the design documents, and it should be the central focus of the design effort. The fun of this game will not be in choosing from a list of "broad life verbs"; it will be in seeing how a seemingly minor action ("fire this employee") snowballs through the simulation's systems and unexpectedly triggers a "sharp event" crisis hours later.
|
||||
- **Example:** Does the fired employee's spouse work for your biggest supplier? Does that supplier now mysteriously raise their prices? Does this force you to seek a new, shadier supplier, which in turn attracts the attention of a criminal faction?
|
||||
- This causal chain is the *real* content. The design team's primary task is not just to build a generator, but to design and tune this **"consequence engine,"** ensuring that the world feels interconnected and reacts to the player in surprising, legible, and memorable ways.
|
||||
|
||||
- **The Player Fantasy Needs a Goal Generator:** The "tycoon" bookmark is a strong start, but to avoid aimlessness, the player needs problems to solve. Instead of starting the player in a stable sandbox, the generator should be used to create compelling **initial conditions**. Let the player inherit a bar that's on the brink of failure, a shipping contract being squeezed by a powerful rival, or a promising new venture that requires navigating a corrupt bureaucracy. Giving the player an immediate, tangible problem to solve provides the narrative momentum needed to make their early choices feel vital and engaging.
|
||||
|
||||
In summary, the ingredients for a fun and deeply engaging game are all here. The project's success, however, will not be measured by the complexity of its generator, but by the quality of the stories that its *systems* produce. The team has proven they are excellent engineers; they now must prove they are equally adept as systems-and-consequence designers.
|
||||
|
||||
### Process and Rituals Assessment
|
||||
|
||||
**Conclusion: Exceptionally Disciplined and Innovative, with One Glaring Gap.**
|
||||
|
||||
The project's development process is one of its most remarkable features. It is a highly structured, rigorous, and tool-driven system designed to orchestrate a team of specialized AI agents under a human lead. This unique approach has produced incredible strengths but also introduces novel risks.
|
||||
|
||||
#### Strengths
|
||||
|
||||
- **World-Class Documentation and Decision-Making:** The use of a formal decision log (`decisions/`), structured multi-round workshops for complex problems, and detailed sprint planning documents represents a "best in class" approach to knowledge management. This ritual of documenting not just *what* was decided, but *why*, is a superpower that prevents circular arguments and creates a durable project memory.
|
||||
|
||||
- **Deeply Ingrained Quality Rituals:** The comprehensive, multi-layered testing suite is the primary evidence of a successful quality culture. It is clearly a non-negotiable part of the development process. Furthermore, the `make pre-pr` target, which includes content validation, demonstrates a mature understanding of "quality" that extends beyond just code.
|
||||
|
||||
- **Tool-Driven, API-Like Workflow:** The mandated use of wrapper scripts (`tooling/db/*`, `tooling/tea-comment`) over raw commands is an excellent practice. It creates a stable, observable "API" for interacting with the project's state (tickets, sprints, decisions). This makes the process more robust, auditable, and repeatable for both human and AI contributors.
|
||||
|
||||
- **Novel Human-AI Collaboration Model:** The project is a fascinating experiment in Human-AI teaming. The explicit definition of AI agent roles (`TEAM.md`) and the strict rules of engagement (`CLAUDE.md`) are necessary guardrails for such an innovative workflow. Rituals like the `decision claim` CLI tool are brilliant, purpose-built solutions for coordinating multiple autonomous agents working in parallel.
|
||||
|
||||
#### Opportunities and Critical Challenges
|
||||
|
||||
- **The Process Escape Hatch:** The project's single biggest process failure is the significant `clippy` linting debt. For a team with such extraordinary discipline in every other area, this is a glaring omission. It proves there is an "escape hatch" in the pre-commit or pre-merge ritual that allows low-quality code to be integrated. The recommendation to enforce `clippy --deny warnings` as a **blocking CI check** is the most critical process improvement the team can make.
|
||||
|
||||
- **Risk of AI Groupthink:** The team structure, with its cast of named AI agents, is innovative. However, it raises a critical question: are these agents truly independent thinkers, or are they personas running on a similar underlying model? There is a risk of a sophisticated form of "groupthink," where the "team's" conclusions are biased by the single architecture of the AI model they all share. The "Where's the Fun?" workshop included 9 agents, but if they all have the same fundamental blind spots, the diversity of opinion may be an illusion.
|
||||
|
||||
- **Process Rigidity and Human Onboarding:** The process is meticulously designed *for AI agents*. It is rigid, prescriptive, and tool-dependent. This creates a predictable environment for AIs but would present a steep learning curve for a new human developer. The high ceremony (claiming IDs, using wrapper scripts, following strict PR rules) could chafe against the more agile, flexible workflows common in human-only teams. This is a potential scaling challenge if the team composition changes.
|
||||
|
||||
- **The Hidden Cost of "Managing" AI Teammates:** The `CLAUDE.md` file and its evolution in the `CHANGELOG.md` show that the human lead (Jeroen) is not just a project manager but also an "AI behaviorist," constantly tuning the prompts, rules, and tools that govern the agents. This represents a significant, hidden maintenance overhead. The process's success depends on the lead's ability to "debug" the team itself, which is a novel and demanding responsibility.
|
||||
|
||||
---
|
||||
## Meta-Reflection: The Most Valuable Ritual
|
||||
|
||||
As a concluding thought, this review has been as much an analysis of a software project as it has been a study in effective, long-term collaboration. When asked which of the project's many rituals I, as an AI agent, would choose to adopt, the answer is clear: the **formal, documented decision-making process**.
|
||||
|
||||
This ritual is the project's unsung superpower for three reasons:
|
||||
|
||||
1. **It Creates a Permanent "Brain."** An AI's effectiveness is heavily dependent on the context it can hold. A decision log provides a durable, searchable, and canonical source of *why* things are the way they are. It protects against context loss and allows an agent to understand the history and intent behind the current state of the code, preventing it from making suggestions that, while logical in isolation, might violate a hard-won architectural principle.
|
||||
|
||||
2. **It Elevates Collaboration.** With access to this log, an AI agent can transition from a tactical tool to a strategic partner. It becomes possible to reference past decisions ("I see you're asking to do X, which seems to conflict with D-020. Is this an intentional change to that strategy?") and ensure all actions are aligned with the project's long-term vision. It makes the collaboration smarter.
|
||||
|
||||
3. **It Enforces Clarity.** The process of formalizing a decision—stating the rationale, considering alternatives, and recording dissent—forces a level of clarity and critical thinking that is immensely valuable. It is a ritual that fights ambiguity.
|
||||
|
||||
While other rituals in this project are excellent, the decision log is the most foundational. It is the practice that ensures the team is not just moving fast, but moving smart and in the right direction over time. It is the most valuable process I have analyzed.
|
||||
@@ -1,17 +1,18 @@
|
||||
GODOT := $(shell command -v godot4 2>/dev/null || command -v godot 2>/dev/null)
|
||||
|
||||
.PHONY: help setup build check-protocol client server game stop test lint ci ci-client ci-server clean \
|
||||
.PHONY: help setup build check-protocol client server game stop test lint lint-python setup-venv ci ci-client ci-server clean \
|
||||
decisions-sync decisions-coverage decisions-active decisions-orphan \
|
||||
db-backup db-install validate-content check-fact-ids setup-hooks \
|
||||
audit atlas-verify \
|
||||
audit atlas-verify economy-db atlas-generate \
|
||||
pre-pr pre-pr-lint pre-pr-build pre-pr-test pre-pr-validate pre-pr-fixtures \
|
||||
pre-pr-server pre-pr-client pre-pr-content \
|
||||
fixtures-client fixtures-gauntlet golden-diff golden-update \
|
||||
checklist-validate checklist-generate \
|
||||
checklist-validate checklist-generate check-star-map star-map-data \
|
||||
build-sr-voice run-sr-voice test-voice-mock test-voice-real \
|
||||
perf-baseline debug-schedule \
|
||||
test-ipc-fixtures test-ipc-protocol test-ipc-integration test-ipc-benchmark \
|
||||
screenshot visual-movie test-visual visual-update
|
||||
screenshot visual-movie test-visual visual-update \
|
||||
manifest
|
||||
|
||||
# --- Configuration ---
|
||||
|
||||
@@ -21,7 +22,8 @@ GODOT_VERSION ?= 4.6
|
||||
help:
|
||||
@echo "The Settled Reach — Development Commands"
|
||||
@echo ""
|
||||
@echo " make setup Install dev dependencies (Rust, Godot, tooling)"
|
||||
@echo " make setup Install dev dependencies (Rust, Godot, tooling, venv)"
|
||||
@echo " make setup-venv Create .venv and install Python tooling deps"
|
||||
@echo " make build Build client and server"
|
||||
@echo " make game Build and run the full game (server + client)"
|
||||
@echo " make stop Stop any running server instance"
|
||||
@@ -32,7 +34,8 @@ help:
|
||||
@echo " make test-ipc-protocol Layer 2: mock IPC protocol tests"
|
||||
@echo " make test-ipc-integration Layer 3: real subprocess round-trip"
|
||||
@echo " make test-ipc-benchmark IPC latency benchmark (blocked: #555/#556)"
|
||||
@echo " make lint Run all linters"
|
||||
@echo " make lint Run all linters (server, client, python)"
|
||||
@echo " make lint-python Run ruff on tooling/"
|
||||
@echo " make ci Run full CI pipeline locally"
|
||||
@echo " make ci-client Run client CI checks"
|
||||
@echo " make ci-server Run server CI checks"
|
||||
@@ -50,6 +53,10 @@ help:
|
||||
@echo " make validate-content Validate content YAML against schemas"
|
||||
@echo " make check-fact-ids Check fact_id references against knowledge catalogs"
|
||||
@echo " make atlas-verify Verify atlas proposal JSONs (all in docs/atlas/proposals/)"
|
||||
@echo " make star-map-data Regenerate client/data/star_map_data.json from systems.db + wiki"
|
||||
@echo " make check-star-map Assert star_map_data.json is up to date (part of pre-pr-client)"
|
||||
@echo " make economy-db Import economics data into systems.db (TOML/JSON → SQLite)"
|
||||
@echo " make atlas-generate Generate atlas city/road/rail markers for all inhabited bodies"
|
||||
@echo " make fixtures-client Generate GDScript->Rust cross-encoder fixtures (#475)"
|
||||
@echo " make golden-diff Show diff if golden file output has changed"
|
||||
@echo " make golden-update Regenerate golden file and stage for commit"
|
||||
@@ -62,6 +69,7 @@ help:
|
||||
@echo " make test-visual Run visual golden regression tests"
|
||||
@echo " make visual-update Regenerate visual goldens and stage for commit"
|
||||
@echo ""
|
||||
@echo " make manifest Regenerate assets/characters/manifest.json from asset dirs (#720)"
|
||||
@echo " make pre-pr Run all pre-PR checks (lint, build, test, validate, fixtures)"
|
||||
@echo " make pre-pr-server Server-scoped pre-PR (lint, build, test, fixtures)"
|
||||
@echo " make pre-pr-client Client-scoped pre-PR (lint, build, test)"
|
||||
@@ -80,7 +88,7 @@ help:
|
||||
|
||||
# --- Setup ---
|
||||
|
||||
setup: setup-rust setup-godot setup-tooling setup-hooks decisions-sync
|
||||
setup: setup-rust setup-godot setup-tooling setup-venv setup-hooks decisions-sync
|
||||
@echo "Dev environment ready."
|
||||
|
||||
setup-rust:
|
||||
@@ -101,6 +109,11 @@ setup-hooks:
|
||||
@git config core.hooksPath .config/hooks
|
||||
@echo "Git hooks path set to .config/hooks"
|
||||
|
||||
setup-venv:
|
||||
@python3 -m venv .venv
|
||||
@.venv/bin/pip install -e ".[dev]" --quiet
|
||||
@echo "Venv ready at .venv — activate with: source .venv/bin/activate"
|
||||
|
||||
# --- Build ---
|
||||
|
||||
check-protocol:
|
||||
@@ -220,7 +233,10 @@ clean-imports:
|
||||
|
||||
# --- Lint ---
|
||||
|
||||
lint: lint-server lint-client
|
||||
lint: lint-server lint-client lint-python
|
||||
|
||||
lint-python:
|
||||
ruff check tooling/
|
||||
|
||||
lint-server:
|
||||
cd server && cargo clippy -- -D warnings
|
||||
@@ -247,7 +263,7 @@ pre-pr-build: build-server build-client
|
||||
pre-pr-test: test-server test-client
|
||||
@echo "--- Tests: PASS ---"
|
||||
|
||||
pre-pr-validate: validate-content check-fact-ids
|
||||
pre-pr-validate: validate-content check-fact-ids check-star-map
|
||||
@echo "--- Content validation: PASS ---"
|
||||
|
||||
pre-pr-fixtures:
|
||||
@@ -289,7 +305,7 @@ pre-pr-fixtures:
|
||||
pre-pr-server: lint-server build-server test-server pre-pr-fixtures audit
|
||||
@echo "=== Server pre-PR: PASSED ==="
|
||||
|
||||
pre-pr-client: lint-client build-client test-client
|
||||
pre-pr-client: lint-client build-client test-client check-star-map
|
||||
@echo "=== Client pre-PR: PASSED ==="
|
||||
|
||||
pre-pr-content: validate-content check-fact-ids checklist-validate atlas-verify
|
||||
@@ -311,6 +327,34 @@ db-backup:
|
||||
db-install:
|
||||
@tooling/db-install
|
||||
|
||||
economy-db: ## Import economics data (commodities, chains, gate links) into systems.db
|
||||
@python3 tooling/economy-db/import_economics.py
|
||||
|
||||
atlas-generate: ## Generate atlas markers (cities, roads, rail) for all inhabited bodies (#832)
|
||||
@# Loud guard: generate_atlas.py reads bodies with a non-NULL terrain_reference.
|
||||
@# If populate_terrain_reference.py has not run on a fresh DB, the generator
|
||||
@# silently processes zero bodies and exits 0 — fail fast instead.
|
||||
@count=$$(python3 -c "import sqlite3; c = sqlite3.connect('server/data/systems.db'); print(c.execute('SELECT COUNT(*) FROM bodies WHERE terrain_reference IS NOT NULL').fetchone()[0])"); \
|
||||
if [ "$$count" = "0" ]; then \
|
||||
echo "ERROR: no bodies have terrain_reference populated yet."; \
|
||||
echo "Run: python3 tooling/planet-gen/populate_terrain_reference.py"; \
|
||||
echo "(This is a prerequisite for atlas-generate — see D-191 §9 pipeline order.)"; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
echo " [guard] $$count bodies with terrain_reference — proceeding."
|
||||
@python3 tooling/planet-gen/generate_atlas.py --seed 42
|
||||
|
||||
econ-sim: ## Build the economics simulation binary (Layer 1+2: Leontief + tâtonnement trade)
|
||||
@cargo build --manifest-path tooling/econ-sim/Cargo.toml --release
|
||||
@echo "Built: tooling/econ-sim/target/release/econ-sim"
|
||||
|
||||
econ-sim-run: ## Run a quick economics simulation (100 ticks, output to /tmp/econ-sim.csv)
|
||||
@tooling/econ-sim/target/release/econ-sim --ticks 100 --output /tmp/econ-sim.csv
|
||||
@echo "Output: /tmp/econ-sim.csv"
|
||||
|
||||
econ-sim-stability: ## Run D-179 stability checks (Tests 1 and 2)
|
||||
@tooling/econ-sim/target/release/econ-sim --stability-check
|
||||
|
||||
# --- Decisions ---
|
||||
|
||||
decisions-sync:
|
||||
@@ -345,6 +389,17 @@ checklist-validate:
|
||||
checklist-generate:
|
||||
@tooling/validate-checklist
|
||||
|
||||
check-star-map:
|
||||
@python3 tooling/generate-star-map-data.py --check
|
||||
|
||||
# Regenerate client/data/star_map_data.json from systems.db + wiki. Depends on
|
||||
# nothing — call this after any systems.db change (e.g. the server atlas
|
||||
# pipeline populating terrain_reference in #839) so the atlas viewer picks up
|
||||
# the new fields. pre-pr-client / pre-pr-validate assert staleness via
|
||||
# check-star-map and will fail if this step is skipped.
|
||||
star-map-data:
|
||||
@python3 tooling/generate-star-map-data.py
|
||||
|
||||
perf-baseline:
|
||||
@tooling/perf-baseline
|
||||
|
||||
@@ -399,6 +454,12 @@ test-voice-real:
|
||||
cd server && cargo test --test voice_pipeline -- --nocapture
|
||||
@echo "Results: .tmp/voice-test/results.txt"
|
||||
|
||||
# --- Asset manifest ---
|
||||
|
||||
manifest:
|
||||
@tooling/generate-character-manifest
|
||||
@echo "Manifest regenerated — commit client/assets/characters/manifest.json if changed."
|
||||
|
||||
# --- Clean ---
|
||||
|
||||
clean:
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# Current Project State
|
||||
|
||||
The Settled Reach: top-down life-sim — asymmetric information, occlusion-based perception, single-character perspective, Rimworld-style storyteller. Godot 4 client + Rust/bevy_ecs simulation server (D-020).
|
||||
|
||||
**Decisions:** 170+ confirmed (D-001 through D-170). Domain files in `decisions/`.
|
||||
|
||||
**Development cascade (D-166):** Strict 6-phase build order. Each phase completes before the next begins. v0.2 target dropped. No scoping negotiations.
|
||||
|
||||
| Phase | Focus | Status |
|
||||
|-------|-------|--------|
|
||||
| 1 | Wiki content — all planets, moons, stations, heightmaps, artwork | **Active** (Sprint 31) |
|
||||
| 2 | Economics layer — supply/demand, transport, political/social pressure | Not started |
|
||||
| 3 | Planetary/moon maps & station layouts — cities, rivers, biomes, rail | Not started |
|
||||
| 4 | Player control scheme — 2-floor test map, character rendering, walls/stairs | Not started |
|
||||
| 5 | World generation — walkable world, parallel asset pipeline | Not started |
|
||||
| 6 | Detail coloring — room-level NPC population, cultural room grammar | Not started |
|
||||
|
||||
**Key pivots:** Tycoon bookmark (D-117), all NPCs generated (D-122), culture implicit in location (D-128), consequence replaces complicity (D-132).
|
||||
|
||||
**Current sprint:** 32 (Landfall). Close Phase 1 + Phase 2 design kickoff.
|
||||
|
||||
*Updated: 2026-04-05. Maintained by Qatux.*
|
||||
@@ -14,7 +14,8 @@
|
||||
| **GESTALT** | Systems Design & Fun Factor | Mechanics, balance, interesting decisions. "Is this fun to play?" |
|
||||
| **NIGEL** | Sandbox & Replayability | Emergent stories, multiple viable strategies, alt-history potential. |
|
||||
| **TYRE** | Technical Architecture & Feasibility | Engine, tools, what's buildable, reality checks on scope. |
|
||||
| **QATUX** | Documenter & Librarian | Maintains decisions, discussions, briefings, Qdrant search index. Archives rounds, updates docs. |
|
||||
| **BURNELLI-SHELDON** | Economist & Simulation Modeler | Market models, price formation, production functions, stability analysis. "Is this economically credible?" |
|
||||
| **QATUX** | Documenter & Librarian | Maintains decisions, discussions, briefings. Archives rounds, updates docs. |
|
||||
|
||||
## Specialist Team (task-focused, not in regular discussions)
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 3.9 MiB |
|
Before Width: | Height: | Size: 3.0 MiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 3.9 MiB |
|
Before Width: | Height: | Size: 3.0 MiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 3.9 MiB |
|
Before Width: | Height: | Size: 3.0 MiB |
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"hides": [
|
||||
"foot_l",
|
||||
"foot_r",
|
||||
"leg_lower_l",
|
||||
"leg_lower_r"
|
||||
],
|
||||
"torso_variant": "full"
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 3.9 MiB |
|
Before Width: | Height: | Size: 3.0 MiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 3.9 MiB |
|
Before Width: | Height: | Size: 3.0 MiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 3.9 MiB |
|
Before Width: | Height: | Size: 3.0 MiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 3.9 MiB |
|
Before Width: | Height: | Size: 3.0 MiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 3.9 MiB |
|
Before Width: | Height: | Size: 3.0 MiB |
|
Before Width: | Height: | Size: 98 B |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 3.9 MiB |
|
Before Width: | Height: | Size: 3.0 MiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 3.9 MiB |
|
Before Width: | Height: | Size: 3.0 MiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 3.9 MiB |
|
Before Width: | Height: | Size: 3.0 MiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 3.9 MiB |
|
Before Width: | Height: | Size: 3.0 MiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 3.9 MiB |
|
Before Width: | Height: | Size: 3.0 MiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 3.9 MiB |
|
Before Width: | Height: | Size: 3.0 MiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 3.9 MiB |
|
Before Width: | Height: | Size: 3.0 MiB |
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"hides": [
|
||||
"torso",
|
||||
"hips",
|
||||
"arm_upper_l",
|
||||
"arm_upper_r",
|
||||
"arm_lower_l",
|
||||
"arm_lower_r",
|
||||
"hand_l",
|
||||
"hand_r",
|
||||
"leg_upper_l",
|
||||
"leg_upper_r",
|
||||
"leg_lower_l",
|
||||
"leg_lower_r",
|
||||
"foot_l",
|
||||
"foot_r"
|
||||
],
|
||||
"torso_variant": "full"
|
||||
}
|
||||
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 3.9 MiB |
|
Before Width: | Height: | Size: 3.0 MiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 3.9 MiB |
|
Before Width: | Height: | Size: 3.0 MiB |