Contributing to MoUI
MoUI is a multi-platform MoonBit GUI framework. The project is currently maintained by a single maintainer with AI assistance, and external contributions are welcome. Pull requests are the primary entry point for changes.
This guide describes how to set up a local environment, where changes should land, what a contribution must satisfy before review, and how the review process works. It complements — and does not repeat — the project-specific documents listed under Before you contribute.
Project posture
- Single maintainer, AI-assisted. The maintainer reviews and merges all PRs. Review latency may be longer than a staffed project; please be patient.
- Open to contributions. Bug fixes, new controls, renderer/backend
improvements, docs, and tests all belong in PRs. Architecturally sensitive
changes follow the RFC process in
GOVERNANCE.md. - No CLA. MoUI is Apache-2.0. Contributors certify origin via the lightweight DCO below; no Contributor License Agreement is required.
- Scope of support. Only the
mainbranch is supported. There is no LTS line. See SECURITY.md for the security support scope.
Before you contribute
Read these first; they define the boundaries a contribution must respect:
- AGENTS.md — repository working rules for any contributor or agent. Start here.
- docs/architecture.md — package map and runtime
pipeline (
View[Msg] -> ElementTree -> LayoutTree -> RenderTree -> DrawCommand -> renderer). - docs/moui-app-package-boundary.md — owning-package rules and the Review Checklist used during review.
- docs/ai-collaboration.md — project invariants and the recommended contributor/agent workflow.
- docs/development.md — local setup, workspace members, and focused development loops.
- docs/testing.md — daily validation script, focused checks, and manual smoke commands.
Local setup
From the repository root:
moon update
sh scripts/check.sh --profile daily
moon update refreshes registry packages. sh scripts/check.sh --profile daily
is the daily validation gate (dependency guards, guidance consistency,
maintenance baseline ratchets, API surface, moon check, core/view/render/
backend package tests, Showcase and Markdown Editor app tests, Web wasm-gc
builds).
Report your MoonBit toolchain version with any issue or PR:
moon version
moon info # for the relevant package, when reporting API-surface issues
Where changes should land
The owning-package rules are authoritative in docs/moui-app-package-boundary.md. The short version:
moui/core— platform-neutral contracts, opaqueView, typed events,Program/Effect/Subscription, geometry, draw, semantics, text contract, neutral theme token surface. Do not add concrete controls, runtime implementation, or design-system brand content here.moui/views— public view constructors and concrete control behavior implemented as@core.ViewNodevalues and wrapped with@core.View::from_node. New built-in controls go here, including the app-facing constructor and any private*_control/*_layout/*_surfacehelper.moui/runtime— runtime lifecycle, element/layout/render tree execution, effects, subscriptions, diagnostics.moui/backend— host service contracts; concrete platform behavior in the platform backend packages.moui/render/*— renderer facade and concrete renderers (Skia, WGPU, WebGPU adapter).examples/*/app— shared app logic; platform entrypoints stay thin.moui_theme/*— design-system addons only; not a default app dependency.
Architectural invariants
These are non-negotiable. Cross-reference docs/ai-collaboration.md for the full list.
- Public view constructors return opaque
@moui.View[Msg]; concrete built-in behavior lives inmoui/viewsas@core.ViewNodeimplementations constructed with@core.View::from_node. - The runtime pipeline stays
View[Msg] -> ElementTree -> LayoutTree -> RenderTree -> DrawCommand -> renderer. - Do not add new
coreenum variants, primitive constructors, or runtime lowering arms to support a new control. New controls are expressed inmoui/views. - Do not let ordinary app packages (
examples/*/app) depend onmoui/runtime,moui/render/*, or platform backends. They default towzzc-dev/mouiandwzzc-dev/moui/views. - Renderer status (mainline / diagnostic) must stay synchronized across code, tests, docs, and Showcase. Native WGPU is diagnostic; native Skia is the mainline.
Pull request requirements
Every PR should:
- Stay focused. One logical change per PR. Broad churn is harder to review and more likely to be rejected.
- Run
sh scripts/check.sh --profile dailylocally and ensure it passes. If your change touchesmoui_themeorexamples/design_systems, also runsh scripts/check.sh --profile theme. - Update the API surface when public API changes. Regenerate
pkg.generated.mbtiand confirmnode scripts/validate-api-surface.mjspasses. The maintenance baseline trackspub(all)counts and root facade forwarding counts; if your change moves those numbers, update the ratchet budget in the same PR. - Keep docs and guidance in sync. If your change affects workflow,
package layout, examples, or text/rendering boundaries, update
docs/,AGENTS.md, and the relevant files underskills/. The guidance consistency guard checks these surfaces. - Do not commit
artifacts/. Generated logs, screenshots, manifests, and benchmark scaffolds are disposable local or CI evidence. Release notes cite the CI run or smoke log instead. - Respect the maintenance baseline. If a change would grow a tracked
large file or ratchet counter past its
max, refactor to stay within the budget rather than bumpingmax, or justify the exception in the PR.
Manual smoke
Automated tests cover the bounded daily baseline. Real platform, browser, or
renderer claims require the smallest matching manual smoke — see
docs/testing.md and AGENTS.md. Cite the smoke log in the
PR description when the change touches rendering, native FFI, or host
behavior.
Commit and PR style
- Use Conventional Commits format:
type(scope): subject. Examples from the project history:feat(views): outline button uses surface tint, no foreground shiftfix(views): use lg shadow for floating layers in minimal themerefactor(theme): remove single-value compatibility aliasesfeat(core): thread ViewStyle through layout and event contexts
- Common
typevalues:feat,fix,refactor,docs,build,test,diagnostic. - Common
scopevalues:core,views,runtime,theme,backend,render,layout,build. - Keep the subject line lowercase and imperative.
Developer Certificate of Origin
MoUI uses a lightweight DCO. By submitting a pull request, you certify that
your contribution is your own original work (or that you have the right to
submit it under Apache-2.0) by adding a Signed-off-by line to your commits:
git commit -s
This adds Signed-off-by: Your Name <your.email@example.com> to the commit
message. Use your real name and the email associated with your GitHub
account. If a commit is missing the line, amend it before pushing.
The full text is the Developer Certificate of Origin v1.1.
Review process
- Open a PR against
main. Fill in the pull request template. - Maintainer review. The maintainer reviews against the architectural
invariants and the Review Checklist
in the package-boundary doc. Expect comments on package ownership, API
surface impact, and whether the change belongs in
corevsviewsvsruntime. - Architecturally sensitive changes — new top-level packages, runtime
pipeline changes,
corecontract changes, status-class reclassification — require a lightweight RFC (an issue taggedrfc) before code review. See GOVERNANCE.md. - Address feedback by pushing new commits (do not force-push over reviewed commits unless asked).
- Merge is at the maintainer's discretion, typically as a squash or
rebase to keep
mainlinear.
Reporting issues
- Bugs and feature requests: use the GitHub issue templates. Bug reports must include the platform × renderer matrix and the MoonBit toolchain version.
- Security vulnerabilities: do not open a public issue. Follow SECURITY.md for private disclosure.
- Questions and discussion: prefer GitHub Discussions or an issue tagged
question.
Questions about boundaries
When unsure where a change belongs, open a draft PR or an issue tagged
question and ask before implementing. A short conversation up front is
cheaper than reworking a PR that lands in the wrong package.