diff --git a/src/Lib/Script/CRTPLuaScriptObject.hh b/src/Lib/Script/CRTPLuaScriptObject.hh
index 623de553698c19946a57833b74b432ce2cb739de..4e0e86f5d9cc9845aad7c1602e98d560e465c340 100644
--- a/src/Lib/Script/CRTPLuaScriptObject.hh
+++ b/src/Lib/Script/CRTPLuaScriptObject.hh
@@ -227,6 +227,7 @@ script_class (JobDeclaration) {
 
     bool isImported{ false };
     int functionRegisterKey{ -1 };
+    JobIteratorType iterationType{ static_cast<JobIteratorType>(0) }; // Invalid by default
 
 public:
     std::string name{};
@@ -235,6 +236,7 @@ public:
 
     bool isLocalToModule() const noexcept;
     void pushLuaFunction(lua_State *const) const noexcept;
+    void getLuaFunctionFromStack(lua_State *const, const JobIteratorType) noexcept;
 };
 
 // Function declaration
@@ -264,6 +266,7 @@ public:
 
     bool isLocalToModule() const noexcept;
     void pushLuaFunction(lua_State *const) const noexcept;
+    void getLuaFunctionFromStack(lua_State *const) noexcept;
 };
 
 // Module declaration
@@ -304,9 +307,10 @@ script_class (ModuleDeclaration) {
     std::vector<std::string> importNames{};
     std::vector<const ModuleDeclaration *> importedModules{};
 
-    bool validateModule(lua_State *const) const noexcept;
-    int exportFunction(lua_State *const, const std::string_view) noexcept;
-    int exportJob(lua_State *const, const std::string_view, const std::string_view) noexcept;
+    void validateModule(lua_State *const) const noexcept;
+    int exportFunction(lua_State *const, const int tableIndex, const std::string_view) noexcept;
+    int exportJob(lua_State *const, const int tableIndex, const std::string_view,
+                  const std::string_view) noexcept;
 
 public:
     std::string moduleName{};
diff --git a/src/Lib/Script/CRTPLuaScriptObject/FunctionDeclaration.cc b/src/Lib/Script/CRTPLuaScriptObject/FunctionDeclaration.cc
index bc6c55bf8bc280c4aceb35abf629993dfb6252b9..82afe1daa0b10b2824dbd4b9b1fbda7588f9f371 100644
--- a/src/Lib/Script/CRTPLuaScriptObject/FunctionDeclaration.cc
+++ b/src/Lib/Script/CRTPLuaScriptObject/FunctionDeclaration.cc
@@ -62,3 +62,10 @@ FunctionDeclaration::isLocalToModule() const noexcept
 {
     return parentScript.size() == 0;
 }
+
+void
+FunctionDeclaration::getLuaFunctionFromStack(lua_State *const L) noexcept
+{
+    luaL_checktype(L, -1, LUA_TFUNCTION);
+    functionRegisterKey = luaL_ref(L, LUA_REGISTRYINDEX);
+}
diff --git a/src/Lib/Script/CRTPLuaScriptObject/JobDeclaration.cc b/src/Lib/Script/CRTPLuaScriptObject/JobDeclaration.cc
index 538d1cef564a9b3a7943eb44030f44576b299bd9..39c676d96f83d05072484122761ea0b91dc34d59 100644
--- a/src/Lib/Script/CRTPLuaScriptObject/JobDeclaration.cc
+++ b/src/Lib/Script/CRTPLuaScriptObject/JobDeclaration.cc
@@ -93,3 +93,11 @@ JobDeclaration::pushLuaFunction(lua_State *const L) const noexcept
 {
     [[maybe_unused]] bool ok = PushFunctionFromRegistry(L, functionRegisterKey);
 }
+
+void
+JobDeclaration::getLuaFunctionFromStack(lua_State *const L, const JobIteratorType itType) noexcept
+{
+    luaL_checktype(L, -1, LUA_TFUNCTION);
+    functionRegisterKey = luaL_ref(L, LUA_REGISTRYINDEX);
+    iterationType       = itType;
+}
diff --git a/src/Lib/Script/CRTPLuaScriptObject/ModuleDeclaration.cc b/src/Lib/Script/CRTPLuaScriptObject/ModuleDeclaration.cc
index de147455ce4b2439a21037dcea61e5ea26afe0e8..949de9c7f0ac5b38e497ba8a18b5e317f471e3f3 100644
--- a/src/Lib/Script/CRTPLuaScriptObject/ModuleDeclaration.cc
+++ b/src/Lib/Script/CRTPLuaScriptObject/ModuleDeclaration.cc
@@ -63,33 +63,40 @@ ModuleDeclaration::exportMethod(lua_State *const L) noexcept
 
     const lua_Unsigned len = lua_rawlen(L, 2);
     if (len == 2)
-        return self->exportFunction(L, objectName);
+        return self->exportFunction(L, 2, objectName);
 
     else if (len == 3) {
-        // Stack will be { top: int, string, table, self }
         lua_pushinteger(L, 2);
         lua_gettable(L, 2);
         const std::string_view jobItTypeStr = CHECK_STRING_VIEW(L, -1);
-        return self->exportJob(L, objectName, jobItTypeStr);
+        return self->exportJob(L, 2, objectName, jobItTypeStr);
     }
 
     LUA_RETURN_NOTHING(L);
 }
 
 int
