diff --git a/.copier-answers.yml b/.copier-answers.yml
new file mode 100644
index 0000000000000000000000000000000000000000..34ffd2287588e48bdee09fbb746bd143f7d61b5f
--- /dev/null
+++ b/.copier-answers.yml
@@ -0,0 +1,11 @@
+# Changes here will be overwritten by Copier
+_commit: v0.1.6
+_src_path: https://gitlab.softwareheritage.org/swh/devel/swh-py-template.git
+description: Software Heritage data model
+distribution_name: swh-model
+have_cli: true
+have_workers: false
+package_root: swh/model
+project_name: swh.model
+python_minimal_version: '3.7'
+readme_format: rst
diff --git a/.gitignore b/.gitignore
index 68708728197a5774d0b68cdd676cd092103aa1fe..d44f090faaff2efa7c3dfa14d2a402ae0d6b4eaf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,15 +1,16 @@
-*~
-build
-/.coverage
-/.coverage.*
-dist
 *.egg-info/
+*.pyc
+.coverage
 .eggs/
 .hypothesis
-*.pyc
-__pycache__
-.pytest_cache
-*.sw?
+.mypy_cache
 .tox
-version.txt
-.mypy_cache/
+__pycache__
+build/
+dist/
+# these are symlinks created by a hook in swh-docs' main sphinx conf.py
+docs/README.rst
+docs/README.md
+# this should be a symlink for people who want to build the sphinx doc
+# without using tox, generally created by the swh-env/bin/update script
+docs/Makefile.sphinx
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 33a226de603535a6347f7fd1c5a5ec7f4a7e8765..8957bec6128b471c890816598b471a0116b18f7e 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -1,13 +1,23 @@
 repos:
   - repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v4.3.0
+    rev: v4.4.0
     hooks:
       - id: trailing-whitespace
       - id: check-json
       - id: check-yaml
 
+  - repo: https://github.com/python/black
+    rev: 23.1.0
+    hooks:
+      - id: black
+
+  - repo: https://github.com/PyCQA/isort
+    rev: 5.12.0
+    hooks:
+      - id: isort
+
   - repo: https://github.com/pycqa/flake8
-    rev: 5.0.4
+    rev: 6.0.0
     hooks:
       - id: flake8
         additional_dependencies: [flake8-bugbear==22.9.23]
@@ -18,6 +28,9 @@ repos:
       - id: codespell
         name: Check source code spelling
         stages: [commit]
+      - id: codespell
+        name: Check commit message spelling
+        stages: [commit-msg]
 
   - repo: local
     hooks:
@@ -29,12 +42,3 @@ repos:
         language: system
         types: [python]
 
-  - repo: https://github.com/PyCQA/isort
-    rev: 5.11.5
-    hooks:
-      - id: isort
-
-  - repo: https://github.com/python/black
-    rev: 22.10.0
-    hooks:
-      - id: black
diff --git a/MANIFEST.in b/MANIFEST.in
deleted file mode 100644
index caa4b690c5fefc3b25112d1e63359adb6f8d48ef..0000000000000000000000000000000000000000
--- a/MANIFEST.in
+++ /dev/null
@@ -1,6 +0,0 @@
-include README.md
-include Makefile
-include requirements*.txt
-include version.txt
-recursive-include swh/model/tests/data *.tgz
-recursive-include swh py.typed
diff --git a/PKG-INFO b/PKG-INFO
index 2b39d445071a74288e1f17dd61eb9983142f4d28..3a5db5f62b9644ca76fa6a426b9450a389a637a4 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,14 +1,13 @@
 Metadata-Version: 2.1
 Name: swh.model
-Version: 6.9.1
+Version: 6.10.0
 Summary: Software Heritage data model
-Home-page: https://forge.softwareheritage.org/diffusion/DMOD/
-Author: Software Heritage developers
-Author-email: swh-devel@inria.fr
-Project-URL: Bug Reports, https://forge.softwareheritage.org/maniphest
+Author-email: Software Heritage developers <swh-devel@inria.fr>
+Project-URL: Homepage, https://gitlab.softwareheritage.org/swh/devel/swh-model
+Project-URL: Bug Reports, https://gitlab.softwareheritage.org/swh/devel/swh-model/-/issues
 Project-URL: Funding, https://www.softwareheritage.org/donate
