一键导入
core-module
Invoke when writing or modifying a Bevy module (SimDomain/StaticData/View/InputUI) on the magnum_opus core. Enforces contract-first workflow.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Invoke when writing or modifying a Bevy module (SimDomain/StaticData/View/InputUI) on the magnum_opus core. Enforces contract-first workflow.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Use when bootstrapping an existing project into PTSD pipeline
Perform a hard audit of the Magnum Opus repo - build, tests, clippy warnings, unwrap/TODO counts, oversized files, PTSD pipeline state, and drift between CLAUDE.md claims and reality. Use at session start when CLAUDE.md claims feel stale, before committing large changes, or whenever asked to verify the true state of the code.
| name | core-module |
| description | Invoke when writing or modifying a Bevy module (SimDomain/StaticData/View/InputUI) on the magnum_opus core. Enforces contract-first workflow. |
The core lives in magnum_opus/src/core/. It is hardened against the v1 failure class
(shared ownership, string-based drift, skip_ flags). Every module is a declarative
contract plus a scoped installer. Break the contract and cargo test panics at build
time. This skill lists the non-negotiable rules.
Source of truth for the API: docs/llm/20_contracts.md.
Worked examples: docs/llm/21_sketches.md.
Test patterns: magnum_opus/tests/.
Choose the archetype - it is NOT negotiable after the fact.
| Need | Archetype | Schedule |
|---|---|---|
| owns a slice of simulation state, mutates per tick | SimDomain | Update |
| loads read-only reference data once | StaticData | Startup |
| read-only projection of sim state (render, export) | View | PostUpdate |
| reads input + sim, pushes commands | InputUI | PreUpdate |
Draft the contract first, code second. List every TypeKey:
writes)?reads)?commands_in/commands_out)?messages_out/messages_in)?metrics)?A contract slot is a promise. The core catches every broken promise.
Name resources with names!. Never write raw "Grid" strings. Always:
writes: names![Grid],
messages_out: names![TilePlaced, PlaceRejected],
names! binds to TypeId, so a::Grid and b::Grid never collide.
Every install(ctx: &mut XxxInstaller) function MUST:
writes entry: call ctx.write_resource::<T>() (needs T: Resource + Default)
or ctx.insert_resource(value) (for non-Default).reads entry: call ctx.read_resource::<T>().messages_out entry: call ctx.emit_message::<T>() (needs T: Message).messages_in entry (Sim only): call ctx.read_message::<T>().commands_in entry (Sim only): call ctx.consume_command::<T>().commands_out entry (Input only): call ctx.emit_command::<T>().ctx.add_system(..) - the primary phase must actually be used.The installer panics if any call targets a type NOT in the contract, AND panics at
finalize() if any declared slot was NEVER exercised. Contract drift is a panic,
not a silent mismatch.
ctx.add_system(sys); // primary phase (Sim: PRIMARY_PHASE; View/Input: Post/Pre-Update)
ctx.add_command_drain(sys); // Sim only: Phase::Commands (for drain systems)
ctx.add_metric_publish(sys); // Sim only: Phase::Metrics (for metric publishers)
ctx.add_startup_system(sys); // Data only: Startup
Arbitrary phase routing does not exist. If you need a system in a phase not in this list, the answer is "no" - either restructure or file an RFC to add a whitelisted slot.
The compiler or installer catches some of these. Others are accepted escape hatches the core CANNOT catch. Do not use them.
ctx.write_resource::<T>() with T
not in writes.Sim module without any ctx.add_system call. Primary phase declared but
never used.writes: names![X]."core").finalize_modules() / Harness::build().app.update() without calling finalize_modules().Treat these as build-breaking during review. A PR that uses any of them without an explicit justification comment is rejected.
fn sys(world: &mut World) routed through any
add_system. Bypasses the whole contract. Use regular Res/ResMut/Query
systems. If an exclusive system is genuinely required (e.g. iterating all
archetypes), justify in a doc comment and make the system read-only.ResMut<T> where T is owned by another module. Even if Bevy's scheduler
permits the borrow, the contract forbids writes outside the owning module.Mutex, RefCell,
AtomicU64, UnsafeCell on types in any contract slot. Plain data only.MetricsRegistry::set / inc on a metric owned by another module.
The runtime does not reject it; review does.#[cfg(feature = ...)] modules with divergent contracts. CI must build all
feature combinations; contract drift across builds is invisible to the core.Harnesslet app = Harness::new()
.with_sim::<MyDomain>()
.with_input::<MyInputSource>()
.build(); // calls finalize_modules() internally
app.update();
Harness::new() is App::new() + MinimalPlugins + CorePlugin. Headless, deterministic.
No rendering, no async.
For every non-trivial contract, add a negative test:
writes: names![T] but install forgets ctx.write_resource::<T>().
Expected panic: install never performed the matching installer call.single-writer violation.closed-messages.single-consumer-commands.Model them after tests/forgotten_write_panics.rs, tests/sim_single_writer.rs,
tests/multi_consumer_commands_panics.rs.
If the module declares metrics, add a test that runs 2-3 ticks and asserts the
counter/gauge/rate values in MetricsRegistry. Pattern: tests/metrics_flow.rs.
Before merging a module PR:
cargo test - 36 baseline tests + any new tests all green.cargo clippy --all-targets - zero warnings.sh docs/llm/validate.sh - docs links resolve.&mut World inside install).ResMut<T> where T is owned by another module (cross-reference contracts).ctx.xxx::<T>(). Either
wire the call or remove the declaration.reads.messages_in / commands_in declaration.ctx.add_system(..).
Add a system or convert to Data archetype if there is nothing to schedule.app.add_sim::<X>() after Harness::build() or app.finalize_modules(). Do
not mutate the registry post-finalize.App::new() path
that skipped finalize_modules(). Call it, or use Harness::build().If the core genuinely blocks a legitimate need (and not the sloppy-author failure
class), the fix is in the CORE, not an escape hatch in the module. Edit
magnum_opus/src/core/ with a clear RFC in the PR description, add negative
tests for the new enforcement, and update docs/llm/20_contracts.md.
Do NOT bypass the core. The v1 rewrite started with one bypass and ended with 238 unwraps and 83 failing tests.