← The Workshop Floor

JarvisOS

The personal operating system

A private operating system for one person running eight businesses — twenty-seven wings, a few hundred background workers, and the only codebase here whose build journal is longer than the poetry.

950 commits
2026-05-08 → 2026-08-11
TypeScript 97.2%
private repository
jarvis-os-wine.vercel.app
The problem

The other builds each solve one problem for one audience. JarvisOS solves the problem of running all of them at once: eight brands, a studio, a shop, a clinic of half-finished ideas, and one person holding every thread. Nothing off the shelf models that, because the market for software that runs a one-woman conglomerate is one woman.

So the design constraint was never features. It was attention. A system that needs to be checked is another job; a system that speaks first is an assistant. Almost every architectural decision below is downstream of that — scheduled workers that surface things, a signal bus so one wing can know what another wing saw, and a morning brief that reads the night's output so she does not have to.

4 decisions

What the constraint forced.

Each of these is a choice with a reason attached. The reason is the part worth reading — a stack list tells you what was used, and nothing at all about the judgment that put it there.

  1. 01

    Route the model to the job, not to the best model available.

    Body-wing AI — recovery alerts, daily summaries, routine chat — runs on Haiku only. That data is structured and formulaic; a frontier model would spend Sonnet money to reformat a number it was handed. Sonnet is reserved for the work that is actually reasoning: reviewing the day's real commits, mediating a judgment call, writing. Model choice is a cost architecture decision, and treating it as a quality setting is how AI bills get away from people.

  2. 02

    Wings talk through a signal bus, never through each other's tables.

    Each wing publishes a small typed payload to a namespaced key and subscribes to the ones it cares about — the body wing emits a recovery score and consumes the cycle phase; the CEO morning brief reads both. Nothing reaches across into another wing's schema. Twenty-seven wings that queried each other directly would be a single wing with twenty-seven names, and the first schema change would take the whole thing down.

    jarvis:signals:body:{userId}
      → { recovery_score, sleep_hours, training_sessions, alert, alert_advice }
    
    jarvis:signals:cycle:{userId}
      → { cycle_phase, cycle_day }
  3. 03

    Derive the score in the open, so it can be argued with.

    The recovery score is not a model output. It is a clamped sum of three contributions — heart-rate variability against personal baseline, sleep hours against a floor, self-reported quality — and it is written down as arithmetic. A number that tells you how your body is doing has to be inspectable, or you either believe it too much or stop reading it. The version that a model produces is more sophisticated and worth strictly less.

    baseline 50
    + hrv     : (hrv_ms / baseline_hrv - 1) × 25 , clamped ±25
    + sleep   : (sleep_hours - 6) × 5            , clamped ±15
    + quality : (sleep_quality - 5) × 2          , clamped ±10
    final = clamp(sum, 0, 100)
  4. 04

    Monitor the monitor.

    One subscriber to the queue's own `function.failed` event covers every worker in the system at once, including the ones written after it, plus a six-hourly sweep over the heartbeat tables with a latch so a stuck job alerts once rather than forty times. This was not foresight. It was written the week after six workers went quiet for a month and nothing said anything — the scar is in the Scar Room, and this is the fix that came out of it.

What generalises

The part that survives the build.

A silent failure is worse than a loud one, and much easier to build by accident.

Six background workers resolved the wrong tenant and did nothing successfully for a month. Every one returned 200. Nothing retried, because nothing had failed. The lesson that generalises: a worker whose no-op and whose success look identical to the outside is not monitored, however much monitoring is pointed at it. Make the no-op an event.

Prompt caching is an architecture decision, not a flag.

Caching a large stable system prompt changes what is affordable, which changes what can be built. Once the standing context is nearly free per call, per-user context injection becomes the cheap part and the design moves from "one big careful call" to "many small situated ones". The saving is the headline; the shift in what is designable is the actual result.

Seed data that looks like production data will eventually be read as production data.

A dashboard panel showed five rows of AI review output for weeks. They were seeds — no such review had ever run. Nobody lied; the fixture simply outlived the moment when everyone knew it was a fixture. Seeds need to be visibly fake or deleted before launch, and a panel with no real rows should say so rather than fill itself.

The cost of a system is the cost of understanding it six months later.

The dedup passes in this journal are mostly about a second copy of something — a legacy dashboard over the same tables, a hub page that re-implemented four dedicated pages inside itself. None of it was broken. All of it doubled the cost of every future change, which is the tax that eventually stops a solo build dead.

The record

Built with

  • Next.js
  • TypeScript
  • Supabase / Postgres
  • Inngest
  • Upstash Redis
  • Claude API
  • Vercel

Measured

commits
950
last commit
2026-08-11
journal sections
299
nights logged
82

Written from JarvisOS BUILD_JOURNEY.md — the diary, 145 sessions. The dossier is composed from the journal rather than quoted out of it — the raw sections stay behind the review gate described in docs/THE_FORGE.md §4, and every figure above is read from the GitHub API at build time.