Manage world permissions, namespaces, resource registration, and access control. Use when configuring world ownership, setting up authorization policies, or managing resource permissions.
80
Does it follow best practices?
If you maintain this skill, you can automatically optimize it using the tessl CLI to improve its score:
npx tessl skill review --optimize ./path/to/skillEvaluation — 97%
↑ 1.18xAgent success when using this skill
Validation for skill structure
Manage your Dojo world's permissions, namespaces, resource registration, and access control policies.
Handles world management:
Configure permissions:
"Grant writer permission to my system"Check permissions:
"List permissions for my world"Owner Permission:
Writer Permission:
Reading is always permissionless.
World Owner (highest)
└── Namespace Owner
└── Resource Owner / Writer (lowest)Set permissions during deployment in dojo_<profile>.toml:
[writers]
# Namespace-level: actions can write to all resources in my_game
"my_game" = ["my_game-actions"]
# Resource-specific: movement can only write to Position
"my_game-Position" = ["my_game-movement"]
[owners]
# Namespace ownership
"my_game" = ["my_game-admin"]Format: "<TARGET_TAG>" = ["<GRANTEE_TAG>"]
# Grant writer permission
sozo auth grant writer my_game-Position,my_game-actions
# Grant owner permission
sozo auth grant owner my_game,my_game-admin# Revoke writer permission
sozo auth revoke writer my_game-Position,my_game-actions
# Revoke owner permission
sozo auth revoke owner my_game,my_game-admin# List all permissions
sozo auth listuse dojo::world::WorldStorage;
// Grant writer permission to a contract
world.grant_writer(
selector_from_tag!("my_game-Position"),
movement_system_address
);
// Grant owner permission
world.grant_owner(
selector_from_tag!("my_game-GameState"),
new_owner_address
);// Revoke writer permission
world.revoke_writer(
selector_from_tag!("my_game-Position"),
old_system_address
);
// Revoke owner permission
world.revoke_owner(
selector_from_tag!("my_game-GameState"),
old_owner_address
);// Check if address is owner
let is_owner = world.is_owner(resource_selector, address);
// Check if address is writer
let can_write = world.is_writer(resource_selector, address);// Good: Specific permissions for specific functions
world.grant_writer(selector_from_tag!("my_game-Position"), movement_contract);
world.grant_writer(selector_from_tag!("my_game-Health"), combat_contract);
// Bad: Overly broad permissions
world.grant_owner(selector_from_tag!("my_game"), movement_contract);// Different systems handle different aspects
world.grant_writer(selector_from_tag!("my_game-Position"), movement_system);
world.grant_writer(selector_from_tag!("my_game-Health"), combat_system);
world.grant_writer(selector_from_tag!("my_game-Inventory"), inventory_system);
// Trading system needs access to Inventory too
world.grant_writer(selector_from_tag!("my_game-Inventory"), trading_system);Grant access to all resources in a namespace:
// This system can write to ANY resource in "my_game" namespace
world.grant_writer(
selector_from_tag!("my_game"),
system_contract
);// Admin has owner permission on namespace
world.grant_owner(selector_from_tag!("my_game"), game_admin);
// Admin has owner permission on critical resources
world.grant_owner(selector_from_tag!("my_game-GameConfig"), game_admin);Anyone can call:
fn spawn(ref self: ContractState) {
let mut world = self.world_default();
let player = get_caller_address();
// No permission check - anyone can spawn
world.write_model(@Position { player, vec: Vec2 { x: 0, y: 0 } });
}fn admin_function(ref self: ContractState) {
let mut world = self.world_default();
let caller = get_caller_address();
// Check caller is owner of the namespace
assert(
world.is_owner(selector_from_tag!("my_game"), caller),
'not authorized'
);
// Proceed with admin logic
}The World contract emits events when permissions change:
#[derive(Drop, starknet::Event)]
pub struct OwnerUpdated {
#[key]
pub resource: felt252,
#[key]
pub contract: ContractAddress,
pub value: bool,
}
#[derive(Drop, starknet::Event)]
pub struct WriterUpdated {
#[key]
pub resource: felt252,
#[key]
pub contract: ContractAddress,
pub value: bool,
}# dojo_dev.toml
[namespace]
default = "my_game"
[writers]
# All resources in my_game can be written by actions
"my_game" = ["my_game-actions"]
[owners]
# Admin system owns the namespace
"my_game" = ["my_game-admin"]fn add_new_system(ref self: ContractState, new_system_address: ContractAddress) {
let mut world = self.world_default();
// Must be namespace owner to grant permissions
world.grant_writer(
selector_from_tag!("my_game-Position"),
new_system_address
);
}fn transfer_ownership(ref self: ContractState, new_owner: ContractAddress) {
let mut world = self.world_default();
// Grant owner to new address
world.grant_owner(selector_from_tag!("my_game"), new_owner);
// Revoke from current owner
world.revoke_owner(selector_from_tag!("my_game"), get_caller_address());
}fn debug_permissions(world: @WorldStorage, resource: felt252, address: ContractAddress) {
let is_owner = world.is_owner(resource, address);
let is_writer = world.is_writer(resource, address);
// Log or print these values for debugging
}After permission setup:
44466c6
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.