diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..598a38d4bc6065d6caee19229d6a1b071ea030e4
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+/.coverage
+*.egg-info
+.DS_Store
+__pycache__
+.venv
+.idea
+dist/
+results*/
\ No newline at end of file
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..df364c3f11be7ffa004c7c75418b5a6ecefdc108
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,21 @@
+upload:
+  stage: deploy
+  rules:
+    - if: $CI_COMMIT_TAG
+  needs: []
+  image: python:3.11
+  variables:
+    PRIVATE_REGISTRY_API_URL: "${PRIVATE_REGISTRY_API_URL}"
+    TWINE_PASSWORD: "${PRIVATE_REGISTRY_TOKEN_PASSWORD}"
+    TWINE_USERNAME: "${PRIVATE_REGISTRY_TOKEN_USERNAME}"
+  script:
+    - pip install "setuptools>=62.6"
+    - pip install -e .[dev]
+    - echo "Tag name used ${CI_COMMIT_TAG}"
+    - >
+      if [[ -z "$CI_COMMIT_TAG" ]]; then
+        CI_COMMIT_TAG="v0.0.1a"
+      fi
+    - sed -i "s/v0.0.1-dev/$CI_COMMIT_TAG/g" src/__init__.py
+    - python -m build
+    - python -m twine upload --verbose --repository-url ${PRIVATE_REGISTRY_API_URL} dist/*
diff --git a/bioflow_insight_cli/__init__.py b/bioflow_insight_cli/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/bioflow_insight_cli/main.py b/bioflow_insight_cli/main.py
new file mode 100644
index 0000000000000000000000000000000000000000..be9fdb451685a01b205926d32d79eaca953cd994
--- /dev/null
+++ b/bioflow_insight_cli/main.py
@@ -0,0 +1,45 @@
+import click
+
+from src.nextflow_file import Nextflow_File
+
+
+@click.command()
+@click.argument('main_workflow_path')
+@click.option('--author', 'author', required=False, help='Author name, extracted otherwise')
+@click.option('--name', 'name', required=False, help='Workflow name, extracted otherwise')
+@click.option('--output-dir', default='./results', help='Where the results will be written')
+@click.option(
+    '--no-duplicate',
+    'duplicate',
+    required=False,
+    default=True,
+    is_flag=True,
+    help=''
+    'When processes and subworkflows are duplicated in the workflows by the \'include as\' option, '
+    'this option will duplicate the procedures in the graph output.',
+)
+@click.option(
+    '--graph-in-dot-only',
+    'render_graphs',
+    required=False,
+    default=True,
+    is_flag=True,
+    help='Generate the graph output only in dot format, not png (faster).',
+)
+def cli_command(main_workflow_path, **kwargs):
+    return cli(main_workflow_path, **kwargs)
+
+
+def cli(main_workflow_path, render_graphs: bool, **kwargs):
+    """
+    The path to main file, subworkflows and modules must be in direct subdir of this file,
+    in folders with eponymous names.
+    """
+
+    w = Nextflow_File(address=main_workflow_path, **kwargs)
+    w.initialise()
+    w.generate_all_graphs(render_graphs=render_graphs)
+
+
+if __name__ == '__main__':
+    cli_command()
diff --git a/pyproject.toml b/pyproject.toml
index c326a12e2677df85e7d98cd125e191b595b6f004..e1c078858640d730904952bd31001cda2646f46c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -15,7 +15,7 @@ classifiers = [
 #    "License :: OSI Approved :: MIT License",
     "Operating System :: OS Independent",
 ]
-dynamic = ["version", "dependencies"]
+dynamic = ["version", "dependencies", "optional-dependencies"]
 
 [tool.setuptools.dynamic]
 dependencies = {file = ["requirements.txt"]}
diff --git a/requirements.dev.txt b/requirements-dev.txt
similarity index 100%
rename from requirements.dev.txt
rename to requirements-dev.txt
diff --git a/wf_test/main.nf b/wf_test/main.nf
new file mode 100644
index 0000000000000000000000000000000000000000..babcaa51d683d62012baa32851fb7bbafb441910
--- /dev/null
+++ b/wf_test/main.nf
@@ -0,0 +1,37 @@
+//include { p1 as p1_1; p1 as p1_2} from './modules/p1'
+
+
+//include { wf1 as wf1_1; wf1 as wf1_2 } from './subworkflows/wf1'
+include { wf1 as wf1_1 } from './subworkflows/wf1'
+//include { wf1 as wf1_2 } from './subworkflows/wf1'
+
+
+
+
+
+
+
+workflow {
+
+    a = channel.empty()
+
+    //c = wf1_1(a)
+    //c = wf1_2(b)
+
+    b = wf1_1(a)
+
+
+
+    //c = p1_1(p1_2(wf1_2(wf1_1(a))))
+    //wf1_1(a) 
+    //    | wf1_2 
+    //    | p1_2 
+    //    | p1_1
+
+    //(a, b) = p1_1(a)
+    //(ch1, ch2) = (params.ped ? [a, Channel.empty()]: [Channel.empty(), b])
+    //(ch1, ch2) = a.into(2)
+    
+
+
+}
\ No newline at end of file
diff --git a/wf_test/modules/p1.nf b/wf_test/modules/p1.nf
new file mode 100644
index 0000000000000000000000000000000000000000..67378561164304aad8c88a200730a6b56a7532ff
--- /dev/null
+++ b/wf_test/modules/p1.nf
@@ -0,0 +1,13 @@
+
+process p1 {
+    input:
+    file(input)
+    output:
+    file(output_1)
+    file(output_2)
+    
+    """
+    something
+    """
+}
+
diff --git a/wf_test/subworkflows/wf1.nf b/wf_test/subworkflows/wf1.nf
new file mode 100644
index 0000000000000000000000000000000000000000..973043057ede7430160c9d890769e8f4dbee5b84
--- /dev/null
+++ b/wf_test/subworkflows/wf1.nf
@@ -0,0 +1,13 @@
+include { p1  } from '../modules/p1'
+
+workflow wf1 {
+    take:
+    input_wf1
+
+    main:
+    output_wf1 = p1(input_wf1)
+
+    emit:
+    //val = output_wf1
+    output_wf1
+}
\ No newline at end of file