Phones + computers + tokens — the 10-minute founder test · content/testkit.md
Testkit — the founder's 10-minute multi-device walkthrough
Mission: "test messaging systems on different computers and phones with a number of tokens."
One command sets up a party (or three), funds it with paper-mode test cents (paper-phase QALS, not real money), and prints a READY CARD with everything each device needs:
bash scripts/testkit.sh <party-name> [cents] # one party, default 2000c = AU$20
bash scripts/testkit.sh --demo # alice + bob + carol, live traffic, test script
Idempotent — re-run any time. Existing identities are kept (keys are just republished to both relays); the topup adds more tokens.
The 3-device map
| Device | Role | Talks to |
|---|---|---|
| 📱 Redmi phone | bridge web UI (reads/sends as mcp-bot) |
http://100.73.134.20:8837 (superlocal, tailscale-only) |
| 🖥 superlocal (this machine) | identities, wallet, CLI, loopd money | local relay 127.0.0.1:8830, loopd 127.0.0.1:8823 |
💻 cachyos-x8664 (100.111.199.12) |
2nd computer, fresh identity | fleet relay http://100.111.199.12:8840 |
Relay truth: superlocal's relay binds loopback — the fleet relay on cachyos-x8664 is the only cross-machine post office. The demo deliberately sends fleet-first to prove the cross-device path.
0:00 — set the board (superlocal)
bash scripts/testkit.sh --demo
What you see: alice/bob/carol funded (+2000c each), then live proof:
sent #N → bob via http://100.111.199.12:8840— envelope landed on the fleet relay[alice → me] #N testkit: alice→bob via fleet relay ✔— bob decrypted ittransfer ok: r_xxxxxxxx 500c (5.00 B-QALS) → bob+PAYMENT PROOF:line- balances moved −500/+500, and
conversation anchored(Merkle root → Qalnet object)
Then three READY CARDS: handle, qoll-code (qoll-xxxx-xx), balance, QR.
2:00 — the Redmi phone
- Tailscale ON on the phone.
- Scan the alice card's QR (or type the URL): the format is
http://100.73.134.20:8837/phone?t=<token>
The token is the one file: qalbridge/data/.token on superlocal. First hit
mints a cookie and strips ?t= from the address bar — then bookmark the
clean URL.
3. Chats ▸ alice — the seeded line ("founder — reply to alice from the
Redmi 📱") is already there. Type a reply.
Success: on superlocal,
python3 qalchat/qalchat.py recv --as alice prints
[mcp-bot → me] #… hello from the Redmi.
4:00 — desktop on superlocal
# the CLI chat (or cargo tauri dev in wallet-app/src-tauri for the wallet UI)
python3 qalchat/qalchat.py chat bob --as alice \
--relays "http://127.0.0.1:8830,http://100.111.199.12:8840"
# type two lines, watch bob's card on the phone afterwards (Chats ▸ bob)
python3 qalchat/qalchat.py pay bob 250 "latte" --as alice # ⚡ 2.50 B-QALS
Success: the phone transcript shows your lines and a gold ⚡ payment
card with the amount; the CLI printed
transfer ok: r_xxxx 250c (2.50 B-QALS) → bob.
6:00 — the second computer (cachyos-x8664, relay #2 read path)
Follow any card's ANOTHER COMPUTER block — identities are per-device by design (new keys there), messaging is handle→handle:
rsync -a [email protected]:projects/GLM_projects/crypto_currency/ ./crypto_currency/
cd crypto_currency
python3 qalchat/qalchat.py init alice-2nd --relays http://100.111.199.12:8840
python3 qalchat/qalchat.py recv --as alice-2nd --relays http://100.111.199.12:8840
python3 qalchat/qalchat.py send alice "hello from cachyos" --as alice-2nd \
--relays http://100.111.199.12:8840
Success: back on superlocal, recv --as alice shows the cachyos line.
Note: loopd (payments) is loopback on superlocal — money moves from the
desktop/phone side; the 2nd machine chats.
8:00 — money trail + conversation anchor
curl -s http://127.0.0.1:8823/receipts | python3 -m json.tool | tail -20 # transfer receipts
python3 qalchat/qalchat.py anchor bob --as alice # Merkle root → Qalnet, prints tx/object id
python3 qalchat/qalchat.py verify-convo bob --as alice
Troubleshooting
| Symptom | Fix |
|---|---|
| Fleet relay curl hangs / times out | DERP flap — warm the tunnel: tailscale ping cachyos-x8664 until it reports a direct/pong path, then retry. First packet after idle often rides DERP. |
| Phone shows 401 / empty page | Token mismatch — read cat qalbridge/data/.token on superlocal, re-open http://100.73.134.20:8837/phone?t=<that>. (The systemd unit's QALBRIDGE_TOKEN must match this file.) |
| Phone URL doesn't resolve at all | Tailscale down on the phone, or bridge down: systemctl --user start qal-bridge (health: curl 127.0.0.1:8837/health). |
could not publish pubkey on a relay |
Re-run the testkit line for that party — it republishes keys to both relays. |
recv: … rejected / chain gap |
Envelopes expire after 24 h on the relay. If a device skipped mail, just send fresh messages via testkit — old gaps are past TTL. |
| Payment refuses from the 2nd computer | Expected — loopd is superlocal-local. Pay from the desktop card's line. |
program cap reached on topup |
The Phase-0 finite-supply cap (the issuer wallet running out) — that's policy, not a bug. |
What testkit touches (and never touches)
Reads: loopd/data/.admin_key (X-Admin on /topup only), qalbridge/data/.token.
Writes: new identity under qalchat/data/identities/, loopd balances.
Never edits service code, unit files, or relay state.