Files
thgtoa/code/index.html
T
2026-06-18 22:31:53 +00:00

1367 lines
59 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="We are the maintainers of the Hitchhiker's Guide and the PSA Matrix space.">
<meta name="author" content="Anonymous Planet">
<link rel="canonical" href="https://anonymousplanet.net/code/">
<link rel="prev" href="../guide/">
<link rel="next" href="../contribute/">
<link rel="icon" href="../media/profile.png">
<meta name="generator" content="mkdocs-1.5.3, mkdocs-material-9.5.17">
<title>Content Contributions - The Hitchhiker's Guide</title>
<link rel="stylesheet" href="../assets/stylesheets/main.bcfcd587.min.css">
<link rel="stylesheet" href="../assets/stylesheets/palette.06af60db.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Public+Sans:300,300i,400,400i,700,700i%7CLiberation+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Public Sans";--md-code-font:"Liberation Mono"}</style>
<link rel="stylesheet" href="../stylesheets/hacker.css">
<link rel="stylesheet" href="../stylesheets/hacker-extra.css">
<link rel="stylesheet" href="../stylesheets/going-dark.css">
<link rel="stylesheet" href="../stylesheets/navigation.css">
<link rel="stylesheet" href="../stylesheets/footer.css">
<link rel="stylesheet" href="../stylesheets/accessibility.css">
<script>__md_scope=new URL("..",location),__md_hash=e=>[...e].reduce((e,_)=>(e<<5)-e+_.charCodeAt(0),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
<meta property="og:type" content="website" >
<meta property="og:title" content="Content Contributions - The Hitchhiker's Guide" >
<meta property="og:description" content="We are the maintainers of the Hitchhiker's Guide and the PSA Matrix space." >
<meta property="og:image" content="https://anonymousplanet.net/assets/images/social/code/index.png" >
<meta property="og:image:type" content="image/png" >
<meta property="og:image:width" content="1200" >
<meta property="og:image:height" content="630" >
<meta property="og:url" content="https://anonymousplanet.net/code/" >
<meta name="twitter:card" content="summary_large_image" >
<meta name="twitter:title" content="Content Contributions - The Hitchhiker's Guide" >
<meta name="twitter:description" content="We are the maintainers of the Hitchhiker's Guide and the PSA Matrix space." >
<meta name="twitter:image" content="https://anonymousplanet.net/assets/images/social/code/index.png" >
</head>
<body dir="ltr" data-md-color-scheme="slate" data-md-color-primary="hacker" data-md-color-accent="green">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#repository-layout" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href=".." title="The Hitchhiker&#39;s Guide" class="md-header__button md-logo" aria-label="The Hitchhiker's Guide" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="m23 11.5-3.05-1.13c-.26-1.15-.91-1.81-.91-1.81a4.189 4.189 0 0 0-5.93 0l-1.48 1.48L5 3c-1 4 0 8 2.45 11.22L2 19.5s8.89 2 14.07-2.05c2.76-2.16 3.38-3.42 3.77-4.75L23 11.5m-5.29.22c-.39.39-1.03.39-1.42 0a.996.996 0 0 1 0-1.41c.39-.39 1.03-.39 1.42 0 .39.39.39 1.02 0 1.41Z"/></svg>
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3V6m0 5h18v2H3v-2m0 5h18v2H3v-2Z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
The Hitchhiker's Guide
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Content Contributions
</span>
</div>
</div>
</div>
<form class="md-header__option" data-md-component="palette">
<input class="md-option" data-md-color-media="" data-md-color-scheme="slate" data-md-color-primary="hacker" data-md-color-accent="green" aria-hidden="true" type="radio" name="__palette" id="__palette_0">
</form>
<script>var media,input,key,value,palette=__md_get("__palette");if(palette&&palette.color){"(prefers-color-scheme)"===palette.color.media&&(media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']"),palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent"));for([key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"/></svg>
</label>
<nav class="md-search__options" aria-label="Search">
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41Z"/></svg>
</button>
</nav>
<div class="md-search__suggest" data-md-component="search-suggest"></div>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list" role="presentation"></ol>
</div>
</div>
</div>
</div>
</div>
<div class="md-header__source">
<a href="https://github.com/Anon-Planet/thgtoa" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>
</div>
<div class="md-source__repository">
</div>
</a>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<nav class="md-tabs" aria-label="Tabs" data-md-component="tabs">
<div class="md-grid">
<ul class="md-tabs__list">
<li class="md-tabs__item">
<a href=".." class="md-tabs__link">
Home
</a>
</li>
<li class="md-tabs__item">
<a href="../verify/" class="md-tabs__link">
Verify
</a>
</li>
<li class="md-tabs__item">
<a href="../guide/" class="md-tabs__link">
Guide
</a>
</li>
<li class="md-tabs__item md-tabs__item--active">
<a href="./" class="md-tabs__link">
Code
</a>
</li>
<li class="md-tabs__item">
<a href="../contribute/" class="md-tabs__link">
Donations
</a>
</li>
<li class="md-tabs__item">
<a href="../constitution/" class="md-tabs__link">
A Constitution
</a>
</li>
<li class="md-tabs__item">
<a href="../mirrors/" class="md-tabs__link">
Mirrors
</a>
</li>
<li class="md-tabs__item">
<a href="../changelog/" class="md-tabs__link">
Changelog
</a>
</li>
<li class="md-tabs__item">
<a href="../about/" class="md-tabs__link">
About
</a>
</li>
<li class="md-tabs__item">
<a href="../pgp/" class="md-tabs__link">
PGP
</a>
</li>
</ul>
</div>
</nav>
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary md-nav--lifted md-nav--integrated" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href=".." title="The Hitchhiker&#39;s Guide" class="md-nav__button md-logo" aria-label="The Hitchhiker's Guide" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="m23 11.5-3.05-1.13c-.26-1.15-.91-1.81-.91-1.81a4.189 4.189 0 0 0-5.93 0l-1.48 1.48L5 3c-1 4 0 8 2.45 11.22L2 19.5s8.89 2 14.07-2.05c2.76-2.16 3.38-3.42 3.77-4.75L23 11.5m-5.29.22c-.39.39-1.03.39-1.42 0a.996.996 0 0 1 0-1.41c.39-.39 1.03-.39 1.42 0 .39.39.39 1.02 0 1.41Z"/></svg>
</a>
The Hitchhiker's Guide
</label>
<div class="md-nav__source">
<a href="https://github.com/Anon-Planet/thgtoa" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>
</div>
<div class="md-source__repository">
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href=".." class="md-nav__link">
<span class="md-ellipsis">
Home
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../verify/" class="md-nav__link">
<span class="md-ellipsis">
Verify
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../guide/" class="md-nav__link">
<span class="md-ellipsis">
Guide
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
<span class="md-ellipsis">
Code
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
<span class="md-ellipsis">
Code
</span>
</a>
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#repository-layout" class="md-nav__link">
<span class="md-ellipsis">
Repository layout
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#building-locally" class="md-nav__link">
<span class="md-ellipsis">
Building locally
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#preview-the-mkdocs-site" class="md-nav__link">
<span class="md-ellipsis">
Preview the MkDocs site
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#cicd-pipeline-overview" class="md-nav__link">
<span class="md-ellipsis">
CI/CD pipeline overview
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#release-process" class="md-nav__link">
<span class="md-ellipsis">
Release process
</span>
</a>
<nav class="md-nav" aria-label="Release process">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#trigger-a-build" class="md-nav__link">
<span class="md-ellipsis">
Trigger a build
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#sign-the-pdfs" class="md-nav__link">
<span class="md-ellipsis">
Sign the PDFs
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#publish-the-release" class="md-nav__link">
<span class="md-ellipsis">
Publish the release
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#update-the-changelog" class="md-nav__link">
<span class="md-ellipsis">
Update the changelog
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#release-tag-format" class="md-nav__link">
<span class="md-ellipsis">
Release tag format
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#commit-message-format" class="md-nav__link">
<span class="md-ellipsis">
Commit message format
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#verifying-a-release" class="md-nav__link">
<span class="md-ellipsis">
Verifying a release
</span>
</a>
<nav class="md-nav" aria-label="Verifying a release">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#troubleshooting" class="md-nav__link">
<span class="md-ellipsis">
Troubleshooting
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="../contribute/" class="md-nav__link">
<span class="md-ellipsis">
Donations
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../constitution/" class="md-nav__link">
<span class="md-ellipsis">
A Constitution
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../mirrors/" class="md-nav__link">
<span class="md-ellipsis">
Mirrors
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../changelog/" class="md-nav__link">
<span class="md-ellipsis">
Changelog
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../about/" class="md-nav__link">
<span class="md-ellipsis">
About
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../pgp/" class="md-nav__link">
<span class="md-ellipsis">
PGP
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<p>Install these before anything else.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="1:2"><input checked="checked" id="__tabbed_1_1" name="__tabbed_1" type="radio" /><input id="__tabbed_1_2" name="__tabbed_1" type="radio" /><div class="tabbed-labels"><label for="__tabbed_1_1">Linux / macOS</label><label for="__tabbed_1_2">Windows</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
<div class="highlight"><pre><span></span><code><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="c1"># Python 3.11+</span>
<a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a>python3<span class="w"> </span>--version
<a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a>
<a id="__codelineno-0-4" name="__codelineno-0-4" href="#__codelineno-0-4"></a><span class="c1"># poppler (pdftoppm) and qpdf</span>
<a id="__codelineno-0-5" name="__codelineno-0-5" href="#__codelineno-0-5"></a>sudo<span class="w"> </span>apt<span class="w"> </span>install<span class="w"> </span>poppler-utils<span class="w"> </span>qpdf<span class="w"> </span><span class="c1"># Debian/Ubuntu</span>
<a id="__codelineno-0-6" name="__codelineno-0-6" href="#__codelineno-0-6"></a>brew<span class="w"> </span>install<span class="w"> </span>poppler<span class="w"> </span>qpdf<span class="w"> </span><span class="c1"># macOS</span>
<a id="__codelineno-0-7" name="__codelineno-0-7" href="#__codelineno-0-7"></a>
<a id="__codelineno-0-8" name="__codelineno-0-8" href="#__codelineno-0-8"></a><span class="c1"># GPG</span>
<a id="__codelineno-0-9" name="__codelineno-0-9" href="#__codelineno-0-9"></a>sudo<span class="w"> </span>apt<span class="w"> </span>install<span class="w"> </span>gnupg<span class="w"> </span><span class="c1"># Debian/Ubuntu</span>
<a id="__codelineno-0-10" name="__codelineno-0-10" href="#__codelineno-0-10"></a>brew<span class="w"> </span>install<span class="w"> </span>gnupg<span class="w"> </span><span class="c1"># macOS</span>
<a id="__codelineno-0-11" name="__codelineno-0-11" href="#__codelineno-0-11"></a>
<a id="__codelineno-0-12" name="__codelineno-0-12" href="#__codelineno-0-12"></a><span class="c1"># Python dependencies</span>
<a id="__codelineno-0-13" name="__codelineno-0-13" href="#__codelineno-0-13"></a>pip<span class="w"> </span>install<span class="w"> </span><span class="s2">&quot;mkdocs-material[imaging]&quot;</span><span class="w"> </span>pillow<span class="w"> </span>numpy
</code></pre></div>
</div>
<div class="tabbed-block">
<div class="highlight"><pre><span></span><code><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a><span class="c"># Python 3.11+ from https://python.org</span>
<a id="__codelineno-1-2" name="__codelineno-1-2" href="#__codelineno-1-2"></a>
<a id="__codelineno-1-3" name="__codelineno-1-3" href="#__codelineno-1-3"></a><span class="c"># poppler: download from https://github.com/oschwartz10612/poppler-windows/releases</span>
<a id="__codelineno-1-4" name="__codelineno-1-4" href="#__codelineno-1-4"></a><span class="c"># Extract and add the bin\ folder to PATH</span>
<a id="__codelineno-1-5" name="__codelineno-1-5" href="#__codelineno-1-5"></a>
<a id="__codelineno-1-6" name="__codelineno-1-6" href="#__codelineno-1-6"></a><span class="c"># qpdf: download from https://github.com/qpdf/qpdf/releases</span>
<a id="__codelineno-1-7" name="__codelineno-1-7" href="#__codelineno-1-7"></a><span class="c"># Extract and add the bin\ folder to PATH</span>
<a id="__codelineno-1-8" name="__codelineno-1-8" href="#__codelineno-1-8"></a>
<a id="__codelineno-1-9" name="__codelineno-1-9" href="#__codelineno-1-9"></a><span class="c"># GPG: download Gpg4win from https://gpg4win.org</span>
<a id="__codelineno-1-10" name="__codelineno-1-10" href="#__codelineno-1-10"></a>
<a id="__codelineno-1-11" name="__codelineno-1-11" href="#__codelineno-1-11"></a><span class="c"># Python dependencies</span>
<a id="__codelineno-1-12" name="__codelineno-1-12" href="#__codelineno-1-12"></a><span class="n">pip</span> <span class="n">install</span> <span class="s2">&quot;mkdocs-material[imaging]&quot;</span> <span class="n">pillow</span> <span class="n">numpy</span>
</code></pre></div>
</div>
</div>
</div>
<p>You also need <strong>Google Chrome</strong> or <strong>Microsoft Edge</strong> installed for the light-mode PDF build (headless Chromium).</p>
<p>You can <a href="https://github.com/Anon-Planet/thgtoa/issues/new">submit bugs and feature requests</a> with detailed information about your issue or idea:</p>
<ul>
<li>If you'd like to propose an addition, please follow the standards outlined here.</li>
<li>If you're reporting an issue, please be sure to include the expected behaviour, the observed behaviour, and steps to reproduce the problem.</li>
<li>This can require technical knowledge, but you can also get involved in conversations about bug reports and feature requests. This is a great way to get involved without getting too overwhelmed!</li>
<li><a href="https://github.com/Anon-Planet/thgtoa/pulls">Help fellow committers test recently submitted pull requests</a>. Simply by pulling down a pull request and testing it, you can help ensure our new code contributions for stability and quality.</li>
</ul>
<p>For those of you who are looking to add content to the guide, include the following:</p>
<ul>
<li><strong>Do</strong> create a <a href="http://git-scm.com/book/en/Git-Branching-Branching-Workflows#Topic-Branches">topic branch</a> to work on instead of working directly on <code>main</code>. This helps to:<ul>
<li>Protect the process.</li>
<li>Ensures users are aware of commits on the branch being considered for merge.</li>
<li>Allows for a location for more commits to be offered without mingling with other contributor changes.</li>
<li>Allows contributors to make progress while a PR is still being reviewed.</li>
</ul>
</li>
<li><strong>Do</strong> follow the <a href="http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html">50/72 rule</a> for Git commit messages.</li>
<li><strong>Do</strong> write "WIP" on your PR and/or open a <a href="https://help.github.com/en/articles/about-pull-requests#draft-pull-requests">draft PR</a> if submitting unfinished changes..</li>
<li><strong>Do</strong> make sure the title of a draft PR makes it immediately clear that it's a draft</li>
<li><strong>Do</strong> target your pull request to the <strong>main branch</strong>.</li>
<li><strong>Do</strong> specify a descriptive title to make searching for your pull request easier.</li>
<li><strong>Don't</strong> leave your pull request description blank.</li>
<li><strong>Don't</strong> abandon your pull request. Being responsive helps us land your changes faster.</li>
<li><strong>Don't</strong> post questions in older closed PRs.</li>
<li><strong>Do</strong> stick to the guide to find common style issues.</li>
<li><strong>Don't</strong> make mass changes (such as replacing "I" with "we") using automated search/replace functionality.<ul>
<li>Search/replace doesn't understand context, and as such, will inevitably cause inconsistencies and make the guide harder to read.</li>
<li>If it's part of a larger PR, it'll also make the reviewer's life harder, as they'll have to go through manually and undo everything by hand.</li>
<li><em>If you're going to make mass changes, take the time to do it properly</em>. Otherwise we'll just have to undo it anyway.</li>
<li>If your change contains backslashes (<code>\</code>), either escape them with another backslash (<code>\\</code>) or put them in a <code>code block</code>.</li>
</ul>
</li>
</ul>
<p>When reporting guide issues:</p>
<ul>
<li><strong>Do</strong> write a detailed description of your issue and use a descriptive title.</li>
<li><strong>Do</strong> make it as detailed as possible and don't just submit 50 line changes without explaining.</li>
<li><strong>Don't</strong> file duplicate reports; search for your bug before filing a new report.</li>
<li><strong>Don't</strong> attempt to report issues on a closed PR.</li>
</ul>
<p>Please split large sets of changes into multiple PRs. For example, a PR that adds Windows 11 support, removes Windows AME references, and fixes typos can be split into 3 PRs. This makes PRs easier to review prior to merging.</p>
<p>For an example of what <em>not</em> to do, see: <a href="https://github.com/Anon-Planet/thgtoa/pull/51">https://github.com/Anon-Planet/thgtoa/pull/51</a>. This PR contains enough changes to split into multiple smaller and individually reviewable PRs.</p>
<p>While a PR is being reviewed, modifications may be made to it by the reviewer prior to merging. If this is the case, a new branch will be created for the PR's review. If you would like to submit a change to a PR that is in the process of being reviewed, <em>do not update the PR directly</em>. This will only cause merge conflicts and delay the PR from being merged. Instead, submit your changes to the PR's review branch.</p>
<p>For an example of what <em>not</em> to do, see: <a href="https://github.com/Anon-Planet/thgtoa/pull/51">https://github.com/Anon-Planet/thgtoa/pull/51</a>. Instead of submitting changes to the PR directly, they should have been submitted as changes to the PR's associated review branch.</p>
<p><strong>Thank you</strong> for taking the few moments to read this far! You're already way ahead of the
curve, so keep it up!</p>
<h2 id="repository-layout">Repository layout<a class="headerlink" href="#repository-layout" title="Permanent link">λ</a></h2>
<div class="highlight"><pre><span></span><code><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a>.github/
<a id="__codelineno-2-2" name="__codelineno-2-2" href="#__codelineno-2-2"></a> workflows/
<a id="__codelineno-2-3" name="__codelineno-2-3" href="#__codelineno-2-3"></a> 01-build.yml # builds PDFs, uploads artifact
<a id="__codelineno-2-4" name="__codelineno-2-4" href="#__codelineno-2-4"></a> 02-sign.yml # hashes + GPG signs, uploads signatures artifact
<a id="__codelineno-2-5" name="__codelineno-2-5" href="#__codelineno-2-5"></a> 03-release.yml # publishes GitHub Release with all assets
<a id="__codelineno-2-6" name="__codelineno-2-6" href="#__codelineno-2-6"></a> 04-changelog.yml # prepends a new entry to docs/changelog/index.md
<a id="__codelineno-2-7" name="__codelineno-2-7" href="#__codelineno-2-7"></a> publish.yml # deploys MkDocs site to GitHub Pages
<a id="__codelineno-2-8" name="__codelineno-2-8" href="#__codelineno-2-8"></a>docs/
<a id="__codelineno-2-9" name="__codelineno-2-9" href="#__codelineno-2-9"></a> guide/index.md # the guide (single Markdown file)
<a id="__codelineno-2-10" name="__codelineno-2-10" href="#__codelineno-2-10"></a> changelog/ # release notes
<a id="__codelineno-2-11" name="__codelineno-2-11" href="#__codelineno-2-11"></a> code/ # this page
<a id="__codelineno-2-12" name="__codelineno-2-12" href="#__codelineno-2-12"></a>export/ # PDF output (PDFs gitignored; .sha256, .b2sum, .asc tracked)
<a id="__codelineno-2-13" name="__codelineno-2-13" href="#__codelineno-2-13"></a>pgp/ # public signing keys
<a id="__codelineno-2-14" name="__codelineno-2-14" href="#__codelineno-2-14"></a>scripts/
<a id="__codelineno-2-15" name="__codelineno-2-15" href="#__codelineno-2-15"></a> build_guide_pdf.py # MkDocs + Chromium PDF builder
<a id="__codelineno-2-16" name="__codelineno-2-16" href="#__codelineno-2-16"></a> convert.py # pixel-based dark mode PDF converter
<a id="__codelineno-2-17" name="__codelineno-2-17" href="#__codelineno-2-17"></a> update_changelog.py # auto-generates changelog entries from git log
<a id="__codelineno-2-18" name="__codelineno-2-18" href="#__codelineno-2-18"></a> setup_workflow.py # GitHub Secrets setup assistant
<a id="__codelineno-2-19" name="__codelineno-2-19" href="#__codelineno-2-19"></a> verify_pdf.py # signature verification helper
<a id="__codelineno-2-20" name="__codelineno-2-20" href="#__codelineno-2-20"></a> archived/
<a id="__codelineno-2-21" name="__codelineno-2-21" href="#__codelineno-2-21"></a> tag_release.py # ARCHIVED - GPG tag helper (not used in current flow)
</code></pre></div>
<h2 id="building-locally">Building locally<a class="headerlink" href="#building-locally" title="Permanent link">λ</a></h2>
<div class="highlight"><pre><span></span><code><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a>python<span class="w"> </span>scripts/build_guide_pdf.py<span class="w"> </span>--both
</code></pre></div>
<p>This builds the MkDocs site, renders it to <code>export/thgtoa.pdf</code> via headless Chromium, then calls <code>scripts/convert.py</code> to produce <code>export/thgtoa-dark.pdf</code>.</p>
<table>
<thead>
<tr>
<th>Flag</th>
<th>Effect</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>--both</code></td>
<td>Light PDF then dark PDF</td>
</tr>
<tr>
<td>(no flag)</td>
<td>Light PDF only</td>
</tr>
<tr>
<td><code>--dark</code></td>
<td>Dark PDF only (light PDF must already exist)</td>
</tr>
</tbody>
</table>
<p>Build only the dark PDF from an existing light PDF:</p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a>python<span class="w"> </span>scripts/convert.py<span class="w"> </span>export/thgtoa.pdf<span class="w"> </span>export/thgtoa-dark.pdf
</code></pre></div>
<p>Options:</p>
<table>
<thead>
<tr>
<th>Flag</th>
<th>Default</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>--dpi</code></td>
<td><code>200</code></td>
<td>Rasterization DPI. 150 = smaller file, 300 = sharper but slow</td>
</tr>
<tr>
<td><code>--batch-size</code></td>
<td><code>50</code></td>
<td>Pages per batch. Reduce if you hit OOM</td>
</tr>
<tr>
<td><code>--bg</code></td>
<td><code>1f1f31</code></td>
<td>Background colour (hex)</td>
</tr>
<tr>
<td><code>--text</code></td>
<td><code>e0e0e0</code></td>
<td>Body text colour (hex)</td>
</tr>
<tr>
<td><code>--link</code></td>
<td><code>5e8bde</code></td>
<td>Link / blue element colour (hex)</td>
</tr>
</tbody>
</table>
<h1 id="preview-the-mkdocs-site">Preview the MkDocs site<a class="headerlink" href="#preview-the-mkdocs-site" title="Permanent link">λ</a></h1>
<div class="highlight"><pre><span></span><code><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a>mkdocs<span class="w"> </span>serve
</code></pre></div>
<p>Opens at <code>http://127.0.0.1:8000</code>.</p>
<h1 id="cicd-pipeline-overview">CI/CD pipeline overview<a class="headerlink" href="#cicd-pipeline-overview" title="Permanent link">λ</a></h1>
<p>The pipeline is fully manual after the initial build - no step automatically triggers the next. This prevents version mismatches between what was built, what was signed, and what gets released. The workflows are numbered to help guide you.</p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a>push to main (or manual trigger)
<a id="__codelineno-6-2" name="__codelineno-6-2" href="#__codelineno-6-2"></a>
<a id="__codelineno-6-3" name="__codelineno-6-3" href="#__codelineno-6-3"></a>
<a id="__codelineno-6-4" name="__codelineno-6-4" href="#__codelineno-6-4"></a> 01-build.yml
<a id="__codelineno-6-5" name="__codelineno-6-5" href="#__codelineno-6-5"></a> Builds thgtoa.pdf + thgtoa-dark.pdf.
<a id="__codelineno-6-6" name="__codelineno-6-6" href="#__codelineno-6-6"></a> Uploads artifact: pdfs
<a id="__codelineno-6-7" name="__codelineno-6-7" href="#__codelineno-6-7"></a> Note the run ID.
<a id="__codelineno-6-8" name="__codelineno-6-8" href="#__codelineno-6-8"></a>
<a id="__codelineno-6-9" name="__codelineno-6-9" href="#__codelineno-6-9"></a> │ # manually trigger 02-sign.yml with the build run ID
<a id="__codelineno-6-10" name="__codelineno-6-10" href="#__codelineno-6-10"></a>
<a id="__codelineno-6-11" name="__codelineno-6-11" href="#__codelineno-6-11"></a> 02-sign.yml
<a id="__codelineno-6-12" name="__codelineno-6-12" href="#__codelineno-6-12"></a> Downloads pdfs artifact. Hashes (SHA-256 + BLAKE2b) and GPG-signs
<a id="__codelineno-6-13" name="__codelineno-6-13" href="#__codelineno-6-13"></a> all files. Commits export/ back to main. Uploads artifacts:
<a id="__codelineno-6-14" name="__codelineno-6-14" href="#__codelineno-6-14"></a> signatures, pdfs-signed
<a id="__codelineno-6-15" name="__codelineno-6-15" href="#__codelineno-6-15"></a> Note the run ID.
<a id="__codelineno-6-16" name="__codelineno-6-16" href="#__codelineno-6-16"></a>
<a id="__codelineno-6-17" name="__codelineno-6-17" href="#__codelineno-6-17"></a> │ # manually trigger 03-release.yml with the sign run ID
<a id="__codelineno-6-18" name="__codelineno-6-18" href="#__codelineno-6-18"></a>
<a id="__codelineno-6-19" name="__codelineno-6-19" href="#__codelineno-6-19"></a> 03-release.yml
<a id="__codelineno-6-20" name="__codelineno-6-20" href="#__codelineno-6-20"></a> Downloads signatures + pdfs-signed artifacts. Runs VirusTotal.
<a id="__codelineno-6-21" name="__codelineno-6-21" href="#__codelineno-6-21"></a> Creates GitHub Release tagged release-YYYYMMDD-&lt;short-sha&gt;.
<a id="__codelineno-6-22" name="__codelineno-6-22" href="#__codelineno-6-22"></a>
<a id="__codelineno-6-23" name="__codelineno-6-23" href="#__codelineno-6-23"></a> │ # manually trigger 04-changelog.yml with the version string
<a id="__codelineno-6-24" name="__codelineno-6-24" href="#__codelineno-6-24"></a>
<a id="__codelineno-6-25" name="__codelineno-6-25" href="#__codelineno-6-25"></a> 04-changelog.yml
<a id="__codelineno-6-26" name="__codelineno-6-26" href="#__codelineno-6-26"></a> Runs update_changelog.py, prepends a new ## [vX.Y.Z] entry,
<a id="__codelineno-6-27" name="__codelineno-6-27" href="#__codelineno-6-27"></a> commits back to main.
</code></pre></div>
<p>Each stage is independent. If signing fails (e.g. an expired/revoked key, other problems in CI), re-run only <code>02-sign.yml</code> pointing at the existing build artifact - no need to rebuild the PDFs.</p>
<div class="admonition warning">
<p class="admonition-title">Before you push</p>
<ul>
<li>Make sure the working tree is clean (<code>git status</code>)</li>
<li>Run <code>mkdocs build</code> locally if you changed <code>docs/</code> to catch broken links before CI does</li>
<li>If you added new footnotes, verify they have both a definition <code>[^N]:</code> and at least one inline citation <code>[^N]</code></li>
</ul>
</div>
<hr />
<h1 id="release-process">Release process<a class="headerlink" href="#release-process" title="Permanent link">λ</a></h1>
<h2 id="trigger-a-build">Trigger a build<a class="headerlink" href="#trigger-a-build" title="Permanent link">λ</a></h2>
<p>Push to <code>main</code> - <code>01-build.yml</code> runs automatically when <code>docs/</code>, <code>mkdocs.yml</code>, or <code>scripts/</code> change. You can also trigger it manually from <strong>Actions → Build PDFs → Run workflow</strong>.</p>
<p>Once it completes successfully, <strong>note the run ID</strong> from the URL or the Actions list.</p>
<hr />
<h2 id="sign-the-pdfs">Sign the PDFs<a class="headerlink" href="#sign-the-pdfs" title="Permanent link">λ</a></h2>
<p>Go to <strong>Actions → Sign PDFs → Run workflow</strong>.</p>
<table>
<thead>
<tr>
<th>Input</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>build_run_id</code></td>
<td>The run ID from step 1</td>
</tr>
</tbody>
</table>
<p><code>02-sign.yml</code> will:</p>
<ul>
<li>Download the PDFs artifact from the build run</li>
<li>Compute SHA-256 and BLAKE2b hashes, writing <code>thgtoa.pdf.sha256</code>, <code>thgtoa.pdf.b2sum</code>, <code>sha256sums.txt</code>, <code>b2sums.txt</code>, and the dark equivalents</li>
<li>GPG-sign all PDFs and hash files, writing <code>.asc</code> detached signature files</li>
<li>Commit the updated <code>export/</code> directory back to <code>main</code></li>
<li>Upload two artifacts: <code>signatures</code> and <code>pdfs-signed</code></li>
</ul>
<p>Once it completes successfully, <strong>note the run ID</strong>.</p>
<hr />
<h2 id="publish-the-release">Publish the release<a class="headerlink" href="#publish-the-release" title="Permanent link">λ</a></h2>
<p>Go to <strong>Actions → Release → Run workflow</strong>.</p>
<table>
<thead>
<tr>
<th>Input</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>sign_run_id</code></td>
<td>The run ID from step 2</td>
</tr>
<tr>
<td><code>prerelease</code></td>
<td><code>false</code> for a normal release</td>
</tr>
</tbody>
</table>
<p><code>03-release.yml</code> will:</p>
<ul>
<li>Download <code>signatures</code> and <code>pdfs-signed</code> artifacts from the sign run</li>
<li>Upload both PDFs to VirusTotal</li>
<li>Auto-generate a release tag in the format <code>release-YYYYMMDD-&lt;short-sha&gt;</code> (e.g. <code>release-20260527-abc1234</code>)</li>
<li>Create a GitHub Release with all PDFs, hash files, and signatures attached, and the VirusTotal report URLs in the body</li>
</ul>
<p>No version number needs to be chosen at this step - the tag is derived from the date and commit SHA, so it is always unique and always traceable.</p>
<hr />
<h2 id="update-the-changelog">Update the changelog<a class="headerlink" href="#update-the-changelog" title="Permanent link">λ</a></h2>
<p>Go to <strong>Actions → Update Changelog → Run workflow</strong>.</p>
<table>
<thead>
<tr>
<th>Input</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>version</code></td>
<td>The human-readable version string, e.g. <code>v1.2.4</code></td>
</tr>
<tr>
<td><code>dry_run</code></td>
<td><code>true</code> to preview without committing</td>
</tr>
</tbody>
</table>
<p><code>04-changelog.yml</code> runs <code>scripts/update_changelog.py</code>, which:</p>
<ul>
<li>Reads git log since the last <code>## [vX.Y.Z]</code> heading in the changelog</li>
<li>Categorises commits into Added / Changed / Fixed using conventional-commit prefixes</li>
<li>Prepends a new <code>## [version]</code> admonition block to <code>docs/changelog/index.md</code></li>
<li>Commits the result back to <code>main</code></li>
</ul>
<p>The version string is the only human decision in the release process. It goes into the changelog only - it does not affect the release tag.</p>
<div class="admonition tip">
<p class="admonition-title">Previewing the changelog entry</p>
<p>Run with <code>dry_run: true</code> first to review the generated entry before it is committed.</p>
</div>
<hr />
<h2 id="release-tag-format">Release tag format<a class="headerlink" href="#release-tag-format" title="Permanent link">λ</a></h2>
<p>Release tags use the format <code>release-YYYYMMDD-&lt;short-sha&gt;</code>, for example:</p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-7-1" name="__codelineno-7-1" href="#__codelineno-7-1"></a>release-20260527-abc1234
</code></pre></div>
<p>This format is always unique, requires no version decision at release time, and is directly traceable to the commit that was built. The version string (e.g. <code>v1.2.4</code>) is a separate, human-assigned label that lives only in the changelog.</p>
<hr />
<h2 id="commit-message-format">Commit message format<a class="headerlink" href="#commit-message-format" title="Permanent link">λ</a></h2>
<p>All commits must follow the <a href="https://www.conventionalcommits.org">Conventional Commits</a> format. This is enforced by the <code>commitizen</code> pre-commit hook. Not because we want to limit cooperation with others, but becasue it promotes a cleaner Changelog; we can avoid all the noise by doing this programatically.</p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-8-1" name="__codelineno-8-1" href="#__codelineno-8-1"></a>&lt;type&gt;(&lt;scope&gt;): &lt;description&gt;
</code></pre></div>
<p>Accepted types and their changelog bucket:</p>
<table>
<thead>
<tr>
<th>Type</th>
<th>Bucket</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>feat</code>, <code>feature</code>, <code>add</code></td>
<td>Added</td>
</tr>
<tr>
<td><code>fix</code>, <code>bugfix</code>, <code>revert</code>, <code>security</code></td>
<td>Fixed</td>
</tr>
<tr>
<td><code>perf</code>, <code>refactor</code>, <code>change</code>, <code>chore</code>, <code>ci</code>, <code>docs</code>, <code>style</code>, <code>test</code>, <code>build</code></td>
<td>Changed</td>
</tr>
</tbody>
</table>
<p>Examples:</p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-9-1" name="__codelineno-9-1" href="#__codelineno-9-1"></a>feat:<span class="w"> </span>add<span class="w"> </span>dark-mode<span class="w"> </span>PDF<span class="w"> </span><span class="nb">export</span>
<a id="__codelineno-9-2" name="__codelineno-9-2" href="#__codelineno-9-2"></a>fix<span class="o">(</span>scripts<span class="o">)</span>:<span class="w"> </span>handle<span class="w"> </span>locked<span class="w"> </span>PDF<span class="w"> </span>on<span class="w"> </span>Windows
<a id="__codelineno-9-3" name="__codelineno-9-3" href="#__codelineno-9-3"></a>docs:<span class="w"> </span>update<span class="w"> </span>developer<span class="w"> </span>workflow<span class="w"> </span>guide
<a id="__codelineno-9-4" name="__codelineno-9-4" href="#__codelineno-9-4"></a>chore<span class="o">(</span>ci<span class="o">)</span>:<span class="w"> </span>pin<span class="w"> </span>Chrome<span class="w"> </span>version<span class="w"> </span>to<span class="w"> </span><span class="m">120</span>
</code></pre></div>
<h1 id="verifying-a-release">Verifying a release<a class="headerlink" href="#verifying-a-release" title="Permanent link">λ</a></h1>
<p>Anyone can verify the authenticity of a release download.</p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-10-1" name="__codelineno-10-1" href="#__codelineno-10-1"></a><span class="c1"># Import the release signing key</span>
<a id="__codelineno-10-2" name="__codelineno-10-2" href="#__codelineno-10-2"></a>gpg<span class="w"> </span>--import<span class="w"> </span>pgp/anonymousplanet-release.asc
<a id="__codelineno-10-3" name="__codelineno-10-3" href="#__codelineno-10-3"></a>
<a id="__codelineno-10-4" name="__codelineno-10-4" href="#__codelineno-10-4"></a><span class="c1"># Verify the PDFs</span>
<a id="__codelineno-10-5" name="__codelineno-10-5" href="#__codelineno-10-5"></a>gpg<span class="w"> </span>--verify<span class="w"> </span>thgtoa.pdf.asc<span class="w"> </span>thgtoa.pdf
<a id="__codelineno-10-6" name="__codelineno-10-6" href="#__codelineno-10-6"></a>gpg<span class="w"> </span>--verify<span class="w"> </span>thgtoa-dark.pdf.asc<span class="w"> </span>thgtoa-dark.pdf
<a id="__codelineno-10-7" name="__codelineno-10-7" href="#__codelineno-10-7"></a>
<a id="__codelineno-10-8" name="__codelineno-10-8" href="#__codelineno-10-8"></a><span class="c1"># Verify the hash files</span>
<a id="__codelineno-10-9" name="__codelineno-10-9" href="#__codelineno-10-9"></a>gpg<span class="w"> </span>--verify<span class="w"> </span>sha256sums.txt.asc<span class="w"> </span>sha256sums.txt
<a id="__codelineno-10-10" name="__codelineno-10-10" href="#__codelineno-10-10"></a>gpg<span class="w"> </span>--verify<span class="w"> </span>b2sums.txt.asc<span class="w"> </span>b2sums.txt
<a id="__codelineno-10-11" name="__codelineno-10-11" href="#__codelineno-10-11"></a>
<a id="__codelineno-10-12" name="__codelineno-10-12" href="#__codelineno-10-12"></a><span class="c1"># Check the PDF hashes match</span>
<a id="__codelineno-10-13" name="__codelineno-10-13" href="#__codelineno-10-13"></a>sha256sum<span class="w"> </span>-c<span class="w"> </span>sha256sums.txt
<a id="__codelineno-10-14" name="__codelineno-10-14" href="#__codelineno-10-14"></a>b2sum<span class="w"> </span>-c<span class="w"> </span>b2sums.txt
</code></pre></div>
<p>A successful verify looks like:</p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-11-1" name="__codelineno-11-1" href="#__codelineno-11-1"></a>gpg: Signature made Sun 31 May 2026 03:23:26 AM EDT
<a id="__codelineno-11-2" name="__codelineno-11-2" href="#__codelineno-11-2"></a>gpg: using EDDSA key C3023DBEA3FB38C438BA1EEDCEC60AEDE8B992A2
<a id="__codelineno-11-3" name="__codelineno-11-3" href="#__codelineno-11-3"></a>gpg: Good signature from &quot;Anonymous Planet Release Signing Key&quot; [ultimate]
<a id="__codelineno-11-4" name="__codelineno-11-4" href="#__codelineno-11-4"></a>Primary key fingerprint: C302 3DBE A3FB 38C4 38BA 1EED CEC6 0AED E8B9 92A2
</code></pre></div>
<p>You can safely ignore Github, Codeberg, etc. warnings like "The email in this signature doesnt match the committer email."</p>
<div class="highlight"><pre><span></span><code><a id="__codelineno-12-1" name="__codelineno-12-1" href="#__codelineno-12-1"></a>λ &gt; git tag -v v1.2.3
<a id="__codelineno-12-2" name="__codelineno-12-2" href="#__codelineno-12-2"></a>object cdc54d8b3bc2b286827b23921d8d4062f85295cf
<a id="__codelineno-12-3" name="__codelineno-12-3" href="#__codelineno-12-3"></a>type commit
<a id="__codelineno-12-4" name="__codelineno-12-4" href="#__codelineno-12-4"></a>tag v1.2.3
<a id="__codelineno-12-5" name="__codelineno-12-5" href="#__codelineno-12-5"></a>tagger nopeitsnothing &lt;no@anonymousplanet.net&gt; 1780212206 -0400
<a id="__codelineno-12-6" name="__codelineno-12-6" href="#__codelineno-12-6"></a>
<a id="__codelineno-12-7" name="__codelineno-12-7" href="#__codelineno-12-7"></a>v1.2.3
<a id="__codelineno-12-8" name="__codelineno-12-8" href="#__codelineno-12-8"></a>gpg: Signature made Sun 31 May 2026 03:23:26 AM EDT
<a id="__codelineno-12-9" name="__codelineno-12-9" href="#__codelineno-12-9"></a>gpg: using EDDSA key C3023DBEA3FB38C438BA1EEDCEC60AEDE8B992A2
<a id="__codelineno-12-10" name="__codelineno-12-10" href="#__codelineno-12-10"></a>gpg: Good signature from &quot;Anonymous Planet Release Signing Key&quot; [ultimate]
<a id="__codelineno-12-11" name="__codelineno-12-11" href="#__codelineno-12-11"></a>Primary key fingerprint: C302 3DBE A3FB 38C4 38BA 1EED CEC6 0AED E8B9 92A2
</code></pre></div>
<hr />
<h2 id="troubleshooting">Troubleshooting<a class="headerlink" href="#troubleshooting" title="Permanent link">λ</a></h2>
<p><strong><code>cairosvg</code> missing during MkDocs build</strong>
Install the imaging extras: <code>pip install "mkdocs-material[imaging]"</code>. Required by the <code>social</code> plugin.</p>
<p><strong><code>KeyError: 'JPEG'</code> in convert.py</strong>
Pillow needs libjpeg. Reinstall after installing the system lib: <code>sudo apt install libjpeg-dev &amp;&amp; pip install --force-reinstall pillow</code>.</p>
<p><strong><code>qpdf: can't find PDF header</code></strong>
Ensure you are on the current version of <code>convert.py</code> - qpdf only accepts PDF inputs, not PNG.</p>
<p><strong>GPG signing fails on CI with <code>No secret key</code></strong>
The <code>GPG_PRIVATE_KEY</code> secret is missing or malformed. Re-export with <code>gpg --armor --export-secret-keys &lt;fingerprint&gt;</code> and paste the full block including header and footer lines.</p>
<p><strong>GPG signing fails with <code>Bad passphrase</code></strong>
The <code>GPG_PASSPHRASE</code> secret has a trailing space or newline. Paste it again with no surrounding whitespace.</p>
<p><strong><code>03-release.yml</code> fails on VirusTotal</strong>
The <code>VT_API_KEY</code> is missing, invalid, or over the rate limit (500 requests/day on the free tier). Check the secret and re-run after a few minutes.</p>
<p><strong><code>02-sign.yml</code> fails downloading PDF artifact</strong>
The <code>build_run_id</code> is wrong, or the artifact has expired (90-day retention). Trigger a new build and use the fresh run ID.</p>
<p><strong>Changelog already contains version X</strong>
<code>update_changelog.py</code> will error if <code>MANUAL_VERSION</code> is set to a version already in the changelog. Choose the next version string.</p>
<p><strong>Footnote warnings from MkDocs (<code>link '#fnref:N' has no anchor</code>)</strong>
A footnote definition <code>[^N]:</code> exists without a matching inline citation. Add the citation or remove the orphaned definition.</p>
</article>
</div>
<script>var tabs=__md_get("__tabs");if(Array.isArray(tabs))e:for(var set of document.querySelectorAll(".tabbed-set")){var tab,labels=set.querySelector(".tabbed-labels");for(tab of tabs)for(var label of labels.getElementsByTagName("label"))if(label.innerText.trim()===tab){var input=document.getElementById(label.htmlFor);input.checked=!0;continue e}}</script>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
<button type="button" class="md-top md-icon" data-md-component="top" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8v12Z"/></svg>
Back to top
</button>
</main>
<footer class="md-footer">
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs
</a>
</div>
<div class="md-social">
<a href="https://mastodon.social/@anonymousplanet" target="_blank" rel="noopener me" title="Mastodon" class="md-social__link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422.038-.008.077-.015.11-.024 2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164.675.77 1.012 1.81 1.012 3.12z"/></svg>
</a>
<a href="http://wmj5kiic7b6kjplpbvwadnht2nh2qnkbnqtcv3dyvpqtz7ssbssftxid.onion/" target="_blank" rel="noopener" title="0xacab" class="md-social__link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="m23.6 9.593-.033-.086L20.3.98a.851.851 0 0 0-.336-.405.875.875 0 0 0-1 .054.875.875 0 0 0-.29.44L16.47 7.818H7.537L5.332 1.07a.857.857 0 0 0-.29-.441.875.875 0 0 0-1-.054.859.859 0 0 0-.336.405L.433 9.502l-.032.086a6.066 6.066 0 0 0 2.012 7.01l.01.009.03.021 4.977 3.727 2.462 1.863 1.5 1.132a1.008 1.008 0 0 0 1.22 0l1.499-1.132 2.461-1.863 5.006-3.75.013-.01a6.068 6.068 0 0 0 2.01-7.002z"/></svg>
</a>
<a href="http://it7otdanqu7ktntxzm427cba6i53w6wlanlh23v5i3siqmos47pzhvyd.onion/anonypla" target="_blank" rel="noopener" title="Darktea" class="md-social__link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4.209 4.603c-.247 0-.525.02-.84.088-.333.07-1.28.283-2.054 1.027C-.403 7.25.035 9.685.089 10.052c.065.446.263 1.687 1.21 2.768 1.749 2.141 5.513 2.092 5.513 2.092s.462 1.103 1.168 2.119c.955 1.263 1.936 2.248 2.89 2.367 2.406 0 7.212-.004 7.212-.004s.458.004 1.08-.394c.535-.324 1.013-.893 1.013-.893s.492-.527 1.18-1.73c.21-.37.385-.729.538-1.068 0 0 2.107-4.471 2.107-8.823-.042-1.318-.367-1.55-.443-1.627-.156-.156-.366-.153-.366-.153s-4.475.252-6.792.306c-.508.011-1.012.023-1.512.027v4.474l-.634-.301c0-1.39-.004-4.17-.004-4.17-1.107.016-3.405-.084-3.405-.084s-5.399-.27-5.987-.324c-.187-.011-.401-.032-.648-.032zm.354 1.832h.111s.271 2.269.6 3.597C5.549 11.147 6.22 13 6.22 13s-.996-.119-1.641-.348c-.99-.324-1.409-.714-1.409-.714s-.73-.511-1.096-1.52C1.444 8.73 2.021 7.7 2.021 7.7s.32-.859 1.47-1.145c.395-.106.863-.12 1.072-.12zm8.33 2.554c.26.003.509.127.509.127l.868.422-.529 1.075a.686.686 0 0 0-.614.359.685.685 0 0 0 .072.756l-.939 1.924a.69.69 0 0 0-.66.527.687.687 0 0 0 .347.763.686.686 0 0 0 .867-.206.688.688 0 0 0-.069-.882l.916-1.874a.667.667 0 0 0 .237-.02.657.657 0 0 0 .271-.137 8.826 8.826 0 0 1 1.016.512.761.761 0 0 1 .286.282c.073.21-.073.569-.073.569-.087.29-.702 1.55-.702 1.55a.692.692 0 0 0-.676.477.681.681 0 1 0 1.157-.252c.073-.141.141-.282.214-.431.19-.397.515-1.16.515-1.16.035-.066.218-.394.103-.814-.095-.435-.48-.638-.48-.638-.467-.301-1.116-.58-1.116-.58s0-.156-.042-.27a.688.688 0 0 0-.148-.241l.516-1.062 2.89 1.401s.48.218.583.619c.073.282-.019.534-.069.657-.24.587-2.1 4.317-2.1 4.317s-.232.554-.748.588a1.065 1.065 0 0 1-.393-.045l-.202-.08-4.31-2.1s-.417-.218-.49-.596c-.083-.31.104-.691.104-.691l2.073-4.272s.183-.37.466-.497a.855.855 0 0 1 .35-.077z"/></svg>
</a>
<a href="https://github.com/anon-planet" target="_blank" rel="noopener" title="Github" class="md-social__link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg>
</a>
<a href="https://gitlab.com/anonymousplanetorg" target="_blank" rel="noopener" title="Gitlab" class="md-social__link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="m23.6 9.593-.033-.086L20.3.98a.851.851 0 0 0-.336-.405.875.875 0 0 0-1 .054.875.875 0 0 0-.29.44L16.47 7.818H7.537L5.332 1.07a.857.857 0 0 0-.29-.441.875.875 0 0 0-1-.054.859.859 0 0 0-.336.405L.433 9.502l-.032.086a6.066 6.066 0 0 0 2.012 7.01l.01.009.03.021 4.977 3.727 2.462 1.863 1.5 1.132a1.008 1.008 0 0 0 1.22 0l1.499-1.132 2.461-1.863 5.006-3.75.013-.01a6.068 6.068 0 0 0 2.01-7.002z"/></svg>
</a>
<a href="https://codeberg.org/anonymousplanet" target="_blank" rel="noopener" title="Codeberg" class="md-social__link">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M11.955.49A12 12 0 0 0 0 12.49a12 12 0 0 0 1.832 6.373L11.838 5.928a.187.14 0 0 1 .324 0l10.006 12.935A12 12 0 0 0 24 12.49a12 12 0 0 0-12-12 12 12 0 0 0-.045 0zm.375 6.467 4.416 16.553a12 12 0 0 0 5.137-4.213z"/></svg>
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"base": "..", "features": ["navigation.instant", "navigation.instant.prefetch", "navigation.tabs", "navigation.sections", "navigation.path", "toc.integrate", "navigation.top", "search.suggest", "search.highlight", "content.tabs.link", "content.code.annotation", "content.code.copy"], "search": "../assets/javascripts/workers/search.b8dbb3d2.min.js", "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}}</script>
<script src="../assets/javascripts/bundle.1e8ae164.min.js"></script>
</body>
</html>