Everything Wants to Replace All Your Software. It Refuses to Share Any Code.

Fifty browser apps in one repo: a spreadsheet, a 3D editor, a CRM, a chess game. No shared workspace, no shared dependencies, no shared build. The only connective tissue is a CI system that treats every app like its own country.

9 min read • View on GitHub • More from HeyPuter

An editorial ink illustration of a long workbench holding dozens of sealed glass jars, each containing a single miniature tool: a spreadsheet grid, a paintbrush, a wireframe cube, a speech bubble, a calculator, a chess knight, an invoice. The jars are individually stoppered and clearly separate, and a single thin ribbon runs along the back of the bench, threading through a small loop on every jar's lid.
One bench, fifty sealed jars, one thread. Everything's repository holds roughly fifty applications, and the only thing touching all of them is the CI system.
Key Takeaways

The Software You Use, Rebuilt in a Browser Tab

The README does not open with a product pitch. It opens with tables. On the left, a category. On the right, the commercial software it means to replace. Excel and Google Sheets for the spreadsheet. Word and Google Docs for documents. Slack for teamchat. Photoshop for photo. AutoCAD for CAD. QuickBooks for invoicing.

The list is the argument. This is not one app that does one thing well. It is a catalog of substitutes for tools most people pay for every month, and the whole catalog is MIT licensed.

It is easy to read a claim like that and stop at the audacity. The interesting part is one level down. When you open the repository, the thing holding all of this together is not a framework, a shared library, or a design system. It is nothing.

Fifty Apps, Zero Shared Workspace

Every app lives in src/<app>/. Each one owns its own package.json, its own lockfile, its own Vite config, its own entry point, its own runtime. There is no root npm workspace. There is no pnpm workspace. There is no shared dependency tree to reconcile.

src/
  spreadsheet/     package.json  package-lock.json  vite.config.ts
  documents/       package.json  package-lock.json  vite.config.ts
  3d/              package.json  package-lock.json  vite.config.ts
  teamchat/        package.json  package-lock.json  vite.config.ts
  ...
dev/
  puter-localhost.mjs
.github/workflows/
  ci.yml
  e2e.yml

The trade-off is deliberate and visible. You cannot bump React once and have fifty apps follow. You cannot refactor a shared component and watch every caller update. A cross-app change is fifty separate pull requests. But you also cannot break fifty apps with one bad dependency. A broken lockfile in src/chess is a broken lockfile in src/chess.

There is a charming detail in how the apps are served locally. A plugin in dev/puter-localhost.mjs rewrites Vite's dev URL from http://localhost:<port>/ to http://<name>.puter.localhost:<port>/. Browsers resolve every *.localhost name to loopback, and Vite accepts those hosts by default. So the spreadsheet runs at spreadsheet.puter.localhost, the 3D editor at 3d.puter.localhost, and each app gets a real subdomain without a line of DNS configuration.

The CI Is the Only Thing That Knows Everything

If nothing shares code, what knows about all fifty apps at once? The answer is a single workflow file. .github/workflows/ci.yml is the only component in the repository that sees the whole map, and it is where the coordination actually happens.

App discovery is a one-liner. CI lists every package.json under src/ with git ls-tree -r --name-only HEAD src and a grep for ^src/[^/]+/package\.json$. Adding a new app requires no CI edits at all. The app exists because its folder exists.

The Blast Radius Map: pick a file, watch which apps get tested. A change inside one app stays inside it. A change to shared tooling or the workflow itself lights up all fifty.

From there, the workflow runs in one of three modes. On a pull request, it computes the diff and runs only the tests that import the changed files, through vitest run --changed "$BASE". That is the affected mode. Overnight, it runs full suites for any app changed in the last 25 hours. That is schedule. A manual dispatch or a first push runs everything. That is full.

The blast radius rules are the part worth reading twice. A change to .github/workflows/ci.yml or to dev/ triggers every app, because every vite.config imports from dev/. A change inside one app's source touches only that app. The two heaviest apps, spreadsheet and documents, are split into four shards each through a small jq expression.

{spreadsheet: 4, documents: 4} as $shards

Quality enforcement is gradual on purpose. Prettier runs only for Whiteboard shard 1, with a comment that says "Only apps whose code is already Prettier-clean are held to it." The format gate is applied one app at a time as each one becomes clean, instead of a repository-wide flag day that would reformat fifty codebases at once.

The workflow also documents its own known failure. Whiteboard is marked non-blocking with continue-on-error, and the comment names the reason: two presence-relay ordering tests in collaboration-peers.test.js fail under CI load. An explicit exception with a stated cause is a more honest signal than a green check that hides a flaky test.

