dcssvox
Hands-free voice control and narration for Dungeon Crawl Stone Soup, built for playing on a phone under Termux with headphones and a mic.
You say what to do; it reads back what happened. No keyboard, no screen-staring.
you: "explore"
it: "You encounter a bat."
you: "attack east"
it: "You hit the bat. Health 17 of 19."
Why it works
DCSS is turn-based and lives in a terminal, which makes it close to the ideal
target for voice: nothing has a reaction window, and both the screen and the
input are trivially machine-accessible. dcssvox runs crawl inside tmux and
drives it from outside — keystrokes in via send-keys, the rendered screen out
via capture-pane. crawl itself is never patched.
Three design rules, all aimed at someone whose hands are busy:
- Never stuck. There is no keyboard to bail out with, so every modal state
is recognised and has a spoken way out.
recover()walks crawl back to normal play without needing to classify the state correctly. - Never surprised. Irreversible actions (quaff, drop, read, take off) are read back and wait for "yes" before a key is sent.
- Never guessing. Item and spell names are matched against the letters crawl just printed on screen, not a hand-maintained table. If nothing matches convincingly it says so instead of pressing something.
Speech priority comes from crawl's own message channels: dcssvox pins each of the 30 channels to a colour in its generated rc, so the SGR code on a message row is an exact, language-independent priority signal. "An endoplasm is nearby!" is urgent; "The endoplasm barely misses you." is not read at all.
Install (Termux)
pkg install crawl tmux git cmake clang make
python -m pip install dcssvox
dcssvox doctor # tells you what's missing
Character creation is done by voice too — just say the species, background and weapon ("minotaur", "berserker", "mace"). A character name is supplied for you, because crawl's name prompt is free text and has no voice path.
For speech output also install the Termux:API app (from F-Droid) plus
pkg install termux-api. For voice input:
dcssvox setup # builds whisper.cpp + fetches tiny.en (one time)
dcssvox play
Watch the game on screen any time with tmux attach -t dcssvox.
Without a mic
dcssvox type runs the exact same loop with typed input — useful for testing
the command vocabulary, and it works on any Linux box.
Vocabulary
| Say | Does |
|---|---|
| explore / keep going | auto-explore until something happens |
| north, go east, southwest | move one square |
| run north | travel in a direction |
| attack / fight / kill it | autofight the nearest enemy — no direction needed |
| fire / shoot | autofire your quivered action at the nearest enemy |
| attack east | attack in a specific direction |
| rest / wait | long rest / pass one turn |
| downstairs / travel to the stairs | descend / auto-travel |
| what's around | read the monster list (no turn used) |
| status / where am i | health, magic, statuses, location |
| inventory | read what you're carrying |
| quaff curing / read blinking / wield mace | menu actions by name |
| stop / cancel | interrupt, back out of anything |
| again | repeat the last thing said |
| what should I do | situation summary (needs --llm) |
| skills / spells / learn a spell | open the screen and read the options aloud |
| abilities / my god / character | same, for those screens |
Anything outside the vocabulary is dropped in silence rather than guessed at — with an always-on mic that refusal is the whole safety model.
Optional: the Claude tier
If you already have Claude Code installed, this costs nothing extra — it runs on your existing subscription:
dcssvox play --llm # uses the `claude` CLI if present
Otherwise it can use the API, which is billed separately:
pip install 'dcssvox[llm]'
export ANTHROPIC_API_KEY=...
dcssvox play --llm
dcssvox doctor reports which backend it found.
Everything ordinary still runs on the local grammar — offline, instant, free. Claude (Haiku 4.5) is consulted in exactly three places:
- Long item and spell names. "Borgnjor's Vile Clutch" is what a recogniser mangles and what token matching handles badly. Only fires when local matching is weak or torn.
- Phrases outside the vocabulary. "get me out of here", "chug a heal". With no keyboard, an unparsed command is a dead end, so this is a safety net more than a convenience.
- "what should I do" — two sentences on your situation.
It is grounded and cannot invent: the letter enum is built from the letters crawl just printed, the command enum is built from the local grammar, and its answer is re-parsed by that same grammar before anything is pressed. Every failure — no key, timeout, network drop — falls back to the local grammar rather than wedging the game. Irreversible actions are still confirmed aloud whether you said them or Claude inferred them.
Status
Alpha. The deterministic loop is verified end-to-end against crawl 0.34.1. The whisper.cpp listener and Termux TTS are written but not yet exercised on a real device.
License
MIT
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 dcssvox-0.6.0.tar.gz.
File metadata
- Download URL: dcssvox-0.6.0.tar.gz
- Upload date:
- Size: 43.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7bc13fff9b1725d73a573bf50f79cfc56393d8218af8b402cf7ad267c313693f
|
|
| MD5 |
b41c695e5e85529bbb69933672f302ac
|
|
| BLAKE2b-256 |
9e7e7ae953156ad484fd9d88b3be8a8757c5e7506c6b9065d690f9f98f3acecd
|
File details
Details for the file dcssvox-0.6.0-py3-none-any.whl.
File metadata
- Download URL: dcssvox-0.6.0-py3-none-any.whl
- Upload date:
- Size: 39.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d64d2d9dd821d87938c5b03cd5823b5a50cf6d2a4de63ac59f373dc702888a9c
|
|
| MD5 |
efae72501d9643ce885d130290867b02
|
|
| BLAKE2b-256 |
020008c85a99a504d36f5a6eff67c469a74989ed6cb377ea4a88b4cf7f99e0a9
|