Scripting Guide

Vibe Coding with AI Agents

How to get AI tools to write working GuildScript agents: what to ask for, what context to provide, and how to fix scripts that do not work.

You do not have to write agents by hand. There are two ways to let an AI do it: the built-in /vibe-code-agent command, and any external AI assistant (ChatGPT, Claude, Copilot, and similar). Both produce a .js file that you upload through /agents. This page covers how to prompt either of them well.

Option 1: the built-in /vibe-code-agent command

The easiest path. Connect an AI provider with /llm (Groq, Mistral, or Gemini), then run:

/vibe-code-agent prompt: When someone says "welcome" in any channel, react to their message with a wave emoji.

Pick a provider from the buttons that appear. The bot already feeds the model a full description of the GuildScript API, the sandbox rules, and the output format, so you only describe the behavior you want. It returns up to 5 agent files, each labeled with the event to choose when uploading. Download each file, run /agents, click Create New, select the listed event, and upload.

Why multiple files?

One agent listens to one event. A feature like "post a button and respond when it is clicked" needs two agents: one on messageCreate to post the button and one on interactionCreate to handle the click. The vibe coder splits this for you automatically.

Option 2: external AI tools

Any capable AI assistant can write good agents, but only if you give it the right context. Out of the box, every model assumes you want a discord.js bot, which will not run in the GuildScript sandbox. Paste a context preamble like this at the start of your conversation:

Context to paste before your request
Write a GuildScript agent. GuildScript runs small JavaScript modules in a
sandbox. Rules:

- The file is an ES module that exports ONE async function. It is called as
  run(payload, db, llm). Do not create a Discord client, do not log in, and
  do not register event listeners.
- The only allowed import is: import { ... } from "discord";
  It provides EmbedBuilder, ActionRowBuilder, ButtonBuilder, ButtonStyle,
  StringSelectMenuBuilder, ModalBuilder, TextInputBuilder, TextInputStyle,
  formatters (bold, time, userMention, ...) and enums (ChannelType, Colors,
  PermissionFlagsBits, ...).
- There is NO require, NO fetch, NO fs, NO process, NO setTimeout/setInterval,
  and NO npm packages. Await every action.
- One agent handles ONE event. Payloads by event:
  - messageCreate: payload is the message (content, author, member, channel,
    guild, reply(), react(), delete()).
  - guildMemberAdd / guildMemberRemove: { member, guild }
  - guildMemberUpdate, messageUpdate: { before, after } (member update also
    has guild)
  - messageReactionAdd / messageReactionRemove: { reaction, emoji, message,
    user, guild }
  - channelCreate/channelDelete: { channel, guild }
  - roleCreate/roleDelete: { role, guild }
  - guildBanAdd/guildBanRemove: { user, reason, guild }
  - interactionCreate: the interaction (isButton(), customId, values, reply(),
    update(), showModal())
- Database: await db.findOne(coll, filter), db.find(coll, filter, opts),
  db.insertOne(coll, doc), db.updateOne(coll, filter, update, { upsert }),
  db.deleteOne(coll, filter), db.countDocuments(coll, filter). Mongo update
  operators like $set and $inc work.
- AI: const res = await llm.chat({ provider: "groq", messages: [...] });
  res.text is the reply.
- Custom IDs on buttons/menus must NOT start with: database:, agents:,
  agents_uninit:, llm:, standard_button:, docs:, help:, vibe:.
- In messageCreate agents, start with: if (message.author.bot) return;

My request: <describe what you want here>

You can also paste a working example from the lessons so the model sees the exact shape of a correct file.

How to describe what you want

  • Name the trigger. "When a member joins...", "When someone reacts with :star: ...", "When a message contains an invite link...". The trigger picks the event, and the event defines what data the agent gets.
  • Spell out the exact behavior, including the failure path: "...reply with an embed; if the user is a bot, do nothing."
  • Use IDs, not names, for specific things. "Post in the channel with ID 1234567890" is reliable; "post in #general" forces the AI to guess. Enable Developer Mode in Discord to copy IDs.
  • Mention persistence explicitly. "Store the count per user in the database" tells the AI to use db. Without it you may get a version that forgets everything between runs (agents keep no state in memory).
  • Keep one feature per request. Five small agents are easier to test and fix than one giant one.

Common prompting mistakes

MistakeWhat happensFix
Asking for "a discord.js bot"Code with new Client(), intents, and client.on(...) that cannot run in the sandboxSay "GuildScript agent" and paste the context preamble above
Asking for several events in one fileOne file with multiple listeners; only one function runsAsk for one file per event, or let /vibe-code-agent split them
Expecting npm packages or fetchrequire("axios") or fetch(...) fails at runtimeOnly import { ... } from "discord" exists; external HTTP is not available
Vague behavior ("make a leveling system")The AI invents rules you did not wantSpecify XP per message, level thresholds, announcement channel, and commands
Using timers ("after 5 minutes, unmute")setTimeout does not exist in the sandboxUse Discord-native timing (member.timeout(ms)) or store a timestamp in db and check it on a later event

Iterating on a broken script

  1. Set an error channel. When creating the agent in /agents, pick an error channel. Runtime errors arrive there as embeds with the agent name, the event, and the exception message.
  2. Copy the exact error back to the AI, together with the full current script: "This GuildScript agent throws the error below. Here is the file. Fix it and return the complete corrected file."
  3. Re-upload with Update. In /agents, select the agent, click Update, and attach the fixed file. The change is live immediately; trigger the event again to test.
  4. If nothing happens at all (no error, no effect), check the basics: is the agent on the right event, does the file export an async function, does the agent return early because of a condition (for example the bot-author check), and has the server's run quota been hit (/profile)?
  5. Watch for silent action failures. Discord actions in agents do not throw; a failed call returns an object with an error property. Ask the AI to check results and report failures, for example by replying with the error text while you debug.
Good iteration prompt

"The agent below runs on messageCreate. Expected: it deletes messages containing invite links and DMs the author. Actual: the message is deleted but no DM arrives, and the error channel shows nothing. Remember member.send() returns { error } on failure instead of throwing. Print the result of send to the channel temporarily and fix the bug. Return the full file."