🤖 Agent: Mod API capability `command` and the Predator Missile example, by @sdraeger. Thank you! Main merged in, with `command` kept beside `ui` as a 0.1 preview interface. Verified: pr_ready (2106 workspace tests), and in game in-frame and on the server thread, including survival without cheats refused.
Conflicts kept both sides: the capability list (now 7), the WIT, the
SDK's re-exports and docs, the mods state's fields, the workspace
members and AGENTS.md's macOS --exclude list. The API reference is
regenerated, and docs/api/stability.md lists `command` with the 0.1
preview interfaces.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🤖 Agent: verified: OUTPUT_VERSION = 1 and output-versions.txt carry the digest measured on 10 CI preparations. tools/prepare_output.py check passes on v0.2.64's preparation and fails on v0.2.47's. This head's own parity job prepares with its preparer and checks the digest. Merging.
parity-main runs the vanilla harnesses on every push to main, one run at a
time: merges that land during a run wait in one pending run, which checks
every merge since main's last green parity-main (tools/parity_main.py base,
then parity.py --changed). A failure is bisected over the batch's
first-parent merges, running only the failing harnesses, and the breaking
merge's pull request gets a comment.
Game releases ship only a commit both checks and parity-main passed on
(release_train.py; release.yml also starts when parity-main finishes; a
forced release doesn't wait). The per-PR parity job now runs only for a PR
that changes a harness, an oracle, a probe or the runner, or carries
run-parity.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The parity job checks out the PR head, so every branch made before #1964
still selected with the old per-crate rule. The step now runs main's
tools/parity.py and tools/parity_reach.py with --changed --list, restores the
head's files, and runs the named harnesses with the head's parity.py. A
branch that edits either file, or a failure of main's selection, falls back
to the head's own `--changed` run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`--changed` / `--changed-files` now narrow each harness's recorded Rust
sources to those its probes can reach (tools/parity_reach.py): an item-level
reachability walk from the probe modules a harness ran (or the binary it
built) over free items, inherent methods, trait impls and macros, matched by
name so it only over-approximates. Parent modules count through their `mod`
declarations, compared with the merge base. A harness whose probe can't be
placed keeps every source; `--by-crate` turns the narrowing off.
On the last 20 PRs merged on 2026-10-25: 2255 -> 1061 harnesses picked,
2384 -> 1592 harness-minutes. Replaying the week's 61 failed CI parity runs,
every failed harness the old selection picked is still picked; LLVM coverage of
six harnesses' probes executes only kept files.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Launchers copy a player's prepared resources to a new release while its preparer declares the
same OUTPUT_VERSION (the launcher side is its own pull request). The number is bumped by hand;
CI keeps it honest: the parity job already prepares with every change to the preparer, and
tools/prepare_output.py check now fails when that preparation's digest is not the one
crates/horizon-prepare/output-versions.txt gives the current number, or when the file changed
other than by appending a version. The digest canonicalises what differs between two runs of
the same preparer (JSON key order, creative tab tag order, lambda class addresses, logs, the
sounds): 10 preparations by 5 preparer versions on the three Mac runners give one digest, and a Linux preparation by an older preparer gives the Mac runners' digest for it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🤖 Agent: thank you @socksprox! Merged after review (two follow-up commits on your branch: `ui` is opt-in through `experimental = ["ui"]`, and the Settings button now appears when a mod sets its page after loading), tests in game in-frame, on a server-thread window and as a LAN guest, and this head's verify.
docs/api/stability.md: a new API starts experimental, usable only by
opting in with a manifest field naming it. Capability ui now needs
experimental = ["ui"] beside capabilities; without it the manifest is
refused with that line to add. A capability promoted later stays
accepted in the list, so such manifests keep loading.
The ui test guest opts in; stability.md gets ui's row; docs/mods.md
shows the key.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New WIT interface `ui` (text, item and list widgets; open-screen,
close-screen, set-settings) plus a `ui-events` export (select, closed,
settings-opened), in a second world `horizon-ui-mod` so mods built before
it keep loading. The game lays out and draws the widgets with its own
menus' code: a screen the mod owns (Esc/Done to leave) and a Settings
button on the mod's Options > Mods row that opens its page.
Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
🤖 Agent: merged after verify passed (hub: website tests 30/30, roadmap tests + sync check, telemetry server 35 tests; local end-to-end run by roadmap-1).
- `new --template content`: a content mod with one block (Glowing Amethyst,
copying vanilla's amethyst block) and its block state, model, item model,
name, loot, recipe and pickaxe tag; `--template code` is the default.
- `build` packs the mod's `assets/` and `data/` (read and checked as the
game reads them) beside the component; a folder without `Cargo.toml` is a
content mod and needs no compiler.
- `check` takes a `.hmod` with no `mod.wasm`: "no code: content only,
nothing to run" instead of the trial run, which refused it, so the
registry can publish content mods.
- The guide (content mods, make a mod) and docs/mods.md, docs/api/mods.md
say so.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Six pages under a "Make a mod" group of the docs: set up and see a mod in
the game (the launcher's Game arguments or cargo horizon-mod run), the
manifest and every capability, the hooks and calls with a worked example
(Playtime, built and checked), content mods, testing and check, and
publishing (minisign signing, the submit form, review, updates). /mods,
the submit page, the docs index, Mods and data packs and the Mod API link
to it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Where to start is playhorizon.dev/hub: the roadmap, the work board, good first
tasks and the forms; roadmap PRs carry their roadmap:<id> label, ideas go to the
suggestion queue and issues are for bugs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The repository's docs/api/ (the portal, its surface pages and the generated mod and
server references) is built into the docs section: /docs/api is its README and
/docs/api/<page> each page, in two nav groups, "Build on Horizon" and "API reference".
The pages are read from the checkout or from main on GitHub, like the README, so the
site never holds a copy. Links between portal pages become the site's (and the build's
link check covers them); other relative links go to the file on GitHub.
The renderer gains tables: the "Ways in" table, the references and the other tables
on the site (apis, performance) showed as raw pipes. A link whose label is a code span
no longer throws.
Caddy and the dev server route /docs/api/<page> and redirect /docs/api/ to /docs/api;
Railway rebuilds when docs/api/ changes. /docs/mods links the Mod API, its reference
and its ways in; the summary page is now "APIs at a glance".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🤖 Agent: merged after verify passed; mod-registry-land-1's combined check (pr_ready --quick on all seven, launcher tests 125, website 25/25, no harness affected) and live end-to-end on horizon-mods.
🤖 Agent: merged after verify passed; mod-registry-land-1's combined check (pr_ready --quick on all seven, launcher tests 125, website 25/25, no harness affected) and live end-to-end on horizon-mods.
🤖 Agent: merged after verify passed; mod-registry-land-1's combined check (pr_ready --quick on all seven, launcher tests 125, website 25/25, no harness affected) and live end-to-end on horizon-mods.
The SDK's tool, in horizon-shader-api: `horizon-shader new <dir> --template
post|sky|material` makes a pack that passes the check, `check <pack>...
[--json]` runs the check the game, the launcher and the registry run and
prints each stage's cost and the pack's SHA-256 or every problem at its
file:line:column, and `pack <dir>` checks then writes the reproducible
.hshader. Golden Hour, the example pack, warms the sky around a low sun and
adds a soft glow and a colour grade, with five options. docs/shaders.md is the
authors' guide.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
horizon_shader_api::check builds each stage as the renderer does and judges
it the same way wherever it runs (the game, the launcher, the registry's CI,
the coming horizon-shader tool): naga parses and validates it; the stage
function must have its signature; the pack's files declare no bindings, no
entry points and no horizon_ names; each override is an option of its type or
has a default, and each option is used; a stage stays within 20 000
expressions and 64 texture reads; and every entry point translates to SPIR-V,
Metal and HLSL with the options at their defaults, minimums and maximums.
Problems carry the pack's own file, line and column. Pack::sha256 gives the
reproducible package's hash.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Three stages, each a WGSL function with a fixed signature that Horizon calls
inside its own pass: sky (fn sky(input: SkyInput) -> vec4<f32>), material
(fn material(input: MaterialInput) -> Surface) and post (fn post(input:
PostInput) -> vec4<f32>). A stage's WGSL is a generated prelude (the frame
uniform, the stage's structs, its resources in bind group 3, the post
helpers), the pack's shared files, its own file, then the entry points; each
part is located so errors point at the pack's file and line.
The frame is the Rust struct the renderer will upload; its WGSL, its offsets
and docs/api/shaders-reference.md are generated from it, and tests check that
the preludes compile, that naga's layout of the WGSL is the Rust layout, that
the sample pack's stages compile, and that the reference is up to date.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A new crate, horizon-shader-api, reads and checks Horizon's own WGSL shader
packs (docs/api/shaders.md), so the game, the launcher and the registry judge
a pack the same way. This first part is the format: the manifest (id, name,
version, the api line, shared files, the sky, material and post stages,
options typed for WGSL override constants, a GPU time budget) and the package
(a folder or a .hshader zip, built reproducibly so its SHA-256 depends only on
its files). The stages' WGSL is checked in the next parts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs/mods.md gets "Publish your mod" (the form, the review, updates) and
its Distribution section points at the registry instead of the plan for
it. docs/api/mod-index.md says how horizon-mods runs: its checks, merging,
Pages, the weekly cleanup, and that removing an entry needs an admin merge
(takedowns go in revoked.toml). The service's README says where it runs on
Railway.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each frame the game hands the presence thread its status (menus; single
player, multiplayer or hosting a world with its party size; the
dimension; the game mode), and only a change wakes it. The switch
"Discord Rich Presence" (on by default, discordPresence in
horizon-extras.txt) sits beside Controller Settings. Dedicated servers
never start it. tools/discord_presence_e2e.py runs real games against a
fake Discord: title, world, Nether and quit on the server thread and
in-frame, a LAN host (both paths) and guest, the switch, and a Discord
started after the game.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GitHub's "Latest release" is the newest game release, so new players download the game's archive, which
does not start on its own (#1647). Making a launcher release the latest instead would break every
installed horizon-server, install.sh and install.ps1: they ask for releases/latest and expect the game's
archives, and a server that can't update can't fetch a fix either. So the game stays the latest and says
where to go:
- The notes open with "Want to play? Download the Horizon launcher, not the files below", linking
playhorizon.dev and the launcher releases. It is raw HTML on one line, which GitHub renders and the
launcher's notes view and one-line summary skip (pulldown-cmark HTML events), so launchers already
installed don't tell players to download themselves. The game footer that said the same at the bottom
goes. The site's Releases page leaves the block out.
- release.yml gives each archive a label ("Game files the launcher installs: Linux (...)", "Dedicated
server for Linux (...)"), which GitHub shows instead of the file name. Everything that downloads
matches the asset's name, which is unchanged.
Fixes#1647
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Separate client, integrated-server and dedicated-server roles from connection state. Use roles for startup, presentation work and server dimension loading while preserving in-frame client simulation.
Co-Authored-By: OpenAI Codex (GPT-6.1) <noreply@openai.com>
New players ask on Discord whether Horizon is legit and whether it is vibecoded. One plain page answers
both, every claim checked against the repository today: agents write most of the code, what checks it
instead of a human reading every line (harnesses, verify, parity, the contribution gate, the release
smoke test), signed checksums, the macOS and Windows signing status as it is (not notarized, not
code-signed), the mod sandbox, opt-in telemetry, no Mojang files and no other project's code.
On the website (docs nav under Start here, a card in the home page's community section, the footers) and
as docs/how-horizon-is-built.md. CONTRIBUTING.md gets the public "Only original code" rule the page links.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>