Ambientes Alpine Linux descartáveis no browser.
Sem instalação. Sem backend. Sem conta.
Abres a página → tens um shell root → fechas o separador → tudo desaparece.
O TERMINUS dá-te um ambiente Linux completo no browser — kernel Alpine 3.22 (x86), userspace com apk, busybox, ferramentas de rede e diagnóstico — tudo a correr num Web Worker via v86 (emulador x86 → WASM JIT).
Nada fica no teu disco. Nada sai do teu browser.
| O que tens | O que NÃO tens |
|---|---|
Shell root (/bin/sh) funcional |
Instalação, Docker, VM, conta |
apk add nmap tcpdump strace |
Backend, base de dados, estado persistente |
| Rede (loopback, DNS, HTTP) | Egresso livre — só assets de primeira parte |
| Ficheiros, pipes, redirecção, job control | Garantia de performance nativa |
| Receitas prontas (sec, forense, OSINT, etc.) | x86_64 (v86 é 32-bit only) |
Nothing to install. Nothing to maintain. Nothing to clean up.
curl -fsSL https://raw.githubusercontent.com/had-nu/terminus/main/terminus.sh | bash -s installAbre http://localhost:5173/apps/web/index.html no browser.
git clone https://github.com/had-nu/terminus.git
cd terminus
./terminus.sh # build (se necessário) + dev servergit clone https://github.com/had-nu/terminus.git
cd terminus
./terminus.sh build # constrói runtime + rootfs (reprodutível, sha256)
./terminus.sh dev # servidor em http://localhost:5173
./terminus.sh test # corre testes de prompt (22 testes)
./terminus.sh clean # remove artefactoshttp://localhost:5173/apps/web/index.html
Vês o kernel a fazer boot (~30s primeira vez, ~8s com cache), aparece o prompt:
TERMINUS P0 - Alpine Linux 3.22.6 (x86)
browser -> runtime -> Alpine -> /bin/sh
/bin/sh: can't access tty; job control turned off
terminus:~#
# Informação do sistema
terminus:~# cat /etc/alpine-release
3.22.6
terminus:~# uname -m
i686
# Instala ferramentas (apk funciona offline com mirror local)
terminus:~# apk add nmap tcpdump htop strace
# Diagnóstico de rede
terminus:~# tcpdump -i lo -n
terminus:~# nmap -sS 127.0.0.1
# Forense rápida
terminus:~# ls -la /proc/self/fd
terminus:~# cat /proc/meminfoBotão Destroy Session na UI — ou fecha o separador. Tudo desaparece. Zero rasto.
Cada receita = environment.yaml declarativo (base image + lista de pacotes apk). Carregas e tens o toolset pronto.
| Receita | Foco | Pacotes-chave |
|---|---|---|
network-research |
Reconhecimento de rede | nmap, masscan, zmap, traceroute, dnsutils |
web-security |
Auditoria de apps web | nikto, sqlmap, gobuster, ffuf, wafw00f |
malware-analysis |
Análise estática/dinâmica | yara, binwalk, volatility3, radare2 |
digital-forensics |
Forense de disco/memória | sleuthkit, autopsy, volatility3, bulk-extractor |
osint |
Inteligência de fontes abertas | theharvester, sherlock, social-analyzer, photon |
linux-fundamentals |
Aprender Linux | vim, htop, man, bash-completion, lsof, strace |
# Ver receitas disponíveis
ls recipes/
# Cada ficheiro .yaml é legível — base + packages
cat recipes/web-security.yaml┌─────────────────────────────────────────────────────────────┐
│ O TEU BROWSER │
│ ┌──────────────────┐ ┌──────────────────────────┐ │
│ │ Main Thread │ │ Web Worker (isolado) │ │
│ │ (UI / xterm.js) │ ←──→ │ v86 (x86 → WASM JIT) │ │
│ │ │ postMsg │ Alpine kernel + initrd │ │
│ └──────────────────┘ │ serial console (ttyS0) │ │
│ └──────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
- Main thread = só UI. React + xterm.js (P1), botões, estado de sessão.
- Web Worker = runtime Linux completo. Kernel 32-bit, userspace Alpine, serial bridge.
- Comunicação =
postMessage/MessageChannel(protocolo tipado empackages/protocol). - Persistência = zero. Worker morre → sessão morre → nada no disco.
| Requisito | Mínimo |
|---|---|
| Browser | Firefox 108+, Chrome 108+, Safari 16.4+, Edge 108+ |
| WASM | Sim (todos os browsers modernos) |
| SharedArrayBuffer | não necessário (v86 não usa) |
| COOP/COEP headers | não necessário |
| Memória RAM | ~300 MB livres (256 MB guest + overhead) |
| Rede | Apenas para carregar a página inicial (depois offline) |
Nota: v86 emula x86 de 32-bit apenas (Pentium 4-class). O Alpine
x86(i686) é a porta suportada — não x86_64.
| Comando | O que faz |
|---|---|
./terminus.sh |
Build se necessário + dev server (default) |
./terminus.sh build |
Constrói tudo: rootfs + initramfs + vendor v86 (pins sha256) |
./terminus.sh dev |
Servidor estático em http://localhost:5173 |
./terminus.sh test |
Corre testes de prompt (Playwright + Chromium) |
./terminus.sh clean |
Remove artefactos de build |
./terminus.sh install |
Baixa do GitHub, builda, e roda (sem clone) |
npm run build:p0 |
Constrói tudo via npm (rootfs + runtime) |
npm run build:rootfs |
Só rootfs/initramfs (fetch Alpine + assemble) |
npm run build:runtime |
Só vendor v86 + BIOS (npm pack, verifica hash) |
npm run dev |
Servidor estático via Python (legacy) |
npm run test:p0 |
Headless test (Playwright + Chromium) — evidência de boot |
Os scripts de build são reprodutíveis:
- Pins de versão + sha256 no topo de cada script
- Falham se o hash não bater (supply-chain protection)
- Artefactos gerados em
runtime/(gitignored — reconstrói com./terminus.sh build)
terminus/
├── terminus.sh # Launcher único (build, dev, test, install)
├── apps/web/ # P0: vanilla spike (index.html + worker); P1: React + xterm.js
├── runtime/
│ ├── alpine/ # Kernel, initramfs, rootfs, BIOS (reconstruídos pelos scripts)
│ ├── wasm/ # v86 runtime (vendored, pinned)
│ └── filesystem/ # P2: base imutável + overlay CoW
├── packages/
│ ├── protocol/ # Mensagens tipadas main↔worker
│ ├── session/ # Lifecycle NEW → DESTROYED
│ └── terminal/ # xterm wiring (P1)
├── recipes/ # 6 environment.yaml declarativos (D-003)
├── docs/
│ ├── spec/README.md # Spec amigável (este ficheiro em formato legível)
│ ├── SPEC.md # Spec técnica completa (local, gitignored)
│ ├── architecture.md # Arquitectura P0
│ ├── benchmarks.md # Métricas medidas
│ ├── reproducibility.md # Pins, scripts, como verificar
│ ├── spike-p0.md # Relatório do spike comparativo (v86 vs c2w)
│ └── evidence/ # JSON + screenshot do boot P0
├── scripts/
│ ├── build-rootfs.sh # Fetch Alpine + verify + initramfs
│ ├── build-runtime.sh # Vendor v86 + BIOS
│ └── dev.sh # Servidor estático (legacy)
├── .github/workflows/ # CI: build + smoke test
├── LICENSE # AGPL-3.0
├── package.json # Workspaces + scripts
└── prompt-tests.js # Testes automatizados de prompt (22 testes)
| Fase | Entregável | Estado |
|---|---|---|
| P0 | Runtime feasibility — v86 → Alpine → shell em worker | Done |
| P1 | Terminal — React + xterm.js + stdin/stdout bridge | Proximo |
| P2 | Filesystem — base imutável + overlay CoW + reset | Planeado |
| P3 | Package management — apk via mirror/local repo |
Planeado |
| P4 | File transfer — upload/download | Planeado |
| P5 | Resource controls — mem, processos, timeout | Planeado |
| P6 | Security review + threat model | Planeado |
| P7 | Public beta — site, docs, exemplos | Planeado |
| Ficheiro | Para quê |
|---|---|
docs/spec/README.md |
Começa aqui — visão geral legível (o que é, como funciona, receitas, decisões, métricas, roadmap) |
docs/SPEC.md |
Spec técnica completa — decisions log, open questions, Appendix A–C (local, gitignored) |
docs/architecture.md |
Arquitectura P0 (diagramas, data flow, decisões locked) |
docs/benchmarks.md |
Métricas medidas (payload 13.7 MiB, boot ~31s, 256 MB RAM) |
docs/reproducibility.md |
Pins sha256, scripts, como verificar |
docs/spike-p0.md |
Spike comparativo v86 vs container2wasm (evidência D-006) |
docs/evidence/ |
p0-v86-evidence.json + p0-v86-terminal.png (boot real) |
- Lê a
docs/spec/README.md— visão geral. - A spec técnica (
docs/SPEC.md) é a fonte de verdade — decisões, open questions, apêndices. - Branches:
develop= integração;main= releases;feat/*por feature (git-flow). - Commits: Conventional Commits (
feat:,fix:,docs:,chore:). - CI:
.github/workflows/build.ymlreconstrói artefactos e corre smoke test. - PRs contra
develop; merge--no-ff.
AGPL-3.0 — ver LICENSE e decisão D-007.
Binários vendored mantêm as suas licenças:
- v86 © copy.sh — BSD-2-Clause (
runtime/wasm/LICENSE.v86) - Alpine Linux © Alpine contributors — GPL-2.0 (kernel) / MIT-ish (userland)