1. Naming conventions

Casing encodes element type:

Element type Convention Examples
Concepts PascalCase Person, Enrollment, GroupMembership
Properties snake_case given_name, date_of_birth
Vocabulary value codes snake_case never_married, bank_transfer
Vocabulary identifiers kebab-case gender-type, enrollment-status

Enforced by JSON Schema regex validators. Once a name is published at candidate or above, it cannot be changed.

2. Domain-scoped URIs

Some concepts share a name across domains but carry different semantics ("Enrollment" in social protection vs. education). Domain-specific elements get a domain segment in their URI; universal elements live at the root:

  • publicschema.org/sp/Enrollment (social protection)
  • publicschema.org/Person (universal)

The test: an element is universal if the same definition carries the same meaning regardless of domain. If not, it belongs in a domain namespace.

Apply the same meaning-based test to properties and vocabularies. A portable primitive shape does not make a property universal: a tax identifier and a vehicle identifier can both be strings while naming different facts. Shared properties such as start_date retain their root URI when used by a sector concept. Existing candidate and normative terms retain their published identities, including older root-property/domain-vocabulary pairs; those are compatibility constraints, not a precedent for assigning new terms by shape alone.

Public names do not need domain abbreviations: use Enrollment, not SPEnrollment. LinkML identifiers must nevertheless be unique within the composite. For example, the authored CrvsPerson represents crvs/Person, a civil-registration snapshot distinct from universal Person; crvs/Parent inherits from that snapshot. See ADR-018.

The build pipeline keys concepts internally by {domain}/{id} (e.g., sp/Enrollment, crvs/Birth) for domain-scoped concepts and by bare id (e.g., Person, Event) for universal ones. This prevents silent overwrites when two domains define concepts with the same short name.

Code Domain Current scope
sp Social protection Benefit programs, participation and public-service delivery relationships
crvs Civil registration Civil registration of vital events and the associated roles and records
agri Agriculture Agricultural and fisheries production: holdings, cultivation, and production-specific roles, facilities, inputs and assertions
land Land administration Spatial and administrative units, tenure and boundary assertions
environment Environment Environmentally regulated facilities and their activities, and water-use authorizations
transport Transport Road vehicles, driving entitlements and vessel attributes
edu Education Education provision, programs, delivery sites and educational facility types
health Health Healthcare facility discovery and integration with selected FHIR resources; no replacement medical ontology
tax Tax administration Registration of persons and organizations with tax authorities, by tax type
elections Elections Voter registration, electoral districts and polling stations

These labels describe represented slices, not complete sector standards. A domain is a namespace and discovery aid, not a superclass or access-control boundary. Any domain can reuse a shared concept or refer to another domain's concept. Module filenames organize authorship and do not determine public namespaces.

ServicePoint stays shared. Its School and HealthFacility subtypes use edu/School and health/HealthFacility. RegistrationOffice remains at root because its definition also covers identity and refugee registration. WaterPoint retains its existing root identity as a disclosed scope exception; a complete water and sanitation namespace has not been designed. Generic animal and plant identities remain shared where their definitions do not require agricultural production. See domain placement and migration for individual dispositions.

Author explicit class_uri, slot_uri, enum_uri and permissible-value meaning values with consistent annotations.source_domain. The renderer uses a property's authored URI to place its page; adding a new consumer must not move that property. Vocabulary catalog paths remain /vocab/<domain>/<kebab-case-id>. schema/publicschema.yaml supplies domain labels through annotations.domains_json; the site shows domains actually present in each collection and keeps unknown codes visible.

3. URI persistence

Every element gets a stable URI. Once published at candidate or above, a URI will not be removed. Deprecated terms continue to resolve with metadata indicating the replacement. See Versioning and Maturity for the full model.

4. Concept, property, or vocabulary

Use this decision tree to determine what kind of element to create.

Decision tree: own identity, closed value set, value has identity

Step 1: Does it have its own identity? Does this thing exist independently, get referenced from multiple places, and have its own lifecycle? If yes, it is a concept.

