Initial commit: Greenfield architectural analysis (14 files, ~80 pages, 10 parallel research agents)

This commit is contained in:
1b-agent committed 2026-10-08 08:48:25 +00:00
commit c4b45cf218
15 files changed
+5444

No files matched your search

+386
View File
@@ -0,0 +1,386 @@
# 00 — What Greenfield Is and How It's Structured
## The one-paragraph summary
Greenfield is a Wayland compositor that runs partly in the browser (the actual
compositing and rendering, written in TypeScript against WebGL / WebCodecs /
WASM) and partly on a Linux host (a Node.js process that hosts real Linux
Wayland apps via `libwayland-server` and bridges their wire traffic to the
browser over WebSocket). The two halves together let you display **real Linux
applications** (GTK3/4, Qt, xterm, X11 apps via XWayland) inside a browser tab,
as if they were native browser apps. An optional Emscripten-based SDK lets you
compile separate Wayland apps to WASM and run them entirely in the browser with
no Linux host required.
## Repo layout
```
greenfield/
├── README.md # "The in-browser wayland compositor"
├── package.json # yarn 4.5.0 workspaces: libs/*, packages/*, examples/webapps/*, examples/compositor/*
├── .yarnrc.yml # nodeLinker: pnpm, global cache off
├── yarn.lock # 9368 lines
├── publish.sh # yarn workspaces foreach npm publish
├── protocol/ # Wayland XML protocol definitions (4 files)
│ ├── wayland.xml # Core Wayland protocol (124KB)
│ ├── xdg-shell.xml # Desktop shell protocol (48KB)
│ ├── wayland-drm.xml # DRM buffer formats (8.8KB)
│ └── web-bitmapbuf-unstable-v1.xml # *** Greenfield custom extension (2KB) ***
├── libs/ # 9 internal @gfld/* libraries
│ ├── common/ # @gfld/common - shared client/server runtime (wire format)
│ ├── client-protocol/ # @gfld/client-protocol - browser-side generated Wayland bindings
│ ├── compositor-protocol/ # @gfld/compositor-protocol - Node.js-side generated Wayland bindings
│ ├── client-generator/ # CLI: XML → TS browser protocol source
│ ├── compositor-generator/ # CLI: XML → TS Node protocol source
│ ├── compositor-proxy-generator/ # CLI: XML → TS proxy protocol source
│ ├── compositor-wasm/ # pixman + xkbcommon compiled to WASM
│ ├── compositor-ffmpeg-h264/ # FFmpeg n5.1.2 compiled to WASM (H.264 software fallback decoder)
│ └── xtsb/ # X11/XCB TypeScript bindings (vendored)
├── packages/ # 4 user-facing @gfld/* packages
│ ├── compositor/ # @gfld/compositor - browser-side Wayland compositor library (AGPL)
│ ├── compositor-shell/ # @gfld/compositor-shell - Preact+Tailwind SPA shell (AGPL) *** OUT OF SCOPE ***
│ ├── compositor-proxy/ # @gfld/compositor-proxy - native Wayland compositor proxy (AGPL, Linux-only)
│ └── compositor-proxy-cli/ # @gfld/compositor-proxy-cli - CLI binary (AGPL, Linux-only)
├── sdk/ # Greenfield WebAssembly SDK (for browser-resident WASM apps)
│ ├── README.md
│ ├── build.sh # clones emsdk 3.1.60, builds 30+ sysrootlibs
│ ├── sdk_env.sh # exports PKG_CONFIG_LIBDIR + PATH=toolkit/bin
│ ├── toolkit/ # gfcc/gf++/gfar/gfnm wrappers around emcc + wayland-scanner + meson cross inis
│ └── sysrootlibs/ # 34 build scripts for cross-compiling graphics stack (wayland, pixman, cairo, pango, gtk4, etc.)
├── examples/
│ ├── compositor/experimental-fullscreen/ # vite PWA kiosk running a single remote app
│ ├── docker-compose/ # Dockerfile + applications.json + docker-compose.yml for gtk3-demo/gtk4-demo/xterm/glxgears
│ ├── sdk/simple-shm/ # Weston simple-shm.c built with gfcc + wayland-scanner
│ ├── sdk/weston/ # Weston clients (terminal, dnd, editor, keyboard, flower, ...) meson-built
│ ├── sdk/gtk4/ # GTK4 demos meson-built to WASM
│ └── webapps/ # Pure-JS browser demos: simple-shm, webgl, weston-clients (symlink), gtk4
├── docs/ # Jekyll site (CNAME: udev.be/greenfield)
│ └── pages/{components, design, future_plans, getting_started, sdk}
└── docker/ # Production Dockerfile for compositor-proxy-cli
```
## The dual-side architecture
Greenfield is split into **two cooperating halves**, connected over WebSocket
(or, in the future, WebTransport). Understanding this split is fundamental to
everything else in this bundle.
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ BROWSER SIDE (TypeScript + WASM) │
│ │
│ ┌─────────────────────────┐ ┌──────────────────────────────────────────┐ │
│ │ @gfld/compositor-shell │ │ @gfld/compositor │ │
│ │ (Preact + Tailwind SPA)│───▶│ - Session, Compositor, Surface, Seat │ │
│ │ *** OUT OF SCOPE *** │ │ - Keyboard, Pointer, Touch, Xkb (WASM) │ │
│ └─────────────────────────┘ │ - Output (WebGL canvas) │ │
│ │ - render/ (WebGL shaders: YUV→RGB, etc.) │ │
│ ┌─────────────────────────┐ │ - desktop/ (Floating vs AlwaysFullScreen) │ │
│ │ JS/WASM webapps │───▶│ - remote/ (Channel, kcp.ts, decoders) │ │
│ │ (use @gfld/client- │ │ - browser/ (dnd, selection, input) │ │
│ │ protocol + common) │ │ │ │
│ └─────────────────────────┘ └──────────────┬──────────────┬─────────────┘ │
│ │ │ │
│ depends on ▼ ▼ │
│ ┌─────────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ @gfld/compositor│ │ @gfld/common │ │ @gfld/xtsb │ │
│ │ -protocol │ │ (Connection, │ │ (X11/XCB bindings,│ │
│ │ (Node-side │ │ wire format)│ │ used by both │ │
│ │ generated │ │ │ │ compositor+proxy)│ │
│ │ bindings) │ │ │ └──────────────────┘ │
│ └─────────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────────────────────────┘
│
│ WebSocket (TCP, perMessageDeflate=false)
│ + KCP-over-WebSocket (reliable UDP, ready for WebTransport)
│ + 9 endpoint paths per session
▼
┌─────────────────────────────────────────────────────────────────────────────┐
│ NATIVE SIDE (Linux, Node 18+, C) │
│ │
│ ┌──────────────────────────┐ ┌──────────────────────────────────────────┐ │
│ │ @gfld/compositor-proxy-cli│───▶│ @gfld/compositor-proxy │ │
│ │ - main.ts: http + ws │ │ - Session, SessionController │ │
│ │ WebSocketServer │ │ - NativeWaylandClientSession │ │
│ │ - forks SessionProcess │ │ - NativeWaylandCompositorSession │ │
│ │ per browser session │ │ - NativeAppContext (launch) │ │
│ │ - --bind-port=8081 │ │ - SurfaceBufferEncoding │ │
│ │ - --applications=<json> │ │ - Channel, FrameFeedback │ │
│ │ - --encoder=x264|nvh264 │ │ - XWaylandSession │ │
│ │ - --render-device=/dev/ │ │ - kcp.ts (1100-line TypeScript impl) │ │
│ │ dri/renderD128 │ │ - wayland-server.ts (TS wrapper) │ │
│ └──────────────────────────┘ │ - io/, encoding/, protocol/ │ │
│ └──────────────┬──────────────┬─────────────┘ │
│ │ │ │
│ depends on ▼ ▼ │
│ ┌────────────────────────┐ ┌────────────────────────────────┐ │
│ │ @gfld/compositor-proxy-│ │ native/ (C, built via CMake + │ │
│ │ generator │ │ Ninja) │ │
│ │ (generates *_interface │ │ - wayland/src/addon.c │ │
│ │ and *_interceptor.js) │ │ - encoding/src/gst_frame_ │ │
│ └────────────────────────┘ │ encoder.c │ │
│ │ - poll/src/poll.c (libuv) │ │
│ │ - wayland-server/ (patched) │ │
│ │ - westfield-*.c (EGL, dmabuf, │ │
│ │ XWayland, etc.) │ │
│ └────────────────────────────────┘ │
│ │
│ Native Wayland apps (GTK3/4, Qt, xterm, X11 via XWayland) attach to the │
│ proxy as if it were a real wl_display. The proxy encodes each surface's │
│ buffer to H.264 via GStreamer (x264 software or nvh264 hardware) using │
│ zero-copy dmabuf, sends frames over WebSocket/KCP to the browser. │
└─────────────────────────────────────────────────────────────────────────────┘
```
## Tech-stack table
| Category | Component | Tech / Version | Role |
|---|---|---|---|
| **Languages** | Browser TS | TypeScript ^5.5.2 | All `@gfld/*` TS packages |
| | Native C | C99 | `packages/compositor-proxy/native/` |
| | Shell | bash | sdk/build.sh, toolkit wrappers |
| | Python | python3 (xcbgen) | libs/xtsb protocol generation |
| **Build tools** | Workspace | Yarn 4.5.0 (Berry, pnpm nodeLinker) | Monorepo workspace mgmt |
| | Browser bundler | Vite ^5.3.1 | compositor-shell, examples |
| | TS compiler | tsc ^5.5.2 | libs/* and packages/* build |
| | Native build | CMake 3.13+ + Ninja | packages/compositor-proxy `build:native` |
| | Native pkg | @vercel/pkg (Brotli) + @vercel/ncc | compositor-proxy-cli single-binary |
| | Lint/format | ESLint ^8.57 + Prettier ^3.3.2 | All TS packages |
| | Test | Jest ^29.7.0 + ts-jest ^29.1.5 | libs/xtsb, packages/compositor-proxy |
| **WASM toolchain** | Emscripten (libs build) | emsdk 3.1.46 | libs/compositor-wasm, libs/compositor-ffmpeg-h264 |
| | Emscripten (SDK build) | emsdk 3.1.60 | sdk/build.sh (sysrootlibs) |
| | Meson cross | meson-gf-cross.ini (host_machine: wasm32/emscripten) | sdk/toolkit |
| **Wayland / GL stack** | wayland.xml / xdg-shell.xml / wayland-drm.xml | upstream freedesktop.org | protocol/ |
| | wayland-scanner | vendored at sdk/toolkit/bin/wayland-scanner | C header/codegen for native clients |
| | libwayland (server) | vendored + patched at packages/compositor-proxy/native/wayland/src/wayland-server/ | native compositor server side |
| | wl_drm + linux-dmabuf-unstable-v1 | implemented in native/wayland/src/wlr_*.c | zero-copy dmabuf to GStreamer |
| **Custom protocol** | web-bitmapbuf-unstable-v1.xml | Greenfield extension (Erik De Rijcke, 2023) | browser JS/WASM clients wrap HTML ImageBitmap as wl_buffer via fd |
| **Native GL/media runtime** | GStreamer | 1.20 (built from gitlab.freedesktop.org in docker) | H.264 encoding pipeline, plugins: base/good/bad/ugly/gl + nvcodec |
| | GStreamer encoders | x264 (software), nvh264 (NVIDIA hardware), vaapih264 (Intel, experimental) | --encoder flag on compositor-proxy-cli |
| | Mesa / OpenGL / EGL | libgbm1, libdrm2, libopengl0, libglvnd0, libegl1-mesa | GPU buffer mgmt + EGL rendering |
| | NVIDIA | libnvidia-egl-wayland1, libnvidia-egl-gbm1 | optional HW accel |
| **Browser transport** | WebSocket | ws ^8.17.1 (Node), native WebSocket (browser) | primary transport (TCP) |
| | KCP | TypeScript impl (1100+ lines per side) | planned reliable UDP — future switch to WebTransport |
| | WebTransport | mentioned in docs/design as future | not yet implemented |
| | XWayland | xwayland package + xauth + xxd | X11 backward compat on native side |
| **Browser rendering** | WebGL | WebGL1 native, `desynchronized:true` | Output.ts canvas, render/*.ts shaders |
| | WebCodecs API | @types/dom-webcodecs ^0.1.11 | H.264 GPU decode in browser (preferred path) |
| | WebAssembly (FFmpeg) | libs/compositor-ffmpeg-h264 (FFmpeg n5.1.2) | software fallback H.264 decode |
| | WebAssembly (pixman+xkbcommon) | libs/compositor-wasm (emsdk 3.1.46) | pixel ops + XKB keymap math |
| | SharedArrayBuffer + Web Workers | browser-native (COOP/COEP required) | async compositor, H.264 NAL decoder workers |
| | ImageBitmap | browser-native | web-bitmapbuf-unstable-v1 backing store |
| **Shell UI (out of scope)** | Preact | ^10.22.0 | compositor-shell SPA |
| | Tailwind CSS | ^3.4.4 | compositor-shell styling |
| | @preact/signals | ^1.2.3 | reactivity |
## Package inventory
### Browser side
**`packages/compositor`** (`@gfld/compositor`, AGPL-3.0) — The browser-side
Wayland compositor library. Pure TypeScript + WebGL + WebCodecs + WASM, no
3rd-party runtime deps. Exports `createCompositorSession()` and
`createAppLauncher(session, 'web' | 'remote')`. Internally: `Session.ts`
orchestrates, `Compositor.ts`/`Surface.ts`/`Seat.ts`/`Pointer.ts`/
`Keyboard.ts`/`Output.ts` implement Wayland semantics, `render/` holds WebGL
shaders (YUV/YUVA/RGB→RGBA conversion), `desktop/` arranges surfaces
(Floating vs AlwaysFullScreen), `web/` speaks to same-origin-iframe JS/WASM
clients, `remote/` speaks to the native proxy (with `kcp.ts`,
`websocket-events.ts`, `webcodec-buffer-decoder.ts`, `wasm-buffer-decoder.ts`,
`H264NALDecoder.worker.ts`, `xwayland/`), `browser/` handles dnd/selection/
input. Output is a WebGL texture inside an HTML5 canvas. Async — a slow client
never blocks another.
**`libs/client-protocol`** (`@gfld/client-protocol`, MIT) — Browser-side
generated Wayland protocol bindings (wayland.xml + xdg-shell.xml +
web-bitmapbuf-unstable-v1.xml). Used by JS/WASM webapps via `@gfld/common`
for the wire format.
**`libs/compositor-protocol`** (`@gfld/compositor-protocol`, MIT) — Node-side
generated Wayland protocol bindings (same 3 XMLs). Used by
`@gfld/compositor` for the in-browser server-side marshalling of Wayland
messages.
**`libs/common`** (`@gfld/common`, MIT) — Shared client/server Wayland
wire-format runtime. Two source files: `Connection.ts` (message framing +
argument codec) + `index.ts`. Tiny core that both `client-protocol` and
`compositor-protocol` build on.
**`libs/compositor-wasm`** (`@gfld/compositor-wasm`, MIT) — pixman 0.42.2 +
xkbcommon 1.5.0 compiled to WASM via emsdk 3.1.46. Exposes
`src/index.ts` (`init` function). Used by `@gfld/compositor` for pixel-region
math and XKB keyboard layout state.
**`libs/compositor-ffmpeg-h264`** (`@gfld/compositor-ffmpeg-h264`, Apache-2.0)
— FFmpeg n5.1.2 compiled to a single WASM module. TypeScript wrapper in
`src/{H264Decoder.ts, H264Worker.ts, index.ts}` runs in a Web Worker. Used as
the software fallback H.264 decoder when the browser lacks WebCodecs.
### Native side
**`packages/compositor-proxy`** (`@gfld/compositor-proxy`, AGPL-3.0,
Linux-only, Node ≥18) — Native Wayland compositor that bridges Linux apps to
the browser. Has BOTH a TypeScript layer (`src/Session.ts`,
`NativeWaylandClientSession.ts`, `NativeWaylandCompositorSession.ts`,
`NativeAppContext.ts`, `SurfaceBufferEncoding.ts`, `XWaylandSession.ts`,
`kcp.ts`, `Channel.ts`, `FrameFeedback.ts`, `wayland-server.ts`) AND a C
layer (`native/`) built with `cmake -G Ninja`. The C layer produces:
- `wayland-server.so` — patched libwayland-server (vendored at
`native/wayland/src/wayland-server/`, with `changes.diff` and
`generate_wayland_server_patch.sh`)
- `westfield.so` — Greenfield's westfield-* helpers (buffer, dmabuf, egl,
xwayland, fdutils) + `wlr_drm.c` + `wlr_linux_dmabuf_v1.c` +
`drm-protocol.c` + `linux-dmabuf-unstable-v1-protocol.c`
- `proxy-encoding.so` — GStreamer frame encoder (`gst_frame_encoder.c` +
`gst_main_loop.c`)
- `proxy-encoding-addon.node` + `proxy-poll-addon.node` +
`wayland-server-addon.node` — Node-API addons (vendored node-api headers in
`native/node-api/`) loaded by `src/addons/`
- `poll.c` — epoll wrapper backed by libuv
CMake deps: glib-2.0, gstreamer-1.0/app/video/gl/allocators ≥1.18,
graphene-1.0, egl ≥1.5, opengl ≥3.3, libffi, gbm, libdrm. Runtime also needs
libudev, mesa, NVIDIA EGL wayland/gbm drivers, xwayland. Implements `wl_drm`
+ `linux-dmabuf-v1` for zero-copy GPU buffer transfer to GStreamer encoder
pipeline (x264 software or nvh264 hardware). Connects to browser via
WebSocket; has TypeScript KCP implementation ready for the future WebTransport
switch. Supports direct peer-to-peer copy-paste between two proxy instances
to avoid browser round-trip.
**`packages/compositor-proxy-cli`** (`@gfld/compositor-proxy-cli`, AGPL-3.0,
Linux-only, Node ≥18) — CLI binary that wraps `@gfld/compositor-proxy`.
`src/main.ts` runs an HTTP server + `ws` WebSocketServer on `--bind-port`
(default 8081), and on first connection per `compositorSessionId` query
param, `fork()`s a `SessionProcess` (src/SessionProcess.ts) — one child per
active browser session. CLI args: `--applications=<json>` (URL→executable
map), `--encoder=x264|nvh264`, `--render-device=/dev/dri/renderD128`,
`--base-url`, `--allow-origin`, `--bind-ip`, `--bind-port`, `--basic-auth`.
The `--applications` JSON maps paths like `/gtk4-demo`, `/kwrite`, `/xterm`
to executables + args + env. Packaged with `@vercel/pkg` (Brotli, target
`node18-linux`) into a single static binary.
**`libs/compositor-proxy-generator`** (`@gfld/compositor-proxy-generator`,
MIT) — CLI that converts `protocol/{wayland,xdg-shell,wayland-drm}.xml` into
TypeScript source under `packages/compositor-proxy/src/protocol/`. Used at
build time only (yarn `generate` script).
### Shell side (OUT OF SCOPE for user)
**`packages/compositor-shell`** (`@gfld/compositor-shell`, AGPL-3.0) — Preact
+ Tailwind single-page-app shell built with Vite. Depends only on
`@gfld/compositor` + `preact` at runtime. Provides application launcher,
keyboard config, window management UI. **Explicitly out of scope for the
user** per task brief. The protocol-level integration point the user needs
to know about is `UserShellApi` (see `08-app-lifecycle.md`).
### Generators (3 sibling CLIs)
All three generators share the same dependency set (`camelcase`,
`uppercamelcase`, `meow`, `xml2js`) and similar layout
(`ProtocolParser.mjs` + `ProtocolArguments.mjs` + `index.mjs`). They consume
the same `protocol/*.xml` files but emit slightly different TypeScript
flavors for each side:
- **`libs/client-generator`** — emits browser-side client bindings into
`libs/client-protocol/src/protocol/`.
- **`libs/compositor-generator`** — emits Node.js-side server bindings into
`libs/compositor-protocol/src/protocol/`.
- **`libs/compositor-proxy-generator`** — emits proxy-side bindings into
`packages/compositor-proxy/src/protocol/`. Different file layout:
`src/EndpointProtocolArguments.mjs` + `EndpointProtocolParser.mjs` +
`index.mjs`.
### XWayland support
**`libs/xtsb`** (`@gfld/xtsb`, MIT, repo: github.com/udevbe/xtsb) — Vendored
TypeScript X11/XCB bindings. Builds from `xcbgen/ts_client.py` against 5
XCB protocol XMLs in `libs/xtsb/protocol/`: `xproto.xml`, `shape.xml`,
`xfixes.xml`, `render.xml`, `composite.xml`. Dual main/module entries:
`dist/main/index.node.js` (Node) + `dist/module/index.web.js` (browser).
Used by BOTH `@gfld/compositor` (browser side,
`packages/compositor/src/remote/xwayland/`) AND `@gfld/compositor-proxy`
(native side, `src/XWaylandSession.ts`) — same TS API on both ends of the
wire. On the native C side,
`packages/compositor-proxy/native/wayland/src/westfield-xwayland.c`
actually launches XWayland and bridges it.
### Wire between browser and native
- **Transport today**: WebSocket over TCP. Browser connects to
`ws(s)://<proxy-host>:<port>/<app-path>?compositorSessionId=<uuid>`.
`compositor-proxy-cli` uses `ws` ^8.17.1 with `perMessageDeflate: false`
(compression off for latency). The `compositorSessionId` is generated by
the browser and used by the CLI to route the upgrade to the correct
per-session child process.
- **Transport future**: KCP-over-WebTransport (reliable UDP). The codebase
already has a full TS KCP implementation in both
`packages/compositor-proxy/src/kcp.ts` (~1100 lines) and
`packages/compositor/src/remote/kcp.ts`. `docs/pages/design/index.md`
explicitly calls out that WebSockets-over-TCP is ill-suited for real-time,
that WebRTC DataChannels' SCTP congestion control is too slow, and that
they're waiting for WebTransport + will pair it with KCP +
forward-error-correction.
- **Out-of-band data**: copy-paste between two proxy instances goes
peer-to-peer (proxy → proxy) without browser round-trip, configured via
`--base-url` so each proxy can advertise itself to peers.
### SDK (`sdk/`) — for browser-resident WASM apps, NOT native apps
The Greenfield SDK lets you compile existing native Wayland C/C++ apps to
WebAssembly and run them directly in the browser compositor (no proxy
needed). Based on Emscripten 3.1.60 with three Greenfield-specific
extensions:
1. `sdk/toolkit/bin/gfcc` and `gf++` — wrapper scripts around `emcc`/`em++`
that inject pthread pool size, asyncify, and the unix-socket fs shim.
2. `sdk/toolkit/bin/wayland-scanner` — symlink to the natively-built
wayland-scanner inside `build-sysroot/bin/wayland-scanner`, used to
generate C client headers/source from xdg-shell.xml during app builds.
3. `sdk/sysrootlibs/` — 34 build scripts that cross-compile a full graphics
stack (wayland, wayland-protocols, pixman, zlib, png, xml2, xkbcommon,
icu, harfbuzz, freetype, fontconfig, pcre2, glib, jpeg, cairo, fribidi,
tiff4, pango, gdk-pixbuf, egl-stub, glesv2-stub, epoxy-emscripten,
graphene, sass, sassc, uapi-stub, upoll, cygepoll, expat, libffi;
gtk4 currently broken) into `sdk/sysroot/` for static linking.
`sdk/build.sh` runs everything end-to-end and writes `meson-gf-toolchain.ini`
(with absolute `_SDK_DIR`). `sdk/sdk_env.sh` exports `PKG_CONFIG_LIBDIR`
(pointing at `sysroot/lib/pkgconfig` + `build-sysroot/lib/pkgconfig`) and
prepends `toolkit/bin` to `PATH`. Meson projects use
`--cross-file toolkit/meson-gf-cross.ini --cross-file toolkit/meson-gf-toolchain.ini`
(host_machine: cpu=mvp, cpu_family=wasm32, system=emscripten).
**Important**: the `sdk/` is **not for native apps**. It's exclusively for
**WASM apps** that run inside the browser via Emscripten. Native Linux apps
on the proxy use the host's own system libraries — the Dockerfile installs
them via `apt-get install libffi8 libgbm1 libgstreamer1.0-plugins-base …
xwayland xauth`.
## Versioning note
Every workspace package is `1.0.0-rc1`. This signals:
1. **Feature freeze for 1.0** — the architecture, protocol bindings, and
public APIs are expected to be stable; no breaking changes anticipated
before 1.0.0 final.
2. **Not yet production-blessed** — known issues remain (e.g. gtk4 WASM is
"broken for now" per `sdk/build.sh` comment; WebTransport/KCP-over-UDP
is designed but not yet active; Linux Kernel Library WASM + JuiceFS web
FS are explicitly future work).
3. **Yarn Berry semantics** — `workspace:^` resolution means all `@gfld/*`
deps are pinned to rc1 across the tree; if the user forks and bumps,
they bump the whole tree consistently.
For the user's purpose (building their own Wayland-to-HTML compositor for an
Odoo 20 + JS/Python web OS), the rc1 status means they should treat
Greenfield as a stable architectural reference but plan to pin to a
specific commit if they fork it, since 1.0.0 final may land breaking-ish
changes before the rc1 → 1.0.0 transition completes.
## License of the source
The four `packages/*` (compositor, compositor-proxy, compositor-proxy-cli,
compositor-shell) are **AGPL-3.0-or-later**. The lower-level `libs/*` are
MIT or Apache-2.0. Anyone forking or building on the runtime packages must
respect AGPL — see `11-pitfalls.md` §License for implications.