Julia
Back

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:

  1. I’m bad at noticing my inner state
  2. I feel like I need permission or external pressure to act
  3. 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:

  1. 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.
  2. Giving the app a commanding tone and forcing a small commitment would apply some external pressure to get me moving.
  3. 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 v1 app, titled DecisionRoller: a list picker set to Meal, a Roll button, the line Options available: 3, and a Recent Rolls list. A two-tab bar at the bottom shows Roll and Config. A result sheet reading Simple cook, with a Why section: uniform roll with no modifiers yet, no tags on this option, list Meal with 3 options. Reroll and Done buttons at the bottom.
DecisionRoller v1 — pick a list, roll, get a uniform result with a plain-language explanation.

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.

The v2 app, titled Portent: three status pills at the top — Mood: Medium, Work: Light, Rest: Okay — above a Dog Walks card showing 6 options and a Roll button, with a Recent Rolls list below. A three-tab bar adds Modifiers. A Modifiers screen with five sliders: Mood (Low to High), Workload (Light to Heavy), Sleep Debt (Rested to Tired), Outdoor Score (Indoor to Outdoor), and Practicality (Treat to Frugal), each showing a current value. A result sheet reading Low-effort cooking, with a detailed Why: a veto rule filtered out one option because sleep debt is high, followed by weighted factors for Energy, Creativity, Motivation, Cognitive Load, and Cost.
Portent v2 — the same roll, now manually weighted.

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.

A design mock-up on a dark canvas showing two light-mode phone frames labelled Roll — scrolled and Roll — page 3: a pink Dog Walks deck card and a purple Meals deck card, each with a Roll button, a deck carousel, and a Recent Rolls list.
Early mock-ups — a brighter, colour-per-deck direction.

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.

A design mock-up showing two dark-mode phone frames labelled Roll — page 5 and Roll — page 3 — rolled: a deep-red Break Activities deck card with a Let the fates decide button, and a result screen reading Yoga with a Rare pick chip and fit chips, the prompt Will you abide by fate?, and a red Obey button.
…then the dark, oracle-deck identity that shipped.

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.

Portent's home screen: a large glowing deck card titled Chores, 30 options, with a Let the fates decide button and a carousel of other decks stacked behind it. Rhythm and Cycle status pills sit across the top. A result screen on a dark background: the option Dust bedroom in large serif type, chips for moderate cognitive load and moderate energy, a Peek behind the curtain link, the prompt Will you abide by fate?, and a red Obey button above Roll Again and Defy the fates.
Pick a deck, let the fates decide — then choose whether to obey.
The Factors screen: stacked cards for Recovery, Workload (Light), Rhythm, Weather (Great for outdoors), and Cycle (Luteal, Day 25, introspective phase) — each derived automatically rather than set by hand. The Configure screen titled Your decks — the fates draw from the decks you create, listing active decks (Break Activity, Stimulants, Perfume, Chores, Personal Projects, Meal) with option counts and roll percentages, plus a Hidden from rolls section. A deck's Setup screen: a Devotion meter reading You've obeyed more than half the rolls (3 of 5 obeyed), an appearance colour set to Mint, a Hide from rolls toggle, and Tag Dimensions (Context, State of mind, Time) that can be switched on per deck. An option's Details screen for Past Lovers: a name field and a Note reading Soft rose with pink peppercorn, osmanthus, mushroom earthiness, and clean white musk: bittersweet, distant floral intimacy — which appears in roll results to remind you why the option exists — plus a Mark as draft toggle. An option's Frequency settings: a base weight stepper, a Rarity tier set to Rare (very unlikely, 5% weight), and a Cooldown selector — None, 6h, 12h, 1 day, 2 days — to stop an option recurring too soon.
Under the hood: context sensed for you, decks (and how devoutly you obey them), and per-option notes, rarity, and cooldown.

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.