Example: GroupMembership is a concept, not a property on Person or Group. It carries its own data (role, dates), has its own lifecycle, and is referenced from both sides.

Step 2: Is it an attribute of a concept? A fact about a specific concept, with no independent identity? If yes, it is a property. Multiple values (e.g., phone numbers) still make it a property with cardinality many.

Step 3: Is the value drawn from a closed set? If the property accepts one answer from a defined list with stable meanings, the value set is a vocabulary.

Step 4: Reference or inline? If the value has its own identity and properties, reference a concept (concept: Location). If it is a simple scalar, use an inline primitive.

Example: latitude is an inline decimal on Location. It has no independent identity, no sub-properties. It is a number.

Situation Element type
Own lifecycle, referenced from multiple concepts Concept
Attribute of a concept, no independent identity Property
Value from a closed set of options Vocabulary
Value has its own identity and sub-properties Property referencing a concept
Simple scalar Inline primitive type

Actor vs. receiver supertypes

Agent and Party are two abstract supertypes that carry different semantics.

  • Party is the receiver side: the persons, organised groups of persons (Household, Family) and organizations that can be identified, enrolled in programs, and receive benefits or services. Beneficiary-side references (beneficiary, recipient, subject, redeemable_by, issued_to) range over Party.
  • Agent is the actor side: the persons, organisations, and software that perform, publish, evaluate, decide, or execute. Actor-side references (performed_by, evaluator, publisher) range over Agent.

Person and Organization belong to both hierarchies: each can both receive services and perform them. Organization covers bodies of any sector, including companies and cooperatives. SoftwareAgent is an Agent only. Two Party-ranged properties do not apply to organizations and say so in their definitions: data_subject, because data protection law protects natural persons, and subject on profiles. See ADR-008 and ADR-028.

Sole proprietorships

Jurisdictions draw the line between a person and their business differently, so the core admits two patterns and an application profile states which one a jurisdiction uses:

  • Person pattern. Where the business has no existence separate from the person, record a Person with the business identifier (an IdentifierAssignment from the business register), the trading name (a NameUsage with name use trading) and industry.
  • Organization pattern. Where the register treats the business as a body distinct from the person, record an Organization whose legal_form is a sole proprietorship, linked to the person by an InstitutionalRole.

A record is a person or an organization, never both: do not define a concept, in the core or in a local extension, that is a subtype of both Person and Organization. FOAF declares the two classes disjoint, and a person can run several successive businesses.

4a. Group-like concepts

Three concepts in PublicSchema describe collections of persons but have distinct semantics. Choosing the right one matters for data quality and interoperability.

Household is a co-residential economic unit. Members share a dwelling and typically share food and resources. The operational definition varies by country and program (combining co-residence, shared budget, shared cooking, and kinship criteria), but the anchor is always physical co-location and shared livelihood. Household is the right concept for registering beneficiary units in social protection programs.

Family is a kinship network. Members are connected by blood, marriage, or adoption, regardless of where they live. A family can span multiple households and geographic areas. Kinship links between members are modelled as Relationship records between Person instances; Family itself carries no dedicated kinship properties at this stage. Family is the right concept when the unit of interest is a relational network rather than a co-residential arrangement.

FamilyRegister is an administrative document, not a group. It is a civil-registration record that tracks a family unit over time as vital events (births, deaths, marriages) occur. It references a Family to expose current membership. FamilyRegister is the right concept for modelling koseki-style, hukou-style, or livret-de-famille-style administrative instruments.

When to use each

You want to record... Use
A beneficiary unit sharing a dwelling and resources Household
A network of persons connected by blood, marriage, or adoption Family
An administrative civil-registration document tracking a family FamilyRegister

Interoperability bridge

Many systems use "family" colloquially to mean the co-residential unit. When exchanging data with such systems, set group_type: family on the Household record. This signals to consumers that the household is being represented as a family for interoperability purposes without misrepresenting the PublicSchema semantics.

5. Temporal context

Almost everything in public service delivery is time-bounded. A status snapshot without a validity period is incomplete. When designing a concept or property, ask: will this value change over time? If yes, model the temporal context explicitly (start/end dates, validity periods).

