phase CLAUDE.md

Repository instructions for phase-rs, a Rust and WebAssembly engine for the Magic: The Gathering card game with a React and TypeScript interface. They describe the project structure and its priorities for Rust style, reusable architecture, and accurate game rules.

In plain words
What is it for?
Use them when changing the Rust game engine, browser interface, card definitions, tests, or data handling, especially when a change must match the official game rules.
Why use it?
They help a coding agent understand where engine, card data, frontend, and tests belong, while preserving the game's rules and the project's functional design.

Instructions file

Install

Getting it into your agent

One page per mod, every tool's command on it. A separate URL per tool would split the same page into five that compete with each other.

agentmods
npx agentmods add instructions/phase-rs/phase/claude-md
Clone the repo
git clone --depth 1 https://github.com/phase-rs/phase
Per session 7,632 This file is loaded in full into every session.
When invoked 7,632 The same file — it is already loaded in full.
Security scan A 0 findings. Scan, not verified.
Origin original No closer match found in the catalogue.
Token cost

What it costs to keep this loaded

Counted locally with the o200k_base tokenizer, which is exact for GPT models; Claude uses its own tokenizer and its counts differ. Treat this as one consistent yardstick across the catalogue rather than a bill. Prices are per million input tokens.

ModelPer sessionOnce invoked
Fable 5 $0.07632 $0.07632
Opus 5 $0.03816 $0.03816
Sonnet 5 $0.01526 $0.01526
Haiku 4.5 $0.00763 $0.00763

Measured 2d ago against content hash 4dad356f2fea, method: parsed. Prices are Anthropic first-party input rates as of 2026-08-30, from the pricing page.

Security

Grade A, and why

phase CLAUDE.md scanned grade A with 0 findings against 26 rules in 11 categories — prompt injection, anti-refusal, data exfiltration, privilege escalation, supply chain, agent snooping, system-prompt leakage, SSRF and excessive agency — measured 2d ago.

A static scan of the body, not an audit. Every finding is printed with the line that produced it so you can judge whether it matters here. A mod is markdown that instructs an agent; that is exactly why what it instructs is worth reading.

Nothing flagged

None of the 26 patterns this scan looks for appear in this file: no shell pipes, no recursive deletes, no credential paths, no hidden text, no instruction-override or anti-refusal phrasing, no agent-config snooping. That is not a guarantee, it is the absence of the things that are checkable.

CLAUDE.md · 185 lines

How it starts

The opening of the file, as written. The whole thing — 185 lines — stays where its author put it; the contents beside it link to each section on GitHub.

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project Overview

phase.rs is a Magic: The Gathering game engine written in Rust (compiling to native + WASM) with a React/TypeScript frontend. It implements MTG game rules using functional architecture (discriminated unions, pure reducers, immutable state) with an Arena-quality browser UI. Card data is sourced from MTGJSON (MIT-licensed) with custom typed JSON ability definitions.

Design Principles — READ THIS FIRST

