App discovery registries (federated, link-only)¶
Audience: Agent, integrator, maintainer, registry operator
This document defines an optional EDOS pattern for browsing and resolving hosted apps before a composition host (or similar tool) loads them in an iframe. It is host-agnostic: any environment that embeds EDOS-style hosted UIs MAY implement the same source list and index formats.
Normative capability data remains on each app’s origin in /.well-known/edos-integration.json per HOSTED_APP_CONTRACT.md. Registries are discovery indexes only — link-only in this revision: index entries MUST NOT embed a full copy of the integration manifest.
Relationship to other contracts¶
| Topic | Where it is specified |
|---|---|
| Integration manifest (capabilities, bootstrap keys, navigation, handshake declaration) | HOSTED_APP_CONTRACT.md — authoritative at app origin |
Journal / file postMessage (IFM) |
IPC.md |
| Federated registry source list and index JSON | This document |
| Composition-host-specific behavior (default sources, slot schema, fan-out rules) | Product docs in the host repo (e.g. elite-dangerous-app-composition) — MUST align with this doc for discovery |
Integrators implementing a new hosted app MUST NOT need a registry to conform to HOSTED_APP_CONTRACT.md. Registries are for operator UX (pick an app, browse known publishers) and for caching index metadata — not for replacing per-origin manifests.
Goals¶
- Federated sources — Like OS package repositories: multiple independent registry endpoints; the user (or a shipped distribution) chooses which sources to trust.
- Third-party publishers — Anyone MAY operate a registry server listing only their apps; users add that source explicitly.
- Link-only indexes — Each index entry points at
entryUrlandmanifestUrl(or the default well-known manifest on the entry origin). Capabilities are read from the manifest after resolution. - Unified mental model — “Tier 1 / 2 / 3” integration levels are deprecated in favor of discovery channels: registry index → origin manifest → runtime handshake → manual URL / host config (see Resolution order).
Non-goals (this revision)¶
- A single mandatory global EDOS registry.
- Embedded manifests inside index files (may be specified later; forbidden in link-only v1).
- Authentication, signing, or revocation infrastructure (reserved for future revisions).
- Composition JSON schema, host→app message types, or journal fan-out rules (host product scope).
Definitions¶
| Term | Meaning |
|---|---|
| Composition host | A host that loads multiple embedded apps (e.g. dashboard / shell). EDAC (elite-dangerous-app-composition) is the reference consumer. |
| Registry source | A named, user-trusted origin of discovery metadata (label + HTTPS URL of an index). |
| Index | JSON document listing app entries for one source. |
| Entry | One row in an index: stable appId, human metadata, URLs to load UI and fetch manifest. |
| Effective app id | When merging indexes: sourceId + / + appId (see Merging multiple sources). |
Federated sources¶
Source list (host-side configuration)¶
A composition host SHOULD persist a list of enabled sources. Minimal shape:
{
"contract": 1,
"sources": [
{
"id": "edos-maintainer",
"label": "EDOS official",
"indexUrl": "https://example.edos.howfe.org/edos/discovery/v1/index.json",
"documentationUrl": "https://docs.edos.howfe.org/"
}
]
}
| Field | Required | Meaning |
|---|---|---|
contract |
yes | Revision of this discovery contract (1 for link-only v1). |
sources |
yes | Array of enabled sources. |
sources[].id |
yes | Stable id for the source ([a-z0-9][a-z0-9-]*, max 64 chars). Used in effective app ids and collision rules. |
sources[].label |
yes | Human-readable name in host UI. |
sources[].indexUrl |
yes | HTTPS URL of the index JSON for this source. |
sources[].documentationUrl |
no | Link explaining trust scope / publisher. |
Rules:
- Hosts MUST fetch indexes only over HTTPS.
- Adding a source is an explicit user action (or pre-enabled in a distribution the user accepted). Hosts SHOULD show
labelanddocumentationUrlbefore enablement. - Disabling a source MUST NOT delete compositions that already reference apps from it; hosts MAY show stale or unresolved entries until the operator fixes slots.
Merging multiple sources¶
When building a combined catalog:
- Prefix each entry’s
appIdwith its source: effective id =sourceId+/+appId(example:edos-maintainer/elite-dangerous-stellar-scan). - If the same
appIdappears twice in one index, the index is invalid — registry operators SHOULD deduplicate at publish time. - If two different sources use the same bare
appId, they remain distinct after prefixing. - Hosts MAY define display order (e.g. maintainer source first, then alphabetical by
label).
Index document (per source)¶
Discovery URL: each source’s indexUrl MUST return JSON.
Example:
{
"contract": 1,
"sourceId": "edos-maintainer",
"updatedAt": "2026-05-24T12:00:00Z",
"entries": [
{
"appId": "elite-dangerous-stellar-scan",
"name": "Stellar Scan",
"entryUrl": "https://edss.howfe.org/",
"manifestUrl": "https://edss.howfe.org/.well-known/edos-integration.json",
"documentationUrl": "https://docs.edos.howfe.org/raw/apps/elite-dangerous-stellar-scan.md"
}
]
}
Index — required fields¶
| Field | Type | Meaning |
|---|---|---|
contract |
number | 1 for this link-only revision. |
sourceId |
string | MUST match the source’s id in the host source list. |
entries |
array | Zero or more entry objects (empty index is valid). |
Index — recommended fields¶
| Field | Type | Meaning |
|---|---|---|
updatedAt |
string | ISO-8601 timestamp of index publication (informational). |
documentationUrl |
string | Publisher-wide documentation for this source. |
Entry — required fields¶
| Field | Type | Meaning |
|---|---|---|
appId |
string | Stable id within the source (often matches workspace folder slug). |
name |
string | Human-readable title for catalogs. |
entryUrl |
string | HTTPS URL the host loads in an iframe or top-level slot (may include path; query bootstrap added by host per HOSTED_APP_CONTRACT.md). |
Entry — recommended fields¶
| Field | Type | Meaning |
|---|---|---|
manifestUrl |
string | HTTPS URL of the integration manifest. If omitted, hosts MUST derive https://<entry-origin>/.well-known/edos-integration.json from entryUrl. |
documentationUrl |
string | Human integration page (capsule, README). |
iconUrl |
string | HTTPS URL of an icon for composer UI. |
summary |
string | Short description for catalogs. |
Entry — forbidden in link-only v1¶
| Field | Rule |
|---|---|
manifest (inline object) |
MUST NOT appear. Capabilities MUST be loaded from manifestUrl / well-known path. |
Duplicate appId in one index |
MUST NOT occur. |
Unknown top-level and entry fields MUST be ignored by hosts (forward compatibility).
Resolution order (normative for hosts)¶
When a composition host needs capabilities for a slot (journal opt-in, host messages, bootstrap defaults, navigation views):
- Loaded slot URL — If the operator set a concrete
entryUrl, use it for bootstrap; still fetch manifest from that origin unless the host caches a recent copy. - Registry entry — If the slot references an effective app id (
sourceId/appId), resolveentryUrlandmanifestUrlfrom the merged index (refresh index per host cache policy). - Origin manifest — Fetch and parse
/.well-known/edos-integration.json(or explicitmanifestUrl). This document is normative for declared capabilities unless superseded by a valid loaded URL per HOSTED_APP_CONTRACT.md — Precedence. - Runtime handshake — Optional
edos.handshakeafter iframe load when manifest is missing, stale, or unreachable — see HOSTED_APP_CONTRACT.md. Handshake MUST NOT grant journal delivery unless capabilities are understood; hosts SHOULD treat handshake as hint and prefer manifest when available. - Manual host configuration — Operator-set flags (e.g. receive journal events, query params) when no declaration exists. Required for arbitrary websites and legacy embeds.
Trust: Journal events and non-IFM host messages MUST only be sent to embeds that opt in via manifest, handshake, or explicit manual configuration — same rule as HOSTED_APP_CONTRACT.md. Registry membership does not imply opt-in.
Manual URL (required host feature)¶
Composition hosts MUST support adding a slot by pasting an HTTPS URL without a registry entry. Raw websites, internal tools, and one-off links use this path; they may still publish a manifest on their origin if the operator controls it.
Publishing guidance¶
App maintainers¶
- Publish HOSTED_APP_CONTRACT.md-conformant manifest at
/.well-known/edos-integration.jsonon the production origin. - Ask registry operators to list
entryUrl+manifestUrl(or rely on well-known default). - Do not require registry listing for third-party embeds of your app.
Registry operators¶
- Serve index over HTTPS with cache-friendly headers (
ETag/Cache-Controlrecommended). - Keep entries link-only; update
updatedAtwhen the index changes. - Document trust scope at
documentationUrl. - TODO: Verify maintainer reference registry URL and deployment host when the first production index ships.
Caching¶
Hosts MAY cache index and manifest responses. On manifest fetch failure after a cache hit, hosts SHOULD retry once, then fall back to handshake or manual config. Hosts SHOULD NOT use stale manifest data for security-sensitive capabilities without a documented policy.
Reference implementation¶
EDAC (elite-dangerous-app-composition, host edac.howfe.org) is the first composition host expected to implement this contract. Product phases, schema fields, and D4 planning in that repo MUST follow this document once adopted; until then, EDAC may ship manual slot URLs only.
Conformance checklist¶
Registry operator
- [ ] Index is HTTPS,
contract: 1,sourceIdmatches published source id. - [ ] Every entry has
appId,name,entryUrl; no inlinemanifestobjects. - [ ]
manifestUrlresolves to a valid integration manifest (or well-known default exists).
Composition host
- [ ] User can add/remove sources; fetches indexes over HTTPS.
- [ ] Resolves capabilities per Resolution order.
- [ ] Supports manual HTTPS URL slots without registry entries.
- [ ] Does not send journal or host contract messages without opt-in.
Hosted app (unchanged)
- [ ] HOSTED_APP_CONTRACT.md conformance checklist — registry optional.
Changelog (this document only)¶
| Revision | Summary |
|---|---|
| Initial (2026-05) | Federated link-only discovery registries; supersedes “single central registry out of scope” as the only discovery story; resolution order replaces tier 1–3 wording for hosts. |