DEV Community

zohayr slileh
zohayr slileh

Posted on

I spent 6 months building a real operating system for web apps

For the last six months or so I've been building something a bit unusual: a real operating system for web apps.

It's called PhreshOS. It's open source (MIT), and you can try a live demo right now: https://demo.phreshos.com/

I want to explain what it is, because "OS for web apps" can mean a lot of things.

The idea

PhreshOS is a programmable system that runs on your machine, with a desktop you open in the browser. You can reach it from anywhere you can reach your machine.

The apps on it (I call them Programs) are built with normal web tools. TypeScript, React if you want it, Vite, whatever you already use.

The difference is where you build them. You build a Program inside the System, and the System takes care of the parts every app has to redo:

  • sign-in and sessions
  • communication between the app's parts, and between apps
  • windows, storage, permissions

So you only write the app's own logic.

And everything you see on the desktop is a Program built on top of the System. The file manager, the settings, the wallpaper. None of it is baked into the core.

What a Program looks like

A Program has two sides: a Server that runs in the background, and a Client that shows up in a window.

Here's the counter you get when you create a new Program. The Server keeps the count:

import { context } from "@phreshos/server"

let count = 0

context.answer("read", () => count)

context.subscribe("increment", () => {
  count += 1
  context.publish("changed", count)
})
Enter fullscreen mode Exit fullscreen mode

The Client asks for it, and follows the changes:

import { context } from "@phreshos/client"

const count = await context.server.ask<number>("read")
context.server.subscribe("changed", render)
context.server.publish("increment")
Enter fullscreen mode Exit fullscreen mode

That's it. No HTTP routes, no WebSocket setup, no auth middleware. ask gets one answer, publish announces something, subscribe listens. The same three work between the two sides of a Program, between Programs, and from outside.

Built for agents first

This is the part I care about most.

On most systems, when an AI agent needs to use an app, it has to drive a browser and click buttons that were designed for eyes. Or someone writes a separate API just for the agent.

In PhreshOS, an agent uses the same apps you do, directly. The phresh command line reaches the whole running System, not just the install. So the agent you already use in your terminal can do things like:

phresh program list --json                  # what's installed
phresh process create --program files --name main   # open an app, its window appears on your desktop
phresh window maximize --process main --program files
phresh system logs --statement "select level, content from logs order by createdAt desc limit 10" --json
Enter fullscreen mode Exit fullscreen mode

And it can call an app's features, the same ones the app's window uses:

phresh endpoint ask --program notes --process main --endpoint server --event notes.list --json
Enter fullscreen mode Exit fullscreen mode

You don't design a special interface for the agent. If a feature exists for the window, it exists for the agent. phresh describe --all --json gives the agent every command as data, so it can find its own way around.

Try it

You need Node.js 24.15 or newer:

npm install --global @phreshos/cli
phresh system install
Enter fullscreen mode Exit fullscreen mode

Then open the address it prints (usually http://localhost:4300) and create your account. You can also run it in a GitHub Codespace.

To build your first Program:

phresh create my-program
cd my-program
phresh dev
Enter fullscreen mode Exit fullscreen mode

Its window opens on your desktop.

I've tested it on macOS and Linux. Windows, honestly, I don't know yet. If you try it there, I'd love to hear how it goes.

Links

It's still early, and there's a lot I want to build on top of it. Any feedback helps, good or bad.

Top comments (1)

Collapse
 
octyn profile image
OCTYN •

sharing the window's interface with an agent removes a lot of duplicate plumbing. i'd still want a different permission boundary: a human being allowed to delete a file shouldn't mean the agent inherits that permission unattended. can a program expose the same command but require approval when the caller is an agent?