Contributing
Thank you for contributing to TunaOS β an image factory that produces bootc-based desktop OS images.
Quick Startβ
brew install just podman shellcheck shfmt yq
git clone https://github.com/tuna-os/tunaOS.git && cd tunaOS
just fix && just check
Contributor onboardingβ
New here? Start with an org-wide good first issue β a curated, maintainer-sized task covering documentation parity, a small script fix, or test coverage. Before starting, leave a comment saying you are taking the issue so the work is not duplicated. The current pool and census are tracked in the Hacktoberfest 2026 contributor plan; new bounded tasks are labelled good first issue during the weekly contributor triage below.
The current starter runway lives in the org-wide good first issue pool, mostly in tuna-os/docs (docs-parity and guide tasks β e.g. desktop quick-starts, verification guides, cheat sheets). These tasks are intentionally independent of the image build pipeline and are curated for first-time contributors. If one is claimed or closed, pick another bounded task from the same search.
Fork β PR loopβ
- Fork
tuna-os/tunaoson GitHub and clone your fork. - Create a focused branch:
git switch -c docs/short-description. - Make the smallest change that satisfies the issue's acceptance criteria.
- Run the checks listed below, then commit and push the branch to your fork.
- Open a PR against
tuna-os/tunaos:main, link the issue withFixes #NNN, and include the checks you ran. - Keep the branch available while review is in progress; follow-up fixes can be pushed to the same PR.
You do not need write access to the upstream repository. GitHub's fork-based PR flow is the normal path for external contributors. If CI fails, include the failing job and a short reproduction in the PR rather than silently retrying it. If a push is rejected because the GitHub App lacks workflows permission, follow the workflow publishing runbook; repository workflow YAML cannot grant that App-level permission.
For the Hacktoberfest 2026 backlog, see the contributor plan for current candidates, acceptance standards, and event dates.
Before drafting a guide, a campaign post, or anything that names an image reference, a shipped tool, hardware support, or readiness, work through the pre-write claim checklist. Five guide PRs in a row were closed for the same two defects: an image reference the project does not publish, and toolchains the images do not ship. The checklist is those defects written down.
Ways to contribute without touching the build pipeline:
- Docs & guides β the docs site has its own
good first issuebacklog and takes content PRs for guides, FAQs, and variant pages; run the claim checklist before you write - Community β help triage open issues, answer questions in Matrix, or improve the adopters list if your org uses TunaOS
- Labels β issues tagged
help wantedare explicitly open for external contribution
When you pick an issue, say so in a comment (prevents double work) and ask in Matrix if you get stuck β someone is usually around.
Weekly contributor triageβ
The maintainer reserves one 30-minute slot each week for contributor work. During that slot:
- Review new issues and label at least one bounded task
good first issuewhen its scope and acceptance criteria are clear. - Check claimed starter issues for unanswered questions, stale claims, or duplicate work.
- Review open contributor PRs, respond to blockers, and keep CI failures distinguishable from code-review requests.
- Refresh the starter links above when tasks are completed, superseded, or moved to another repository.
This is a lightweight queue-management commitment, not a promise of immediate review. Contributors should expect an acknowledgement or status update within the next weekly triage slot.
Pre-Commit (mandatory)β
just fix # format shell scripts and Justfile
just check # shellcheck, yamllint, actionlint
just ci runs what the PR gate runs β check, the CI contract, and every
unit suite β so a green just ci locally is a green PR, minus the
scheduled build matrix. The rest of the contributor contract:
| Command | What it is |
|---|---|
just setup | install the tools the checks and tests need, print versions |
just test-fast | the Python suites only, stop at the first failure |
just test | bats + pytest, same as CI |
just test-contract | every green gate exists, is reachable, meets its freshness SLA |
just test-random [seed] | the suites in a seeded random order (the nightly lane) |
just test-cell <variant> <flavor> | the desktop contract against one published image, as the nightly sweep runs it |
just test-e2e <iso> | boot an ISO under QEMU and assert the live environment reaches readiness |
Every incident becomes a regression testβ
A bug that let an unusable or wrongly-promoted image ship is not fixed until a
test proves the old failure mode cannot silently recur. Put that test in
tests/regressions/, named after the issue
(test_issue_<number>_<what_must_not_recur>.py), with a docstring that cites
the issue and the run or log that measured the failure. The seed example is
#858 (marlin:kde shipped with no Wayland session): the regression test runs
the desktop contract's own check against a filesystem with no session file
and holds that it fails. tests/test_regression_convention.py enforces the
naming.
Building Imagesβ
just build yellowfin gnome # single flavor (~25 min warm cache)
just build yellowfin kde linux/amd64 # specific platform
just build yellowfin all # all flavors
Adding a Desktop Environmentβ
No shell scripting required. Write a YAML manifest:
# 1. Create the manifest
cat > manifests/desktops/budgie.yaml <<EOF
display_manager: gdm
packages:
fedora:
packages: [budgie-desktop, budgie-extras, gdm]
el10:
packages: [budgie-desktop, gdm]
optional: [budgie-extras]
apt:
- budgie-desktop
- gdm3
versionlock: [glib2]
EOF
# 2. Add stage to Containerfile (copy from existing DE pattern)
# 3. Add flavor to .github/build-config.yml
# 4. That's it β install-desktop.sh handles the rest
Architectureβ
The build system is manifest-driven:
manifests/desktops/*.yaml β install-desktop.sh β image
Key scripts:
scripts/resolve-flavor.shβ routes flavor to Containerfile + build paramsscripts/resolve-image.shβ resolves image refs from 3 config sourcesscripts/build-image-inner.shβ the build engine (env-var driven)build_scripts/desktop/install-desktop.shβ generic DE installer (reads YAML)build_scripts/lib.shβ shared helpers (OS detection, pkg abstraction)
Full architecture: docs/AGENT_GUIDE.md
Pull Request Processβ
- Fork and create a feature branch
- Run
just fix && just check - Open PR against
main - CI validates (lint, unit tests, image build on PR)
- Merge queue handles the rest (automerge for passing PRs)
Testingβ
just test # all tests (bats + pytest)
just test-bats # shell script tests
just verify-disk image.qcow2 # QEMU boot verification
Documentationβ
- Vision β project philosophy
- Agent Guide β architecture reference
- Pipeline β CI/CD details
- Testing β test harness