diff --git a/Cargo.lock b/Cargo.lock
index 894aafdb1ab35ed6fd3c905568ec9749d947f39f..9366642865089914ba331c8647ed52b2155c9f0c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -366,6 +366,7 @@ dependencies = [
  "log",
  "paste",
  "serde",
+ "thiserror",
 ]
 
 [[package]]
diff --git a/grimoire_engine_types/Cargo.toml b/grimoire_engine_types/Cargo.toml
index 637d58e0800bb08cda725282b4b41883f6b5f715..a7c6bce469c0ed65c650ee008191659a8b30ca13 100644
--- a/grimoire_engine_types/Cargo.toml
+++ b/grimoire_engine_types/Cargo.toml
@@ -15,3 +15,4 @@ paste.workspace       = true
 serde.workspace       = true
 hashbrown.workspace   = true
 log.workspace         = true
+thiserror.workspace   = true
diff --git a/grimoire_engine_types/src/error.rs b/grimoire_engine_types/src/error.rs
new file mode 100644
index 0000000000000000000000000000000000000000..482b1706099d59407254425bcf211b15de40f615
--- /dev/null
+++ b/grimoire_engine_types/src/error.rs
@@ -0,0 +1,2 @@
+#[derive(Debug, thiserror::Error)]
+pub enum SpellError {}
diff --git a/grimoire_engine_types/src/lib.rs b/grimoire_engine_types/src/lib.rs
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..46bc08dfe30f0d9858f04de2a36dc136db55a584 100644
--- a/grimoire_engine_types/src/lib.rs
+++ b/grimoire_engine_types/src/lib.rs
@@ -0,0 +1,3 @@
+pub mod spell;
+pub mod state;
+pub mod error;
diff --git a/grimoire_engine_types/src/spell.rs b/grimoire_engine_types/src/spell.rs
new file mode 100644
index 0000000000000000000000000000000000000000..8db3e85ab9ed0d14d4120cdc82ab5007662e2f25
--- /dev/null
+++ b/grimoire_engine_types/src/spell.rs
@@ -0,0 +1,54 @@
+use crate::{error::SpellError, state::State};
+
+pub trait Spell {
+    fn cast(&self, state: State) -> Result<State, SpellError>;
+
+    fn uncast(&self, state: State) -> Result<State, SpellError>;
+}
+
+pub struct SpellArguments {}
+
+pub trait BuildableSpell: Spell + TryFrom<SpellArguments, Error = SpellError> {
+    fn name() -> &'static str;
+
+    fn aliases() -> &'static [&'static str] {
+        &[]
+    }
+
+    fn name_list() -> impl Iterator<Item = &'static str> {
+        [Self::name()]
+            .into_iter()
+            .chain(Self::aliases().iter().copied())
+    }
+
+    fn create(arguments: SpellArguments) -> Result<Box<dyn Spell>, SpellError>;
+}
+
+type SpellBuilderFunction = fn(SpellArguments) -> Result<Box<dyn Spell>, SpellError>;
+
+#[derive(Debug, Default)]
+pub struct SpellFactory {
+    dispatch: hashbrown::HashMap<&'static str, SpellBuilderFunction>,
+}
+
+impl SpellFactory {
+    pub fn register<Spell: BuildableSpell + 'static>(&mut self) -> Result<(), SpellError> {
+        Spell::name_list()
+            .find(|spell_name| self.dispatch.contains_key(spell_name))
+            .map(|_name| -> Result<(), SpellError> { todo!("error") })
+            .unwrap_or(Ok(()))?;
+
+        Spell::name_list().for_each(|name| _ = self.dispatch.insert(name, Spell::create));
+
+        Ok(())
+    }
+
+    pub fn try_build_spell(
+        &self,
+        name: &str,
+        arguments: SpellArguments,
+    ) -> Result<Box<dyn Spell>, SpellError> {
+        let builder_function = self.dispatch.get(name).ok_or_else(|| todo!("error"))?;
+        builder_function(arguments)
+    }
+}
diff --git a/grimoire_engine_types/src/state.rs b/grimoire_engine_types/src/state.rs
new file mode 100644
index 0000000000000000000000000000000000000000..815e4be480ea4e1d739caa5873ebe2b950287fee
--- /dev/null
+++ b/grimoire_engine_types/src/state.rs
@@ -0,0 +1,2 @@
+pub struct State {
+}