Certifications¶
The cert list on the resume, the fun room wall, /llms.txt and /api/v1/profile comes from
portfolio/src/content/certs.json. The GitHub profile reads it through that API. The file is
generated; edit scripts/sync-certs.py, not the JSON. The resume and the fun room link each cert
to its verify page; the id only goes into the Person schema and the API.
Two public sources feed it:
- Credly (
credly.com/users/morten-victor-nordbye): Anthropic, the Linux Foundation and AWS badges, each linking to its Credly badge page. The Credly id is left out ofcredentialId: it is a 36-character UUID and the url already identifies the badge. - The Microsoft Learn transcript share link: Microsoft and GitHub certifications, each linking to
its Learn share page, with the certification number as
credentialId. The transcript does not carry the credential ids those pages need, and Learn has no public list of them, so the script maps titles to ids inLEARN_IDS.
.github/workflows/sync-certs.yaml runs the script daily and opens a PR from bot/sync-certs
when the list changed. Run it locally with python3 scripts/sync-certs.py.
Traps¶
- The transcript link must stay shared. Revoking or recreating it in Learn changes its id, and
the script fails until
LEARN_TRANSCRIPTandLEARN_APIpoint at the new one. - A fetch failure exits before the file is written, so an outage never removes certs. Expired certs stay: Credly keeps listing them, and the script reads the transcript's historical list as well as the active one. A cert deleted at the source does drop from the PR; review the diff.
- Titles are normalised to what the site has always shown: GitHub certs get a "Certification" suffix and Credly's ASCII hyphen becomes an en dash.
- A new Learn cert links to the transcript until its credential id (from its share link on the
Learn profile) is added to
LEARN_IDS. - Bot PRs are opened with
GITHUB_TOKEN, so they do not triggerbuild-portfolio.yaml. That needs "Allow GitHub Actions to create and approve pull requests" on in the repo's Actions settings.