product

Downstream — decide with the version of you who has to live with it

Status: v1 in build (2026-07-15). The user's north-star "holy grail" app. Internal model name: stress curves. Product name: Downstream.

Every task app treats a task as a point — a due date. Downstream treats it as a function: how the cost and the stress of a deferred thing change over time. The reminder stops being "this is due" and becomes "you're about to hit the knee of the curve — act now, before it gets expensive."

Downstream is the maintenance half of the self. DreamPro / Workout Window is the aspiration engine (become who you want to be); Downstream is the upkeep engine (keep your life from quietly falling apart). Together they're the whole picture — growth and maintenance — and upkeep is the half almost every self-improvement product ignores.


The thesis (why it's named Downstream)

The core discipline the product teaches: don't let the version of you that exists right now — dreading something, or comfortably ignoring it — make the call. Look at what flows downstream, to the version of you who has to live with it. The name is the thesis. It also holds a second, on-brand reading: once you act, it's all downstream from here — the ease you earn. The name carries both the discipline and the payoff.

Present emotion is a terrible predictor of downstream cost, and that error runs in both directions — which is the product's central intelligence (below).


It's two curves, not one — and the gap between them is the whole product

Every deferred thing has two separate curves:

  • Cost — the objective consequence over time (money, damage, a lapsed relationship, a legal problem).
  • Stress — your subjective dread over time.

They rarely match, and the mismatch is the diagnosis:

Low costHigh cost
High stressThe dreaded 4-minute phone call → reframe / just do it (this is our existing reframe engine, pointed at a task)Do it now
Low stressGenuinely fine → permission to ignoreThe slow roof leak, the check-engine light → warn (the one place a scary forecast is earned)

Nobody has built the "you're more stressed about this than it deserves / you're not stressed enough about that" mirror. That mirror is "look downstream."


The soul is relief, not dread — a triage engine, not a nag

The failure mode is obvious: a wall of curves all climbing toward pain = an anxiety machine. We invert it. The hero output is a don't-do list with a clear conscience: "you can safely let 11 of your 14 open things drift today — here's the 1 that's about to spike." Productivity culture screams do everything now; Downstream can, with evidence, grant permission to defer the flat-curve stuff.

The emotional promise is a worry-offloader: dump the nagging background maintenance into it and it holds the anxiety for you, surfacing things only when they matter. "Put it down; Downstream will tell you when." This plugs into the JQ-as-second-brain thread.

Brand bright line (non-negotiable): Downstream is never a guilt machine. The scary forecast is used sparingly and only for the low-stress/high-cost trap. Everything else leads with relief and agency. (Consistent with the "no consumption/nagging metaphors — transformation, not pressure" brand voice.)


The curve model (the engine)

Deferred things fall into a few archetypes; naming them is most of the model. Each archetype is a function pressure(elapsed | timeToDeadline, params) → 0..1, plus a phase label and a plain-language downstream forecast.

  • flat — pressure ~constant and low. The permission-to-defer items. (Most of a typical list.)
  • ramp — deadline-anchored. Cost is roughly fixed, but stress rises as the date nears (taxes, an RSVP, a birthday gift). Params: deadline, leadDays (how far out it starts climbing).
  • decay — no hard deadline, but the real cost grows, usually accelerating, the longer you wait (oil change → engine wear; a cavity → root canal). Modeled as a logistic with the knee at kneeDays. This is the "maintenance debt" case and the heart of the product.
  • step — cost jumps at discrete thresholds (late fee at day 30, a lapsed license). Params: steps: [{ atDays, level }].
  • compounding — interest-like growth (debt, clutter, the inbox). Params: ratePerDay.

phasecalm | warming | knee | urgent | overdue, derived from pressure (and past-deadline for ramp). The knee — where marginal cost starts accelerating — is the actionable moment, and it is not the due date. Finding the knee is the product's whole value.

Curves are inferred, never entered

No one will hand-author a logistic. The design rule: the user just names the thing ("change the furnace filter", "renew the passport") and the curve is proposed from three sources —

  1. an LLM prior by task category (v1),
  2. the calendar (seasonal shapes: taxes, tires, gutters),
  3. eventually your own history.

A starter library of ~30 common maintenance tasks with default curves does the cold-start. The user only ever nudges a curve; they never draw one.


The calibration loop is the open-science dataset

When you finally resolve a thing, one tap: "how bad was it actually — easier / as expected / worse?" That single signal does triple duty:

  1. refines your personal curve steepness,
  2. feeds the normative crowd curve (the citizen-science data point),
  3. builds the public artifact — "the shape of human procrastination cost."

The two-layer "open science" (species-level normative curve + personal overlay) rides the existing Citizen Science infra (crowd data, world map, contribute-and-refine). The most valuable thing the crowd data can reveal: which deferrals are actually harmless — so the platform can hand out guilt-free permission with evidence behind it.

Snooze-with-consequences: deferring doesn't just re-alarm tomorrow — it shows the curve cost of the snooze ("+$40 and +2 dread if you push this a week"). Honest, not manipulative.


The metaphor system (the product's language)

Downstream lives in fluid dynamics — warm, on-brand for HiveJournal's science DNA (Graphene, Emberkiln, allotrope) — with a few borrowed mechanical terms for the starting problem:

  • Downstream — the future consequence you inspect before deciding.
  • Current — the natural momentum of your week.
  • Eddies — things stuck circling, going nowhere (a stalled to-do).
  • Downstream cost — what flows to you later if you don't clear it now.
  • Activation energy (borrowed) — the push needed to start; JQ's nudge supplies it at the right moment.
  • Static friction (borrowed) — why starting is the hard part; once moving, it's easier.

Talk to humans in this language, not "the knee of the logistic."


v1 scope (what's being built now)

The core loop, delivering the soul:

  1. Capture — type a thing you're putting off → JQ infers its archetype + params + the cost/stress split + a downstream forecast (the starter library seeds common ones).
  2. Triage — your things sorted by where they are on their curve, led by the relief headline ("let these drift; do this one") and the cost-vs-stress mirror.
  3. Detail — a per-item pressure gauge + "what's downstream if you wait" + resolve / snooze-with-consequences.
  4. Calibrate — on resolve, the one-tap "how bad was it actually" that refines the curve.

Phasing beyond v1

  • Curve-timed nudges — ✅ BUILT 2026-07-15. A 6-hourly cron (downstream-nudge.ts) finds each user's most-pressing item that has crossed the knee (phase knee/urgent/overdue), composes a short calm line (templated — no per-tick LLM), renders it in the user's own cloned voice when they have one (sayInUserVoice, cache-first) else text-only, and records it. Calm by design: ≤1 nudge/user/tick, ≥3 days between nudges for the same item. OFF by default (kill switch downstream_nudge, heartbeat downstream_nudge_tick). Surfaced as a banner on /dashboard/downstream (with the voiced audio) and via GET /api/downstream/nudges. The downstream_nudges table (migration 482) doubles as the traceability log — a reviewable record of everything Downstream ever said to you (the seed of the glasses "what did it tell me" feature), surfaced as a "what Downstream has told you" history on the dashboard.
    • Quiet hours — ✅ BUILT. The browser timezone is captured into downstream_prefs (migration 483) on dashboard load, and the tick never records a nudge during the user's night (default 21:00–08:00 local, per-user configurable). GET/POST /api/downstream/prefs.
    • Web push — ✅ BUILT. A service worker (public/sw.js)
      • a "Turn on nudges" button on the dashboard subscribe the browser; the nudge tick sends a web push (downstream-push.ts) so a nudge lands even when the app is closed. Migration 484 (downstream_push_subs). Requires VAPID env keys (VAPID_PUBLIC_KEY / VAPID_PRIVATE_KEY / VAPID_SUBJECT on the backend, NEXT_PUBLIC_VAPID_PUBLIC_KEY on the frontend) — degrades to no-op (in-app banner still works) until set.
    • Still to do: glasses delivery (the glasses app polls the /nudges endpoint — a glasses-app change, backend already ready).
  • Built-in Pomodoro (focus sessions) — ✅ v0 BUILT 2026-07-15. Turns triage's "do this one" into a bounded work/break session (classic 25/5, long break every 4 rounds). At each boundary it speaks a calm cue in your own voice (reusing the nudge/voice/push plumbing) and logs it to the traceability log; finishing a work phase on a pinned item eases that item's curve (applyFocusProgressfocusEasedAnchor, elapsed-based archetypes only), closing the triage → act → recalibrate loop. downstream-focus.ts (pure core tested 16/16), migration 485 (downstream_focus_sessions), a dashboard focus widget + per-item Focus ▶ button. The client timer drives boundaries while the app is open; app-closed delivery is the downstream_focus cron (1-min, OFF by default) which advances due sessions so the in-voice + push cue lands with the tab closed — kept safe against the client timer by a compare-and-set (no double cue), and self-terminating after the long break. Still to do: wiring the rhythm engine (below) into the cadence + in-ear soundtracks — see DOWNSTREAM_AUDIO_IDEAS.md.
  • Ultradian-rhythm engine (v0) — ✅ BUILT 2026-07-15. The timing layer: estimates where you are on your ~90-min BRAC energy wave from time-since-wake (no hardware) and surfaces a phase-aware suggestion (peak → take the hard item; trough → take the break). downstream-rhythm.ts (pure, tested 9/9), GET /api/downstream/rhythm, migration 486 (wake time + cycle on downstream_prefs), a dashboard rhythm strip labeled a rough estimate. It now drives the Pomodoro cadencerhythmTunedDurations tunes a session's block/break lengths to the current phase (peak → longer block; trough → shorter block + longer break), via a "⚡ Match focus blocks to my energy" toggle (on by default). v1 calibration is builtcalibratePhase blends recent signal into the estimate (recency×weight-weighted): self-report Low/Steady/High taps (downstream_energy_taps, migration 487) + behavioral signal from completed focus sessions (focusEnergyTaps), flipping the read to behavioral when either's in play. Open-science overlay is builtaggregateEnergyCurve pools the taps into a personal + anonymized-normative average-energy-by-hour curve (GET /api/downstream/rhythm/curve, ≥5/hour anonymity floor), shown as a "shape of your day" overlay (you vs everyone). Interaction-cadence signal is builtinteractionEnergy folds live app-usage cadence (?epm=) in as a weak, ephemeral (never-stored) nudge. The normative curve now feeds back into the estimate — ✅ BUILT: applyNormativePrior folds the crowd's average energy at the current local hour (cached ~30 min; ≥5-sample anonymity floor) into the base as a WEAK prior (0.2), applied before calibratePhase so any personal signal (up to 0.7) still dominates; when no personal signal follows, the read is source:'normative' ("· crowd-informed" on the dashboard). Still to do: the (unbuilt) adaptive soundtracks; v2 opt-in watch HR/HRV.
  • Normative / open-science curves — aggregate the calibration data into per-category crowd curves; personal-vs-normative overlay.
    • "Shape of your procrastination" — ✅ BUILT. The dread-vs-reality mirror, broken out per category with a you-vs-everyone overlay. Pure core (downstream-calibration-core.ts: shapeCategoryCalibration + aggregateNormativeCategories (privacy floor — a category's crowd rate shows only past NORMATIVE_MIN_ROWS=8 resolutions AND NORMATIVE_MIN_USERS=3 distinct users) + compareCalibration, tested 11/11). GET /api/downstream/calibration/categories → per-category {personal, normative, delta}; the dashboard renders a bar per category (your easier-rate) with the crowd average as a ▏marker, and calls out the category you over-dread most vs the crowd. No new migration — reads the existing resolution_feedback rows.
    • Public "shape of human procrastination" — ✅ BUILT. A public, no-auth page at /downstream/shape: the anonymized normative dread-vs-reality across everyone — an overall "N% turned out easier than feared" + per-category bars, framed as open science. GET /api/downstream/public/shape (getPublicProcrastinationShape, reuses the floor-gated aggregateNormativeCategories, cached ~1h + CDN cache headers). Linked from the /downstream landing.
  • Household / shared curves — maintenance is often shared (who changes the furnace filter); ties to JQ Bridge / family.
  • Downstream Glasses — the ambient layer: your curves surface in-ear at the knee, hands-free (see the glasses buildables). (Brand rename JQ Glasses → Downstream Glasses tracked as its own task.)

  • DreamPro Coaching System — the aspiration half; Downstream is the maintenance half.
  • The Citizen Science platform — the open-science substrate for normative curves.
  • The JQ reframe engine — pointed at high-stress/low-cost tasks.
  • MOBILE_JQ_PRESENCE.md / the glasses docs — curve-timed nudges + the ambient "Downstream Glasses" layer.
DOWNSTREAM — Docs | HiveJournal