-Project-URL: Source, https://forge.softwareheritage.org/source/swh-model
 Project-URL: Documentation, https://docs.softwareheritage.org/devel/swh-model/
+Project-URL: Source, https://gitlab.softwareheritage.org/swh/devel/swh-model.git
 Classifier: Programming Language :: Python :: 3
 Classifier: Intended Audience :: Developers
 Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
@@ -29,15 +28,10 @@ Provides-Extra: cli
 Requires-Dist: swh.core>=0.3; extra == "cli"
 Requires-Dist: Click; extra == "cli"
 Requires-Dist: dulwich; extra == "cli"
-Provides-Extra: testing-minimal
-Requires-Dist: aiohttp; extra == "testing-minimal"
-Requires-Dist: click; extra == "testing-minimal"
-Requires-Dist: pytest; extra == "testing-minimal"
-Requires-Dist: pytz; extra == "testing-minimal"
-Requires-Dist: types-click; extra == "testing-minimal"
-Requires-Dist: types-python-dateutil; extra == "testing-minimal"
-Requires-Dist: types-pytz; extra == "testing-minimal"
 Provides-Extra: testing
+Requires-Dist: swh.core>=0.3; extra == "testing"
+Requires-Dist: Click; extra == "testing"
+Requires-Dist: dulwich; extra == "testing"
 Requires-Dist: aiohttp; extra == "testing"
 Requires-Dist: click; extra == "testing"
 Requires-Dist: pytest; extra == "testing"
@@ -45,9 +39,14 @@ Requires-Dist: pytz; extra == "testing"
 Requires-Dist: types-click; extra == "testing"
 Requires-Dist: types-python-dateutil; extra == "testing"
 Requires-Dist: types-pytz; extra == "testing"
-Requires-Dist: swh.core>=0.3; extra == "testing"
-Requires-Dist: Click; extra == "testing"
-Requires-Dist: dulwich; extra == "testing"
+Provides-Extra: testing-minimal
+Requires-Dist: aiohttp; extra == "testing-minimal"
+Requires-Dist: click; extra == "testing-minimal"
+Requires-Dist: pytest; extra == "testing-minimal"
+Requires-Dist: pytz; extra == "testing-minimal"
+Requires-Dist: types-click; extra == "testing-minimal"
+Requires-Dist: types-python-dateutil; extra == "testing-minimal"
+Requires-Dist: types-pytz; extra == "testing-minimal"
 
 Software Heritage - Data model
 ==============================
diff --git a/docs/Makefile b/docs/Makefile
index b97c7532e5b946df72b8641f22f6e3e2ba84602c..5e57d15d9e950b11d45d4f1241e9eadc67ecbd38 100644
--- a/docs/Makefile
+++ b/docs/Makefile
@@ -1,2 +1,2 @@
-include ../../swh-docs/Makefile.sphinx
+include Makefile.sphinx
 -include Makefile.local
diff --git a/mypy.ini b/mypy.ini
index d411c51089c58ee654ae210c90af17e8bb388e1a..2f09ec1206332b62139f5d945e5fabbe1c165d2b 100644
--- a/mypy.ini
+++ b/mypy.ini
@@ -1,6 +1,13 @@
 [mypy]
 namespace_packages = True
 warn_unused_ignores = True
+explicit_package_bases = True
+# ^ Needed for mypy to detect py.typed from swh packages installed
+# in editable mode
 
 # 3rd party libraries without stubs (yet)
+[mypy-pkg_resources.*]
+ignore_missing_imports = True
 
