station/AGENTS.md

6.5 KiB

Project notes for agents

Project overview

Station is a persistent-world, RPG-style station simulation inspired by Space Station 13, with singleplayer and multiplayer. It is built in Rust (edition 2024) with Bevy 0.19 (ECS), bevy_replicon + renet (networking), Rune (scripting), rsn (data files) and Tiled (maps). Project documentation: README.md.

Agent rules

  • Never push changes unless explicitly told to.
  • After changing files, run cargo fmt --all. Do not override project formatting configuration or invoke a formatter directly on individual files.
  • Use conventional commits with the types feat, fix, refactor, perf, test, docs, ci, build and chore, scoped by crate or area where useful (feat(server): ..., ci(gitea): ...). Use ! and a BREAKING CHANGE: footer for breaking API, save-format or protocol changes.
  • End commit messages with a co-author trailer appropriate to the agent and product. For example: Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>.
  • Inform the user about commits and other Git changes, including commit messages.
  • Commit changes after each step unless the user says not to or a .NOCOMMIT file exists in the repository root.
    • Changes affecting compilation or tests may only be committed after cargo clippy --workspace --all-targets -- -D warnings and cargo nextest run --workspace pass.
    • Documentation, CI, editor, and deployment configuration changes do not require code checks; validate workflow YAML syntax.
    • Check the current branch before every commit.
  • Commit formatting-only changes separately when formatting reformats code unrelated to the functional changes.
  • Add user-visible changes to the Unreleased section of CHANGELOG.md (Keep a Changelog format).

Repository structure

  • crates/game_core/: shared data definitions (data.rs), ECS components, grid helpers, Tiled loader (map.rs) and network protocol (protocol.rs).
  • crates/game_server/: authoritative simulation, Rune engine (scripting.rs), persistence, and the game-server dedicated server binary. Integration tests live in crates/game_server/tests/.
  • crates/game_client/: the game binary: rendering, UI and input; embeds the server for singleplayer and hosting.
  • assets/data/: item, recipe, building and skill definitions (.rsn).
  • assets/scripts/: Rune scripts (.rn), referenced as "module::function".
  • assets/maps/, assets/tilesets/, assets/sprites/: Tiled maps and art.
  • tools/gen_placeholder_assets.py: regenerates placeholder art and the example map (generated output is committed).
  • .github/workflows/, .gitea/workflows/: CI for GitHub and Gitea.
  • .config/nextest.toml: test runner configuration.

Keep README.md (run instructions, controls, data formats, script API, Tiled conventions) in sync with API, configuration, and behavior changes.

Architecture and constraints

  • The server is authoritative. Clients only send protocol events (Login, SetMoveDir, Interact, Craft, ...) and render replicated state; never mutate game state from client code. Singleplayer runs the same server plugin in-process, so behavior must not depend on the mode.
  • Game rules belong in data files or Rune scripts where possible; Rust code provides generic mechanics. Data references and script hooks are validated at load time.
  • Protocol registration order in game_core::protocol must match between client and server; changing it breaks compatibility.
  • Rune scripts stage changes in ScriptState; they are applied after the script returns, and a failing script has no effect. Ctx methods need #[rune::function(keep)]; script-facing numbers are integers.
  • Save files (persistence.rs, SAVE_VERSION) are the source of truth for an existing world; the Tiled map only seeds new worlds. Changing saved types requires a version bump or a compatible migration.
  • Characters are identified by name only (no authentication); renet uses unsecure authentication. Do not treat client input as trusted.
  • Replicon builds its systems in Plugin::finish; headless tests must call app.finish(); app.cleanup(); and update the app once more per round trip.
  • Release builds of the client on Windows use the windows subsystem (no console output).

Commands

cargo fmt --all
cargo build --workspace
cargo clippy --workspace --all-targets -- -D warnings
cargo nextest run --workspace

Run binaries with cargo run (client; --host, --connect) and cargo run -p game_server --bin game-server. The Windows client can be cross-built with cargo build --release -p game_client --target x86_64-pc-windows-gnu (needs MinGW). Running the client requires a Vulkan or GL capable GPU or a software driver such as lavapipe.

Conventions

  • Write comments for why, not what: invariants, non-obvious constraints, workarounds (with the reason or a link), and units/timebases where the type doesn't say. Never restate what the code does.
  • Before committing, review every comment in your diff (git diff): delete those that restate the code or describe the change itself (e.g. "now uses X instead of Y"; that belongs in the commit message), and shorten the rest to one line where possible.
  • Comment only code that needs clarification; keep comments short.
  • Follow the repository's formatting, lint, error-handling, logging, and dependency-management conventions.
  • Prefer existing helpers and patterns; keep changes focused and surface failures explicitly.
  • Preserve existing line endings when editing files that use non-default line endings.
  • Do not add tests in locations the project's normal test commands do not discover.

Code reviews

For reviews of commits, branches, diffs, or specific files, report every finding as an entry in a list with this shape:

  • Location: file:line (use a range such as file:120-146 when the finding spans several lines)
  • Category: one of Blocking, FYI, or Nit (use another category, such as Question, only when none of those fit)
  • Comment: the concrete issue or risk and, when claiming a defect, its failure scenario rather than only an abstract concern

Order findings by severity, with Blocking first. Use Blocking for defects, unbounded resource use, or policy violations that must change before merge; use FYI for design consequences and risks worth a conscious decision; use Nit for style and cleanliness. Verify findings against the code and run the relevant lint and test commands before reporting them. Say when a finding is a possibility rather than a confirmed defect.