Exploration 01 — Designing with AI Personal project · Seattle · July 2026

Working Overtime

I directed an AI to build my relay team's race-day command center. Eight hours of work across three releases, ten runners, and a deadline that could not move.

10
Runners
24h
Race
8h
Build time
3
Releases
AI generated the implementation. I defined the constraints, chose the trade-offs, tested every release, and decided what shipped.
Open the live boardreal schedule · try it yourself
The shift board: four six-hour rows showing all 39 legs, with daylight, twilight and dark bands painted behind them
Shift board · live All 39 legs on one screen. Each block is a runner; the bands behind them are daylight, twilight and dark. ◐ marks a headlamp leg, ✦ marks golden or blue hour. Interface is in Chinese — it was built for my team, not for this page.
How we worked

The machine was fast.
The calls were mine.

Five stages, and the split never moved: AI owned execution, I owned the definition of "correct." Every hard moment in this case sits in the left column.

Stage
I decide
AI does
Frame
Which requests are hard limits, which are soft preferences, and what the team actually values underneath both
Turns the rules into a runnable model
Generate
What "good" has to satisfy before I'll look at it
Produces the schedule and the interface
Judge
Check the output against people's original words; reject the schedule that is optimal but unfair
Recomputes alternatives in seconds
Ship
Design the manual override, test the sync, decide what's good enough to release
Implements, fixes, deploys
Operate
On the night, decide when to trust the plan and when to overrule it
Re-flows every later leg the moment reality changes
The setup

Captain first.
Designer second.

An homage to the round-the-clock relays of the 1970s and 80s: teams of 5–10 run the same loop for a full day and night. I captain a team of ten.

The race
24 h8 PM Fri → 8 PM Sat
The loop
4 miVolunteer Park, clockwise
Winning
Most lapsnothing else counts
The team
10and one spreadsheet, historically
Problem I found

Long before race week, the job I'd actually signed up for became obvious: somebody has to decide who runs when. Ten people, forty-plus legs, a night nobody wants, and preferences that quietly contradict each other. Historically that somebody keeps a spreadsheet, answers the group chat all night, and does arithmetic at 1 AM. I wanted a live board instead — one that recalculates the moment reality drifts, and shows the whole team where they stand without anyone having to ask.

3 weeks — waiting on 10 humans
v1 · Single-player
schedule it at all
Jul 5–6
~3 h · live URL by next evening
v2 · Multiplayer
one board, ten phones
Jul 28
~3 h · preferences + shared state
v3 · Race-ready
live ops + sync
Jul 29
~2 h · 48 h before the gun
Race
Jul 31 · 8 PM

Building it by hand would have cost me weeks I didn't have — so I brought in an AI as the engineering half, and kept the judgment half. It could re-plan in real time and show the result visually enough that ten runners could read it at a glance. That was the whole bet.

First message · Sunday 11:25 PM Help me schedule my ten-runner relay team… and I don't want a perfectly even split — I want to explore what's possible.
Course page: the elevation profile of the four-mile loop, drawn from last year's GPS track, beside per-lap and per-team climb totals
Course · the loop isn't flat Drawn from last year's GPS track: 6.04 km, 103 m of climb, most of it in the back half. Multiply by five laps and each runner climbs about half a kilometre — which is why "how fast is a lap" was never one number.
Shift 01

The brief was
a group chat

No spec — just ten friends texting. The design work: translating soft human language into rules, and knowing which rules bend.

"I'd rather not run 11 PM–4 AM… but I can if you need me to."
"Put us on back-to-back legs so we can hand off to each other."
"Three legs before 4 AM, close together, then one long break."
Softavoid 23:00–04:00 · may bend
Pairadjacent legs · best effort
Hard3 legs before 04:00 → rest ≥ 5h
From the build logJul 28 · 10:25 PM
"Before you build anything, walk me through the data first."
What it did: forced analysis before code — caught two name collisions and six missing pace estimates. The one misread that slipped through is the next section.
Shift 02

The AI optimized
my mistake

A teammate wrote "I prefer night running — just not 1 to 5 AM." I encoded it as "he loves the night." Watch what the machine did with that.

● My spec — "loves night" 3 legs · jammed into his no-go window
8 PM2 AM8 AM2 PM8 PM
● His actual words — "anything but deep night" 4 legs · all daylight · zero conflicts
8 PM2 AM8 AM2 PM8 PM
From the build logJul 28 · Late night
"You've got him wrong. He can run any time except deep night."
What it did: one sentence — the schedule snapped into place. No amount of computing would have found the error, because it wasn't in the code. It was in my translation.

AI doesn't dilute a bad spec.
It optimizes it.

Shift 03

Fair beat
optimal

The preference-optimal schedule honored every request — and gave friends wildly unequal rest. The team's real value wasn't optimization. It was fairness. So neither version shipped: the two got crossed.

Preference-optimal
Rest per runner — 30 min to 9+ hours
The hybrid — even spacing, preference-ordered
≈ 5.6 h for everyone · preferences pick the order
One thing no schedule could fix
Night · 7h 50m
One rotation · 6h 15m

The night outlasts the loop — everyone runs the dark at least once. The tool says so out loud instead of hiding it.

A system that admits what it can't do
earns more trust than one that pretends.

Craft decisions

Three calls
inside the board

01Showing a day without a clock