+# [mypy-add_your_lib_here.*]
+# ignore_missing_imports = True
diff --git a/pyproject.toml b/pyproject.toml
index 69b8f4dd830abf638e624eeea85dbc580c862538..dc4a8fdbcfa318a976278be5dac404f5fde26591 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,3 +1,52 @@
+[project]
+name = "swh.model"
+authors = [
+    {name="Software Heritage developers", email="swh-devel@inria.fr"},
+]
+
+description = "Software Heritage data model"
+readme = {file = "README.rst", content-type = "text/x-rst"}
+requires-python = ">=3.7"
+classifiers = [
+    "Programming Language :: Python :: 3",
+    "Intended Audience :: Developers",
+    "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
+    "Operating System :: OS Independent",
+    "Development Status :: 5 - Production/Stable",
+]
+dynamic = ["version", "dependencies", "optional-dependencies"]
+
+[tool.setuptools.packages.find]
+include = ["swh.*"]
+
+[tool.setuptools.dynamic]
+dependencies = {file = ["requirements.txt"]}
+
+[tool.setuptools.dynamic.optional-dependencies]
+cli = {file = "requirements-cli.txt"}
+testing = {file = ["requirements-cli.txt", "requirements-test.txt"]}
+testing_minimal = {file = "requirements-test.txt"}
+
+[project.entry-points.console_scripts]
+"swh.identify" = "swh.model.cli:identify"
+
+[project.entry-points."swh.cli.subcommands"]
+"swh.model" = "swh.model.cli"
+
+[project.urls]
+"Homepage" = "https://gitlab.softwareheritage.org/swh/devel/swh-model"
+"Bug Reports" = "https://gitlab.softwareheritage.org/swh/devel/swh-model/-/issues"
+"Funding" = "https://www.softwareheritage.org/donate"
+"Documentation" = "https://docs.softwareheritage.org/devel/swh-model/"
+"Source" = "https://gitlab.softwareheritage.org/swh/devel/swh-model.git"
+
+[build-system]
+requires = ["setuptools", "setuptools-scm"]
+build-backend = "setuptools.build_meta"
+
+[tool.setuptools_scm]
+fallback_version = "0.0.1"
+
 [tool.black]
 target-version = ['py37']
 
@@ -9,3 +58,4 @@ use_parentheses = true
 ensure_newline_before_comments = true
 line_length = 88
 force_sort_within_sections = true
+known_first_party = ['swh']
diff --git a/pytest.ini b/pytest.ini
index 10242f24f0323cac877764b3d4db78b11aa182f7..1782940443bf7d2776787ba40c5344c1989ff032 100644
--- a/pytest.ini
+++ b/pytest.ini
@@ -1,8 +1,12 @@
 [pytest]
-addopts = --doctest-modules -p no:pytest_swh_core
 norecursedirs = build docs .*
+asyncio_mode = strict
+# There is not --import-mode=importlib below because it is incompatible
+# with the tox-in-tox hack we use for now to run tests.
+addopts =
+    --doctest-modules
+    -p no:pytest_swh_core
+
 markers =
     fs: tests that involve filesystem ios
     requires_optional_deps: tests in test_cli.py that should not run if optional dependencies are not installed
-
-asyncio_mode = strict
diff --git a/setup.py b/setup.py
deleted file mode 100755
index 8698ecc1975a5ffe4091d738cb9407c2bc443bf5..0000000000000000000000000000000000000000
--- a/setup.py
+++ /dev/null
@@ -1,76 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (C) 2015-2020  The Software Heritage developers
-# See the AUTHORS file at the top-level directory of this distribution
-# License: GNU General Public License version 3, or any later version
-# See top-level LICENSE file for more information
-
-from io import open
-from os import path
-
-from setuptools import find_packages, setup
-
-here = path.abspath(path.dirname(__file__))
-
-# Get the long description from the README file
-with open(path.join(here, "README.rst"), encoding="utf-8") as f:
-    long_description = f.read()
-
-
-def parse_requirements(name=None):
-    if name:
-        reqf = "requirements-%s.txt" % name
-    else:
-        reqf = "requirements.txt"
-
-    requirements = []
-    if not path.exists(reqf):
-        return requirements
-
-    with open(reqf) as f:
-        for line in f.readlines():
-            line = line.strip()
-            if not line or line.startswith("#"):
-                continue
-            requirements.append(line)
-    return requirements
-
-
-setup(
-    name="swh.model",
-    description="Software Heritage data model",
-    long_description=long_description,
-    long_description_content_type="text/x-rst",
-    python_requires=">=3.7",
-    author="Software Heritage developers",
-    author_email="swh-devel@inria.fr",
-    url="https://forge.softwareheritage.org/diffusion/DMOD/",
-    packages=find_packages(),
-    setup_requires=["setuptools-scm"],
-    use_scm_version=True,
-    install_requires=parse_requirements() + parse_requirements("swh"),
-    extras_require={
-        "cli": parse_requirements("cli"),
-        "testing-minimal": parse_requirements("test"),
-        "testing": parse_requirements("test") + parse_requirements("cli"),
-    },
-    include_package_data=True,
-    entry_points="""
-        [console_scripts]
-        swh-identify=swh.model.cli:identify
-        [swh.cli.subcommands]
-        identify=swh.model.cli
-    """,
-    classifiers=[
-        "Programming Language :: Python :: 3",
-        "Intended Audience :: Developers",
-        "License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
-        "Operating System :: OS Independent",
-        "Development Status :: 5 - Production/Stable",
-    ],
-    project_urls={
-        "Bug Reports": "https://forge.softwareheritage.org/maniphest",
-        "Funding": "https://www.softwareheritage.org/donate",
-        "Source": "https://forge.softwareheritage.org/source/swh-model",
-        "Documentation": "https://docs.softwareheritage.org/devel/swh-model/",
-    },
-)
diff --git a/swh.model.egg-info/PKG-INFO b/swh.model.egg-info/PKG-INFO
index 2b39d445071a74288e1f17dd61eb9983142f4d28..3a5db5f62b9644ca76fa6a426b9450a389a637a4 100644
--- a/swh.model.egg-info/PKG-INFO
+++ b/swh.model.egg-info/PKG-INFO
@@ -1,14 +1,13 @@
 Metadata-Version: 2.1
 Name: swh.model
