diff --git a/README.md b/README.md
index ad67e49..464af7e 100644
--- a/README.md
+++ b/README.md
@@ -5,6 +5,8 @@ to install them, how to upload them, how to maintain them, how to work
 with them. For details consult https://packaging.python.org, or
 https://py-pkgs.org, or other sites.
 
+Before you create a package please consider building a [virtual
+environment](./venv.md) for your project.
 
 ## Why packages?
 
@@ -17,12 +19,14 @@ other scripts in the very same directory.
 
 For example, consider a module `addition.py` and a script `analyze.py`
 both in the same directory:
+
 ```txt
 ├── addition.py
 └── analyze.py
 ```
 
 In `addition.py` we define a function `add_two()`:
+
 ```
 def add_two(x):
     return x + 2
@@ -30,6 +34,7 @@ def add_two(x):
 
 We can use this function in `analyze.py` by importing it from
 `addition.py`:
+
 ```
 from addition import add_two
 
@@ -42,7 +47,6 @@ directory (or if modules are in sub-directories). To make modules
 available in other places of your file system or even for other
 people, you need to turn the modules into packages.
 
-
 ## Minimal package
 
 First we make a project directory for our new package. Usually the
@@ -87,16 +91,20 @@ on your machine and import it from wherever you want.
 
 To install the project, go to the project root, here `packagehowto/` and run
 from your shell
+
 ```sh
 pip3 install .
 ```
+
 This installs the package of the current project folder `.` somewhere
 in your home directory. From anywhere in your home file system you now
 can import this package. The import line of our `analyze.py` file
 needs to look like this:
+
 ```
 from numerix.addition import add_two
 ```
+
 From the addition module of the numerix package the function add_two
 is imported.
 
@@ -105,13 +113,14 @@ package, for exmple when you add a new function or when you just fix
 some package code. This is tedious, and that is why there is a `-e`
 option ("editable install") for `pip install`. So install your package
 with
+
 ```sh
 pip3 install -e .
 ```
+
 Then all future changes on your package are immediately available
 without the need to reinstall the package again.
 
-
 ## The `__init__.py` file
 
 This file is your package. In fact, you could write a package that
@@ -119,11 +128,14 @@ only has an `__init__.py` file in the package directory. All code you
 want to make available in you package could be placed in the
 `__init__.py` file. For example, if you define an `add_four()` function
 in `__init__.py` like this:
+
 ```
 def add_four(x):
     return x + 4
 ```
+
 then it can be imported directly from the package:
+
 ```
 from numerix import add_four
 ```
@@ -132,34 +144,41 @@ Alternatively, you can define all your functions in module files, like
 we did with the function `add_two()` in the `addition.py` module. In
 the `__init__.py` file you can import this function and this way make
 it available directly from the package. With this line in `__init__.py`
+
 ```
 from .addition import add_two
 ```
+
 (note the `.` in front of `addition` - this makes it a relative
 import) you can import `add_two()` without specifying the module:
+
 ```
 from numerix import add_two
 ```
 
-
 ## Multiple modules within a package
 
 You can have as many modules as you need in your package. Let's add a
 module `numbers.py` to the `numerix` package
+
 ```txt
     └── numerix
         ├── __init__.py
         ├── addition.py
         └── numbers.py
 ```
+
 with the following content:
+
 ```
 from .addition import add_two
 
 def three():
     return add_two(1)
 ```
+
 This makes a function `three()` available that can be imported via
+
 ```
 from numerix.numbers import three
 ```
@@ -171,7 +190,6 @@ Note, that the `numbers.py` module imports a function from the
 And of course you can also import this function in `__init__.py` so
 that it can be imported from the package directly.
 
-
 ## Versioning
 
 Your package needs a version number (for details see below). But how to
@@ -187,7 +205,6 @@ by a dot. These numbers are incremented in the following way:
 - `minor`, when functionality is added in a backwards-compatible manner, and
 - `patch`, for backwards-compatible bug fixes.
 
