One entry per merged pull request (with its roadmap item), game or launcher release, shipped roadmap item (post and announce) and weekly summary, newest first, ids stable forever: the feed kira's src/journal.js posts to #updates and X. The journal's item links are hub#<id>; the board's and the journal's ids are reserved too, and the page-wide unique-id test covers every tab. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The roadmap
roadmap.toml is the one source of the roadmap. tools/roadmap.py build turns it into
ROADMAP.md; the website's hub (playhorizon.dev/hub) and Kira read the same items. The work
board stays the task-level view (every issue and pull request); the roadmap is the overview, and each pull
request carries the roadmap:<id> label of the item it moves.
An item
[[item]]
id = "server-dialogs" # lowercase words joined by dashes; never renamed (votes and links use it)
title = "Server dialogs and login screens"
status = "now" # now | next | later | help-wanted | shipped
area = "servers" # one of the [[area]] ids, listed in the order of priority
focus = true # optional: one of the 3 to 5 Now items in the overview
ongoing = true # optional: a workstream that goes on after its pull requests merge
plain = """Servers that show dialogs ... will work in Horizon.""" # players' words, at most 240 characters
dev = """26.3's dialog packets and model (#1720), ...""" # crates, approach, what is left
links = ["#1720", "#1734", "docs/hosting.md"] # #N, a repository path, or https://
shipped_in = "v0.2.58" # shipped items only: a game tag, launcher@x.y.z, or "website"
post = "..." # optional: the announcement when it ships, if `plain` doesn't read as one
announce = true # optional: when it ships, Kira also posts it on X (`post`, else `plain`)
- No dates, ever: Now, Next, Later. The check rejects month names, years, quarters and "next week". "Coming soon" is the only phrase for something waiting on someone else (Microsoft sign-in, CurseForge).
- Only what is decided. Ideas stay in issues and in the suggestion queue until they are.
- Only what is true in a release for shipped items: a merged pull request isn't shipped until a release has it.
plainis for players: what they will be able to do, not how.devis for contributors: the code, the vanilla classes, the pull requests, what is left. Both stay public: no machines, accounts or private notes.- Help wanted items are good first contributions: a clear vanilla behaviour, an issue with steps, a place to
start in
dev.
Keeping it current
Whoever moves the work (the orchestrator on each heartbeat, or anyone in their pull request):
python3 tools/roadmap.py sync: every item whose linked pull requests all went out in a release, whose linked issues are all closed and that isn'tongoingbecomesshipped, with that release inshipped_in, on top of the shipped items. It rewritesroadmap.tomland ROADMAP.md; open a pull request with the change (skip-release).python3 tools/roadmap.py check: the file's rules, then GitHub's state of every link. It fails when a link is not an issue or pull request, when a Now item has no open pull request and none merged in the last 14 days (link the new work, or move it to Next or Later), and when every link of a Help wanted item is closed. It also says which itemssyncwill ship once a release has them.- When work starts, opens a pull request or is decided: add or move the item, add its links, then
python3 tools/roadmap.py build. Keep the overview's focus to the 3 to 5 biggest Now items. python3 tools/roadmap.py labels(after the change merges): creates aroadmap:<id>label for each new item, updates their colour (by status) and description, and adds the label to the open pull requests an item links. Label a new pull request for an item by hand or by linking it and runninglabelsagain. Labels of removed items are listed, never deleted.- Once a week, write the week's summary in
roadmap/journal/<year>-<ISO week>.md(for example2026-43.md):# Title, a paragraph or two for players, then## Technicaland the same week for contributors, with its pull requests.buildputs it into website/data/roadmap.json; the hub's Journal tab shows it among the releases, and/data/journal.jsoncarries it to Kira's #updates and to X. - Suggestions from the website and Discord are read and triaged by the maintainers. A good one becomes an item in a normal pull request; none is published automatically.
CI runs tests/test_roadmap.py (in the Python tests), which fails when ROADMAP.md is not what build writes
or when the file breaks a rule; python3 tools/roadmap.py check --offline runs the same rules without GitHub.
The journal
The hub's Journal tab and https://playhorizon.dev/data/journal.json are built with each deploy of the website
(website/src/hub.js). The tab shows every game and launcher release with its notes' changes, each placed under
the roadmap item it moves (the pull request's roadmap:<id> label, else the item that links it), the merged pull
requests no release has yet, and the weekly summaries above.
journal.json is what Kira reads for #updates and its X posts (kira's src/journal.js): one flat entry per
merged pull request, release, shipped item and weekly summary, newest first, the latest 300.
{ "format": "horizon-journal", "version": 2, "generated": "…", "url": "https://playhorizon.dev/hub#journal",
"entries": [
{ "id": "pr-1788", "kind": "merge", "date": "…", "title": "the pull request's title", "url": "…",
"number": 1788, "item": "discord-presence", "item_title": "Discord Rich Presence" },
{ "id": "release-v0.2.57", "kind": "release", "date": "…", "title": "…", "plain": "one line", "url": "…",
"tag": "v0.2.57" },
{ "id": "shipped-server-resource-packs", "kind": "shipped", "date": "the release's", "title": "…",
"plain": "…", "url": "https://playhorizon.dev/hub#server-resource-packs", "item": "…", "item_title": "…",
"shipped_in": "v0.2.48", "post": "at most 240 characters", "announce": false },
{ "id": "weekly-2026-43", "kind": "weekly", "date": "the week's last second", "title": "…", "plain": "…",
"dev": "…", "url": "https://playhorizon.dev/hub#week-2026-43" } ] }
- An
idnever changes: readers post each one once.mergeentries are the pull requests players see (noskip-releaselabel), plus any that moves a roadmap item;itemis absent when none does. announce: true(the item'sannouncekey) asks Kira to post the shipped item on X too, withpost.https://playhorizon.dev/data/roadmap.jsonisroadmap.tomlas JSON (areas,itemswith every key above,overview, the weekly summaries); an item's page ishttps://playhorizon.dev/hub#<id>.