@floez-werk/pi-extension-release-tool
v0.1.4
Published
Release tooling for FloezWerk pi extensions: scaffolding, README release-notes sync, GitHub release notes and the shared CI/CD workflows.
Readme
pi-extension-release-tool
Release tooling, shared CI/CD and the project template for the FloezWerk pi extensions. Everything that used to be copied into each extension repository lives here once.
Table of contents
- What is in here
- Tooling
- Prompt template: new extension
- New extension repository
- Releasing an extension
- Updating this toolkit
- Changelog
What is in here
tooling/- the published npm package@floez-werk/pi-extension-release-tool(commandpi-release): scaffolding, generated README blocks (badges, release notes) and the GitHub release body. Used by every extension repository vianpx -y …@^0.1 ….template/- the skeleton a new extension repository starts from (extension stub, README with badges and the changelog block,CHANGELOG.md,package.json,AGENTS.md,LICENSE,.gitignore/.gitattributes, thin CI/release callers, and a.gitea/workflows/placeholder that keeps Gitea from scheduling the GitHub-only workflows)..github/workflows/reusable-*.yml- the shared CI and release pipelines. Extension repositories call them withuses: …/[email protected], so a fix here reaches all of them without touching their files.prompts/- the interactive prompt template shipped with the package (/new-pi-extension): it collects the scaffold parameters, then follows the "New extension repository" flow below. Install the package as a pi package to get it.
Nothing in here is specific to a single extension; extension-specific code stays in the extension repository.
Tooling
# scaffold a new extension repository (see below for the full flow)
npx -y @floez-werk/pi-extension-release-tool@^0.1 init /srv/projects/piagent-my-ext \
--name @floez-werk/piagent-my-ext \
--desc "Pi extension: one-line description"
# regenerate the generated README blocks (badges, release notes) / verify them
npx -y @floez-werk/pi-extension-release-tool@^0.1 sync-readme
npx -y @floez-werk/pi-extension-release-tool@^0.1 sync-readme --check
# GitHub release body (the CHANGELOG section of the current version)
npx -y @floez-werk/pi-extension-release-tool@^0.1 release-notes --out /tmp/notes.md
# move the moving "v<major>.<minor>" tag (run after a release, from the repo)
npx -y @floez-werk/pi-extension-release-tool@^0.1 tag-major --pushThe README and release-notes subcommands read package.json and
CHANGELOG.md from the current directory, so they work in any repository. Two
blocks in README.md are generated instead of maintained by hand (both guarded
by --check in CI):
- the badges block (
badges:start/badges:end) - npm version, license, CI and changelog badges built frompackage.json(skipped in repositories without the markers) - the release-notes block (
changelog:start/changelog:end) - the notes of the current version fromCHANGELOG.md
Write those marker names in prose and in CHANGELOG.md without the comment
syntax; a literal marker would look like a second block to the check.
Prompt template: new extension
The package is also a pi package and ships one prompt template. Install it once and the wizard is available as a slash command:
pi install npm:@floez-werk/pi-extension-release-toolRun /new-pi-extension (no arguments needed). It asks for the package name, the
brief and the optional init flags, then scaffolds the repository and implements
the extension as described under New extension repository.
After a package update, /reload picks up the new version of the template.
New extension repository
Steps 1-2 happen in the browser, 3-4 on the shell, 5-8 once for the repository.
<repo> below is the repository name, e.g. piagent-my-ext.
Gitea: create the repository (
FloezWerk/<repo>, no README/license), then GitHub: create it as well (empty, public) - the GitHub repository is the mirror target and runs the workflows.Gitea: add the push mirror - Settings → Repository → Mirror Settings → Add Push Mirror with the GitHub URL and "Sync when new commits are pushed" enabled. Branches and tags are mirrored, which is what makes the release flow work: the tag is pushed to Gitea and GitHub Actions reacts on GitHub.
Gitea must not run the workflows itself (it has no runner): the scaffolded
.gitea/workflows/directory makes Gitea stop looking for workflows before it reads.github/workflows. Keep that placeholder in place, otherwise every push shows up in the Gitea Actions tab as a queued run with "No runner is online to pick up this job."Scaffold the repository (the tooling comes from npm, no clone needed):
npx -y @floez-werk/pi-extension-release-tool@^0.1 init /srv/projects/<repo> \ --name @floez-werk/<repo> \ --desc "Pi extension: one-line description" cd /srv/projects/<repo> && npm run checkThe scaffolder replaces all placeholders, generates the README release-notes block, runs
git init -b mainand creates the initial commit. Useful flags:--ext <file.ts>(extension file, default<repo>.ts),--cmd <name>(command without slash),--owner,--no-git.Push to Gitea:
git remote add origin ssh://git@gitea/FloezWerk/<repo>.git git push -u origin mainVerify on GitHub that the commit arrived (the mirror reacts on push).
First npm publish (manual, once per package): the package does not exist on npm yet, so an automation token cannot be scoped to it. Run locally:
npm login npm publish --access publicDo not push the tag of this version (
v0.1.0): the release workflow rejects versions that are already published, so the first tag-driven release is the next patch (v0.1.1). Keep the[0.1.0]link inCHANGELOG.mdpointing at npm.GitHub: set the secret
NPM_TOKEN(Settings → Secrets and variables → Actions): a granular token with publish rights for the new package (or an account-level automation token). Nothing else is needed - permissions and the workflow call are already in the scaffolded files.Optional, after the first tag-driven release: point the
[Unreleased]link inCHANGELOG.mdatcompare/v0.1.1...HEADinstead ofcommits/main.Verify the pipeline with the next change: bump the patch version, move the
[Unreleased]bullets into## [X.Y.Z],npm run readme, commit, thengit tag -a vX.Y.Z -m "vX.Y.Z" && git push origin main vX.Y.ZGitHub Actions then publishes to npm (with provenance), creates the GitHub release from the CHANGELOG section and attaches the tarball.
pi.dev/packageslists the package automatically (pi-packagekeyword).
Releasing an extension
- Move the
[Unreleased]bullets into## [X.Y.Z] - YYYY-MM-DDinCHANGELOG.md. - Bump
"version"inpackage.json, runnpm run readme, commit both. git tag -a vX.Y.Z -m "vX.Y.Z" && git push origin main vX.Y.Z.
The rest is the shared pipeline (see reusable-release.yml).
Updating this toolkit
- Versioning is
0.y.z; every change totooling/ortemplate/must end in a release, otherwise the pinnednpxversion in the extensions does not see it. - Release:
CHANGELOG.md([Unreleased]→## [X.Y.Z]),npm run readme, version bump, commit, tagvX.Y.Z, push. The release workflow then publishes to npm and creates the GitHub release. - Afterwards move the moving tag locally:
npm run tag-majorsetsvX.Yto this release and pushes it to Gitea, which mirrors it to GitHub. Tags are never created in a workflow, so Gitea stays the single source of truth for refs. - Extension repositories pin two refs: the npm package (
@^X.Yin theirpackage.jsonscripts) and the reusable workflows (@vX.Yin theirci.yml/release.yml). A patch release reaches them after the tag move; a minor release is a deliberate update - after a0.2.0release, update the pins in the affected repositories. - Workflows can be changed without touching the extensions: the tag move is what
delivers the change. Watch the first run after a change
(
publishjob of the tag build). - Changes that require new placeholders in
template/must also updatetooling/scaffold.mjs;npm run check(self-test) fails otherwise.
Changelog
Notable changes per version are documented in CHANGELOG.md.
0.1.4 - 2026-09-20
Added
- The toolkit doubles as a pi package and ships one prompt template
(
prompts/new-pi-extension.md): afterpi install npm:@floez-werk/pi-extension-release-tool,/new-pi-extensionasks for the package name, the brief and the optionalinitflags, then scaffolds the repository and implements the extension following this README. The package is flagged as a pi package (pi-packagekeyword,pi.prompts), so pi discovers the template automatically (/reloadafter an update). - The template ships
.gitea/workflows/with a README placeholder. Gitea scans that directory before.github/workflowsand only falls back when it does not exist, so the scaffolded repositories no longer queue a run for every push to Gitea (“No runner is online to pick up this job.”): the GitHub-only workflows are never scheduled there.
Full history and all versions: CHANGELOG.md
