Contributing to UrsaMU
Thanks for your interest in contributing to UrsaMU. This page captures the
ground rules for v2.6.0.
Prerequisites
Initial Setup
git clone https://github.com/lcanady/ursamu.git
cd ursamu
deno task test # confirm clean baseline
If you plan to send PRs, fork on GitHub and add your fork as origin,
keeping upstream pointed at lcanady/ursamu.
Branching
Always work on a topic branch off main:
git fetch upstream
git checkout -b feature/short-description upstream/main
There is no long-lived develop branch — main is the release line.
Pre-Commit Gauntlet
Run these four steps in order before every commit. They mirror CI:
deno check --unstable-kv mod.ts
deno lint
deno test tests/ --allow-all --unstable-kv --no-check
deno test tests/security_*.test.ts --allow-all --unstable-kv --no-check
A commit isn’t ready until all four pass.
Docs Stay in Sync
If you touch a public API, command, config key, script, scaffold output, or
plugin surface — update README.md and the relevant page under docs/ in the
same commit. Stale docs ship as broken docs.
Commits
- Write descriptive, present-tense subject lines:
feat:,fix:,docs:,chore:,refactor:,test:. - One logical change per commit.
- No AI/Claude attribution. Do not add
Co-Authored-By: Claude …, do not
reference AI tools in commit messages, PR descriptions, or code comments. - Never amend a commit that failed a pre-commit hook — fix and create a new
commit instead.
Pull Requests
- Push your branch to your fork.
- Open a PR against
lcanady/ursamu:main. - Keep PRs scoped — one feature or fix per PR.
- Fill in the description: what changed, why, and how it was tested.
- Make sure CI is green.
PRs are squash-merged. After merge, maintainers tag the release:
git tag v<version>
git push --tags
No AI attribution in PR titles or bodies either.
Coding Standards
- TypeScript only. Follow the
Deno style guide. - Early return over nested conditionals.
- No function longer than ~50 lines; no file longer than ~200 lines — decompose.
catch (e: unknown)— never barecatch.- Library-first: if the SDK does it, use the SDK.
- No comments unless the why is non-obvious (hidden invariant, bug workaround).
Testing
- All new commands need tests in
tests/. - See Testing for
mockPlayer/mockUhelpers and DB
cleanup conventions.
Plugin Audit Checklist
Mental pass before opening a PR that touches plugins or core commands:
u.util.stripSubs()on user strings before DB ops or length checksawait u.canEdit(u.me, target)before modifying any object not owned byu.me- DB writes use
"$set"/"$inc"/"$unset"/"$push"— never raw overwrite u.util.target()result null-checked- Admin-only paths gate on
u.me.flagsexplicitly system/scripts/files use no Deno APIs, nofetch, no non-uglobals- All
%c*color codes closed with%cn gameHooks.on()ininit()paired withgameHooks.off()inremove()(same named ref)- DBO collection names prefixed with
<pluginName>. - REST handlers return 401 before any work when
userIdis null init()returnstrue
Getting Help
- File an issue on GitHub
- Join the Discord linked from the project README
- Reach out to maintainers in the PR thread