-ModuleDeclaration::exportFunction(lua_State *const L, const std::string_view name) noexcept
+ModuleDeclaration::exportFunction(lua_State *const L, const int tableIndex,
+                                  const std::string_view name) noexcept
 {
-    auto *const context = LuaContext::getContext(L);
+    auto *const context             = LuaContext::getContext(L);
+    FunctionDeclaration *const func = context->getFunction(moduleName, name);
     out(context) << "Export function " << moduleName << "::" << name << '\n';
+
+    lua_pushinteger(L, 2);
+    lua_gettable(L, tableIndex);
+    func->getLuaFunctionFromStack(L);
+
     LUA_RETURN_NOTHING(L);
 }
 
 int
-ModuleDeclaration::exportJob(lua_State *const L, const std::string_view name,
+ModuleDeclaration::exportJob(lua_State *const L, const int tableIndex, const std::string_view name,
                              const std::string_view itTypeStr) noexcept
 {
     auto *const context             = LuaContext::getContext(L);
     const JobIteratorType jobItType = getJobIteratorTypeFromString(itTypeStr);
+    JobDeclaration *const job       = context->getJob(moduleName, name);
     if (jobItType != JobIteratorType::Line && jobItType != JobIteratorType::Syllabe) {
         char str[itTypeStr.length() + 1];
         std::memset(str, 0, sizeof(str));
@@ -99,6 +106,10 @@ ModuleDeclaration::exportJob(lua_State *const L, const std::string_view name,
 
     out(context) << "Export job " << moduleName << "::" << name << "{" << itTypeStr << "}\n";
 
+    lua_pushinteger(L, 3);
+    lua_gettable(L, tableIndex);
+    job->getLuaFunctionFromStack(L, jobItType);
+
     LUA_RETURN_NOTHING(L);
 }
 
diff --git a/utils/lua/simple.module b/utils/lua/simple.module
new file mode 100644
index 0000000000000000000000000000000000000000..2c963d7066d3bb8b4e038df6b52bac5ddfb9d27b
--- /dev/null
+++ b/utils/lua/simple.module
@@ -0,0 +1,48 @@
+--- Declaration
+
+local custom_opt = DeclareOption { option1 = false }
+local time_opt   = DeclareOption { preTime = -900, postTime = 300, }
+local color_opt  = DeclareOption { color1 = Vivy:newColor("#314159") }
+
+local module = DeclareModule {
+    name        = "sample-spec",
+    description = "Sample script used for the specification proposition",
+    author      = "Vivy",
+    revision    = "rev-1254",
+    options     = { custom_opt, time_opt, color_opt },
+    functions   = {
+        DeclareFunction { "tripleCopySyl" },
+        DeclareFunction { "printFoo" },
+    },
+    jobs = {
+        DeclareJob { "set_retime", options = { time_opt } },
+        DeclareJob { "demultiply_syllabes" },
+    }
+}
+
+--- Implementation
+
+local tripleCopySyl = module:export { "tripleCopySyl", function (syl)
+    return { syl:copy(), syl:copy(), syl:copy() }
+end }
+
+module:export { "printFoo", function () prettyPrint ("Bar") end }
+
+module:export { "retime_lines", LINE, function (opt, line)
+    line.start  = line.start + opt.preTime
+    line.finish = line.start + opt.postTime
+    if line.start  <= Vivy:start()  then line.start  = Vivy:start()  end
+    if line.finish >= Vivy:finish() then line.finish = Vivy:finish() end
+    return line
+end }
+
+module:export { "create_syllabes", SYLLABE, function (opt, syl)
+    local newSyls     = tripleCopySyl(syl)
+    newSyls[1].start  = syl.line.start
+    newSyls[1].finish = syl.start
+    newSyls[3].finish = syl.line.finish
+    newSyls[3].start  = syl.finish
+    return newSyls
+end }
+
+-- vim: ft=lua