diff --git a/grimoire/src/spell/factory.rs b/grimoire/src/spell/factory.rs
index 84c128132ed1de1484f986dfe03e587be1d1781d..53dffa866ba7e3aab27d9d3a6baa6c52e6afec5e 100644
--- a/grimoire/src/spell/factory.rs
+++ b/grimoire/src/spell/factory.rs
@@ -8,12 +8,23 @@ use std::collections::HashMap;
 pub type SpellBuilderFunction = fn(SpellArguments) -> Result<Box<dyn Spell>, Error>;
 
 /// The spell factory, you have to register the spell before trying to create them.
-#[derive(Debug, Default)]
+#[derive(Debug)]
 pub struct SpellFactory {
     /// The dispatch map, to get a builder by an associated spell name.
     dispatch: HashMap<&'static str, SpellBuilderFunction>,
 }
 
+impl Default for SpellFactory {
+    fn default() -> Self {
+        use crate::spell::std as spell;
+        let mut this = Self { dispatch: Default::default() };
+
+        this.register::<spell::Log>().expect("error in std spells");
+
+        this
+    }
+}
+
 impl SpellFactory {
     /// Get the list of all registered spells.
     pub fn get_registered_spells(&self) -> impl Iterator<Item = &'static str> {
diff --git a/grimoire/src/spell/mod.rs b/grimoire/src/spell/mod.rs
index 35fd600f5db86c16027dfce7e58d48d9afcd9abd..aa9e2fa067f3d84de85bd54191554cbb6161edd5 100644
--- a/grimoire/src/spell/mod.rs
+++ b/grimoire/src/spell/mod.rs
@@ -1,9 +1,16 @@
 //! The definition of Spells in the Grimoire engine.
 
-mod factory;
 mod arguments;
+mod factory;
 mod traits;
 
-pub use factory::*;
+/// Standard spells.
+pub mod std {
+    mod log;
+
+    pub use log::Log;
+}
+
 pub use arguments::*;
+pub use factory::*;
 pub use traits::*;
diff --git a/grimoire/src/spell/std/log.rs b/grimoire/src/spell/std/log.rs
new file mode 100644
index 0000000000000000000000000000000000000000..5c7ba6f16334b67d41d7cb2209bd69139ecdefe0
--- /dev/null
+++ b/grimoire/src/spell/std/log.rs
@@ -0,0 +1,57 @@
+use crate::prelude::*;
+
+#[derive(Debug)]
+pub struct Log {
+    level: String,
+    messages: Vec<String>,
+}
+
+impl Spell for Log {
+    fn cast(&self, state: GrimoireState) -> Result<GrimoireState, GrimoireError> {
+        let (heading, complementary) = match self.messages.split_first() {
+            Some((heading, complementary)) => (heading, complementary),
+            None => return Ok(state),
+        };
+
+        let logger = |ident: bool, str: &str| {
+            let ident = ident.then_some("\t").unwrap_or_default();
+            match self.level.as_str() {
+                "error" => log::error!(target: "grimoire", "{ident}{str}"),
+                _ => log::info!(target: "grimoire", "{ident}{str}"),
+            }
+        };
+
+        logger(false, heading);
+        complementary
+            .iter()
+            .for_each(|complementary| logger(true, complementary));
+
+        Ok(state)
+    }
+}
+
+impl TryFrom<SpellArguments> for Log {
+    type Error = GrimoireError;
+
+    fn try_from(mut args: SpellArguments) -> Result<Self, Self::Error> {
+        let level = args
+            .remove_as("level", GrimoireType::Identifier)?
+            .to_string();
+        args.has_named()
+            .then_some(())
+            .ok_or(GrimoireError::Unexpected("too much named arguments"))?;
+
+        let messages = args
+            .into_iter()
+            .filter_map(|(key, msg)| key.is_none().then(|| msg.to_string()))
+            .collect();
+
+        Ok(Self { level, messages })
+    }
+}
+
+impl BuildableSpell for Log {
+    fn name() -> &'static str {
+        "log"
+    }
+}