A generic Siren hypermedia browser. Point it at an API and it renders whatever that API offers — properties, sub-entities, links and actions. Follow a link and it fetches it. Press an action and, after confirming, it performs it, then re-reads the document to see what changed. If the work outlives the request, it keeps watching until the server says it is done.
Grep the source of any of the three apps for the name of any particular API and you will not find one. That is the point: a client that never builds a URL cannot contain server-specific code, which is exactly what makes it reusable.
This repository holds three independent implementations of the same browser. They share no code — one is C plus ES5 JavaScript, one is Dart, one is Go — and they are not meant to. What they share is the contract, and every invariant that follows from it.
| Directory | What it is | Toolchain |
|---|---|---|
pebble/ |
The Pebble watchapp, for Pebble Time 2 (emery) and Pebble Round 2 (gabbro). Split across watch and phone: the watch renders frames and reports button presses, PebbleKit JS on the phone does everything else. Also on the Pebble Appstore. | Rebble Pebble SDK 4.9+, just, node, python3 |
flutter/ |
The Android app. One device, so no split — but the same rules, the same confirmation policy and the same refusal to know anything about a server. Also runs on Linux desktop for development. | Flutter 3.41+ / Dart 3.11+, just |
cli/ |
The terminal client: an interactive Bubble Tea TUI and scriptable one-shot subcommands (restforge get, restforge act) in one binary. Same rules again, ported to Go. |
Go 1.26.5+, just |
For what each one does and how to use, build, run and check it, read its own
README and its AGENTS.md:
pebble/README.md— the Pebble watchappflutter/README.md— the Android appcli/README.md— the terminal client
The design all three are held to — the rule everything else follows from, and
the invariants worth protecting — is written down once, in
docs/DESIGN.md; read it before changing any app, because
those are behavioural requirements rather than implementation notes, and they
apply to all three.
Each app has its own Justfile. The root one forwards to them and owns the one
check that has to see all three at once:
just pebble dev # → cd pebble && just dev
just flutter run-linux # → cd flutter && just run-linux
just cli run # → cd cli && just run
just test # all three test suites; none needs an emulator
just check # secret scan (whole tree) + all three apps' code checksjust check must print nothing. It is the check to pay attention to: a leaked
API key, ES5 syntax that only fails on the watch, and server vocabulary that
should not be in a generic client are all mistakes that look fine right up
until they do not.
MIT.