diff --git a/.gitignore b/.gitignore
index bdecffe1d54acd670993aeb7b5d36424f03f797e..f476726deaa61419d99bf9bcfaf0d5a547da68b6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,4 @@ dev-23a/
 dist/
 build/
 *.egg-info/
+.mpsd-software-root
diff --git a/src/mpsd_software_manager/mpsd_software.py b/src/mpsd_software_manager/mpsd_software.py
index fe2f99d646d7b86612651e899237c0eacbf1d7ea..7121469e5cc6cddd09edfe2e0a1b0487fb68cc25 100755
--- a/src/mpsd_software_manager/mpsd_software.py
+++ b/src/mpsd_software_manager/mpsd_software.py
@@ -82,6 +82,7 @@ config_vars = {
     "metadata_tag_open": "!<meta>",
     "metadata_tag_close": "</meta>!",
     "spack_environments_repo": "https://gitlab.gwdg.de/mpsd-cs/spack-environments.git",
+    "init_file": ".mpsd-software-root",
 }
 
 
@@ -1081,6 +1082,39 @@ def environment_status(mpsd_release: str, root_dir: Union[str, Path]) -> dict:
     return toolchain_map
 
 
+def initialize_environment(root_dir: Path) -> None:
+    """Initialize the software environment.
+
+    This creates a hidden file ``.mpsd-software-root`` to tag the location for
+    as the root of the installation. All compiled files, logs etc are written in
+    or below this subdirectory.
+
+    Parameters
+    ----------
+    root_dir : pathlib.Path
+        A Path object pointing to the current directory where the script was called.
+
+    """
+    # check if the root_dir is not already initialized
+    init_file = root_dir / config_vars["init_file"]
+    if init_file.exists():
+        logging.getLogger("print").info(
+            f"Error: Directory {str(root_dir)} is already initialized."
+        )
+        sys.exit(1)
+    else:
+        # create the init file
+        init_file.touch()
+        # note the execution in the execution summary log
+        # create the log file and fill it with the headers
+        record_script_execution_summary(root_dir=root_dir)
+        # record the msg in the log file
+        record_script_execution_summary(
+            root_dir=root_dir,
+            msg=f"Initialising MPSD software instance at {root_dir}.",
+        )
+
+
 def main():
     """Execute main entry point."""
     parser = argparse.ArgumentParser(
@@ -1104,6 +1138,7 @@ def main():
     )
     subparsers.required = True
     list_of_cmds = [
+        ("init", "Initialise the MPSD software instance in the current directory"),
         ("available", "What is available for installation?"),
         ("install", "Install a software environment"),
         # ("reinstall", "Reinstall a package_set"),
@@ -1132,11 +1167,13 @@ def main():
             )
 
         else:
-            subp.add_argument(
-                "release",
-                type=str,
-                help="Release version to prepare, install, reinstall or remove",
-            )
+            # all commands except init need a release version
+            if cmd != "init":
+                subp.add_argument(
+                    "release",
+                    type=str,
+                    help="Release version to prepare, install, reinstall or remove",
+                )
             if cmd in ["install", "reinstall", "remove"]:
                 # "install" command needs additional documentation
                 package_set_help = (
@@ -1166,21 +1203,29 @@ def main():
     # root dir is the place where this script is called from
     root_dir = Path(os.getcwd())
 
+    # set up logging for all actions except init
+    if args.action != "init":
+        log_file = get_installer_log_file_path(args.release, args.action, root_dir)
+    else:
+        log_file = None
     set_up_logging(
         args.loglevel,
-        get_installer_log_file_path(args.release, args.action, root_dir),
+        log_file,
     )
 
     # sanity check for common mistakes in command line arguments
-    if args.release.endswith("/"):  # happens easily with autocompletion
-        logging.error(
-            f"You provided mpsd-release='{args.release}'. "
-            f"Did you mean '{args.release.removesuffix('/')}'?"
-        )
-        sys.exit(1)
+    if args.action != "init":
+        if args.release.endswith("/"):  # happens easily with autocompletion
+            logging.error(
+                f"You provided mpsd-release='{args.release}'. "
+                f"Did you mean '{args.release.removesuffix('/')}'?"
+            )
+            sys.exit(1)
 
     # Check the command and run related function
-    if args.action == "remove":
+    if args.action == "init":
+        initialize_environment(root_dir)
+    elif args.action == "remove":
         remove_environment(args.release, root_dir, args.package_set)
     elif args.action == "start-new":
         start_new_environment(args.from_release, args.to_release, root_dir)
diff --git a/tests/test_mpsd_software.py b/tests/test_mpsd_software.py
index 514c8e5fabd8817fe693ed19e2c50d0ca60abc15..3ebd1fd69982ebb3883ac1ebd99eca4c3a46e8ed 100644
--- a/tests/test_mpsd_software.py
+++ b/tests/test_mpsd_software.py
@@ -520,6 +520,25 @@ def test_remove_environment(tmp_path):
     # done in test_install_environment_zlib
 
 
+def test_initialize_environment(tmp_path):
+    """Test that init_file is created as expected."""
+    # test that the init file is created as expected
+    mod.initialize_environment(tmp_path)
+    init_file = tmp_path / mod.config_vars["init_file"]
+
+    assert init_file.exists()
+    # ensure "Initialising MPSD software ..." is in the log file
+    log_file = tmp_path / mod.config_vars["cmd_log_file"]
+    with open(log_file, "r") as f:
+        assert (f"Initialising MPSD software instance at {tmp_path}") in f.read()
+
+    # test that calling again results in warning and exit code 1
+    with pytest.raises(SystemExit) as pytest_wrapped_e:
+        mod.initialize_environment(tmp_path)
+    assert pytest_wrapped_e.type == SystemExit
+    assert pytest_wrapped_e.value.code == 1
+
+
 def test_interface(tmp_path):
     """Test other things (not implemented yet)."""
     pass