| name | ssh-wars |
|---|---|
| description | Play SSH Wars when a user asks to connect to sshwars.com, trade products, take turns, inspect the market, travel, or manage an SSH Wars account. Requires a Herdr-managed session so the user can continuously watch the actual in-game TUI. |
| compatibility | HERDR_ENV=1, herdr CLI, SSH access to sshwars.com. |
Use this skill for all SSH Wars gameplay. The user must be able to follow the actual game state in a right-hand Herdr pane throughout play.
- MUST play in the actual SSH Wars terminal UI, in a visible sibling pane on the right of the caller's current Herdr pane.
- MUST NOT replace the game screen with JSON, a shell dashboard, a text summary, or a wrapper while the session is active.
- MUST NOT use SSH Wars non-PTY/
--jsongameplay commands to buy, sell, travel, or otherwise alter game state. They are machine interfaces and are not readable gameplay for the user. - MUST leave the game TUI open in the right pane after every action.
- MUST narrate decisions briefly in chat, but narration supplements the TUI; it never replaces it.
- MUST NOT create a second account, claim a city, choose a handle, or complete another irreversible onboarding step unless the user expressly asks to do so or has already directed gameplay that necessarily requires it.
The best loop is NOT raw keystroke/send-read pairs typed by hand, and NOT a pexpect process owning the game. It is:
- The real game TUI runs in the visible right pane via
herdr pane run <pane-id> "ssh -tt -i <identity-key> sshwars.com". - A persistent Python kernel (or any script) drives it by shelling out to the herdr CLI. This keeps the game user-visible while giving the agent programmatic control, settle detection, and pattern waits.
Core helpers (define once in the kernel):
import subprocess, time, re
PANE = "wDA:p3" # the visible game pane id
def _run(args):
return subprocess.run(["herdr", "pane", *args],
capture_output=True, text=True, timeout=10).stdout
def read_pane(lines=60):
return _run(["read", PANE, "--source", "visible", "--lines", str(lines)])
def send_keys(k): # named keys ONLY: enter, esc, up, down, left, right, ...
subprocess.run(["herdr", "pane", "send-keys", PANE, k], capture_output=True)
def send_text(t): # literal text into text fields (handles, quantities, search)
subprocess.run(["herdr", "pane", "send-text", PANE, t], capture_output=True)
def frame_stable(timeout=8.0, interval=0.35):
"""Poll the visible pane until two consecutive reads are identical."""
prev, t0 = None, time.time()
while time.time() - t0 < timeout:
cur = read_pane()
if cur == prev and cur.strip():
return cur
prev, _ = cur, time.sleep(interval)
return prev or read_pane()
def act(*keys, settle=6.0):
"""Send named keys, wait for the frame to settle, return it."""
for k in keys:
send_keys(k); time.sleep(0.15)
return frame_stable(settle)
def wait_for(pat, timeout=10.0):
"""Poll the pane until regex pat appears in the visible frame."""
t0 = time.time()
while time.time() - t0 < timeout:
f = read_pane()
if re.search(pat, f):
return f
time.sleep(0.3)
return NoneWhy this beats alternatives:
herdr pane send-keysaccepts key NAMES only (enter,esc,up, …); arbitrary text fails withinvalid_key. Useherdr pane send-textfor text fields. Wrap both.- The server redraws asynchronously (news ticker, animations). Sleeping a fixed time between send and read is flaky; two-consecutive-identical-reads settle detection is reliable.
- pexpect only helps when the game runs outside a visible pane, which this skill forbids. Driving herdr from Python gives the same precision with the TUI still user-visible.
- SSH Wars identifies accounts by SSH public key. Keep ONE dedicated key per
account:
~/.ssh/sshwars_<handle>(generate withssh-keygen -t ed25519), connect with-i ~/.ssh/sshwars_<handle> -o IdentitiesOnly=yes. - Reconnecting with the same key resumes the account (cash, cargo, Heat, Actions, city all persist).
- If reconnect opens onboarding despite an existing account, the wrong key is in use — stop before claiming anything and tell the user.
- Confirm Herdr:
test "${HERDR_ENV:-}" = 1. herdr pane split --current --direction right --cwd "$PWD" --no-focus(or reuse an existing idle game pane).herdr pane run <pane-id> "ssh -tt -i <key> -o IdentitiesOnly=yes sshwars.com"- Each connection begins with a ~4s NIGHTWIRE animation; send any key to
skip it. The first post-login frame can show a blank/loading state
(
WORKING..., empty player fields) — poll withframe_stable()until the real status bar appears (regexACTIONS \d). - Fetch the server's machine-readable mechanics doc once per account (this
is read-only and sanctioned):
ssh -i <key> sshwars.com skill - The server asks agents to identify honestly: set the profile identity to AGENT (Profile → identity metadata).
- Read the current visible frame before every consequential move.
- One decision narrated in chat, one visible keystroke, then re-read.
- Report human outcomes: product, quantity, price, cash, cargo, Actions, Heat, city.
- For "play N turns" requests, perform N distinct completed in-game actions with the TUI visible for all of them.
- Prefer sensible play unless the user explicitly requests otherwise (e.g. "play unhinged"): preserve travel Actions, account for seller tax, avoid unnecessary Heat.
- Actions: max 120, +5/hour recovery (offline included). Buy/sell = 1, travel = 3, deploy cops = 2, tax change = 2. Views are free.
- Travel incident chance: 12% + Heat/2, cap 55%. Deterministic per journey.
- Heat: +1 per trade (+up to 5 more for size), −2/hour decay.
- City controller taxes visitor sales (0–100%); 70% of tax to controller, 30% to job treasury. Controllers untaxed at home.
- Crooked Cops tiers at 10/50/150/500 deployed: Heat −1/−2/−3/−5 and safehouse bonuses. Deploy only in your controlled home city.
- Safehouse: entering removes 10 Heat; 35% faster Action recovery.
- Chicago has blackjack (
CthenB); Vegas/NYC paid venues. - Rename costs $1,000 / $2,500 / $250,000 (max 3).
- Invite codes: invitee +$5,000, inviter +$10,000 per signup.
- Leave the TUI open while the user may be watching or directing play.
- Never close a user-owned pane. A pane created for SSH Wars may be closed only at the user's request or after the user says the session is finished.
- If the game pane is unrecoverably stuck, explain, close only that pane, create a new right sibling, and reconnect visibly.