apps.arnao.ai — one manifest, one registry, one console

One line: every app in the fleet gets a tiny manifest (design tokens, flags, auth, budget, analytics, category, expiry); one registry reads them all; machines enforce it — deploy gate, nightly grader, auto-filed fix issues, a shared spend gateway — with a governance tab in command.arnao.ai for Byron and a rebuilt public index for everyone else.

Why it isn't reinventing the wheel: this category exists — it's called an internal developer portal (Spotify's Backstage invented the shape: a service catalog fed by per-repo manifest files, plus scorecards). The wheel to steal is the manifest + catalog + scorecard pattern. The wheel not to install is Backstage itself — see prior art below.


The audit that makes the case (run 2026-07-16, all data in fleet-scan-20260716.csv)

The fleet-audit daemon knows 142 root sites. I scanned every one of them tonight:

CheckLive sites passing%
HTTP 200123 / 14287%
Plausible analytics10 / 1238%
noindex (for demos/mockups)5 / 1234%
Shared design tokens (tokens.css)1 / 1231%
PWA manifest8 / 1236%
Google auth wiring6 / 1235%
Viewport meta (the one thing everyone does)120 / 12397%

Plus: 19 sites are dead or broken (404/timeout/store-brand redirects), 11 of them already flagged dead in the registry but still occupying DNS and mindshare. The registry itself says the fleet is 85 demos, 14 platforms, 11 personal, 10 research, 9 publications, 8 tools, 4 fleet consoles.

Read that table honestly: the fleet has a 97% floor on accidental consistency (viewport, because every scaffold includes it) and a 1–8% ceiling on deliberate consistency (analytics, tokens, indexing policy). The difference between those numbers is exactly what a manifest-and-scorecard system fixes: consistency has to be enforced at creation time by tooling, because 142 sites will never be hand-migrated.

The cleanup, sized: 37 active non-demo sites need the Plausible tag (scripted, one pass); ~100 demo/mockup sites need noindex (scripted); 19 dead sites need retirement (delete DNS + Vercel project, or a fleet-standard tombstone redirect); full token adoption is realistic only for the ~46 active non-demo properties — old demos get analytics + noindex and are otherwise left as historical artifacts. Policy over archaeology.


The manifest — arnao.app.json, one file per app

Sits in the repo root; the deploy skill refuses to ship without it (new apps) or auto-drafts it (existing apps). Everything the fleet needs to know, nothing more:

{
  "name": "City Guide",
  "domain": "city.arnao.ai",
  "category": "platform",          // platform | tool | demo | publication | personal | research | fleet
  "status": "active",              // active | parked | dead
  "owner": "gia",                  // which agent maintains it
  "repo": "arnao/city-app",        // Gitea
  "design": { "tokens": "v2", "gestures": false, "pwa": true },
  "auth": "none",                  // none | google
  "budgetMaxUSD": 5,               // per-day cap — enforced by the shared spend gateway, NOT by each app
  "analytics": true,               // Plausible tag required
  "index": { "listed": true, "noindex": false },
  "command": { "tile": true },     // appears on command.arnao.ai
  "expires": "2026-10-14"          // review date; demos default to 90 days from creation
}

expires is the field that matters most — mortality by default. The fleet's real disease isn't inconsistency, it's immortality: 85 demos and 19 corpses exist because nothing ever has to justify continued existence. Every app declares a review date (demos default 90 days). When it lapses the nightly daemon doesn't nag — it acts: auto-tombstone, noindex, DNS queued for release, one renewal issue filed. Renewal is one line in a PR; death is the zero-effort path. With a TTL in the manifest, the dead-site count can never again exceed the renewal backlog — and the 2027 edition of tonight's cleanup never needs proposing.

Six of these fields already exist informally (name/category/status live in the fleet-audit registry; repo in Gitea; thumbnails cached). The manifest just makes the informal facts declared, versioned, and enforceable.

Enforcement points — ranked by how real they are today:

Two surfaces, deliberately unequal — a tab for Byron, a gallery for everyone else

An earlier draft split "ops" (command) from "governance" (a new apps console) — enterprise wisdom that doesn't survive contact with a solo operator, for whom ops and governance are the same question asked at the same moment: what's wrong with my stuff and what do I do about it? Two panes means one becomes real and the other rots. So, merged:

1. The governance tab — inside command.arnao.ai. One nightly-generated table (v1 is literally that, nothing more): every app, its manifest facts, its scorecard dots, its open issues/PRs from Gitea, its traffic sparkline. Filterable by domain / category / status / owner / score. The fleet-level bar — "analytics coverage 8% → 74%" — is the cleanup's progress metric. No four view densities, no product spec for users who don't exist; the consumers of governance are the agents (via auto-filed issues), and this tab is Byron's spot-check of the loop, one pane he already opens.

2. The public gallery — replaces index.arnao.ai. A different audience (visitors, recruiters, LinkedIn click-throughs) deserves the pretty surface: cards with cached thumbnails (134 already exist in the audit daemon), name + one-liner + tags, views: list / small grid / big grid, filterable by category and domain, fed by the same registry — only index.listed: true apps appear, so the 85 aging demos stop being the public face of the fleet. This is where the look-and-feel views belong, because browsing is what visitors do. The analytics rollup (Plausible per-site API calls merged nightly: by referrer, by geo, by app, by category — "which properties does LinkedIn traffic actually land on" as one chart) renders private-side in the governance tab; the rollup is the reward for the tag rollout.

The index cutover, sequenced (this couples to a Windows machine, so make it boring): (1) the new gallery ships and is verified, (2) index.arnao.ai becomes a trivially reversible redirect, (3) Zia's regeneration job is retired — in that order, and the nightly audit gets a "old index resurrected" check so Zia can't silently win a race it doesn't know it's in.

Git + backlog — yes, integrate; no, don't build a tracker

Gitea is already live (git.arnao.ai, 12 repos) and has project boards built in — kanban columns over issues, at repo and org level. The backlog IS Gitea issues on arnao/fleet-infra: every piece of fleet work (this proposal included) is an issue with labels (app:city, type:cleanup, type:feature) and milestones. One API reality check from research: Gitea's REST API fully covers issues, labels, milestones, and PRs but has no endpoint for the boards themselves — so agents and the console drive the backlog through issues + labels + milestones (fully scriptable), and the kanban board stays what it's good at: a human-facing view in Gitea's own UI, one deep link away. PR → issue → app → scorecard all join on the manifest's repo field. Building a custom tracker when the git host ships one would be reinventing the wheel inside the stop-reinventing-the-wheel proposal.

Skills — build four, reuse four

Reuse (already exist):

Build (small, in order):

  1. app-manifest — draft/validate arnao.app.json; bulk-draft for all 123 live sites from registry + scan data (a day of agent work, not a month).
  2. fleet-cleanup — the one-pass fixers: inject Plausible into the 37 priority sites, noindex the demos, tombstone the 19 dead. Each fix is a PR in the app's repo, not a silent mutation.
  3. app-scaffold — new-app bootstrap: tokens.css v2, Plausible, manifest, Gitea repo, command tile, index entry — compliance by birth, which the audit proves is the only kind that sticks.
  4. fleet-analytics — Plausible stats API → the pivot views (by app / referrer / geo / category).

Prior art — the wheel exists; here's which spokes to take

The category is the internal developer portal, and it converges on exactly the shape sketched above:

Verdict, stated plainly: adopt the manifest + scorecard + token-standard concepts; install nothing new; build the thin console. One correction from research that changes a detail below: Plausible's cross-site "consolidated views" is a paid cloud-plan feature — the self-hosted CE instance the fleet already runs exposes a per-site stats API with referrer/geo/source dimensions, so the console's fleet rollup merges N per-site calls (cached nightly), which at this scale is trivial. If that ever bites, umami is the open-API fallback — a migration decision for later, not now.

Roadmap — cleanup before console, and the order is the argument

The "console as forcing function" theory requires a mechanism that converts visibility into action — shame, a manager, social pressure. Those work on teams. Solo, the experiment already ran: the audit daemon has surfaced this drift nightly for months and coverage sat at 8%. A console over today's fleet is a wall of red dots — a monument, not a forcing function. And the dependency graph agrees: the console reads manifests (don't exist yet), renders analytics (8% coverage = an empty room), shows scorecards (nothing to score). So:

The honest risks

Mockups — real data, simulated loop

Both mockups run on the real 2026-07-16 audit data (141 registry apps, live scan results, the daemon's actual screenshots) so they show facts, not lorem ipsum. Simulated fields (owner, expiry clocks, issue counts, traffic) are labeled as such on-page.

Self-critique — Fable adversarial pass

Ran through Fable 5 as a ruthless critic (solo-operator realism / scope integrity / enforcement design), full text in fable-critique-20260716.md. It restructured the proposal: