diff --git a/larp/routes/playbook.py b/larp/routes/playbook.py
index b4d60a7a34570863f56b841bffe81006e5f67867..efcc8389654fd3b3e1cadd55b227c0e369ef638c 100644
--- a/larp/routes/playbook.py
+++ b/larp/routes/playbook.py
@@ -5,10 +5,6 @@ from fastapi import APIRouter
 from fastapi.responses import JSONResponse
 from pydantic import BaseModel
 
-import ansible_runner
-import venv
-import tempfile
-
 from larp import config
 
 router = APIRouter()
@@ -48,7 +44,7 @@ async def add_playbook(new_playbook: Playbook) -> Playbook:
 
 
 @router.get('/run/{playbook_name}')
-async def run_playbook(playbook_name: str) -> JSONResponse | PlaybookRun:
+async def run_playbook(playbook_name: str) -> PlaybookRun:
     # TODO: implement
     params = config.load()
     playbook_list = os.listdir(params['playbook-dir'])
@@ -57,16 +53,6 @@ async def run_playbook(playbook_name: str) -> JSONResponse | PlaybookRun:
     except ValueError:
         return JSONResponse(status_code=404, content=f'Playbook with name {playbook_name} not found.')
 
-    # Build a temp venv
-    venv_path = tempfile.mkdtemp(prefix='workflow-', suffix='-venv')
-    builder = venv.EnvBuilder(with_pip=True, system_site_packages=True)
-    builder.create(venv_path)
-
-
-    # Get collection from Ansible Galaxy
-    # ansible_collections
-
-    # Run playbook asynchronously
-    ansible_runner.run_async()
+    # Run playbook asynchronously with run_playbook.sh
 
     return PlaybookRun(result_code=1)
diff --git a/larp/run_playbook.sh b/larp/run_playbook.sh
new file mode 100755
index 0000000000000000000000000000000000000000..500dabe58683db64f8ff5a75fdd2fb6180e30aa7
--- /dev/null
+++ b/larp/run_playbook.sh
@@ -0,0 +1,37 @@
+#!/bin/sh
+
+usage() {
+  echo "Usage: $0 <larp_collection_uri> <playbook-name> <remote-host> (<extra-vars> ...)" 1>&2;
+  exit 2
+}
+
+if [ $# -lt 2 ]; then
+  echo "Illegal number of parameters"
+  usage
+fi
+
+VENV_PATH=$(mktemp -d -t larp-venv-)
+if [[ ! -d "$VENV_PATH" ]]; then
+  echo "Unable to create temp directory for venv"
+  exit 1
+fi
+
+cleanup() {
+  rm -rf "$VENV_PATH"
+  echo "Deleted venv in $VENV_PATH"
+}
+
+# Always delete old venv upon exit
+trap cleanup EXIT
+
+###
+
+echo "Creating venv in $VENV_PATH"
+python3 -m venv "$VENV_PATH"
+source "$VENV_PATH/bin/activate"
+pip install -r ../requirements.txt  # FIXME
+pip install ansible ansible_runner
+
+ansible-galaxy collection install "$1"
+ansible-playbook "$2" -i "$3", --connection=local  # TODO: Add support for extra vars
+# FIXME: remove --conection=local from command above
diff --git a/requirements.txt b/requirements.txt
index 40613c9048f6efd5bc942b4a9c266a20fad198a2..53d10f35b8d8783f172f0fc8b0eae53037b61ab2 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,9 +1,6 @@
 jsonschema
 requests
-ansible
-ansible-runner
 
-httpx
 fastapi
 pydantic
 uvicorn[standard]
diff --git a/setup.py b/setup.py
index 061160ceba1b387cad25db40dfd12bab939334a7..0a52ae1994b658a66459bf0a53a7b3109b2f4852 100644
--- a/setup.py
+++ b/setup.py
@@ -11,5 +11,7 @@ setup(
     install_requires=[
         'jsonschema',
         'requests',
+        'fastapi',
+        'pydantic'
     ]
 )
diff --git a/test/playbook.yml b/test/playbook.yml
new file mode 100644
index 0000000000000000000000000000000000000000..148b72e59a4d98ee30db7bf65959a4e1d587c22e
--- /dev/null
+++ b/test/playbook.yml
@@ -0,0 +1,4 @@
+- name: test-playbook
+  hosts: all
+  roles:
+    - kvklink.echo.echo_uptime