Contributing and reference7 of 12
Continuous integration
On this page
None of this has ever run. The workflows below are files in
.github/workflows/; the tree they live in has no git history and has never been pushed anywhere, so no job has ever been scheduled, no runner has ever picked one up, and no step has been observed passing or failing. This page describes what they are written to do. Read it as intent, not as evidence.Where a step matches a command that was run locally, that is said explicitly.
ci.yml — three jobs
Triggered on a push to main and on every pull request. Permissions are contents: read and nothing
else. Runs of the same ref cancel each other.
python
Three legs: Ubuntu on Python 3.11, Ubuntu on 3.13, and Windows on 3.13. fail-fast is off,
so one red leg does not hide the others. Thirty-minute timeout, chosen because a test that wedges on
Windows would otherwise hold a runner for the six-hour default before anybody learned anything.
Windows is in the matrix because a single unguarded POSIX import once stopped every command there. Only one Windows version: the Python floor is already enforced on Ubuntu.
pip install -e "./api[dev]"
pytest api/tests -q
KOTOBA_CHROMIUM_NO_SANDBOX=1 is set for the whole job. The Linux image ships Chrome and forbids
unprivileged user namespaces, so a headless render finds no usable sandbox and hands back nothing —
which is a failing assertion rather than a skip. The variable is the product's own answer for a host of
that shape.
frontend
npm ci
npx tsc --noEmit --noUnusedLocals --noUnusedParameters
npm test
Node comes from .nvmrc. Both of these commands were run locally while writing these pages: the
typecheck exited 0 with no output, and npm test reported 325 passing.
package — the one that matters
This is the job that answers a question no local run can: does pip install give a stranger a working
app on a machine with no Node?
It builds the frontend, installs the package, runs the packaged-UI test with KOTOBA_REQUIRE_WEB=1 —
which turns "nobody built the web UI" from a skip into a failure — and builds a wheel. Then:
python -m venv /tmp/fresh
/tmp/fresh/bin/pip install "$(ls dist/*.whl)[server,cli]"
# rebuild PATH without any directory that holds node, npm or npx
PATH="$CLEAN" /tmp/fresh/bin/python -c "…"
Inside that interpreter it asserts shutil.which("node") is None, imports kotoba.core.frontend, and
requires describe()["kind"] == "packaged".
Two details worth copying:
- It checks that Node was there to begin with (
command -v node || exit 1), because a job that removes something absent proves nothing. - It strips whole directories, not the
nodebinary, because the runner image ships its own Node beside the one the setup step installs. Python goes with them, which is why the fresh interpreter is invoked by absolute path.
If you touch packaging, expect this job to have an opinion.
codeql.yml
Static analysis over three languages — python, javascript-typescript and actions — with the
security-and-quality query pack. It runs on pushes to main, on pull requests targeting it, and
weekly on a Monday, because findings arrive as the rules improve and not only as the code changes.
Results land in the repository's Security tab.
The comment at the top says why it exists: this project runs shell commands and Python on the machine of whoever installs it, and a scanner that traces a path from an argument into a subprocess is the one kind of review a solo maintainer cannot do by eye on every change.
Every action here is pinned by commit SHA rather than by tag, because this job holds
security-events: write.
release.yml — never walked
Triggered by a tag matching v*, or manually.
The build job runs npm ci, python scripts/build_web.py, then a check that the tag and
kotoba.__version__ agree, then the whole test suite, then the packaged-UI test, then
python -m build. A release is the one moment a green suite is not optional: the version number it
spends cannot be spent again.
The publish job uploads to PyPI using Trusted Publishing — PyPI trusts the workflow by name, so
there is no API token to leak or rotate. That arrangement has to be configured once on the PyPI
project before the first release will go through, and there is nothing in this repository that can
tell you whether it has been. Treat the publication path as unproven.
The attach job uploads the same artifacts to the GitHub release, using the GitHub CLI rather than a
third-party action, because that job can write to the repository and that is not a permission to hand
to code nobody here reviews.
No package has been published from this tree, and no tag has been pushed from it. PyPI is the only
distribution channel the repository contains: searching it for winget, homebrew and chocolatey
returns nothing, and no workflow pushes a container image. There are two Dockerfiles and a
docker-compose.yml, but they are for running Kotoba yourself, not for publishing an image.
dependabot.yml
Monthly and grouped, across four ecosystems: pip (/api), npm (/), GitHub Actions (/) and Docker
(/). Minor and patch updates are grouped into one pull request each. pip and npm are capped at five
open pull requests; the other two declare no cap. The reasoning written into the file is that a solo
maintainer drowning in pull requests reviews none of them — except security ones, which arrive on their
own regardless of the schedule.
The Dockerfiles are in there because they are a documented way to run Kotoba, so their base images age in public.
Reproducing CI locally
Everything except the package job:
pytest api/tests -q
npx tsc --noEmit --noUnusedLocals --noUnusedParameters
npm test
python scripts/build_web.py
The package job cannot be reproduced honestly on a machine that has Node installed, which is the
point of it.
