Skip to content

About

Scope

A knowledge explorer of the research-information ecosystem: identifiers, registration agencies, indices, institutional systems, standards, communities and coalitions. It currently holds 169 entries and 357 relationships.

The site is read-only. It does not assess or score services.

Inclusion criteria

An entry is included when it has a stable public URL, when another entry in the graph refers to it or it is a recognised registry, standards body or coalition, and when it is not a single project's internal tooling.

Editorial policy

  • One fact, one place: derived facts (inverse relations, layers, totals) are computed, never written by hand.
  • Every relationship is written once, in its canonical direction.
  • Descriptive, not evaluative: no quality adjectives.
  • Provenance required: every entry cites at least one source with an access date.
  • Freshness tracked: every entry records when it was last reviewed.

How to read the map

Each dot is an entry: a concept, an identifier, a service, a rule or an organisation. Each line is a directed relationship that reads as a sentence: "Crossref issues DOI".

Relationships fall into 5 families, which the map and the entry pages use to order what they show:

Who is behind it
Who issues, owns, governs, operates, develops or funds the thing.
Builds on
Standards, protocols and services the thing is built on or assessed against.
Connects to
Interoperability, indexing, membership and containment between infrastructures.
Shapes
Policies, mandates, endorsements and replacements that steer what is done.
What it is
Classification — which concept the thing falls under, or is related to.

Data model

These tables are generated from the repository vocabularies (vocab/entity-types.yaml and vocab/predicates.yaml), so they cannot drift from the rules applied when the data is validated.

Entry types

TypeDefinitionEntries
AggregatorInfrastructure that harvests, links or federates metadata across institutions and countries for content it does not itself hold.7
CoalitionA political grouping pushing change rather than writing specifications.7
CommunityA body that writes the rules or certifies against them.10
ConceptAn idea or term — persistent identifier, open access, metadata — of which concrete things are instances.31
CRISAn institution's administrative register of its own research activity.5
IdentifierA permanent code pointing at a thing, and the commitment not to delete it.10
IndexA database recording facts about research outputs and the infrastructure holding them.15
OrganizationThe actor behind the thing — company, non-profit, university, agency, intergovernmental body.42
PolicyA normative instrument constraining behaviour.3
Publishing platformA programme that hosts, marks up and publishes journals, preprints or books under its own admission criteria.3
Registration agencyA body that mints identifiers and holds their metadata.4
RepositoryWhere objects are deposited and preserved — both the software and the running service.11
StandardA specification, set of principles, protocol or certification criteria others conform to.21

Relationships

