Contributing
Sending a change back to Vantage itself - where issues go, how branches and commits are written in this repository, what "verified" means before a merge request, what the pipeline checks, and the house rules the code keeps.
On this page
Vantage is MIT-licensed and its source is public on GitLab. Most people who change it should fork it and ship
their own; Fork it says why, and Forking says how. This page is for the other case: you have
fixed something or built something, and you would like it in Vantage itself. It describes how this repository
already does things, read from its history, its pipeline file and ARCHITECTURE.md, so that your merge request
reads like the rest of the log and passes the same checks.
Before you start
Vantage has one maintainer. A small fix can go straight to a merge request. For anything larger, such as a new feature, a new dependency or a change to how something is stored, open an issue first and describe what you want to do. Finding out that a change does not fit costs one message that way, rather than an evening.
Issues live on the project's GitLab page, at gitlab.com/Ekoss/vantage/-/issues. You need a GitLab account to open one, as with any GitLab project.
Getting the code
The default branch is main. Fork the project on GitLab, clone your fork, and work on a branch of your own:
git clone https://gitlab.com/<you>/vantage.git
cd vantage
git checkout -b fix/short-description-of-the-fix
./gradlew compileJava testYou need JDK 25 to run Gradle; Building has the details, and the one flag to remember when you build a jar.
Branches
A branch is named <type>/<short-kebab-description>. The type is drawn from the same vocabulary as commit
prefixes, so a reviewer scanning open merge requests knows the shape of the change before opening it. These are
real branches from the history:
| Branch | What it carried |
|---|---|
feat/waypoints-anywhere | Waypoints scoped by the world you are in, not by island |
fix/chat-click-actions | Chat lines that kept their click after a feature rewrote them |
feat/pathfinding-revamp | A new pathfinding engine |
polish/obsidian-glass | The Obsidian Glass interface |
fix/stats-2.0.1 | The Vantage Stats fixes of a patch release |
Branch from main and target main. A large piece of work may have a branch of its own that smaller branches
merge into first, as fix/stats-2.0.1 did, but you will rarely need that.
Commits
The subject
A subject is a lower-case area prefix, a colon, and a short lower-case line saying what the change does:
chat: keep the click when a feature rewrites a line
stats: one refused row no longer stops every upload, and the mod's own words pass its own filter
pathfinding: a new engine - real block shapes, searched off the client thread
features/mining: gemstone grinding efficiency and drill fuel burn rate
release: 2.0.1 for both targetsThe prefix names where the change lives or what kind of work it is:
| Kind of prefix | Examples from the log |
|---|---|
| A feature area, as its package path | features/mining, features/qol, features/combat |
| A subsystem | stats, ui, hud, chat, pathfinding, api |
| A kind of work | docs, build, tools, ci, refactor, chore, fix |
| The release routine | release, announce |
Some subjects are imperative ("keep the click…"); many name the result instead ("a new engine…", "2.0.1 for both targets"). Either reads well in a log. What they avoid is vagueness: "fixes" or "update" says nothing a reviewer can check.
The body
The body says why: what was broken, what you tried and rejected, and what you deliberately left alone. It is
fine for it to run to several paragraphs when the decision was not obvious. It ends with a paragraph that starts
Verified: and names the commands you ran and what they said, not "tested and works". Shortened, from the
commit that fixed chat clicks:
chat: keep the click when a feature rewrites a line
On Hypixel the click is the interaction. A party invite, a warp, the stash
pickup line and a duel accept are all a click on a chat line, so a rewrite
that drops the ClickEvent does not cost formatting - it turns a working
prompt into dead text, with nothing in the log to say why.
…
Verified: ./gradlew compileJava test clean on both targets (26.2, and
-Pminecraft_version=26.1.2), … ChatActionsTest builds the
component shape Hypixel actually sends - plain text with one clickable run
inside it - and pins that the legacy round trip loses the click, that
keepActions puts it back without touching the rewrite's text, …Merges
History keeps a branch's own commits and joins them to main with a merge commit. A merge made locally is
written merge: <branch> into <target>, for example merge: fix/stats-2.0.1 into main; one made on GitLab keeps
GitLab's own Merge branch '<branch>' into 'main'. Keep your branch's commits meaningful on their own, since they
stay in the log.
What "verified" means
Before you open a merge request, run these and keep their output:
./gradlew compileJava test # the default Minecraft version
./gradlew compileJava test -Pminecraft_version=26.1.2 # the other one
./gradlew runUiSmokeTest # then read run/screenshots/smoke-report.txt
python tools/tracker.py --checkThe pipeline compiles only the default Minecraft version, so the second line is yours to run. The smoke test's report, not its exit code, is the verdict, and as of 2.0.1 a healthy report lists exactly one expected line; Testing shows it.
Some changes owe one more check:
| If you changed | Also run |
|---|---|
| A feature's annotation, its options, a command or a key | python tools/tracker.py, python tools/tracker.py --catalog and python tools/sitedocs.py, then commit what they regenerate |
| A mixin | python tools/mixin_targets.py, after building each version once |
| Vantage Stats | python tools/stats_catalogue.py --check and python tools/stats_golden.py --check |
| Anything you can see | Open the screenshots; the menu-lit, gallery-lit and menu-ember frames show the light and a second preset |
| A feature id or an option's field name | Add a migration, because both are persistence keys; Options and config shows how |
Merge requests
The description
Write it in three parts, in the same voice as a commit body:
| Part | What goes in it |
|---|---|
| Why | The problem, not the patch: what was wrong that made the change necessary |
| What was verified | The commands you ran and what each said, the smoke-test report included |
| Risk | What could break, and what you deliberately left out of scope |
Mark an unfinished merge request as a draft by starting its title with Draft:. GitLab will not merge it until
the prefix is gone.
Linking issues
Write Closes #12 in the description to close issue 12 when the merge request is merged.
What the pipeline runs
A pipeline starts once the merge request exists. A branch with no merge request open runs nothing, so pushing early is quiet until you open one. On a merge request these jobs run:
| Job | What it checks | Fails the pipeline? |
|---|---|---|
compile | ./gradlew compileJava test on the default Minecraft version, with the test report shown on the merge request | Yes |
build-jar | ./gradlew build -PnoVersionBump; the jar and its checksum stay downloadable for 30 days, so a reviewer can try it | Yes |
tracker-current | The tracker check, then the regenerated docs/catalog.json diffed against yours | Yes |
sast, secret_detection | GitLab's scanners; findings show on the merge request as reports | No |
ui-smoke-test | The UI smoke test under a virtual display, only when someone starts it by hand | No |
The release jobs run only for version tags, and the Discord announcement job only on main. Testing
lists every job, and Releasing the ones that ship a build.
House rules
ARCHITECTURE.md opens with the ground rules every change is written against. Restated for someone new to the
code:
- Never guess a Minecraft or Fabric signature. Read the sources. Minecraft 26.x ships unobfuscated, so the names you read are the real ones; there are no mappings.
- Read other mods for facts, never for code. Skyblocker and SkyHanni are LGPL. Reading them to learn a chat message's format, an item's NBT keys or a room's data is fine; copying their code is not, because Vantage is MIT.
- Compile often, and leave no stub that throws. A change is not done until it compiles cleanly.
- Write Java 25. Records, sealed interfaces, pattern-matching
switch,varwhere the type is obvious, text blocks, virtual threads for blocking I/O,java.net.http.HttpClient. No Kotlin. - Keep a change inside its package. Every subsystem has a package of its own under
dev.cherishev.vantage. A diff that wanders into an unrelated one should say why. - Write player-facing text as plain English literals, not translation keys, unless it is a vanilla component.
- Mixins go in
mixin.<area>, listed in the matchingvantage.<area>.mixins.json. Prefer a Fabric API event where one exists. A widened member goes in both versions' access wideners; Multi-version explains why. - Touch Minecraft's state only on the client thread. Network and file I/O run on virtual threads and post their results back.
- The Minecraft access token has exactly one call site, in
core/stats/sync/IdentityProof.java, where it goes straight to Mojang.grep -rn "getAccessToken\|getSessionId" src/main/javamust print one line. This is a release gate.
A few more come up in review often enough to know in advance:
- A feature is one file. The
@FeatureInfoannotation registers it; never add a hand-writtenregister(new X())line to an area'sXFeatures.register(), which is only for that area's shared setup. Writing a feature covers the annotation. - Use
core.util.Timerfor cooldowns and debounces, notSystem.currentTimeMillis(). The wall clock is right only for a timestamp that is saved, compared with Hypixel's, shown as a date or time, or read across threads. - A chat line the mod rewrites keeps its click. On Hypixel the click is the interaction;
TextUtils.keepActionsand a unit test guard it. - Visual work follows the glass contract,
docs/design/liquid-glass.md. The UI toolkit is the guided tour.
Your contribution's licence
Vantage is released under the MIT licence, with the copyright line Copyright (c) 2026 CherishEv. The repository
has no contributor agreement and no separate terms for contributions, and this page does not add any. If the
terms under which your change is merged matter to you, say so in the merge request before it is merged.
Whatever you send has to be yours to give: code you wrote, or code under a licence that allows it. That is the same reason rule 2 exists.
Related
- Forking: taking the code and making it yours, which is usually the better road.
- Testing: every check behind "verified", and what CI runs.
- Architecture: where things live before you change them.
- Writing a feature: the annotation, the lifecycle and the build's checks.