An operating system that runs in a browser tab.
braamix.github.io — a whole system in under a megabyte, and it is running before you have finished reading this line. Nothing to install, nobody to sign up with, no server anywhere: the page downloads a kernel and gives you a prompt. Your files stay in the browser and are still there tomorrow. It works on a phone.
Braam is a small command-line system: a kernel, a filesystem, a terminal, a shell, forty-five programs and a package manager. It is written from scratch in C++20 and compiled to WebAssembly, which browsers run at close to native speed. There is no server side. The whole system is a few static files, so any web host can serve it.
Nothing is borrowed — no C library, no Emscripten, no xterm.js. Every program
is a separate WebAssembly file running in a sandbox of its own, and none of them
lives inside the kernel.
Open the page and there is a prompt:
$ ls /bin # every program, one wasm file each
$ echo hello > notes # your files survive a reload
$ curl https://example.com | less # a download, into a pager
$ edit notes # ^S saves, ^Q quits
$ spin & # a program that loops forever
$ kill %1 # killed anyway
It is not a Unix clone: no POSIX layer, no fork, no VT100 escape codes, and no
attempt to run C programs written for other systems. Giving that up makes the
system far smaller and lets every part use what the browser already provides.
Programs pause instead of blocking. Anything that would wait pauses, and the browser continues it when the answer arrives. So there are no threads.
The screen is a grid of cells, not a stream of bytes. A colour is a field in a cell and moving the cursor is indexing an array, so there is nothing to parse.
JavaScript never hands data straight back. Answers arrive later through one callback, which keeps the boundary small enough to check by eye.
A shell. A Bourne shell after v7: variables, functions, if, loops, case,
globbing, command substitution, pipes, redirection, background jobs, and line
editing with history. ^C stops whatever is running and gives the prompt back.
doc/Shell.md is the manual.
A filesystem. Everything lives in the browser's private storage and survives
a reload; /tmp is emptied at boot. /bin and /etc come from an archive
downloaded with the kernel, and are replaced whenever a new version is opened.
/proc shows what is running, and /dev has null, zero, random and
urandom. Where the browser will not store files at all, the system says so and
stops.
Access to the browser. curl fetches a URL, chat talks over a WebSocket,
fimport and fexport move files in and out, and pbcopy and pbpaste reach
the clipboard.
Full-screen programs. less and edit draw into a grid of their own and
send only the part that changed. ^C still reaches them.
A usage block in every program. -h asks one what it takes, and asking is
not a mistake: the block goes to the screen and the status is 0.
Isolated processes. Each command runs in a worker of its own, with its own
memory and its own open files. One stuck in a loop is killed outright, without
having to cooperate — spin exists to show that. The shell is one of these
programs, not part of the kernel.
A package manager. pkg installs software that did not ship with the
system. A repository is just files on a web server: an index and one zip per
package. The index is signed, and the keys it is checked against ship inside the
archive. An install is committed by renaming a single symbolic link, so a tab
that dies partway has installed nothing. The system ships pointed at the public
repository https://braamix.github.io, and
doc/Package_Formats.md §10 explains running one of
your own.
An embedding API. web/braam.js puts a terminal on any web page with
mount({ canvas }). web/embed.html is a working example, and
web/dual.html splits a window between two screens of one kernel —
mount({ screens: [ … ] }), a shell and a ^C of its own on each, over one
filesystem. web/quad.html is the same in a 2×2 of four, which is as many
terminals as there can be.
You need a clang that can target wasm32, plus CMake, make and Node. On macOS
that is brew install llvm lld; on Debian or Ubuntu,
apt install clang lld llvm.
make # build the kernel, the programs and the tests
make run # run the tests
make serve # serve the site and open it in a browser
make install # install the SDK, to /usr/local or ~/.local
make release # pack the site and the SDK as build/*.zip
make clean
The build leaves a complete website in build/web/. It needs no server program
and no special headers, so copying that directory to a web host is a deployment.
Every command is a wasm file, and building one needs nothing private to this
repository — make install puts an SDK under /usr/local or ~/.local.
#include "proc/file.h"
Task<i32> proc_main(Args)
{
co_await write_out("Hello, world!\n");
co_return 0;
}
write_out is the buffered stream File::stdout(), flushed when the program
exits.
find_package(braam REQUIRED)
braam_add_program(NAME hello SOURCES hello.cpp)
A program does not have to be part of the system to run: bring the file in with
the browser's file picker and run /import/hello.wasm, or curl it into
/home and run it there. doc/Programming_Manual.md
is the guide and examples/hello/ is the worked example.
| Directory | What is in it |
|---|---|
| src/kernel/ | coroutines, allocator, scheduler, screen, the JavaScript boundary |
| src/fs/ | paths, the mount table, the filesystem over browser storage |
| src/svc/ | URLs, WebSockets, clipboard, file transfer, clock |
| src/ui/ | the layout layer over the grid of cells |
| src/user/ | starting programs, system calls, the console, pipes, /proc, boot |
| src/proc/ | the runtime every program carries |
| src/cmd/ | one file per program; sh/ and pkg/ have directories |
| web/ | the page, the workers, the renderer, the browser side of everything |
| rootfs/ | what the boot archive carries |
| tools/ | the build's scripts, and the ones a package publisher signs with |
| test/ | the tests, and a simulated browser to run them against |
| doc/ | the specification, the manuals and the release notes |
/bin/sh.Version 0.7. Everything above works and the tests pass. A tablet works too: tap to type, drag to select, with a row of buttons for the keys a touch keyboard does not have.
Some things are missing on purpose. There is no bg and no ^Z yet. Lines are
not
re-wrapped when the window is resized. One program has the screen at a time.
There are no file permissions and no CPU limits — a program can be killed, but
not slowed down.
MIT. See LICENSE.
212 commits
C++
59.7%
JavaScript
19.5%
C
16.8%
Python
1.7%
CMake
1.4%
An operating system that runs in a browser tab.
braamix.github.io — a whole system in under a megabyte, and it is running before you have finished reading this line. Nothing to install, nobody to sign up with, no server anywhere: the page downloads a kernel and gives you a prompt. Your files stay in the browser and are still there tomorrow. It works on a phone.
Braam is a small command-line system: a kernel, a filesystem, a terminal, a shell, forty-five programs and a package manager. It is written from scratch in C++20 and compiled to WebAssembly, which browsers run at close to native speed. There is no server side. The whole system is a few static files, so any web host can serve it.
Nothing is borrowed — no C library, no Emscripten, no xterm.js. Every program
is a separate WebAssembly file running in a sandbox of its own, and none of them
lives inside the kernel.
Open the page and there is a prompt:
$ ls /bin # every program, one wasm file each
$ echo hello > notes # your files survive a reload
$ curl https://example.com | less # a download, into a pager
$ edit notes # ^S saves, ^Q quits
$ spin & # a program that loops forever
$ kill %1 # killed anyway
It is not a Unix clone: no POSIX layer, no fork, no VT100 escape codes, and no
attempt to run C programs written for other systems. Giving that up makes the
system far smaller and lets every part use what the browser already provides.
Programs pause instead of blocking. Anything that would wait pauses, and the browser continues it when the answer arrives. So there are no threads.
The screen is a grid of cells, not a stream of bytes. A colour is a field in a cell and moving the cursor is indexing an array, so there is nothing to parse.
JavaScript never hands data straight back. Answers arrive later through one callback, which keeps the boundary small enough to check by eye.
A shell. A Bourne shell after v7: variables, functions, if, loops, case,
globbing, command substitution, pipes, redirection, background jobs, and line
editing with history. ^C stops whatever is running and gives the prompt back.
doc/Shell.md is the manual.
A filesystem. Everything lives in the browser's private storage and survives
a reload; /tmp is emptied at boot. /bin and /etc come from an archive
downloaded with the kernel, and are replaced whenever a new version is opened.
/proc shows what is running, and /dev has null, zero, random and
urandom. Where the browser will not store files at all, the system says so and
stops.
Access to the browser. curl fetches a URL, chat talks over a WebSocket,
fimport and fexport move files in and out, and pbcopy and pbpaste reach
the clipboard.
Full-screen programs. less and edit draw into a grid of their own and
send only the part that changed. ^C still reaches them.
A usage block in every program. -h asks one what it takes, and asking is
not a mistake: the block goes to the screen and the status is 0.
Isolated processes. Each command runs in a worker of its own, with its own
memory and its own open files. One stuck in a loop is killed outright, without
having to cooperate — spin exists to show that. The shell is one of these
programs, not part of the kernel.
A package manager. pkg installs software that did not ship with the
system. A repository is just files on a web server: an index and one zip per
package. The index is signed, and the keys it is checked against ship inside the
archive. An install is committed by renaming a single symbolic link, so a tab
that dies partway has installed nothing. The system ships pointed at the public
repository https://braamix.github.io, and
doc/Package_Formats.md §10 explains running one of
your own.
An embedding API. web/braam.js puts a terminal on any web page with
mount({ canvas }). web/embed.html is a working example, and
web/dual.html splits a window between two screens of one kernel —
mount({ screens: [ … ] }), a shell and a ^C of its own on each, over one
filesystem. web/quad.html is the same in a 2×2 of four, which is as many
terminals as there can be.
You need a clang that can target wasm32, plus CMake, make and Node. On macOS
that is brew install llvm lld; on Debian or Ubuntu,
apt install clang lld llvm.
make # build the kernel, the programs and the tests
make run # run the tests
make serve # serve the site and open it in a browser
make install # install the SDK, to /usr/local or ~/.local
make release # pack the site and the SDK as build/*.zip
make clean
The build leaves a complete website in build/web/. It needs no server program
and no special headers, so copying that directory to a web host is a deployment.
Every command is a wasm file, and building one needs nothing private to this
repository — make install puts an SDK under /usr/local or ~/.local.
#include "proc/file.h"
Task<i32> proc_main(Args)
{
co_await write_out("Hello, world!\n");
co_return 0;
}
write_out is the buffered stream File::stdout(), flushed when the program
exits.
find_package(braam REQUIRED)
braam_add_program(NAME hello SOURCES hello.cpp)
A program does not have to be part of the system to run: bring the file in with
the browser's file picker and run /import/hello.wasm, or curl it into
/home and run it there. doc/Programming_Manual.md
is the guide and examples/hello/ is the worked example.
| Directory | What is in it |
|---|---|
| src/kernel/ | coroutines, allocator, scheduler, screen, the JavaScript boundary |
| src/fs/ | paths, the mount table, the filesystem over browser storage |
| src/svc/ | URLs, WebSockets, clipboard, file transfer, clock |
| src/ui/ | the layout layer over the grid of cells |
| src/user/ | starting programs, system calls, the console, pipes, /proc, boot |
| src/proc/ | the runtime every program carries |
| src/cmd/ | one file per program; sh/ and pkg/ have directories |
| web/ | the page, the workers, the renderer, the browser side of everything |
| rootfs/ | what the boot archive carries |
| tools/ | the build's scripts, and the ones a package publisher signs with |
| test/ | the tests, and a simulated browser to run them against |
| doc/ | the specification, the manuals and the release notes |
/bin/sh.Version 0.7. Everything above works and the tests pass. A tablet works too: tap to type, drag to select, with a row of buttons for the keys a touch keyboard does not have.
Some things are missing on purpose. There is no bg and no ^Z yet. Lines are
not
re-wrapped when the window is resized. One program has the screen at a time.
There are no file permissions and no CPU limits — a program can be killed, but
not slowed down.
MIT. See LICENSE.
212 commits
C++
59.7%
JavaScript
19.5%
C
16.8%
Python
1.7%
CMake
1.4%