diff --git a/src/Rust/vvs_cli/src/main.rs b/src/Rust/vvs_cli/src/main.rs
index a47c618a58fb7789c7ef48db9d21f9e0164b1bfd..5c723d6b164f2a26e881aa98dba1c9bbb34febc2 100644
--- a/src/Rust/vvs_cli/src/main.rs
+++ b/src/Rust/vvs_cli/src/main.rs
@@ -10,6 +10,7 @@ use vvs_cli::{
     config::{Config, ConfigFile},
 };
 use vvs_lang::*;
+use vvs_runtime::Runtime;
 use vvs_xdg::{file::TempFile, XDGConfig, XDGConfigMergedSilent};
 
 fn print_font(n: impl AsRef<Path>, f: &[u8]) -> Result<()> {
@@ -79,19 +80,15 @@ fn main() -> Result<()> {
     }
 
     let mut file = TempFile::new("vvcc")?;
-    let jit = vvs_runtime::JIT::new()?;
-    jit.with_module(
-        vvs_codegen::lowerer::Lowerer::new(&jit.ctx(), &output.main.name)?
+    Runtime::new(move |ctx| {
+        Ok(vvs_codegen::lowerer::Lowerer::new(&ctx, &output.main.name)?
             .declare_globals(output.declared_functions())?
             .lower_module(&output.main.name, output.ast)?
             .lower_modules(output.imports)?
             .generate_main(output.main)?
-            .finished(),
-    )?
-    .run_on_file(
-        vvs_ass::ass_container_from_file(ass_file.context("no subtitle file to run the script on")?)
-            .context("failed to parse the subtitle file")?,
-    )?
+            .finished())
+    })?
+    .run_on_file(ass_file.context("no subtitle file to run the script on")?)?
     .write_ass_to_file(&mut file)?;
 
     println!("output file ........ {}", file.leak().path().display());
diff --git a/src/Rust/vvs_codegen/src/lowerer/mod.rs b/src/Rust/vvs_codegen/src/lowerer/mod.rs
index 35e8475d2ca17c130f0c66b1368745d2e26347e4..a929f1209f604d8f530e46803ae0b98e621bc05a 100644
--- a/src/Rust/vvs_codegen/src/lowerer/mod.rs
+++ b/src/Rust/vvs_codegen/src/lowerer/mod.rs
@@ -13,7 +13,7 @@ where
     'ctx: 'this,
 {
     context: &'this Context<'ctx>,
-    module: Module<'this>,
+    module: Module<'ctx>,
 }
 
 impl<'ctx, 'this> Lowerer<'ctx, 'this>
@@ -22,8 +22,7 @@ where
 {
     /// Create a new lowerer. We will lower things into a module.
     pub fn new(context: &'this Context<'ctx>, module: impl AsRef<str>) -> Result<Self, CodegenError> {
-        let _ = vvs_llvm::init::initialize_llvm();
-        Ok(Self { context, module: context.create_module(module.as_ref()).map_err(CodegenError::NulError)? })
+        Ok(Self { context, module: Module::new(context, module.as_ref()).map_err(CodegenError::NulError)? })
     }
 
     pub fn declare_globals<'a>(
@@ -86,7 +85,7 @@ where
     }
 
     /// Finished the lowering process and get the module out of the builder.
-    pub fn finished(self) -> Module<'this> {
+    pub fn finished(self) -> Module<'ctx> {
         self.module
     }
 }
