Writing

Agility

August 19, 2026

On abandoning a feature I was committed to, and finding the better one already sitting in the tools I owned.

The open-window complication on my watch was working nicely. I moved on. Circling back during QA before release, I noticed the “last sync” time on the complication had not changed. It still showed two days ago. It never worked again.

That was BetterKey’s window status feature, and it was going to be the first tile in a return I had been planning for a while. Putting BetterKey back into HomeKit.

Back is the right word. Before BetterKey was an app, it was a Homebridge plugin. In the fall of 2024, I reverse-engineered Subaru’s undocumented API after finding a Reddit post about a Siri Shortcut and shipped homebridge-subaru. One car. One lock. No status readback. It existed for one reason: a Goodnight Automation. Ask the house to lock up, and that same command would lock the front door, turn off the lights, and lock the car in the driveway.

That was the question I could not stop asking myself in bed at night. Did I remember to lock the car? BetterKey grew out of that plugin, because some things belonged in an app: onboarding a car, granting permissions, running background tasks HomeKit could not touch. But the Home app never stopped being the natural surface. It is the last thing we check before going to bed. If the car’s state was there, none of us would have to open an app to see it.

HomeKit works best when the accessory has one job and does it plainly. A lock tile that shows locked or unlocked. A sensor that trips and resets. Read-only, one-way surfaces. You do not build much control into HomeKit. You put a piece of trustworthy state where the user already looks, and you let their existing automations do the rest.

I liked the shape of that constraint. It matched something I already believed about BetterKey, which is that the app should quietly earn its place and then get out of the way.

Window status was going to be the first tile. It seemed obvious. People care about it. It fit the read-only shape. And it would give me an excuse to redesign the vehicle screen to hold this new class of information: odometer, charge, fuel, range, tire pressure. Every one of those would need its own slot in the app, its own screenshot in the App Store listing, its own line in the help docs, its own paragraph in the owner’s manual I had been writing. Adding a new piece of telemetry is not one change. It is a shelf of changes.

I was ready to pay that cost. Then the window status stopped working on my own car.

I called Subaru. A patient person on the phone took my report and filed a bug. That was the appropriate answer, and also not one I could ship on. Then I noticed the same thing on a Toyota RAV4 in the app. Different manufacturer, different API, same failure mode. The data was there sometimes. It was not there when I needed it to be.

This was not the first time.

Months earlier I had built the plumbing and UI for a lock-status card. It read from a webhook the SDK said would fire every time the doors locked. On my own Forester the webhook never fired. The command worked. The lock engaged. The confirmation never came. I called Smartcar. The engineer told me something I have not been able to forget: even between two cars of the same make and model, capabilities can differ. What one Forester exposes, another may not. They filed the bug. That was the appropriate answer, and also not one I could ship on. The card is still in the repo, flagged off.

The vehicle SDKs I build on are kitchen-sink surfaces. Every capability is listed. Every endpoint is documented. What the documentation cannot tell you is which of those capabilities are wired end-to-end on the specific car in the specific customer’s driveway. You find out by shipping and watching. A fleet team can cover more of the range, and still not all of it. I do not have a fleet. I have a Subaru.

Even that understates it. Subaru is partly owned by Toyota, and I keep seeing the same bug shapes surface on both makes. When I talked about my window issue with other Subaru owners in forums, I found cars built in the United States were running a different interface, with different failure modes, than the ones built in Japan. Same company. Similar cars. Different result depending on which plant assembled the car. Conway’s law reaches past the org chart. It reaches into the assembly line.

I could see the shape of the next year if I kept pushing. I would build the tile. I would build the IA around it. I would update the screenshots and the docs and the manual. And every so often a user would open the Home app, see their window reported as closed, and walk out to a car with a window cracked or open.

I flagged the feature off. I put it on ice.

Somewhere in that quiet stretch I wrote down a rule for myself.

If it does not work on my car, it does not ship.

The rule is smaller than it sounds. I am not claiming my car is a good sample size. I am saying I get to be the last gate. If a feature fails on the one vehicle I drive every day, in the app I use more than any customer will, I have all the evidence I need to stop.

Once I stopped defending window status, I could look at the rest of what I had.

The app already knew when the car was parked. BetterKey had shipped park location a while back. I added one more thing: a home location the user could set on a map. When the car stopped and it was inside a radius of home, the app published an event. The Homebridge plugin picked it up and flipped a HomeKit motion sensor to motion detected for thirty seconds, then back.

That was the whole feature. There was no OEM in it.

The coordinates never left the phone. HomeKit did not need to know where home was. Homebridge did not need to know where the car was. It only needed to know that the car had arrived. The user’s own automations did the rest. Turn on the porch light. Open the garage. Nothing I had to build.

I ran it on my own phone for weeks before shipping it in August. I have not had to fix it since. It works on my Subaru because it does not ask my Subaru for anything.

I have been thinking about this as agility, though the word is easy to overuse. Agility is not the same as pivoting on impulse, or swapping ideas until one of them lands. Both of those look like motion and are usually not.

Agility is smaller. It is the willingness to abandon a feature you were emotionally committed to once the evidence stops supporting it. It is the flexibility to notice that the next feature is often already sitting in the tools you have, if you can bring yourself to look at them without the shape of the old plan in your head.

I still want BetterKey to reach more platforms. I still want the vehicle screen to hold more. Those ideas are not dead. They are waiting for the day the underlying data is reliable enough to earn the shelf of changes it costs to display it.

Until then, the feature that ships is the one that works on my car.