diff --git a/alice-ci/setup.cfg b/alice-ci/setup.cfg
index d1e593d..9271d70 100644
--- a/alice-ci/setup.cfg
+++ b/alice-ci/setup.cfg
@@ -1,6 +1,6 @@
 [metadata]
 name = alice-ci
-version = 0.0.6
+version = 0.0.7
 author = Daniel Gyulai
 description = Alice CI framework
 long_description = file: README.md
@@ -16,11 +16,15 @@ classifiers =
 [options]
 package_dir =
     = src
-packages = find:
+packages = alice
 python_requires = >=3.6
 install_requires =
     PyYAML==6.0
     virtualenv==20.14.0
 
+[options.entry_points]
+console_scripts =
+    alice = alice.cli:main
+
 [options.packages.find]
 where = src
\ No newline at end of file
diff --git a/alice-ci/src/alice/cli.py b/alice-ci/src/alice/cli.py
index bd958c4..74a7cc6 100644
--- a/alice-ci/src/alice/cli.py
+++ b/alice-ci/src/alice/cli.py
@@ -6,7 +6,7 @@ from alice.runnerfactory import Factory
 from alice.exceptions import ConfigException, NonZeroRetcode, RunnerError
 
 
-def gen_env(self, param_list):
+def gen_env(param_list):
     env_vars = {}
     for item in param_list:
         item_parts = item.split("=")
@@ -24,8 +24,7 @@ def parse_jobs(args):
             envs = gen_env(args.env)
             if args.verbose:
                 print(f"[Alice] Env vars from CLI: {envs}")
-            factory.update_runners({"env": envs})
-        jobParser = ConfigParser(args.input, factory, args.verbose)
+        jobParser = ConfigParser(args.input, factory, gen_env(args.env), args.verbose)
 
         print("Begin pipeline steps...")
         for step in args.steps:
diff --git a/alice-ci/src/alice/runnerfactory.py b/alice-ci/src/alice/runnerfactory.py
index f9012e5..93a561b 100644
--- a/alice-ci/src/alice/runnerfactory.py
+++ b/alice-ci/src/alice/runnerfactory.py
@@ -1,3 +1,4 @@
+import inspect
 from os import getcwd
 
 from alice.runners.pythonrunner import PythonRunner
@@ -8,12 +9,14 @@ class Factory():
     def __init__(self, verbose) -> None:
         self.verbose = verbose
         self.runnertypes = self.__load_runners()
+        self.runner_configs = {}
         self.runners = {}
         self.workdir = getcwd()
         self.globals = {}
 
     def __load_runners(self):
         # TODO: Runners can be imported via cli too
+        # https://git.gyulai.cloud/gyulaid/alice/issues/4
         # module = __import__("module_file")
         # my_class = getattr(module, "class_name")
         runners = {"python": PythonRunner}
@@ -25,15 +28,11 @@ class Factory():
     def set_globals(self, globals):
         self.globals = globals
 
-    def update_globals(self, update):
-        if "env" in update:
-            self.globals["env"].update(update["env"])
-
     def update_runners(self, config):
         for runnertype, runnerconfig in config.items():
             if runnertype != "global":
                 if (self.verbose):
-                    print(f"[Alice] Configuring runner {runnertype}")
+                    print(f"[Alice] Configuring runner: {runnertype}")
                 self.get_runner(runnertype).update_config(runnerconfig)
 
     def get_runner(self, runnertype):
@@ -41,9 +40,14 @@ class Factory():
             if runnertype in self.runnertypes:
                 if (self.verbose):
                     print(f"[Alice] Initializing runner: {runnertype}")
-                self.runners[runnertype] = self.runnertypes[runnertype](self.workdir,
-                                                                        self.globals,
-                                                                        self.verbose)
+                params = {
+                    "workdir": self.workdir,
+                    "verbose": self.verbose
+                }
+                print(type(self.runnertypes[runnertype]))
+                print(inspect.signature(self.runnertypes[runnertype]))
+                print(inspect.getargspec(self.runnertypes[runnertype]))
+                self.runners[runnertype] = self.runnertypes[runnertype](params, self.globals)
             else:
                 raise ConfigException(f"Invalid runner type: {runnertype}")
         return self.runners[runnertype]
