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 fleet-audit daemon knows 142 root sites. I scanned every one of them tonight:
| Check | Live sites passing | % |
|---|---|---|
| HTTP 200 | 123 / 142 | 87% |
| Plausible analytics | 10 / 123 | 8% |
| noindex (for demos/mockups) | 5 / 123 | 4% |
| Shared design tokens (tokens.css) | 1 / 123 | 1% |
| PWA manifest | 8 / 123 | 6% |
| Google auth wiring | 6 / 123 | 5% |
| Viewport meta (the one thing everyone does) | 120 / 123 | 97% |
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.
arnao.app.json, one file per appSits 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:
vercel-deploy validates the manifest and injects the boring parts, so a new app cannot ship non-compliant. The precondition to verify before building anything: the choke point must be total — if any agent runs vercel deploy bare or any repo auto-deploys on push, the gate is a suggestion. Step one of the roadmap is auditing how the last 20 deploys actually happened and closing the side doors. And honesty about "injects the boring parts": the noindex header is genuinely one vercel.json block; the Plausible tag is a small matrix (static HTML vs. SPA vs. Next) — a solved matrix, but a matrix, not one line.budgetMaxUSD centrally. This converts the manifest's weakest field into its strongest: load-bearing runtime config, which is also the only durable answer to "the manifest nobody updates."auth field ships as declared intent and turns real when the shared module does — same Phase as the gateway. A flag pointing at a demo is the manifest lying at birth, so until then the scorecard renders it "declared, not enforced."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.
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.
Reuse (already exist):
vercel-deploy — gains manifest validation + auto-injection (the gate).branding-console — content pipeline, untouched; the console links to it.dataviz — the analytics rollup charts follow its rules.Build (small, in order):
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).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.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.fleet-analytics — Plausible stats API → the pivot views (by app / referrer / geo / category).The category is the internal developer portal, and it converges on exactly the shape sketched above:
catalog-info.yaml manifests (owner, type, lifecycle — the vocabulary arnao.app.json borrows), golden-path software templates (= app-scaffold), and scorecards via Soundcheck / Tech Insights. Do not install it: it's a TypeScript monorepo you operate as a product, with realistic estimates of 2–4 dedicated engineers and analyses concluding that under ~50 engineers the overhead outweighs the benefit. For one person, the concepts are the value; the software is a liability.tokens.json in a shared repo → one generated fleet.css every compliant app imports. The design.tokens: "v2" manifest field points at a version of that, not at a vibe.app.json for deploy/governance spirit, catalog-info.yaml for shape, PWA manifest.json for the browser-facing identity subset. arnao.app.json is those three, minus everything a 142-site personal fleet doesn't need.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.
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:
vercel-deploy gets closed or instrumented. No gate, no system.expires dates); cleanup executed as PRs — Plausible into the 37 priority sites, noindex across the demos, the 19 corpses tombstoned; grader + auto-filed issues live in the nightly daemon. Analytics coverage 8% → ~74% on active sites, and the push loop (fail → issue → agent PR → Byron review) starts breathing.budgetMaxUSD centrally for the API-backed apps; auth.arnao.ai promoted from demo to the fleet's actual Google sign-in module. These two are what make the manifest load-bearing at runtime.expires date, and are otherwise historical artifacts.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.
index.listed in miniature).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:
budgetMaxUSD was "a comment with delusions" — per-app self-enforcement never happens. Fix: the shared spend gateway is now Phase 2's centerpiece; the field is enforced centrally or it's nothing.expires): demos die at 90 days unless renewed by a one-line PR; entropy does the janitorial work.