Inside the 3D Editor: Blender's Brain in a Browser Tab

The CI story explains how fifty apps survive in one repo. It does not explain whether any of them are built seriously. One of them is.

src/3d reimplements Blender's operator architecture in TypeScript. The same poll / exec / invoke split. The same RUNNING_MODAL return code. The same modal cancel-by-revert. That is not the skeleton of a weekend project. It is a signal that at least one of the fifty apps is being built with real depth.

A close-up editorial ink illustration of a single operator mounted on a machine: a hand gripping a large lever pulled into a forward position. The lever's base has three labeled notches behind it, and a taut thread runs from the lever's tip to a pencil mid-stroke on a blueprint. At the base of the lever sits a small rewind crank connected by a second thread that trails back to the pencil's starting point.
The operator model in physical form: a gate (poll), a fixed setting (exec), a live control (invoke), a lever that takes over the tool (RUNNING_MODAL), and a crank that rewinds the tool's own work (modal cancel by revert).
interface Operator {
  idname: string;
  label: string;
  props?: PropDef[];
  poll?(app: App): boolean;
  exec?(app: App, props: Props): OpResult;
  invoke?(app: App, event: Event, props: Props): OpResult;
}

type OpResult =
  | 'FINISHED'
  | 'CANCELLED'
  | 'RUNNING_MODAL'
  | 'PASS_THROUGH'
  | void;

The vocabulary is Blender's. poll gates whether an operator is available right now. exec runs it with fixed parameters. invoke runs it interactively, taking over pointer and keyboard input until it finishes. The return codes match too: FINISHED, CANCELLED, RUNNING_MODAL, PASS_THROUGH.

Properties are declared, not hand-wired. Each PropDef carries a type, bounds (min, max, softMin, softMax), a subtype like distance or angle or percentage, and a showIf predicate for conditional visibility. The same schema drives the UI, so a panel can show or hide a field based on another field's value without any bespoke code.

Modals are cancelled by reverting their own work. A ModalHandler supplies pointer, wheel, and key callbacks, plus a required cancel() that "undoes whatever the modal did so far." It does not restore a snapshot. It undoes the change the modal itself made, which is exactly how Blender's modal operators behave.

Operators are registered in a Map<string, Operator> keyed by string ID. That one decision is what makes an F3-style operator search possible: you can find an operator by name and replay it, the way Blender's redo panel re-runs the last operation with new parameters.

Two defensive details stand out. notifyOperator wraps each listener in a try/catch with the comment "listeners must never break operator execution," so a buggy UI extension cannot take down the core. And errorDescribers is an array of functions that each try to turn an error into a friendly message, letting modules register their own without the core knowing about them.

Everything vs. Everyone Else

The obvious question is how this compares to the open-source software that already exists. The honest answer is that most of it is narrower in scope and more mature in practice.

ProjectScopeDeploymentOverlap with Everything
LibreOfficeOffice suite (Writer, Calc, Impress)Desktop, local installDocuments, spreadsheets, presentations
NextcloudSelf-hosted collaboration platformSelf-hosted serverFiles, chat, documents
CryptPadPrivacy-first browser productivityBrowser, self-hostableDocuments, spreadsheets, collaboration
PenpotBrowser design and prototypingBrowser, self-hostableVector, design
Blender3D creation suiteDesktop3D
OdooBroad business application suiteSelf-hosted or cloudCRM, invoicing, accounting

Breadth of categories does not imply comparable maturity. Every alternative above is a focused project that has had years to harden one thing. Everything is a collection of things, most of them young.

The Gap Between Everything and Everything Working

The repository's own mission statement is the only verbatim text available, and it is worth holding next to the reality of the code.

We're rebuilding and open-sourcing the world’s software from scratch.

HeyPuter/everything, Project description on GitHub · HeyPuter/everything on GitHub

The repository analysis reports uneven maturity across the apps. Some identify themselves as alpha or early alpha. Some warn that data could be lost. The available sources do not establish broad production adoption, and the project itself has not explained in public how complete each app is.

That is the whole shape of the thing. The ambition is encyclopedic. The architecture is humble, because it refuses to couple fifty apps together. The coordination is real, and it lives in one workflow file. And the depth is uneven, with at least one app built seriously enough to make the rest plausible.

Everything is not everything working. It is a bet that the way to rebuild all of your software is to build each piece as if it were alone, and let CI carry the weight of knowing about all of them.