-Version: 6.9.1
+Version: 6.10.0
 Summary: Software Heritage data model
-Home-page: https://forge.softwareheritage.org/diffusion/DMOD/
-Author: Software Heritage developers
-Author-email: swh-devel@inria.fr
-Project-URL: Bug Reports, https://forge.softwareheritage.org/maniphest
+Author-email: Software Heritage developers <swh-devel@inria.fr>
+Project-URL: Homepage, https://gitlab.softwareheritage.org/swh/devel/swh-model
+Project-URL: Bug Reports, https://gitlab.softwareheritage.org/swh/devel/swh-model/-/issues
 Project-URL: Funding, https://www.softwareheritage.org/donate
-Project-URL: Source, https://forge.softwareheritage.org/source/swh-model
 Project-URL: Documentation, https://docs.softwareheritage.org/devel/swh-model/
+Project-URL: Source, https://gitlab.softwareheritage.org/swh/devel/swh-model.git
 Classifier: Programming Language :: Python :: 3
 Classifier: Intended Audience :: Developers
 Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
@@ -29,15 +28,10 @@ Provides-Extra: cli
 Requires-Dist: swh.core>=0.3; extra == "cli"
 Requires-Dist: Click; extra == "cli"
 Requires-Dist: dulwich; extra == "cli"
-Provides-Extra: testing-minimal
-Requires-Dist: aiohttp; extra == "testing-minimal"
-Requires-Dist: click; extra == "testing-minimal"
-Requires-Dist: pytest; extra == "testing-minimal"
-Requires-Dist: pytz; extra == "testing-minimal"
-Requires-Dist: types-click; extra == "testing-minimal"
-Requires-Dist: types-python-dateutil; extra == "testing-minimal"
-Requires-Dist: types-pytz; extra == "testing-minimal"
 Provides-Extra: testing
+Requires-Dist: swh.core>=0.3; extra == "testing"
+Requires-Dist: Click; extra == "testing"
+Requires-Dist: dulwich; extra == "testing"
 Requires-Dist: aiohttp; extra == "testing"
 Requires-Dist: click; extra == "testing"
 Requires-Dist: pytest; extra == "testing"
@@ -45,9 +39,14 @@ Requires-Dist: pytz; extra == "testing"
 Requires-Dist: types-click; extra == "testing"
 Requires-Dist: types-python-dateutil; extra == "testing"
 Requires-Dist: types-pytz; extra == "testing"
-Requires-Dist: swh.core>=0.3; extra == "testing"
-Requires-Dist: Click; extra == "testing"
-Requires-Dist: dulwich; extra == "testing"
+Provides-Extra: testing-minimal
+Requires-Dist: aiohttp; extra == "testing-minimal"
+Requires-Dist: click; extra == "testing-minimal"
+Requires-Dist: pytest; extra == "testing-minimal"
+Requires-Dist: pytz; extra == "testing-minimal"
+Requires-Dist: types-click; extra == "testing-minimal"
+Requires-Dist: types-python-dateutil; extra == "testing-minimal"
+Requires-Dist: types-pytz; extra == "testing-minimal"
 
 Software Heritage - Data model
 ==============================
