Browse this guide

Contributing

Add or correct content, improve the site, and maintain its generated metadata

Contributor guide

Start here

What we welcome, how to send it, and how content is reviewed

Ways to contribute

cpp.social is a community-maintained project - your help is required to keep this site up to date and ensure we're listing the resources people actually care about.

If you notice missing resources, wrong descriptions and other mistakes or have general feedback on how to improve the usability to this site, please do reach out. While we prefer it where possible, you do not have to submit a pull request for your suggested changes - it is also possible to let us know through an issue.

For content submissions, please check for duplicates first and make sure the suggested content fulfills our content requirements.

Content PRs require two approvals

Every content change needs at least two approvals by current curators or maintainers before we can accept it. You can find a list of current maintainers and curators on the About page.

What we list

Content must be relevant to C++ developers and have a stable public page.

  • Tutorials, guides, and other learning resources must be free to access in full, without a purchase or subscription. Books are of course exempt from this.
  • Books, blogs, and YouTube channels must contain substantive human-created work. Purely AI-generated publications are not eligible.
  • Tooling must have real users beyond personal experiments or toy projects. Include available evidence of use, such as public projects that depend on them.

Use direct links

Use canonical HTTPS URLs without tracking parameters. URL shorteners, referral or affiliate links, and vanity links are not accepted.

Submit a pull request

To locally build the site, you will need Python 3.13 or newer and Node.js 24 (the version used in CI). The rest of the tooling can be installed by invoking make install.

  1. Read the relevant guide below and edit the relevant file(s). Follow a nearby entry's structure and use only supported fields.
  2. Optional: If the entry needs fetched metadata, you may run the guide's updater command for that entry (do inspect the output to ensure there's no unrelated changes!).
  3. Run make build and check the affected page under build/.
  4. Open a pull request against cppsocial/site. Describe the change and explain why it was made.

For code changes, also run make check-format, make lint, and make test. If formatting fails, use the matching make format-* command shown in the failure message.

Generated files

Add content through the source files named in these guides, not by editing generated files under data/.

Related metadata changes are welcome

Content PRs may include related data/ changes, such as the initial ingest or a targeted refresh for a new blog or YouTube channel. Leave out metadata changes for unrelated entries.

However, this is purely optional.

Hand-maintained exceptions are covered in the Packages and Content maintenance guides.

Contributor guide

Directory entries

Resources, guides, ecosystem tools, standards links, and recurring conferences

Pick the destination

EntryFile
General reference or online toolcontent/resources/general.yaml
Guide, FAQ, or learning materialcontent/resources/guides.yaml
Compiler or toolchaincontent/ecosystem/compilers.yaml
Build system or project generatorcontent/ecosystem/builds.yaml
Library or standard-library implementationcontent/ecosystem/libraries.yaml
Package manager as a toolcontent/ecosystem/packages.yaml
ABI resourcecontent/ecosystem/abi.yaml
General standardization resourcescontent/evolution/resources.yaml
Related technical standardcontent/evolution/related-standards.yaml
Active recurring conference seriescontent/events/conferences.yaml
Conference series no longer runningcontent/events/past-conferences.yaml

Events and registry packages have separate guides

For dated events, follow the Events guide. For packages listed in a registry, follow the Packages guide.

Add a card

Add a record under the existing cards list:

