diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..d7a44e8c1f72ffdabb0deda04538ac2e4191efbf
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,41 @@
+# Steps:
+# - Getting apps
+# - Running the dag
+# - Publishing the release with the dag inside
+
+download_apps:
+  stage: .pre
+  tags: 
+    - stable
+  image:
+    name: kaczmarj/apptainer:latest
+    entrypoint: [""]
+  rules:
+    - if: '$CI_COMMIT_BRANCH == "main" && $CI_PIPELINE_SOURCE == "merge_request_event"'
+  script:
+    - mkdir apps
+    #- apptainer build apps/pggb.sif oras://registry.forgemia.inra.fr/alexis.mergez/pangratools/pggb:latest
+    - apptainer build apps/snakebox.sif oras://registry.forgemia.inra.fr/alexis.mergez/pangratools/snakebox:latest
+    #- apptainer build apps/pytools.sif oras://registry.forgemia.inra.fr/alexis.mergez/pangetools/pytools:latest
+    #- apptainer build apps/PanGeTools.sif oras://registry.forgemia.inra.fr/alexis.mergez/pangetools/pangetools:latest
+
+shallow_run_workflow:
+  stage: test
+  tags: 
+    - stable
+  image: 
+    name: kaczmarj/apptainer:latest
+    entrypoint: [""]
+  rules:
+    - if: '$CI_COMMIT_BRANCH == "main" && $CI_PIPELINE_SOURCE == "merge_request_event"'
+  script:
+    - apptainer run apps/snakebox.sif snakemake -c1 --dag | dot -Tsvg > workflow.svg
+  artifacts:
+    paths:
+      - workflow.svg
+
+
+
+    
+
+
diff --git a/Snakefile b/Snakefile
index 0ec2a67187395d26f9eeb5e1a1cbdd520158beb0..35bf42d125566ad5d96fb2d4f76237f76c0cfd7d 100644
--- a/Snakefile
+++ b/Snakefile
@@ -2,18 +2,22 @@ configfile: "config.yaml"
 
 import os
 import numpy as np
+import gzip
 
 SAMPLES = np.unique([os.path.basename(f).split('.fa')[0] for f in os.listdir("data/haplotypes/")])
 nHAP = len(SAMPLES)
 
+# Getting the list of chromosomes
+with gzip.open("data/haplotypes/"+config['reference'], "r") as handle:
+    CHRLIST = [line.decode().split("#")[-1].split('\n')[0] for line in handle.readlines() if line.decode()[0] == ">"]
+
 rule all:
     input:
         "output/pan1c.pggb."+config['name']+".gfa",
         "output/pan1c.pggb."+config['name']+".chromGraph.stats.tsv",
         "output/figures",
         "output/pav.matrices",
-        "logs/pan1c.pggb."+config['name']+".logs.tar.gz",
-        "output/pan1c.pggb."+config['name']+".time.stats.tsv"
+        "output/pan1c.pggb."+config['name']+".stats.tsv"
 
 rule samtools_index:
     # Using samtools faidx to index compressed fasta
@@ -52,21 +56,21 @@ rule ragtag_scaffolding:
             -o {output}
         """
 
-checkpoint clustering:
+rule clustering:
     # Read alignment file to create bins for each chromosome
     input:
         expand('data/hap.ragtagged/{haplotype}.ragtagged.fa.gz', haplotype=SAMPLES)
     output:
-        directory("data/chrInputs")
+        expand('data/chrInputs/{chromosome}.fa.gz', chromosome=CHRLIST)
     threads: workflow.cores
     params:
         apppath=config["app.path"]
     shell:
         """
-        mkdir -p {output}
+        mkdir -p $(dirname {output[0]})
         apptainer run {params.apppath}/pytools.sif python scripts/inputClustering.py \
