diff --git a/packages/build-brainscales/package.py b/packages/build-brainscales/package.py
index eeccdd89b86c23e500ba9abf898af3acc8d653ca..6583d2ed169d6bd8e4de4c63031b8d9c14154fba 100644
--- a/packages/build-brainscales/package.py
+++ b/packages/build-brainscales/package.py
@@ -15,10 +15,20 @@ import spack.build_environment
 class BuildBrainscales(WafPackage):
     """Common stuff for BrainScaleS packages..."""
 
+    version(
+        "9.0-a4",
+        git="https://github.com/electronicvisions/releases-ebrains",
+        tag="ebrains-9.0-a4",
+        submodules=True, # the "submodules" parameter isn't part of the source cache key/name
+    )
+
     # waf setup performs git clone and might query gerrit
     depends_on('git', type=('build', 'link'))
     depends_on('py-git-review', type=('build', 'link'))
 
+    # old BrainScaleS EBRAINS releases used `waf setup --project=X` to download
+    # sources of the dependent repositories
+    @when("@:8")
     def do_fetch(self, mirror_only=False):
         """Setup the project."""
 
@@ -56,6 +66,16 @@ class BuildBrainscales(WafPackage):
         with unittest.mock.patch('spack.fetch_strategy.GitFetchStrategy.archive', new=custom_archive):
             self.stage.cache_local()
 
+    # new BrainScaleS EBRAINS releases use git submodules to download sources;
+    # we still need to keep the `.git/` folders of the submodules in the source cache though
+    @when("@9:")
+    def do_fetch(self, mirror_only=False):
+        # in the configure step, we need access to all archived .git folders
+        def custom_archive(self, destination):
+            super(spack.fetch_strategy.GitFetchStrategy, self).archive(destination)
+        with unittest.mock.patch('spack.fetch_strategy.GitFetchStrategy.archive', new=custom_archive):
+            super(BuildBrainscales, self).do_fetch(mirror_only)
+
     def _setup_common_env(self, env):
         # grenade needs to find some libraries for the JIT-compilation of
         # programs for BrainScaleS-2's embedded processor.
@@ -112,6 +132,9 @@ class BuildBrainscales(WafPackage):
 
         args = ['--prefix={0}'.format(self.prefix)]
         args += self.configure_args()
+
+        if spec.version >= Version("9"):
+            self.waf('setup', '--directory=' + str(spec.name), '--repo-db-url=https://github.com/electronicvisions/projects')
         self.waf('configure', '--build-profile=release', '--disable-doxygen', *args)
 
     def build_args(self):
diff --git a/packages/hxtorch/package.py b/packages/hxtorch/package.py
index c1450d958b7e47cdf00491f564924b9df8e67feb..d953effc49b439faa4a6d4132103a36bcb1486e9 100644
--- a/packages/hxtorch/package.py
+++ b/packages/hxtorch/package.py
@@ -22,8 +22,9 @@ class Hxtorch(build_brainscales.BuildBrainscales):
     # This repo provides a custom waf binary used for the build below
     git      = "https://github.com/electronicvisions/pynn-brainscales.git"
 
-    maintainers = ['emuller']
+    maintainers = ["emuller", "muffgaga"]
 
+    # newer versions are defined in the common base package
     version('8.0-a5',         tag='hxtorch-8.0-a5')
     version('8.0-a4',         tag='hxtorch-8.0-a4')
     version('8.0-a3',         tag='hxtorch-8.0-a3')
