The Whole UI Is a Hashtag

The Whole UI Is a Hashtag

Pedal Wrencher has a web dashboard with gauges and buttons, and I put real effort into it. Its most useful interface is none of that. It’s a hashtag.

When you replace your chain, you add #pwchain to the title of the ride you were already going to log. The next time the sync worker sees that activity, the chain’s mileage counter resets to zero. #pwshoes does the same for running shoes, and each part type has its own tag. No login, no form, no app switch. You’re standing in the garage with degreaser on your hands, you title the ride “Sunday loop, new chain #pwchain,” and the bookkeeping is done.

Why this beats a button

A maintenance tracker has a brutal interaction profile: you need it maybe six times a year, at unpredictable moments, and always immediately after doing something else (the actual wrenching). A dashboard button means remembering the site exists, finding the login, locating the right bike, clicking reset. Each step is trivial and the chain of them is exactly how a reset doesn’t happen until three weeks later, at which point your new chain has phantom miles and the whole premise of mileage tracking breaks without anyone noticing.

The hashtag works because it piggybacks on a habit with a 100% completion rate. The kind of person who wants Strava-driven maintenance reminders logs every ride without exception. Titling the activity is already part of the ritual. The reset just rides along on a workflow that needs no reminding, which is the only workflow you can trust with data entry six times a year.

There’s a bonus that I didn’t design for: the maintenance record lives on the activity itself. Scroll your Strava history and the #pwchain rides are your service log, timestamped, with the ride that christened the new part attached. People keep maintenance spreadsheets that reconstruct exactly this. Here the log is a side effect of the reset.

The costs of squatting in a text field

Designing an interface inside another product’s title field is rent-free living on someone else’s property, and it comes with the problems you’d expect.

Discoverability is zero. No one has ever typed #pwchain by accident. The feature has to be taught, on the dashboard, in the reminder emails, in the docs, because the interface itself is invisible until the exact moment someone uses it. This is the classic command-line tradeoff, efficiency for discoverability, transplanted into a fitness app.

Parsing is adversarial, gently. Activity titles are user-authored free text. The matcher has to be forgiving about case and position, strict about not matching #pwchainring when it means chain, and silent about everything else in the title. When someone tags a part they haven’t registered, nothing happens, and that nothing has to be safe. The rule I held: a hashtag can only ever cause a reset that the dashboard could also do. There’s no tag that deletes anything, so the worst possible typo is a no-op or a reset you didn’t mean, both recoverable with a click.

Feedback is asynchronous. Press a button and the gauge visibly zeroes. Type a hashtag and nothing confirms it until the sync worker next runs. The email acknowledging the reset matters a lot here; without it, users double-tag, wonder, and check the dashboard, which defeats the point.

The pattern

The general shape: find the record your user already creates reliably, and let a small annotation on it carry your feature. Commit messages that close tickets do this. Calendar event titles that set Zoom settings do this. The host system doesn’t know about you, the user barely changes behavior, and your feature inherits the reliability of a habit you didn’t have to build.

You give up control of the surface and all discoverability. In exchange, the interface is available exactly where and when the real-world event happens. For a tool whose entire failure mode is “the human forgot to tell it something,” I’d make that trade every time.