riggy is an early-alpha AI-driven text game built in Rust.
The current game loop is:
- one authoritative directed
petgraphworld insrc/world.rs - one manually controlled actor that the UI presents as
You - colocated AI actors that choose actions through
rigtool calls - typed commands, events, read models, and presenter formatting between the world and the UI
This README is written as an operator/developer reference for working on riggy autonomously.
- Runtime UI: ratatui in
src/tui.rs - Headless test client:
src/bin/riggy_headless.rs - Authoritative application service:
src/app/service.rs - Authoritative world graph:
src/world.rs - AI turn context and prompting:
src/ai/context.rsandsrc/ai/prompting.rs rigbackend adapter and agent tools:src/llm.rs- Read-model projection:
src/app/read_model.rs - World prose and event rendering:
src/presenter.rs - Logging bootstrap:
src/logging.rs
Run the main game:
cargo run -p riggyRun the scriptable headless client:
cargo run -p riggy --bin riggy_headlessForce the mock backend:
cargo run -p riggy --bin riggy_headless -- --mockRun one-shot commands:
cargo run -p riggy --bin riggy_headless -- --mock \
--command look \
--command "say 0 hello"Run a script file:
cargo run -p riggy --bin riggy_headless -- --mock --script scripts/smoke_test.riggyBackend selection is currently environment-driven in src/llm.rs:
- If
OLLAMA_MODELis set,riggyuses Ollama. - Otherwise, if
OPENAI_API_KEYorOPENAI_BASE_URLis set,riggyuses the OpenAI-compatible backend. - Otherwise,
riggyfalls back to the local mock backend.
Useful environment variables:
OLLAMA_MODELOLLAMA_API_BASE_URLOPENAI_API_KEYOPENAI_BASE_URLOPENAI_MODELRUST_LOG
Example Ollama run:
export OLLAMA_MODEL=qwen3:4b
cargo run -p riggyImportant:
- The debug panel shows the exact backend model, not just the provider.
- If the panel says
rig/ollama (llama3.2), you are still runningllama3.2. rigcan support Ollama tool calls, but individual local models may still ignore tools or use them badly.
riggy now writes a root log file to:
logs/riggy.log
The logger is initialized by both binaries in src/main.rs and src/bin/riggy_headless.rs, using src/logging.rs.
What the log captures:
- startup and backend selection
- action planning and execution
- autonomous NPC turn selection
rigagent selection flow- tool call arguments/results/errors
- TUI action submission and pending completion
- panics with backtraces
The file is intentionally formatted for live tailing: compact, one-line events, no span open/close noise, and the most useful riggy fields kept inline.
Default filter:
riggy=trace,rig=debug,info
Override with RUST_LOG, for example:
RUST_LOG=riggy=trace,rig=trace cargo run -p riggylogs/ is ignored in git.
The TUI has an agent debug panel.
- Press
F2to toggle it. - It shows the latest local NPC decision traces.
- It includes backend label, selected action, errors, available actions, recent speech, model output, and tool calls.
When debugging NPCs, the fastest loop is:
- Reproduce in the TUI or headless client.
- Tail
logs/riggy.log. - Check the agent debug panel or headless
debugoutput. - Confirm whether the model made a real tool call or only emitted plain text.
The headless client currently supports:
lookactionspeopleroutesentitiescontextdebugfocus mefocus <actor-id>travel <route-index-or-place-id>say <person-index-or-actor-id> <text>inspect <entity-index-or-entity-id>wait <30s|2m|1h>agent <actor-id>save <path>load <path>source <path>quit
Notes:
people,routes, andentitiesshow both list indices and stable ids.say 0 hellotalks to the first visible actor in the current place.agent <actor-id>forces one autonomous decision pass for that actor.sourceis top-level only; nestedsourcecommands inside script files are intentionally rejected.
Example script:
# scripts/smoke_test.riggy
look
people
say 0 hello
debug
wait 30s
look
If you are developing riggy without manually driving the TUI every time, use this loop:
- Start with the headless client and the mock backend.
- Reproduce the intended action flow with one-shot commands or a script file.
- Inspect
logs/riggy.log. - If the issue is AI-related, run
debugin headless mode or use the TUIF2panel. - Only switch to Ollama/OpenAI-compatible once the game-side behavior is correct with the mock backend.
- Use provider-backed runs to debug tool-calling and prompt behavior, not world-state logic.
Recommended command sequence:
cargo test -p riggy
cargo run -p riggy --bin riggy_headless -- --mock -c look -c "say 0 hello" -c debug
tail -n 200 logs/riggy.logUseful live log commands:
tail -f logs/riggy.log
tail -f logs/riggy.log | rg "selected_action|tool|autonomous|error"Run the full crate tests:
cargo test -p riggyRun a compile-only pass:
cargo check -p riggyThere are unit tests around:
- world invariants
- command planning
- speech/action flow
- autonomous NPC turn taking
- headless parsing and headless mock conversation flow
The game is no longer player-special-cased at the world level.
- The player is just the single
ControllerMode::Manualactor. - NPCs are
ControllerMode::AiAgent. - Both use the same typed action system.
- Actions are recorded as process nodes with duration in the graph.
- NPC decision making goes through
rigtools, not direct LLM-to-world mutation.
Current actor actions include:
- move
- speak
- inspect
- wait
- do_nothing
This means:
- speech is a real action
- speech advances time
- NPC replies are separate actions, not magical side effects
- Tool-calling quality depends heavily on the model. Smaller local models may still emit fake tool syntax in plain text.
- If an NPC appears idle, inspect both the debug panel and
logs/riggy.logbefore assuming world logic is broken. - The workspace still contains ontology-related crates, but the
riggygame crate’s runtime logic lives insrc/. - Save/load exists, but persistence versioning is still an open roadmap item.
High-signal paths:
src/world.rs: authoritative game graph, generation, validation, processessrc/domain/commands.rs: typed action APIsrc/domain/events.rs: typed result/event APIsrc/app/service.rs: orchestration, action execution, autonomous turnssrc/llm.rs: backend selection, agent tools, decision flowsrc/tui.rs: ratatui runtimesrc/headless.rs: headless automation clientdocs/architecture-roadmap.md: architecture intent and unfinished items
If you only remember five things, remember these:
- Use the headless client first.
- Read
logs/riggy.log. - Use the mock backend for game logic, real backends for tool-calling behavior.
- Check the exact model name in the debug output before trusting any AI result.
- Treat the graph in
src/world.rsas authoritative.