@@ -36,6 +37,7 @@ class Hxtorch(build_brainscales.BuildBrainscales):
     deps_hxtorch_core = [
         # compiler for the BrainScaleS-2 embedded processor ("PPU"); needed for
         # building/linking, at runtime and for testing
+        ('oppulance@9.0-a4', { "when":'@9.0-a4', "type": ('build', 'link', 'run', 'test') } ),
         ('oppulance@8.0-a5', { "when":'@8.0-a5', "type": ('build', 'link', 'run', 'test') } ),
         ('oppulance@8.0-a4', { "when":'@8.0-a4', "type": ('build', 'link', 'run', 'test') } ),
         ('oppulance@8.0-a3', { "when":'@8.0-a3', "type": ('build', 'link', 'run', 'test') } ),
@@ -73,6 +75,7 @@ class Hxtorch(build_brainscales.BuildBrainscales):
         ('py-pycodestyle', { "type": ('build', 'link', 'run') } ),
         ('py-pyelftools', { "type": ('build', 'link', 'run') } ),
         ('py-pylint', { "type": ('build', 'link', 'run') } ),
+        ('py-pytest', { "type": ('build', 'link', 'run') } ),
         ('py-torch@1.9.1:', { "type": ('build', 'link', 'run', 'test') } ),
         ('py-torchvision', { "type": ('run') } ), # for demos
         ('py-pyyaml', { "type": ('build', 'link', 'run') } ),
diff --git a/packages/jaxsnn/package.py b/packages/jaxsnn/package.py
index 1b1c07cf0f3da92463c2d864955b6384a5c48bb9..b2b3329696d60c417f627406876c1494b4320b45 100644
--- a/packages/jaxsnn/package.py
+++ b/packages/jaxsnn/package.py
@@ -15,6 +15,7 @@ import importlib
 build_brainscales = importlib.import_module("spack.pkg.ebrains-spack-builds.build_brainscales")
 hxtorch = importlib.import_module("spack.pkg.ebrains-spack-builds.hxtorch")
 
+
 class Jaxsnn(build_brainscales.BuildBrainscales):
     """jaxsnn is an event-based approach to machine-learning-inspired training
     and simulation of SNNs, including support for the BrainScaleS-2
@@ -24,8 +25,9 @@ class Jaxsnn(build_brainscales.BuildBrainscales):
     # This repo provides a custom waf binary used for the build below
     git      = "https://github.com/electronicvisions/pynn-brainscales.git"
 
-    maintainers = ['emuller']
+    maintainers = ["emuller", "muffgaga"]
 
+    # newer versions are defined in the common base package
     version('8.0-a5', tag='jaxsnn-8.0-a5')
     version('8.0-a4', tag='jaxsnn-8.0-a4')
     version('8.0-a3', tag='jaxsnn-8.0-a3')
diff --git a/packages/oppulance/package.py b/packages/oppulance/package.py
index 0d6feb978a0a7a5b94ddf5b6645f05ca5b5e75fa..826cc4394a612e1c799c29a5e0a35d866afb7feb 100644
--- a/packages/oppulance/package.py
+++ b/packages/oppulance/package.py
@@ -21,6 +21,13 @@ class Oppulance(Package):
     depends_on('wget')
     depends_on('gmp')
 
+    version(
+        "9.0-a4",
+        git="https://github.com/electronicvisions/releases-ebrains",
+        tag="ebrains-9.0-a4",
+        submodules=True, # the "submodules" parameter isn't part of the source cache key/name
+    )
+
     releases = [
         {
             'version': '8.0-a5',
@@ -68,7 +75,8 @@ class Oppulance(Package):
                 name=res,
                 git='https://github.com/electronicvisions/{}'.format(res),
                 tag=release['tag'],
-                placement=res
+                placement=res,
+                when="@"+release['version'],
             )
 
     # defined by gcc/contrib/download_prerequisites
@@ -111,7 +119,8 @@ class Oppulance(Package):
         bash('binutils-gdb/ci/00_build_install.sh')
         bash('gcc/ci/01_build_install_freestanding.sh')
         bash('newlib/ci/00_build_install.sh')
-        bash('ci/00_build_install_libstdc++.sh')
+        wdir = spec.version >= Version("9") and "oppulance" or "."
+        bash(wdir + '/ci/00_build_install_libstdc++.sh')
         mkdirp(spec.prefix)
         install_tree('install/.', spec.prefix)
 
diff --git a/packages/pynn-brainscales/package.py b/packages/pynn-brainscales/package.py
index 1ba865b89b14bfe9299783557cc94d1e801942fc..5b32e7f8e6ebd9269cc90cc010816658cedfd53d 100644
--- a/packages/pynn-brainscales/package.py
+++ b/packages/pynn-brainscales/package.py
@@ -22,8 +22,9 @@ class PynnBrainscales(build_brainscales.BuildBrainscales):
     # This repo provides a custom waf binary used for the build below
     git      = "https://github.com/electronicvisions/pynn-brainscales.git"
 
-    maintainers = ['emuller']
+    maintainers = ["emuller", "muffgaga"]
 
+    # newer versions are defined in the common base package
     version('8.0-a5',         tag='pynn-brainscales-8.0-a5')
     version('8.0-a4',         tag='pynn-brainscales-8.0-a4')
     version('8.0-a3',         tag='pynn-brainscales-8.0-a3')
@@ -35,6 +36,7 @@ class PynnBrainscales(build_brainscales.BuildBrainscales):
 
     # compiler for the BrainScaleS-2 embedded processor ("PPU"); needed for
     # building/linking, at runtime and for testing
+    depends_on('oppulance@9.0-a4', when='@9.0-a4', type=('build', 'link', 'run', 'test'))
     depends_on('oppulance@8.0-a5', when='@8.0-a5', type=('build', 'link', 'run', 'test'))
     depends_on('oppulance@8.0-a4', when='@8.0-a4', type=('build', 'link', 'run', 'test'))
     depends_on('oppulance@8.0-a3', when='@8.0-a3', type=('build', 'link', 'run', 'test'))
@@ -73,6 +75,7 @@ class PynnBrainscales(build_brainscales.BuildBrainscales):
     depends_on('py-pyelftools', type=('build', 'link', 'run'))
     depends_on('py-pylint', type=('build', 'link', 'run'))
     depends_on('py-pynn@0.9.4:', type=('build', 'link', 'run'))
+    depends_on('py-pytest', type=('build', 'link', 'run'))
     depends_on('py-pyyaml', type=('build', 'link', 'run'))
     depends_on('py-scipy', type=('build', 'link', 'run'))
     depends_on('py-sqlalchemy', type=('build', 'link', 'run'))
diff --git a/packages/wf-brainscales2-demos/package.py b/packages/wf-brainscales2-demos/package.py
index 42d0455785d4b5413df95aa4cd41990d3c622599..9adc239d05c8aca335529b373f9c81718bcd8c01 100644
--- a/packages/wf-brainscales2-demos/package.py
+++ b/packages/wf-brainscales2-demos/package.py
@@ -13,9 +13,10 @@ class WfBrainscales2Demos(Package):
 
     homepage="https://electronicvisions.github.io/documentation-brainscales2"
     git = "https://github.com/electronicvisions/brainscales2-demos"
-    maintainer = ["muffgaga"]
+    maintainers = ["emuller", "muffgaga"]
 
     # ECM: we probably should build the ipynb file in this package
+    version("9.0-a4", tag="jupyter-notebooks-9.0-a4")
     version("8.0-a5", tag="jupyter-notebooks-8.0-a5")
     version("8.0-a4", tag="jupyter-notebooks-8.0-a4")
     version("7.0-rc1-fixup3", tag="jupyter-notebooks-7.0-rc1-fixup3")