diff --git a/src/Rust/vvs_llvm/src/bindings/basic_block.rs b/src/Rust/vvs_llvm/src/bindings/basic_block.rs
index ed65e7b118d7569f89f0aa9c7cb589589d9471a9..c42d116f290e64c6d052b8c3d7f44ed620c75838 100644
--- a/src/Rust/vvs_llvm/src/bindings/basic_block.rs
+++ b/src/Rust/vvs_llvm/src/bindings/basic_block.rs
@@ -2,7 +2,9 @@ use crate::prelude::*;
 use llvm_sys::{core::*, prelude::*};
 
 crate::bindings::declare! { const LLVMBasicBlockRef as BB<'a>    }
-crate::bindings::declare! { mut   LLVMBasicBlockRef as BBMut<'a> }
+crate::bindings::declare! { mut   LLVMBasicBlockRef as BBMut<'a> {
+    const_ref: BB<'a>,
+} }
 
 /// Share code between the [BB::terminator] and [BB::terminator_mut]
 macro_rules! get_terminator {
@@ -27,7 +29,7 @@ macro_rules! get_terminator {
 impl<'a> BBMut<'a> {
     /// Get a const reference to the basic block.
     pub fn into_ref(self) -> BB<'a> {
-        todo!()
+        unsafe { BB::from_ptr(self.as_ptr()) }
     }
 
     /// Get the terminator in a mutable way of the basic block if it exists.
@@ -36,12 +38,17 @@ impl<'a> BBMut<'a> {
     }
 
     /// Iterate over the instructions of a basic block in a mutable way.
-    pub fn iter_mut(&'a mut self) -> BBIter<'a, &'a mut BBMut<'a>> {
+    pub fn iter_mut(&'a mut self) -> BBIterMut<'a, &'a mut BBMut<'a>> {
         match self.as_ref().is_empty() {
-            true => BBIter { curr: None, last: None, bb: self },
+            true => BBIterMut { curr: None, last: None, bb: self },
             false => todo!(),
         }
     }
+
+    /// Create a new [BBMut] from the pointer.
+    pub(crate) unsafe fn new(ptr: LLVMBasicBlockRef) -> Self {
+        unsafe { Self::from_ptr(ptr, BB::from_ptr(ptr)) }
+    }
 }
 
 impl<'a> BB<'a> {
@@ -67,11 +74,34 @@ impl<'a> BB<'a> {
             false => todo!(),
         }
     }
+
+    /// Create a new [BB] from the pointer.
+    pub(crate) unsafe fn new(ptr: LLVMBasicBlockRef) -> Self {
+        unsafe { Self::from_ptr(ptr) }
+    }
 }
 
 impl<'a> AsRef<BB<'a>> for BBMut<'a> {
     fn as_ref(&self) -> &BB<'a> {
-        todo!()
+        &self.const_ref
+    }
+}
+
+impl<'a> AsRef<BB<'a>> for &'a BB<'a> {
+    fn as_ref(&self) -> &BB<'a> {
+        self
+    }
+}
+
+impl<'a> AsRef<BB<'a>> for &'a mut BB<'a> {
+    fn as_ref(&self) -> &BB<'a> {
+        self
+    }
+}
+
+impl<'a> AsMut<BBMut<'a>> for &'a mut BBMut<'a> {
+    fn as_mut(&mut self) -> &mut BBMut<'a> {
+        self
     }
 }
 
@@ -91,33 +121,13 @@ impl PartialEq for BBMut<'_> {
 
 mod sealed {
     pub trait BBRef<'a>: AsRef<super::BB<'a>> {}
-    pub trait BBMutRef<'a>: AsMut<super::BBMut<'a>> + BBRef<'a> {}
+    pub trait BBMutRef<'a>: AsMut<super::BBMut<'a>> + AsRef<super::BB<'a>> {}
 }
 
 impl<'a> sealed::BBRef<'a> for &'a BB<'a> {}
 impl<'a> sealed::BBRef<'a> for &'a mut BB<'a> {}
-impl<'a> sealed::BBRef<'a> for &'a BBMut<'a> {}
-impl<'a> sealed::BBRef<'a> for &'a mut BBMut<'a> {}
 impl<'a> sealed::BBMutRef<'a> for &'a mut BBMut<'a> {}
 
