diff --git a/Justfile b/Justfile
index b00f6f9..54be580 100644
--- a/Justfile
+++ b/Justfile
@@ -50,3 +50,8 @@ nm:
 expand:
     # Run `cargo expand` on modules
     cargo make expand -- nucleus
+
+doc:
+    # Generate and open documentation
+    cargo make docs-flow
+
diff --git a/nucleus/Makefile.toml b/nucleus/Makefile.toml
index 6caeb14..02bb76c 100644
--- a/nucleus/Makefile.toml
+++ b/nucleus/Makefile.toml
@@ -15,6 +15,10 @@ args = ["expand", "--target=${TARGET_JSON}", "--release", "--features=${TARGET_F
 env = { "TARGET_FEATURES" = "${QEMU_FEATURES}" }
 args = ["test", "--target=${TARGET_JSON}", "--features=${TARGET_FEATURES}"]
 
+[tasks.docs]
+env = { "TARGET_FEATURES" = "" }
+args = ["doc", "--open", "--no-deps", "--target=${TARGET_JSON}", "--features=${TARGET_FEATURES}"]
+
 # These tasks are written in cargo-make's own script to make it portable across platforms (no `basename` on Windows)
 [tasks.kernel-binary]
 script_runner = "@duckscript"
diff --git a/nucleus/src/arch/aarch64/boot.rs b/nucleus/src/arch/aarch64/boot.rs
index fa050f0..94bab34 100644
--- a/nucleus/src/arch/aarch64/boot.rs
+++ b/nucleus/src/arch/aarch64/boot.rs
@@ -6,7 +6,7 @@
  */
 
 //! Low-level boot of the Raspberry's processor
-//! http://infocenter.arm.com/help/topic/com.arm.doc.dai0527a/DAI0527A_baremetal_boot_code_for_ARMv8_A_processors.pdf
+//! <http://infocenter.arm.com/help/topic/com.arm.doc.dai0527a/DAI0527A_baremetal_boot_code_for_ARMv8_A_processors.pdf>
 
 use {
     crate::endless_sleep,
diff --git a/nucleus/src/platform/rpi3/fb.rs b/nucleus/src/platform/rpi3/fb.rs
index fa806fa..e09fbd8 100644
--- a/nucleus/src/platform/rpi3/fb.rs
+++ b/nucleus/src/platform/rpi3/fb.rs
@@ -89,7 +89,7 @@ impl MailboxOps for FrameBuffer {
         self.base_addr as *const _
     }
 
-    /// https://github.com/raspberrypi/firmware/wiki/Accessing-mailboxes says:
+    /// <https://github.com/raspberrypi/firmware/wiki/Accessing-mailboxes> says:
     /// **With the exception of the property tags mailbox channel,**
     /// when passing memory addresses as the data part of a mailbox message,
     /// the addresses should be **bus addresses as seen from the VC.**
diff --git a/nucleus/src/platform/rpi3/gpio.rs b/nucleus/src/platform/rpi3/gpio.rs
index 340c22a..169ef88 100644
--- a/nucleus/src/platform/rpi3/gpio.rs
+++ b/nucleus/src/platform/rpi3/gpio.rs
@@ -54,8 +54,8 @@ states! {
 pub struct Reserved<T>(T);
 
 /// The offsets for reach register.
-/// From https://wiki.osdev.org/Raspberry_Pi_Bare_Bones and
-/// https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf
+/// From <https://wiki.osdev.org/Raspberry_Pi_Bare_Bones> and
+/// <https://github.com/raspberrypi/documentation/files/1888662/BCM2837-ARM-Peripherals.-.Revised.-.V2-1.pdf>
 #[allow(non_snake_case)]
 #[repr(C)]
 pub struct RegisterBlock {
diff --git a/nucleus/src/platform/rpi3/mailbox.rs b/nucleus/src/platform/rpi3/mailbox.rs
index 64273f6..734ff53 100644
--- a/nucleus/src/platform/rpi3/mailbox.rs
+++ b/nucleus/src/platform/rpi3/mailbox.rs
@@ -478,7 +478,7 @@ impl Mailbox {
     }
 
     /// NB: Do not intermix Get/Set and Test tags in one request!
-    /// See https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface
+    /// See <https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface>
     /// * It is not valid to mix Test tags with Get/Set tags in the same operation
     ///   and no tags will be returned.
     #[inline]
@@ -492,7 +492,7 @@ impl Mailbox {
     }
 
     /// NB: Do not intermix Get/Set and Test tags in one request!
-    /// See https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface
+    /// See <https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface>
     /// * It is not valid to mix Test tags with Get/Set tags in the same operation
     ///   and no tags will be returned.
     #[inline]
diff --git a/nucleus/src/platform/rpi3/mod.rs b/nucleus/src/platform/rpi3/mod.rs
index 5e73330..38fab56 100644
--- a/nucleus/src/platform/rpi3/mod.rs
+++ b/nucleus/src/platform/rpi3/mod.rs
@@ -15,14 +15,14 @@ pub mod power;
 pub mod vc;
 
 /// See BCM2835-ARM-Peripherals.pdf
-/// See https://www.raspberrypi.org/forums/viewtopic.php?t=186090 for more details.
+/// See <https://www.raspberrypi.org/forums/viewtopic.php?t=186090> for more details.
 
 pub struct BcmHost;
 
 impl BcmHost {
     /// This returns the ARM-side physical address where peripherals are mapped.
     ///
-    /// As per https://www.raspberrypi.org/documentation/hardware/raspberrypi/peripheral_addresses.md
+    /// As per <https://www.raspberrypi.org/documentation/hardware/raspberrypi/peripheral_addresses.md>
     /// BCM SOC could address only 1Gb of memory, so 0x4000_0000 is the high watermark.
     pub const fn get_peripheral_address() -> usize {
         0x3f00_0000
@@ -38,7 +38,7 @@ impl BcmHost {
         0xc000_0000 // uncached
     }
 
-    /// As per https://www.raspberrypi.org/forums/viewtopic.php?p=1170522#p1170522
+    /// As per <https://www.raspberrypi.org/forums/viewtopic.php?p=1170522#p1170522>
     ///
     pub fn bus2phys(bus: usize) -> usize {
         bus & !0xc000_0000
diff --git a/nucleus/src/sync.rs b/nucleus/src/sync.rs
index 9983b59..4dcee83 100644
--- a/nucleus/src/sync.rs
+++ b/nucleus/src/sync.rs
@@ -19,8 +19,8 @@ pub struct NullLock<T> {
 /// threads don't exist yet in our code.
 ///
 /// Literature:
-/// https://doc.rust-lang.org/beta/nomicon/send-and-sync.html
-/// https://doc.rust-lang.org/book/ch16-04-extensible-concurrency-sync-and-send.html
+/// * <https://doc.rust-lang.org/beta/nomicon/send-and-sync.html>
+/// * <https://doc.rust-lang.org/book/ch16-04-extensible-concurrency-sync-and-send.html>
 unsafe impl<T> Sync for NullLock<T> {}
 
 impl<T> NullLock<T> {