Set up and configure Torii indexer for GraphQL queries, gRPC subscriptions, and SQL access. Use when indexing your deployed world for client queries or real-time updates.
Sets up Torii indexer for your deployed world, providing GraphQL queries, gRPC subscriptions, and SQL access. Use when you need to query world state or receive real-time updates from your contracts.
/plugin marketplace add dojoengine/book/plugin install book@dojoengineThis skill is limited to using the following tools:
Set up and use Torii, the Dojo indexer, for efficient querying and real-time subscriptions to your world state.
Manages Torii indexer:
Start Torii:
"Start Torii indexer for my deployed world"
GraphQL queries:
"Create GraphQL query for all player positions"
Subscriptions:
"Set up real-time subscriptions for entity updates"
Torii is the Dojo indexer that:
Why use Torii:
torii \
--world WORLD_ADDRESS \
--rpc http://localhost:5050
torii \
--world 0xabc... \
--rpc http://localhost:5050 \
--database torii.db \
--indexing-from-block 0 \
--allowed-origins "*"
| Option | Description | Default |
|---|---|---|
--world | World contract address | Required |
--rpc | RPC endpoint URL | Required |
--database | SQLite database path | torii.db |
--indexing-from-block | Start block | 0 |
--allowed-origins | CORS origins | * |
--graphql-port | GraphQL port | 8080 |
--grpc-port | gRPC port | 8081 |
Torii provides GraphQL endpoint at http://localhost:8080/graphql
Get all entities of a model:
query {
positions {
edges {
node {
player
x
y
}
}
}
}
Get single entity:
query {
position(id: "0x123") {
player
x
y
}
}
Filter by field value:
query {
positions(where: { x: { eq: 10 } }) {
edges {
node {
player
x
y
}
}
}
}
Multiple conditions:
query {
positions(
where: {
x: { gte: 10, lte: 20 }
y: { eq: 5 }
}
) {
edges {
node {
player
x
y
}
}
}
}
Cursor-based pagination:
query {
positions(first: 10, after: "cursor_value") {
edges {
node {
player
x
y
}
cursor
}
pageInfo {
hasNextPage
endCursor
}
}
}
query {
positions(orderBy: { x: ASC }, first: 10) {
edges {
node {
player
x
y
}
}
}
}
Query related entities:
query {
players {
edges {
node {
address
position {
x
y
}
health {
current
max
}
inventory {
gold
items
}
}
}
}
}
Real-time updates via gRPC at grpc://localhost:8081
Subscribe to specific entity changes:
import { createClient } from '@dojoengine/torii-client';
const client = await createClient({
rpcUrl: "http://localhost:5050",
toriiUrl: "http://localhost:8080",
worldAddress: WORLD_ADDRESS,
});
// Subscribe to Position changes
await client.onEntityUpdated(
[{ model: "Position", keys: [playerId] }],
(entity) => {
console.log("Position updated:", entity);
}
);
Subscribe to all entities of a model:
// Subscribe to all Position updates
await client.onModelUpdated(
"Position",
(entities) => {
console.log("Positions updated:", entities);
}
);
Subscribe to world events:
await client.onEventEmitted(
"Moved",
(event) => {
console.log("Player moved:", event);
}
);
Torii stores data in SQLite, accessible for complex queries.
sqlite3 torii.db
Torii creates tables for each model:
-- Position model table
CREATE TABLE position (
id TEXT PRIMARY KEY,
player TEXT NOT NULL,
x INTEGER NOT NULL,
y INTEGER NOT NULL,
updated_at INTEGER NOT NULL
);
Spatial queries:
SELECT * FROM position
WHERE x BETWEEN 10 AND 20
AND y BETWEEN 5 AND 15;
Aggregations:
SELECT
AVG(health.current) as avg_health,
COUNT(*) as player_count
FROM health;
Joins:
SELECT
p.player,
p.x,
p.y,
h.current as health
FROM position p
JOIN health h ON p.player = h.player
WHERE h.current < 50;
import { createClient } from '@dojoengine/torii-client';
const client = await createClient({
rpcUrl: "http://localhost:5050",
toriiUrl: "http://localhost:8080",
worldAddress: WORLD_ADDRESS,
});
// Query entities
const positions = await client.getEntities({
model: "Position",
where: { x: { $gte: 10 } },
limit: 10
});
// Subscribe to updates
await client.onEntityUpdated(
[{ model: "Position", keys: [playerId] }],
(entity) => updateUI(entity)
);
import { ApolloClient, InMemoryCache, gql } from '@apollo/client';
const client = new ApolloClient({
uri: 'http://localhost:8080/graphql',
cache: new InMemoryCache(),
});
// Query
const { data } = await client.query({
query: gql`
query GetPositions {
positions(where: { x: { gte: 10 } }) {
edges {
node {
player
x
y
}
}
}
}
`
});
Index from specific block:
# Skip early blocks with no data
torii --indexing-from-block 1000 ...
Selective model indexing:
Configure in torii.toml:
[indexing]
models = ["Position", "Health"] # Only index these models
Use pagination:
query {
positions(first: 50) { # Limit results
edges {
node { player x y }
cursor
}
}
}
Filter early:
query {
# ✅ Filter in query
positions(where: { x: { gte: 10 } }) {
edges { node { player x y } }
}
}
# ❌ Don't fetch all then filter client-side
Select only needed fields:
query {
positions {
edges {
node {
x y # Only fields needed
}
}
}
}
# Terminal 1: Katana
katana --dev
# Terminal 2: Deploy world
sozo migrate
# Terminal 3: Torii
torii --world WORLD_ADDRESS --rpc http://localhost:5050
# Use production RPC
torii \
--world 0xabc... \
--rpc https://api.cartridge.gg/x/starknet/mainnet \
--database /data/torii.db \
--allowed-origins "https://mygame.com"
FROM ghcr.io/dojoengine/torii:latest
CMD ["torii", \
"--world", "${WORLD_ADDRESS}", \
"--rpc", "${RPC_URL}", \
"--database", "/data/torii.db"]
curl http://localhost:8080/health
query {
indexingStatus {
currentBlock
latestBlock
synced
}
}
du -h torii.db
After Torii setup:
dojo-client skill)This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.