A runner's real question isn't "what time is my leg." It's "will I need a headlamp, and will I see the sunrise?" So daylight is painted into the schedule itself — not written next to it.

The detail people actually noticed

The board also derives the golden and blue hours from the same four sun times and marks those legs ✦. Nobody asked for it — but a 24-hour relay isn't only a logistics problem, and five of these legs are the prettiest run of somebody's year. Now they're claimable instead of accidental.

The same board on a phone: stacked six-hour rows with the light bands intact
The screen it was really designed for

A band lets you see your leg sitting inside the dark instead of doing the math. And one 24-hour bar on a phone makes every leg 8 pixels wide — that's why the day is cut into four rows. The desktop layout is the leftover, not the target.

02Whose 38 minutes is it, anyway?

Every start time in the schedule is downstream of one guess: how long a lap takes. Ten runners, ten different answers — and one runner is not one number.

Layer 1 — everyone owns their average
Haotian32:00Unconfirmed
Tianxiang34:00
Jing Lu37:30
Lu Yao42:00
Lingzi45:00Unconfirmed

A 13-minute spread between the fastest and slowest — across 39 legs that's hours of drift. So each runner edits their own number, and an Unconfirmed chip marks whoever is still on a placeholder.

Layer 2 — one leg can disagree with the average
38:30
Leg 10
39:00
Leg 20
39:30
Leg 30
40:00
Leg 36

Real data from one teammate: he set each of his four legs individually and modelled his own fatigue — 90 seconds slower by the last one. Nobody asked him to. The feature existed, so he used it to say something a single average can't.

The assign screen: a grid of 39 leg cards, each with a runner dropdown and its own estimated time
Assign · every leg is editable Each card is one leg: start time, a dropdown to swap the runner, and its own estimate at the bottom (预估). A ● dot means that leg was hand-set and no longer follows the runner's average.
From the build logJul 29
"Editing a single leg should recalculate the average automatically. Changing the average by hand should warn me first — then reset every leg to it."
What it did: settled the direction of truth. Two fields that both mean "how fast" will contradict each other eventually; the question isn't whether to sync them but which one is allowed to overwrite the other silently. The specific one wins. The general one has to ask.

03Demote. Don't delete.

I'd asked for options, and got six scheduling methods — six buttons of equal weight, side by side. Once the right one existed, six equal choices stopped being generous and started being noise. Below is what the team sees now instead.

Cut · Restraint · Payoff

Equal weight reads as "you figure it out." Ten tired runners don't want a menu — they want a plan, and a way to see it's a considered one.

Demoting to a drawer cost one line of markup. Deleting would have cost the ability to change my mind — and I did change it: what shipped is the plain rotation crossed with the preference solver, reachable only because I hadn't thrown it away.

The assign screen header: one highlighted primary method card above a collapsed drawer reading other methods (5)
Shipped state · one card, one drawer What the team sees now: the chosen method as a single yellow card marked 当前方案 — current plan, and everything else folded into one grey line that warns it will overwrite the plan.
The full assign grid: all 39 leg cards, each with a runner dropdown and its own editable estimate
All 39 legs · every one editable
And one thing I never automated

Every leg keeps a plain dropdown to swap the runner by hand, and every time keeps a manual override — all 39 of them, shown here.

It didn't stay theoretical. The team decided the captain should run leg one — not a scheduling argument, a team one. No solver has an opinion about that. I moved myself to the front by hand, which knocked the next runner loose, so that one had to be re-assigned too. Six legs now sit outside the generated pattern.

The schedule is a starting position, not a verdict. The last move belongs to a person standing at the exchange.

Shift 04

A demo is
not a tool

Ten phones, one shared board. Every bug below was found by using it like a runner — and two were introduced by my own fixes.

One shared board every edit · every phone · seconds
Jul 29 · AMEdits quietly undo themselves seconds after savingFixed
Jul 29 · PMA new device wipes the whole team's changes on first openFixed
Jul 29 · PMZombie tabs keep writing last week's data over everyoneGated
T-minus 48hCloud storage suspended — quota burned in a dayMigrated overnight
From the build logJul 29 · Afternoon
"I edit on one device, it says 'synced' — but on another device, the change isn't there."
What it did: a reproducible bug report — steps, expected, actual. It exposed the one scenario every test had skipped. Testing like a user is the skill AI makes decisive.
Shift 05

2 AM is a
design constraint

The race-day brief was one sentence: gloves on, headlamp on, zero patience.

One tap logs the handoff at the current time
Every later leg re-flows on every phone in seconds
One badge answers the only question: ahead or behind?
Race day tab on a phone: countdown, the pending leg card with a runner dropdown, a large log-at-current-time button, and the upcoming legs list

The real screen · 已同步 = synced · 按现在时间打卡 = log at current time

Post-race

What I
keep

01

Spec is a conversation

The most valuable inputs were the corrections — "that's not what I meant." Ship something concrete early. Even wrong. Especially wrong.

02

Making → judging

I wrote zero code and was never more responsible for what shipped. Judgment calls have no autocomplete.

03

Real walls, real users

Every upgrade was forced by a person hitting a wall — a teammate's phone, my own second window, a billing page. Not one came from foresight.

Race night · Jul 31 · 8 PMWritten before the gun · results to follow

Everything above is what the plan and the build looked like going in.
What the night did to it gets added here.