The Forgejo Dialect
Forgejo (the forge behind Codeberg, self-hosted Forgejo, and Gitea) runs
GitHub-Actions-compatible workflows. You author exactly as you would for
GitHub Actions — same Workflow, Job, Step, and composites, imported
from @intentius/chant-lexicon-forgejo instead of the github package:
import { Workflow, Job, Step, Checkout, SetupNode } from "@intentius/chant-lexicon-forgejo";
export const workflow = new Workflow({ name: "CI", on: { push: { branches: ["main"] } },});
export const build = new Job({ "runs-on": "ubuntu-latest", steps: [ Checkout({}).step, SetupNode({ nodeVersion: "22", cache: "npm" }).step, new Step({ name: "Test", run: "npm test" }), ],});On build, the dialect:
- Drops keys Forgejo ignores —
permissionsandcontinue-on-errorare silently ignored by the Forgejo runner, so they are removed from the output and reported as build warnings (emitting them is misleading). - Maps runner labels — GitHub-hosted labels like
ubuntu-latesthave no fixed meaning on Forgejo. They are mapped to a default Forgejo label (docker), overridable per project. Unmapped labels pass through with a warning. - Resolves
uses:action refs — Forgejo has no GitHub Marketplace, so a bareuses: actions/checkout@v4is rewritten to a resolvable form. Commonactions/*are mapped under an actions root (https://code.forgejo.orgby default, overridable viaforgejo.actionsRoot);docker/*are pinned to their full GitHub URL. Local (./...),docker://, and full-URL refs pass through untouched. Anything else passes through and is reported as a warning so it’s never silently unresolvable.
Everything else is emitted by the github serializer, which already produces the exact YAML shape Forgejo executes.
Lint rules and editor support
Section titled “Lint rules and editor support”Forgejo has no lint rules or LSP completions/hover of its own — a forgejo
workflow is TypeScript indistinguishable in shape from an equivalent github
one, so chant lint and editor tooling run github’s checks and catalog
against forgejo source unmodified (completionProvider() and
hoverProvider() forward straight to githubPlugin’s). Lint rules are
wrapped rather than re-exported verbatim — each GHA0xx rule appears under a
WFJ- prefix (e.g. WFJ-GHA001) with its check logic untouched, so a
project (or chant audit) can load the github and forgejo plugins together
without an id collision. See the
github lexicon’s Lint Rules page for
the full GHA0xx catalog.
Migrating from GitHub Actions
Section titled “Migrating from GitHub Actions”Because github → forgejo YAML is near-identical, the migration is thin — it applies the same dialect as a build. Its real value is the compare: what the move costs.
chant migrate .github/workflows/ci.yml --to forgejo -o .forgejo/workflows/ci.yml --validate--validate prints a security posture report classifying each property’s
fate across the edge:
| Fate | Meaning |
|---|---|
translated | carried across as-is |
approximated | carried with a close equivalent |
needs-review | confirm/adjust on Forgejo (unresolved uses:, unmapped runner label) |
lost | the Forgejo runner ignores it (permissions, continue-on-error) |
The same view is available to agents as the forgejo:compare MCP tool, which
takes a workflow file and returns per-property fates plus summary counts —
read-only.