Reference
Kaliumhexacyanoferrat/genhttp-pages@v1 takes every input of
actions/deploy-pages, so a workflow keeps working as it is, and answers
with the same page_url.
How activation works
Activating a repository makes a lambda (or takes yours, by its editor key), gives you
the link to its editor and an activation code, and remembers the repository by name.
The first run that presents the code with a GitHub OIDC token of that repository binds
the code to the repository's id, which outlives renames. From then on the action asks
GitHub for a token of the run, and pages.genhttp.run hands it the editor key
of the lambda to publish to.
- Only someone who can change the repository's workflows gets the code into a run of it, so nobody can activate a repository that is not theirs. Once used, the code is bound and gives nothing to whoever reads it in a public workflow.
- A repository with one site may drop the code after the first run. With several, each workflow keeps its code to say which site it publishes.
- The job needs
permissions: id-token: write, which Pages workflows have. Runs of forks get no token. - The browser that activated keeps the editor link, the address and the code, under "Activated in this browser" on the start page; nothing else can hand the link out again, so bookmark it to have it elsewhere.
- Editor keys are kept sealed with a key of their own, codes only as their hash. What is kept: the repository's name and id, and the lambda.
- Prefer a secret? The editor link ends with the editor key: store it as
GENHTTP_KEYand passkey: ${{ secrets.GENHTTP_KEY }}instead of the activation.
Inputs
The inputs of deploy-pages
| Input | Default | What it does here |
|---|---|---|
artifact_name | github-pages | The artifact to publish, as actions/upload-pages-artifact made it in an earlier job of the run. |
timeout | 600000 | Milliseconds to wait for the upload. |
preview | false | Publishes to a feature of the lambda instead, with an address of its own, named after the pull request. Delete it in the editor when you are done. |
token | github.token | Used only to check out a branch. |
error_count, reporting_interval | Accepted and not used: a lambda answers at once, so there is nothing to poll. |
Its own inputs
| Input | Default | What it does |
|---|---|---|
activation | The code the assistant gave for this repository. Needed for the first run; after that, a run is recognised by its GitHub OIDC token. With several sites in one repository, keep each code to say which lambda it goes to. | |
key | Instead of an activation: the editor key of the lambda, from a secret. Left out, the GENHTTP_KEY environment variable is read. | |
path | Publish this folder rather than an artifact. | |
branch | Publish this branch, as GitHub's “Deploy from a branch” does. | |
folder | / | With branch: the folder to publish, / or /docs. |
jekyll | auto | With branch: build with Jekyll unless there is a .nojekyll (auto), always (true) or never (false). |
include_hidden_files | false | With path or branch: publish files starting with a dot, such as .well-known/. An artifact holds what its upload included. |
base_path | auto | Where else the site answers. auto serves a project site at / and at /repository/, where it was built for; none serves the root only. |
backend | A folder of C# published beside the site, see below. | |
server | https://genhttp.dev | Another installation of GenHTTP Lambda. |
broker | https://pages.genhttp.run | Where activations are kept and tokens exchanged for the key. |
Outputs
| Output | What it holds |
|---|---|
page_url | The address the site answers at, such as https://my-site.genhttp.run/. |
version | The version of the lambda that is online. |
Configuring the build
actions/configure-pages keeps working while GitHub Pages is enabled for the
repository. To switch Pages off, use its drop-in, which answers with the lambda's
address instead, without a base path:
- id: pages
uses: Kaliumhexacyanoferrat/genhttp-pages/configure@v1
with:
activation: gp-…
# ${{ steps.pages.outputs.base_url }} is https://my-site.genhttp.run
It does not rewrite the configuration of a static site generator as
configure-pages does with static_site_generator; a site at the
root of its address needs no base path.
How the site is served
The way GitHub Pages serves it:
/docs/answers withdocs/index.html, and/docssends you there./aboutanswers withabout.html.- What is not there answers with your
404.htmland status 404. - Every answer may be cached for ten minutes, is readable from any origin, and an unchanged file answers 304.
- Names with spaces, accents, no extension or many folders work as they do on GitHub.
A backend beside the site
A static site sometimes needs code on the server: a form that stores what it is sent,
a counter, a proxy that keeps an API key from the browser, something live. A lambda
runs it beside the site, on the same address, so the pages call it with
fetch('api/…').
Ask for it
GenHTTP Lambda is built to be changed by agents. Open the lambda's editor, go to Change and say what you need: "Add an API at api/signups that stores the e-mail addresses my newsletter form posts." Its agent writes the routes, switches on a database if they need one, tries them in a draft and puts them online.
Or use your own agent - Claude Code, Codex, Cursor - through MCP, and give it the editor link:
claude mcp add --transport http genhttp https://genhttp.dev/mcp
Why a push keeps it
A push replaces the site and nothing else: resources/site/,
resources/blobs/, resources/pages.json,
pages/PagesSite.cs and docs/pages.md. Everything else - the
routes, resources/migrations/, the documentation - stays as the agent or you
left it, and the database is never touched by a deployment. docs/pages.md
says so to the next agent that reads the lambda.
The routes go in front of the site in lambda.cs, which keeps serving the
site last. A lambda.cs without PagesSite.Create() is replaced by
the next push.
return Layout.Create()
.Add("api", api)
.Add(PagesSite.Create());
A form or a button that uses the API belongs to the site, so it is changed in the
repository; what the agent changes in resources/site/ is gone with the next
push.
Or keep it in the repository
To have the C# in the repository instead, name its folder in backend: its
lambda.cs replaces the lambda's, the other files go to backend/,
and its resources/ - migrations, say - become the lambda's, all replaced on
every push.
This site does it: its backend activates repositories and exchanges the tokens of their runs, with a database of activations.
Compared with GitHub Pages
| GitHub Pages | GenHTTP Pages | |
|---|---|---|
| Static files, Jekyll, your build | Yes | Yes, from the same artifact |
| Code on the server | No | C# routes beside the site: a form, an API, a proxy that keeps a key from the browser |
| A database | No | SQLite, one per site |
| Live updates, multiplayer | No | Websockets and server-sent events |
| Secrets while it runs | No, only during the build | Read by your code, never shown again |
| Traffic statistics | Only with a third-party script | Counted on the server: no script, no cookie |
| Request log and errors | No | Every request, what your code printed, errors with stack traces |
| Going back | Run an old workflow again | Every deployment is a version, one click to put it back |
| Previews of pull requests | Not available to the public | preview: true |
| Account | Your GitHub account | None; the key is the access |
| Your own domain | Free | With the premium tier |
| Size | 1 GB | 32 MB on the free tier |
| How long it stays | As long as the repository | As long as it is used, on the free tier |
What to know when you switch
- The address
-
Your site answers at
https://name.genhttp.run/. A project site built forowner.github.io/repository/still works: it is served at the root and below/repository/. - How long it stays online
- A free lambda stays online as long as it is used. One that nobody visits and nobody deploys to for a month goes offline, and is removed two months after that. The premium tier keeps it online.
- Size
- A free lambda holds 32 MB per deployment, against GitHub's 1 GB. The action says so before it uploads, and how large the site is.
- Your own domain
-
Comes with the premium tier, set in the lambda's editor. A
CNAMEfile is published like any other file. - Permissions
-
None needed:
pages: write,id-token: writeand thegithub-pagesenvironment do no harm and can stay. - History
- Every deployment is a version you can read, compare and put back online in the lambda's editor.