Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .github/workflows/leadership-refresh.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Leadership roster refresh check

# Deterministic, no-AI change detector for the _leadership dataset.
# Weekly it fetches each foundation's leadership page, hashes the visible text,
# and compares against _data/leadership-refresh-state.json. If any roster page
# changed, it opens an issue listing the foundations that need re-extraction, so
# a maintainer or an AI coding agent only revisits the pages that actually moved.

on:
schedule:
- cron: "17 6 * * 1" # Mondays 06:17 UTC
workflow_dispatch: {}

permissions:
contents: read
issues: write

jobs:
detect-changes:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.x"
- name: Detect changed leadership pages
id: detect
run: |
python3 assets/python/leadership_refresh.py --check --output changed.json | tee summary.txt
count=$(python3 -c 'import json,sys; print(len(json.load(open("changed.json"))))' 2>/dev/null || echo 0)
echo "count=$count" >> "$GITHUB_OUTPUT"
- name: Write job summary
run: cat summary.txt >> "$GITHUB_STEP_SUMMARY"
- name: Open issue if rosters changed
if: steps.detect.outputs.count != '0'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh issue create \
--title "Leadership rosters changed ($(date +%Y-%m-%d))" \
--body-file summary.txt \
--label leadership || true
74 changes: 74 additions & 0 deletions _data/leadership-schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
"$schema": "http://json-schema.org/draft-06/schema#",
"$id": "https://fossfoundation.info/leadership/asf.json",
"type": "object",
"title": "FOSS Foundation Leadership Schema",
"description": "Current governing people (board, officers, paid staff) for a FOSS foundation, keyed by the same identifier as its _foundations record. Complements the foundation model's boardSize / boardType / numberOfEmployees counts with the named individuals. Person type derives from Schema.org Person. Every fact carries a source URL and a confidence; absent data is null, never guessed.",
"required": ["identifier", "asOf", "people"],
"properties": {
"identifier": {
"section": "General",
"title": "Foundation identifier",
"description": "Matches the _foundations/<identifier>.md filename.",
"type": "string"
},
"commonName": {
"title": "Common Name",
"description": "Common name of the foundation, for readability.",
"type": "string"
},
"asOf": {
"title": "As Of Date",
"description": "Date this leadership roster was last verified against source. Answers the open metadata-freshness question in CONTRIBUTING.",
"type": "string",
"format": "date"
},
"sources": {
"title": "Sources",
"description": "Official URLs the roster was verified against.",
"type": "array",
"items": {
"type": "object",
"required": ["url"],
"properties": {
"url": { "title": "Source URL", "type": "string", "format": "url" },
"type": { "title": "Source Type", "description": "e.g. org_live, bylaws, annual_report.", "type": "string" },
"retrieved": { "title": "Retrieved Date", "type": "string", "format": "date" }
}
}
},
"people": {
"title": "People",
"description": "Governing individuals. Include only verifiable roles; never guess.",
"type": "array",
"items": {
"type": "object",
"required": ["name", "roles", "sourceUrl", "confidence"],
"properties": {
"name": { "title": "Name", "description": "Full name exactly as the foundation publishes it.", "type": "string" },
"personId": { "title": "Person ID", "description": "Stable cross-foundation id; null until entity resolution assigns one.", "type": ["string", "null"] },
"roles": {
"title": "Roles",
"description": "One or more governance roles held by this person.",
"type": "array",
"items": {
"type": "object",
"required": ["role", "roleClass"],
"properties": {
"role": { "title": "Role", "description": "Role title as published, e.g. President, Board Director.", "type": "string" },
"roleClass": { "title": "Role Class", "description": "Normalised class of the role.", "type": "string", "enum": ["board_director", "officer", "paid_staff", "volunteer"] }
}
}
},
"contact": { "title": "Contact", "description": "Per-person contact if the foundation publishes it, else null.", "type": ["string", "null"] },
"bio": { "title": "Bio", "description": "Published biography, verbatim, else null.", "type": ["string", "null"] },
"termStart": { "title": "Term Start", "description": "Only if explicitly stated by the foundation, else null.", "type": ["string", "null"] },
"termEnd": { "title": "Term End", "description": "Only if explicitly stated by the foundation, else null.", "type": ["string", "null"] },
"sourceUrl": { "title": "Source URL", "description": "Page the person and role were read from.", "type": "string", "format": "url" },
"derived": { "title": "Derived", "description": "How the record was captured, e.g. org_live.", "type": "string" },
"confidence": { "title": "Confidence", "description": "1.0 for facts stated verbatim; lower when inferred, with a note in the body.", "type": "number", "minimum": 0, "maximum": 1 }
}
}
}
}
}
9 changes: 9 additions & 0 deletions _data/leadership-template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
identifier: # Foundation id; must match the _foundations/<identifier>.md filename
commonName: # Common name of the foundation
asOf: # Date this roster was last verified against source (YYYY-MM-DD)
sources: # List of official URLs verified against; each with url, type, retrieved
people: # List of governing people; per-person fields are in leadership-schema.json
---

