The app roster — about a dozen launcher apps

Maintainer, 2026-10-10 (binding for this phase):

This page records phase 2 of the plan in Apps live on the instance (Store/AppsOnTheInstance, §6 and §8). Phase 2 changes only declarations: app, hostedIn, extensionSlot, tier and display names. It copies no app data into anyone's home. The launcher still reads the _App records until phase 1a's AppDirectory is switched on, so until then the existing install machinery does what it always does with these declarations:

The roster

Only these packages may declare app: true. The literal set is APP_ROSTER in scripts/validate-repos.py; adding a tile is a reviewed one-line change to it.

App Package Notes
Threads AI providers and harnesses are hosted in AI/AiThreads
Learning Edu courses, the learning roadmap and the tours (host Edu/Courses)
Feedback Feedback
Examples Developer shown as Examples; the id and path stay Developer so every hosted path stays put
Approvals Approvals
Expenses Expenses
Signature Signature keeps hostedIn: {user}/Settings (signingAuthority) for the signing-authority tab, so the per-user record path (Localizer.ShouldRegisterApp) still mints no tile for it; AppDirectory reads app: true
Personal Personal (new) free; host Personal/Home; preInstalled (see below)
Games Games (new) personal tier; host Games/Home; preInstalled (see below)

Satellite repos carry their own roster: SocialMedia, Reinsurance, Crm, Manufacturing, the FundReporting root, and none in Education.

Where every other package lives

Host (hostedIn) Slot (extensionSlot) Packages
Developer/Home (Examples) examples (shown as Galleries) AppleMaps (new), GoogleMaps, OpenStreetMap, and the control galleries already hosted
Personal/Home accounts Google, ICloud
Personal/Home home HomeAssistant, AppleWeather
Personal/Home entertainment AppleMusic
Games/Home games Chess, RolePlay, QualityTime, QualityTimeDe — all tier: personal
Edu/Courses (Learning) tools LearningRoadmap, Training
Edu/Courses (Learning) courses the Education courses and the three Reinsurance courses (satellite PRs)
{user}/Settings ai MyAi (the person app's Extensions tab lists it)
Admin (core Admin app) operations / aiProviders Hosting, Governance, BuildServer, Observability, AzureCostManagement (operations); Providers (aiProviders) — rendered by Administration › Operations and AI providers (Store/AdminTabs)
SocialMedia/Home channels / campaigns LinkedIn, X, YouTube / Marketing (satellite)
Reinsurance/Home underwriting · claims · finance · capital · operations · demo the insurance modules by line of work (satellite); demo: ReinsuranceDemo and Cornerstone (this repo)

category values are unchanged everywhere.

Reachable on the day it lands

Until phase 1a's AppDirectory is the launcher's source (core #6446, behind Home:AppSource, default Records), a tile exists only as a {viewer}/_App record, and the same deploy that hosts a package purges its tile (HostedTilePurgeWatcher). So a host must be reachable before its guests lose their tiles, and a package whose host has no shelf yet is not hosted yet:

The gate

check_app_roster in validate-repos.py fails a pull request when:

The checker is one block, the same text in all seven plugin repos; only APP_ROSTER and HOST_SLOTS are repo input. Its fixtures also run from main(), so a regression reds ordinary validation.

Both failures are silent at runtime: a stray app is one more tile on every home, and a missing host removes the package's tile and lists it on a shelf nobody renders. --self-test runs the gate over fixtures in both directions.

Host apps and their shelves

Host Shelf State
Developer/Home DeveloperApp renders Store/area/Extensions per slot built
Personal/Home PersonalApp, three sections new, built the same way
Games/Home GamesApp, one section new, built the same way
Edu/Courses the course catalog page embeds the tools shelf under More in Learning; courses are listed by the catalog's own query, never by the shelf, so a hosted course is not shown twice built
{user}/Settings the person app's Extensions tab exists
AI/AiThreads the Threads app's shelves exists
Admin Administration › Operations and AI providers render the operations / aiProviders shelves (phase 3) ✅
SocialMedia/Home SocialMediaApp (MeshWeaver.SocialMedia), Channels and Campaigns built (follow-up, 2026-10-10)
Reinsurance/Home ReinsuranceApp (MeshWeaver.Reinsurance), six sections by line of work built (follow-up, 2026-10-10)

Cornerstone (in this repo, category Insurance) is hosted by Reinsurance: hostedIn: "Reinsurance/Home", slot demo, beside ReinsuranceDemo. Plugins' HOST_SLOTS carries the Reinsurance/Home entry so the gate accepts it; the node itself lives in the satellite, so the node-exists check does not apply here. Cornerstone stays tier: free. A hosted package loses its own tile, and the catalog lists hosted packages only to admins. So a viewer who holds Cornerstone but not the enterprise Reinsurance app reaches it only by its URL until phase 1a's AppDirectory shows hosted packages by plan.

The satellite hosts (follow-up, 2026-10-10). In phase 2, the SocialMedia and Reinsurance guests named the satellite ROOT as their host, and no page there rendered a shelf. Each now has a host page, SocialMedia/Home and Reinsurance/Home, built like Personal. Each root's entryPoint opens that page, and the guests name it in hostedIn. Reinsurance replaced its single modules slot with one slot per line of work. LinkedIn profile pins (ProfileAppPin, ProfileTilesEnsure) still mint _App tiles. Making them sections of Social Media would retire two writers and their tile migration, and would need a purge of the records already in every home. That is phase 4/5 work, recorded in SocialMedia's Guide.

After a deploy — in this order

A merge reaches an instance through the registry once main's settle-locks pull request lands. Then:

  1. Recycle the Store root (enqueue_recycle(path: "Store", reason: "app roster deployed: rebind the catalog")), so its hub binds the new catalog. Recycling mints no tile for Personal or Games: they install nothing (Localize takes its NothingToInstall branch), and the hosted-tile purge runs on that activation anyway.

  2. Run RefreshAppTiles straight after: a Store/Maintenance node under Admin/Maintenance with task: RefreshAppTiles, requestedAction: Run. This step mints the hosts' tiles and fixes the rename:

    • AppTileRefresh.Missing mints a tile for every package that is an app, preInstalled and not hosted, which is exactly Personal and Games, in every home.
    • A tile copies its package's name at install, so this also renames the Developer tiles to Examples.

    Between the purge and this run there is a short window in which a home has neither the old guest tiles nor the new hosts. No data is touched: every package stays at its own URL and on its host's shelf. A viewer who renders the Store in that window self-heals the same way. Phase 1a's AppDirectory removes the window, because the launcher stops reading records.

  3. Recycle the changed types: Developer/DeveloperApp, Edu/CourseCatalog, Personal/PersonalApp and Games/GamesApp, each with enqueue_recycle(path, reason). The reason is required and is recorded in the audit under Admin/_Recycle.

  4. Verify on a real home (get @{user}/_App/*). Personal and Games are present; Google, iCloud, Home Assistant, Apple Music, Apple Weather, Learning Roadmap and the game tiles are gone; the Examples tile reads Examples. Personal/Home and Games/Home render their sections.