Date property conventions

Lifecycle concepts use domain-specific named dates that describe the domain event. Relationship and membership concepts use generic start_date / end_date.

Concept type Date pattern Examples
Lifecycle (Enrollment) Domain-specific named dates enrollment_date, exit_date
Lifecycle (Entitlement) Domain-specific period coverage_period_start, coverage_period_end
Lifecycle (Grievance) Domain-specific event dates submission_date, resolution_date
Single event (PaymentEvent) Single event date payment_date
Relationship (GroupMembership, Relationship) Generic dates start_date, end_date
Calendar validity of an assertion (RegistryEntry, Registration) First and last applicable dates valid_from, valid_to

Do not mix both patterns on the same concept. A lifecycle concept should not carry both enrollment_date and start_date.

The two generic pairs are not aliases. start_date names the first day a relationship is effective and end_date the last day, both included (ADR-027). valid_from and valid_to name the first and last applicable calendar dates of an assertion's validity. recorded_at instead records when the source entered the assertion. Missing dates remain unknown; an omitted end does not prove perpetual validity.

Use start_date / end_date for relationship and membership concepts, such as HoldingParcelLink, AnimalResidence, AnimalResponsibility, AgriculturalServiceRole, IdentifierAssignment, NameUsage, ContactPoint, AssetPartyRole and AssetAddressAssignment. Registration (including Authorization specializations such as DrivingEntitlement), RegistryEntry, AgriculturalParcel, Certification and LandTenureAssertion retain their declared calendar validity. The relationship date conversion guide describes the explicit conversion contract for source records that use calendar validity.

An application that compares or converts dates must first know the source's interval boundaries. Both pairs include their end day, so an inclusive source valid_to: 2026-06-30 becomes end_date: 2026-06-30, and the next period starts on 1 July. A source whose end is the first day that no longer applies needs one day subtracted. Do not convert when source precision or boundary semantics are unknown. The farm-work example follows the same convention.

6. Property independence

A property like start_date is defined once and reused across concepts. When a shared property needs concept-specific value sets (e.g., status on Enrollment vs. Grievance), it specializes via different vocabulary references rather than pretending the differences don't exist.

Cross-concept property reuse

Property independence is not limited to repeated structural fields. Substantive observables can be reused across concepts too. water_source, sanitation_facility, and dwelling_type appear on both SocioEconomicProfile (baseline registration context) and DwellingDamageProfile in a sibling schema (post-shock assessment). In each case the property is declared once and listed in each concept's properties; the pattern also illustrates how PublicSchema properties can be reused by domain-specific profile subtypes vendored in a sibling schema.

The rules that keep this honest:

  1. One reusable slot per named fact. water_source is declared once under slots: and referenced from both profiles.
  2. Contextual framing lives on the concept, not the property. The property definition names the observable ("the household's primary source of drinking water"). Each concept definition names how that observable is interpreted in that concept (baseline vs. post-shock).
  3. Reuse must be disclosed in both concepts' narrative definitions. A reader on either page must be able to see that the field also appears elsewhere and why.
  4. Reuse does not make records type-compatible. A SocioEconomicProfile record and a DwellingDamageProfile record are different things even when their property values overlap. Adopters should consult the concept page, not the property list, when serialising into a strongly typed shape.
  5. Split when wording diverges. If the property's own definition needs different text in each context, create two properties. location and location_of_assessment are split this way: location is the concept-agnostic geographic location of the record's subject (the household's site for a Household record, the organisation's primary site for an Organization record); location_of_assessment is where a post-shock damage assessment was physically carried out, which may differ after displacement.

triggering_hazard_event (on DwellingDamageProfile) and triggering_vital_event (on CivilStatusAnnotation) follow the same split. Both were originally unified as one triggering_event whose type was widened to concept:Event, but the expected subtype carries meaning for validators and practitioners, so each consumer now declares its own typed reference. See ADR-007 for the full argument.

7. Age applicability

