diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 486930329ea0c964957c53e166e62987731c6f4c..31a17376b2763828d2d6bfd724730603e687e9f6 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -25,7 +25,7 @@ build-template:
     - git add .
     - git commit -m 'Test'
     - git remote add origin git@git.astron.nl:templates/python-package-test
-    - git push --dry-run -u origin test
+    - git push --dry-run -u origin main
     - rm -r .venv
     - rm -r .git
   # cannot use needs, for artifacts on child pipeline so must regenerate template!
diff --git a/{{cookiecutter.project_slug}}/.pre-commit-config.yaml b/{{cookiecutter.project_slug}}/.pre-commit-config.yaml
index 47c01821516f4efefdb5b92d6a0e16e588793217..2980237ca655f4a550d2b1e8eee9db66c321417f 100644
--- a/{{cookiecutter.project_slug}}/.pre-commit-config.yaml
+++ b/{{cookiecutter.project_slug}}/.pre-commit-config.yaml
@@ -12,11 +12,6 @@ repos:
       - id: check-yaml
       - id: check-toml
       - id: detect-private-key
-  - repo: https://github.com/tox-dev/tox-ini-fmt
-    rev: "1.4.1"
-    hooks:
-      - id: tox-ini-fmt
-        args: ["-p", "fix"]
   - repo: local
     hooks:
       - id: tox-black
diff --git a/{{cookiecutter.project_slug}}/pyproject.toml b/{{cookiecutter.project_slug}}/pyproject.toml
index 1b3c57862a73ed1fa7c5271e6f9e647587d1cedf..9d1c2ead206133d22f799ab6a11c9d15a2d1ae4e 100644
--- a/{{cookiecutter.project_slug}}/pyproject.toml
+++ b/{{cookiecutter.project_slug}}/pyproject.toml
@@ -11,3 +11,69 @@ version_file = "{{cookiecutter.project_slug}}/_version.py"
 
 [tool.pylint]
 ignore = "_version.py"
+
+[tool.tox]
+# Generative environment list to test all supported Python versions
+requires = ["tox>=4.21"]
+env_list = ["fix", "pep8", "black", "pylint", "py{13, 12, 11, 10, 9}"]
+
+[tool.tox.env_run_base]
+package = "editable"
+deps = [
+    "-r{toxinidir}/requirements.txt",
+    "-r{toxinidir}/tests/requirements.txt"]
+set_env = { LANGUAGE = "en_US", LC_ALL = "en_US.UTF-8", PYTHONWARNINGS = "default::DeprecationWarning" }
+commands = [["python", "--version"], ["python", "-m", "pytest"]]
+
+[tool.tox.env.fix]
+description = "format the code base to adhere to our styles, and complain about what we cannot do automatically"
+skip_install = true
+deps = ["pre-commit-uv>=4.1.1"]
+commands = [["pre-commit", "run", "--all-files", "--show-diff-on-failure"]]
+
+[tool.tox.env.coverage]
+commands = [
+    ["python", "--version"],
+    ["python", "-m", "pytest", "--cov-report", "term", "--cov-report", "xml", "--cov-report", "html", "--cov={{cookiecutter.project_slug}}"]]
+
+# Command prefixes to reuse the same virtualenv for all linting jobs.
+[tool.tox.env.pep8]
+commands = [
+    ["python", "-m", "flake8", "--version"],
+    ["python", "-m", "flake8", { replace = "posargs", default = ["{{cookiecutter.project_slug}}", "tests"], extend = true }]
+]
+
+[tool.tox.env.black]
+commands = [
+    ["python", "-m", "black", "--version"],
+    ["python", "-m", "black", "--check", "--diff", { replace = "posargs", default = ["{{cookiecutter.project_slug}}", "tests"], extend = true }]
+]
+
+[tool.tox.env.pylint]
+commands = [
+    ["python", "-m", "pylint", "--version"],
+    ["python", "-m", "pylint", { replace = "posargs", default = ["{{cookiecutter.project_slug}}", "tests"], extend = true }]
+]
+
+[tool.tox.env.format]
+commands = [
+    ["python", "-m", "autopep8", "-v", "-aa", "--in-place", "--recursive", { replace = "posargs", default = ["{{cookiecutter.project_slug}}", "tests"], extend = true }],
+    ["python", "-m", "black", "-v", { replace = "posargs", default = ["{{cookiecutter.project_slug}}", "tests"], extend = true }]
+]
+
+[tool.tox.env.docs]
+deps = [
+    "-r{toxinidir}/requirements.txt",
+    "-r{toxinidir}/docs/requirements.txt"]
+# unset LC_ALL / LANGUAGE from testenv, would fail sphinx otherwise
+set_env = ""
+changedir = "{tox_root}"
+commands = [
+    ["python", "docs/cleanup.py"],
+    ["sphinx-build", "-b", "html", "docs/source", "docs/build/html"]
+]
+
+[tool.tox.env.build]
+package = "wheel"
+deps = ["build"]
+commands = [["python", "-m", "build"]]
diff --git a/{{cookiecutter.project_slug}}/setup.py b/{{cookiecutter.project_slug}}/setup.py
index b908cbe55cb344569d32de1dfc10ca7323828dc5..10fdaec810e96f0f1cbedb4a5ddf532c03f50dc4 100644
--- a/{{cookiecutter.project_slug}}/setup.py
+++ b/{{cookiecutter.project_slug}}/setup.py
@@ -1,3 +1,7 @@
+#  Copyright (C) 2023 ASTRON (Netherlands Institute for Radio Astronomy)
+#  SPDX-License-Identifier: Apache-2.0
+
+""" Setuptools entry point  """
 import setuptools
 
 setuptools.setup()
