diff --git a/Cargo.lock b/Cargo.lock
index 71d79adb..d9af38d2 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -472,6 +472,16 @@ dependencies = [
  "pkg-config",
 ]
 
+[[package]]
+name = "cargo_toml"
+version = "0.20.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ad639525b1c67b6a298f378417b060fbc04618bea559482a8484381cce27d965"
+dependencies = [
+ "serde",
+ "toml",
+]
+
 [[package]]
 name = "cc"
 version = "1.1.6"
@@ -666,8 +676,10 @@ dependencies = [
  "argon2",
  "axum 0.7.5",
  "bytes",
+ "cargo_toml",
  "checked_ops",
  "chrono",
+ "conduit_macros",
  "const-str",
  "either",
  "figment",
diff --git a/Cargo.toml b/Cargo.toml
index 5fcb03ef..acaed701 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -28,6 +28,10 @@ name = "conduit"
 [workspace.dependencies.const-str]
 version = "0.5.7"
 
+[workspace.dependencies.cargo_toml]
+version = "0.20"
+features = ["features"]
+
 [workspace.dependencies.sanitize-filename]
 version = "0.5.0"
 
diff --git a/src/core/Cargo.toml b/src/core/Cargo.toml
index 453d7b13..620aad02 100644
--- a/src/core/Cargo.toml
+++ b/src/core/Cargo.toml
@@ -53,8 +53,10 @@ sha256_media = []
 argon2.workspace = true
 axum.workspace = true
 bytes.workspace = true
+cargo_toml.workspace = true
 checked_ops.workspace = true
 chrono.workspace = true
+conduit-macros.workspace = true
 const-str.workspace = true
 either.workspace = true
 figment.workspace = true
diff --git a/src/core/error/mod.rs b/src/core/error/mod.rs
index 9439261e..8664d740 100644
--- a/src/core/error/mod.rs
+++ b/src/core/error/mod.rs
@@ -55,6 +55,8 @@ pub enum Error {
 	Http(#[from] http::Error),
 	#[error("{0}")]
 	HttpHeader(#[from] http::header::InvalidHeaderValue),
+	#[error("{0}")]
+	CargoToml(#[from] cargo_toml::Error),
 
 	// ruma
 	#[error("{0}")]
diff --git a/src/core/info/cargo.rs b/src/core/info/cargo.rs
new file mode 100644
index 00000000..0d2db1ad
--- /dev/null
+++ b/src/core/info/cargo.rs
@@ -0,0 +1,66 @@
+//! Information about the build related to Cargo. This is a frontend interface
+//! informed by proc-macros that capture raw information at build time which is
+//! further processed at runtime either during static initialization or as
+//! necessary.
+
+use std::sync::OnceLock;
+
+use cargo_toml::Manifest;
+use conduit_macros::cargo_manifest;
+
+use crate::Result;
+
+// Raw captures of the cargo manifest for each crate. This is provided by a
+// proc-macro at build time since the source directory and the cargo toml's may
+// not be present during execution.
+
+#[cargo_manifest]
+const WORKSPACE_MANIFEST: &'static str = ();
+#[cargo_manifest("macros")]
+const MACROS_MANIFEST: &'static str = ();
+#[cargo_manifest("core")]
+const CORE_MANIFEST: &'static str = ();
+#[cargo_manifest("database")]
+const DATABASE_MANIFEST: &'static str = ();
+#[cargo_manifest("service")]
+const SERVICE_MANIFEST: &'static str = ();
+#[cargo_manifest("admin")]
+const ADMIN_MANIFEST: &'static str = ();
+#[cargo_manifest("router")]
+const ROUTER_MANIFEST: &'static str = ();
+#[cargo_manifest("main")]
+const MAIN_MANIFEST: &'static str = ();
+
+/// Processed list of features access all project crates. This is generated from
+/// the data in the MANIFEST strings and contains all possible project features.
+/// For *enabled* features see the info::rustc module instead.
+static FEATURES: OnceLock<Vec<String>> = OnceLock::new();
+
+/// List of all possible features for the project. For *enabled* features in
+/// this build see the companion function in info::rustc.
+pub fn features() -> &'static Vec<String> {
+	FEATURES.get_or_init(|| init_features().unwrap_or_else(|e| panic!("Failed initialize features: {e}")))
+}
+
+fn init_features() -> Result<Vec<String>> {
+	let mut features = Vec::new();
+	append_features(&mut features, WORKSPACE_MANIFEST)?;
+	append_features(&mut features, MACROS_MANIFEST)?;
+	append_features(&mut features, CORE_MANIFEST)?;
+	append_features(&mut features, DATABASE_MANIFEST)?;
+	append_features(&mut features, SERVICE_MANIFEST)?;
+	append_features(&mut features, ADMIN_MANIFEST)?;
+	append_features(&mut features, ROUTER_MANIFEST)?;
+	append_features(&mut features, MAIN_MANIFEST)?;
+	features.sort();
+	features.dedup();
+
+	Ok(features)
+}
+
+fn append_features(features: &mut Vec<String>, manifest: &str) -> Result<()> {
+	let manifest = Manifest::from_str(manifest)?;
+	features.extend(manifest.features.keys().cloned());
+
+	Ok(())
+}
diff --git a/src/core/info/mod.rs b/src/core/info/mod.rs
index 42ec971e..7749bbdc 100644
--- a/src/core/info/mod.rs
+++ b/src/core/info/mod.rs
@@ -1,4 +1,5 @@
 //! Information about the project. This module contains version, build, system,
 //! etc information which can be queried by admins or used by developers.
 
+pub mod cargo;
 pub mod version;
diff --git a/src/macros/cargo.rs b/src/macros/cargo.rs
new file mode 100644
index 00000000..17132a6c
--- /dev/null
+++ b/src/macros/cargo.rs
@@ -0,0 +1,51 @@
+use std::{fs::read_to_string, path::PathBuf};
+
+use proc_macro::TokenStream;
+use quote::quote;
+use syn::{parse_macro_input, AttributeArgs, ItemConst, Lit, NestedMeta};
+
+pub(super) fn manifest(args: TokenStream, item: TokenStream) -> TokenStream {
+	let item = parse_macro_input!(item as ItemConst);
+	let args = parse_macro_input!(args as AttributeArgs);
+	let member = args.into_iter().find_map(|arg| {
+		let NestedMeta::Lit(arg) = arg else {
+			return None;
+		};
+		let Lit::Str(arg) = arg else {
+			return None;
+		};
+		Some(arg.value())
+	});
+
+	let path = manifest_path(member.as_deref());
+	let manifest = read_to_string(&path).unwrap_or_default();
+
+	let name = item.ident;
+	let val = manifest.as_str();
+	let ret = quote! {
+		const #name: &'static str = #val;
+	};
+
+	ret.into()
+}
+
+#[allow(clippy::option_env_unwrap)]
+fn manifest_path(member: Option<&str>) -> PathBuf {
+	let mut path: PathBuf = option_env!("CARGO_MANIFEST_DIR")
+		.expect("missing CARGO_MANIFEST_DIR in environment")
+		.into();
+
+	// conduwuit/src/macros/ -> conduwuit/src/
+	path.pop();
+
+	if let Some(member) = member {
+		// conduwuit/$member/Cargo.toml
+		path.push(member);
+	} else {
+		// conduwuit/src/ -> conduwuit/
+		path.pop();
+	}
+
+	path.push("Cargo.toml");
+	path
+}
diff --git a/src/macros/mod.rs b/src/macros/mod.rs
index 6f286d66..718583a4 100644
--- a/src/macros/mod.rs
+++ b/src/macros/mod.rs
@@ -1,4 +1,5 @@
 mod admin;
+mod cargo;
 mod utils;
 
 use proc_macro::TokenStream;
@@ -7,3 +8,6 @@ use proc_macro::TokenStream;
 pub fn admin_command_dispatch(args: TokenStream, input: TokenStream) -> TokenStream {
 	admin::command_dispatch(args, input)
 }
+
+#[proc_macro_attribute]
+pub fn cargo_manifest(args: TokenStream, input: TokenStream) -> TokenStream { cargo::manifest(args, input) }