diff --git a/src/EllieBot/Modules/Utility/Ai/AiAssistantService.cs b/src/EllieBot/Modules/Utility/Ai/AiAssistantService.cs
new file mode 100644
index 0000000..422aae6
--- /dev/null
+++ b/src/EllieBot/Modules/Utility/Ai/AiAssistantService.cs
@@ -0,0 +1,314 @@
+using EllieBot.Common.ModuleBehaviors;
+using EllieBot.Modules.Administration;
+using EllieBot.Modules.Games.Services;
+using System.Net;
+using System.Net.Http.Json;
+using System.Text;
+using System.Text.Json;
+using JsonSerializer = System.Text.Json.JsonSerializer;
+
+namespace EllieBot.Modules.Utility;
+
+public enum GetCommandErrorResult
+{
+    RateLimitHit,
+    NotAuthorized,
+    Disregard,
+    Unknown
+}
+
+public sealed class AiAssistantService
+    : IAiAssistantService, IReadyExecutor,
+        IExecOnMessage,
+        IEService
+{
+    private IReadOnlyCollection<AiCommandModel> _commands = [];
+
+    private readonly IBotStrings _strings;
+    private readonly IHttpClientFactory _httpFactory;
+    private readonly CommandService _cmds;
+    private readonly IBotCredsProvider _credsProvider;
+    private readonly DiscordSocketClient _client;
+    private readonly ICommandHandler _cmdHandler;
+    private readonly BotConfigService _bcs;
+    private readonly IMessageSenderService _sender;
+
+    private readonly JsonSerializerOptions _serializerOptions = new();
+    private readonly IPermissionChecker _permChecker;
+    private readonly IBotCache _botCache;
+    private readonly ChatterBotService _cbs;
+
+    public AiAssistantService(
+        DiscordSocketClient client,
+        IBotStrings strings,
+        IHttpClientFactory httpFactory,
+        CommandService cmds,
+        IBotCredsProvider credsProvider,
+        ICommandHandler cmdHandler,
+        BotConfigService bcs,
+        IPermissionChecker permChecker,
+        IBotCache botCache,
+        ChatterBotService cbs,
+        IMessageSenderService sender)
+    {
+        _client = client;
+        _strings = strings;
+        _httpFactory = httpFactory;
+        _cmds = cmds;
+        _credsProvider = credsProvider;
+        _cmdHandler = cmdHandler;
+        _bcs = bcs;
+        _sender = sender;
+        _permChecker = permChecker;
+        _botCache = botCache;
+        _cbs = cbs;
+    }
+
+    public async Task<OneOf.OneOf<EllieCommandCallModel, GetCommandErrorResult>> TryGetCommandAsync(
+        ulong userId,
+        string prompt,
+        IReadOnlyCollection<AiCommandModel> commands,
+        string prefix)
+    {
+        using var content = new StringContent(
+            JsonSerializer.Serialize(new
+            {
+                query = prompt,
+                commands = commands.ToDictionary(x => x.Name,
+                    x => new AiCommandModel()
+                    {
+                        Desc = string.Format(x.Desc ?? "", prefix),
+                        Params = x.Params,
+                        Name = x.Name
+                    }),
+            }),
+            Encoding.UTF8,
+            "application/json"
+        );
+
+        using var request = new HttpRequestMessage();
+        request.Method = HttpMethod.Post;
+        // request.RequestUri = new("https://nai.nadeko.bot/get-command");
+        request.RequestUri = new("https://nai.nadeko.bot/get-command");
+        request.Content = content;
+
+        var creds = _credsProvider.GetCreds();
+
+        request.Headers.TryAddWithoutValidation("x-auth-token", creds.EllieAiToken);
+        request.Headers.TryAddWithoutValidation("x-auth-userid", userId.ToString());
+
+
+        using var client = _httpFactory.CreateClient();
+
+        // todo customize according to the bot's config
+        // - CurrencyName
+        // - 
+
+        using var response = await client.SendAsync(request);
+
+        if (response.StatusCode == HttpStatusCode.TooManyRequests)
+        {
+            return GetCommandErrorResult.RateLimitHit;
+        }
+        else if (response.StatusCode == HttpStatusCode.Unauthorized)
+        {
+            return GetCommandErrorResult.NotAuthorized;
+        }
+
+        var funcModel = await response.Content.ReadFromJsonAsync<CommandPromptResultModel>();
+
+
+        if (funcModel?.Name == "disregard")
+        {
+            Log.Warning("Disregarding the prompt: {Prompt}", prompt);
+            return GetCommandErrorResult.Disregard;
+        }
+
+        if (funcModel is null)
+            return GetCommandErrorResult.Unknown;
+
+        var comModel = new EllieCommandCallModel()
+        {
+            Name = funcModel.Name,
+            Arguments = funcModel.Arguments
+                                 .OrderBy(param => _commands.FirstOrDefault(x => x.Name == funcModel.Name)
+                                                            ?.Params
+                                                            .Select((x, i) => (x, i))
+                                                            .Where(x => x.x.Name == param.Key)
+                                                            .Select(x => x.i)
+                                                            .FirstOrDefault())
+                                 .Select(x => x.Value)
+                                 .Where(x => !string.IsNullOrWhiteSpace(x))
+                                 .ToArray(),
+            Remaining = funcModel.Remaining
+        };
+
+        return comModel;
+    }
+
+    public IReadOnlyCollection<AiCommandModel> GetCommands()
+        => _commands;
+
+    public Task OnReadyAsync()
+    {
+        var cmds = _cmds.Commands
+                        .Select(x => (MethodName: x.Summary, CommandName: x.Aliases[0]))
+                        .Where(x => !x.MethodName.Contains("///"))
+                        .Distinct()
+                        .ToList();
+
+        var funcs = new List<AiCommandModel>();
+        foreach (var (method, cmd) in cmds)
+        {
+            var commandStrings = _strings.GetCommandStrings(method);
+
+            if (commandStrings is null)
+                continue;
+
+            funcs.Add(new()
+            {
+                Name = cmd,
+                Desc = commandStrings?.Desc?.Replace("currency", "flowers") ?? string.Empty,
+                Params = commandStrings?.Params.FirstOrDefault()
+                                       ?.Select(x => new AiCommandParamModel()
+                                       {
+                                           Desc = x.Value.Desc,
+                                           Name = x.Key,
+                                       })
+                                       .ToArray()
+                         ?? []
+            });
+        }
+
+        _commands = funcs;
+
+        return Task.CompletedTask;
+    }
+
+    public int Priority
+        => 2;
+
+    public async Task<bool> ExecOnMessageAsync(IGuild guild, IUserMessage msg)
+    {
+        if (string.IsNullOrWhiteSpace(_credsProvider.GetCreds().EllieAiToken))
+            return false;
+
+        if (guild is not SocketGuild sg)
+            return false;
+
+        var nadekoId = _client.CurrentUser.Id;
+
+        var channel = msg.Channel as ITextChannel;
+        if (channel is null)
+            return false;
+
+        var normalMention = $"<@{nadekoId}> ";
+        var nickMention = $"<@!{nadekoId}> ";
+        string query;
+        if (msg.Content.StartsWith(normalMention, StringComparison.InvariantCulture))
+            query = msg.Content[normalMention.Length..].Trim();
+        else if (msg.Content.StartsWith(nickMention, StringComparison.InvariantCulture))
+            query = msg.Content[nickMention.Length..].Trim();
+        else
+            return false;
+
+        var success = await TryExecuteAiCommand(guild, msg, channel, query);
+
+        return success;
+    }
+
+    public async Task<bool> TryExecuteAiCommand(
+        IGuild guild,
+        IUserMessage msg,
+        ITextChannel channel,
+        string query)
+    {
+        // check permissions
+        var pcResult = await _permChecker.CheckPermsAsync(
+            guild,
+            msg.Channel,
+            msg.Author,
+            "Utility",
+            "prompt"
+        );
+
+        if (!pcResult.IsAllowed)
+            return false;
+
+        using var _ = channel.EnterTypingState();
+
+        var result = await TryGetCommandAsync(msg.Author.Id, query, _commands, _cmdHandler.GetPrefix(guild.Id));
+
+        if (result.TryPickT0(out var model, out var error))
+        {
+            if (model.Name == ".ai_chat")
+            {
+                if (guild is not SocketGuild sg)
+                    return false;
+                
+                var sess = _cbs.GetOrCreateSession(guild.Id);
+                if (sess is null)
+                    return false;
+
+                await _cbs.RunChatterBot(sg, msg, channel, sess, query);
+                return false;
+            }
+
+            var commandString = GetCommandString(model);
+
+            var msgTask = _sender.Response(channel)
+                                 .Embed(_sender.CreateEmbed()
+                                               .WithOkColor()
+                                               .WithAuthor(msg.Author.GlobalName,
+                                                   msg.Author.RealAvatarUrl().ToString())
+                                               .WithDescription(commandString))
+                                 .SendAsync();
+
+
+            await _cmdHandler.TryRunCommand(
+                (SocketGuild)guild,
+                (ISocketMessageChannel)channel,
+                new DoAsUserMessage((SocketUserMessage)msg, msg.Author, commandString));
+
+            var cmdMsg = await msgTask;
+
+            cmdMsg.DeleteAfter(5);
+
+            return true;
+        }
+
+        if (error == GetCommandErrorResult.Disregard)
+        {
+            // await msg.ErrorAsync();
+            return false;
+        }
+
+        var key = new TypedKey<bool>($"sub_error:{msg.Author.Id}:{error}");
+
+        if (!await _botCache.AddAsync(key, true, TimeSpan.FromDays(1), overwrite: false))
+            return false;
+
+        var errorMsg = error switch
+        {
+            GetCommandErrorResult.RateLimitHit
+                => "You've spent your daily requests quota.",
+            GetCommandErrorResult.NotAuthorized
+                => "In order to use this command you have to have a 5$ or higher subscription at <https://patreon.com/nadekobot>",
+            GetCommandErrorResult.Unknown
+                => "The service is temporarily unavailable.",
+            _ => throw new ArgumentOutOfRangeException()
+        };
+
+        await _sender.Response(channel)
+                     .Error(errorMsg)
+                     .SendAsync();
+        
+        return true;
+    }
+
+    private string GetCommandString(EllieCommandCallModel res)
+        => $"{_bcs.Data.Prefix}{res.Name} {res.Arguments.Select((x, i) => GetParamString(x, i + 1 == res.Arguments.Count)).Join(" ")}";
+
+    private static string GetParamString(string val, bool isLast)
+        => isLast ? val : "\"" + val + "\"";
+}
\ No newline at end of file
diff --git a/src/EllieBot/Modules/Utility/Ai/AiCommandModel.cs b/src/EllieBot/Modules/Utility/Ai/AiCommandModel.cs
new file mode 100644
index 0000000..eeaf38b
--- /dev/null
+++ b/src/EllieBot/Modules/Utility/Ai/AiCommandModel.cs
@@ -0,0 +1,15 @@
+using System.Text.Json.Serialization;
+
+namespace EllieBot.Modules.Utility;
+
+public sealed class AiCommandModel
+{
+    [JsonPropertyName("name")]
+    public required string Name { get; set; }
+
+    [JsonPropertyName("desc")]
+    public required string Desc { get; set; }
+
+    [JsonPropertyName("params")]
+    public required IReadOnlyList<AiCommandParamModel> Params { get; set; }
+}
\ No newline at end of file
diff --git a/src/EllieBot/Modules/Utility/Ai/AiCommandParamModel.cs b/src/EllieBot/Modules/Utility/Ai/AiCommandParamModel.cs
new file mode 100644
index 0000000..594d581
--- /dev/null
+++ b/src/EllieBot/Modules/Utility/Ai/AiCommandParamModel.cs
@@ -0,0 +1,12 @@
+using System.Text.Json.Serialization;
+
+namespace EllieBot.Modules.Utility;
+
+public sealed class AiCommandParamModel
+{
+    [JsonPropertyName("name")]
+    public required string Name { get; set; }
+
+    [JsonPropertyName("desc")]
+    public required string Desc { get; set; }
+}
\ No newline at end of file
diff --git a/src/EllieBot/Modules/Utility/Ai/CommandPromptResultModel.cs b/src/EllieBot/Modules/Utility/Ai/CommandPromptResultModel.cs
new file mode 100644
index 0000000..78d6179
--- /dev/null
+++ b/src/EllieBot/Modules/Utility/Ai/CommandPromptResultModel.cs
@@ -0,0 +1,16 @@
+using System.Text.Json.Serialization;
+
+namespace EllieBot.Modules.Utility;
+
+public sealed class CommandPromptResultModel
+{
+    [JsonPropertyName("name")]
+    public required string Name { get; set; }
+
+    [JsonPropertyName("arguments")]
+    public required Dictionary<string, string> Arguments { get; set; }
+    
+    [JsonPropertyName("remaining")]
+    [JsonConverter(typeof(NumberToStringConverter))]
+    public required string Remaining { get; set; }
+}
\ No newline at end of file
diff --git a/src/EllieBot/Modules/Utility/Ai/EllieCommandCallModel.cs b/src/EllieBot/Modules/Utility/Ai/EllieCommandCallModel.cs
new file mode 100644
index 0000000..4de388e
--- /dev/null
+++ b/src/EllieBot/Modules/Utility/Ai/EllieCommandCallModel.cs
@@ -0,0 +1,8 @@
+namespace EllieBot.Modules.Utility;
+
+public sealed class EllieCommandCallModel
+{
+    public required string Name { get; set; }
+    public required IReadOnlyList<string> Arguments { get; set; }
+    public required string Remaining { get; set; }
+}
\ No newline at end of file
diff --git a/src/EllieBot/Modules/Utility/Ai/IAiAssistantService.cs b/src/EllieBot/Modules/Utility/Ai/IAiAssistantService.cs
new file mode 100644
index 0000000..0fc17e2
--- /dev/null
+++ b/src/EllieBot/Modules/Utility/Ai/IAiAssistantService.cs
@@ -0,0 +1,20 @@
+using OneOf;
+
+namespace EllieBot.Modules.Utility;
+
+public interface IAiAssistantService
+{
+    Task<OneOf<EllieCommandCallModel, GetCommandErrorResult>> TryGetCommandAsync(
+        ulong userId,
+        string prompt,
+        IReadOnlyCollection<AiCommandModel> commands,
+        string prefix);
+
+    IReadOnlyCollection<AiCommandModel> GetCommands();
+
+    Task<bool> TryExecuteAiCommand(
+        IGuild guild,
+        IUserMessage msg,
+        ITextChannel channel,
+        string query);
+}
\ No newline at end of file
diff --git a/src/EllieBot/Modules/Utility/Ai/UtilityCommands.cs b/src/EllieBot/Modules/Utility/Ai/UtilityCommands.cs
new file mode 100644
index 0000000..52fe4d5
--- /dev/null
+++ b/src/EllieBot/Modules/Utility/Ai/UtilityCommands.cs
@@ -0,0 +1,23 @@
+using EllieBot.Modules.Administration;
+
+namespace EllieBot.Modules.Utility;
+
+public partial class UtilityCommands
+{
+    public class PromptCommands : EllieModule<IAiAssistantService>
+    {
+        [Cmd]
+        [RequireContext(ContextType.Guild)]
+        public async Task Prompt([Leftover] string query)
+        {
+            await ctx.Channel.TriggerTypingAsync();
+            var res = await _service.TryExecuteAiCommand(ctx.Guild, ctx.Message, (ITextChannel)ctx.Channel, query);
+        }
+
+        private string GetCommandString(EllieCommandCallModel res)
+            => $"{_bcs.Data.Prefix}{res.Name} {res.Arguments.Select((x, i) => GetParamString(x, i + 1 == res.Arguments.Count)).Join(" ")}";
+
+        private static string GetParamString(string val, bool isLast)
+            => isLast ? val : "\"" + val + "\"";
+    }
+}
\ No newline at end of file
diff --git a/src/EllieBot/Modules/Utility/Calc/CalcCommand.cs b/src/EllieBot/Modules/Utility/Calc/CalcCommands.cs
similarity index 100%
rename from src/EllieBot/Modules/Utility/Calc/CalcCommand.cs
rename to src/EllieBot/Modules/Utility/Calc/CalcCommands.cs
diff --git a/src/EllieBot/Modules/Utility/ConfigCommands.cs b/src/EllieBot/Modules/Utility/ConfigCommands.cs
index 28f9772..57b8f4c 100644
--- a/src/EllieBot/Modules/Utility/ConfigCommands.cs
+++ b/src/EllieBot/Modules/Utility/ConfigCommands.cs
@@ -1,4 +1,4 @@
-#nullable disable
+#nullable disable
 namespace EllieBot.Modules.Utility;
 
 public partial class Utility
@@ -138,12 +138,12 @@ public partial class Utility
         private string GetPropsAndValuesString(IConfigService config, IReadOnlyCollection<string> names)
         {
             var propValues = names.Select(pr =>
-            {
-                var val = config.GetSetting(pr);
-                if (pr != "currency.sign")
-                    val = val?.TrimTo(28);
-                return val?.Replace("\n", "") ?? "-";
-            })
+                                  {
+                                      var val = config.GetSetting(pr);
+                                      if (pr != "currency.sign")
+                                          val = val?.TrimTo(28);
+                                      return val?.Replace("\n", "") ?? "-";
+                                  })
                                   .ToList();
 
             var strings = names.Zip(propValues, (name, value) => $"{name,-25} = {value}\n");
diff --git a/src/EllieBot/Modules/Utility/Giveaway/GiveawayCommands.cs b/src/EllieBot/Modules/Utility/Giveaway/GiveawayCommands.cs
index a2ebf58..2109eef 100644
--- a/src/EllieBot/Modules/Utility/Giveaway/GiveawayCommands.cs
+++ b/src/EllieBot/Modules/Utility/Giveaway/GiveawayCommands.cs
@@ -48,30 +48,30 @@ public partial class Utility
         [UserPerm(GuildPerm.ManageMessages)]
         public async Task GiveawayEnd(kwum id)
         {
-            var success = await _service.EndGiveawayAsync(ctx.Guild.Id, id);
+           var success = await _service.EndGiveawayAsync(ctx.Guild.Id, id);
 
-            if (!success)
-            {
-                await Response().Error(strs.giveaway_not_found).SendAsync();
-                return;
-            }
+           if(!success)
+           {
+               await Response().Error(strs.giveaway_not_found).SendAsync();
+               return;
+           }
 
-            await ctx.OkAsync();
+           await ctx.OkAsync();
             _ = ctx.Message.DeleteAfter(5);
         }
 
         [Cmd]
         [UserPerm(GuildPerm.ManageMessages)]
         public async Task GiveawayReroll(kwum id)
-        {
+        { 
             var success = await _service.RerollGiveawayAsync(ctx.Guild.Id, id);
             if (!success)
             {
                 await Response().Error(strs.giveaway_not_found).SendAsync();
                 return;
             }
-
-
+            
+            
             await ctx.OkAsync();
             _ = ctx.Message.DeleteAfter(5);
         }
diff --git a/src/EllieBot/Modules/Utility/GuildColors.cs b/src/EllieBot/Modules/Utility/GuildColors.cs
index bf50902..7f787e6 100644
--- a/src/EllieBot/Modules/Utility/GuildColors.cs
+++ b/src/EllieBot/Modules/Utility/GuildColors.cs
@@ -4,7 +4,7 @@ namespace EllieBot.Modules.Utility;
 
 public interface IGuildColorsService
 {
-
+    
 }
 
 public sealed class GuildColorsService : IGuildColorsService, IEService
@@ -34,6 +34,6 @@ public partial class Utility
 {
     public class GuildColorsCommands : EllieModule<IGuildColorsService>
     {
-
+        
     }
 }
\ No newline at end of file
diff --git a/src/EllieBot/Modules/Utility/Info/InfoCommands.cs b/src/EllieBot/Modules/Utility/Info/InfoCommands.cs
index 87b8aa1..e2533e0 100644
--- a/src/EllieBot/Modules/Utility/Info/InfoCommands.cs
+++ b/src/EllieBot/Modules/Utility/Info/InfoCommands.cs
@@ -1,4 +1,4 @@
-#nullable disable
+#nullable disable
 using System.Text;
 using EllieBot.Modules.Patronage;
 
@@ -34,7 +34,7 @@ public partial class Utility
         {
             var guild = (IGuild)_client.GetGuild(guildId)
                         ?? await _client.Rest.GetGuildAsync(guildId);
-
+            
             if (guild is null)
                 return;
 
@@ -144,9 +144,9 @@ public partial class Utility
                      true)
                  .WithOkColor();
 
-            var patron = await _ps.GetPatronAsync(user.Id);
+            var mPatron = await _ps.GetPatronAsync(user.Id);
 
-            if (patron.Tier != PatronTier.None)
+            if (mPatron is {} patron && patron.Tier != PatronTier.None)
             {
                 embed.WithFooter(patron.Tier switch
                 {
diff --git a/src/EllieBot/Modules/Utility/Invite/InviteService.cs b/src/EllieBot/Modules/Utility/Invite/InviteService.cs
index aa6946b..d89ec28 100644
--- a/src/EllieBot/Modules/Utility/Invite/InviteService.cs
+++ b/src/EllieBot/Modules/Utility/Invite/InviteService.cs
@@ -1,4 +1,4 @@
-#nullable disable
+#nullable disable
 using CommandLine;
 
 namespace EllieBot.Modules.Utility.Services;
@@ -45,4 +45,4 @@ public class InviteService : IEService
                 Expire = 0;
         }
     }
-}
+}
\ No newline at end of file
diff --git a/src/EllieBot/Modules/Utility/Quote/IQuoteService.cs b/src/EllieBot/Modules/Utility/Quote/IQuoteService.cs
index 55dc96b..ccf360e 100644
--- a/src/EllieBot/Modules/Utility/Quote/IQuoteService.cs
+++ b/src/EllieBot/Modules/Utility/Quote/IQuoteService.cs
@@ -3,4 +3,4 @@
 public interface IQuoteService
 {
     Task<int> DeleteAllAuthorQuotesAsync(ulong guildId, ulong userId);
-}
+}
\ No newline at end of file
diff --git a/src/EllieBot/Modules/Utility/Quote/QuoteCommands.cs b/src/EllieBot/Modules/Utility/Quote/QuoteCommands.cs
index cea5914..913781b 100644
--- a/src/EllieBot/Modules/Utility/Quote/QuoteCommands.cs
+++ b/src/EllieBot/Modules/Utility/Quote/QuoteCommands.cs
@@ -1,4 +1,4 @@
-#nullable disable warnings
+#nullable disable warnings
 using LinqToDB;
 using LinqToDB.EntityFrameworkCore;
 using EllieBot.Common.Yml;
@@ -157,8 +157,8 @@ public partial class Utility
                 async (sm) =>
                 {
                     var msg = sm.Data.Components.FirstOrDefault()?.Value;
-
-                    if (!string.IsNullOrWhiteSpace(msg))
+                    
+                    if(!string.IsNullOrWhiteSpace(msg)) 
                         await QuoteEdit(id, msg);
                 }
             );
@@ -307,7 +307,7 @@ public partial class Utility
                                       .UpdateWithOutputAsync((del, ins) => ins);
 
                 q = result.FirstOrDefault();
-
+                
                 await uow.SaveChangesAsync();
             }
 
diff --git a/src/EllieBot/Modules/Utility/Quote/QuoteService.cs b/src/EllieBot/Modules/Utility/Quote/QuoteService.cs
index bebed66..db49648 100644
--- a/src/EllieBot/Modules/Utility/Quote/QuoteService.cs
+++ b/src/EllieBot/Modules/Utility/Quote/QuoteService.cs
@@ -1,4 +1,4 @@
-#nullable disable warnings
+#nullable disable warnings
 using LinqToDB;
 using LinqToDB.EntityFrameworkCore;
 using EllieBot.Db.Models;
@@ -13,7 +13,7 @@ public sealed class QuoteService : IQuoteService, IEService
     {
         _db = db;
     }
-
+    
     /// <summary>
     /// Delete all quotes created by the author in a guild
     /// </summary>
diff --git a/src/EllieBot/Modules/Utility/Remind/RemindCommands.cs b/src/EllieBot/Modules/Utility/Remind/RemindCommands.cs
index 8a414dc..67b87af 100644
--- a/src/EllieBot/Modules/Utility/Remind/RemindCommands.cs
+++ b/src/EllieBot/Modules/Utility/Remind/RemindCommands.cs
@@ -113,10 +113,9 @@ public partial class Utility
                 foreach (var rem in rems)
                 {
                     var when = rem.When;
-                    var diff = when - DateTime.UtcNow;
                     embed.AddField(
                         $"#{++i + (page * 10)} {rem.When:HH:mm yyyy-MM-dd} UTC "
-                        + $"(in {diff.ToPrettyStringHm()})",
+                        + $"{TimestampTag.FromDateTime(when)}",
                         $@"`Target:` {(rem.IsPrivate ? "DM" : "Channel")}
 `TargetId:` {rem.ChannelId}
 `Message:` {rem.Message?.TrimTo(50)}");
@@ -203,16 +202,15 @@ public partial class Utility
                 await uow.SaveChangesAsync();
             }
 
-            var gTime = ctx.Guild is null ? time : TimeZoneInfo.ConvertTime(time, _tz.GetTimeZoneOrUtc(ctx.Guild.Id));
+            // var gTime = ctx.Guild is null ? time : TimeZoneInfo.ConvertTime(time, _tz.GetTimeZoneOrUtc(ctx.Guild.Id));
             try
             {
                 await Response()
-                      .Confirm($"\u23f0 {GetText(strs.remind(
+                      .Confirm($"\u23f0 {GetText(strs.remind2(
                           Format.Bold(!isPrivate ? $"<#{targetId}>" : ctx.User.Username),
                           Format.Bold(message),
-                          ts.ToPrettyStringHm(),
-                          gTime,
-                          gTime))}")
+                          TimestampTag.FromDateTime(DateTime.UtcNow.Add(ts), TimestampTagStyles.Relative),
+                          TimestampTag.FormatFromDateTime(time, TimestampTagStyles.ShortDateTime)))}")
                       .SendAsync();
             }
             catch
diff --git a/src/EllieBot/Modules/Utility/Repeater/RepeaterService.cs b/src/EllieBot/Modules/Utility/Repeater/RepeaterService.cs
index 6adb2c0..07d05cc 100644
--- a/src/EllieBot/Modules/Utility/Repeater/RepeaterService.cs
+++ b/src/EllieBot/Modules/Utility/Repeater/RepeaterService.cs
@@ -273,7 +273,7 @@ public sealed class RepeaterService : IReadyExecutor, IEService
                                       .Text(text)
                                       .Sanitize(false)
                                       .SendAsync();
-
+            
             _ = newMsg.AddReactionAsync(new Emoji("🔄"));
 
             if (_noRedundant.Contains(repeater.Id))
diff --git a/src/EllieBot/Modules/Utility/Repeater/RunningRepeater.cs b/src/EllieBot/Modules/Utility/Repeater/RunningRepeater.cs
index 52f4072..509347f 100644
--- a/src/EllieBot/Modules/Utility/Repeater/RunningRepeater.cs
+++ b/src/EllieBot/Modules/Utility/Repeater/RunningRepeater.cs
@@ -1,4 +1,4 @@
-#nullable disable
+#nullable disable
 using EllieBot.Db.Models;
 
 namespace EllieBot.Modules.Utility.Services;
diff --git a/src/EllieBot/Modules/Utility/StreamRole/StreamRoleService.cs b/src/EllieBot/Modules/Utility/StreamRole/StreamRoleService.cs
index 1b5796a..4ded9d0 100644
--- a/src/EllieBot/Modules/Utility/StreamRole/StreamRoleService.cs
+++ b/src/EllieBot/Modules/Utility/StreamRole/StreamRoleService.cs
@@ -30,7 +30,7 @@ public class StreamRoleService : IReadyExecutor, IEService
 
     private Task OnPresenceUpdate(SocketUser user, SocketPresence? oldPresence, SocketPresence? newPresence)
     {
-
+        
         _ = Task.Run(async () =>
         {
             if (oldPresence?.Activities?.Count != newPresence?.Activities?.Count)
diff --git a/src/EllieBot/Modules/Utility/Todo/TodoService.cs b/src/EllieBot/Modules/Utility/Todo/TodoService.cs
index 72a7d13..38ea848 100644
--- a/src/EllieBot/Modules/Utility/Todo/TodoService.cs
+++ b/src/EllieBot/Modules/Utility/Todo/TodoService.cs
@@ -140,7 +140,7 @@ public sealed class TodoService : IEService
 
             return ArchiveTodoResult.NoTodos;
         }
-
+        
         await tr.CommitAsync();
 
         return ArchiveTodoResult.Success;
@@ -183,7 +183,7 @@ public sealed class TodoService : IEService
     public async Task<TodoModel?> GetTodoAsync(ulong userId, int todoId)
     {
         await using var ctx = _db.GetDbContext();
-
+        
         return await ctx
             .GetTable<TodoModel>()
             .Where(x => x.UserId == userId && x.Id == todoId)
diff --git a/src/EllieBot/Modules/Utility/UnitConversion/ConverterService.cs b/src/EllieBot/Modules/Utility/UnitConversion/ConverterService.cs
index 85c299d..12d9f8e 100644
--- a/src/EllieBot/Modules/Utility/UnitConversion/ConverterService.cs
+++ b/src/EllieBot/Modules/Utility/UnitConversion/ConverterService.cs
@@ -63,20 +63,20 @@ public class ConverterService : IEService, IReadyExecutor
             UnitType = unitTypeString
         };
         var units = currencyRates.ConversionRates.Select(u => new ConvertUnit
-        {
-            Triggers = [u.Key],
-            Modifier = u.Value,
-            UnitType = unitTypeString
-        })
+                                 {
+                                     Triggers = [u.Key],
+                                     Modifier = u.Value,
+                                     UnitType = unitTypeString
+                                 })
                                  .ToList();
 
-        var stream = File.OpenRead("data/units.json");
+        var stream =  File.OpenRead("data/units.json");
         var defaultUnits = await JsonSerializer.DeserializeAsync<ConvertUnit[]>(stream);
-        if (defaultUnits is not null)
+        if(defaultUnits is not null)
             units.AddRange(defaultUnits);
-
+        
         units.Add(baseType);
-
+        
         await _cache.AddAsync(_convertKey, units);
     }
 
@@ -90,7 +90,7 @@ public class Rates
 {
     [JsonPropertyName("base")]
     public string Base { get; set; }
-
+    
     [JsonPropertyName("date")]
     public DateTime Date { get; set; }
 
diff --git a/src/EllieBot/Modules/Utility/Utility.cs b/src/EllieBot/Modules/Utility/Utility.cs
index 1c53f8c..7382403 100644
--- a/src/EllieBot/Modules/Utility/Utility.cs
+++ b/src/EllieBot/Modules/Utility/Utility.cs
@@ -1,4 +1,4 @@
-#nullable disable
+#nullable disable
 using EllieBot.Modules.Utility.Services;
 using Newtonsoft.Json;
 using System.Diagnostics;
diff --git a/src/EllieBot/Modules/Utility/VerboseErrorsService.cs b/src/EllieBot/Modules/Utility/VerboseErrorsService.cs
index e80f889..c5cf886 100644
--- a/src/EllieBot/Modules/Utility/VerboseErrorsService.cs
+++ b/src/EllieBot/Modules/Utility/VerboseErrorsService.cs
@@ -58,7 +58,7 @@ public class VerboseErrorsService : IEService
         if (maybeEnabled is bool isEnabled) // set it
             gc.VerboseErrors = isEnabled;
         else // toggle it
-            isEnabled = gc.VerboseErrors = !gc.VerboseErrors;
+            isEnabled = gc.VerboseErrors = !gc.VerboseErrors; 
 
         uow.SaveChanges();
 
diff --git a/src/EllieBot/Modules/Utility/_common/ConvertUnit.cs b/src/EllieBot/Modules/Utility/_common/ConvertUnit.cs
index e38cbe4..b65fdea 100644
--- a/src/EllieBot/Modules/Utility/_common/ConvertUnit.cs
+++ b/src/EllieBot/Modules/Utility/_common/ConvertUnit.cs
@@ -1,4 +1,4 @@
-#nullable disable
+#nullable disable
 using System.Diagnostics;
 
 namespace EllieBot.Modules.Utility.Common;
diff --git a/src/EllieBot/Modules/Utility/_common/EvalGlobals.cs b/src/EllieBot/Modules/Utility/_common/EvalGlobals.cs
index ffe3ecd..a31c056 100644
--- a/src/EllieBot/Modules/Utility/_common/EvalGlobals.cs
+++ b/src/EllieBot/Modules/Utility/_common/EvalGlobals.cs
@@ -1,4 +1,4 @@
-// ReSharper disable InconsistentNaming
+// ReSharper disable InconsistentNaming
 #nullable disable
 namespace EllieBot.Modules.Utility;
 
diff --git a/src/EllieBot/Modules/Utility/_common/Exceptions/StreamRoleNotFoundException.cs b/src/EllieBot/Modules/Utility/_common/Exceptions/StreamRoleNotFoundException.cs
index 45e007e..d1880b2 100644
--- a/src/EllieBot/Modules/Utility/_common/Exceptions/StreamRoleNotFoundException.cs
+++ b/src/EllieBot/Modules/Utility/_common/Exceptions/StreamRoleNotFoundException.cs
@@ -1,4 +1,4 @@
-#nullable disable
+#nullable disable
 namespace EllieBot.Modules.Utility.Common.Exceptions;
 
 public class StreamRoleNotFoundException : Exception
@@ -8,13 +8,13 @@ public class StreamRoleNotFoundException : Exception
     {
     }
 
-    public StreamRoleNotFoundException(string message) 
+    public StreamRoleNotFoundException(string message)
         : base(message)
     {
     }
 
-    public StreamRoleNotFoundException(string message, Exception innerException) 
+    public StreamRoleNotFoundException(string message, Exception innerException)
         : base(message, innerException)
     {
     }
-}
+}
\ No newline at end of file
diff --git a/src/EllieBot/Modules/Utility/_common/Exceptions/StreamRolePermissionException.cs b/src/EllieBot/Modules/Utility/_common/Exceptions/StreamRolePermissionException.cs
index 97fd187..d75c53c 100644
--- a/src/EllieBot/Modules/Utility/_common/Exceptions/StreamRolePermissionException.cs
+++ b/src/EllieBot/Modules/Utility/_common/Exceptions/StreamRolePermissionException.cs
@@ -1,4 +1,4 @@
-#nullable disable
+#nullable disable
 namespace EllieBot.Modules.Utility.Common.Exceptions;
 
 public class StreamRolePermissionException : Exception
diff --git a/src/EllieBot/Modules/Utility/_common/StreamRoleListType.cs b/src/EllieBot/Modules/Utility/_common/StreamRoleListType.cs
index 775b346..aca487b 100644
--- a/src/EllieBot/Modules/Utility/_common/StreamRoleListType.cs
+++ b/src/EllieBot/Modules/Utility/_common/StreamRoleListType.cs
@@ -1,4 +1,4 @@
-#nullable disable
+#nullable disable
 namespace EllieBot.Modules.Utility.Common;
 
 public enum StreamRoleListType