LEADERSHIP_TEMPLATE To add a leadership roster, copy this file to _leadership/<identifier>.md using the same identifier as the foundation's _foundations record. Fill the people list with board directors, officers, and paid staff you can verify against official sources (from that foundation, not wikipedia or the like). Never guess: leave a field null and note it in the body if unknown. Every person carries a sourceUrl and a confidence; use 1.0 only for facts stated verbatim. Field descriptions are in the leadership-schema.json file. Then replace this section (the content of the Jekyll document) with a short factual note on scope, provenance, and any gaps. Submit a PR with this new identifier.md file in the _leadership directory.
110 changes: 110 additions & 0 deletions _leadership/almalinux.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
---
identifier: almalinux
commonName: AlmaLinux OS Foundation
asOf: 2026-07-25
sources:
- url: https://almalinux.org/foundation
type: org_live
retrieved: 2026-07-25
people:
- name: benny Vasquez
personId: null
roles:
- role: Chair, Board of Directors
roleClass: officer
- role: Board Director
roleClass: board_director
contact: null
bio: null
termStart: 2022
termEnd: 2029
sourceUrl: https://almalinux.org/foundation
derived: org_live
confidence: 1.0
- name: Jack Aboutboul
personId: null
roles:
- role: Board Director
roleClass: board_director
contact: null
bio: Program Manager, Microsoft Azure AOSI
termStart: 2022
termEnd: 2027
sourceUrl: https://almalinux.org/foundation
derived: org_live
confidence: 1.0
- name: Simon Phipps
personId: null
roles:
- role: Board Director
roleClass: board_director
contact: null
bio: Open source advocate, former president of OSI
termStart: 2022
termEnd: 2027
sourceUrl: https://almalinux.org/foundation
derived: org_live
confidence: 1.0
- name: Moshe Bar
personId: null
roles:
- role: Board Director
roleClass: board_director
contact: null
bio: CEO, Codenotary Inc.
termStart: 2022
termEnd: 2028
sourceUrl: https://almalinux.org/foundation
derived: org_live
confidence: 1.0
- name: Daniel Pearson
personId: null
roles:
- role: Board Director
roleClass: board_director
contact: null
bio: CEO, KnownHost
termStart: 2022
termEnd: 2028
sourceUrl: https://almalinux.org/foundation
derived: org_live
confidence: 1.0
- name: Alex Iribarren
personId: null
roles:
- role: Board Director
roleClass: board_director
contact: null
bio: Penguin Wrangler and Cloud Watcher, CERN
termStart: 2023
termEnd: 2029
sourceUrl: https://almalinux.org/foundation
derived: org_live
confidence: 1.0
- name: David Snead
personId: null
roles:
- role: Board Director (Non-voting Invited Expert)
roleClass: board_director
contact: null
bio: General Counsel, WebPros
termStart: null
termEnd: null
sourceUrl: https://almalinux.org/foundation
derived: org_live
confidence: 1.0
---

# AlmaLinux OS Foundation — Leadership

Scope: the AlmaLinux OS Foundation Board of Directors as published on the foundation page. The foundation is a 501(c)(6) governed by a community-elected board with four-year staggered terms; the board elects its own officers, including the chair.

Roster: seven directors listed — six voting plus one non-voting invited expert (David Snead). benny Vasquez is Chair (captured as both officer and board_director). The remaining voting members carry only board_director.

Term dates: the page states each director's election year ("Elected YYYY") and term end ("Term ends YYYY"), captured verbatim as term_start / term_end with confidence 1.0. Term dates reflect the staggered four-year cohorts established by the amended bylaws adopted April 2026. David Snead is a non-voting invited expert with no stated term.

Paid vs volunteer: the board operations statement says "No paid board roles," so all directors are unpaid governance roles (board_director / officer), confidence 1.0. No separate paid-staff / Executive Director role is published on this page.

Bios: no narrative bios are published. Each person carries a one-line employer/title descriptor from the roster card (e.g. "CEO, Codenotary Inc."), captured verbatim in the bio field. benny Vasquez's card shows only the role/foundation, so bio is null.

Contact: no per-person contact is published (foundation contact is hello@almalinux.org only), so contact is null for all.
Loading