RelationshipInverse readingFamilyUses
certified bycertifiesBuilds on1
complies withcomplied with byBuilds on4
depends ondepended on byBuilds on22
implementsimplemented byBuilds on21
is a profile ofhas profileBuilds on1
indexesindexed byConnects to4
interoperates withinteroperates withConnects to10
is a member ofhas memberConnects to42
is part ofhas partConnects to4
applies tosubject toShapes1
endorsed byendorsesShapes8
mandatesmandated byShapes1
supersedessuperseded byShapes1
is a kind ofincludesWhat it is43
relates torelates toWhat it is98
developed bydevelopsWho is behind it18
funded byfundsWho is behind it16
governed bygovernsWho is behind it15
issuesissued byWho is behind it5
operated byoperatesWho is behind it30
owned byownsWho is behind it12
Validation rules (35)
RuleLevelDefinition
I1ERROR`id` matches /^[a-z0-9]+(?:-[a-z0-9]+)*$/, 2–64 chars, equals the filename stem.
I2ERROR`id` is unique across all entity types. No type-scoped namespacing.
I3ERRORNo dangling references: every relations[].target resolves.
I4ERRORNo self-loops.
I5ERRORNo duplicate triples (id, predicate, target).
I6ERRORpredicate ∈ vocab/predicates.yaml. Closed vocabulary.
I7ERRORCanonical direction only. An inverse-form predicate (owns, issued-by, implemented-by, …) is rejected with a message naming the canonical form and the file it belongs in.
I8ERRORDomain/range: subject.type ∈ predicate.domain, target.type ∈ predicate.range; where sameTypeOnly, also subject.type === target.type.
I9ERRORSymmetric predicates authored once per unordered pair, on the lexicographically smaller id.
I10ERRORAcyclic predicates form a DAG (part-of, supersedes, profile-of, depends-on, owned-by, member-of). Error prints the cycle path.
I11ERRORNo orphans: in-degree + out-degree ≥ 1 unless isolated: true with an explanatory note.
I12ERROREvery declared EntityType has ≥1 instance and every declared predicate ≥1 edge. Unused vocabulary is removed or populated; an entry flagged `pending: true` is exempt until its first instance (WARN if the flag is then left behind).
I13ERROREvery tags[], disciplines[], status, governance value exists in the corresponding vocab file.
I14ERRORsummary (in each locale file) is 40–200 chars, single-line, no Markdown syntax, not identical to name.
I15ERRORsources.length ≥ 1; every Source.url is https:; accessed is a valid ISO date not in the future. Relations with confidence !== 'asserted' carry ≥1 source.
I16ERRORcodebase: open-source requires a licence-bearing sourceUrl or an explanatory note; SPDX identifiers validated against spdx-license-ids.
I17ERRORurl and all Source.url are syntactically valid absolute https: URLs. (Reachability checked weekly, non-blocking — §11.)
I18ERRORPopulated identifiers.* match their format regexes (§5.1).
I19ERRORowned-by targets an organization with orgKind: company. Ownership by a non-company is governed-by or operated-by, not owned-by.
I20ERRORsince ≤ until where both present; valid partial ISO dates; neither >1 year in the future.
I21ERROREntityId-valued subtype fields resolve to an entity of the required type: persistentIdScheme[] → identifier, harvestProtocols[] → standard, markupStandard[] → standard.
I22ERRORgovernance: commercial requires ≥1 outgoing owned-by edge, or a note on the entity explaining why none is recorded. Enforces the memo's central question at authoring time.
I23ERRORlayer is never present in an entity file — it is derived (§5.1, C1).
I24ERROREvery View.query (§5.6) resolves against the current graph; kind: 'explicit' entity IDs must exist.
I25ERRORA View.query resolving to zero entities is an error, not an empty page.
I26WARNlastReviewed older than 18 months (the date itself is shown on the entity page).
I27WARNAn identifier entity with no inbound issues edge.
I28WARNAn entity authors more relations of one predicate than its maxOutDegree (the map shows the most relevant neighbours and "show more" for the rest; the page lists all); or the graph has >1 weakly connected component (prints each component's size and members).
I29ERROREvery entity and every view has a prose file in the default locale, with a valid summary. A facts file without content/i18n/<default>/<id>.yaml fails the build (§5.7).
I30WARN / ERRORWARN per missing non-default-locale prose file, aggregated as one line per locale (e.g. 'en: 12 of 78 entities untranslated') — or, with REQUIRE_FULL_I18N on (src/lib/invariants/config.ts / env), one ERROR per missing file. ERROR if a locale file declares a field outside the translatable set, if a relationNotes key does not resolve to a relation authored in the facts file, or if shortName is longer than the name or set in some locales but not others.
I31ERRORAn entity facts file carries prose (a body, summary or description field). Prose exists only in content/i18n/** (C10).
I32WARNEvery edge of a governance predicate (owned-by, governed-by, operated-by, developed-by, funded-by) carries relations[].verified: { date, url } recording the primary source it was checked against.
I33WARNCompleteness floor: every repository/index/aggregator/publishing-platform has ≥1 of {operated-by, developed-by, governed-by}; every standard has ≥1 of {developed-by, governed-by}.
I34WARNHeuristic: an entity's note/relationNote/source-note text mentions another entity by name with no relation connecting the two — a likely fact-recorded-as-prose gap.
I35ERROREvery predicate declares a `family` that exists in vocab/predicate-families.yaml (display grouping, ≤5 families).

Downloads

The complete data is published under CC-BY-4.0 in open formats:

Contribute

You do not need to edit any file. To add, change or remove something, open an issue: pick a form, say what is wrong or missing and where it can be checked. A maintainer checks the source and makes the change. Issues are public. Open an issue on GitHub(opens in a new tab)

The content of this site (entities, relations, translations, stories) is plain YAML in src/content/, checked by a Zod schema and a set of graph invariants every time you run npm run validate and every time you build. A change is good when the validator passes and a person can tell from the diff that it is true, sourced and in scope.

Suggest a change without editing files

Open an issue at https://github.com/Data-Observatory/open-ecosystem-explorer/issues/new/choose and pick the form that fits. The forms are in English and Spanish.

  • New entry on the map: an institution, standard, identifier, infrastructure or concept that is missing.
  • Connection between two entries: add, change or remove one line on the map (how entry A relates to entry B, from the list of 21 kinds of connection).
  • Description or facts of an entry: the short description, the longer text, the name, a fact in the table, the note for Chile and Latin America, a translation, a source or link, or where it appears on the map.
  • Remove an entry: it does not belong, is a duplicate, is not true or no longer exists.
  • Bug or accessibility problem and Idea or feature: about the site itself, not the content of the map.

Every entry page has two links ("Suggest a change to the description or facts" and "Suggest a change to its connections") that open the matching form with that entry filled in, and the footer links to the chooser.

  • A maintainer reads the issue, checks the source, and makes the change as a pull request that closes the issue, or answers why not. If in doubt, the change is left out.
  • Give a source for what you propose: the organisation's own page or an authoritative register. A proposal without one may wait until one is found.
  • Issues are public. Do not include personal data.
  • Issues are labelled new-entry, connection, description, remove-entry, bug and idea.

Everything below is for people who prefer to make the change themselves, in a pull request.

Before you start

You need Node 22 or newer and npm. Run npm install once. Run npx playwright install chromium only if you also want to run the browser tests.

Read the specs.md sections for the part you touch: §3 (curation policy), §5 (data model and invariants) and §8 (authoring format). docs/known-issues.md lists what is already known to be unverified, so you do not repeat it.

Add or change an entity

  • For autocomplete and validation while you type, map schema/entity.schema.json to src/content/entities/*.yaml and schema/prose.schema.json to src/content/i18n/*/*.yaml in your editor's YAML settings (for example the yaml.schemas setting of the redhat.vscode-yaml extension). Personal editor settings are not committed (.vscode/ is ignored).
  • An entity is two or three small files, never one big one. Facts and outgoing relations go in src/content/entities/<id>.yaml. The filename is the id.
  • Prose goes in src/content/i18n/es/<id>.yaml and src/content/i18n/en/<id>.yaml: a one-sentence summary and a short body. Both languages are required, and a missing one is a validation error.
  • Copy two existing files of the same type as models. The closed vocabularies in src/content/vocab/ (types, predicates, tags, disciplines, statuses) say which values are allowed. Do not invent terms; adding a vocabulary term is a separate change.
  • Author each relation once, in the canonical direction, in the file of the subject. The inverse is derived. If the target entity does not exist, add it in the same change or leave the relation out.
  • Every entity needs at least one entry in sources with a real URL and the date you read it. Cite the organisation's own page or an authoritative register, not a summary of it.
  • Descriptions are neutral and descriptive, not evaluative. Chile and Latin America specifics go in an optional localNote (30 words at most), never in the definition.
  • If in doubt, leave it out. A missing relation costs less than a wrong one.
  • Ideas such as open access, metadata or FAIR are entities of type concept. Link concrete things to them with is-a or related-to (with a short note), not with the other predicates.
  • prominence (core, extended or detail) controls what a newcomer sees first. Leave the default unless you have discussed it.

prompts/add-entity.md is a ready-made prompt for an LLM agent doing the same job. An agent edits, the validator checks, a person reviews and merges.

The check loop

Run these after every edit, from the repository root:

  • npm run validate must end with 0 errors. It takes a few seconds and prints the rule, the file, the field and the fix. Warnings are information; report them, do not hide them.
  • npm run layout:generate after you add, remove or change a relation or an entity, then commit src/generated/graph-layout.json. The build fails (layout:check) if it is stale.
  • npm run check, npm run lint and npm test before you open a pull request.
  • npm run build then npm run test:e2e when you touch pages or the map. The e2e tests run against the build. Set PW_PORT to a free port, and PLAYWRIGHT_CHROME_PATH to use a system Chrome.

Change the site or the UI text

UI strings live in messages/es.json and messages/en.json. Every key must exist in both. Code under src/lib/model, graph, i18n, invariants, views, stories and export must stay free of Svelte and SvelteKit imports. docs/architecture.md explains the routes and the map.

Commits and reviews

  • Use conventional commits (feat:, fix:, docs:, chore:, refactor:, test:, style:) and small, incremental commits: one idea per commit.
  • Do not add co-author or tool attribution lines to commit messages.
  • The reviewer reads for what the validator cannot see: is the relation true, is the source the right one, is the summary neutral, is the entity in scope.
  • main is protected: work on a branch and open a pull request. It can be merged only when the CI jobs test and infra are green and the branch is up to date with main; direct pushes are refused, for administrators too. Merging is squash or rebase, so keep the pull request title a conventional commit.
  • CI (.github/workflows/ci.yml) runs the check loop above on every pull request and on every push to main.
  • Every change merged to main is deployed to https://oee.dataobservatory.net by .github/workflows/deploy.yml after CI passes on main, with no further approval. Merge only what you are ready to publish.
  • Analytics, hosting and deployment settings (static/consent-loader.js, infra/, .github/workflows/deploy.yml) are decided by the project owner. Open an issue instead of changing them.
Template for adding an entry

Add an entity

Add <name> to this repository as an entity.

Read first: specs.md §5.1–5.2 (fields per type), specs.md A.2 (the predicates, with domain and range), src/content/vocab/*.yaml (closed vocabularies — do not invent terms), and two existing files of the same type as models.

Then: create src/content/entities/<id>.yaml with the facts and outgoing relations only, and src/content/i18n/es/<id>.yaml with summary and body prose (en too if you can source it). Author relations in the canonical direction only; if a target entity does not exist, either add it in the same change or omit the relation. Every entity needs ≥1 sources entry with a real URL and today's accessed date — do not cite the memo for an external fact, cite the thing itself.

Optional prominence: core | extended | detail (default extended) controls progressive disclosure; set core only for the handful of nodes a newcomer must see first. A new idea or term (persistent identifier, open access, metadata, ...) is a concept (13th type; governance: not-applicable, url = its reference page, no type-specific fields): link concrete things to it with is-a (any type -> concept; concept -> concept for subtypes; acyclic; only when the thing genuinely *is a kind of* the concept) or related-to (symmetric, any type -> concept, at most 5 per node (a warning beyond that), always with a short note saying how; use it when the thing operates, practises or addresses the idea without being a kind of it), and write the concept's own relations in the same direction. Principles and frameworks (FAIR, CARE, TRUST) are concepts, not standards: tie them to things with related-to, never complies-with or developed-by. For a symmetric edge between two concepts, author it on the file whose id sorts first. Prose: an optional localNote (<=30 words) carries a Chile/LatAm-specific fact about a global concept; definitions stay neutral. Provide both es and en files: a missing locale is a validation ERROR (REQUIRE_FULL_I18N in src/lib/invariants/config.ts).

Finally: run npm run validate and fix every ERROR before stopping; if you added or changed any relation or entity, also run npm run layout:generate and keep the changed src/generated/graph-layout.json. Report the WARN lines rather than suppressing them. Do not add a vocabulary term (that is a separate PR, C6), and do not edit any other entity's file to add the inverse relation.

Changelog

Changes to the data and to the site are recorded in the changelog.

  • Proposals through GitHub issues (2026-11-14)
  • CI and deployment infrastructure (2026-11-14)
  • Spec brought in line with the code (2026-11-14)
  • Contributor documentation (2026-11-14)
  • Clean-up after the SvelteKit migration (2026-11-14)

See the full changelog

Privacy and cookies

To understand how the site is used, visit activity is measured through Google Tag Manager, a Google service that loads the analytics tools configured for this site (for example, Google Analytics). It receives technical usage data, such as the pages visited, the browser and device type and the approximate location, together with a cookie that identifies the browser with a random code. The site asks for no name, email or other personal data, and analytics are not used for advertising.

Analytics are on by default. The notice shown on the first visit lets you keep them on or turn them off, with equal weight, and it is shown again after one year.

You can turn them off or on again at any time with the analytics settings button on this page or in the footer. Turning them off stops Google Tag Manager from loading on later visits and deletes the Google Analytics cookies of this site.

Your choice is stored only in this browser (localStorage, key oee-consent), with its date. It is not sent to any server. Apart from that, the site only remembers in the browser your map mode preference.