Build, test, and play Wherigo cartridges with AI — an MCP server for GPS-based interactive stories
Project description
wheriflo
🧪 Beta. wheriflo is under active development — expect rough edges and please report issues.
Build, test, and play Wherigo cartridges from the command line — with an MCP server for AI-assisted cartridge creation.
Describe it. AI builds it. Go play it.
Install
One command, any AI client — installs wheriflo and configures every AI client found on your machine (Claude Desktop, Claude Code, VS Code/Copilot, Cursor, OpenAI Codex):
Mac / Linux:
curl -LsSf https://raw.githubusercontent.com/harrisonhoffman1/wheriflo/main/scripts/install.sh | sh
Windows (PowerShell):
powershell -ExecutionPolicy ByPass -c "irm https://raw.githubusercontent.com/harrisonhoffman1/wheriflo/main/scripts/install.ps1 | iex"
Already have Python? You can install with pip and run the configurator yourself:
pip install wheriflo
wheriflo setup # detects your AI clients and configures them
wheriflo setup merges into existing config files (never overwrites other
servers), backs up anything it touches, and is safe to re-run. Use
--dry-run to preview and --client KEY to target one client.
Verify it works:
wheriflo --version
Note: If you have multiple Python environments,
wheriflo --versionmay report a different version than what you just installed (e.g. a previously installed version in user site-packages). Usepip show wherifloto confirm which version is active.
Running with uvx in sandboxed environments
Some AI coding agents and CI sandboxes only allow writes inside the workspace or
temporary directories. If uvx cannot write to its default directories under
your home folder, it may fail before wheriflo starts. Set both UV_CACHE_DIR
and UV_TOOL_DIR to writable paths:
UV_CACHE_DIR=.uv-cache UV_TOOL_DIR=.uv-tools uvx --from wheriflo wheriflo compile path/to/Cartridge.lua
Use absolute paths if your MCP client starts outside the workspace.
Quick Start
# Configure your AI clients to use wheriflo (one-time)
wheriflo setup
# Scaffold a new geocache cartridge (default type)
wheriflo init "My Adventure" --author "Jane" --location 47.6,-122.3 --find-location 47.601,-122.301
# Scaffold a standalone game (no physical cache)
wheriflo init "Mystery Game" --author "Jane" --location 47.6,-122.3 --activity WherigoGame
# Test in browser (auto-reloads when file changes)
wheriflo play my-adventure/MyAdventure.lua --watch
# Build for release
wheriflo build my-adventure/MyAdventure.lua
# Store Groundspeak credentials securely (one-time setup)
wheriflo credentials set
# Compile via the official Groundspeak API
wheriflo compile my-adventure/MyAdventure.lua
# Review and edit cartridge text — iOS screen previews, variable inspector, inline editing
wheriflo edit my-adventure/MyAdventure.lua
# View gameplay flow map with jump-to-section testing
wheriflo flow my-adventure/MyAdventure.lua
# Publish to wherigo.com (opens browser, copies .gwz path)
wheriflo publish my-adventure/MyAdventure.lua
# Validate a compiled cartridge
wheriflo validate MyAdventure.gwc
# Check version
wheriflo --version
How It Works
Groundspeak Compiler
The toolkit can compile your cartridge through the official Groundspeak (wherigo.com) compiler API. This is the definitive compatibility test — if Groundspeak accepts it, the cartridge will work on all Wherigo players.
Setting up credentials
You need a free wherigo.com account.
Option 1: System keyring (recommended) — credentials are encrypted by your OS:
pip install keyring # if not already installed
wheriflo credentials set # prompts for username and password
wheriflo credentials check # verify credentials are stored
This uses Windows Credential Manager, macOS Keychain, or Linux Secret Service.
Option 2: Environment variables — for CI/automation or if keyring is unavailable:
# Linux / Mac
export WHERIGO_USERNAME=your_username
export WHERIGO_PASSWORD=your_password
# Windows (PowerShell)
$env:WHERIGO_USERNAME = "your_username"
$env:WHERIGO_PASSWORD = "your_password"
Option 3: Provide at compile time — when using the MCP server, the AI
assistant can ask for your credentials and pass them directly to
wheriflo_compile. They are never stored.
For MCP clients, you can also add credentials to your server configuration (note: these are stored as plain text in the config file):
{
"servers": {
"wheriflo": {
"command": "uvx",
"args": ["wheriflo", "mcp"],
"env": {
"WHERIGO_USERNAME": "your_username",
"WHERIGO_PASSWORD": "your_password"
}
}
}
}
Security: Credentials are resolved in order: runtime parameters → environment variables → system keyring. They are never logged, never included in error messages, and the connection to wherigo.com uses HTTPS. The SOAP request body is built with XML-safe escaping to prevent injection.
Sandbox: Cartridge Lua runs in a restricted lupa (Lua 5.1) sandbox when you
play/test a cartridge. The Python bridge is disabled (register_eval=False,register_builtins=False), an attribute filter blocks access to private/dunder attributes of Python objects, andio,os,debug,loadfile,dofile,loadstring,load, andpackage.loadlib/loadersare removed before cartridge code runs. See SECURITY.md for details.
MCP Server
The toolkit includes an MCP server for use with AI coding assistants (GitHub Copilot, Claude Desktop, Claude Code, Cursor, Zed, etc.).
Tools
| Tool | Description |
|---|---|
wheriflo_init |
Scaffold a new cartridge project |
wheriflo_build |
Compile .lua → .gwc/.gwz (local) |
wheriflo_compile |
Compile via official Groundspeak API |
wheriflo_validate |
Validate a .gwc binary |
wheriflo_lint |
Check .lua for common mistakes |
wheriflo_play |
Load cartridge + start web player |
wheriflo_get_state |
Inspect current game state |
wheriflo_teleport |
Enter a zone (trigger OnEnter) |
wheriflo_leave_zone |
Exit a zone (trigger OnExit) |
wheriflo_set_position |
Set player GPS coordinates |
wheriflo_respond |
Dismiss message or answer prompt |
wheriflo_autoplay |
Run a sequence of play-test steps |
wheriflo_get_resource |
Read API reference, design guide, or template |
wheriflo_edit |
Review/extract all cartridge text |
wheriflo_flow |
Analyze cartridge gameplay flow graph |
wheriflo_publish |
Open wherigo.com to upload or update |
wheriflo_reset |
Full state wipe and restart |
wheriflo_stop |
Stop web player and free the port |
Resources
wherigo://api-reference— Lua API docswherigo://design-guide— Design best practiceswherigo://lua-template— Starter template
Guides
- Getting Started — Installation, setup, first cartridge
- Flow Map Guide — Interactive gameplay flow visualization, jump-to-section testing, coverage tracking
Prompts
design-cartridge— Guided workflow to create a cartridge from scratchreview-cartridge— Automated play-test and bug report
Quick Start for AI Agents
This is the typical MCP workflow for building and testing a cartridge:
1. wheriflo_init → scaffold a new project
2. (edit the .lua file) → write your cartridge logic
3. wheriflo_lint → check for common mistakes
4. wheriflo_build → compile to .gwc/.gwz + auto-starts web player
5. wheriflo_teleport → enter a zone
wheriflo_respond → dismiss messages / answer prompts
wheriflo_leave_zone → test OnExit handlers
wheriflo_get_state → inspect zones, inventory, tasks
6. wheriflo_compile → validate with official Groundspeak API
7. wheriflo_publish → upload or update on wherigo.com
8. wheriflo_stop → shut down the web player when done
Use wheriflo_get_resource("api-reference") to read the full Lua API
documentation, and wheriflo_get_resource("design-guide") for best practices.
Setup: automatic (any client)
wheriflo setup
Detects installed AI clients and writes the MCP configuration for each. The sections below are the equivalent manual steps, if you prefer to edit configs yourself or need a workspace-scoped setup.
Setup: VS Code / GitHub Copilot
Add to .vscode/mcp.json in your workspace:
{
"servers": {
"wherigo": {
"command": "uvx",
"args": ["wheriflo", "mcp"]
}
}
}
Or open the Command Palette → MCP: Open User Configuration to add it globally.
If your agent environment restricts writes to the workspace, add workspace-local
uv directories so uvx does not try to use ~/.cache/uv or
~/.local/share/uv/tools:
{
"servers": {
"wherigo": {
"command": "uvx",
"args": ["wheriflo", "mcp"],
"env": {
"UV_CACHE_DIR": ".uv-cache",
"UV_TOOL_DIR": ".uv-tools"
}
}
}
}
Setup: Claude Desktop
Add to your claude_desktop_config.json:
{
"mcpServers": {
"wherigo": {
"command": "uvx",
"args": ["wheriflo", "mcp"]
}
}
}
On Windows, use:
{
"mcpServers": {
"wherigo": {
"command": "cmd",
"args": ["/c", "uvx", "wheriflo", "mcp"]
}
}
}
Setup: Claude Code
claude mcp add wherigo -- uvx wheriflo mcp
Setup: OpenAI Codex
codex mcp add -- uvx wheriflo mcp
Setup: Cursor
Add to Cursor Settings → MCP Servers:
{
"mcpServers": {
"wherigo": {
"command": "uvx",
"args": ["wheriflo", "mcp"]
}
}
}
Setup: pip install (alternative to uvx)
If you prefer a permanent install instead of uvx:
pip install wheriflo
Then replace "command": "uvx", "args": ["wheriflo", "mcp"] with
"command": "wheriflo", "args": ["mcp"] in any config above.
Setup: Docker
docker build -t wheriflo .
{
"mcpServers": {
"wherigo": {
"command": "docker",
"args": ["run", "--rm", "-i", "wheriflo"]
}
}
}
Linting
Check a .lua file for common Wherigo mistakes without building:
wheriflo lint MyAdventure.lua
Checks for:
Media = nil/Icon = nil(crashes iOS app)ShowObjects = "OnEntry"(wrong enum, should be"OnEnter")MoveObject()usage (doesn't exist — suggestsMoveTo()instead)- Missing
require "Wherigo",OnStart,OnEnter,OnGetInput - Unreachable zones (never set
Active = true) - Apostrophes in comments (crashes Groundspeak compiler)
Add -- wheriflo:ignore to any line to suppress warnings on that line.
For zones activated dynamically through helper functions, add the comment
to the Wherigo.Zone() constructor line.
Also available as the wheriflo_lint MCP tool.
Debugging
Test the MCP server with the MCP Inspector:
npx @modelcontextprotocol/inspector uvx wheriflo mcp
Or with mcp dev:
uv run mcp dev wheriflo/src/wheriflo/mcp_server.py
Architecture
%%{init: {'theme': 'base', 'themeVariables': {'fontFamily': 'Segoe UI, sans-serif', 'lineColor': '#78909c'}}}%%
flowchart LR
subgraph clients["Works with any MCP client"]
direction TB
VS["<b>VS Code</b>\n+ GitHub Copilot"]
CL["<b>Claude</b>\nDesktop & Code"]
CX["<b>OpenAI Codex</b>"]
CU["<b>Cursor</b>"]
end
subgraph mcp["wheriflo MCP Server"]
direction TB
tools["🛠️ <b>18 Tools</b>\ninit · build · compile · lint\nplay · teleport · leave_zone · set_position\nrespond · autoplay · get_state · get_resource\nedit · flow · publish · validate · reset · stop"]
resources["📚 <b>3 Resources</b>\nAPI reference\nDesign guide\nStarter template"]
prompts["💬 <b>2 Prompts</b>\ndesign-cartridge\nreview-cartridge"]
end
subgraph engine["Sandboxed Lua Engine"]
direction TB
shim["Wherigo API shim"]
sandbox["🔒 No io · os · debug"]
web["🌐 Web player\nlocalhost:8000"]
end
clients <-->|"stdio"| mcp
mcp <--> engine
style clients fill:#e3f2fd,stroke:#1a73e8,rx:12,color:#0d47a1
style mcp fill:#fff3e0,stroke:#ff9800,rx:12,color:#e65100
style engine fill:#fce4ec,stroke:#e91e63,rx:12,color:#880e4f
style VS fill:#bbdefb,stroke:#42a5f5,rx:8,color:#0d47a1
style CL fill:#bbdefb,stroke:#42a5f5,rx:8,color:#0d47a1
style CX fill:#bbdefb,stroke:#42a5f5,rx:8,color:#0d47a1
style CU fill:#bbdefb,stroke:#42a5f5,rx:8,color:#0d47a1
style tools fill:#ffe0b2,stroke:#ffa726,rx:8,color:#e65100
style resources fill:#ffe0b2,stroke:#ffa726,rx:8,color:#e65100
style prompts fill:#ffe0b2,stroke:#ffa726,rx:8,color:#e65100
style shim fill:#f8bbd0,stroke:#ec407a,rx:8,color:#880e4f
style sandbox fill:#f8bbd0,stroke:#ec407a,rx:8,color:#880e4f
style web fill:#f8bbd0,stroke:#ec407a,rx:8,color:#880e4f
Troubleshooting
uvx cache or tool directory permission errors
If a command fails with an error like Failed to initialize cache at ~/.cache/uv, Could not create temporary file, or a path under
~/.local/share/uv/tools, the failure is from uvx setup rather than
wheriflo, Groundspeak, or your cartridge. Point uv at writable directories:
UV_CACHE_DIR=.uv-cache UV_TOOL_DIR=.uv-tools uvx --from wheriflo wheriflo compile path/to/Cartridge.lua
For MCP server configs, put the same values in the server env block. Use
absolute paths if relative paths are resolved outside your project.
Run the diagnostic tool to check your setup:
wheriflo doctor
This verifies Python version, lupa, mcp SDK, credentials, Groundspeak API reachability, and the starter template.
Known Limitations
- Media in web player — images referenced in
ZMediaobjects are embedded in the GWC/GWZ and displayed in the web player during play-testing. Audio files are embedded but not played back in the web player. - Timers run in real time —
ZTimerCountdown and Interval timers fireOnTick/OnStopon real wall-clock schedules during play-testing. Because MCP play-testing is turn-based, a timer may fire between tool calls; checkwheriflo_get_stateafter waiting out a timer. Timer state is not saved/restored. - No save/restore —
OnRestoreis not implemented. The engine always starts fresh. Usewheriflo_resetto restart. - Single-player only — the engine simulates one player. Multi-player or co-op cartridges can only be tested on the single-player path.
- Limited GPS simulation — zones are entered via
wheriflo_teleport, not by simulating GPS movement. Usewheriflo_set_positionto set arbitrary coordinates for proximity testing, butOnDistanceChangedcallbacks don't fire automatically. - iOS line breaks — only
[[ ]]long strings render line breaks on the iOS Wherigo app.\nin quoted strings works on Android and the web player but not iOS. See the API reference for workarounds. - Web player is local only — the browser player binds to
localhostand is not suitable for remote access or sharing.
Security
The Lua runtime is sandboxed: io, os, debug, loadfile, and dofile
are removed before any cartridge code executes. Cartridges can only use the
Wherigo API and standard Lua string/table/math operations.
See SECURITY.md for the full security policy and vulnerability reporting.
Contributing
See CONTRIBUTING.md for development setup, project structure, and guidelines.
License
MIT — see LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file wheriflo-2.9.0.tar.gz.
File metadata
- Download URL: wheriflo-2.9.0.tar.gz
- Upload date:
- Size: 1.7 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
49ead0fe6ad2e6764afbc3f9b465abc099597bea965afb02061806b00f7fde85
|
|
| MD5 |
45ff7d3b060154846d6a86078158ec0a
|
|
| BLAKE2b-256 |
cc909ac998f0af61cddfe21e74347f512b99cb4a59dd99d818962af4d2b5e96e
|
Provenance
The following attestation bundles were made for wheriflo-2.9.0.tar.gz:
Publisher:
publish.yml on harrisonhoffman1/wheriflo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wheriflo-2.9.0.tar.gz -
Subject digest:
49ead0fe6ad2e6764afbc3f9b465abc099597bea965afb02061806b00f7fde85 - Sigstore transparency entry: 2170921748
- Sigstore integration time:
-
Permalink:
harrisonhoffman1/wheriflo@a40fef68bfb77a901d32552d272dda89d5ab74a9 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/harrisonhoffman1
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a40fef68bfb77a901d32552d272dda89d5ab74a9 -
Trigger Event:
push
-
Statement type:
File details
Details for the file wheriflo-2.9.0-py3-none-any.whl.
File metadata
- Download URL: wheriflo-2.9.0-py3-none-any.whl
- Upload date:
- Size: 160.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5287cb3284e19d7b775837609058ca8c036bd238a65ed9bdbdeb04c1ad5fcaab
|
|
| MD5 |
011f3c67abb6a3b6a2865730106c5947
|
|
| BLAKE2b-256 |
8e2f6c3207b74ac705404f4ebf71d3f68a1f43b776729b1a5a57cad9c55bd075
|
Provenance
The following attestation bundles were made for wheriflo-2.9.0-py3-none-any.whl:
Publisher:
publish.yml on harrisonhoffman1/wheriflo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
wheriflo-2.9.0-py3-none-any.whl -
Subject digest:
5287cb3284e19d7b775837609058ca8c036bd238a65ed9bdbdeb04c1ad5fcaab - Sigstore transparency entry: 2170921764
- Sigstore integration time:
-
Permalink:
harrisonhoffman1/wheriflo@a40fef68bfb77a901d32552d272dda89d5ab74a9 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/harrisonhoffman1
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a40fef68bfb77a901d32552d272dda89d5ab74a9 -
Trigger Event:
push
-
Statement type: