diff --git a/README.md b/README.md
index f748457..4fbf2f2 100644
--- a/README.md
+++ b/README.md
@@ -98,6 +98,10 @@ Quickly kills (terminates) the server on trigger, via command or HTTP request.
 ### Swing through grass
 Self-explanatory
 
+### Durability alert
+Self-explanatory too. \
+For simplicity, there's no configuration. Control with `tweaks724.durabilityalert`
+
 ### Utility commands
 
 - `/ping` - displays player ping P \
diff --git a/src/main/java/eu/m724/tweaks/TweaksPlugin.java b/src/main/java/eu/m724/tweaks/TweaksPlugin.java
index 8c6430e..7da3a4a 100644
--- a/src/main/java/eu/m724/tweaks/TweaksPlugin.java
+++ b/src/main/java/eu/m724/tweaks/TweaksPlugin.java
@@ -14,6 +14,7 @@ import eu.m724.tweaks.module.auth.AuthModule;
 import eu.m724.tweaks.module.chat.ChatModule;
 import eu.m724.tweaks.module.door.DoorKnockModule;
 import eu.m724.tweaks.module.door.DoorOpenModule;
+import eu.m724.tweaks.module.durability.DurabilityModule;
 import eu.m724.tweaks.module.full.FullModule;
 import eu.m724.tweaks.module.hardcore.HardcoreModule;
 import eu.m724.tweaks.module.killswitch.KillswitchModule;
@@ -154,6 +155,8 @@ public class TweaksPlugin extends MStatsPlugin {
             TweaksModule.init(SwingModule.class);
         }
 
+        TweaksModule.init(DurabilityModule.class);
+
         /* end modules */
 
         if (config.metrics()) {
diff --git a/src/main/java/eu/m724/tweaks/module/durability/DurabilityCaches.java b/src/main/java/eu/m724/tweaks/module/durability/DurabilityCaches.java
new file mode 100644
index 0000000..4ab41d7
--- /dev/null
+++ b/src/main/java/eu/m724/tweaks/module/durability/DurabilityCaches.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2025  Minecon724
+ * Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
+ * in the project root for the full license text.
+ */
+
+package eu.m724.tweaks.module.durability;
+
+import org.bukkit.Material;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class DurabilityCaches {
+    private final Map lastFullReminder = new HashMap<>();
+    //                              BAD
+    private final Map> lastUse = new HashMap<>();
+    //                              BAD
+    private final Map> lastPing = new HashMap<>();
+
+    boolean shouldFullRemind(Player player, long now) {
+        var lfr = lastFullReminder.getOrDefault(player, 0L);
+
+        if (now - lfr > 300 * 1000) {
+            lastFullReminder.put(player, now);
+            return true;
+        } else if (now - lfr < 3 * 1000) {
+            return true;
+        }
+
+        return false;
+    }
+
+    boolean shouldRemind(Player player, ItemStack itemStack, long now) {
+        var lu = lastUse.computeIfAbsent(player, (k) -> new HashMap<>()).getOrDefault(itemStack.getType(), 0L);
+
+        if (now - lu > 180 * 1000) {
+            lastUse.get(player).put(itemStack.getType(), now);
+            return true;
+        } else if (now - lu < 3 * 1000) {
+            return true;
+        }
+
+        return false;
+    }
+
+    boolean shouldPing(Player player, ItemStack itemStack, long now) {
+        var lp = lastPing.computeIfAbsent(player, (k) -> new HashMap<>()).getOrDefault(itemStack.getType(), 0L);
+
+        if (now - lp > 60 * 1000) {
+            lastPing.get(player).put(itemStack.getType(), now);
+            return true;
+        }
+
+        return false;
+    }
+}
diff --git a/src/main/java/eu/m724/tweaks/module/durability/DurabilityModule.java b/src/main/java/eu/m724/tweaks/module/durability/DurabilityModule.java
new file mode 100644
index 0000000..f8bde5a
--- /dev/null
+++ b/src/main/java/eu/m724/tweaks/module/durability/DurabilityModule.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2025  Minecon724
+ * Tweaks724 is licensed under the GNU General Public License. See the LICENSE.md file
+ * in the project root for the full license text.
+ */
+
+package eu.m724.tweaks.module.durability;
+
+import eu.m724.tweaks.DebugLogger;
+import eu.m724.tweaks.module.TweaksModule;
+import net.md_5.bungee.api.ChatColor;
+import net.md_5.bungee.api.ChatMessageType;
+import net.md_5.bungee.api.chat.ComponentBuilder;
+import org.bukkit.Bukkit;
+import org.bukkit.Material;
+import org.bukkit.Sound;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerItemDamageEvent;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.Damageable;
+import org.bukkit.scheduler.BukkitRunnable;
+
+import java.awt.Color;
+
+public class DurabilityModule extends TweaksModule implements Listener {
+    private final DurabilityCaches cache = new DurabilityCaches();
+
+    @Override
+    protected void onInit() {
+        registerEvents(this);
+
+        new BukkitRunnable() {
+            @Override
+            public void run() {
+                Bukkit.getServer().getOnlinePlayers().forEach(p -> refreshBar(p));
+            }
+        }.runTaskTimerAsynchronously(getPlugin(), 0, 40);
+    }
+
+    @EventHandler
+    public void onPlayerItemDamage(PlayerItemDamageEvent event) {
+        refreshBar(event.getPlayer(), event.getItem(), event.getDamage());
+    }
+
+    private void refreshBar(Player player) {
+        refreshBar(player, null, -1);
+    }
+
+    private void refreshBar(Player player, ItemStack justDamaged, int damage) {
+        var items = new ItemStack[] {
+                player.getInventory().getHelmet(),
+                player.getInventory().getChestplate(),
+                player.getInventory().getLeggings(),
+                player.getInventory().getBoots(),
+                player.getInventory().getItemInMainHand(),
+                player.getInventory().getItemInOffHand()
+        };
+
+        var builder = new ComponentBuilder();
+
+        var now = System.currentTimeMillis();
+        var all = cache.shouldFullRemind(player, now);
+
+        for (var itemStack : items) {
+            if (itemStack == null || !itemStack.hasItemMeta()) continue;
+
+            if (itemStack.getItemMeta() instanceof Damageable meta) {
+                var target = itemStack.equals(justDamaged);
+
+                var maxDurability = itemStack.getType().getMaxDurability();
+                var durability = maxDurability - meta.getDamage() - (target ? damage : 0);
+                durability = Math.max(0, durability);
+                var percentage = (double) durability / maxDurability;
+
+                var notify = durability < 30 && (durability < 10 || percentage < 0.1);
+
+                var remind = cache.shouldRemind(player, itemStack, now);
+                var important = target && notify && cache.shouldPing(player, itemStack, now);
+
+                DebugLogger.finer("%s's %s: %d / %d (%.2f%%)%s%s", player.getName(), itemStack.getType().name(), durability, maxDurability, percentage * 100, notify ? " notify" : "", important ? " important" : "");
+
+                if (notify || all || remind) {
+                    var longName = remind || important;
+                    var label = longName ? getMaterialLongName(itemStack.getType()) : getMaterialShortName(itemStack.getType());
+                    var labelColor = percentage > 0 ? matColor(itemStack.getType()) : ChatColor.DARK_RED;
+
+                    var percentageStr = (int) (percentage * 100) + "%";
+                    var percentageColor = mixColor(labelColor, ChatColor.DARK_RED, 1.0 - percentage * 10);
+
+                    builder.append(label + " ").color(labelColor);
+                    builder.append(percentageStr + "  ").color(percentageColor);
+
+                    if (important) {
+                        player.playSound(player, Sound.BLOCK_ANVIL_PLACE, 0.5f, 1.5f);
+                        player.sendTitle("", labelColor + label + " " + percentageColor + percentageStr, 5, 20, 5);
+                    }
+                }
+            }
+        }
+
+        var component = builder.create();
+        if (component.length > 0)
+            player.spigot().sendMessage(ChatMessageType.ACTION_BAR, component);
+    }
+
+    private String getMaterialLongName(Material material) {
+        var sp = material.name().split("_");
+        var str = sp[sp.length - 1];
+        return str.charAt(0) + str.substring(1).toLowerCase();
+    }
+
+    private String getMaterialShortName(Material material) {
+        return getMaterialLongName(material).substring(0, 2);
+    }
+
+    private ChatColor mixColor(ChatColor from, ChatColor to, double percentage) {
+        percentage = Math.clamp(percentage, 0.0, 1.0);
+
+        var diffR = to.getColor().getRed() - from.getColor().getRed();
+        var diffG = to.getColor().getGreen() - from.getColor().getGreen();
+        var diffB = to.getColor().getBlue() - from.getColor().getBlue();
+
+        var r = from.getColor().getRed() + (int) (diffR * percentage);
+        var g = from.getColor().getGreen() + (int) (diffG * percentage);
+        var b = from.getColor().getBlue() + (int) (diffB * percentage);
+
+        return ChatColor.of(new Color(r, g, b));
+    }
+
+    private ChatColor matColor(Material material) {
+        var color = ChatColor.DARK_GRAY;
+
+        if (material.name().startsWith("DIAMOND_")) {
+            color = ChatColor.AQUA;
+        } else if (material.name().startsWith("NETHERITE_")) {
+            color = ChatColor.DARK_PURPLE;
+        } else if (material.name().startsWith("IRON_")) {
+            color = ChatColor.WHITE;
+        } else if (material.name().startsWith("STONE_")) {
+            color = ChatColor.GRAY;
+        } else if (material.name().startsWith("WOODEN_")) {
+            color = ChatColor.DARK_GREEN;
+        } else if (material.name().startsWith("GOLDEN_")) {
+            color = ChatColor.GOLD;
+        }
+
+        return color;
+    }
+}
diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml
index 5b193b2..5a84f24 100644
--- a/src/main/resources/plugin.yml
+++ b/src/main/resources/plugin.yml
@@ -40,6 +40,9 @@ commands:
   servkill:
     description: Immediately stop the server
     permission: tweaks724.servkill
+  durabilityalert:
+    description: Durability alert toggle
+    permission: tweaks724.durabilityalert
 
 permissions:
   tweaks724.chatmanage:
@@ -58,6 +61,8 @@ permissions:
     default: op
   tweaks724.servkill:
     default: false
+  tweaks724.durabilityalert:
+    default: true
 
   7weaks724.ignore.this:
     description: "Internal, not for use. ${project.spigot.version}"