This is the experimental path for running Tele-Arena as a standalone telnet
target and driving it with Spree's bbs-door-line profile. It does not use
Synchronet. Ether serves the game directly on telnet port 3000.
The important harness detail is line endings: Ether accepts LF for Enter. Keep
--telnet-enter lf when using bbs-gym against Ether. The default remains CR
because that is what the Synchronet/TW2 path currently expects.
- Tested with Tele-Arena 5.6d data converted by AreaBuilder.
- Tested with the Ether Java telnet server on
127.0.0.1:3000. - Tested with Codex and Claude CLI via
examples/tele_arena_activity.py. - Ether runtime fixes are maintained outside this repo in https://github.com/rwightman/ether-arena.
- Game data, Ether archives, generated data, player files, and logs belong
under ignored
runtime/tele-arena/.
This repo does not ship Tele-Arena, Ether, converted data, player files, or
registration material. Use files you are allowed to run. Ether's own install
notes state that Ether does not include the copyrighted Tele-Arena data files.
For Java/runtime fixes, use the ether-arena fork.
- Ether fork with local runtime fixes: https://github.com/rwightman/ether-arena
- Original Ether runtime: https://sourceforge.net/projects/jether/files/ether1.00b56.zip/download
- Original Ether source: https://sourceforge.net/projects/jether/files/src/ether_src1.00b53.zip/download
- Ether/AreaBuilder install notes: https://tdod.org/ether/install.html
- Tele-Arena module page: https://www.mbbsemu.com/Module/TSGARN
- Tele-Arena wiki notes: https://wiki.mbbsemu.com/doku.php?id=modules%3Atsgarn
sudo apt install unzip ant default-jdkThe original Ether tooling was built for old Java. For Java 21, use the
ether-arena fork. It carries the Java/runtime fixes separately from Spree's
terminal-agent harness code.
Create the ignored workspace:
mkdir -p runtime/tele-arena/downloadsDownload or place these archives there:
runtime/tele-arena/downloads/ether1.00b56.zip
runtime/tele-arena/downloads/AreaBuilder1.00b1.zip
runtime/tele-arena/downloads/TSGARN_MBBSEmu.zip
TSGARN_MBBSEmu.zip is one convenient source for the .MSG files AreaBuilder
needs. The original installer can also work if you extract the same message
files yourself.
mkdir -p runtime/tele-arena/ether \
runtime/tele-arena/area-builder
unzip -q runtime/tele-arena/downloads/ether1.00b56.zip \
-d runtime/tele-arena/ether
unzip -q runtime/tele-arena/downloads/AreaBuilder1.00b1.zip \
-d runtime/tele-arena/area-builderFor the patched Java source tree, clone the fork under ignored runtime storage:
git clone https://github.com/rwightman/ether-arena.git \
runtime/tele-arena/ether-arenaThe resulting paths should include:
runtime/tele-arena/ether/ether/
runtime/tele-arena/ether-arena/
runtime/tele-arena/area-builder/AreaBuilder/
AreaBuilder expects these six files in its data/ directory:
TSGARN-C.MSG
TSGARN-D.MSG
TSGARN-M.MSG
TSGARN-T.MSG
TSGARNDD.MSG
TSGARNDT.MSG
For the MBBSEmu-ready archive, extract them with:
mkdir -p runtime/tele-arena/area-builder/AreaBuilder/data
unzip -j runtime/tele-arena/downloads/TSGARN_MBBSEmu.zip \
'TSGARN*.MSG' \
-d runtime/tele-arena/area-builder/AreaBuilder/dataConfirm:
ls runtime/tele-arena/area-builder/AreaBuilder/data/TSGARN*.MSGRun AreaBuilder from its own directory:
cd runtime/tele-arena/area-builder/AreaBuilder
java \
--add-opens java.base/java.util=ALL-UNNAMED \
--add-opens java.base/java.text=ALL-UNNAMED \
--add-opens java.desktop/java.awt.font=ALL-UNNAMED \
-DTaConfigFile=config/ta.properties \
-jar AreaBuilder.jarThe generated files land in build/. A successful local conversion produced
town.xml, world1.xml, room descriptions, item/mob/spell data, help data,
and tamessages.properties.
From the repository root:
ETHER_HOME=runtime/tele-arena/ether-arena
cp runtime/tele-arena/area-builder/AreaBuilder/build/town.xml \
runtime/tele-arena/area-builder/AreaBuilder/build/world1.xml \
runtime/tele-arena/area-builder/AreaBuilder/build/town_room_desc.xml \
runtime/tele-arena/area-builder/AreaBuilder/build/world_room_desc.xml \
"$ETHER_HOME/area/"
cp runtime/tele-arena/area-builder/AreaBuilder/build/armor.dat \
runtime/tele-arena/area-builder/AreaBuilder/build/barriers.dat \
runtime/tele-arena/area-builder/AreaBuilder/build/cmd_triggers.xml \
runtime/tele-arena/area-builder/AreaBuilder/build/emotes.dat \
runtime/tele-arena/area-builder/AreaBuilder/build/equipment.dat \
runtime/tele-arena/area-builder/AreaBuilder/build/help.dat \
runtime/tele-arena/area-builder/AreaBuilder/build/mob_weapons.dat \
runtime/tele-arena/area-builder/AreaBuilder/build/mobs.dat \
runtime/tele-arena/area-builder/AreaBuilder/build/npcs.dat \
runtime/tele-arena/area-builder/AreaBuilder/build/spells.dat \
runtime/tele-arena/area-builder/AreaBuilder/build/tamessages.properties \
runtime/tele-arena/area-builder/AreaBuilder/build/teleporters.dat \
runtime/tele-arena/area-builder/AreaBuilder/build/traps.dat \
runtime/tele-arena/area-builder/AreaBuilder/build/treasures.dat \
runtime/tele-arena/area-builder/AreaBuilder/build/weapons.dat \
"$ETHER_HOME/data/"Set ETHER_HOME=runtime/tele-arena/ether/ether instead if you intentionally
want to run the original unpacked runtime.
cd runtime/tele-arena/ether-arena
ant jar
java -DTaConfigFile=config/ta.properties -jar ether.jarExpected startup includes:
PortListener ;Listening to Port 3,000
Genesis ;Server up
If the original Ether jar fails on a modern JDK with XStream or reflection
errors, use the ether-arena fork above.
In another shell:
telnet 127.0.0.1 3000You should see:
Welcome to the Java port of Tele-Arena 5.6d!
Enter your character's name or type NEW:
From the repository root:
uv run python examples/tele_arena_activity.py \
--activity bbs-door-line \
--provider codex \
--model gpt-5.5 \
--max-decision-ticks 100The wrapper delegates to:
uv run bbs-gym run-activity \
--host 127.0.0.1 \
--port 3000 \
--transport telnet \
--telnet-enter lf \
--activity bbs-door-line \
--provider codex \
--model gpt-5.5bbs-door-line is the preferred Tele-Arena profile. It allows submit_line
for complete line-oriented commands while keeping type_text and press_key
available for prompts that behave like single-key BBS inputs. Use
bbs-door-safe when testing a door that auto-accepts values before Enter, such
as the TW2 JavaScript door.
Claude Code can run through the same wrapper in stateful mode:
uv run python examples/tele_arena_activity.py \
--activity bbs-door-line \
--provider claude \
--model sonnet \
--agent-id tele-arena-claude \
--claude-stateful \
--claude-session-file runtime/claude-sessions/tele-arena-claude.session \
--max-decision-ticks 100The trace defaults to:
runtime/logs/tele-arena-codex-bbs-door-line-lf.jsonl
Pretty-print it with:
python scripts/trace_pretty.py \
runtime/logs/tele-arena-codex-bbs-door-line-lf.jsonl \
--show-new-text \
--out runtime/logs/tele-arena-codex-bbs-door-line-lf.pretty.txtThe first successful Codex run created ArenaCodex, completed character
creation, entered the north plaza, used HELP, STATUS, INVENTORY, EXITS,
and LOOK, navigated to the equipment shop, bought a torch/waterskin/food,
visited the guild hall, returned to the plaza, and hung up cleanly at step 100.
A stateful Claude run with bbs-door-line created ArenaLine, completed
character creation, bought starter supplies, entered the arena, fought a giant
bat, died, recovered in the temple, and continued until the 100-step budget.
The same run used submit_line for most complete commands and had no action
validation failures.
run-match opens one telnet session per participant. The default sequential
scheduler alternates one decision tick per active agent. parallel_barrier
collects decisions concurrently and commits them in the scheduled order;
parallel_race commits actions as model decisions finish. continuous keeps
one decision in flight per active agent and immediately requeues that agent
after each committed action, so faster models get more chances to act during the
same match wall-clock budget. Inline participant specs use
agent_id:provider:model; each participant still gets its own per-agent JSONL
trace and model state.
uv run bbs-gym run-match \
--host 127.0.0.1 \
--port 3000 \
--transport telnet \
--telnet-enter lf \
--no-agents-config \
--activity bbs-door-line \
--participant arena-codex:codex:gpt-5.5 \
--participant arena-claude:claude:sonnet \
--codex-stateful \
--claude-stateful \
--prompt-layout cache_friendly \
--log-path runtime/logs/tele-arena-match.jsonl \
--disable-action hangup \
--run-objective "Play Tele-Arena as {agent_id}. If asked for a character name, create or log in as {agent_id}. Stay connected; do not hang up or quit. Other active agents: {opponents}. Survive, gain experience and gold, buy and equip useful supplies, spend gold wisely, recover when hurt, find opponents, and defeat them when prepared." \
--max-rounds 100 \
--max-decision-ticks 100The match trace goes to runtime/logs/tele-arena-match.jsonl. Per-agent traces
use the same stem, for example tele-arena-match.arena-codex.jsonl and
tele-arena-match.arena-claude.jsonl.
For match runs, --max-wall-seconds is match-level. --max-decision-ticks
still applies per participant. In continuous mode, --max-rounds caps the
total queued action decisions for the whole match rather than full all-agent
rounds. Continuous traces use tick instead of round for scheduler events and
do not emit round_started / round_completed lifecycle events.
- Use
--telnet-enter lffor Ether. CR-only caused repeated delayed submits. bbs-door-lineis the right starting profile for Tele-Arena because most gameplay commands are typed lines that expect Enter.bbs-door-safeis still useful for doors that often auto-accept typed values before Enter.- The wrapper is intentionally thin; pass any extra
bbs-gym run-activityarguments after the wrapper arguments and they will be forwarded. - Match-specific objectives should carry game strategy. Add
--disable-action hangupfor competitive runs so agents cannot leave the match with the harness-level hangup action.