Speediance CLI
Drive a smart home-gym from the command line.
the project
Speediance CLI talks to a Speediance “Gym Monster”smart cable machine from the command line: read your completed workouts, create training programs, and get it all back as JSON. It's built to be driven by an agent — the home gym as something a script can read from and write to.
Like its siblings, it ships as a single static Go binary and an OpenClaw / ClawHub skill plugin, MIT-licensed.
the hard problems
- An unofficial, undocumented API.There's no public SDK — the tool wraps Speediance's cloud API by replicating exactly what the mobile app sends: frozen request headers (a spoofed Dart user-agent, version / timezone / timestamp fields) and the
{ code, message, data }response envelope. Every call is isolated in oneinternal/apipackage, and the spec documents each header and endpoint byte-for-byte so an app update that breaks something is easy to spot and patch. - Dual-namespace session resolution. A training session can live in two independent namespaces (a structured program vs. a free-lift), and the integer IDs can collide across them — the same number can mean two unrelated sessions. The tool auto-dispatches to the right namespace and reports which via a
kindfield, with--program/--freeflags to disambiguate when needed. - A backward-compatible rewrite. This is a Go replacement for an earlier Python tool, and existing agents (plus the published skill) already parse its
--jsonoutput. So the contract is frozen: golden-file tests assert push payloads are byte-identical to the Python version, and schema-parity tests cover every--jsoncommand. A rewrite that quietly changed the output would break every downstream consumer. - Tokens that don't leak across machines. Session tokens are cached at
0600in the non-roamingOS cache dir (so a live credential doesn't sync between machines or into the working-dir repos the tool runs in), with one-shot migration forward from a legacy token path.
lessons learned
No “doctor” command — diagnostics through parity. Instead of a vague health-check that bundles state, the tool fails fast with actionable errors and leans on version, config show, config path, and loginto surface exactly what's wrong. The deeper rule, shared across the CLI family in a common CLI_CONVENTIONS.md: an agent-facing tool owns no downstream data layout and freezes its output contract — which means versioning and tests do the heavy lifting, because a silent schema drift is the one failure an agent can't recover from on its own.
what this demonstrates
- Hardware / IoT integration against an unofficial API, with the wire format pinned down and isolated so upstream drift is contained.
- Contract discipline. Golden-file and schema-parity tests treat the output as an API that other software depends on — because it is.
- Part of a coherent toolset. Shared conventions with
google-health-cliandloseit-cli— credential handling, cache locations, migration — so the family behaves predictably.