diff --git a/{{cookiecutter.project_slug}}/tox.ini b/{{cookiecutter.project_slug}}/tox.ini
deleted file mode 100644
index 52ca16f7fd9870256d114f53b627dcec761c3ac6..0000000000000000000000000000000000000000
--- a/{{cookiecutter.project_slug}}/tox.ini
+++ /dev/null
@@ -1,69 +0,0 @@
-[tox]
-# Generative environment list to test all supported Python versions
-requires =
-    tox>=4.21
-env_list =
-    fix
-    pep8
-    black
-    pylint
-    py3{13, 12, 11, 10, 9}
-
-[testenv]
-package = editable
-wheel_build_env = .pkg
-deps =
-    -r{toxinidir}/requirements.txt
-    -r{toxinidir}/tests/requirements.txt
-setenv =
-    LANGUAGE = en_US
-    LC_ALL = en_US.UTF-8
-    PYTHONWARNINGS = default::DeprecationWarning
-commands =
-    {envpython} --version
-    {envpython} -m pytest
-
-[testenv:fix]
-description = format the code base to adhere to our styles, and complain about what we cannot do automatically
-skip_install = true
-deps =
-    pre-commit-uv>=4.1.1
-commands =
-    pre-commit run --all-files --show-diff-on-failure
-
-[testenv:coverage]
-commands =
-    {envpython} --version
-    {envpython} -m pytest --cov-report term --cov-report xml --cov-report html --cov={{cookiecutter.project_slug}}
-
-# Use generative name and command prefixes to reuse the same virtualenv
-# for all linting jobs.
-[testenv:{pep8,black,pylint,format}]
-commands =
-    pep8: {envpython} -m flake8 --version
-    pep8: {envpython} -m flake8 {posargs:{{cookiecutter.project_slug}} tests}
-    black: {envpython} -m black --version
-    black: {envpython} -m black --check --diff {posargs:{{cookiecutter.project_slug}} tests}
-    pylint: {envpython} -m pylint --version
-    pylint: {envpython} -m pylint {posargs:{{cookiecutter.project_slug}} tests}
-    format: {envpython} -m autopep8 -v -aa --in-place --recursive {posargs:{{cookiecutter.project_slug}}}
-    format: {envpython} -m autopep8 -v -aa --in-place --recursive {posargs:tests}
-    format: {envpython} -m black -v {posargs:{{cookiecutter.project_slug}} tests}
-envdir = {toxworkdir}/linting
-
-[testenv:docs]
-deps =
-    -r{toxinidir}/requirements.txt
-    -r{toxinidir}/docs/requirements.txt
-; unset LC_ALL / LANGUAGE from testenv, would fail sphinx otherwise
-setenv =
-changedir = {toxinidir}
-commands =
-    {envpython} docs/cleanup.py
-    sphinx-build -b html docs/source docs/build/html
-
-[testenv:build]
-deps =
-    build
-commands =
-    {envpython} -m build