diff --git a/Cargo.lock b/Cargo.lock
index 0f862072923fa67d6434cf022f6c31b2a816236c..9bee6c43cd5ae5b038b81460a1079a3650345c4b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -575,6 +575,7 @@ dependencies = [
  "ipaddress",
  "itertools 0.12.1",
  "jsonwebtoken",
+ "lib",
  "log",
  "loole",
  "lru-cache",
@@ -1796,6 +1797,10 @@ version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
 
+[[package]]
+name = "lib"
+version = "0.1.0"
+
 [[package]]
 name = "libc"
 version = "0.2.153"
diff --git a/Cargo.toml b/Cargo.toml
index 2302972affb9d20bf96490be2819112ec0dbe0d1..4fddac7cb61c9216b9126e6eacd8bdee493778a5 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -16,11 +16,17 @@ edition = "2021"
 # See also `rust-toolchain.toml`
 rust-version = "1.76.0"
 
+# for hot lib reload
+[workspace]
+members = ["lib"]
 
 [dependencies]
 console-subscriber = { version = "0.1", optional = true }
 
+# for hot lib reload
 hot-lib-reloader = { version = "^0.7", optional = true }
+lib = { path = "lib", optional = true }
+#no-mangle-if-debug = { version = "*" }
 
 # Used for secure identifiers
 rand = "0.8.5"
@@ -400,7 +406,7 @@ perf_measurements = [
 # incompatible with release_max_log_level
 tokio_console = ["console-subscriber", "tokio/tracing"]
 
-hot_reload = ["dep:hot-lib-reloader"]
+hot_reload = ["dep:hot-lib-reloader", "lib"]
 
 hardened_malloc = ["hardened_malloc-rs"]
 
diff --git a/lib/Cargo.toml b/lib/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..b301b6908b67951ca1e8a38f8089b6c701691bd0
--- /dev/null
+++ b/lib/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "lib"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+crate-type = ["rlib", "dylib"]
diff --git a/lib/src/lib.rs b/lib/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..91e765868e590170ac36a0cc834be912b7ba1e3b
--- /dev/null
+++ b/lib/src/lib.rs
@@ -0,0 +1,4 @@
+#[no_mangle]
+pub fn test_command() {
+	println!("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
+}
diff --git a/src/service/admin/mod.rs b/src/service/admin/mod.rs
index 64ca48c4fa9aa8dda60777daa30e828b5ffbc5a6..b6b810bd950eaaf9536951ef56af34b2007322d7 100644
--- a/src/service/admin/mod.rs
+++ b/src/service/admin/mod.rs
@@ -27,6 +27,9 @@
 use tracing::{error, warn};
 
 use self::fsck::FsckCommand;
+#[cfg(feature = "hot_reload")]
+#[allow(unused_imports)]
+use self::test_cmd::TestCommands;
 use super::pdu::PduBuilder;
 use crate::{
 	service::admin::{
@@ -44,6 +47,9 @@
 pub(crate) mod query;
 pub(crate) mod room;
 pub(crate) mod server;
+#[cfg(feature = "hot_reload")]
+#[allow(unused_imports)]
+pub(crate) mod test_cmd;
 pub(crate) mod user;
 
 const PAGE_SIZE: usize = 100;
@@ -87,6 +93,10 @@ enum AdminCommand {
 	#[command(subcommand)]
 	/// - Query all the database getters and iterators
 	Fsck(FsckCommand),
+
+	#[cfg(feature = "hot_reload")]
+	#[command(subcommand)]
+	Test(TestCommands),
 }
 
 #[derive(Debug)]
@@ -304,6 +314,8 @@ async fn process_admin_command(&self, command: AdminCommand, body: Vec<&str>) ->
 			AdminCommand::Debug(command) => debug::process(command, body).await?,
 			AdminCommand::Query(command) => query::process(command, body).await?,
 			AdminCommand::Fsck(command) => fsck::process(command, body).await?,
+			#[cfg(feature = "hot_reload")]
+			AdminCommand::Test(command) => test_cmd::process(command, body).await?,
 		};
 
 		Ok(reply_message_content)
diff --git a/src/service/admin/test_cmd/mod.rs b/src/service/admin/test_cmd/mod.rs
new file mode 100644
index 0000000000000000000000000000000000000000..852afbe764c0ba36c76cb97c9115f7b9c6094733
--- /dev/null
+++ b/src/service/admin/test_cmd/mod.rs
@@ -0,0 +1,31 @@
+use clap::Subcommand;
+#[cfg(feature = "hot_reload")]
+#[allow(unused_imports)]
+#[allow(clippy::wildcard_imports)]
+use hot_lib::*;
+use ruma::events::room::message::RoomMessageEventContent;
+
+use crate::{debug_error, Result};
+
+#[cfg(feature = "hot_reload")]
+#[hot_lib_reloader::hot_module(dylib = "lib")]
+mod hot_lib {
+	hot_functions_from_file!("lib/src/lib.rs");
+}
+
+#[cfg_attr(test, derive(Debug))]
+#[derive(Subcommand)]
+pub(crate) enum TestCommands {
+	Test1,
+}
+
+pub(crate) async fn process(command: TestCommands, _body: Vec<&str>) -> Result<RoomMessageEventContent> {
+	Ok(match command {
+		TestCommands::Test1 => {
+			debug_error!("before calling test_command");
+			test_command();
+			debug_error!("after calling test_command");
+			RoomMessageEventContent::notice_plain(String::from("loaded"))
+		},
+	})
+}