Some Person-scoped properties are only meaningful for specific age groups. The Washington Group Short Set and Extended Set apply to adults; the Child Functioning Module applies to children ages 2-4 and 5-17. WHO growth standards apply to under-5s. Rather than encoding these rules in definition prose alone (which machines cannot parse), properties carry an optional age_applicability array of controlled tags.

Tag Numeric range Source of the band
infant_0_1 0-23 months General infancy (covers MICS infant modules, early WHO growth)
child_2_4 2-4 years (24-59 months) CFM 2-4 variant; WHO Child Growth Standards
child_5_17 5-17 years CFM 5-17 variant; also CRC definition of "child"
adolescent 10-19 years WHO definition (deliberately crosscutting with child_5_17 and adult)
adult 18+ years WG-SS / WG-ES

Topical relevance, not eligibility

age_applicability answers "which age groups does this property concern?" It is not a filter primitive for eligibility. Age-based filtering is the consumer's job, computed from date_of_birth. Under this framing, overlap between tags is a feature, not a bug: a property about adolescent reproductive health carries both child_5_17 and adolescent because the topic genuinely concerns both the under-18 bracket and the WHO 10-19 bracket.

A consumer asking "is this field relevant for a 15-year-old?" evaluates the child's age against all of the property's bands and asks whether any match. A consumer asking "is this topic adolescence-specific?" checks for the adolescent tag specifically.

Population rules

  • Only populate on properties that attach to Person. Age-applicability is meaningless on concepts without an age.
  • Not required. Absence means the property applies broadly to any age.
  • Validator enforces bibliography-implied coverage: properties cited by washington-group-ss or washington-group-es must include adult; properties cited by washington-group-cfm must include at least one of the child bands (child_2_4 or child_5_17). Properties may narrow CFM coverage where the definition text explains which variant they map to.

8. External equivalents vs. serialisation bindings

The external_equivalents field on properties was originally intended for equivalents in other ontologies (SEMIC Core Vocabularies, DCI Core): a property like given_name maps exactly to http://www.w3.org/ns/person#firstName. The match is semantic: both describe the same concept in an alternate ontology.

The same field is also used for serialisation bindings such as FHIR R4 Observation with LOINC codes. These are not equivalents in the semic/dci sense; they are instructions for how to serialise this property into a specific interop format. The distinction matters when reading a property detail page: a SEMIC row says "this concept exists in another ontology"; a FHIR/LOINC row says "when you serialise this data into FHIR, use this code."

Convention:

  • Per-item LOINC codes belong on the property (each WG item has its own LOINC code).
  • Whole-vocabulary LOINC answer-list references belong on the vocabulary (standard.uri). Example: pregnancy-status carries one LOINC answer-list URI for the whole value set.

9. Sensitivity annotations

Some properties reveal sensitive circumstances regardless of whether they identify a specific person. program_ref reveals enrollment in a specific program (which may target HIV, disability, or poverty). grievance_type reveals that someone filed a complaint.

Level When to use What it signals
standard Default. No special handling beyond normal data protection. Can be omitted (assumed if absent).
sensitive Reveals circumstances (health, poverty, victimhood) in most contexts. Requires justification to collect or disclose.
restricted Should not appear in credentials at routine service points. Requires a Data Protection Impact Assessment.

This is a practitioner warning, not a compliance label. Whether a property constitutes personal data depends on the record it appears in, not the property itself. See Selective Disclosure for credential-level classification.

10. Display escape hatches

Some properties carry schema-level semantics that are intentionally decoupled from jurisdiction-specific display requirements. The certificate_label property on Parent is an example: the data model stores role-nature (biological, gestational, legal, adoptive) on parental_role, decoupled from gender, but some jurisdictions are required by law to print gendered or positional labels ("mother", "father", "parent 1", "parent 2") on the civil certificate. Rather than forcing the schema to carry gendered codes, certificate_label provides a free-text field for the label as it must appear on the printed document. The underlying role-nature remains machine-readable and gender-neutral; the display-layer requirement is satisfied without contaminating the data model.

See a problem on this page? Report it on GitHub.