The tool goes first.
Most tools wait for you to know what you want. Fractal flips it: the tool tells you what to work on next, and you can just follow. The part that makes that promise honest — the only part that makes it honest — is that the tool actually learns you. This page is what the tool needs to learn, and the loop that lets it.
The agency inversion
Today’s AI tools sit on the other side of a counter. You walk up with a question already formed; they hand back an answer. The cognitive burden of figuring out what to ask stays on you. That’s most of the burden.
Fractal swaps sides. The agent reads your inbox, your sessions, your calendar, your past completion data — and it surfaces the next move. “Reply to Sasha now — 10m, then drop into deep work until lunch.” If you want to follow it, you follow. If you want to override, you override. But the default is: the tool already knows.
· Old loop: human plans → human asks AI for help on a sub-task → AI answers
· New loop: AI plans → human follows (or vetoes) → AI learns from what happened
For the new loop to be worth following, the AI’s plan has to be better than the user’s default. Which means it has to know you specifically — not productivity-in-general.
The objective: completion, not productivity
“Productivity” is a soft optimization target. It absorbs every metric and means nothing. Fractal optimizes for one thing: did the work get done. Per ticket. Per session. Per day.
· The north star: completion_rate = resolved / (resolved + abandoned)
· Estimates are right when work fits. Schedules are right when the day finishes. Plans are right when tomorrow’s easier than today.
· Everything else — energy, focus, capability — only matters as a predictor of completion.
What the AI has to learn about you
To plan well, the agent needs a tendency profile — a running model of the human factors that affect whether work ships:
· What hours of the day produce shipped work, and what hours produce drift
· Day-of-week effects (Monday cold-start? Friday faded?)
· Recovery cost after high-stakes meetings (1:1 with the boss → next 30m wasted?)
· Maximum useful session length before resolution rate drops
· Tolerance for back-to-back density (3 meetings before deep work = how often it works)
· Context-switch tax (interleaved projects vs clustered)
· What surfaces (docs, sheets, links) reliably accompany completed work — vs which rooms tickets die in
· Which collaborators’ replies block downstream tickets
· Where the user codes/writes well (specific projects, specific repositories)
· Per-class completion: how reliably does the user finish writing tickets vs. data tickets vs. admin tickets
· Per-class estimate accuracy: where does the user systematically under-estimate or over-estimate
· Per-project stamina: which projects produce daily progress, which produce procrastination
· Today’s read of the above — “you slept poorly, you have three meetings before noon, your resolution rate this morning is half of average”
· Updated continuously as sessions resolve
The data the loop ingests
Every signal lives in one of two buckets — passively observed (no friction) and actively elicited (one prompt, sometimes).
· Resolution per ticket — the binary outcome that everything else explains
· Time accuracy — actual_min / estimated_min per ticket, per class, per project
· Drift — when did the user blow past the planned end-time? what came before?
· Acceptance rate — when the agent proposed X, did the user follow? if so, did X complete?
· Override outcomes — when the user overrode the agent, was the override better or worse?
· Session shape — start time, length, kind, density of surrounding meetings
· Capture-to-resolve latency — how long does a ticket sit in inbox by class/urgency
When a session ends with unresolved tickets, the user gets a small, single-screen prompt. One reason per failed ticket. Two seconds, multi-choice plus a free-text line.
╭─ Session over · Marcus prep · 13:30–15:00 ────────────────╮ │ T-0241 Prep 3 metrics ✓ shipped │ │ T-0245 Annotate launch doc · 13/25m │ │ │ │ Why didn't this finish? │ │ ◯ Underestimated the work │ │ ◉ Got pulled into something else │ │ ◯ Lost focus / energy │ │ ◯ Blocked on a dependency │ │ ◯ Wrong context (didn't have what I needed) │ │ ◯ Wrong time of day for this kind of work │ │ Optional · what would have helped? [_______________] │ │ │ │ [Skip] [Save and end session →] │ ╰────────────────────────────────────────────────────────────╯
The interview is short on purpose. Long surveys teach the user to lie. The signal that matters is the cause class — energy vs. context vs. capability vs. interruption. Five categories, five different countermeasures the agent can take.
The cause-to-countermeasure map
The reason data isn’t for analytics. It’s for changing the next plan.
· Update the user’s estimate-bias coefficient for that ticket class
· Future estimates of similar tickets get padded by the learned ratio
· If the puller was meetings, propose calendar holds before deep blocks
· If the puller was inbox, propose ⌘J Triage windows that contain the chaos
· Lower the user’s expected concentration at this hour for this kind of work
· Rebalance: heavy work pushed to recorded high-energy windows; admin to low-energy ones
· Tag the ticket with blocked_on and watch for the unblock
· Next time the user picks a ticket like this, the agent flags the dependency before scheduling
· Learn which docs/sheets/links accompany completion of this ticket class
· The agent assembles them into the session before the user sits down
· Strongest signal for the energy model. One vote per failed session.
· Over weeks, the agent stops scheduling that work in that window
The tendency profile (what gets stored)
The output of the loop is a small, human-readable per-user record. Visible to the user. Editable. The agent reads from it on every planning turn.
{
"user_id": "u1",
"updated_at": "2026-04-29T13:42",
"energy_curve": [
{ "hour": 9, "score": 0.92, "kinds": ["writing", "build"] },
{ "hour": 11, "score": 0.78, "kinds": ["writing"] },
{ "hour": 14, "score": 0.41, "kinds": ["admin"] },
{ "hour": 16, "score": 0.85, "kinds": ["build"] }
],
"estimate_bias": {
"writing": 1.18, // tickets take 18% longer than estimated
"build": 1.05,
"data": 1.42, // chronically under-estimates analysis
"meeting_prep": 0.88 // over-estimates this; pad less
},
"session_stamina": { "p50_minutes": 78, "p90_minutes": 120 },
"context_switch_cost_min": 11,
"rules_learned": [
"Never schedule a refactor session after a 1:1 with Marcus.",
"Writing blocks under 25 minutes don't ship — split or extend.",
"Friday afternoons resolve at 0.4× weekday rate; defer ambitious work."
],
"failure_clusters": {
"wrong_time_of_day": 14,
"got_pulled": 9,
"underestimated": 7,
"wrong_context": 4
},
"open_questions": [
"Does morning meditation actually correlate with afternoon ship rate?",
"Two consecutive crafted blocks vs one long block — which finishes more?"
]
}Two qualities of this record matter: it’s readable(you can audit it; it’s the AI’s notes about you, not a black box) and it’s small (a few hundred tokens; cheap to load on every planning call so the agent actually reasons with it).
When the AI's plan is wrong
The user’s veto is sacred. Every proposal carries Accept and Reject; the agent learns from both. But there’s a subtler failure mode: the plan is right and the user just doesn’t follow it.
· If the user accepts and the work ships: reinforce the plan shape (this hour + this kind + this length worked)
· If the user accepts and the work fails: exit interview → update the relevant axis
· If the user rejects and overrides: log the override + outcome. If the override completes more reliably than the plan, the agent learns the user’s instinct is sharper than the model. If it doesn’t, the agent gently surfaces that asymmetry next time.
· If the user just ignores the plan: treat as soft rejection. Lower the agent’s confidence for that class of suggestion until the user re-engages.
Privacy, control, and the off switch
· The tendency profile is visible. A /learning/me page (post-V1) shows everything the AI has inferred. Edit, delete, dispute.
· The exit interview is skippable. Always. Skipping is itself a signal (the user doesn’t want to talk → save it for tomorrow).
· Manual mode. One toggle disables proposals entirely. The agent goes back to a passive ⌘J — wait until asked. The learning loop pauses.
· Forget mode. User can wipe their tendency profile. The agent goes back to defaults.
· Local-first. V1 keeps the profile in the same Supabase row family as their tickets. Same RLS rules. Same export path.
What V1 captures · what's deferred
· Passive · resolution events — every accept/reject of an agent proposal is a labeled training point. The accept handler already updates the wire history with the user’s decision; this is the first signal.
· Active · session-end exit interview — the “Stop session” button on the live session screen opens the 5-radio prompt before closing the session.
· Storage · a flat tendency_profile row per user, stored in localStorage in V1, mirrored to Supabase when auth lands.
· Plumbing · the agent reads tendency_profile as part of its context on every /api/agent call (added to state alongside today and now_min).
· Time-accuracy tracking per ticket (needs a session timer with start/stop, not just an estimate)
· Energy curve inference (needs ~2 weeks of resolution data to stabilize)
· Estimate-bias auto-correction (needs the timer)
· Per-context room assembly (needs database/object-detail screens to be wired)
· /learning/me introspection page
· Manual / forget / off switches
The honest tradeoffs
· Cold start. The first week of plans are guesses. The agent has to be transparent about that — call them defaults, not predictions, until enough data lands.
· Survivorship bias. The agent learns from sessions that were attempted. Tickets that never made it onto the calendar are invisible. Need a complementary signal — “capture-to-attempt latency” — to see what the user systematically avoids.
· Stale assumptions. A user’s job changes. The model needs decay. Old data weights down faster than new.
· Self-fulfilling prophecy. If the agent learns “you can’t finish writing in the afternoon” and stops scheduling it there, it never gets the data to disconfirm. Periodic exploration proposals — “let’s try a writing block this afternoon, just to test” — keep the model honest.
· Anxiety. Some users will hate being modeled. The off switch isn’t a courtesy — it’s a load-bearing feature. People should be able to use Fractal as a calm calendar without the agent ever inferring anything about them.
How this lands in the product
· Today (existing): agent already proposes assignments, new sessions, snoozes. Accept/Reject flow is wired. The wire history already reflects user decisions.
· Next (V1.1): add the session-end exit interview. One screen. Five radios. Save as a session_outcome row with the cause.
· V1.2: aggregate session_outcome rows into tendency_profile nightly. Surface in the agent’s system prompt.
· V1.3: ship /learning/me — the user reads back what the AI thinks of them.
· V1.4: exploration proposals. The agent occasionally proposes against its own model to keep learning.
The promise of this product is “you don’t need to figure out what to do.” It can only be kept if the tool is willing to be wrong out loud, ask why, and update. The exit interview is the most important screen in Fractal. It’s the only one where the AI asks something of the user, and it’s the difference between a clever calendar and a tool that gets sharper every week.
Press ⌘J from any screen to talk to the agent.