Commands
Prefix Commands
Create a command that responds to a prefix like !. The message object and an args table are passed to your handler.
-- Basic command
client:CreateCommand("ping", function(message, args)
message:Reply("Pong!")
end)
-- With arguments: !say hello world
client:CreateCommand("say", function(message, args)
-- args[1] = "hello", args[2] = "world"
-- args.raw = "hello world"
message:Reply(args.raw)
end)
-- task.wait inside commands
client:CreateCommand("countdown", function(message, args)
message:Reply("3...")
silicord.task.wait(1)
message:Reply("2...")
silicord.task.wait(1)
message:Reply("1... Go!")
end)
Slash Commands
Requires app_id in your Connect config. Supported argument types: string, integer, number, bool, user, channel, role, any.
client:CreateSlashCommand("ban", {
description = "Ban a user from the server",
options = {
{ name = "user", description = "The user to ban", type = "user", required = true },
{ name = "reason", description = "Reason for the ban", type = "string", required = false }
}
}, function(interaction, args)
interaction:Reply("Banned " .. args.user .. ". Reason: " .. (args.reason or "none"))
end)
Error Handling
Listen to client.OnError to catch command errors without crashing the bot. The signal fires with an error type string, the context object, the command name, and the error message.
client.OnError:Connect(function(error_type, ctx, name, detail)
if error_type == "CommandNotFound" then
ctx:Reply("❌ Unknown command `!" .. name .. "`.")
elseif error_type == "MissingArgument" then
ctx:Reply("❌ Missing argument for `!" .. name .. "`.")
elseif error_type == "CommandError" then
ctx:Reply("❌ Something went wrong running `!" .. name .. "`.")
print("CommandError in !" .. name .. ": " .. detail)
elseif error_type == "SlashCommandError" then
ctx:Reply("❌ Something went wrong running `/" .. name .. "`.")
elseif error_type == "ComponentError" then
print("ComponentError in " .. name .. ": " .. detail)
elseif error_type == "UnknownInteraction" then
ctx:Reply("❌ Unknown slash command.")
end
end)
CommandNotFoundMissingArgumentCommandErrorSlashCommandErrorComponentErrorUnknownInteractionMessage Object
The message object is passed to every prefix command handler.
message:Reply() and message:Send() now return a Message object, so you can chain edits, reactions, or deletes on the sent message.message:Reply(text)message:Reply(text, embed)message:Reply(text, embed, components)message:Send(text)message:Send(text, embed)message:Send(text, embed, components)message:Edit(text)message:React("👍")message:Unreact("👍") v1.2.0message:Delete()message:Pin()message:Unpin()message:GetGuild()message:GetMember()message:SendPrivateMessage(text)message:SendPrivateMessage(text, embed)Chaining on returned Message v1.2.0
-- Edit the reply after a delay
client:CreateCommand("temp", function(message, args)
local response = message:Reply("Processing...")
silicord.task.wait(3)
response:Edit("Done! ✅")
end)
-- Auto-delete the bot response
client:CreateCommand("autodelete", function(message, args)
local response = message:Send("This disappears in 5 seconds.")
silicord.task.delay(5, function()
response:Delete()
end)
end)
message.author
message.author.id -- user ID
message.author.username -- username
message.author.bot -- true if the author is a bot
Interaction Object
Passed to slash command handlers and component callbacks.
interaction:Reply(text)interaction:Reply(text, embed)interaction:Reply(text, embed, components)interaction:Update(text)interaction:Update(text, embed, components)interaction:GetGuild()interaction:GetMember()interaction:SendPrivateMessage(text)interaction:SendPrivateMessage(text, embed)interaction.argsinteraction.valuesinteraction.authorinteraction.custom_idinteraction.guild_idinteraction.channel_idMember Object
Get a member from a message, interaction, or guild.
local member = message:GetMember()
local member = interaction:GetMember()
local member = guild:GetMember(user_id)
member:Kick(reason)member:Ban(reason, delete_days)member:Timeout(seconds, reason)Enum.PunishmentLength valuemember:RemoveTimeout()member:GiveRole(role_id)member:RemoveRole(role_id)member:SetNickname(nick)member:ResetNickname()member:SendDM(text)member:SendDM(text, embed)member:GetStatus() v1.2.0Enum.UserStatusInGuild value: checks if banned, timed out, or presentTimeout & status with Enum v1.2.0
-- Raw seconds still work
member:Timeout(300, "Spamming")
-- Enum.PunishmentLength values (v1.2.0+)
member:Timeout(silicord.Enum.PunishmentLength["5Minutes"], "Spamming")
member:Timeout(silicord.Enum.PunishmentLength["1Hour"])
member:Timeout(silicord.Enum.PunishmentLength.Permanent, "Repeated violations")
-- Check member status (v1.2.0+)
local status = member:GetStatus()
if status == silicord.Enum.UserStatusInGuild.Banned then
ctx:Reply("That user is already banned.")
end
member properties
member.id -- user ID
member.username -- username
member.nickname -- server nickname (nil if not set)
member.roles -- table of role IDs
member.user -- raw Discord user object
Guild Object
Get a guild from any message or interaction.
local guild = message:GetGuild()
-- guild.id, guild.name
guild:CreateChannel(name, kind, options)kind accepts a string name or Enum.ChannelType valueguild:EditChannel(channel_id, options)guild:DeleteChannel(channel_id)guild:CreateRole(name, color, permissions)guild:EditRole(role_id, options)guild:DeleteRole(role_id)guild:GetMembers(limit)guild:GetMember(user_id)guild:GetRandomMember()guild:GetChannels()guild:GetRoles()guild:KickMember(user_id, reason)guild:BanMember(user_id, reason)guild:CreateEvent(options)guild:EditEvent(event_id, options)guild:DeleteEvent(event_id)guild:GetEvents()guild:Edit(options)Channel types
-- String names
guild:CreateChannel("general", "text")
guild:CreateChannel("General", "voice")
guild:CreateChannel("Info", "category")
guild:CreateChannel("news", "announcement")
guild:CreateChannel("Stage", "stage")
guild:CreateChannel("help", "forum")
guild:CreateChannel("media", "media")
-- Enum.ChannelType values (v1.2.0+)
guild:CreateChannel("general", silicord.Enum.ChannelType.Text)
guild:CreateChannel("Music", silicord.Enum.ChannelType.Voice)
-- With options
guild:CreateChannel("general", "text", {
topic = "General chat",
parent_id = "category_channel_id",
nsfw = false,
slowmode = 5
})
guild:CreateChannel("Music", "voice", {
bitrate = 64000,
user_limit = 10
})
Scheduled Events
guild:CreateEvent({
name = "Game Night",
description = "Monthly game night!",
type = "external", -- "stage", "voice", or "external"
location = "Discord Stage", -- for "external" type
start_time = "2025-09-01T20:00:00Z",
end_time = "2025-09-01T23:00:00Z"
})
guild:CreateEvent({
name = "Community Call",
type = "stage",
channel_id = "stage_channel_id",
start_time = "2025-09-01T20:00:00Z",
end_time = "2025-09-01T21:00:00Z"
})
guild:EditEvent(event_id, { name = "Updated Name" })
guild:DeleteEvent(event_id)
local events = guild:GetEvents()
Embeds
OOP API v1.0.0+
The preferred way to build embeds in v1.0.0+. Use silicord.Instance.new("Embed") for a clean, chainable builder. Pass a Color3 object directly to .Color
local embed = silicord.Instance.new("Embed")
embed.Title = "My Embed"
embed.Description = "This is the description."
embed.Color = silicord.Color3.fromRGB(88, 101, 242)
embed.Url = "https://example.com"
embed.Timestamp = os.date("!%Y-%m-%dT%H:%M:%SZ")
embed.Author = "Author Name"
embed.AuthorIcon = "https://example.com/icon.png"
embed.AuthorUrl = "https://example.com"
embed.Footer = "Footer text"
embed.FooterIcon = "https://example.com/icon.png"
embed.Image = "https://example.com/image.png"
embed.Thumbnail = "https://example.com/thumb.png"
embed:AddField("Field 1", "Value 1", true)
embed:AddField("Field 2", "Value 2", false)
message:Reply("Here is info:", embed:Build())
embed.Titleembed.Descriptionembed.ColorColor3 objectembed.Urlembed.Timestampembed.Author / .AuthorIcon / .AuthorUrlembed.Footer / .FooterIconembed.Image / .Thumbnailembed:AddField(name, value, inline)embed:Build():Reply() etc.Table syntax deprecated
silicord.Embed({ ... }) still works but prints a runtime warning. Migrate to silicord.Instance.new("Embed") shown above. This helper will be removed in a future major version.-- ⚠ DEPRECATED — use silicord.Instance.new("Embed") instead
local embed = silicord.Embed({
title = "My Embed",
description = "This is the description.",
color = "#5865F2"
})
message:Reply(embed)
Color3
A Roblox-style color class. In v1.0.0+, Color3 objects can be passed directly to any .Color / color field.
local c = silicord.Color3.fromRGB(88, 101, 242)
local c = silicord.Color3.fromHex("#5865F2")
-- Pass directly to any color field (v1.0.0+)
embed.Color = silicord.Color3.fromHex("#57F287")
-- Use in guild:CreateRole
guild:CreateRole("Moderator", silicord.Color3.fromRGB(255, 165, 0))
-- Get the raw integer (rarely needed)
local int = c:ToInt()
Color3.fromRGB(r, g, b)Color3.fromHex(hex)"#RRGGBB" or "RRGGBB")color.r / .g / .bcolor:ToInt()Buttons & Select Menus
OOP API v1.0.0+
Use silicord.Instance.new() to build components and action rows with a chainable, object-oriented style.
client:CreateCommand("vote", function(message, args)
local yes = silicord.Instance.new("Button")
yes.Label = "Yes"
yes.Style = "success"
yes.CustomId = "vote_yes"
local no = silicord.Instance.new("Button")
no.Label = "No"
no.Style = "danger"
no.CustomId = "vote_no"
local row = silicord.Instance.new("ActionRow")
row:Add(yes)
row:Add(no)
message:Reply("Cast your vote!", nil, { row:Build() })
end)
client:CreateComponent("vote_yes", function(interaction)
interaction:Update("You voted Yes! ✅")
end)
Button properties
button.Label"Button")button.Style"primary", "secondary", "success", "danger", "link"button.CustomIdclient:CreateComponent()button.Url"link"-style buttonsbutton.Emoji"👍")button.Disabledtrue to disable the button (default: false)button:Build()Select Menus v1.0.0+
client:CreateCommand("color", function(message, args)
local menu = silicord.Instance.new("SelectMenu")
menu.CustomId = "color_pick"
menu.Placeholder = "Pick a color"
menu:AddOption("Red", "red", "A warm color")
menu:AddOption("Blue", "blue", "A cool color")
menu:AddOption("Green", "green", "A natural color")
local row = silicord.Instance.new("ActionRow")
row:Add(menu)
message:Reply("Choose a color:", nil, { row:Build() })
end)
client:CreateComponent("color_pick", function(interaction)
interaction:Update("You picked: **" .. interaction.values[1] .. "**")
end)
SelectMenu properties
menu.CustomIdclient:CreateComponent()menu.Placeholder"Select an option...")menu.MinValuesmenu.MaxValuesmenu:AddOption(label, value, desc, emoji, default)menu:Build()Legacy table syntax deprecated
silicord.Embed({ ... })→silicord.Instance.new("Embed")silicord.Button({ ... })→silicord.Instance.new("Button")silicord.SelectMenu({ ... })→silicord.Instance.new("SelectMenu")silicord.ActionRow(...)→silicord.Instance.new("ActionRow")silicord.DataStore("name")→silicord:GetService("DataStoreService"):GetDataStore("name")
-- ⚠ DEPRECATED
local row = silicord.ActionRow(
silicord.Button({ label = "Yes", style = "success", custom_id = "vote_yes" }),
silicord.Button({ label = "No", style = "danger", custom_id = "vote_no" })
)
GetService v1.2.0
silicord uses a service system inspired by Roblox's game:GetService(). Services are lazy-loaded so they are only created the first time you call GetService, saving memory.
local DS = silicord:GetService("DataStoreService")
local Http = silicord:GetService("HttpService")
local Presence = silicord:GetService("PresenceService")
local AI = silicord:GetService("AIService")
"DataStoreService""HttpService""PresenceService""AIService"Enum v1.2.0
Roblox-style enums for type-safe values throughout your bot.
Enum.Presence
silicord.Enum.Presence.Online -- "online"
silicord.Enum.Presence.Idle -- "idle"
silicord.Enum.Presence.DoNotDisturb -- "dnd"
silicord.Enum.Presence.Invisible -- "invisible"
Enum.ChannelType
silicord.Enum.ChannelType.Text -- 0
silicord.Enum.ChannelType.DM -- 1
silicord.Enum.ChannelType.Voice -- 2
silicord.Enum.ChannelType.GDM -- 3
silicord.Enum.ChannelType.Category -- 4
silicord.Enum.ChannelType.Announcement -- 5
silicord.Enum.ChannelType.Thread -- 11
silicord.Enum.ChannelType.Stage -- 13
silicord.Enum.ChannelType.Forum -- 15
silicord.Enum.ChannelType.Media -- 16
-- Pass directly to guild:CreateChannel()
guild:CreateChannel("general", silicord.Enum.ChannelType.Text)
guild:CreateChannel("Music", silicord.Enum.ChannelType.Voice)
Enum.Permissions
Permission bit values for role creation and checks. 26 permissions total.
silicord.Enum.Permissions.CreateInstantInvite -- 0x1
silicord.Enum.Permissions.KickMembers -- 0x2
silicord.Enum.Permissions.BanMembers -- 0x4
silicord.Enum.Permissions.Administrator -- 0x8
silicord.Enum.Permissions.ManageChannels -- 0x10
silicord.Enum.Permissions.ManageGuild -- 0x20
silicord.Enum.Permissions.AddReactions -- 0x40
silicord.Enum.Permissions.ViewAuditLog -- 0x80
silicord.Enum.Permissions.PrioritySpeaker -- 0x100
silicord.Enum.Permissions.Stream -- 0x200
silicord.Enum.Permissions.ReadMessages -- 0x400
silicord.Enum.Permissions.ViewChannel -- 0x400
silicord.Enum.Permissions.SendMessages -- 0x800
silicord.Enum.Permissions.SendTTSMessages -- 0x1000
silicord.Enum.Permissions.ManageMessages -- 0x2000
silicord.Enum.Permissions.EmbedLinks -- 0x4000
silicord.Enum.Permissions.AttachFiles -- 0x8000
silicord.Enum.Permissions.ReadMessageHistory -- 0x10000
silicord.Enum.Permissions.MentionEveryone -- 0x20000
silicord.Enum.Permissions.UseExternalEmojis -- 0x40000
silicord.Enum.Permissions.ViewGuildInsights -- 0x80000
silicord.Enum.Permissions.Connect -- 0x100000
silicord.Enum.Permissions.Speak -- 0x200000
silicord.Enum.Permissions.MuteMembers -- 0x400000
silicord.Enum.Permissions.DeafenMembers -- 0x800000
silicord.Enum.Permissions.MoveMembers -- 0x1000000
silicord.Enum.Permissions.UseVAD -- 0x2000000
silicord.Enum.Permissions.ChangeNickname -- 0x4000000
silicord.Enum.Permissions.ManageNicknames -- 0x8000000
silicord.Enum.Permissions.ManageRoles -- 0x10000000
silicord.Enum.Permissions.ManageWebhooks -- 0x20000000
silicord.Enum.Permissions.ManageExpressions -- 0x40000000
-- Create a role with a specific permission
guild:CreateRole("Admin", silicord.Color3.fromRGB(255, 0, 0), silicord.Enum.Permissions.Administrator)
Enum.PunishmentLength
Pre-defined timeout durations in seconds. Pass directly to member:Timeout().
silicord.Enum.PunishmentLength["1Minute"] -- 60
silicord.Enum.PunishmentLength["5Minutes"] -- 300
silicord.Enum.PunishmentLength["10Minutes"] -- 600
silicord.Enum.PunishmentLength["30Minutes"] -- 1800
silicord.Enum.PunishmentLength["1Hour"] -- 3600
silicord.Enum.PunishmentLength["6Hours"] -- 21600
silicord.Enum.PunishmentLength["12Hours"] -- 43200
silicord.Enum.PunishmentLength["1Day"] -- 86400
silicord.Enum.PunishmentLength["3Days"] -- 259200
silicord.Enum.PunishmentLength["1Week"] -- 604800
silicord.Enum.PunishmentLength.Permanent -- nil (no end date)
member:Timeout(silicord.Enum.PunishmentLength["30Minutes"], "Spamming")
member:Timeout(silicord.Enum.PunishmentLength.Permanent, "Repeated violations")
Enum.UserStatusInGuild
Returned by member:GetStatus().
silicord.Enum.UserStatusInGuild.None -- "none"
silicord.Enum.UserStatusInGuild.TimedOut -- "timed_out"
silicord.Enum.UserStatusInGuild.Kicked -- "kicked"
silicord.Enum.UserStatusInGuild.Banned -- "banned"
DataStoreService v1.2.0
JSON file-based key-value persistence. Each store saves to a <name>.datastore.json file. Calling GetDataStore("name") twice returns the same cached instance.
local DS = silicord:GetService("DataStoreService")
local db = DS:GetDataStore("PlayerData")
db:SetAsync("score_user123", 500)
local score = db:GetAsync("score_user123")
local new_score = db:IncrementAsync("score_user123", 10)
db:RemoveAsync("score_user123")
local keys = db:GetKeys()
for _, k in ipairs(keys) do
print(k, db:GetAsync(k))
end
name.datastore.json.corrupted_<timestamp> and the store resets. All writes use an atomic temp-file swap — a crash mid-write cannot corrupt your data. IncrementAsync resets non-numeric values to 0 with a warning instead of throwing.store:SetAsync(key, value)store:GetAsync(key)nil if missingstore:RemoveAsync(key)store:IncrementAsync(key, delta)delta to a numeric key (default +1)store:GetKeys()HttpService v1.2.0
Make outbound HTTP/HTTPS requests from your bot.
local Http = silicord:GetService("HttpService")
-- GET request
local body, code = Http:Get("https://api.example.com/data")
-- POST request
local body, code = Http:Post("https://api.example.com/submit", '{"key":"value"}')
-- Full control
local body, code = Http:Request("https://api.example.com", "PATCH", '{"x":1}', {
["X-Custom-Header"] = "abc"
})
Http:Get(url, headers?)body, status_codeHttp:Post(url, body, headers?)body, status_codeHttp:Request(url, method, body?, headers?)PresenceService v1.2.0
Set the bot's presence and activity text. Requires app_id in your Connect config.
local Presence = silicord:GetService("PresenceService")
Presence:SetPresence(client, {
presence = silicord.Enum.Presence.Online, -- Enum.Presence value
status = "Watching over the server!", -- text shown under the bot name
type = 3 -- 0=Playing, 1=Streaming, 2=Listening, 3=Watching, 5=Competing
})
presenceEnum.Presence value — status indicator (default: Online)statustype0=Playing, 1=Streaming, 2=Listening, 3=Watching, 5=Competing (default: 0)AIService v1.2.0 [BETA]
Connect an OpenAI-compatible AI to your bot. Works with OpenAI, Groq, and any provider using the /v1/chat/completions endpoint. THIS IS HEAVILY IN BETA TESTING.
local AI = silicord:GetService("AIService")
AI:Configure("sk-your-api-key-here", {
model = "gpt-4o", -- default: "gpt-3.5-turbo"
base_url = "https://api.openai.com/v1" -- change for other providers
})
client:CreateSlashCommand("ask", {
description = "Ask the AI a question",
options = {
{ name = "question", description = "Your question", type = "string", required = true }
}
}, function(interaction, args)
local reply = AI:Prompt(args.question, "You are a helpful Discord bot assistant.")
interaction:Reply(reply or "Sorry, I could not get a response.")
end)
AI:Configure(api_key, options?)model and base_urlAI:Prompt(prompt, system?)nil, error on failure)DataStore deprecated
JSON file-based persistence. Each store maps to a <name>.datastore.json file on disk. Stores are cached in memory after the first load — calling silicord.DataStore("name") twice returns the same instance.
silicord.DataStore("name") still works but prints a runtime warning. Migrate to silicord:GetService("DataStoreService"):GetDataStore("name") — the DataStore API methods are identical. See DataStoreService for full documentation.-- ⚠ DEPRECATED — use DataStoreService instead
local db = silicord.DataStore("PlayerData")
db:SetAsync("score_user123", 500)
local score = db:GetAsync("score_user123")
local new_score = db:IncrementAsync("score_user123", 10)
db:RemoveAsync("score_user123")
local keys = db:GetKeys()
for _, k in ipairs(keys) do
print(k, db:GetAsync(k))
end
store:SetAsync(key, value)store:GetAsync(key)nil if missingstore:RemoveAsync(key)store:IncrementAsync(key, delta)delta to a numeric key (default +1)store:GetKeys()Signal
A Roblox-style event system. Create custom signals to decouple different parts of your bot. client.OnMessage and client.OnError are built-in signals exposed by the client.
-- Create a custom signal
local mySignal = silicord.Signal.new()
-- Connect a listener (returns a connection)
local conn = mySignal:Connect(function(a, b)
print("Signal fired!", a, b)
end)
-- Fire the signal
mySignal:Fire("hello", 42)
-- Disconnect later
conn.Disconnect()
-- Yield until the signal fires (must be inside a coroutine)
silicord.task.spawn(function()
local a, b = mySignal:Wait()
print("Resumed with:", a, b)
end)
-- Built-in: listen to all non-command, non-bot messages
client.OnMessage:Connect(function(message)
print(message.author.username .. ": " .. message.content)
end)
Signal.new()signal:Connect(callback).Disconnect()signal:Fire(...)signal:Wait()Standard Libraries
silicord ships small utility modules that mirror Roblox's standard library extensions. They don't replace Lua's built-ins — they add helpers that Lua is missing.
silicord.math
silicord.math.clamp(n, min, max)n between min and maxsilicord.math.round(n)silicord.math.lerp(a, b, t)t in 0–1silicord.math.sign(n)1, -1, or 0silicord.table
silicord.table.find(t, value)value, or nilsilicord.table.contains(t, value)true if value is in the tablesilicord.table.keys(t)silicord.table.values(t)silicord.table.copy(t)silicord.string
silicord.string.split(str, sep)silicord.string.trim(str)silicord.string.startsWith(str, prefix)true if str starts with prefixsilicord.string.endsWith(str, suffix)true if str ends with suffixsilicord.string.pad(str, length, char)str to length with char (default: space)local clamped = silicord.math.clamp(150, 0, 100) -- 100
local lerped = silicord.math.lerp(0, 10, 0.5) -- 5.0
local parts = silicord.string.split("a,b,c", ",") -- {"a","b","c"}
local clean = silicord.string.trim(" hello ") -- "hello"
local idx = silicord.table.find({"a","b","c"}, "b") -- 2
local copy = silicord.table.copy(someTable)
CollectionService
A Roblox-style tag registry. Attach string tags to any Lua value (table, string, number, etc.) and query them later. Useful for flagging users, channels, or custom objects without storing extra state.
local cs = silicord.CollectionService
cs:AddTag(message.author.id, "admin")
cs:AddTag(message.author.id, "vip")
print(cs:HasTag(message.author.id, "admin")) -- true
local admins = cs:GetTagged("admin")
local tags = cs:GetTags(message.author.id) -- { "admin", "vip" }
cs:RemoveTag(message.author.id, "vip")
cs:AddTag(object, tag)cs:RemoveTag(object, tag)cs:HasTag(object, tag)true if the object has the tagcs:GetTagged(tag)cs:GetTags(object)Middleware
Middleware hooks run before every prefix command and slash command. Return false to block the command. Multiple middleware functions can be registered and run in order.
-- Cooldown (3 seconds per user per command)
local cooldowns = {}
client:AddMiddleware(function(ctx, cmd, args)
local key = ctx.author.id .. ":" .. cmd
if os.time() - (cooldowns[key] or 0) < 3 then
ctx:Reply("Slow down! Wait 3 seconds between commands.")
return false
end
cooldowns[key] = os.time()
end)
-- Admin-only guard using CollectionService tags
silicord.CollectionService:AddTag(nil, "ban", "AdminOnly")
silicord.CollectionService:AddTag(nil, "kick", "AdminOnly")
local ADMIN_ID = "123456789012345678"
client:AddMiddleware(function(ctx, cmd, args)
if silicord.CollectionService:HasTag(nil, cmd, "AdminOnly") then
if ctx.author.id ~= ADMIN_ID then
ctx:Reply("You do not have permission to use this command.")
return false
end
end
end)
Caching
silicord automatically caches guild and user data from Discord gateway events. message:GetGuild() checks the cache before making an HTTP request, avoiding unnecessary API calls.
client.cache.guilds -- raw guild data keyed by guild ID
client.cache.users -- raw user data keyed by user ID
client.cache.bot_user -- the bot's own user object (set after READY)
Sharding
Sharding is fully automatic. silicord fetches the recommended shard count from Discord on startup and spawns the correct number of gateway connections with the required 5-second delay between each. You don't need to configure anything.
task scheduler
Roblox-style async helpers available anywhere in your bot code. All functions run inside copas coroutines — they never block the gateway loop.
silicord.task.wait(n)n seconds; returns nsilicord.task.spawn(f, ...)f in a new coroutine immediatelysilicord.task.defer(f, ...) v1.0.0+f on the next scheduler cycle — useful for avoiding stack overflows in recursive patternssilicord.task.delay(n, f, ...) v1.0.0+f(...) after n seconds without blocking the caller — the clean way to write timers-- Pause inside any coroutine
silicord.task.wait(2)
-- Fire and forget a background thread
silicord.task.spawn(function()
silicord.task.wait(5)
print("5 seconds later")
end)
-- defer: runs after the current frame completes
silicord.task.defer(function()
print("deferred to next cycle")
end)
-- delay: clean one-shot timer
silicord.task.delay(10, function()
print("10 seconds have passed!")
end)
-- Practical: send a temp message that auto-deletes
client:CreateCommand("temp", function(message, args)
local response = message:Reply("This disappears in 5 seconds!")
silicord.task.delay(5, function()
response:Delete()
end)
end)
Changelog
silicord:GetService() with lazy-loaded DataStoreService, HttpService, PresenceService, and AIService.Enum:
Enum.Presence, Enum.ChannelType, Enum.Permissions, Enum.PunishmentLength, Enum.UserStatusInGuild.Message chaining:
message:Reply() and message:Send() now return a Message object.New methods:
message:Unreact(), member:GetStatus().Enum integration:
member:Timeout() accepts Enum.PunishmentLength (including Permanent); guild:CreateChannel() accepts Enum.ChannelType.Deprecated:
silicord.DataStore() — use DataStoreService:GetDataStore() instead.
OnMessage now fires correctly for plain messages; nil author guard for webhook/system messages; Signal fire snapshot safety; Signal:Wait coroutine guard; WebSocket large-frame header fix; GET request body fix; rate-limit retry cap; embed detection overhaul; ActionRow empty component guard; legacy ActionRow flatten fix; Lua 5.1 unpack compat shim; DataStore variable shadowing fix; Guild:CreateRole color fix; Message:Edit nil id guard; Run error type safety.
IncrementAsync now handles corrupt/empty/locked JSON without crashing; writes use atomic temp-file swapping; corrupt files are auto-backed-up.Color3 UX:
Color3 objects can be passed directly to all color fields — no more :ToInt().task.defer(): Defers a function to the next scheduler cycle to avoid stack overflows.
task.delay(): Clean one-shot timer — call a function after
n seconds without a manual loop.Instance.new("SelectMenu") and Instance.new("ActionRow"): OOP classes added to match Embed and Button.
Deprecation warnings:
silicord.Embed(), silicord.Button(), silicord.SelectMenu(), and silicord.ActionRow() now print runtime warnings. Migrate to silicord.Instance.new().
client.OnErrormessage:Send(), message:Edit(), message:Pin(), message:Unpin(); message:GetMember() and interaction:GetMember(); guild:Edit().client.cache), middleware system (client:AddMiddleware).message:React()), embeds, DMs, prefix command arguments, slash commands, task.wait().:Reply(), WebSocket gateway connection.