# Greenfield (AGPL) vs MIT-Licensed Custom Compositor — Final Comparison & Recommendation > **Executive summary.** This document compares two approaches to building > a Wayland-to-HTML5 compositor for the Odoo 20 fork: > > 1. **Option A — Use Greenfield as-is** (AGPL-3.0): faster time-to-market, > battle-tested codebase, but **AGPL contamination forces the entire > Odoo fork to be open-sourced** under AGPL-3.0. **NOT COMPATIBLE with > the user's proprietary goal.** > > 2. **Option B — Build a fully MIT-licensed custom compositor** (this > bundle): reuse Greenfield's 7 MIT libs as building blocks, replace > the 4 AGPL packages with clean-room reimplementations in TypeScript > (browser) and Python (host). **Fully proprietary, but ~6-9 months > of engineering effort.** > > **Final recommendation: Option B (MIT-licensed custom compositor)**. > The user's #1 priority is license purity for a proprietary Odoo fork — > this rules out Option A. With 2 senior engineers in parallel, Option B > is achievable in ~5-6 months to MVP, ~8-9 months to production. ## TL;DR — Decision matrix | Dimension | Option A: Greenfield (AGPL) | Option B: MIT Custom Compositor | |---|---|---| | **License purity** | ❌ **AGPL-3.0 contamination** — entire Odoo fork must be open-sourced | ✅ **Fully proprietary** — MIT/Apache/BSD/LGPL only, with 3 substitutions | | **Time to MVP** | ✅ 1-2 weeks (run as-is in dev) | ❌ ~32 weeks (with 2 engineers in parallel) | | **Time to production** | ⚠️ Never (AGPL blocks shipping) | ❌ ~38 weeks (with 2 engineers) | | **Performance** | ✅ Battle-tested, optimised | ✅ Modern stack (WebGL2 + WebCodecs HW + OffscreenCanvas), should match or exceed Greenfield | | **Maintainability** | ⚠️ Forked from rc1, must track upstream | ✅ Full control, no upstream dependency | | **Sandboxing** | ❌ Zero (apps have full host access) | ✅ bubblewrap + seccomp + systemd-run from day 1 | | **Multi-tenancy** | ❌ Single-user single-session | ✅ Per-Odoo-DB isolation, JWT-scoped sessions | | **Odoo integration** | ⚠️ Custom shell needed (Preact → Odoo OWL) | ✅ Native Odoo 20 OWL shell + backend addon | | **Vendor lock-in** | ❌ Locked to Greenfield's architecture + upstream churn | ✅ Swap any component (e.g. replace pywayland with Smithay Rust) | | **Clean-room legal risk** | N/A (using AGPL code directly) | ⚠️ Must maintain SPEC.md + CLEAN_ROOM_LOG.md as legal defense | | **Total effort** | ~1-2 weeks to dev MVP, **never shippable** | ~32-38 weeks to production MVP | | **Recommendation** | ❌ **REJECT** (license incompatible) | ✅ **ADOPT** (the only viable path) | ## Detailed comparison ### 1. License purity (user's #1 priority) #### Option A — Greenfield (AGPL) **Critical problem**: The 4 user-facing packages are AGPL-3.0: - `@gfld/compositor` (browser compositor library) - `@gfld/compositor-proxy` (native proxy) - `@gfld/compositor-proxy-cli` (proxy CLI) - `@gfld/compositor-shell` (Preact shell — out of scope, user replaces with Odoo) **AGPL §13 network-use clause**: "If you modify the Program, your modified version must prominently offer all users interacting with it remotely through a computer network, an opportunity to obtain the source code of your modified version." **Impact on Odoo fork**: The Odoo fork is a network service (users access it via browser). If the compositor is AGPL-derivative, the entire Odoo fork must be open-sourced to all users. This **destroys the proprietary value** of the Odoo fork. **Additional GPL contaminants found in Greenfield** (Agent T audit): - `@gfld/compositor-ffmpeg-h264` — declared Apache-2.0 but actually GPL-3.0 (FFmpeg built with `--enable-gpl --enable-version3 --enable-nonfree`) - `x264enc` GStreamer plugin — GPL-2.0+ (no dynamic-linking exception) - `gstreamer1.0-libav` on Debian — LGPL source but GPL binary (libavcodec built with `--enable-gpl` and links `libx264.so.164` + `libx265.so.215`) **Verdict**: ❌ **NOT VIABLE** for a proprietary product. #### Option B — MIT Custom Compositor **License stack** (verified clean by Agent T): | Component | License | Compatible? | |---|---|---| | @gfld/common, @gfld/client-protocol, @gfld/compositor-protocol | MIT | ✅ | | @gfld/compositor-wasm (pixman + xkbcommon) | MIT | ✅ | | @gfld/xtsb (optional, XWayland) | MIT | ✅ | | @gfld/client-generator, @gfld/compositor-generator | MIT | ✅ | | pywayland | Apache-2.0 | ✅ | | python-xkbcommon | MIT | ✅ | | PyGObject + GStreamer | LGPL-2.1+ (dynamic linking) | ✅ | | gst-vaapi (vaapih264enc) | LGPL + MIT (libva) | ✅ | | gst-plugins-bad (nvh264enc, openh264enc) | BSD subset | ✅ | | libwayland, libdrm, mesa | MIT | ✅ | | aiohttp | Apache-2.0 | ✅ | | kcp (PyPI) | MIT | ✅ | | PyJWT | MIT | ✅ | | bubblewrap | LGPL-2.0+ (dynamic linking) | ✅ | | libseccomp | LGPL-2.1 | ✅ | | Odoo 20 Community | LGPL-3.0 (separate process) | ✅ | | WebCodecs, WebGL2, OffscreenCanvas | W3C standards | ✅ | | OpenH264 (BSD fallback decoder) | BSD-2-Clause | ✅ | | Custom browser compositor (your code) | PROPRIETARY (clean-room) | ✅ | | Custom Python proxy (your code) | PROPRIETARY | ✅ | | Custom Odoo 20 addon (your code) | PROPRIETARY | ✅ | **3 mandatory substitutions** (to avoid GPL contamination): 1. **WebCodecs API** replaces `@gfld/compositor-ffmpeg-h264` (GPL) 2. **vaapih264enc / nvh264enc / openh264enc** replaces `x264enc` (GPL) 3. **Don't install `gstreamer1.0-libav`** (GPL binary on Debian) **Clean-room requirement**: The custom browser compositor MUST be written clean-room — Person A writes spec (may read AGPL), Person B implements (must NOT read AGPL). Maintain `SPEC.md` + `CLEAN_ROOM_LOG.md` as legal-defensibility artifacts. **Verdict**: ✅ **FULLY PROPRIETARY VIABLE** with 3 substitutions + clean-room discipline. ### 2. Time to MVP #### Option A — Greenfield (AGPL) - **Week 1-2**: Run Greenfield's compositor-proxy-cli in Docker, embed the compositor-shell in an Odoo iframe, launch `gtk4-demo`, see it render. - **Week 3-4**: Replace compositor-shell with minimal Odoo OWL component. - **Week 5-6**: Integrate with Odoo auth, add app launcher. **Total to dev MVP**: ~4-6 weeks. **But**: This is dev-only. You cannot ship this without open-sourcing your Odoo fork. So time-to-MVP is irrelevant — the option is non-viable. #### Option B — MIT Custom Compositor | Phase | Weeks (1 dev) | Weeks (2 devs parallel) | |---|---|---| | Phase 0: Spike (validate libwayland ↔ asyncio) | 1 | 1 | | Phase 1: Browser compositor MVP (clean-room TS) | 25 | 15 (one on compositor, one on transport+input) | | Phase 2: Python proxy MVP (aiohttp + pywayland + GStreamer) | 3.5 | 3.5 (parallel with Phase 1) | | Phase 3: Odoo integration (OWL shell + backend addon + JWT) | 3.5 | 3.5 (parallel with Phase 1) | | Phase 4: Sandboxing v1 (bubblewrap + seccomp) | 1.5 | 1.5 | | Phase 5: Polish & testing | 3 | 3 | | **TOTAL to MVP** | **~37.5 weeks (~9 months)** | **~24 weeks (~6 months)** | | Phase 6 (optional): XWayland + multi-tenant + portal | +9 | +6 | **Critical path**: Browser compositor (Phase 1) is the bottleneck. With 2 senior engineers (one on compositor core + roles, one on transport + input + Python proxy + Odoo integration), MVP in ~6 months. ### 3. Performance #### Option A — Greenfield (AGPL) - WebGL1 (no OffscreenCanvas, no WebGL2) - Main-thread WebGL (jank on heavy frames) - WebCodecs with hardware decode **disabled** (FIXME: "frame offset is wrong") - FFmpeg Wasm fallback (GPL — can't ship anyway) - H.264 encoding: x264 software (GPL — can't ship anyway) - No adaptive bitrate (EncoderFeedback data produced but not consumed) - Single-threaded JS compositor #### Option B — MIT Custom Compositor - **WebGL2** (uniform buffer objects, simplified shaders) - **OffscreenCanvas + Web Workers** (render in worker, never block main thread) - **WebCodecs with hardware decode enabled** (fix Greenfield's FIXME) - **OpenH264 BSD Wasm fallback** (replaces Greenfield's GPL FFmpeg Wasm) - **Hardware-accelerated encoding by default** (vaapih264 on Intel/AMD, nvh264 on NVIDIA) - **Adaptive bitrate** (consumes EncoderFeedback data Greenfield ignores) - Multi-threaded (render worker + decode worker) **Expected performance**: Should match or exceed Greenfield. Hardware decode + hardware encoding + worker offload should give 2-3× improvement on heavy content. ### 4. Maintainability #### Option A — Greenfield (AGPL) - Forked from `1.0.0-rc1` — must track upstream commits manually - 3 native Node addons (`.node` files, Linux-x64 only, ABI-locked to Node major) - Heavy build toolchain (Yarn 4 + CMake + Ninja + Meson + pkg-config + 2 Emscripten versions) - Solo maintainer (Erik De Rijcke) — single point of failure - No CHANGELOG, no SECURITY.md, no CONTRIBUTING.md #### Option B — MIT Custom Compositor - Full control over the codebase - No native Node addons (pure Python + TypeScript) - Standard build toolchain (npm/pnpm + pip + standard tsc/aiohttp) - Python team can maintain Python parts; TS team can maintain browser parts - No upstream churn to track ### 5. Sandboxing & security #### Option A — Greenfield (AGPL) **Zero sandboxing** (Agent S analysis, pitfall M): - Plain `child_process.spawn()` with no isolation - Apps have full host filesystem access - Apps share the proxy's env (could leak DB passwords, Odoo session cookies) - No network isolation - No resource limits - Basic Auth (single replayable credential) - Client-generated `compositorSessionId` (spoofable) **Verdict**: ❌ **Cannot ship in production** without major security work. #### Option B — MIT Custom Compositor **Sandboxing from day 1** (Agent S analysis): - `bubblewrap --unshare-all --clearenv --seccomp ` - `--ro-bind /usr /usr`, minimal `/etc` whitelist, `$HOME` overlay - `--dev-bind /dev/dri/renderD128` (single GPU render node) - `--ro-bind $HOST_XDG/wayland-N /run/user//wayland-N` (single socket only) - `--uid 100000-165535` per-app (UID remap via `/etc/subuid`) - `--unshare-net` by default (most apps don't need network) - `systemd-run --scope -p MemoryMax=1G -p CPUQuota=200% -p TasksMax=256` - JWT auth (HS256, 15-min expiry, signed by Odoo backend) - Server-generated `compositor_session_id` (UUID, not client-generated) **Effort**: ~7-9 dev-days for v1 (shippable), +4-9 days for v2 (XWayland sandbox + veth networking). **Verdict**: ✅ **Production-grade sandboxing** out of the box. ### 6. Multi-tenancy #### Option A — Greenfield (AGPL) Single-user single-session. No multi-tenant isolation. Each Odoo database would need its own proxy instance, manually configured. #### Option B — MIT Custom Compositor - One compositor proxy per Odoo database (Docker container per tenant) - JWT `db` claim scopes every WS to one Odoo database - Per-session wayland socket (`$XDG_RUNTIME_DIR/wayland-N`) - Per-session forked worker process - Per-app UID remap (100000-165535) - Per-app cgroup limits (MemoryMax, CPUQuota, TasksMax) - Optional: per-tenant Docker container with `--cpus` and `--memory` limits ### 7. Odoo integration depth #### Option A — Greenfield (AGPL) - Custom shell needed: replace Preact compositor-shell with Odoo OWL component - Auth bridging: Greenfield's Basic Auth → Odoo session (fragile) - No audit log integration - No multi-tenancy #### Option B — MIT Custom Compositor - **Native Odoo 20 OWL shell** (ir.actions.client with target=fullscreen) - **JWT auth** issued by Odoo backend (HS256, 15-min expiry) - **Audit log** model (`compositor.audit.log`, append-only) — every app launch/terminate/crash logged with user, timestamp, app, duration - **App catalog** model (`compositor.app`) — per-user allowed apps list, filtered by `res.groups` - **Session model** (`compositor.session`) — mail.thread mixin for tracking - **Nginx reverse proxy** for single-origin HTTPS (eliminates CORS) - **Docker Compose** with GPU passthrough ### 8. Vendor lock-in #### Option A — Greenfield (AGPL) - Locked to Greenfield's architecture (browser compositor + Node proxy) - Locked to Node.js (N-API addons ABI-locked to Node major) - Locked to Linux-x64 (no ARM64) - Locked to Greenfield's wire protocol (no schema versioning) - Must track upstream rc1 → 1.0 transitions #### Option B — MIT Custom Compositor - Swap any component: - Replace pywayland with Smithay (Rust) if Python doesn't work out - Replace aiohttp with FastAPI if needed - Replace GStreamer with PyAV (FFmpeg Python bindings) if needed - Replace WebGL2 with WebGPU when browser support is widespread - No Node.js dependency (pure Python + TypeScript) - Linux-x64 + ARM64 (pywayland ships ARM64 wheels) - Can version your own wire protocol from commit #1 ## Effort estimates (detailed, person-weeks) ### Option A — Greenfield (AGPL) | Phase | Person-weeks | Notes | |---|---|---| | Dev MVP (run as-is in Docker) | 1-2 | Cannot ship — AGPL | | Replace shell with Odoo OWL | 2 | Cannot ship — AGPL | | Auth integration | 1 | Cannot ship — AGPL | | Sandboxing (NEW, not in Greenfield) | 1.5 | Cannot ship — AGPL | | Multi-tenancy | 1.5 | Cannot ship — AGPL | | **TOTAL** | **~7-8 weeks** | **All wasted — cannot ship** | ### Option B — MIT Custom Compositor #### Single engineer, sequential | Phase | Weeks | Deliverable | |---|---|---| | Phase 0: Spike | 1 | Validate libwayland ↔ asyncio integration (5-line cffi shim) | | Phase 1: Browser compositor MVP | 25 | Clean-room TypeScript, ~13,400 LOC | | Phase 1a: Surface state stack | 3 | Surface.ts, SurfaceRole.ts, Subsurface.ts (1,200 LOC) | | Phase 1b: Rendering pipeline | 3 | Renderer.ts, Scene.ts, View.ts, Output.ts, shaders (1,800 LOC, WebGL2) | | Phase 1c: Buffers | 1.5 | Shm.ts, BufferContents.ts, ImageBitmapBuffer.ts (600 LOC) | | Phase 1d: Transport + decoders | 4 | Channel.ts, kcp.ts, ReconnectingWebSocket.ts, WebCodecsFrameDecoder.ts, OpenH264FrameDecoder.ts (3,500 LOC + 500 LOC) | | Phase 1e: Input | 3 | Seat.ts, Keyboard.ts, Pointer.ts, Touch.ts, Xkb.ts (2,500 LOC) | | Phase 1f: Roles (xdg-shell) | 3 | XdgWmBase.ts, XdgSurface.ts, XdgToplevel.ts, XdgPopup.ts, XdgPositioner.ts (1,800 LOC, HIGH RISK) | | Phase 1g: Data device + clipboard + DnD | 1.5 | DataDeviceManager.ts, DataSource.ts, DataOffer.ts, PrimarySelectionDeviceManager.ts (NEW) (600 LOC) | | Phase 1h: Desktop policy | 1.5 | Desktop.ts, FloatingDesktopSurface.ts (800 LOC) | | Phase 1i: Math | 0.5 | Mat4.ts, Vec4.ts, Point.ts, Size.ts, Rect.ts (500 LOC) | | Phase 1j: UserShellApi | 0.5 | UserShellApi.ts (120 LOC) | | Phase 1k: Browser glue | 2 | input.ts, pointer.ts, touch.ts (NEW), dnd.ts, selection.ts (750 LOC) | | Phase 1l: Core | 0.5 | Session.ts, Globals.ts (200 LOC) | | Phase 2: Python proxy MVP | 3.5 (~17 dev-days) | aiohttp + pywayland + GStreamer, ~2,880 LOC Python | | Phase 2a: aiohttp WS server (9 endpoints) | 3 days | /signal, /channel, /mkfifo, /mkstemp-mmap, /read-fd, etc. | | Phase 2b: Channel/ARQChannel/SimpleChannel port | 1.5 days | Clean-room from spec | | Phase 2c: kcp PyPI package integration | 0.5 days | RealistikDash/kcp.py | | Phase 2d: NativeAppContext (signaling, escalation) | 2 days | 10-min SIGHUP grace, SIGTERM escalation | | Phase 2e: ProxyInputOutput (FD workaround) | 2 days | os.pipe(), os.memfd_create(), asyncio streams | | Phase 2f: libwayland event-loop integration | 1 day | 5-line cffi shim for wl_event_loop_get_fd | | Phase 2g: Multiprocessing + FD passing | 1.5 days | multiprocessing.reduction.send_handle | | Phase 2h: GStreamer encoder thread + marshalling | 2 days | GLib MainLoop in separate thread, asyncio.run_coroutine_threadsafe | | Phase 2i: Reconnection & lifecycle | 1 day | | | Phase 2j: Tests | 3 days | pytest + pytest-asyncio | | Phase 3: Odoo integration | 3.5 (~18 dev-days) | OWL shell + backend addon + JWT + Nginx + Docker | | Phase 3a: Odoo addon skeleton | 2 days | Models + controllers + views + security | | Phase 3b: JWT issuance + audit log | 1.5 days | HS256, 15-min expiry, pyjwt | | Phase 3c: OWL 3 fullscreen client action | 2.5 days | ir.actions.client, target=fullscreen, **must use proxy() not useState()** | | Phase 3d: Browser compositor integration | 2 days | userShell.actions.initScene | | Phase 3e: JWT middleware + WS handshake | 1.5 days | | | Phase 3f: Audit POSTback + Nginx + Docker + GPU | 2 days | | | Phase 3g: Multi-tenant | 1.5 days | Per-DB proxy spawning + db claim | | Phase 3h: Tests | 2 days | HttpCase + TransactionCase | | Phase 3i: Documentation + buffer | 3 days | | | Phase 4: Sandboxing v1 | 1.5 (~7-9 dev-days) | bubblewrap + seccomp + systemd-run | | Phase 4a: bwrap integration | 2-3 days | | | Phase 4b: seccomp profile + compile | 1-2 days | Docker default profile + CLONE_NEWUSER allow | | Phase 4c: systemd-run cgroup wrapper | 1 day | MemoryMax=1G, CPUQuota=200%, TasksMax=256 | | Phase 4d: Wayland socket ownership fix | 0.5 days | chmod 0660 + sandbox group | | Phase 4e: GPU passthrough testing | 1 day | /dev/dri/renderD128 only | | Phase 4f: Schema + docs | 1 day | | | Phase 5: Polish & testing | 3 | Tests, hardening, docs | | **MVP TOTAL** | **~37.5 weeks** | Single-tenant, single-app, fully proprietary, sandboxed | | Phase 6 (optional): XWayland | +8 | ~5,000 LOC TS, uses @gfld/xtsb (MIT) | | Phase 6 (optional): Multi-tenant portal | +2 | XDG Desktop Portal (FileChooser/Secret) | | Phase 6 (optional): Per-tenant veth networking | +2 | nftables filter | | **GRAND TOTAL (with Phase 6)** | **~49.5 weeks** | Production-ready | #### Two engineers in parallel | Phase | Weeks | Notes | |---|---|---| | Phase 0: Spike | 1 | Both engineers validate together | | Phase 1 (Eng A: compositor core + roles) + Phase 2+3 (Eng B: transport + Python + Odoo) | 25 (Eng A is critical path) | Parallel | | Phase 4 (Eng B: sandboxing) + Phase 5 (Eng A: tests) | 3 | Parallel | | **MVP TOTAL** | **~29 weeks (~7 months)** | | | Phase 6 (optional): XWayland (Eng A) + multi-tenant (Eng B) | +6 | Parallel | | **GRAND TOTAL (with Phase 6)** | **~35 weeks (~9 months)** | | #### Three engineers in parallel (aggressive) | Phase | Weeks | Notes | |---|---|---| | Phase 0: Spike | 1 | All three validate together | | Phase 1 (Eng A: compositor + roles) + Phase 2 (Eng B: Python proxy) + Phase 3 (Eng C: Odoo integration) | 25 (Eng A is critical path) | Fully parallel | | Phase 4 (Eng B: sandboxing) + Phase 5 (Eng A + C: tests) | 2 | Parallel | | **MVP TOTAL** | **~28 weeks (~7 months)** | | | Phase 6 (optional): XWayland (Eng A) + portal (Eng B) + veth (Eng C) | +5 | Parallel | | **GRAND TOTAL (with Phase 6)** | **~33 weeks (~8 months)** | | ## Final recommendation ### Strong recommendation: Option B (MIT Custom Compositor) **The user's #1 priority is license purity for a proprietary Odoo fork.** This single requirement rules out Option A entirely — AGPL §13 would force the entire Odoo fork to be open-sourced, destroying the proprietary value. **Option B is the only viable path.** With 3 mandatory substitutions (no GPL x264, no GPL FFmpeg Wasm, no Debian gst-libav) + clean-room discipline for the browser compositor, the entire stack is MIT/Apache/BSD/LGPL — fully proprietary-compatible. ### Effort justification The user is essentially building a Wayland compositor from scratch. This is a significant engineering effort (~25-30 dev-weeks for the browser compositor alone), but: 1. **It's a one-time cost.** Once built, the compositor is yours to maintain and extend indefinitely. 2. **The browser compositor is the bulk of the work** (~60% of total effort). The Python proxy + Odoo integration + sandboxing are relatively quick (~8.5 weeks total). 3. **The clean-room approach is legally defensible.** With proper SPEC.md + CLEAN_ROOM_LOG.md artifacts, the user can demonstrate non-infringement even if Greenfield's maintainer alleges derivative-work infringement. 4. **The modernized stack is better than Greenfield** — WebGL2, WebCodecs HW decode, OffscreenCanvas + Workers, adaptive bitrate, sandboxing, multi-tenancy, Odoo integration. The user gets a better product, not just a license-clean one. ### Phased rollout recommendation To minimize risk and validate assumptions early: **Phase 0 (Week 1): Spike** - Validate libwayland ↔ asyncio integration (5-line cffi shim) - Validate `kcp` PyPI package works with aiohttp WebSocket - Validate WebCodecs `prefer-hardware` decode works on target hardware - If any of these fail, reassess before committing to the full plan **Phase 1 (Weeks 2-15, 2 engineers): Browser compositor MVP** - Eng A: Surface + Roles (xdg-shell state machine) - Eng B: Transport + Input + Decoders - Target: A single Linux app renders in a `` via the custom compositor **Phase 2 (Weeks 2-6, parallel with Phase 1): Python proxy MVP** - Eng C: aiohttp + pywayland + GStreamer + bubblewrap sandboxing - Target: Python proxy can spawn a sandboxed Linux app and stream its surface to the browser compositor **Phase 3 (Weeks 7-10, after Phase 2): Odoo integration** - Eng C: OWL shell + backend addon + JWT + Nginx + Docker - Target: End-to-end: user clicks app in Odoo, app launches sandboxed, renders in Odoo canvas **Phase 4 (Weeks 11-13): Polish & testing** - All engineers: tests, hardening, docs - Target: Production-ready MVP **Phase 5 (Weeks 14+, optional): XWayland + multi-tenant + portal** - Add X11 app support, per-tenant isolation, XDG Desktop Portal ### Critical success factors 1. **Hire 2-3 senior engineers** with Wayland + WebGL + TypeScript + Python expertise. The browser compositor is the critical path — don't understaff it. 2. **Set up clean-room discipline from day 1.** Designate Person A (spec author, may read AGPL) and Person B (implementer, must NOT read AGPL). Maintain `SPEC.md` + `CLEAN_ROOM_LOG.md`. 3. **Add CI/CD license hygiene gates from day 1.** Docker image audit, npm license-checker, pip-licenses, gst-inspect check. Catch GPL contamination early. 4. **Engage legal counsel** before starting the clean-room process. This bundle is engineering analysis, not legal advice. 5. **Test with real Linux apps early.** Don't wait until Phase 4 to test with GTK4/Qt6 apps. Bugs in the xdg-shell state machine are subtle and need real apps to surface. 6. **Skip XWayland in MVP.** Most modern GTK4/Qt6 apps are Wayland-native. Add XWayland only if a specific X11-only app is needed. 7. **Use the kcp PyPI package.** Don't port Greenfield's TS KCP to Python — the Cython wrapper is faster and battle-tested. 8. **Reuse Greenfield's MIT C files** (westfield-egl.c, wlr_drm.c, wlr_linux_dmabuf_v1.c, etc.) via cffi. ~3,374 lines of MIT C reused verbatim — significant effort savings. 9. **Use vendored ReconnectingWebSocket** (Pedro Ladaria, MIT, 514 lines TS). Don't reinvent. 10. **Plan for 6-9 months**, not 3. The browser compositor is a significant piece of engineering. Underestimating it is the most common failure mode for Wayland compositor projects. ## What's at stake **If the user chooses Option A (AGPL)**: - They cannot ship a proprietary product. - They must open-source their entire Odoo fork. - Their investment in Odoo customizations becomes a gift to competitors. - The product is non-viable as a commercial offering. **If the user chooses Option B (MIT)**: - They invest ~6-9 months of engineering effort. - They get a fully proprietary Wayland-to-HTML5 compositor. - They get a modernized stack (WebGL2, WebCodecs HW, OffscreenCanvas, sandboxing, multi-tenancy, Odoo integration). - They have full control over their IP and roadmap. - The product is viable as a commercial offering. **The choice is clear: Option B.** --- ## Appendix: Quick reference cards ### Option A — Greenfield (AGPL) quick reference | Aspect | Detail | |---|---| | Repo | https://github.com/udevbe/greenfield | | Version | 1.0.0-rc1 | | License | AGPL-3.0 (4 packages) + MIT (7 libs) + GPL (compositor-ffmpeg-h264, hidden) | | Browser stack | WebGL1, main-thread, FFmpeg Wasm (GPL), WebCodecs HW disabled | | Backend | Node.js + 3 C N-API addons (Linux-x64 only) | | Sandboxing | None | | Multi-tenancy | None | | Odoo integration | Custom shell needed, Basic Auth | | Time to dev MVP | 4-6 weeks | | Time to production | **Never** (AGPL blocks shipping) | | Verdict | ❌ **REJECT** | ### Option B — MIT Custom Compositor quick reference | Aspect | Detail | |---|---| | Browser stack | WebGL2 + OffscreenCanvas + Web Workers + WebCodecs (HW enabled) + OpenH264 BSD Wasm fallback | | Backend | Python (aiohttp + pywayland + PyGObject/GStreamer + bubblewrap + seccomp) | | License | MIT/Apache/BSD/LGPL only, fully proprietary-compatible | | Sandboxing | bubblewrap + seccomp + systemd-run + cgroups v2, from day 1 | | Multi-tenancy | Per-Odoo-DB Docker container, JWT-scoped sessions | | Odoo integration | Native OWL shell + backend addon + JWT (HS256) + Nginx + Docker Compose | | Effort (2 engineers) | ~6 months to MVP, ~9 months to production | | Effort (3 engineers) | ~7 months to MVP, ~8 months to production | | Clean-room requirement | Mandatory (SPEC.md + CLEAN_ROOM_LOG.md) | | GPL contaminants to avoid | 3 (FFmpeg Wasm, x264enc, gst-libav) | | Verdict | ✅ **ADOPT** |