What is Portent?
Portent was an idea I had during my last Christmas holiday break. I’d noticed that I had an aversion to making small choices, and had a habit of externalising my locus of control. I began to wonder whether I could build a tool that would help me break through these problems so I’d stop getting stuck in place.
My problem was threefold:
- I’m bad at noticing my inner state
- I feel like I need permission or external pressure to act
- I keep forgetting what my options are
The best read I had on my own state came from two apps built on health data from my smartwatch: Training Today and Rise Sleep. Both sample health data — HRV and sleep respectively — over a rolling window rather than a single day’s reading.
And so, my plan started taking shape:
- Connecting to the same health data these apps consume and using it to assess energy and mood seemed like a great evolution of my existing heuristics.
- Giving the app a commanding tone and forcing a small commitment would apply some external pressure to get me moving.
- Maintaining lists to roll against would prevent me from having to reconstruct my options over and over.
The first version
The first prototype was called DecisionRoller. It was very simple; it allowed lists to be configured and a random option to be picked from a list. Just a uniform roll of the dice. I already had plans for roll weighting, but the systems weren’t set up yet. I was learning the ropes with Claude Code, and learning the basics of working with Xcode.
The second pass
The second pass was a mad dash ahead of a Christmas party to make something aesthetically coherent with the little bit of SwiftUI understanding I’d picked up, and I added slider inputs to mock weighted modifiers: mood, workload, sleep debt, weather, and spending intent. Options could be vetoed based on their tags, but the app still required me to understand my current state and keep the modifiers up to date. My next big challenges were going to be figuring out all of the app signing and permissions for using live health, weather, and calendar data from Apple’s APIs, and deciding on a visual identity for the app.
Finding the look
Before wiring up the hard parts, I pushed the visual identity around in mock-ups. My first pass was based on the current UI and introduced the swiping mechanic for list selection, as well as list themes. The exploration revealed the tarot card concept to me, and I quickly moved into a more ceremonial tone, which I hoped would help provide the sense of external pressure and solemnity I needed to make the roll results matter enough to move me.
And so I’d finally landed on the playing-card format for list presentation (actual tarot cards tend to be taller, which didn’t fit the available space), and the language began leaning more woo. I found a free-use font called “Zodiak”, deepened colours, added a grain texture to the cards, tuned aspect ratio and border radius, and began optimising more heavily for dark mode, my preference anyway. The “Obey” button and references to “The Fates” appeared.
Where it is now
The current version leans all the way into the metaphor. It’s a deck of oracle cards: you pick a deck, let the fates decide, and then choose whether to obey or defy the fates. The manual sliders are only adjusters. Factors from a few sources began to weight the odds in the background. Options got notes, tags, rarity tiers, and cooldowns to allow more intricate up-front decision encoding.
The engine, as it’s described to me
Though the logic is more or less mine, I wrote very little of the decision engine that offers options when you ask the fates.
Far as I can tell, it doesn’t confuse want with what’s viable right now. Those are two pretty different questions, and at first the engine was scoring them with the same additive maths, producing results that were technically legal but felt obviously wrong (like a long outdoor task on a rainy day).
Eventually, it came to be that a roll runs in three phases: a hard veto throws out whatever’s genuinely off the table, soft, multiplicative caps dim the options that don’t suit current state without fully removing them, and finally preference scoring chooses from what’s left. The pick itself is still random, with the weights only changing the odds.
A decision that paid off immensely was making the schema the source of truth instead of the code. Every dimension, score, and constraint lives as data the engine just interprets, so adding a new dimension is a data change rather than surgery on the algorithm. Options are tagged data, scored for energy, cognitive load, reversibility, whether they’re restorative or taxing, and how much they invite “autopilot” (the user getting captured by habituation). I insisted on designing the engine to be generic, which is why the same machinery can roll meals, perfumes, chores, and break activities without knowing or caring what any of them are, contextually. Each option is a small vector of weighted dimensions, and context tilts those weights.
What stuck around, and how I use it
The interface and the capabilities changed a lot across versions. The concept didn’t actually move all that much from the start.
From the very first prototype, the enemy was decision fatigue rather than a lack of productivity. I wanted to spend less of my energy deciding so that I’d have more energy to spend on things I actually care about. That’s why the core mechanic is a dice roll and not a really engaging to-do list, and why I’ve avoided features that would turn it into a habit tracker or a planner that requires frequent data maintenance. The randomness and set-and-forget pattern are what let me act without deliberating.
Over time as the app grew into what I wanted it to be, “Pick something” became “pick the thing that likely fits this moment.” Rather than ask me how I’m doing (I’m pretty bad at reading my body state), Portent detects it from its factors: sleep and HRV, resting heart rate, where I am in my cycle, the weather, my calendar, even barometric pressure and how much daylight is left. Each signal only tilts the odds a little, and every roll has a peek behind the curtain if I want to check the maths (which often came in handy during debugging).
I haven’t extensively tested some of the later features: drift detection and list maintenance helpers. To be honest, these days I mostly use the app to pick my perfume, but I think when I need it I’ll fall back on it, and I’m still excited about what I built and want to share it and perfect it.