A bash terminal that runs in the browser. Commands run in bashkit, a WebAssembly bash, inside a Web Worker, over files kept in the browser's OPFS storage. In-page builtins provide git, sqlite3, python3, pip, curl, wget and fx's WebAssembly core. Apps share floosie's browser stream hub. The only Node code is a static server that serves the page.
The earlier gm-backed CLI and library were removed.
Live: https://anentrypoint.github.io/thebird/ (GitHub Pages, deployed from main by .github/workflows/pages.yml).
- Node >= 22, for the static server.
- Chromium, for the witness. Set
CHROME_BIN; the default is/usr/bin/chromium-browser.
After a fresh clone, generate the vendored runtime (needs network):
node scripts/vendor-bashkit.mjs
node scripts/vendor-fx.mjs
node scripts/vendor-floosie.mjsvendor-fx.mjs reads the sibling ../fx/fx checkout, or FX_REPO, and uses Zig 0.17.1 from ZIG or its local paths. The Pages workflow sets FX_REPO to the latest main checkout of AnEntrypoint/gmfx and rebuilds it on every deployment. vendor-gm.mjs reads the sibling ../gm checkout, or GM_REPO, and builds gm-core.wasm from gm's portable C++ JSON, SHA-256 and compaction sources with the same Zig toolchain. vendor-floosie.mjs builds floosie's bare JS browser bundle from ../floosie, or FLOOSIE_REPO. The Pages workflow checks out the gm and floosie repositories at main and rebuilds both on every deployment.
npm start
node bin/thebird-relay.js --port 8080 --host 127.0.0.1Open the URL the server prints. --port defaults to an OS-assigned port and --host to 127.0.0.1. The server answers GET and HEAD only.
?run=<command>runs eachrunvalue in order when the page loads. The body getsdata-done="true"when they finish. Repeat the parameter for more commands.
- Bash syntax and common commands from bashkit: pipelines, variables, loops, functions, redirects, sed, awk, grep, find, jq, sha256sum and others.
git init,status,log,diff,add,commit -m, and localbranchandcheckout.commitruns the in-page gate.sqlite3 <database> <sql>, with the database kept as a file in OPFS. It runs through txiki.js'stjs:sqlitemodule.python3 -c <code>andpython3 <file>, run by Pyodide.pip install <package>...for pure-Python packages from PyPI.curlandwget, for hosts that send CORS headers to the page.fx --version,fx --helpandfx checkfrom fx's browser WebAssembly core.fx ask <prompt>needswindow.THEBIRD_FX = { apiKey, model }and WebAssembly JSPI.playwriter --version,playwriter status,playwriter execute <code>andplaywriter stdio '<json-rpc>'. Load the Birdman extension, grant the toolbar button on the thebird tab, thenplaywriter execute <code>controls other tabs over CDP. Execute bodies run in txiki.js withbrowser,context,stateandconsolein scope; no Node playwriter server or upstream browser extension is used.which,typeandcommand -vgive the same answer for each name.
run_shellbodies, git remotes, MCP client processes, auto-update, browser automation and the wiki, review and row verbs are not ported to the in-page wasm core;run_shellis refused.- No background jobs. A bare
&is refused. - No
nodeand no host binaries; they exit 127. - No git remotes.
push,fetchandpullare refused. - pip takes plain names only. Version specifiers, URLs and packages in the Pyodide set are refused. Installed packages last for the page session.
- Each command line has a 900 s limit. See
ARCHITECTURE.md.
- Up and Down: history.
- Tab: command names on the first word, otherwise workspace paths.
- Ctrl-C: cancels the running command and drops queued lines.
- Touch: tap the terminal to focus it. Drag on it to scroll the output.
- Ctrl-L clears the output. Ctrl-U clears the line. Ctrl-A and Ctrl-E move to the start and end of the line.
- Left, Right, Home, End and Delete edit the line, Ctrl-K cuts to the end and Ctrl-W cuts the word before the cursor. Paste inserts the text, and each pasted newline submits a line.
History is kept in localStorage under thebird.history. It holds the submitted command lines only, capped at 500.
npm run check
npm run lint:comments
npm run lint:architecture
npm run witnessnpm run witness drives headless Chromium through scripts/browser-driver.mjs and checks the in-page shell end to end.