diff --git a/swh.model.egg-info/SOURCES.txt b/swh.model.egg-info/SOURCES.txt
index e835209099f5b62c794fd0f8ddde6eb5bd602c23..e7c1502139a4ff80f2c4bf578489a4722799019e 100644
--- a/swh.model.egg-info/SOURCES.txt
+++ b/swh.model.egg-info/SOURCES.txt
@@ -1,3 +1,4 @@
+.copier-answers.yml
 .git-blame-ignore-revs
 .gitignore
 .pre-commit-config.yaml
@@ -5,7 +6,6 @@ AUTHORS
 CODE_OF_CONDUCT.md
 CONTRIBUTORS
 LICENSE
-MANIFEST.in
 Makefile
 Makefile.local
 README.rst
@@ -16,7 +16,6 @@ requirements-cli.txt
 requirements-test.txt
 requirements.txt
 setup.cfg
-setup.py
 tox.ini
 bin/git-revhash
 bin/swh-hashtree
@@ -35,7 +34,6 @@ docs/_templates/.placeholder
 docs/images/.gitignore
 docs/images/Makefile
 docs/images/swh-merkle-dag.dia
-swh/__init__.py
 swh.model.egg-info/PKG-INFO
 swh.model.egg-info/SOURCES.txt
 swh.model.egg-info/dependency_links.txt
diff --git a/swh.model.egg-info/entry_points.txt b/swh.model.egg-info/entry_points.txt
index 4e29a6a9f180b72d0492d92a68223c4afae58c83..086c813cb88693d1a78a390eb534950953067d88 100644
--- a/swh.model.egg-info/entry_points.txt
+++ b/swh.model.egg-info/entry_points.txt
@@ -1,5 +1,5 @@
 [console_scripts]
-swh-identify = swh.model.cli:identify
+swh.identify = swh.model.cli:identify
 
 [swh.cli.subcommands]
-identify = swh.model.cli
+swh.model = swh.model.cli
diff --git a/swh.model.egg-info/requires.txt b/swh.model.egg-info/requires.txt
index 39f740b37efe9a654ae1762e2cde95e53e487434..f10fca8983487e0ae01fabb44eedfbdbdc5d402b 100644
--- a/swh.model.egg-info/requires.txt
+++ b/swh.model.egg-info/requires.txt
@@ -12,6 +12,9 @@ Click
 dulwich
 
 [testing]
+swh.core>=0.3
+Click
+dulwich
 aiohttp
 click
 pytest
@@ -19,11 +22,8 @@ pytz
 types-click
 types-python-dateutil
 types-pytz
-swh.core>=0.3
-Click
-dulwich
 
-[testing-minimal]
+[testing_minimal]
 aiohttp
 click
 pytest
diff --git a/swh/__init__.py b/swh/__init__.py
deleted file mode 100644
index b36383a61027f0875a3cb103edc8f2a4528a3289..0000000000000000000000000000000000000000
--- a/swh/__init__.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from pkgutil import extend_path
-
-__path__ = extend_path(__path__, __name__)
diff --git a/swh/model/cli.py b/swh/model/cli.py
index 6508602110672049403ed507b5274549527d14dc..7fd99ed0a1c51407fae814786ff2deb6aed72537 100644
--- a/swh/model/cli.py
+++ b/swh/model/cli.py
@@ -20,10 +20,12 @@ except ImportError:
     exit(1)
 
 try:
-    from swh.core.cli import swh as swh_cli_group
+    import swh.core.cli
+
+    cli_command = swh.core.cli.swh.command
 except ImportError:
     # stub so that swh-identify can be used when swh-core isn't installed
-    swh_cli_group = click  # type: ignore
+    cli_command = click.command
 
 from swh.model.from_disk import Directory
 from swh.model.swhids import CoreSWHID
