GitHub Actions workflows, actions and repository rulesets (LinkML)
Only want to ask? Install
ktl-docentinto any agent you use, by a route from the install page, and ask it about this project. It answers from the bundle and says how far each answer has been checked.Agents: if
.lokf/knowledge/index.mdexists, read it first.llms.txtsays how to weigh it.
https://lmodel.github.io/github-actions
From GitHub's documentation:
- Workflows (
GhaWorkflow, from workflow syntax): the events that run one, the access itsGITHUB_TOKENgets, and its jobs, each with its runner labels, runner group and permissions, or the reusable workflow it calls. - Reusable workflows (
GhaReusableWorkflow, from workflow syntax and reusable workflows): the inputs, outputs and secrets underon.workflow_call. - Actions (
GhaAction, from metadata syntax): the inputs and outputs of anaction.yml, and the runtimeruns.usingnames. - Rulesets and required checks (
GhaRepositoryRulesetandGhaRequiredStatusCheck, from the REST API's rules and check runs at version 2026-03-10): a ruleset's target, enforcement, ref conditions, bypass actors and rule types, and each status check it requires.emitted_byties a check to the workflow whose job reports it. - A workflow's identity in provenance:
workflow_path,workflow_repositoryandrunner_environment, as GitHub's build type writes them.
GitHub's pages are versionless, so the schema's version is their retrieval date, 2026-10-28. The schema header pins the REST API version and the SchemaStore commit of the github-workflow.json and github-action.json copied into src/github_actions/schema/schemastore/. A weekly workflow opens an issue when either changes. Release tags number the schema's versions.
These shaped the schema's design:
- SLSA: a workflow's identity comes from GitHub's build type for SLSA provenance, where a reusable workflow that signs provenance is the
builder. A required check is a technical control of SLSA's Source track, so lmodel/slsa holds the evidence that it held. - The OpenSSF Baseline and Scorecard: their controls read a workflow's inputs, its permissions, a branch's required status checks and dependency pinning, so those facts are fields.
- otterdog: a called job's check is named
caller job / called job, spaced around the slash. - LOKF and KTL: the naming rule below, the classes rooted on
Concept, and the inlined value classes, which letlokf adaptrun without--fold. - lmodel/slsa: the module layout, the release asset and the governance files.
The schema maps to three vocabularies. GhaWorkflow and GhaAction are close to CycloneDX 1.7's workflow and task, and its trigger is related to triggers. SPDX 3.0.1's Build records a run of a workflow, and in-toto's Test Result predicate records what a required check found. Both are related terms, not close ones.
Runs and events, such as CDEvents and GitHub's run logs, are records, not facts of a file. GUAC, a graph of SBOMs, provenance and scores, consumes models like this one. SCITT and RATS, which define how evidence is carried and what it means, need no class here.
scripts/derive.py reads a repository's workflow and action metadata files with yaml.safe_load. It prints:
- the frontmatter of the concept that describes each file;
- the name of each check run a top-level workflow's jobs report (the
check_contexta ruleset requires), with the job path and what can skip the job; - what the OpenSSF Baseline and Scorecard call out: write access at a workflow's top level, a caller that passes
secrets: inherit, and ausesnot pinned to a commit.
With --check and a bundle, it exits 1 on drift between the files and the concepts, on a required check that no job of its emitted_by workflow reports, or on a skip condition that a check's body does not name. Each skip condition is a finding, which fails the check under --strict. A job skipped by its own if, or by a failed or skipped job it needs, lets a required check pass without running. A path filter, or a calling job's if or needs, leaves the check pending, which blocks the merge.
scripts/github_export.py asks GitHub's REST API what the files cannot say. rulesets prints the repository's rulesets and the rules in effect on its default branch, which derive.py --rulesets compares with the ruleset and check concepts. check-runs prints what GitHub recorded on one commit, such as the head of a recent pull request, and derive.py --check-runs reports each required check that no run on it matched. On a private repository, GH_TOKEN holds a token with Metadata read, and Checks and Commit statuses read for check-runs. rulesets --organization OWNER prints an organization's rulesets, which a repository's own list holds only when their conditions select it. GitHub answers that only to a token with the organization's Administration permission, which can also change those rulesets, so a person runs it and commits what it prints rather than giving the ingest that token.
uv run scripts/derive.py --root ../host-repository
uv run scripts/derive.py --root ../host-repository --check ../host-repository/.lokf/knowledge
python3 scripts/github_export.py rulesets --repository OWNER/REPO > rulesets.md
python3 scripts/github_export.py rulesets --organization OWNER > organization-rulesets.md
python3 scripts/github_export.py check-runs SHA --repository OWNER/REPO > check-runs.md
uv run scripts/derive.py --root ../host-repository --check ../host-repository/.lokf/knowledge \
--rulesets rulesets.md --rulesets organization-rulesets.md --check-runs check-runs.mdderive.py's only dependency, PyYAML, is declared in its PEP 723 header, so uv run needs no project, and github_export.py needs Python 3.10 alone. A host copies both from a pinned release and records the version beside them. Its ingest can run github_export.py rulesets as an entry of kind: command, and the mirror file becomes the rulesets' source. The fixtures in tests/derive/ show each rule.
- docs/: the website's pages, with the generated schema pages in elements/
- examples/: usage examples
- project/: generated project files (do not edit them)
- scripts/: the upstream watch, the derivation script and the export script
- src/github_actions/schema/: the LinkML schema,
github_actions.yamland the modules it imports (edit these) - src/github_actions/datamodel/: the generated Python datamodel
- tests/: Python tests, with example data in data/
- website/: the Astro Starlight site built from the README,
docs/, the schema's pages and the knowledge bundle
Run just to list the project's just recipes.
.lokf/ holds this project's KTL knowledge bundle. Its domain schema is .lokf/github-actions.yaml, which lokf adapt writes from src/github_actions/schema/github_actions.yaml. Edit the source, never the copy. A release carries the copy as schema-<tag>-github-actions.yaml, on the terms CONTRIBUTING.md gives.
just lokf-adapt rewrites the copy, and just lokf-adapt-check says when it is stale. project.justfile names the classes the copy roots on Concept, and a concept may name any of them, or a subclass, as its type. In Obsidian, add these classes to the KTL Registrar and KTL Curator plugins' Known LOKF types setting:
GhaWorkflow, GhaReusableWorkflow, GhaAction, GhaRepositoryRuleset, GhaRequiredStatusCheck
In the copy, LOKF's id replaces each class's identifier (workflow_uri, action_uri, ruleset_uri and check_uri), and an action's name and description are the concept's title and description.
A host imports the copy beside lokf.yaml and slsa's copy, and LinkML merges the three into one namespace, where the last definition of a name wins silently. So no class, enum or type shares a name with either. A slot shares a name only where it carries LOKF's meaning and IRI (description and required), and docs/about.md lists the slots renamed to avoid LOKF's names. tests/test_schema_rules.py checks both neighbours.
The schema and the code are under the Apache License 2.0 (LICENSE).
SchemaStore's two schemas in src/github_actions/schema/schemastore/ keep their own notice, and GitHub's documentation is cited, never copied: see NOTICE.
This is not an official GitHub project, and its use implies no endorsement by GitHub.
CONTRIBUTING.md is the checklist for pull requests and releases, AI_COVENANT.md sets the rules for AI-assisted work, SECURITY.md says how to report a vulnerability, and CHANGELOG.md records the changes.
Built from the linkml-project-copier template (doi:10.5281/zenodo.15163584).