Scripting Guide
Lesson 1: Your First Agent
From an empty file to a running agent: the anatomy of an agent, how to upload it, and how to test it.
What an agent is
An agent is one JavaScript file with one job. The file is an ES module that exports a single async function. When the agent's event fires, GuildScript calls that function with three arguments:
| Argument | What it is |
|---|---|
payload | A snapshot of the event: the message, the member, the interaction, and so on. Its shape depends on the event (Lesson 2). |
db | Your MongoDB helper. Only useful once you have connected a database with /database (Lesson 9). |
llm | Your AI helper. Only useful once you have connected a provider with /llm (Lesson 11). |
You can name the function anything, and you can ignore the arguments you do not need. The runtime simply calls the first function your module exports.
Hello, server
This agent listens to the messageCreate event and answers a greeting. Save it as hello.js:
// One exported async function. For messageCreate, the payload IS the message.
export async function onMessage(message) {
// Always ignore bots first, including GuildScript itself.
// Without this line, an agent that replies to messages can loop forever.
if (message.author.bot) return;
// message.content is the raw text of the message.
if (message.content.toLowerCase() === "hello bot") {
// Every action is asynchronous: always await it.
await message.reply("Hello " + message.author.username + "!");
}
}Uploading it
- Run
/initializein your server if you have not already (one time only). - Run
/agentsand click Create New. - Name it (for example
Hello Agent), pick the event Message Create, optionally pick an error channel, and attachhello.js. - Submit. The agent is live immediately; there is no deploy step.
Expected behavior
Type hello bot in any channel the bot can see. The bot replies Hello <yourname>! within a moment. Any other message does nothing, and messages from bots are ignored entirely.
The rules every agent follows
- One file, one exported async function, one event. Multi-event features are built from multiple agents (Lesson 13).
- Await everything. Replies, reactions, database calls, AI calls. A run ends when your function returns; un-awaited work may never finish.
- No outside world. There is no
fetch, no file system, noprocess, nosetTimeout, and no npm packages. The only import that exists is"discord"(Lesson 6 onward uses it). - Time and memory are limited. A run gets 3.5 s and 20 MiB on Free (10 s and 96 MiB with Premium). Exceeding either aborts the run.
- Errors are reported, not shown inline. If your function throws, the error is posted to the agent's error channel, throttled to one report per two minutes per agent (Lesson 12).
Common pitfalls
- Forgetting `export`. A file with a plain
async function run() {}and noexportdoes nothing: the runtime finds no exported function. - Forgetting the bot check. An agent that replies to every message will reply to its own replies.
if (message.author.bot) return;is the first line of nearly every message agent. - Uploading the wrong event. The same file uploaded under
messageUpdatereceives a different payload shape and breaks. The event you select in the form is part of the agent. - Editing without re-uploading. Changing the file on your computer does nothing until you upload it again via
/agentsthen Update.
Exercise
Make the agent answer ping with pong, but only when the message is exactly ping. Then extend it: if the message is ping me, reply and also add a reaction to the original message with await message.react("\u{1F3D3}") (the table tennis emoji, written as a Unicode escape). Re-upload with Update after each change and test in a channel.