ADR 0005: app.manifest.yml — Self-Describing Apps¶
Status: Accepted Date: 2026-04-29
Context¶
The portal needs to know which apps exist, their display names, icons, routing, and entitlement rules. The gateway needs routing info. CI needs metadata for affected-build calculations. Humans need a place to look up an app's owner.
The two patterns are:
- Central registry — a single config file (
apps.yml) listing every app and its metadata. - Self-describing apps — each app carries a manifest in its own directory; the platform discovers apps by scanning the filesystem.
Decision¶
Use self-describing apps via app.manifest.yml at the root of every app directory. Schema is defined in schemas/app-manifest.schema.json (JSON Schema draft 2020-12). CI rejects PRs with invalid manifests.
Auto-discovery flow:
1. The portal scans apps/**/app.manifest.yml and clients/**/app.manifest.yml at runtime.
2. Filters by lifecycle.status != "archived" and hub.visible == true.
3. Queries Authentik for the current user's entitled application slugs.
4. Intersects: only apps where auth.authentik_app_slug matches an entitled app are shown.
5. Groups by hub.category, sorts by hub.order.
Adding a new app to the hub = creating its manifest. No portal code changes.
Key schema choices¶
id(UUID) is separate fromslug. If an app gets renamed, the slug and directory change but theidstays. Entitlements, audit logs, and cross-app references all key offid. Renaming doesn't orphan history.manifest_version: 1— explicit schema version. Lets us evolve the schema without breaking old manifests.- No secrets. Manifests are committed. Anything secret goes in
.env. - Optional fields have sensible defaults. The scaffold script produces a minimal but fully valid manifest; humans add detail later.
dependencies.events_publish/subscribecaptures async wiring even before a message bus exists. Costs nothing now, lets the docs site render a service map automatically when we have one.
For the full schema, see ../reference/app-manifest.md.
Consequences¶
Positive: - No central config file to keep in sync. The filesystem is the registry. - Adding/removing/archiving an app touches one directory. - Validation in CI catches typos and schema drift before they hit prod. - The manifest is plain YAML — humans can edit it, agents can generate it, scripts can read it.
Negative:
- The portal must do filesystem scanning. Cost is small (manifests are tiny), but it's not zero. Caching layer can be added if it becomes hot.
- A schema change requires updating every existing manifest — partially mitigated by manifest_version allowing graceful coexistence of old and new versions during migration.
Alternatives considered¶
- Central
apps.yml. Rejected — every new app would need two PRs (one to add the app, one to register it). High friction for agents. - Convention-only (no manifest). Rejected — too many things (icons, descriptions, ownership, entitlements) need explicit declaration.