7 downloads
valheim-ai-agent
An AI agent framework for controlling a Valheim character programmatically, using a BepInEx plugin as a game bridge and a Python agent powered by an LLM.
Inspired by Minecraft bot frameworks such as mineflayer, adapted to Valheim's closed binary via BepInEx modding.
Architecture
The system has three layers:
┌─────────────────────────────────────────────────────┐
│ Valheim Process │
│ ┌───────────────────────────────────────────────┐ │
│ │ ValheimBotBridge (BepInEx C# plugin) │ │
│ │ - Serializes game state to JSON │ │
│ │ - Hosts WebSocket server on localhost:25500 │ │
│ │ - Executes action commands from agent │ │
│ └───────────────────┬───────────────────────────┘ │
└──────────────────────│──────────────────────────────┘
│ WebSocket (ws://localhost:25500)
┌──────────────────────│──────────────────────────────┐
│ Python Agent │ │
│ ┌───────────────────▼───────────────────────────┐ │
│ │ valheim_agent.py │ │
│ │ - Receives game state │ │
│ │ - Calls LLM (Claude / GPT-4o) │ │
│ │ - Sends action commands │ │
│ └───────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
Data flow: Game state → WebSocket → Python agent → LLM → action command → WebSocket → game.
Prerequisites
System
- Linux (tested on Pop!_OS 24.04)
- .NET SDK 10 (
dotnet --versionto confirm) - Python 3.11+
- Steam with Valheim installed
Valheim modding
- r2modman installed
- BepInEx installed via r2modman (denikson-BepInExPack_Valheim 5.4.2333)
- An active r2modman profile for Valheim
Env Var Requirements
# Required for LLM mode
export OPENAI_API_KEY="sk-..."
# Optional
export VALHEIM_LLM_MODEL="gpt-4o" # default
export VALHEIM_WS_URL="ws://localhost:25500/bridge" # default
Running Tests
cd /opt/repos/itenev/valheim-ai-agent
pytest tests/ -v
Quick Start
These are the minimum steps to get from a fresh clone to a running plugin (Phase 1). See the per-module READMEs for full detail.
1. Populate the libs/ folder
Copy reference DLLs from your Valheim and BepInEx installations into plugin/libs/.
Required files are listed in plugin/README.md.
2. Build the plugin
cd plugin
dotnet build -c Release
3. Deploy to r2modman
PROFILE="<your-profile-name>"
PLUGINS=~/.config/r2modmanPlus-local/Valheim/profiles/$PROFILE/BepInEx/plugins
cp plugin/bin/Release/netstandard2.1/ValheimBotBridge.dll $PLUGINS/
cp plugin/bin/Release/netstandard2.1/websocket-sharp.dll $PLUGINS/
cp plugin/bin/Release/netstandard2.1/Newtonsoft.Json.dll $PLUGINS/
4. Launch Valheim via r2modman (Start modded)
5. Verify the plugin loaded
tail -f ~/.config/r2modmanPlus-local/Valheim/profiles/$PROFILE/BepInEx/LogOutput.log
Expected output:
[Info : BepInEx] Loading [ValheimBotBridge 0.1.0]
6. Start the Python agent (Phase 3 — see agent/README.md)
cd agent
pip install -r requirements.txt
python valheim_agent.py
Release Flow
1. Build
cd plugin && dotnet build -c Release && cd ..
2. Stage DLLs into release/plugins/
bash scripts/prepare-release.sh
3. Update changelog, then commit
vim CHANGELOG.md git add release/plugins/ CHANGELOG.md git commit -m "Release v0.1.0"
4. Tag and push — this triggers the GitHub Action
git tag v0.1.0
git push origin main v0.1.0
Progress Status
| Phase | Status | Tests | Notes |
|---|---|---|---|
| Phase 1: Protocol Alignment | COMPLETE | 50 | WS endpoint, action envelope, state normalizer |
| Phase 2: LLM Integration | COMPLETE | 34 | Real API, retry, guardrails, mock fallback |
| Phase 3: Autonomous Loop | PENDING | - | Control loop wiring |
| Integration Tests | PENDING | - | Full E2E |
What's Working
- WebSocket connects to
/bridgeendpoint by default - Action envelope converts Python ↔ plugin format correctly
- State normalizer handles camelCase → snake_case conversion
- Config loads API key from environment (no hardcoded secrets)
- LLM planner makes real OpenAI calls with:
- Exponential backoff retry (1s, 2s, 4s)
- JSON schema validation
- Fallback to IDLE on all failures
- Mock mode when API key missing
What's Pending
- Phase 3: Full autonomous control loop (connect planner → bridge → send actions)
- Integration tests with live plugin
- Observability (structured logs, metrics)
Next Steps
- Phase 3: Wire autonomous loop
- Connect
planner.call_llm()output →bridge.send_action()with protocol envelope - Run integration test with mock plugin
- Update AGENTS.md with final setup instructions
