25 KiB
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:
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.
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)x264encGStreamer plugin — GPL-2.0+ (no dynamic-linking exception)gstreamer1.0-libavon Debian — LGPL source but GPL binary (libavcodec built with--enable-gpland linkslibx264.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):
- WebCodecs API replaces
@gfld/compositor-ffmpeg-h264(GPL) - vaapih264enc / nvh264enc / openh264enc replaces
x264enc(GPL) - 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 (
.nodefiles, 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 <memfd>--ro-bind /usr /usr, minimal/etcwhitelist,$HOMEoverlay--dev-bind /dev/dri/renderD128(single GPU render node)--ro-bind $HOST_XDG/wayland-N /run/user/<UID>/wayland-N(single socket only)--uid 100000-165535per-app (UID remap via/etc/subuid)--unshare-netby 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
dbclaim 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
--cpusand--memorylimits
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 byres.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:
- It's a one-time cost. Once built, the compositor is yours to maintain and extend indefinitely.
- 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).
- 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.
- 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
kcpPyPI package works with aiohttp WebSocket - Validate WebCodecs
prefer-hardwaredecode 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
<canvas>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
-
Hire 2-3 senior engineers with Wayland + WebGL + TypeScript + Python expertise. The browser compositor is the critical path — don't understaff it.
-
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. -
Add CI/CD license hygiene gates from day 1. Docker image audit, npm license-checker, pip-licenses, gst-inspect check. Catch GPL contamination early.
-
Engage legal counsel before starting the clean-room process. This bundle is engineering analysis, not legal advice.
-
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.
-
Skip XWayland in MVP. Most modern GTK4/Qt6 apps are Wayland-native. Add XWayland only if a specific X11-only app is needed.
-
Use the kcp PyPI package. Don't port Greenfield's TS KCP to Python — the Cython wrapper is faster and battle-tested.
-
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.
-
Use vendored ReconnectingWebSocket (Pedro Ladaria, MIT, 514 lines TS). Don't reinvent.
-
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 |