diff --git a/alice-ci/src/alice/runners/__init__.py b/alice-ci/src/alice/runners/__init__.py
index e6df5ea..ddb45ff 100644
--- a/alice-ci/src/alice/runners/__init__.py
+++ b/alice-ci/src/alice/runners/__init__.py
@@ -1,3 +1 @@
 from alice.runners.pythonrunner import PythonRunner
-
-__all__ = ["PythonRunner"]
diff --git a/alice-ci/src/alice/runners/pythonrunner.py b/alice-ci/src/alice/runners/pythonrunner.py
index 30367c5..473822c 100644
--- a/alice-ci/src/alice/runners/pythonrunner.py
+++ b/alice-ci/src/alice/runners/pythonrunner.py
@@ -2,21 +2,20 @@ import subprocess
 import os
 import sys
 import shlex
-from tabnanny import verbose
 
 from alice.exceptions import NonZeroRetcode, RunnerError, ConfigException
 
 
-# same venv across all runs!
 class PythonRunner():
-    def __init__(self, workdir, defaults, verbose) -> None:
-        self.workdir = workdir
-        self.virtual_dir = os.path.abspath(os.path.join(workdir, "venv"))
-        self.config = defaults
+    def __init__(self, params, user_defaults) -> None:
+        print("Python")
+        self.workdir = params["workdir"]
+        self.virtual_dir = os.path.abspath(os.path.join(self.workdir, "venv"))
+        self.config = user_defaults
         self.env_vars = os.environ.copy()
-        for env_var in defaults["env"]:
+        for env_var in user_defaults["env"]:
             self.env_vars[env_var["name"]] = env_var["value"]
-        self.verbose = verbose
+        self.verbose = params["verbose"]
 
         self.__init_venv()
 
diff --git a/alice-ci/src/alice/utils.py b/alice-ci/src/alice/utils.py
index af1e1c0..b90f275 100644
--- a/alice-ci/src/alice/utils.py
+++ b/alice-ci/src/alice/utils.py
@@ -6,26 +6,26 @@ from alice.exceptions import ConfigException
 
 
 class ConfigParser:
-    def __init__(self, file_path, factory, verbose=False) -> None:
+    def __init__(self, file_path, factory, env_vars, verbose=False) -> None:
         self.verbose = verbose
         with open(file_path) as f:
             self.config = yaml.safe_load(f)
         self.factory = factory
-        self.factory.set_globals(self.__gen_globals())
+        self.factory.set_globals(self.__gen_globals(env_vars))
         if "runners" in self.config:
             self.factory.update_runners(self.config["runners"])
         self.jobs = self.__get_jobs()
 
-    # Initialize env, workdir if not present
-    def __gen_globals(self):
+    # Initialize env and workdir if not present in global
+    def __gen_globals(self, env_vars):
         globals = {
-            "env": [],
+            "env": env_vars,
             "workdir": None
         }
         if "runners" in self.config:
             if "global" in self.config["runners"]:
                 if "env" in self.config["runners"]["global"]:
-                    globals["env"] = self.config["runners"]["global"]["env"]
+                    globals["env"].update(self.config["runners"]["global"]["env"])
                 if "workdir" in self.config["runners"]["global"]:
                     globals["workdir"] = self.config["runners"]["global"]["workdir"]
         
diff --git a/docs/runners.md b/docs/runners.md
index 08a4b8e..f10daff 100644
--- a/docs/runners.md
+++ b/docs/runners.md
@@ -5,4 +5,17 @@ Runners are responsible to execute a list of commands in a set environment defin
 ## List of runners
 
 * Python - executes python commands in a virtual environment
-* Docker - executes each job in a separate Docker container - unimplemented
\ No newline at end of file
+* Docker - executes each job in a separate Docker container - unimplemented
+
+## Import schema
+
+TODO
+
+## Runner API
+
+Each runner has to support the following functions:
+
+### Constructor(params, user_defaults)
+
+* params: dict of runtime variables regarding the program itself
+* user_defaults: raw data from the CI file's global dict, with 
\ No newline at end of file