programminghistorian/jekyll: the Jekyll site behind The Programming Historian
Jekyll-based static site for The Programming Historian
At a glance
- What is it?
- The programminghistorian/jekyll repository holds the source of the live Programming Historian site, a multi-language set of digital humanities lessons built on Jekyll with a Netlify deploy and an HTMLProofer link check in the Makefile. It is a content repository with a build pipeline, not a theme, and the site is maintained by a named technical manager.
- Who is it for?
- programminghistorian/jekyll fits an editor or translator who wants to contribute a lesson to The Programming Historian, or a maintainer who wants to see how a large multi-language Jekyll site is structured and checked. It is the wrong tool if you want a starter theme, since this is one site rather than a reusable framework, and it is the wrong tool for a site with heavy dynamic content, since the whole model is static files built by Jekyll.
- Can I use it commercially?
- Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly HTML, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
This is one site's source, not a framework
The README describes this as the main repository for the Programming Historian, at programminghistorian.org, where the files for the live website are kept. That sentence sets the scope precisely. This is not a Jekyll theme, not a starter, and not a plugin. It is the content and configuration of one specific publication, a set of open educational resources for digital humanities with lessons on web scraping, text analysis, network analysis, mapping, and data management, plus a project team and a translation process. The audience is therefore two groups. The first is an instructor or student who wants to use or translate the lessons, and the second is a contributor who wants to add to the site, and for the second group the README points to a separate submissions repository for tutorials in submission.
The Makefile is the entire build and check pipeline
The Makefile at the repository root is short and shows exactly what the project does on every change. There is a build target that runs the bundle exec jekyll build, a check target that runs HTMLProofer over the built site, and an all target that does clean, build, and check in sequence. The check target is where the interesting decisions live, because it configures which links the project is willing to fail on:
check:
@echo "Checking internal and external HTML links..."
$(BUNDLE) exec htmlproofer $(SITE_DIR) \
--assume-extension .html \
--ignore-missing-alt \
--ignore-empty-alt \
--allow-missing-href \
--no-check-internal-hash \
--no-enforce-https \
--only-4xx \
--ignore-status-codes 429,403,400,415 \The `--only-4xx` flag means server errors and 5xx responses do not fail the build, which is the difference between a check that is useful and one that is always red because a third party is down. The `--ignore-status-codes` list then carves out specific client errors, 429, 403, 400 and 415, which are the ones a link checker tends to trip over on real sites.
A separate target checks internal links only
There is a `check-internal` target that runs the same check with external links disabled, and it does so by passing the flag through the `HTMLPROOFER_ARGS` variable rather than by duplicating the command. The Makefile declares `HTMLPROOFER_ARGS ?=` at the top, and the check target ends with `$(HTMLPROOFER_ARGS)`, so the internal-only run appends `--disable-external` to the same invocation. That is a small but useful design. External link checking depends on the network and on other people's servers, so it belongs in a nightly or scheduled job, while internal link checking depends only on the repository and belongs in a pull request check. A `clean` target removes the site directory, and the `SITE_DIR` and `BUNDLE` variables are overridable from the command line, so a different output directory or a different bundle command is a one-line change rather than a fork.
The repository layout is a four-language content tree
Based on the repository listing, the site is organised around its translations. There are `en/`, `es/`, `fr/`, and `pt/` directories at the top level, and there is a `translation-concordance.md` file whose name alone suggests a mapping between lessons across those language versions. Alongside them sit the usual Jekyll structure: `_config.yml` for site configuration, `_data/` for data files, `_includes/` and `_layouts/` for the template layers, `_plugins/` for Ruby plugins, `_posts/` for blog posts, and `assets/`, `css/`, `js/`, and `images/` for static content. There is a `blog/` directory separate from `_posts/`, plus `gallery/`, `researchpapers/`, `avatars/`, and a root `index.md`. The `gh-pages` default branch and the Netlify deploy badge in the README indicate that the built site is served from that branch, with Netlify running the build for the preview site.
Two workflow repositories keep content and code separate
The contribution path is split across several places, and understanding which is which saves a wasted pull request. Tutorial submissions go to a separate repository, the Programming Historian Submissions one, while this repository holds the files for the live website. Site suggestions go to the Issues tab, and the README is explicit that an issue is public, with private correspondence handled by contacting one of the current managing editors listed on the Project Team page of the site. The contributions page on the website carries detailed instructions for authors, reviewers, and editors, and the Project Wiki holds the technical contribution guidance and the policies for new language sub teams interested in creating a translation. The technical manager is named as Zoe LeBlanc. A Code of Conduct file sits at the repository root, and the project has a Zenodo DOI badge, which is how a course site like this gets citable.
A link checker with a long ignore list tells you what this site links to
The HTMLProofer invocation includes an `--ignore-urls` list and an `--ignore-files` list, and both are more informative than they look. The ignored URLs include the project's own GitHub organisation, Project Gutenberg, an `/espanol/` path, a `/deprecated/` path, and a set of external sites that are known to block automated requests, among them the British Museum collection, HathiTrust analytics, DocNow, a Doxygen site, a DOI resolver pattern, an Omeka manual, and a University of Alabama PDF on a web archive link. The ignored files are the directories where broken links are expected: assets, the blog, posts, and the retired lessons folders in each language, such as `/en/lessons/retired/`, `/es/lecciones/retirada/`, `/fr/lecons/retrait/`, and `/pt/licoes/retiradas/`. A site with translated lesson archives is exactly the kind of project where a naive link check would fail on every archived translation, so the ignore list is doing necessary work.
Where this repository is the wrong thing to reach for
Two limits are worth being clear about. The first is that it is not a general purpose starting point. There is no gem you can install and no theme you can reuse, because what is here is one site's configuration, its plugins, its content, and its own link-checking rules. Anyone wanting a Jekyll site with a similar structure will find it instructive to read and awkward to adopt. The second is the dynamic content question. The model is static Markdown and HTML built by Jekyll, and the presence of `_plugins/` means Ruby runs during the build, which is the point where a site like this either stays fast and simple or acquires a build that is hard to keep fast. The repository also has a `_build/` directory at the root and a `Gemfile.lock` and a `.ruby-version`, so the Ruby and gem versions are pinned, and the Netlify status badge implies the deploy runs the same build the Makefile describes.
Editorial conclusion
programminghistorian/jekyll fits an editor or translator who wants to contribute a lesson to The Programming Historian, or a maintainer who wants to see how a large multi-language Jekyll site is structured and checked. It is the wrong tool if you want a starter theme, since this is one site rather than a reusable framework, and it is the wrong tool for a site with heavy dynamic content, since the whole model is static files built by Jekyll. Before you open a pull request, read the contributions page for the author, reviewer, and editor workflow, read the Project Wiki for the technical and translation policy, and check the `gh-pages` branch, since that is the default branch and where the live site is served from.
Frequently asked questions
What is programminghistorian/jekyll?
It is the main repository for The Programming Historian at programminghistorian.org, where the files for the live website are kept. The site is a Jekyll-based collection of multi-language digital humanities lessons covering scraping, text analysis, network analysis, mapping, and data management.
How do I build the Programming Historian site locally?
The Makefile has a build target that runs `bundle exec jekyll build` into the `_site` directory, a clean target that removes it, and an all target that runs clean, build, and check. The build and check steps are driven by Bundler, so the gem versions in the Gemfile.lock and the `.ruby-version` file determine what you get.
What does the HTMLProofer check target do in programminghistorian/jekyll?
It runs HTMLProofer over the built site, assuming the .html extension, ignoring missing and empty alt attributes, allowing missing hrefs, not checking internal hashes, not enforcing HTTPS, and only failing on 4xx responses. The status codes 429, 403, 400 and 415 are explicitly ignored, and a long list of URLs and directories is excluded.
How do I contribute a tutorial to The Programming Historian?
Tutorial submissions are handled in a separate repository, the Programming Historian Submissions one, rather than in the site repository. The website's contributions page carries detailed instructions for authors, reviewers, and editors, and the Project Wiki covers technical contributions and the policy for new language sub teams creating a translation.
Which languages is the Programming Historian site available in?
The repository has top level directories for English, Spanish, French, and Portuguese, along with a `translation-concordance.md` file that maps content between them. The retired lesson folders are listed per language in the HTMLProofer ignore list, for example the English `en/lessons/retired/` path and the Spanish `es/lecciones/retirada/` path.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/programminghistorian-jekyll)Was this useful?