AutoMUD
A persistent telnet/MUD session you drive with small, discrete commands. There is no
language model and no API key inside it: the intelligence is whoever runs it, a person, a
script, or an autonomous agent. It exists because a raw telnet session is interactive and
blocking, so it cannot be held open across separate shell commands. AutoMUD keeps the
connection alive in a small background daemon and exposes simple verbs against it.
Install
pipx install git+https://github.com/CharlesCNorton/automud
Or from a clone:
pip install .
Standard library only, Python 3.8+.
Use
automud sites # list verified public targets
automud connect achaea # by name, or: automud connect <host> <port>
automud send 2 # send a line, print the reply
automud send Maelvorn
automud recv # drain any new output
automud wait --for "You are hungry" # block until output matches a regex
automud state # structured game state (GMCP) as JSON
automud status
automud close
| verb | what it does |
|---|---|
connect HOST PORT / --demo NAME |
open a session and start the daemon (--tls, --encoding ENC, --idle-exit SEC, --debug) |
send [TEXT] |
send one line, print what comes back (omit TEXT for a blank line; --stdin reads the text from stdin) |
recv |
print any new output (--nowait returns whatever is buffered immediately) |
wait --for REGEX / --gmcp PKG |
block until output matches, or a GMCP package updates |
gmcp PACKAGE [JSON] |
send a GMCP message (e.g. Char.Skills.Get) |
state [--key PKG] [--times] |
captured GMCP state as JSON (--times: seconds since each package updated) |
status |
connection, options, vitals summary |
log [--tail N] |
session transcript (last N lines with --tail) |
close |
end the session and stop the daemon |
kill |
force-stop a wedged daemon and clear the session |
sites |
directory of ~45 verified public targets (MUDs, MOOs, BBSes, services) |
Every entry in sites was verified reachable by a live probe. Connect to any of them by
name: automud connect aardwolf, automud connect telehack, automud connect fics.
Every reading verb takes --json and prints one structured object (data, prompt,
connected, elapsed, ...) instead of raw text, which is the natural mode for driving it
from a program. A minimal agent loop is just:
automud connect example.com 4000 --json
automud send look --json # {"ok": true, "data": "...", "prompt": true, ...}
automud wait --for "^You (win|die)" --max 120 --json
Exit codes: 0 ok, 1 failure, 2 usage error, 3 the operation succeeded but the
connection is closed.
Driving it with an agent
There is no agent mode and nothing to configure: an agent drives the same verbs a person does, and everything past that is behavior. One pattern is worth writing down because it falls out of the design. Since the agent holding the session sits between the user and the wire, it can be the user's entire interface to the game and re-voice everything that crosses it: a total conversion of the setting, applied live. The user names the world they want in conversation ("Achaea, but it is Paris on the 14th of July 1789 and I am a hated noble"), and from then on the agent translates both directions, the user's stated intent into real commands and the raw replies into the agreed fiction, mechanics included if the user wants them (vitals re-skinned as a HUD). What keeps it honest:
- The theme is the user's to pick. If they have not said what they want, ask; do not invent on their behalf.
- Translate, do not decide. The user's intent picks the command, and the server's actual reply decides what happened. Failures and deaths render in-fiction, but they render.
- Keep the mapping stable: the same room, denizen, or stat appears under the same converted name every time.
out.logkeeps the untranslated transcript, so the fiction is always auditable against what the server really said.
Local single-player (Cataclysm)
automud connect cdda launches a local game of Cataclysm: Dark Days
Ahead and drives it through the same verbs, so there is a
world to play even with no MUD to connect to, an obligate single-player mode for when
every public server is finally gone. It is a second backend: a persistent tmux session
holds the game open the way the telnet daemon holds a socket, and send / recv /
wait / state / status / close all work against it.
Requirements: tmux and a terminal cataclysm binary. On Windows the game runs in WSL
and automud bridges to it automatically (AUTOMUD_CDDA_DISTRO selects the distro;
AUTOMUD_CDDA_DIR / AUTOMUD_CDDA_BIN / AUTOMUD_CDDA_LAUNCH point at the binary).
automud connect cdda
automud send north # move; the reply is the message log + a status line
automud send examine east # a named action, not the seven keystrokes e-x-a-m-i-n-e
automud send nearby # list items/creatures around you (no map needed)
automud state # the character as JSON: stats, hp, needs, place, threats
automud send help # the action vocabulary for the current screen
The map is obscured on purpose. A blurry ASCII minimap is neither reliable for a
language model to parse nor necessary to one that reads a room description, so game-mode
output is the message log plus a structured status line (vitals, place, time, nearby
threats), never the tilemap. Ask for spatial detail when you want it: send look,
send examine <dir>, send nearby.
Actions, not raw keys. send understands word directions (north, se), named
keys (enter, escape), and named game actions (examine, wield, wear, ...) that
map to the right key. pickup [NAME], eat [NAME], sleep [HOURS] and wait <SPEC>
drive their whole multi-prompt flow to completion rather than just opening the menu, and
report what happened. An unrecognized word is reported, not typed out letter by letter;
single characters are still sent literally, so raw CDDA keys work too.
Character creation is one line per choice. send newgame drives the whole
pre-chargen main menu (a maze with no readable cursor where New Game and World look
identical) to the character-creation screen, and each choice is its own verb:
automud send newgame # main menu -> character creation
automud send options profession # list every choice on a tab (they scroll)
automud send scenario Sheltered
automud send profession "Sheltered Survivor" # or: send class ...
automud send stats 8 10 10 10 # STR DEX INT PER; reports the real values
automud send trait Fleet-Footed
automud send name Dougal
automud send finalize
Each reports what it actually committed (and refuses a locked or mismatched entry rather
than silently selecting the wrong one), and in chargen state returns the build so far
(scenario, profession, stats, name). Since the option lists are long and scroll off
screen (roughly 60 scenarios, 175 professions, 120 backgrounds, 200 traits), send options [TAB] enumerates every choice on a tab so nothing is hidden below the fold. The missing-mod prompts a fresh world throws are
cleared automatically.
Behaviour
- Smart waiting.
sendandrecvreturn as soon as the server stops talking, either a telnet GA/EOR prompt marker or output going quiet, so you never guess a sleep duration.--maxcaps the wait and--quietsets the idle threshold.waitextends this to regex/GMCP conditions. - GMCP. It negotiates GMCP and parses the structured state modern MUDs push (health,
room, exits, skills) into JSON for
state. Standard list deltas (Room.AddPlayer,Char.Afflictions.Add, ...) are applied to their lists, andComm.Channel.Textis kept as a boundedComm.Channel.History. TTYPE, NAWS and CHARSET negotiation are answered; options it does not implement (compression, MSDP, MXP) are refused rather than mishandled. - Encodings and TLS.
--encodingsets the wire charset (defaultutf-8; uselatin-1orcp437for older servers), and telnet CHARSET negotiation can switch it when the server asks.--tlswraps the connection (--tls-insecurefor self-signed certificates). - One session per name, held by a background daemon; a new
connectreplaces it, and-s NAMEgives you independent parallel sessions. Session state and transcripts live under a per-user state directory (override withAUTOMUD_DIR); the previous session's transcript is kept asout.prev.log. - Robust lifecycle. TCP keepalive is enabled, a dead daemon is detected by pid and its
stale session cleared, concurrent connects are serialized by a lock, a wedged daemon is
force-killed on reconnect (or by
kill), and--idle-exitstops a forgotten daemon.
Security
The control channel is a localhost-only socket authenticated by a per-session random
token. State lives in a per-user directory ($XDG_RUNTIME_DIR/automud, else
<tempdir>/automud-<uid> on POSIX, %TEMP%\automud on Windows) that is created 0700
and refused if another user owns it. Prefer automud send --stdin for passwords: argv is
visible to other local processes, and shell history persists. Plain telnet is cleartext;
use --tls where the server offers it.
Tests
python -m unittest discover -s tests -t .
License
MIT. See LICENSE.
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 automud-0.3.7.tar.gz.
File metadata
- Download URL: automud-0.3.7.tar.gz
- Upload date:
- Size: 59.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e039065979ba3d68d006dd33157672dfce4a694ed0420c5cd81c39c73659827a
|
|
| MD5 |
267119c01dc2d608b23ac2891e97af86
|
|
| BLAKE2b-256 |
7421a9531a5128f53203430d1c489185a2df2078bd6fea43a5ccba6cd20a256b
|
Provenance
The following attestation bundles were made for automud-0.3.7.tar.gz:
Publisher:
publish.yml on CharlesCNorton/automud
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
automud-0.3.7.tar.gz -
Subject digest:
e039065979ba3d68d006dd33157672dfce4a694ed0420c5cd81c39c73659827a - Sigstore transparency entry: 2103480112
- Sigstore integration time:
-
Permalink:
CharlesCNorton/automud@aa9c5720a2af2b36152951d66f43a8d14b4be23e -
Branch / Tag:
refs/tags/v0.3.7 - Owner: https://github.com/CharlesCNorton
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@aa9c5720a2af2b36152951d66f43a8d14b4be23e -
Trigger Event:
release
-
Statement type:
File details
Details for the file automud-0.3.7-py3-none-any.whl.
File metadata
- Download URL: automud-0.3.7-py3-none-any.whl
- Upload date:
- Size: 51.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
264d284f558cb6e71a23a801bdda42a5e0544d8af9f714785f215af7a2278561
|
|
| MD5 |
cc75a96c636a41f31466e52d14918c86
|
|
| BLAKE2b-256 |
1829afeb7e9c23b17611eca779f1121903df5e1ca1dbc9563e2ec4b72db35e52
|
Provenance
The following attestation bundles were made for automud-0.3.7-py3-none-any.whl:
Publisher:
publish.yml on CharlesCNorton/automud
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
automud-0.3.7-py3-none-any.whl -
Subject digest:
264d284f558cb6e71a23a801bdda42a5e0544d8af9f714785f215af7a2278561 - Sigstore transparency entry: 2103480675
- Sigstore integration time:
-
Permalink:
CharlesCNorton/automud@aa9c5720a2af2b36152951d66f43a8d14b4be23e -
Branch / Tag:
refs/tags/v0.3.7 - Owner: https://github.com/CharlesCNorton
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@aa9c5720a2af2b36152951d66f43a8d14b4be23e -
Trigger Event:
release
-
Statement type: