🤖 Agent: merged after verify passed and the agent-control-2 integration of all six PRs on the Mac mini. agent_control_e2e passes in CLI and MCP (one known survival flake), launcher_mcp_e2e passes, No AI is refused, and the options, screen_layout, menu_click and world_options parity harnesses pass. Ludovic asked for this on 2026-10-23.
🤖 Agent: merged after verify passed and the agent-control-2 integration of all six PRs on the Mac mini. agent_control_e2e passes in CLI and MCP (one known survival flake), launcher_mcp_e2e passes, No AI is refused, and the options, screen_layout, menu_click and world_options parity harnesses pass. Ludovic asked for this on 2026-10-23.
🤖 Agent: merged after verify passed. Ludovic asked on 2026-10-23 for every hardware fact players send (opt-in). The end-to-end run against a local server is in the description: breakdowns need ≥3 installs, with no install ID or exact value. The consent version goes up to 2, so players who opted in are asked again, as the privacy page promises.
website/docs/agents.md, in the nav under "Going further", is the player's page.
It covers what an agent can do, connecting it from the launcher, copy-paste
config for Claude Code, Codex, Cursor and any MCP client, the game's AI Agent
page, a CLI quick reference, safety and No AI.
docs/agent-control.md is rewritten for developers:
- the surfaces, and why one MCP server covers the launcher and the game;
- the inventory, before and after, for the launcher and the game;
- No AI on every surface, and the launcher commands that stay;
- connecting from the launcher and the game;
- the design rules for a new command.
docs/launcher-commands.md lists every launcher command, its arguments and its
MCP tool. It is generated from the clap definition (cli_tools::markdown). The
launcher test the_launcher_reference_is_up_to_date fails when it is stale or a
tool is undocumented, like horizon-ctl's generated reference.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The table gains what only the raw socket could do (options pages, connect
and invite codes, disconnect, LAN, Play with Friends, books, signs, mount
inventories, effects, xp, enchant, potion, fill, containers) and new
commands: worlds, world-rename, world-backup, world-delete --confirm (the
Select and Edit World screens, from the title screen only), servers (the
Multiplayer list) and interact-entity (right-click an entity). status,
mouse, pad, release, bench and stats become MCP tools; summon takes a
position. Destructive and network tools carry MCP annotations.
docs/horizon-ctl-commands.md is generated from the table
(horizon-ctl help --markdown) and a test fails when it drifts. The
agent_control_e2e manage scenario exercises the new commands.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What players send (opt-in, unchanged switches) now describes the whole machine:
CPU cores and base/boost clock, the GPU's maker, integrated or discrete and its
VRAM, the drive under the game folder (NVMe/SSD/HDD), the screen (size, refresh,
scale), on battery or mains, laptop or desktop. Perf, crash and bug items carry
them in `system`; benchmark reports in `hardware`. No serials, host or user
names, or paths. CONSENT_VERSION goes to 2, so players are asked again.
The server keeps the new fields in `systems.extra` (the table is rebuilt once
on old databases, ids kept). /v1/aggregate and /v1/benchmarks/summary add
breakdowns by RAM class, VRAM class, drive, OS and integrated/discrete GPU;
a class is published only with at least 3 different installs, never a raw value.
website/scripts/benchmarks.mjs mirrors the classes on the shared fixtures.
The summary's "not Horizon or plain vanilla" check returned None (accepted)
instead of the rejection; it now matches the site's script.
The launcher's "View what would be sent" and `data show` list every field.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
🤖 Agent: merged after verify passed and the integration run on the desktop (integ-w3: main + the mod browser stack + #1269; fmt, clippy, 1224 + 131 tests, mod_browser_harness ok).
🤖 Agent: merged after verify passed and the integration run on the desktop (integ-w3: main + the mod browser stack + #1269; fmt, clippy, 1224 + 131 tests, mod_browser_harness ok).
🤖 Agent: merged after verify passed and the integration run on the desktop (integ-w3: main + the mod browser stack + #1269; fmt, clippy, 1224 + 131 tests, mod_browser_harness ok).
🤖 Agent: merged after verify passed and the integration run on the desktop (integ-w3: main + the mod browser stack + #1269; fmt, clippy, 1224 + 131 tests, mod_browser_harness ok).
🤖 Agent: merged after verify passed and the integration run on the desktop (integ-w3: main + the mod browser stack + #1269; fmt, clippy, 1224 + 131 tests, mod_browser_harness ok).
🤖 Agent: merged after verify passed. telemetry.playhorizon.dev is live on Railway (service telemetry in horizon-site, volume /data): /healthz, /v1/live (a test ping counted) and /v1/benchmarks/summary (CORS for playhorizon.dev) answer. The PR's local end-to-end runs are in the description.
launcher/src/main.rs: main (#1271) removed the Game menus setting (one menu
style now) where this branch restyled Settings. Kept the Game and About
group headings, dropped the Game menus row as main does, and renumbered the
rows after it (game arguments n+4, Horizon n+5, Launcher n+6).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts: the menu blur (#1249) now runs without the Horizon style check,
chat and the tab list draw under every screen as before the blur split,
and the HUD's second range draws without the removed colour grade. Play
with Friends blurs the world behind it like vanilla's other menus.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- DEFAULT_ENDPOINT is https://telemetry.playhorizon.dev. The heartbeat, the launcher's live count and the
outbox upload all go there; HORIZON_TELEMETRY_URL still names another server, and HORIZON_TELEMETRY_URL=off
sends nothing at all. CI workflows and the harnesses that start the game or the launcher set off. Consent
is unchanged: the four switches stay opt-in, only the anonymous ping is always on.
- GET /v1/benchmarks/summary: players' benchmark uploads grouped by GPU, CPU, render distance and game, groups
of 3+ installs only, medians per install then across installs, no install ID, day, OS version, driver,
memory or screen. Cached 10 minutes, CORS for the website. Same rules as website/scripts/benchmarks.mjs,
tested on the same fixtures; a deleted install leaves its groups at once.
- /v1/aggregate no longer lists the newest 50 raw benchmark reports (hardware, driver, day, one install each):
uploads are published only through the summary.
- Behind Railway's proxy the rate limit counts X-Real-IP, else the last X-Forwarded-For entry (the one the
proxy adds; a client could choose the first). Still in memory only, never stored or logged.
- crates/horizon-telemetry-server/railway.json: Dockerfile build from the repository root, health check
/healthz, one replica in europe-west4 (one SQLite file on the /data volume).
- Docs: docs/telemetry.md, the server README (the summary's shape, Railway setup), the privacy page (the ping
is on, where the data lives, how benchmark uploads are shown).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Captured on the Mac mini with the game's offscreen capture (1280x720),
replacing the Horizon menu style's Video page.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The pause menu's Friends icon is recorded as a widget, so a controller
reaches it and the control socket names it. The sharing screen's long help
URL ran off the screen: a Troubleshooting... button beside Done opens it,
and the hint drops out when it would reach the footer. The graphics docs
say what the two Horizon screens hold (vanilla's own settings stay on Video
Settings).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Drop the Horizon menu style (options_horizon.rs, front.rs, the live title
backdrop and its post grade, the launcher's menu-style setting, CLI and MCP
tool). Every screen is vanilla's. Horizon's own settings hang off vanilla's
Options the way mods add theirs: Horizon Settings... and Mods... take the
Telemetry/Credits slots, and Horizon Settings opens Graphics, Advanced
Graphics, Shader Packs, Controller Settings, Extras and Mods, each a vanilla
options list with tooltips. Play with friends moves behind vanilla's Friends
buttons: the pause menu's opens Play with Friends (share, copy, stop), the
title screen's opens Join a Friend, and Direct Connection takes a full code.
Old files load as before: horizon.txt's menuStyle line and
horizon-graphics.txt's level line are ignored.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Blocks palettes (dark default, light, or the system's, chosen in Settings), Pixelify Sans for
headings and controls, Pixelarticons icons, square panels with an outline, a bevel and a lip,
inventory tabs, and pixel art drawn in code: a stone texture behind the pages and a landscape
behind Home. A top bar with the pages and the account chip, and a sidebar with the instances
(Horizon shows the grass block the mod browser draws from the player's prepared textures), the
hosted servers, and the launcher's version and channel. The mod browser's pages (kinds as tabs,
project icons in slots, verdicts as badges, the project page) are restyled, not rebuilt. The
benchmark also measures scrolling the Versions list.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
horizon-theme gains the Blocks palettes (light and dark, WCAG AA on every panel and on the stone),
Pixelify Sans (OFL) and Pixelarticons (MIT); tokens.css now carries the Blocks colours, the pixel
font and the block edges. The site sets headings, navigation and buttons in Pixelify Sans, turns
the index lists into stacks of panels with an outline, a bevel and a lip, puts a stone texture
behind the page and Horizon's pixel landscape (a dawn or a sunset) behind the hero, both drawn in
code by scripts/art.mjs. Light and dark still follow the system, with the toggle.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The pack lists them with the mods left off, the port's log and fetch label say
the same, and docs/modpacks.md no longer asks for a key.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Importing a modpack from the Mods page (or `mods install`) now ports it right away
for the selected version, so Play works straight after. port-pack leaves a
namespace two carried mods both claim to none of them (YUNG's mods all ship
`yungsapi`, which made the game drop three of them), and the launcher applies
the game's first-wins rule before it starts a pack, listing what it left off.
Measured on Vanilla Perfected, Slimes Adventure and All the Mods 10 (docs/modpacks.md):
2, 20 and 42 mods ported, every world loads, no crash.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
mod_browser_harness.py searches, checks and installs a mod through the launcher's
mods CLI in a scratch game folder, opens a world with it offscreen, places one of
its blocks and crafts one of its recipes on a crafting table, and times the world
load with and without it. Macaw's Fences: check 4.0 s, install 3.1 s, world load
5.4 s -> 7.3 s, hedge placed, 4 crafted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A result's title opens its page in the launcher: icon, authors, downloads,
followers, licence, verdict (for a Java mod, what ports and what doesn't) and
Install, links, then Description (Markdown), Gallery and Versions tabs
(browser::details, Source::details on Modrinth's project and members).
Filters: sort (relevance, downloads, follows, newest, updated), loader, game
version, environment and categories, from the source's tag lists.
Icons and gallery images are fetched at run time over HTTPS from the sources'
image CDNs only, size-capped, decoded and scaled to PNGs in a 128 MB disk cache
(browser::images); a placeholder shows until they arrive. Vanilla's mark is a
grass block drawn from the player's prepared game files. Modrinth's logo isn't
shown: its branding is all rights reserved without written permission.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ludovic dropped CurseForge for now (its API needs a paid key). The Mods page shows
"CurseForge (coming soon)" beside the Modrinth switch, disabled and inert;
browser::sources() is Modrinth only, so no search or install goes to CurseForge,
and `--source curseforge` says it is coming soon. Text that asked for a key or
an environment variable now says CurseForge support is coming soon. Importing a
CurseForge zip or instance still works; jars only CurseForge serves are listed
as "CurseForge downloads coming soon".
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Mods page gets a Mods tab: Fabric, NeoForge, Forge and Quilt mods for 26.3
(1.21 and later with Show everything). Each result's jar is downloaded (allowed
CDNs, checksum), checked with horizon-port-pack (Works, Partly, Doesn't run, with
what ports and what doesn't) and the answer cached per file. Install copies the
carry into horizon-mods/<id>/ and turns it on in horizon-mods.txt, with required
mods that port; libraries with nothing to port are listed as not ported; id or
namespace clashes are refused. Remove deletes it and turns it off.
The Modpacks page becomes the Mods page's Modpacks tab: imported packs first,
then the search. CLI: mods search --kind mod, mods check <project>.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`horizon-port-pack check <jar> <out>` carries a single jar into a folder content
mod and reads its class files (constant pool, superclass, declared methods) for
what the carry can't take: block entities, menus, entities, blocks and items with
behaviour of their own, recipe types, worldgen code, Mixins, game events. The
verdict and the lists of what ports and what is skipped go to check.json, for the
launcher's mod browser to show before install.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The whole of Horizon is in beta, so the channel that installs every build as
soon as it is built is called Alpha; Stable keeps its name. The launcher's
Settings, the update-channel command, the MCP tool, the release notes footer
and the docs say Alpha. update_channel is saved as "alpha"; "nightly" and the
old beta_builds switch still read as Alpha.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
🤖 Agent: merged. Nightly/Stable update channels (Ludovic's request 2026-10-22): Settings choice, nightly train 5/20 min, one stable promotion a day at 20:00 UTC, Nightly launchers check every 30 min. verify passes on b197682d (main merged in: Settings keeps update_channel and #1185's ping_notice_seen). Ships in launcher@0.2.0; launcher.yml stays disabled until #1132.
🤖 Agent: merged after integration wave 2 on the desktop (integ/w2 @ 38307d15 = main c16b41ab + this wave): fmt, clippy -D warnings, workspace + launcher + telemetry-server tests, release build and every affected parity harness pass; the 3 harness failures and the panel test passed on rerun (known flakes).
🤖 Agent: merged after integration wave 2 on the desktop (integ/w2 @ 38307d15 = main c16b41ab + this wave): fmt, clippy -D warnings, workspace + launcher + telemetry-server tests, release build and every affected parity harness pass; the 3 harness failures and the panel test passed on rerun (known flakes).
🤖 Agent: merged after integration wave 2 on the desktop (integ/w2 @ 38307d15 = main c16b41ab + this wave): fmt, clippy -D warnings, workspace + launcher + telemetry-server tests, release build and every affected parity harness pass; the 3 harness failures and the panel test passed on rerun (known flakes).
🤖 Agent: merged after integration wave 2 on the desktop (integ/w2 @ 38307d15 = main c16b41ab + this wave): fmt, clippy -D warnings, workspace + launcher + telemetry-server tests, release build and every affected parity harness pass; the 3 harness failures and the panel test passed on rerun (known flakes).
🤖 Agent: merged after integration wave 2 on the desktop (integ/w2 @ 38307d15 = main c16b41ab + this wave): fmt, clippy -D warnings, workspace + launcher + telemetry-server tests, release build and every affected parity harness pass; the 3 harness failures and the panel test passed on rerun (known flakes).