- title: Example Tool
  path: https://example.org/
  description: Short factual explanation of its use in C++
  metadata:
    License: MIT
  links:
    - {label: Documentation, path: https://example.org/docs/}
    - {label: Source, path: https://github.com/example/tool}

Requirements

  • Provide a concise title and the canonical HTTPS path
  • Explain the entry's relevance to C++ in a short, factual description
  • Check that the entry is public and not already listed; for active projects, look for recent releases or development
  • For a project or tool, show that it has real users and is relevant to C++ developers
  • Add metadata and secondary links only when they help someone evaluate or use the entry
  • Use labels already established in that section
  • Follow the shared URL, description, and YAML rules in the Style guide

Icons and hidden entries

Omit icon to discover the site's favicon automatically. Set icon: null when no icon should be displayed. Use an explicit HTTPS image URL only when favicon discovery gives the wrong result.

No hidden placeholders

Use hidden: true only to hide an existing entry. New entries must be complete and visible.

Check the result

Run make build, open the affected page under build/, and check the card at narrow and wide widths. Confirm that every link works and that the description does not duplicate the title.

Contributor guide

Stylistic conventions

The conventions that apply across repository content

Descriptions

  • Write one factual sentence and do not end it with a period
  • Use the project's own description if it is clear and factual, otherwise summarize what it does
  • Avoid first person, superlatives, calls to action, download counts, and other marketing claims
  • Preserve the project's own spelling and capitalization

URLs and sources

  • Use canonical HTTPS URLs without tracking parameters or fragments unless the fragment is essential
  • Prefer first-party project, organizer, publisher, or repository pages
  • Use a primary resource for event dates and corrections, not a search result or social repost
  • Keep link labels short and consistent with nearby entries
  • Discord invites must be permanent and cannot be vanity links

YAML

  • Copy the indentation and field order of a nearby record
  • Quote strings that YAML could misread, such as "yes", "0123", or text containing : or #
  • Use ISO YYYY-MM-DD dates and IANA timezone names
  • Keep locally assigned IDs lowercase, unique, and stable
  • Preserve external identifiers exactly, including case in YouTube channel IDs, Discord invite codes, and package IDs
  • Do not reformat unrelated entries in a content pull request

The $schema line describes the whole document and should not be changed when adding a record. Unknown fields fail schema validation.

Markdown

Use semantic line breaks for prose in docs/ and other long-form Markdown. Use sentence-case headings, fenced code blocks with a language, and relative links for repository documentation.

Contributor guide

Communities

Discord, Slack, IRC, Reddit, forums, and meetup groups

Chat, forum, and Q&A communities

Add chat communities to the cards list in content/communities/im.yaml and forums or Q&A sites to the cards list in content/communities/forums.yaml. Every community_id must be unique and must not change after publication.

- community_id: example-community
  metadata_source: {source: web, key: 'https://example.org/community/'}
  title: Example C++ Community
  platform: forum
  path: https://example.org/community/
  description: Public forum for C++ library design and implementation questions

Allowed platform values are discord, slack, irc, reddit, and forum. Allowed metadata sources are discord, web, reddit, and stackoverflow. For web, the key is the canonical page URL; for Reddit, it is the subreddit name without r/. For Stack Overflow, use the encoded tag c%2B%2B as the key.

Communities must be public, active, and substantially about C++. Use a direct community URL and a description of its audience or focus.

Discord

Non-expiring, non-vanity invites only

Use an active invite with no expiry. Server vanity or custom invites are not accepted.

Copy the code after discord.gg/ from the community's invite, or create an invite with expiry set to Never if you have permission. Use that code as both the URL suffix and metadata key:

- community_id: example-discord
  metadata_source: {source: discord, key: Ab3dE9xYz2}
  title: Example C++ Discord
  platform: discord
  path: https://discord.gg/Ab3dE9xYz2
  description: Public chat for C++ developers working on embedded systems

The PR check uses Discord's API to check that the invite resolves, has no expiry, and is not the server's vanity code. Open it to confirm that it leads to the intended community.

Check the result

For a new community, fetch only its metadata, then build:

make communities ID=example-community
make build

For Meetup groups, run make events, then make build and inspect /events/. This refreshes all configured event feeds; leave unrelated changes out of the PR. See Generated files for when to include updater output.

Contributor guide

Blogs, books, and YouTube

Sources whose metadata is fetched after review

Blogs

Add the source to content/blogs/sources.yaml:

- id: example_blog
  title: Example C++ Blog
  author: Ada Example
  website_url: https://example.org/
  rss_url: https://example.org/feed.xml

The blog must publish substantial C++ content and provide a public RSS or Atom feed.

  • Choose a unique lowercase id based on the publication name and follow the naming convention in the file.
  • Copy the title and canonical website URL from the blog. Include author if it names an individual author.
  • Find the feed through the site's RSS or Subscribe link, or the page source's RSS/Atom alternate link. Open it and check that it contains post URLs and publication dates.
  • Add a description only if the title does not explain the source.

sitemap_url may be required to properly backfill the blog's content archive. You do not need to do this for a content PR, but you can if you want.

Backfilling is done by executing meta-updater blogs ingest --id example_blog. The normal make blogs command only fetches the RSS feed to discover new posts.

YouTube channels

Add a channel to the cards list in the file matching its owner:

ChannelFilechannel_type
Independent creator or educatorcontent/youtube/channels.yamlcreator
Conference archivecontent/youtube/conferences.yamlconference
Organizationcontent/youtube/organizations.yamlorganization
Podcast or recurring showcontent/youtube/organizations.yamlshow
- title: Example C++ Channel
  channel_type: creator
  channel_id: UCxxxxxxxxxxxxxxxxxxxxxx

The channel must publish substantial C++ material. Copy its title from the channel header and choose the file and channel_type from the table above.

Use the channel ID

Use the stable ID beginning with UC, not a handle, playlist, or video ID.

On desktop, open the channel, expand its description with more, then choose Share channel → Copy channel ID (YouTube Help Community instructions). For your own channel, you can also use Advanced settings. Open https://www.youtube.com/channel/<channel_id> to check that it is the intended channel.

Do not manually add video IDs, thumbnails, descriptions, or feed URLs - those are fetched automatically by the metadata updater.

Books

Add an ISBN record to the cards list in content/books/books.yaml (this example is already listed):

- { isbn: "9780321563842" }

Use the quoted 13-digit ISBN from the publisher page or copyright page for the exact edition and format you want to list. Hardbacks, paperbacks, ebooks, and later editions can have different ISBNs.

Book metadata is fetched automatically

Submit only the ISBN and, if needed, a cover override. Open Library supplies the title, author, publisher, and description.

Only add cover_url when Open Library has no usable cover or returns the wrong edition:

- isbn: "9780321563842"
  cover_url: https://example.org/covers/9780321563842.jpg

The override must be a stable HTTPS image URL that the project is allowed to display.

Generated metadata

Run the command for the entry you added, then build:

make blogs ID=example_blog
make youtube ID=UCxxxxxxxxxxxxxxxxxxxxxx
make books ID=9780321563842
make build

The ID must already exist in the relevant curated file. To refresh multiple entries, repeat --id, for example meta-updater blogs all --id first_blog --id second_blog.

Check the affected page for the correct publication and metadata. Do not create or edit cache files by hand. See Generated files for when to include updater output in the PR.

Contributor guide

Events

Conferences, workshops, committee meetings, and individual meetup events

Meetup groups

Add a group to the cards list in content/events/meetups.yaml only when it exposes a public Meetup iCalendar feed. The updater imports individual occurrences from that feed.

- type: meetup_card
  source_id: example-cpp
  timezone: Europe/Paris
  title: Example C++ Meetup
  path: https://www.meetup.com/example-cpp/
  description: Regular C++ meetup in Paris
  metadata:
    Location: Paris, France
  links:
    - {label: RSS feed, path: https://www.meetup.com/example-cpp/events/rss/}
    - {label: Calendar, path: https://www.meetup.com/example-cpp/events/ical/}

Include the meetup type

Set type: meetup_card on the entry itself. The event importer does not use the group's card_type default.

Use the group name from meetup.com/<group-name>/ as source_id, in lowercase. Choose the group's timezone from IANA's list, for example Europe/Paris. Copy the group calendar feed using Meetup's export instructions. Include exactly one calendar link ending in /events/ical/ (the trailing slash is optional). Open the link to check that the feed is public. Do not copy imported occurrences into content/events/events.yaml.

Recurring series or dated occurrence

A recurring conference series is a directory card in content/events/conferences.yaml. Move a series to content/events/past-conferences.yaml when it is no longer running. Follow the Directory entries guide for that record.

Add a specific conference, workshop, committee meeting, or one-off meetup to the YAML list in content/events/events.yaml.

Do not duplicate imported events

Meetup events from configured calendar feeds are imported automatically. Do not add them to content/events/events.yaml.

Add a dated event

- ical_uid: exampleconf-2027@cpp.social
  title: ExampleConf 2027
  description: Two-day conference focused on C++ systems programming
  start_date: 2027-04-12
  end_date: 2027-04-13
  location: Paris, France
  venue: Example Convention Centre
  format: in_person
  event_type: conference
  organizer: Example C++ Association
  path: https://example.org/2027/
  registration_url: https://example.org/2027/register/
  source_url: https://example.org/2027/announcement/
  source_name: ExampleConf
  last_verified: 2026-09-07

Requirements

  • Provide ical_uid, title, start_date, event_type, and source_url
  • Provide the canonical event URL, format, organizer, location, and a useful factual description when available
  • Keep ical_uid globally unique and stable; use a readable slug and year followed by @cpp.social
  • Use ISO 8601 YYYY-MM-DD dates; end_date is the final day of the event
  • Allowed format values are in_person, online, and hybrid
  • Allowed event_type values are conference, meetup, committee, and workshop
  • Omit registration_url or venue when they are not known
  • source_url must link directly to first-party evidence for the date and location
  • Set status to tentative or cancelled when applicable; otherwise omit it
  • Set last_verified to the date on which the source was checked

Times are optional

Omit start_time and end_time for multi-day events or when times are not published. For a single-day event, you may add its published start and end times as quoted HH:MM values, with a timezone from IANA's list.

Check the current announcement

Only add an event once the organizer has published its date. Do not reuse a previous year's location, venue, or format without checking the current announcement.

Check the calendar

Run make build and inspect /events/ in the build output. Check multi-day boundaries, timezone labels, external links, and the generated calendar entry.

Contributor guide

Packages

Missing registry packages, metadata corrections, and package matching

Missing packages

The package search is built from supported package-manager registries. There is no hand-written package list in this repository.

If a package is missing from its registry, add it upstream first. If it exists upstream but is absent from cpp.social, open a content-correction issue with:

  • The package manager and exact package ID
  • The upstream registry or recipe URL
  • The expected project homepage or repository
  • The date on which you confirmed it was present upstream

Registry catalogs are generated

Do not add records directly to data/packages/conan.yaml, meson.yaml, spack.yaml, or another manager catalog.

Correct a metadata field

First fix the upstream registry when possible. For a local metadata fix, add a corrections entry to data/packages/overrides.yaml. These entries use PackageFieldCorrection in the schema:

corrections:
  - package: vcpkg:example
    field: homepage
    operation: replace
    value: https://example.org/
    reason: Registry metadata still points to the retired project site

package is the exact ID from a registry catalog, such as vcpkg:fmt. field names a field on that package; add version to target one exact version instead. replace is the default operation; remove deletes a field, and add appends unique values to a list field. Explain the correction in reason and link to its source in the PR description.

See the override schema and correction code for the supported fields and behavior.

Group packages from the same project

Records for the same upstream project can be grouped under groups in data/packages/overrides.yaml. These entries use PackageGroupOverride, which has different fields from a metadata correction:

groups:
  - id: example
    name: Example
    packages:
      - conan:example
      - vcpkg:example
    reason: These recipes use the same upstream repository

Replace the example IDs with exact IDs from the registry catalogs. id, name, aliases, and reason are optional; packages is required.

Every ID in packages must already exist in the saved registry catalogs; a missing ID fails package publishing. Do not add placeholders for packages that are not yet available.

To keep two packages separate, add a never_merge record with those two IDs under packages and a reason.

preferences selects the source for a merged entry's summary or licenses. Its package is the entity ID from data/packages/entities.yaml; its source is a registry package ID belonging to that entity. The schema also accepts URL fields here, but the current browser build does not apply those preferences.

Package matching changes require updater tests.

Matching output is generated

Edit data/packages/overrides.yaml, not the generated entities.yaml or matches.yaml.

Check package changes

Run make package-publish to apply overrides to the saved catalogs and regenerate package identities and matches, then make build to update the browser data. Run make packages only when the registries need fetching again. For matching changes, also run make test. Check the affected package details and leave unrelated generated changes out of the PR.

Contributor guide

Code, UI, and docs

Templates, styles, browser code, updater changes, and documentation

Put the change in the right subtree

ChangeLocation
Site contentcontent/
Text for UI elementsui/
Site and page settingsconfig/
Page-specific templatestemplates/pages/
Reusable UI componentstemplates/components/
Top-level sectionstemplates/blocks/
Client-side JS codefrontend/
Stylesheets and static filesassets/
Browser data generationsite_plugins/
Metadata updaterupdater/
Contributor and maintainer documentationdocs/

UI changes

The primary CSS entrypoint is assets/static/style.css. All other stylesheets should be put in assets/static/styles, especially when that stylesheet is specific to some page or feature.

Keep the import order unless the change needs a different CSS cascade.

Check keyboard navigation, focus visibility, narrow layouts, dark mode, empty states, and long titles. Include screenshots or a short recording in the pull request for visible changes.

Updater changes

Network failures, empty responses, and malformed source data must not replace a valid dataset. Keep output deterministic and preserve provenance URLs and retrieval timestamps.

Do not mix a broad metadata refresh into an updater code change. Use small fixtures rather than live network calls in tests.

Documentation changes

The contributing page renders the files under docs/ in the order declared by content/contributing/_index.yaml. Create new documentation files under docs/ and register each one in the index with a title, stable anchor ID, description, and !include entry.

Run make build and inspect /contributing/ at desktop and mobile widths.

Maintainer guide

Content maintenance

Content review guidelines and manual update and override procedures

Review a content submission

  1. Confirm that the entry is C++-relevant, public, maintainable, and not duplicated.
  2. Check that it is in the file named by the contributor guide and matches a nearby record.
  3. Open the canonical URL, all secondary links, and the first-party verification source.
  4. Verify names, identifiers, dates, timezone, location, and factual claims.
  5. Check the hard constraints for the content type.
  6. (Optionally) Run make build and inspect the affected rendered page or request a preview in the PR (/preview command).

Some CI checks may run (e.g. for Discord we verify that links are active, non-expiring and not a vanity link), inspect their output.

Two approvals are required

A pull request that changes any file under content/ may be accepted only after approval from at least two current maintainers or curators listed on the About page.

Manually refresh metadata

Install the tools once with make install.

To update metadata for some specific new content, prefer running a narrow updater rather than make update-all.

Curated changeCommand
Blog sourcemake blogs ID=<source-id>
Book ISBNmake books ID=<isbn>
Communitymake communities ID=<community-id>
Meetup calendar sourcemake events
YouTube channelmake youtube ID=<channel-id>
Package override onlymake package-publish
Package registry sourcesmake packages

These commands update data/. All fetch remote sources except make package-publish, which uses saved catalogs. make events refreshes every configured Meetup feed - it has no per-group ID option.

Content PRs may include related data/ changes, such as the initial ingest or a targeted refresh for a new blog or YouTube channel. Do not include metadata changes for unrelated entries.

For metadata patches, verify:

  • Expected source IDs appear once and in the correct dataset
  • Provenance names the URLs actually fetched
  • Existing records were not removed because of a transient or empty response
  • Sorting and serialization are stable
  • No unrelated updater output is included

For updater code changes, run:

make check-format
make lint
make test
make build

Add overrides

  • Manually added events go to content/events/events.yaml, never data/events-imported.yaml
  • To suppress a fetched post or video, keep its post_id or video_id and set hidden: true in data/blogs/posts/<source-id>.yaml or data/youtube/videos/<channel-id>.yaml. Other fields may be removed from that hidden record
  • Put package corrections and merge decisions in data/packages/overrides.yaml, never in generated manager catalogs
  • Apart from these overrides and hidden records, do not hand-edit fetched metadata, provenance, imported events, package entities, or match output

To remove registry records from package search, add a fully qualified manager ID to ignored or a stable, manager-qualified prefix to ignored_prefixes in data/packages/overrides.yaml. Make sure to do this for every affected package manager.

Run make package-publish, then make build, and confirm the primary package and its graph edges are absent.

Maintainer guide

Triage

Issue forms, types, and labels used to route repository work

To make long-term maintenance of the site easier, please make sure issues are tagged correctly.

We currently use only a small number of thematic labels, since the issue content generally makes it clear what kind of issue it is.

Issue types

TypeUse
AdditionNew directory or calendar entry
CorrectionExisting content is stale or wrong
BugSite or updater behavior is broken
FeatureNew feature suggestions

Labels

LabelUse
communityAdditions to the communities page
eventChanges to the events page
publicationBlogs, books, or YouTube channels
resourceResource or ecosystem listing
uiTemplates, styles, UI configuration etc.
updaterMetadata updater changes
documentationImprovements or additions to documentation
duplicateThis issue or pull request already exists

Admin guide

Site administration

Documentation for administration of the site and the Github organization

Hosting

The site is published at cpp.social through GitHub Pages from cppsocial/site. The deployment workflow also triggers a separate mirror repository.

To manually redeploy, rerun the build-deploy.yaml workflow.

Redeploying manually

Make sure to only ever run the build-deploy.yaml workflow on master. Deploying from other branches interferes with our metadata handling and may break the page.

Pull request previews

Pull request previews are opt-in because the preview builds code from the pull request. After reviewing the change, a repository collaborator with write access can comment /preview on the pull request. The workflow records the current pull request commit, refreshes only metadata selected by changed curated records, builds without repository secrets, and deploys the resulting artifact to https://pr-<number>--cppsocial.netlify.app.

The deploy uses the netlify-preview environment, never github-pages. On success, the workflow comments with the preview URL and Netlify CLI output.

Tokens & Mirror

The content of the primary site is mirrored onto cppsocial.github.io via Github actions. This is a separate repository (and just republishes the build artifacts from the primary repo) to prevent Github from redirecting to cpp.social.

To facilitate this, there's two PATs in place: - GH_IO_MIRROR gives cppsocial/site R/W access to actions in cppsocial/cppsocial.github.io. This is used to start the mirroring action after a successful site built. - GH_IO_SOURCE gives cppsocial/cppsocial.github.io read access to cppsocial/site's action artifacts

These might need updating every now and then.

Adding Maintainers/Curators

Checklist:

  • Add new maintainer or curator to MAINTAINERS.md
  • Invite them to the cppsocial organization here
  • Add them to the appropriate teams (always add Maintainers to the Curator team as well!)

MAINTAINERS.md Changes

New maintainers/curators may add themselves to MAINTAINERS.md and are encouraged to do so.

If we instead open that PR for them, make sure they approve the PR before merging.