A setup wizard you can finish with the keyboard, on one box, without a toast to chase
Four problems in the wizard on origin/main. (1) Service cards in step 2 are <div data-action="toggleWizardService"> with no tabindex or role (app.js:3078), so Tab skips them: a keyboard user cannot pick a service at all. (2) Each service's "Deploy to" box starts unticked even when only one box exists (app.js:1798-1800); pressing Deploy only says "Select at least one worker node" in a toast (app.js:3325-3329). The summary then blames a missing online worker (app.js:2959-2961), which was not the cause. (3) Credentials that already run the service have to be typed again under Settings → Collectors to see a balance (app.js:3163-3170). (4) The preflight warning is a native window.confirm (app.js:3319-3321), and results and "kept settings" notes are toasts that disappear (app.js:3395-3401).
Pick and deploy Honeygain on a one-box installToday: 1 category click + Next, 1 card click + Next, 2 fields, then Deploy fails until you notice and tick the box, then Deploy again: 7 clicks, 2 fields. Keyboard only: cannot be done (step 2 is unreachable). After: 5 keys + 2 fields (SpaceEnter · arrows, Space, Enter · type · Ctrl+Enter).
See the balance of what you just deployedToday: after deploying, Settings → Collectors → the service → type the same email and password again (3 clicks, 2 fields, a second page). After: 0 extra steps: one ticked-by-default checkbox reuses them, and the read is checked before you leave.
Find out why a deploy failedToday: a toast for a few seconds, then a summary that says "check the Fleet page" for every cause (1 page change + guessing). After: the cause stays on the card, with Open Fleet, Copy logs command and Retry.
BEFORE
Today: no keyboard path in step 2, unticked box, wrong cause in the summary
v2.1.1 screenshots, fake data
A
BC
D
AStep 2: cards are plain divs. Tab goes from the step header straight to Back and Next; Next then says "Select at least one service".
BStep 3 on a one-box install: local is listed as Available but unticked, so Deploy does nothing useful.
CThe only feedback is a toast in the corner (app.js:3327) and a short line beside the button. Credentials are asked for once here and again in Settings for the balance.
DSummary: "None of the selected services could be deployed … check the Fleet page for a worker that is online". The worker was online; the box was simply not ticked.
AFTER
Step 2: real checkbox cards, arrow keys, a sticky footer
1440 × 900 · focus on IPRoyal Pawns, moved there with ↓→
Bandwidth · 18 services. Grade and estimate come from the catalog's ratings; estimates are per box per month on a home connection.
Selected: 3Honeygain, EarnApp, IPRoyal Pawns · ~$5–12/mo per box3
1The grid is a role="group" of real <label><input type="checkbox"> cards. Screen readers announce "IPRoyal Pawns, checkbox, checked"; one Tab stop enters the grid (roving tabindex), arrows move inside it.
2The focused card has the theme's focus ring (cyan in Classic night, the existing :focus-visible colour), distinct from the pink "selected" border, so focus and selection never look alike.
3A sticky footer keeps the count, the names and Next on screen however long the grid is. Next is disabled with the reason ("Pick at least one service") instead of a toast after the click.
1"Runs behind a proxy" marks services that can run extra copies through an egress; "Stateful" marks ones whose identity lives on disk. Both come from the catalog (services/_schema.yml), not hand-written labels.
Tab into the grid←→↑↓ move between cardsSpace tick / untickEnter Next/ filter the grid by nameEsc Back
AFTER
Step 3: one "Deploy to" for everything, credentials once, warnings inline
1440 × 900 · one-box install, so box-a is ticked for you
Deploy to:Ticked for you: it is the only box that fits these 3 services. Add another box4
Honeygain needs your Honeygain account
EarnApp a device id that links this box to your account
After deploy, CashPilot opens EarnApp's link page for this id and keeps checking until it is on your account.
IPRoyal Pawns email and password
This may not earn on box-a. box-a already runs Pawns for another account on the same public IP; IPRoyal may close one of the two accounts and keep its balance.6
3 services → box-a1 warning to answer7
4One target for the whole step, not a checkbox per service. Auto-ticked when exactly one online box fits every chosen service; with several boxes nothing is pre-ticked and Deploy is disabled with "Pick a box". Boxes that are offline show dashed with the reason.
5Credentials once. The catalog maps a deploy field to a collector field (collector.fields in services/_schema.yml); the box is ticked by default and the read runs as you leave the field, so a typo shows here, not a day later in the bell.
6The preflight finding (app.js:3305-3321) is a warning in the card with two buttons, not a window.confirm. Deploy all stays enabled: pressed before the warning is answered, it deploys the other two and holds Pawns back, and the footer says so.
7Ctrl/⌘+Enter deploys from any field in the step. Copy as CLI (wave 3, L5) gives the same deploy for a terminal or an agent (see the last frame).
AFTER
Step 3 during and after Deploy: progress on each card, then a result that stays
two-box install, both ticked; box-b went offline at 10:02
Deploy to:
Honeygain 8
box-a · pulling 34 / 80 MB
pulling → creating → starting → first heartbeat
box-b · waiting
EarnApp
✓ Running on box-a · started 14:03:12 · image 2.4.1
× box-b: worker offline since 10:02. Nothing was sent to it.
IPRoyal Pawns
✓ Running on box-a · deployed after your "Deploy anyway"
Kept from the previous deployment on box-a: device name pawns-a. Why
× box-b: worker offline since 10:02
8Progress is streamed from the worker (pull bytes, create, start, first heartbeat), one line per box. Today the card shows "Deploying" with a spinner until one request per box returns (app.js:3336-3393).
8Results stay on the card until you leave the step. A failure names the cause and offers the three ways forward. "Copy logs command" copies docker logs --tail 100 cashpilot-earnapp for the box, for when the worker is up but the container is not.
AFTER
Summary: the real cause per service, and the next useful step
1Categories
2Services
3Set up and deploy
4Summary
Partly deployed: 3 of 6 copies running
Everything that failed failed for one reason: box-b is offline. Start its worker and press Retry on each, or deploy them later from the catalog.
9Have proxies? Run extra copies. Honeygain and IPRoyal Pawns can run more copies, each through its own proxy or VPN exit, for more income from the same box.
9The step after a success is where people ask "can I earn more?", so the egress entry point sits here, only for services the catalog marks as proxy-capable.
DReplaces the single sentence at app.js:2959-2969: the cause comes from each deploy's own result, never a guess.
× Could not load the catalog: the server answered 502.
Your picks from step 1 are kept.
Step 3 · no box
Deploy to:No box is reporting. Deploy is off until one is.
"Save choices for later" keeps the fields.
CLI · AGENT
Copy as CLI (wave 3): the same deploy from a terminal
proposed; secrets go through a file or stdin, never argv
terminal
$ cashpilot service deploy honeygain earnapp pawns --box box-a --env-file ./earners.env --collector-from-env
preflight pawns@box-a warn same public IP already runs pawns for another account (--accept pawns to deploy anyway)exit 5: answer the warning or drop pawns$ cashpilot service deploy honeygain earnapp pawns --box box-a --env-file ./earners.env --collector-from-env --accept pawns --json
{"results":[{"service":"honeygain","box":"box-a","status":"running","balance":{"read":true,"value":4.12,"currency":"USD"}},
{"service":"earnapp","box":"box-a","status":"running","device_link":{"pending":true,"url":"https://earnapp.com/r/sdk-node-4a9d…7e65"}},
{"service":"pawns","box":"box-a","status":"running","kept_from_previous_deployment":["device name"]}],
"failed":[]}