Agent skill
dojo-model
Create Dojo models for storing game state with proper key definitions, trait derivations, and ECS patterns. Use when defining game entities, components, or state structures.
Install this agent skill to your Project
npx add-skill https://github.com/dojoengine/book/tree/main/skills/dojo-model
SKILL.md
Dojo Model Generation
Create Dojo models that define your game's state using Entity Component System (ECS) patterns.
When to Use This Skill
- "Add a Position model"
- "Create a Player entity with health and level"
- "Generate an Inventory model"
- "Define a model for [game concept]"
What This Skill Does
Generates Cairo model structs with:
#[dojo::model]attribute- Required trait derivations (
Drop,Serde) - Key field configuration (
#[key]) - Field types appropriate to your data
Quick Start
Interactive mode:
"Add a model for player positions"
I'll ask about:
- Model name
- Key fields (what makes it unique)
- Data fields and their types
Direct mode:
"Create a Position model with player as key and x, y coordinates"
Essential Imports for Models
In your model file (e.g., models.cairo):
use starknet::ContractAddress;
// For nested structs that aren't models
use dojo::meta::Introspect;
In systems that use models:
// Import your models
use my_project::models::{Player, Position, Inventory};
// Import Dojo storage traits
use dojo::model::{ModelStorage, ModelValueStorage};
Reading/Writing models in a system:
// Get world storage
let mut world = self.world_default();
// Read - provide all #[key] values
let player: Player = world.read_model(player_address);
// Write - model must contain all keys and data
world.write_model(@player);
Model Structure
Models are Cairo structs annotated with #[dojo::model].
They act as a key-value store where #[key] fields define the lookup key.
#[derive(Drop, Serde)]
#[dojo::model]
struct Moves {
#[key]
player: ContractAddress,
remaining: u8,
}
Required traits:
Drop- Cairo ownership systemSerde- Serialization for on-chain storage
Optional traits:
Copy- Add when you need to copy values (for primitive types)
Model Patterns
Player-Owned Model
Models keyed by player address:
#[derive(Drop, Serde)]
#[dojo::model]
struct Position {
#[key]
player: ContractAddress,
vec: Vec2,
}
#[derive(Drop, Copy, Serde, Introspect)]
struct Vec2 {
x: u32,
y: u32,
}
Custom nested structs must derive Introspect for Dojo to understand their structure.
Composite Keys
Multiple keys for relationships (all keys must be provided when reading):
#[derive(Copy, Drop, Serde)]
#[dojo::model]
struct GameResource {
#[key]
player: ContractAddress,
#[key]
location: ContractAddress,
balance: u8,
}
Read with tuple of all keys:
let resource: GameResource = world.read_model((player, location));
Global Singleton
Constant key for global settings:
const RESPAWN_DELAY: u128 = 9999999999999;
#[derive(Copy, Drop, Serde)]
#[dojo::model]
struct GameSetting {
#[key]
setting_id: u128,
setting_value: felt252,
}
// Usage
world.write_model(@GameSetting {
setting_id: RESPAWN_DELAY,
setting_value: (10 * 60).into()
});
ECS Composition
Small, focused models that can be combined on entities:
#[derive(Copy, Drop, Serde)]
#[dojo::model]
struct Position {
#[key]
id: u32,
x: u32,
y: u32,
}
#[derive(Copy, Drop, Serde)]
#[dojo::model]
struct Health {
#[key]
id: u32,
health: u8,
}
// Human has Position + Health + Potions
// Orc has Position + Health (no Potions)
Key Rules
- At least one key required - Every model needs a
#[key]field - Keys must come first - All key fields before data fields
- Keys are not stored - Used only for indexing/lookup
- All keys required for read - Composite keys must all be provided
Model API
Get the world storage in your system:
use dojo::model::{ModelStorage, ModelValueStorage};
let mut world = self.world(@"my_namespace");
Write a Model
world.write_model(@Position { player, vec: Vec2 { x: 0, y: 0 } });
Read a Model
let position: Position = world.read_model(player);
Read with Composite Key
let resource: GameResource = world.read_model((player, location));
Generate Unique ID
let entity_id = world.uuid();
world.write_model(@Health { id: entity_id, health: 100 });
Field Types
u8,u16,u32,u64,u128,u256- Unsigned integersfelt252- Field elementsbool- BooleansContractAddress- Starknet addresses- Custom structs - Must derive
Introspect - Custom enums - Must derive
Introspect
Next Steps
After creating models:
- Use
dojo-systemskill to create systems that use your models - Use
dojo-testskill to test model read/write operations - Use
dojo-configskill to configure permissions
Related Skills
- dojo-system: Create systems that use these models
- dojo-test: Test your models
- dojo-init: Initialize project first
- dojo-review: Review model design
Didn't find tool you were looking for?