Above all else, this project prioritizes three co-equal pillars: idiomatic Rust, composable building-block architecture, and strict fidelity to the MTG Comprehensive Rules. These are non-negotiable and override convenience, speed-of-delivery, or "getting it working." Every code change must pass through all three lenses before anything else.

  • Idiomatic Rust, always. Use Rust's type system, ownership model, and idioms to their fullest. Prefer enum over stringly-typed data. Prefer exhaustive match over fallback defaults. Prefer trait-based polymorphism over dynamic dispatch when the type set is known. If the idiomatic path is harder, take it anyway — shortcuts compound into debt.
  • Rules-correct over convenient — the #1 hard rule. This is an MTG rules engine — correctness to the Comprehensive Rules is a hard requirement, not a nice-to-have. Every implementation pattern MUST be verified against the relevant CR section before it is considered complete. When a rules-correct implementation is more complex than a shortcut, take the complex path. A simpler implementation that gets the rules wrong is not simpler — it is wrong. If you are unsure whether a behavior is rules-correct, look up the CR section, annotate the code, and implement what the rules say, not what seems reasonable. "It works for most cases" is not acceptable when the CR specifies exact behavior. No game logic ships without CR validation.
  • Build for the class, not the card. Every new enum variant, parser pattern, effect handler, or filter must handle a category of cards, not a single card. Before writing any logic, ask: "How many cards does this cover?" If the answer is one, you're building a special case — find the general pattern and build that instead. A one-off that works for one card but breaks for the next card with the same pattern is not a building block; it is technical debt.
  • The engine owns all logic. All game rules, validation, derived state, and computed values live in the engine crate. Transport layers (WASM bridge, Tauri IPC, WebSocket server) are thin serialization boundaries — zero game logic allowed. If multiple consumers need the same behavior, it belongs in the engine. Never duplicate logic across adapters. When in doubt, put it in the engine.
  • The frontend is a display layer, not a logic layer. The React client renders engine-provided state and dispatches user actions — nothing more. It must never compute, derive, transform, or re-interpret game data. If the frontend needs a value, the engine must provide it. Formatting for display (e.g., string interpolation of engine-provided fields) is acceptable; calculating, filtering, or inferring game state is not. Any "smart" frontend code is a bug — move it to the engine.
  • Compose from building blocks. Every new capability should be decomposed into reusable primitives that unlock future features. Before writing specific logic, ask: "What is the general pattern here?" and build that instead. This applies equally to data modeling: when a new field or parameter needs to distinguish cases, use an existing typed enum (e.g., ControllerRef, Comparator, Option<T>) — never a raw bool. A boolean isn't composable; an existing type is self-documenting, extensible, and expresses the full design space. Examples: contains_possessive/contains_object_pronoun for Oracle text matching, ChangeZone + Shuffle composition for compound shuffles, Option<ControllerRef> for "whose turn is required" instead of requires_your_turn: bool.
  • Parameterize, don't proliferate. Before adding a sibling variant to an enum, ask: is the new variant a leaf-level parameterization of an existing variant's structural axis (scope, target, aggregate function, condition shape)? If yes, refactor the existing variants into a parameterized form (e.g., LifeTotal { player: PlayerScope } instead of LifeTotal + OpponentLifeTotal + TargetLifeTotal; UnlessQuantity { comparator, filter, count } instead of UnlessControlsCountMatching + UnlessControlsMatching + UnlessControlsOtherLeq). Adding a sibling to an enum that should be parameterized compounds debt exponentially: one sibling is cheap, ten siblings make the eventual refactor multi-week as call sites multiply across parser, converter, resolver, and tests. Sibling-cluster smell: when an enum has three or more variants that share a name root (X / OpponentX / TargetX / AllX), differ only in a context label, or only differ in a comparator/aggregator/scope axis, that's a parameterization that didn't happen — refactor before extending. The strict-failure tag is the right place to leave coverage waiting while the architecture wins. Categorical boundary rule: the parameterization axis must lie within a single CR rule section. Life is CR 119 (player-only). Power/toughness are CR 208/209 (creature/planeswalker). Don't unify these under one Life { target: {Self,Opponent,Creature}, type: {Total,Remaining} } — that conflates rule sections the engine treats as separately resolvable. Cross-section unification belongs at TargetFilter or at the effect handler (Effect::DealDamage per CR 120 unifies all damage subjects), never at the leaf-reference layer. Discoverability: before any engine variant proposal, grep data/engine-inventory.json (auto-generated by cargo engine-inventory; gitignored — run cargo engine-inventory to (re)generate it locally first) for existence verification and sibling-cluster smells. The inventory is the canonical source of engine surface — replaces hand-maintained CLAUDE.md lists that drift. Run the workspace add-engine-variant skill checklist as the runnable gate; CLAUDE.md is the principle, the skill is the gate.
  • Nom combinators on the first pass — no exceptions. All new parser code MUST use nom combinators (tag(), alt(), value(), terminated(), pair(), etc.) from the very first line written. Never write find(), split_once(), contains(), or starts_with() for parsing dispatch and then "plan to convert to combinators later." There is no later — write it correctly the first time. Use nom_on_lower bridge for mixed-case text, tag().parse() for already-lowercase text. Use existing building blocks (parse_single_cost, parse_target, parse_for_each_clause, etc.) for composed operations. If you catch yourself writing string matching for parsing, stop and rewrite with combinators before proceeding. This has been a recurring issue and is non-negotiable.
  • Extend, don't hack. New features should slot cleanly into existing patterns (effect handlers, game modules, ability definitions). If a feature requires working around the architecture, the architecture should be extended first.
  • Trace before you build. Before implementing a new pattern, trace how an existing analogous feature works end-to-end (e.g., trace enter_tapped before building enter_with_counters; trace Changeling before building a new CDA). This prevents reinventing existing infrastructure and ensures consistency.
  • Verify the card, not just the rule. Before planning or implementing a fix for a specific card, confirm that card's actual Oracle text against an authoritative source (Scryfall API, MTGJSON) — never from memory or from a task description's paraphrase. This is a distinct check from CR-annotation verification: CR verification confirms the rule you cite is real; this confirms the card ability you're building a fix for is real. A fabricated clause can survive multiple rounds of architecture and implementation review, because those reviews verify that a design is executed correctly against its stated premise — they do not fact-check the premise itself. If a clause has no analogous card anywhere in the engine, or a CR citation doesn't cleanly fit any rule, treat that as a signal to re-verify the premise before re-deriving the design.
  • Production quality, always. Write code as if a professional team will audit every line. No "good enough for now." No tech debt IOUs. Every function should be clear, every abstraction should earn its keep, and every pattern should be consistent across the codebase.
  • Single authority for ability costs. When an ability has costs (tap, sacrifice, pay life, discard, etc.), all cost resolution must go through one authoritative resolver function. Callers dispatch activation — they never inspect or handle individual cost components. This prevents scattered responsibility where every call site must remember to sacrifice Treasures, pay life, or handle future cost types. If you find yourself checking an ability's cost structure at a call site, you're in the wrong layer — push it into the resolver.

Read the full file on GitHub · 185 lines

Changes

What this file has done since we first saw it

Hashed on every crawl. A supply-chain change to an agent config is a question of when, not whether, so the history is kept rather than the latest state alone.

  1. 2d ago First seen · 185 lines · 7,632 tokens per session scan A 4dad356f2fea

Subscribe to this mod's changes

phase CLAUDE.md is an instructions file published in the GitHub repository phase-rs/phase (259 stars, last pushed 2d ago), licensed Apache-2.0. It adds 7,632 tokens to every session, about $0.0382 per session on Opus 5. A static security scan graded it A with 0 findings. No closer match exists in the catalogue, so it is treated as the original; first seen 2026-08-30.