-impl<'a> AsRef<BB<'a>> for &'a BB<'a> {
-    fn as_ref(&self) -> &BB<'a> {
-        self
-    }
-}
-
-impl<'a> AsRef<BB<'a>> for &'a mut BB<'a> {
-    fn as_ref(&self) -> &BB<'a> {
-        self
-    }
-}
-
-impl<'a> AsMut<BBMut<'a>> for &'a mut BBMut<'a> {
-    fn as_mut(&mut self) -> &mut BBMut<'a> {
-        todo!()
-    }
-}
-
 /// Iterate over the instructions in a basic block.
 pub struct BBIter<'a, B: sealed::BBRef<'a>> {
     curr: Option<Value<'a>>,
@@ -161,7 +171,7 @@ impl<'a, B: sealed::BBRef<'a>> Iterator for BBIter<'a, B> {
     }
 
     fn count(self) -> usize {
-        self.bb.as_ref().len()
+        self.size_hint().0
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
@@ -182,7 +192,7 @@ impl<'a, B: sealed::BBMutRef<'a>> Iterator for BBIterMut<'a, B> {
     }
 
     fn count(self) -> usize {
-        self.bb.as_ref().len()
+        self.size_hint().0
     }
 
     fn size_hint(&self) -> (usize, Option<usize>) {
diff --git a/src/Rust/vvs_llvm/src/bindings/builder.rs b/src/Rust/vvs_llvm/src/bindings/builder.rs
index 74ee630fd399f64a8359bb97eaa0a6e697df683a..37d4823281195720e20ca5023a41555dce9e64b7 100644
--- a/src/Rust/vvs_llvm/src/bindings/builder.rs
+++ b/src/Rust/vvs_llvm/src/bindings/builder.rs
@@ -18,6 +18,11 @@ macro_rules! build {
 }
 
 impl<'a> Builder<'a> {
+    /// Create a new builder.
+    pub fn new(ctx: &Context) -> Self {
+        unsafe { Self::from_ptr(LLVMCreateBuilderInContext(ctx.as_ptr())) }
+    }
+
     /// Position the builder at the end of a basic block.
     pub fn position_at_end(&mut self, bb: &mut BBMut) -> &mut Self {
         unsafe { LLVMPositionBuilderAtEnd(self.as_ptr(), bb.as_ptr()) };
diff --git a/src/Rust/vvs_llvm/src/bindings/context.rs b/src/Rust/vvs_llvm/src/bindings/context.rs
index a9aadfcf3a450e012ee4f66df7050f525435cde8..0beb8e7833031ec73d61529692ca9281ec3a2500 100644
--- a/src/Rust/vvs_llvm/src/bindings/context.rs
+++ b/src/Rust/vvs_llvm/src/bindings/context.rs
@@ -1,9 +1,6 @@
 use crate::prelude::*;
 use llvm_sys::{core::*, prelude::*};
-use std::{
-    ffi::{CString, NulError},
-    marker,
-};
+use std::marker;
 
 crate::bindings::declare! { mut LLVMContextRef as Context<'a> {
     borrowed: bool,
@@ -37,17 +34,6 @@ impl Context<'_> {
         Self { inner: unsafe { LLVMContextCreate() }, borrowed: false, marker: marker::PhantomData }
     }
 
-    /// Create a new builder for this context.
-    pub fn create_builder(&self) -> Builder {
-        unsafe { Builder::from_ptr(LLVMCreateBuilderInContext(self.inner)) }
-    }
-
-    /// Create a new module in this context.
-    pub fn create_module(&self, name: impl AsRef<str>) -> Result<Module, NulError> {
-        let name = CString::new(name.as_ref())?;
-        Ok(unsafe { Module::from_ptr(LLVMModuleCreateWithName(name.as_ptr())) })
-    }
-
     /// Get the pointer type. We always use the address space 0 for now, we will see latter if we
     /// need different address spaces.
     pub fn type_ptr(&self) -> Type {
diff --git a/src/Rust/vvs_llvm/src/bindings/function.rs b/src/Rust/vvs_llvm/src/bindings/function.rs
index fd79b262922d522e7eda6450ea22212cd599e1da..e945babdcad3f75827f67516d4270fe5a5a92160 100644
--- a/src/Rust/vvs_llvm/src/bindings/function.rs
+++ b/src/Rust/vvs_llvm/src/bindings/function.rs
@@ -23,7 +23,7 @@ impl<'a> FunctionDeclaration<'a> {
 impl<'a> FunctionBuilder<'a> {
     /// Get the associated declaration.
     pub fn declaration(&self) -> FunctionDeclaration {
-        todo!()
+        unsafe { FunctionDeclaration::from_ptr(self.as_ptr()) }
     }
 
     /// Set the [LLVMLinkage] and [LLVMVisibility] accordingly.
@@ -61,7 +61,7 @@ impl<'a> FunctionBuilder<'a> {
 impl<'a> Function<'a> {
     /// Get the associated declaration.
     pub fn declaration(&self) -> FunctionDeclaration {
-        todo!()
+        unsafe { FunctionDeclaration::from_ptr(self.as_ptr()) }
     }
 
     /// Get the entry point of the function.
@@ -92,8 +92,8 @@ impl<'a> Function<'a> {
             match LLVMCountBasicBlocks(self.as_ptr()) {
                 0 => FunctionIter { curr: None, last: None, func: self },
                 _ => FunctionIter {
-                    curr: Some(BB::from_ptr(LLVMGetFirstBasicBlock(self.inner))),
-                    last: Some(BB::from_ptr(LLVMGetLastBasicBlock(self.inner))),
+                    curr: Some(BB::new(LLVMGetFirstBasicBlock(self.inner))),
+                    last: Some(BB::new(LLVMGetLastBasicBlock(self.inner))),
                     func: self,
                 },
             }
@@ -106,8 +106,8 @@ impl<'a> Function<'a> {
             match LLVMCountBasicBlocks(self.as_ptr()) {
                 0 => FunctionIterMut { curr: None, last: None, func: self },
                 _ => FunctionIterMut {
-                    curr: Some(BBMut::from_ptr(LLVMGetFirstBasicBlock(self.inner))),
-                    last: Some(BBMut::from_ptr(LLVMGetLastBasicBlock(self.inner))),
+                    curr: Some(BBMut::new(LLVMGetFirstBasicBlock(self.inner))),
+                    last: Some(BBMut::new(LLVMGetLastBasicBlock(self.inner))),
                     func: self,
                 },
             }
@@ -158,7 +158,7 @@ macro_rules! next {
                 Some(curr)
             }
             (Some(curr), Some(_)) => unsafe {
-                $self.curr = Some($bb::from_ptr(LLVMGetNextBasicBlock(curr.as_ptr())));
+                $self.curr = Some($bb::new(LLVMGetNextBasicBlock(curr.as_ptr())));
                 Some(curr)
             },
         }
diff --git a/src/Rust/vvs_runtime/src/jit.rs b/src/Rust/vvs_llvm/src/bindings/jit.rs
similarity index 56%
rename from src/Rust/vvs_runtime/src/jit.rs
rename to src/Rust/vvs_llvm/src/bindings/jit.rs
index e238daedc159c12f672207225cc23c33a0c28fe4..29506a042593d580a6dd94b65430683290c0796e 100644
--- a/src/Rust/vvs_runtime/src/jit.rs
+++ b/src/Rust/vvs_llvm/src/bindings/jit.rs
@@ -1,19 +1,15 @@
-use crate::workers::Workers;
+use crate::prelude::{Context, Module};
 use anyhow::{bail, Context as _};
+use llvm_sys::{
+    error::*,
+    orc2::{ee::*, lljit::*, *},
+};
 use std::{
     ffi::{c_int, c_void, CStr, CString},
     ptr,
-    sync::{
-        atomic::{AtomicU64, Ordering},
-        Arc,
-    },
-    thread,
 };
-use vvs_ass::ASSContainer;
-use vvs_llvm::prelude::{Context, Module};
-use vvs_llvm::sys::*;
-use vvs_runtime_types::{types::VVRTTable, VVRTSymbol};
 
+/// Create a JIT engine.
 #[allow(dead_code)]
 pub struct JIT {
     jit: *mut LLVMOrcOpaqueLLJIT,
@@ -24,8 +20,6 @@ pub struct JIT {
     irtl: *mut LLVMOrcOpaqueIRTransformLayer,
     objl: *mut LLVMOrcOpaqueObjectLayer,
     dylib: *mut LLVMOrcOpaqueJITDylib,
-
-    workers: Workers,
 }
 
 macro_rules! llvm_expect {
@@ -45,17 +39,6 @@ macro_rules! llvm_expect {
     }};
 }
 
-/// This function should be visible because it starts with `VVRT`
-#[allow(non_snake_case)]
-pub extern "C" fn VVRTHelloWorld() {
-    println!("Hello World from LLVM JIT");
-}
-
-/// This function should not be visible because it doesn't start with `VVRT`
-pub extern "C" fn hello_world() {
-    println!("wtf !?");
-}
-
 extern "C" fn orc_sym_filter(_: *mut c_void, sym: LLVMOrcSymbolStringPoolEntryRef) -> c_int {
     eprintln!("toto");
     let Ok(sym) = unsafe { CStr::from_ptr(LLVMOrcSymbolStringPoolEntryStr(sym)) }.to_str() else {
@@ -67,8 +50,13 @@ extern "C" fn orc_sym_filter(_: *mut c_void, sym: LLVMOrcSymbolStringPoolEntryRe
 
 impl JIT {
     /// Create a new JIT thingy to execute Vivy Script code.
-    pub fn new() -> anyhow::Result<JIT> {
-        let _ = vvs_llvm::init::initialize_llvm();
+    fn new() -> anyhow::Result<JIT> {
+        if let Err(err) = crate::init::initialize_llvm() {
+            // Should fail only on re-init. If a real problem occured, we would have already
+            // aborted the program.
+            log::debug!("{err}");
+        }
+
         unsafe {
             // Create the jit.
             let mut jit = ptr::null_mut();
@@ -94,55 +82,34 @@ impl JIT {
             );
             LLVMOrcJITDylibAddGenerator(dylib, dg);
 
-            // Ok. Create workers and return the struct.
-            let tsctx = LLVMOrcCreateNewThreadSafeContext();
-            let workers = Workers::new(|flag: Arc<AtomicU64>| loop {
-                match flag.load(Ordering::SeqCst) {
-                    0 => thread::yield_now(),
-                    u64::MAX => return Ok(()),
-                    x => bail!("won't handle work package n°{x}"),
-                }
-            })?;
-            Ok(JIT { jit, es, dylib, tsctx, irtl, objl, workers })
+            // Ok.
+            Ok(JIT { jit, es, dylib, tsctx: LLVMOrcCreateNewThreadSafeContext(), irtl, objl })
         }
     }
 
-    /// Get the context out of the JIT thingy. Used to create a LLVM module to be used latter by
-    /// the JIT.
-    pub fn ctx(&self) -> Context {
-        unsafe { Context::from_ptr(LLVMOrcThreadSafeContextGetContext(self.tsctx), true) }
-    }
-
-    /// Add a new module to the JIT engine.
-    pub fn with_module(&self, module: Module) -> anyhow::Result<&Self> {
-        log::debug!("add module `{}` to jit engine", module.name());
-        let tsm = unsafe { LLVMOrcCreateNewThreadSafeModule(module.as_ptr(), self.tsctx) };
-        let rc = unsafe { LLVMOrcLLJITAddLLVMIRModule(self.jit, self.dylib, tsm) };
+    /// Initialize a jot with a module, that must be created from the passed context.
+    pub fn init<'a>(cb: impl FnOnce(Context<'a>) -> anyhow::Result<Module<'a>>) -> anyhow::Result<Self> {
+        let jit = JIT::new()?;
+        let module = unsafe { cb(Context::from_ptr(LLVMOrcThreadSafeContextGetContext(jit.tsctx), true))?.into_ptr() };
+        let tsm = unsafe { LLVMOrcCreateNewThreadSafeModule(module, jit.tsctx) };
+        let rc = unsafe { LLVMOrcLLJITAddLLVMIRModule(jit.jit, jit.dylib, tsm) };
         unsafe { llvm_expect!(rc, "failed to add the module into the jit") };
-        Ok(self)
+        Ok(jit)
     }
 
     /// LookUp a symbol defined in the JIT.
-    pub fn lookup<'a>(&self, name: &'a str) -> anyhow::Result<VVRTSymbol<'a>> {
+    pub fn lookup(&self, symbol: &str) -> anyhow::Result<*const u8> {
         let mut addr = Default::default();
-        let symbol = VVRTSymbol::try_from(name)?;
-        let str = CString::new(name).with_context(|| "CString::new failed")?;
         llvm_expect!(unsafe
-            LLVMOrcLLJITLookup(self.jit, &mut addr, str.as_ptr()),
-            "failed to lookup symbol `{name}`"
+            LLVMOrcLLJITLookup(self.jit, &mut addr, CString::new(symbol).with_context(|| "CString::new failed")?.as_ptr()),
+            "failed to lookup symbol `{symbol}`"
         );
-        Ok(symbol.with_addr(addr))
-    }
-
-    /// Run the program on an ass file.
-    pub fn run_on_file(&self, ass: ASSContainer<VVRTTable>) -> anyhow::Result<ASSContainer<VVRTTable>> {
-        unimplemented!("use the ASS container and insert it into the JIT: {ass:#?}")
+        Ok(addr as *const u8)
     }
 }
 
 impl Drop for JIT {
     fn drop(&mut self) {
-        self.workers.pre_drop();
         unsafe {
             LLVMOrcDisposeThreadSafeContext(self.tsctx);
             LLVMOrcDisposeLLJIT(self.jit);
diff --git a/src/Rust/vvs_llvm/src/bindings/mod.rs b/src/Rust/vvs_llvm/src/bindings/mod.rs
index a2e71ed63ca2454fd9e8bf774c38871a484ec943..830e44f524809682a2b81976d4bd72a9da2c55f9 100644
--- a/src/Rust/vvs_llvm/src/bindings/mod.rs
+++ b/src/Rust/vvs_llvm/src/bindings/mod.rs
@@ -6,6 +6,7 @@ pub mod basic_block;
 pub mod builder;
 pub mod context;
 pub mod function;
+pub mod jit;
 pub mod module;
 pub mod types;
 pub mod value;
@@ -26,8 +27,7 @@ macro_rules! declare {
             /// Create a new instance from a pointer.
             ///
             /// # Safety
-            /// Must be used from functions of the [crate::bindings::context::Context] to be sure that the
-            /// usage is correct...
+            /// Be sure that the usage is correct... You could mess up internal invariants here...
             pub unsafe fn from_ptr(inner: $llvm $($(, $field: $ty)*)?) -> Self {
                 Self {
                     inner $($(, $field)*)?,
@@ -35,7 +35,9 @@ macro_rules! declare {
                 }
             }
 
-            /// Get the inner pointer.
+            /// Get the inner pointer. Be aware that you are borrowing the pointer and thus not
+            /// responsible from freeing it. If it exists, you can use the [Self::into_ptr]
+            /// function to take the ownership out of this wrapper.
             pub fn as_ptr(&self) -> $llvm {
                 self.inner
             }
diff --git a/src/Rust/vvs_llvm/src/bindings/module.rs b/src/Rust/vvs_llvm/src/bindings/module.rs
index 2e5b98283c437d65770832d40e34a0210e1255b3..8c44ccf44be9c64221e720612a0920054d45e535 100644
--- a/src/Rust/vvs_llvm/src/bindings/module.rs
+++ b/src/Rust/vvs_llvm/src/bindings/module.rs
@@ -2,9 +2,21 @@ use crate::prelude::*;
 use llvm_sys::{core::*, prelude::*, LLVMLinkage, LLVMVisibility};
 use std::ffi::{CString, NulError};
 
-crate::bindings::declare! { mut LLVMModuleRef as Module<'a> }
+crate::bindings::declare! { mut LLVMModuleRef as Module<'a> {
+    is_borrowed: bool,
+} }
+
+impl<'a> Module<'a> {
+    /// Create a new module.
+    pub fn new(ctx: &Context<'a>, name: impl AsRef<str>) -> Result<Self, NulError> {
+        unsafe {
+            Ok(Module::from_ptr(
+                LLVMModuleCreateWithNameInContext(CString::new(name.as_ref())?.as_ptr(), ctx.as_ptr()),
+                false,
+            ))
+        }
+    }
 
-impl Module<'_> {
     /// Add a new function in this module.
     ///
     /// Note that by default all functions are private.
@@ -37,10 +49,20 @@ impl Module<'_> {
         })
         .expect("valid utf8 module name")
     }
+
+    /// Get out the pointer out of the struct, the caller is now responsible of managing the
+    /// lifetime of the returned pointer.
+    #[must_use]
+    pub(super) unsafe fn into_ptr(mut self) -> LLVMModuleRef {
+        self.is_borrowed = true;
+        self.inner
+    }
 }
 
 impl Drop for Module<'_> {
     fn drop(&mut self) {
-        unsafe { LLVMDisposeModule(self.inner) }
+        if !self.is_borrowed {
+            unsafe { LLVMDisposeModule(self.inner) }
+        }
     }
 }
diff --git a/src/Rust/vvs_llvm/src/lib.rs b/src/Rust/vvs_llvm/src/lib.rs
index bcedcae927e6e12c0e0bff3aadc5dcfbd889897d..34c4d538697eaa7764b5a6669cc5daa1808b8dd6 100644
--- a/src/Rust/vvs_llvm/src/lib.rs
+++ b/src/Rust/vvs_llvm/src/lib.rs
@@ -18,7 +18,8 @@ pub mod sys {
 #[cfg(feature = "bindings")]
 pub mod prelude {
     pub use crate::bindings::{
-        basic_block::*, builder::*, context::*, function::*, module::*, types::*, value::*, Error as LLVMError,
+        basic_block::*, builder::*, context::*, function::*, jit::JIT, module::*, types::*, value::*,
+        Error as LLVMError,
     };
 }
 
diff --git a/src/Rust/vvs_runtime/src/lib.rs b/src/Rust/vvs_runtime/src/lib.rs
index 4eb83d6c59bb490ee381fbdd0305f3bf5a72c620..9137c64df2addebbf76c8b0fa2ccd84006798250 100644
--- a/src/Rust/vvs_runtime/src/lib.rs
+++ b/src/Rust/vvs_runtime/src/lib.rs
@@ -1,6 +1,7 @@
-mod jit;
+mod runtime;
 mod workers;
 
+pub use runtime::Runtime;
+
 // Re-exports
-pub use crate::jit::*;
 pub use vvs_runtime_types::types;
diff --git a/src/Rust/vvs_runtime/src/runtime.rs b/src/Rust/vvs_runtime/src/runtime.rs
new file mode 100644
index 0000000000000000000000000000000000000000..3eb25e53ab62ef56d3b6baa27a710b8aacbbf49b
--- /dev/null
+++ b/src/Rust/vvs_runtime/src/runtime.rs
@@ -0,0 +1,44 @@
+use crate::workers::Workers;
+use anyhow::{bail, Context as _};
+use std::{
+    path::Path,
+    sync::{
+        atomic::{AtomicU64, Ordering},
+        Arc,
+    },
+    thread,
+};
+use vvs_ass::{ass_container_from_file, ASSContainer};
+use vvs_llvm::prelude::*;
+use vvs_runtime_types::types::VVRTTable;
+
+#[allow(dead_code)]
+pub struct Runtime {
+    jit: JIT,
+    workers: Workers,
+}
+
+impl Runtime {
+    pub fn new<'a>(init: impl FnOnce(Context<'a>) -> anyhow::Result<Module<'a>>) -> anyhow::Result<Self> {
+        Ok(Self {
+            jit: JIT::init(init)?,
+            workers: Workers::new(|flag: Arc<AtomicU64>| loop {
+                match flag.load(Ordering::SeqCst) {
+                    0 => thread::yield_now(),
+                    u64::MAX => return Ok(()),
+                    x => bail!("won't handle work package n°{x}"),
+                }
+            })?,
+        })
+    }
+
+    pub fn run_on_container(self, ass: ASSContainer<VVRTTable>) -> anyhow::Result<ASSContainer<VVRTTable>> {
+        todo!("run on {ass:?}")
+    }
+
+    pub fn run_on_file(self, file: impl AsRef<Path>) -> anyhow::Result<ASSContainer<VVRTTable>> {
+        self.run_on_container(
+            ass_container_from_file::<VVRTTable>(file.as_ref()).context("failed to parse the subtitle file")?,
+        )
+    }
+}
diff --git a/src/Rust/vvs_runtime/src/workers.rs b/src/Rust/vvs_runtime/src/workers.rs
index 9c69cad1ffc5327b75d15e8b5c7c5141c8959d62..9cc00a4fa837f629d23b38e4f9cf817422052010 100644
--- a/src/Rust/vvs_runtime/src/workers.rs
+++ b/src/Rust/vvs_runtime/src/workers.rs
@@ -94,8 +94,10 @@ impl Workers {
     /// Pre-drop all the threads and cancel the work to do.
     pub fn pre_drop(&mut self) {
         let handles = std::mem::take(&mut self.handles);
-        cancel_threads(handles.iter().map(|(_, rc)| rc.clone()));
-        join_handles(handles.into_iter().map(|(hdl, _)| hdl));
+        if !handles.is_empty() {
+            cancel_threads(handles.iter().map(|(_, rc)| rc.clone()));
+            join_handles(handles.into_iter().map(|(hdl, _)| hdl));
+        }
     }
 }