-
 ## Package version
 
 For uploading your package to [PyPi](https://pypi.org/) you need to
@@ -233,7 +250,7 @@ file? It would be a very bad idea to write it there directly and
 update it whenever you change it in the `__init__.py` file. The
 version number should be set only in one place.
 
-This is possible, of course.  You need to specify the `version` field
+This is possible, of course. You need to specify the `version` field
 as `dynamic` in the `[project]` section. This tells the package tool
 that the version will be set dynamically by some code. There are
 several options to do so. The simplest one is to add a
@@ -272,18 +289,21 @@ python3 -m twine upload dist/*
 
 token
 
+## Using `poetry`
+
+You have now seen how you can do everything "from scratch". This is of course
+good to know. But there are tools to significantly simplify package creation
+and management, such as [`poetry`](https://python-poetry.org/). Its worth
+checking it out. Heres a nice demo: https://python-poetry.org/docs/basic-usage/
 
 ## Unit tests
 
 pytest
 
 coverage
+
 ```sh
 pytest -v --cov-report html --cov numerix tests/
 ```
 
 ## Documentation
-
-
-
-
diff --git a/venv.md b/venv.md
new file mode 100644
index 0000000..1d7e584
--- /dev/null
+++ b/venv.md
@@ -0,0 +1,111 @@
+# Why and how to use virtual environments?
+
+## What is a virtual environment?
+
+- A venv is **seperated** from your system packages / software, such as
+  firefox, thunderbird, etc.
+- Packages that are installed cannot talk to system packages and vice versa ->
+  you know what you use because you have to explicitly install **all** packages
+  that your project requires.
+- They can be build and destroyed easily and quickly to test different versions
+  of packages (or even python itself!).
+
+## How to build a `venv`?
+
+- PEP405 (=python style guide) virtual environments should be named "venv" or ".venv".
+
+To create one, run:
+
+```sh
+python -m venv <name> # e.g. venv or .venv
+```
+
+You should now see a new directory in your current working directory called "venv" or ".venv".
+
+To activate it, run this on linux or macos:
+
+```sh
+source <name>/bin/activate
+```
+
+On windows, you can run
+
+```sh
+./<name>/Scripts/Activate.ps1
+```
+
+You should now see an indicator in your shell prompt such as:
+
+```sh
+(venv) user@host:~/path/to/your/project
+```
+
+It is active as long as you do not explicitly deactivate it or close the shell.
+You can now `pip install <package>` as you normally would.
+To check which python version it uses, you can run this on linux/macos:
+
+```sh
+which python3 && which pip
+```
+
+Both paths should point to your virtual environment in the project directory.
+
+To deactivate, simply run on linux/macos/windows:
+
+```sh
+deactivate
+```
+
+What we have now seen all comes with python but there are tools that make this
+more convenient: What if you also want to try another pyhton version? Or use
+the same venv in multiple projects? For this, there is `pyenv`:
+
+### `venv` pitfalls
+
+- You cannot move or rename **any** directory inside the path to your project
+  directory or the `venv` breaks. You can rename a folder _inside_ the project
+  directory as long as you dont change the path to the venv.
+- You cannot use the venv for multiple projects
+
+`pyenv` fixes this:
+
+## Using [`pyenv`](https://github.com/pyenv/pyenv.git) / [`pyenv-virtualenv`](https://github.com/pyenv/pyenv-virtualenv.git)
+
+Use pyenv for managing python versions and pyenv-virtualenv for a slightly
+easier way of interacting with venvs.
+
+To download another python version (without destroying your system), simply run:
+
+```sh
+pyenv install python3.12
+```
+
+To see which versions are installed, you can run
+
+```sh
+pyenv versions
+```
+
+To set this version as the default in a specific directory (and all its subdirectories), run:
+
+```sh
+pyenv local 3.12
+```
+
+Now you can either use the tutorial above to create a standard venv or use `pyenv-virtualenv` like this:
+
+```sh
+pyenv virtualenv 3.12 <name>
+```
+
+Now you can activate it by `pyenv activate <name>` or use it as the standard in the current and subdirectories with
+
+```sh
+pyenv local <name>
+```
+
+The convenient thing is, that this venv will always be automatically activated
+when you enter the directory. If you do this in multiple directories, you can
+have the same venv for multiple projects.
+
+There are some alternatives to `pyenv` such as