@@ -175,7 +177,7 @@ def identify_object(
     return swhid
 
 
-@swh_cli_group.command(context_settings=CONTEXT_SETTINGS)
+@cli_command(context_settings=CONTEXT_SETTINGS)
 @click.option(
     "--dereference/--no-dereference",
     "follow_symlinks",
@@ -304,7 +306,7 @@ def identify(
                 click.echo("SWHID mismatch: %s != %s" % (verify, swhid))
                 sys.exit(1)
         else:
-            for (obj, swhid) in results:
+            for obj, swhid in results:
                 msg = swhid
                 if show_filename:
                     msg = "%s\t%s" % (swhid, os.fsdecode(obj))
diff --git a/swh/model/collections.py b/swh/model/collections.py
index d7150fa9c2477d2297c175bee37d67da2a5f8408..35314ca06c3b925982fa0a544d6532d6f17d7a9e 100644
--- a/swh/model/collections.py
+++ b/swh/model/collections.py
@@ -45,7 +45,7 @@ class ImmutableDict(Mapping, Generic[KT, VT]):
         return self._data[key]
 
     def __iter__(self):
-        for (k, v) in self.data:
+        for k, v in self.data:
             yield k
 
     def __len__(self):
@@ -61,5 +61,5 @@ class ImmutableDict(Mapping, Generic[KT, VT]):
         """Returns a copy of this ImmutableDict without the given key,
         as well as the value associated to the key."""
         new_items = copy.deepcopy(self._data)
-        popped_value = new_items.pop(popped_key, None)  # type: ignore
+        popped_value: Optional[VT] = new_items.pop(popped_key, None)
         return (popped_value, ImmutableDict(new_items))
diff --git a/tox.ini b/tox.ini
index 15d0702f8e538a5c4f57fd2a94a2505859507f17..394f961c9cf461ed145ea3cc2df876b7b9b10b56 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,6 +1,10 @@
 [tox]
-minversion=4
-envlist=black,flake8,mypy,py3-{minimal,full-cover}
+minversion = 4
+envlist =
+  black
+  flake8
+  mypy
+  py3-{minimal,full-cover}
 
 [testenv]
 extras =
@@ -14,6 +18,8 @@ commands =
   full:    {envsitepackagesdir}/swh/model \
   minimal: {envsitepackagesdir}/swh/model/tests/test_cli.py -m 'not requires_optional_deps' \
            {posargs}
+# --rootdir and --import-mode must NOT be used here due to the (hack-ish) way of
+# executing tests (using tox-in-tox); see below
 
 [testenv:py3{,7,8,9,10,11,12,13},pypy3{,5,6,7,8,9,10,11,12,13}]
 skip_install = true
@@ -25,7 +31,7 @@ commands =
 [testenv:black]
 skip_install = true
 deps =
-  black==22.10.0
+  black==23.1.0
 commands =
   {envpython} -m black --check swh
 
@@ -42,7 +48,7 @@ commands =
 extras =
   testing
 deps =
-  mypy==1.0.1
+  mypy>1.4
 commands =
   mypy swh
 
@@ -51,32 +57,14 @@ commands =
 # breaking doc build
 [testenv:sphinx]
 allowlist_externals = make
-usedevelop = true
 extras =
   testing
 deps =
-  # fetch and install swh-docs in develop mode
-  -e git+https://gitlab.softwareheritage.org/swh/devel/swh-docs.git\#egg=swh.docs
+  # fetch and install swh-docs
+  git+https://gitlab.softwareheritage.org/swh/devel/swh-docs.git\#egg=swh.docs
 setenv =
   SWH_PACKAGE_DOC_TOX_BUILD = 1
   # turn warnings into errors
   SPHINXOPTS = -W
 commands =
-  make -I ../.tox/sphinx/src/swh-docs/swh/ -C docs
-
-# build documentation only inside swh-environment using local state
-# of swh-docs package
-[testenv:sphinx-dev]
-allowlist_externals = make
-usedevelop = true
-extras =
-  testing
-deps =
-  # install swh-docs in develop mode
-  -e ../swh-docs
-setenv =
-  SWH_PACKAGE_DOC_TOX_BUILD = 1
-  # turn warnings into errors
-  SPHINXOPTS = -W
-commands =
-  make -I ../.tox/sphinx-dev/src/swh-docs/swh/ -C docs
+  make -I {env_dir}/share/swh-docs -C docs