-            --fasta {input} --output {output}
-        for file in {output}/*.fa; do
+            --fasta {input} --output $(dirname {output[0]})
+        for file in $(dirname {output[0]})/*.fa; do
             apptainer run --app bgzip {params.apppath}/PanGeTools.sif -@ {threads} $file
         done
         """
@@ -91,31 +95,20 @@ rule pggb_on_chr:
             apptainer run {params.apppath}/pggb.sif \
             -i {input.fa} {params.pggb} -n {nHAP} -t {threads} -T {threads} -o data/chrGraphs/{wildcards.chromosome} 2>&1 | \
             tee {log.cmd}
-        echo $(ls data/chrGraphs/{wildcards.chromosome})
         mv data/chrGraphs/{wildcards.chromosome}/*.gfa {output.gfa}
         """
 
-def availGraphs(wildcards):
-    # Get the list of output from 'clustering' and returns the list of corresponding graphs
-    # This triggers snakemake to run pggb on every chromosomes available
-    checkpoint_output = checkpoints.clustering.get(**wildcards).output[0]
-    return expand(
-        "data/chrGraphs/{i}.gfa",
-        i=glob_wildcards(os.path.join(checkpoint_output, "{i}.fa.gz")).i
-        )
-
 rule generate_graph_list:
     # Generate a text file containing all created graphs
     input:
-        availGraphs
+        expand("data/chrGraphs/{chromosome}.gfa", chromosome=CHRLIST)
     output:
         "data/chrGraphs/graphsList.txt"
     threads: 1
-    shell:
-        """
-        touch {output}
-        for file in {input}; do echo $file >> {output}; done
-        """
+    run:
+        with open(output[0], "w") as handle:
+            for file in input:
+                handle.write(file+"\n")
 
 rule graph_squeeze:
     # Using odgi to merge every subgraphs into a final one
@@ -181,11 +174,12 @@ rule aggregate_stats:
     output:
         "output/pan1c.pggb."+config['name']+".chromGraph.stats.tsv"
     params:
-        apppath=config['app.path']
+        apppath=config['app.path'],
+        panname=config['name']
     shell:
         """
         apptainer run {params.apppath}/pytools.sif python scripts/statsAggregation.py \
-            --input {input} --output {output}
+            --input {input} --output {output} --panname {params.panname}
         """
 
 rule get_pav:
@@ -194,7 +188,7 @@ rule get_pav:
         "data/chrGraphs/graphsList.txt"
     output:
         directory("output/pav.matrices")
-    threads: 0.25 * workflow.cores
+    threads: 16
     params:
         apppath=config['app.path']
     run:
@@ -211,7 +205,7 @@ rule pggb_log_compression:
         flag="output/pan1c.pggb."+config['name']+".chromGraph.stats.tsv"
     output:
         tar="logs/pan1c.pggb."+config['name']+".logs.tar.gz",
-        chrLen="logs/chrInputLen.tsv"
+        chrLen="logs/pan1c.pggb."+config['name']+".chrInputLen.tsv"
     shell:
         """
         cd logs/pggb
@@ -229,18 +223,19 @@ rule pggb_log_compression:
         done
         """
 
-rule ressources_statistics:
+rule workflow_statistics:
     input:
         tar="logs/pan1c.pggb."+config['name']+".logs.tar.gz",
-        chrLen="logs/chrInputLen.tsv"
+        chrLen="logs/pan1c.pggb."+config['name']+".chrInputLen.tsv",
+        chrGraphStats="output/pan1c.pggb."+config['name']+".chromGraph.stats.tsv"
     output:
-        tsv="output/pan1c.pggb."+config['name']+".usage.stats.tsv",
+        tsv="output/pan1c.pggb."+config['name']+".stats.tsv",
         dir=directory("output/pggb.usage.figs")
     params:
         apppath=config['app.path']
     shell:
         """
         mkdir -p {output.dir}
-        apptainer run {params.apppath}/pytools.sif python scripts/usageStats.py \
-            -i {input.tar} -l {input.chrLen} -o {output.tsv} -f {output.dir}
+        apptainer run {params.apppath}/pytools.sif python scripts/workflowStats.py \
+            -i {input.tar} -l {input.chrLen} -g {input.chrGraphStats} -o {output.tsv} -f {output.dir}
         """
\ No newline at end of file
diff --git a/example/CICC1445.fa.gz b/example/CICC1445.fa.gz
new file mode 100644
index 0000000000000000000000000000000000000000..e527dff0ce6a530edf318b26fed6edee0025a5f6
Binary files /dev/null and b/example/CICC1445.fa.gz differ
diff --git a/example/R64.fa.gz b/example/R64.fa.gz
new file mode 100644
index 0000000000000000000000000000000000000000..11e4e68704043afddb9f15926d30a25e8e934b07
Binary files /dev/null and b/example/R64.fa.gz differ
diff --git a/example/SX2.fa.gz b/example/SX2.fa.gz
new file mode 100644
index 0000000000000000000000000000000000000000..e4dc314af7e623b1404c827b95a3c0ce4990085a
Binary files /dev/null and b/example/SX2.fa.gz differ
diff --git a/runSnakemake.sh b/runSnakemake.sh
index 6f7c9df9381d671f3ca1efd7f8d83125826778f8..d3dd88e0a93243bd33325c595f65a94d1bc7f53a 100755
--- a/runSnakemake.sh
+++ b/runSnakemake.sh
@@ -1,9 +1,8 @@
 #!/bin/bash
-#SBATCH -p unlimitq
 #SBATCH --cpus-per-task=32
 #SBATCH -o <log path>.log
 #SBATCH -J <jname>
-#SBATCH --mem=1T
+#SBATCH --mem=256G
 #SBATCH --mail-type=BEGIN,END,FAIL
 #SBATCH --mail-user=<mail>
 
@@ -14,4 +13,5 @@ module load devel/Miniconda/Miniconda3
 source ~/.bashrc
 mamba activate snakemake
 
+snakemake -c $(nproc) --dag | dot -Tsvg > workflow.svg
 snakemake -c $(nproc)
diff --git a/scripts/getPanachePAV.sh b/scripts/getPanachePAV.sh
old mode 100644
new mode 100755
index f5189662c61821f526bd1449910095fdfb9ad00a..676cfb199cf893b0f622c980eb440b5dde47ab79
--- a/scripts/getPanachePAV.sh
+++ b/scripts/getPanachePAV.sh
@@ -26,13 +26,16 @@ done
 chrname=$(basename ${gfa} .gfa)
 
 # Getting paths in chromosome graph
+echo "[getPanachePAV::odgi::paths] Running on ${gfa}"
 apptainer run --app odgi "${appdir}/PanGeTools.sif" paths -i ${gfa} -L > ${chrdir}/$chrname.paths.txt
 
 # Creating bed using odgi untangle
+echo "[getPanachePAV::odgi::untangle] Running on ${gfa}"
 apptainer run --app odgi "${appdir}/PanGeTools.sif" untangle -i ${gfa} -R ${chrdir}/$chrname.paths.txt -t $threads -P | sed '1d' | \
     cut -f 4,5,6 | sort | uniq > ${chrdir}/$chrname.untangle.multiref.bed
 
 # Running odgi pav
+echo "[getPanachePAV::odgi::pav] Running on ${gfa}"
 apptainer run --app odgi "${appdir}/PanGeTools.sif" pav -i ${gfa} -b ${chrdir}/$chrname.untangle.multiref.bed -M \
     -B 0.5 -t $threads -P > ${chrdir}/$chrname.untangle.multiref.pavs.matrix.tsv
 
diff --git a/scripts/ragtagChromInfer.sh b/scripts/ragtagChromInfer.sh
index bb529b6aaccc95b767e0b61bd31b754487e539ba..7721a181f79d19ec6a408817956613b6e8619c38 100755
--- a/scripts/ragtagChromInfer.sh
+++ b/scripts/ragtagChromInfer.sh
@@ -18,7 +18,7 @@ while getopts "d:a:t:r:q:o:" option; do
         r) inputref="$OPTARG";;
         q) inputquery="$OPTARG";;
         o) output="$OPTARG";;
-        \?) echo "Usage: $0 [-d tmpdir] [-a appdir] [-t threads] [-r inputref] [-q inputquery] [-o output]" >&2
+        \?) echo "Usage: $0 [-d tmpdir] [-a apptainer dir] [-t threads] [-r inputref] [-q inputquery] [-o output fasta] [-n pangenome name]" >&2
             exit 1;;
     esac
 done
diff --git a/scripts/statsAggregation.py b/scripts/statsAggregation.py
index c60fe940b0403609efcd22ba80fa383cacc21b19..c399b6dbc6b3882acfe17ca80dbe71a6c3b3529f 100644
--- a/scripts/statsAggregation.py
+++ b/scripts/statsAggregation.py
@@ -26,6 +26,13 @@ arg_parser.add_argument(
     required = True,
     help = "Output file"
     )
+arg_parser.add_argument(
+    "--panname",
+    "-p",
+    dest = "panname",
+    required = True,
+    help = "Pangenome name"
+    )
 args = arg_parser.parse_args()
 
 ## Main script
@@ -40,9 +47,9 @@ for file in [k for k in os.listdir(args.inputDir) if k[-3:] == "tsv"]:
     # Reading second line of the file and adding to line list
     with open(os.path.join(args.inputDir, file), 'r') as handle:
         _ = handle.readlines()
-        header = "chr\t"+_[0][:-1]
+        header = "pangenome.name\tchrom.id\t"+_[0][:-1]
         line = _[1][:-1]
-    lines.append(f"{filename}\t{line}")
+    lines.append(f"{args.panname}\t{filename}\t{line}")
 
 # Writting to the output
 with open(args.output, 'w') as handle:
diff --git a/scripts/usageStats.py b/scripts/workflowStats.py
similarity index 53%
rename from scripts/usageStats.py
rename to scripts/workflowStats.py
index d04d2034a5997dbeee21670838aaec0f5fb228cc..8426780be5756c324948afd22fa3b847cb299deb 100644
--- a/scripts/usageStats.py
+++ b/scripts/workflowStats.py
@@ -1,5 +1,5 @@
 """
-Usage statistics script for Pan1c workflow
+Workflow statistics script for Pan1c workflow.
 
 Given one or more tarball containing time logs of the pggb rule of the workflow, 
 the script returns an aggregated table as well as figures    
@@ -31,9 +31,18 @@ arg_parser.add_argument(
 arg_parser.add_argument(
     "--chrinputlen",
     "-l",
-    dest = "chrinputlen",
+    nargs = "+",
+    dest = "chrinputlenfiles",
     required = True,
-    help = "TSV containing input sequence length (generated by Pan1c workflow)"
+    help = "One or more TSV containing input sequence length (generated by Pan1c workflow)"
+    )
+arg_parser.add_argument(
+    "--graphstats",
+    "-g",
+    nargs = "+",
+    dest = "graphstatsfiles",
+    required = True,
+    help = "One or more TSV containing graphs statistics (generated by Pan1c workflow)"
     )
 arg_parser.add_argument(
     "--output",
@@ -67,10 +76,13 @@ def getRegEquation(x, y):
     return f'y = {slope:.2f}x + {intercept:.2f} (R2 : {r2:.2f})'
 
 ## Main script
-aggregatedData = {}
+aggregatedData = {} # Temporary data holder. Will be transformed into dataframe after having parsed every inputs
 
+#%% Parsing section
+## Parsing graph creation ressources for each pangenome.
 # Iterating through tarballs
 for tarball in args.tarballs:
+    panname = os.path.basename(tarball).split(".")[2] # Works if name is pan1c.pggb.<panname>.logs.tar.gz
 
     # Iterating in given tarball files
     with tarfile.open(tarball, "r") as tar :
@@ -99,60 +111,95 @@ for tarball in args.tarballs:
             except :
                 time = pd.to_timedelta(f"00:{time}")
 
-            if args.debug: print(f"[timeStats::debug] Chr: {chrid}\tTime: {time}\tCPU: {cpu}%\t memory: {memory}Gb")
+            if args.debug: print(f"[timeStats::debug] Pangenome Name: {panname}\tChr: {chrid}\tTime: {time}\tCPU: {cpu}%\t memory: {memory}Gb")
 
             # Adding to aggregatedData
-            aggregatedData[chrid] = {"time": time, "cpu": cpu, "mem": memory}
-
-# Reading chrInputLen to get number of bases used to construct chromosomes
-chrSeqLength = pd.read_csv(
-    args.chrinputlen,
-    sep="\t",
-    header=None,
-    index_col=0
-).to_dict()[1]
+            aggregatedData[(panname,chrid)] = {"time": time, "cpu": cpu, "mem": memory}
 
-if args.debug: print("[timeStats::debug]", chrSeqLength)
+## Parsing chromosome input file size (in #bases).
+# Iterating over input length files
+for chrInputLength in args.chrinputlenfiles:
 
-# Adding base counts to aggregatedData
-for chromName, chromLength in chrSeqLength.items():
-    aggregatedData[chromName]["mbases"] = chromLength/1000000
+    panname = os.path.basename(chrInputLength).split(".")[2] # Works if name is pan1c.pggb.<panname>.chrInputLen.tsv
     
-# Creating a dataframe
-df = pd.DataFrame(aggregatedData).transpose()
+    # Reading chrInputLen to get the number of bases used to construct chromosomes
+    chrSeqLength = pd.read_csv(
+        chrInputLength,
+        sep="\t",
+        header=None,
+        index_col=0
+    ).to_dict()[1]
+
+    if args.debug: print("[timeStats::debug]", chrSeqLength)
+
+    # Adding base counts to aggregatedData
+    for chromName, chromLength in chrSeqLength.items():
+        aggregatedData[(panname,chromName)]["nbases"] = chromLength
+
+## Parsing graph statistics generated by odgi stats
+graphColDict = {
+    "#length": "graph.length",
+    "nodes": "graph.nodes",
+    "edges": "graph.edges",
+    "paths": "graph.paths",
+    "steps": "graph.steps"
+}   
+
+# Iterating over graph stats files
+for graphStats in args.graphstatsfiles:  
+
+    # Reading graphStats to get graph general statistics
+    graphStatsdf = pd.read_csv(
+        graphStats,
+        sep="\t"
+    )
+
+    # Iterating over dataframe's rows
+    for index, row in graphStatsdf.iterrows():
+        for column in graphColDict.keys():
+            aggregatedData[(row["pangenome.name"], row["chrom.id"])][column] = row[column]
+        
+        # Computing mean degree
+        aggregatedData[(row["pangenome.name"], row["chrom.id"])]["graph.degree"] = row["edges"]/row["nodes"]
+
+# Creating a dataframe from aggregatedData
+df = pd.DataFrame.from_dict(aggregatedData, orient='index')
+df.reset_index(inplace=True)
+df.rename(columns={'level_0': 'pangenome.name', 'level_1': 'chrom.id'}, inplace=True)
+df.rename(columns=graphColDict, inplace = True)
 df.time = pd.to_timedelta(df.time)
 df.mem = df.mem.astype(float)
 df.cpu = df.cpu.astype(int)
-df.mbases = df.mbases.astype(int)
+df.nbases = df.nbases.astype(int)
 
 if args.debug: print("[timeStats::debug]", df.dtypes)
 
 # Saving the dataframe
-df.to_csv(args.output, sep='\t')
+df.to_csv(args.output, sep='\t', index=False)
 
 # Creating some figures
 # Time versus base count
-sns.regplot(x=df.mbases, y=df.time.dt.total_seconds(), line_kws={"color":"r","alpha":0.7,"lw":5})
-equation = getRegEquation(x=df.mbases, y=df.time.dt.total_seconds())
-plt.xlabel('Total input sequences length (Mb)')
+sns.regplot(x=df.nbases, y=df.time.dt.total_seconds(), line_kws={"color":"r","alpha":0.7,"lw":5})
+equation = getRegEquation(x=df.nbases, y=df.time.dt.total_seconds())
+plt.xlabel('Total input sequences length (#bases)')
 plt.ylabel('Graph creation time (s)')
 plt.annotate(equation, xy=(0.05, 0.95), xycoords='axes fraction', fontsize=12, color='red')
 plt.savefig(os.path.join(args.figdir,"TimeVSSeqLength.png"))
 plt.close()
 
 # Memory versus base count
-sns.regplot(x=df.mbases, y=df.mem, line_kws={"color":"r","alpha":0.7,"lw":5})
-equation = getRegEquation(x=df.mbases, y=df.mem)
-plt.xlabel('Total input sequences length (Mb)')
+sns.regplot(x=df.nbases, y=df.mem, line_kws={"color":"r","alpha":0.7,"lw":5})
+equation = getRegEquation(x=df.nbases, y=df.mem)
+plt.xlabel('Total input sequences length (#bases)')
 plt.ylabel('Peak memory usage (GB)')
 plt.annotate(equation, xy=(0.05, 0.95), xycoords='axes fraction', fontsize=12, color='red')
 plt.savefig(os.path.join(args.figdir,"MemoryVSSeqLength.png"))
 plt.close()
 
 # CPU versus base count
-sns.regplot(x=df.mbases, y=df.cpu, line_kws={"color":"r","alpha":0.7,"lw":5})
-equation = getRegEquation(x=df.mbases, y=df.cpu)
-plt.xlabel('Total input sequences length (Mb)')
+sns.regplot(x=df.nbases, y=df.cpu, line_kws={"color":"r","alpha":0.7,"lw":5})
+equation = getRegEquation(x=df.nbases, y=df.cpu)
+plt.xlabel('Total input sequences length (#bases)')
 plt.ylabel('CPU usage (%)')
 plt.annotate(equation, xy=(0.05, 0.95), xycoords='axes fraction', fontsize=12, color='red')
 plt.savefig(os.path.join(args.figdir,"CpuVSSeqLength.png"))