This example creates a small Node.js bot and uses the agent tools to upload it. You need your own Discord application and bot token. The host does not create that application for you. Give the agent read, manage and deploy scopes, keep tool approvals enabled, and read its proposed plan before it starts. The calls below are examples of arguments, not a request to paste a live secret into chat.
Prepare the project
Create a folder with package.json and index.js. This example uses the host's existing hello-bot dependency version and only the basic Guilds intent. Add commands and permissions later as your project requires. Keep secrets out of the repository and dependency manifests.
{
"name": "my-bot",
"version": "1.0.0",
"private": true,
"main": "index.js",
"dependencies": {
"discord.js": "14.21.0"
}
}const { Client, GatewayIntentBits } = require('discord.js');
const client = new Client({ intents: [GatewayIntentBits.Guilds] });
client.once('ready', () => console.log('BOT_READY'));
client.login(process.env.BOT_TOKEN).catch(() => {
console.error('Discord login failed. Check your saved token.');
process.exitCode = 1;
});Create and identify the bot
Call whoami, list_plans and list_bots. Choose a plan from the returned data, then call create_bot with name my-bot and runtime node. For Free, claim_free_bot returns a browser link; finish any email verification or captcha yourself. For a paid plan, include that plan's tier id and complete the returned Checkout link. The agent cannot pay it for you. Ask it to list bots again and use the new entry's id. The examples use PUBLIC_BOT_ID as a placeholder; replace it with that actual returned reference.
Upload the source
Approve writing package.json and index.js with write_file, passing the bot id, the absolute file path, the full file content and confirm equal to my-bot. These writes go through the same disk guards as the dashboard. Uploading an archive is also possible with upload_files, followed by extract_file; use the same explicit name confirmation and inspect the result before continuing. A full disk or unsafe archive is rejected rather than partially authorized by a different agent upload path.
{
"id": "PUBLIC_BOT_ID",
"path": "/index.js",
"content": "FULL_CONTENT_OF_INDEX_JS",
"confirm": "my-bot"
}Configure the token and start
Use your client's protected secret workflow to supply BOT_TOKEN to set_bot_token. That call also takes id and confirm. It never returns the credential. Set MAIN_FILE to index.js through set_env, confirm the current name, and approve the change. Starting installs the project's declared dependencies through the normal runtime startup. Call start, then get_status, get_usage and get_logs. Look for BOT_READY and a running state. A successful start acknowledgment alone does not establish a Discord gateway connection.
If startup fails, check the saved token, filename and dependency manifest before repeating anything. Enable privileged intents in Discord only if your code needs them; this example does not request them. Invite the application to a test server with the permissions your commands actually need. Never solve a crash loop by repeatedly forcing starts. Read the troubleshooting guide first.
Git and cleanup
Instead of file upload, connect_github can set the repository, branch and automatic startup updates. It needs manage and deploy scopes and exact-name confirmation. Free accepts public repositories only within the existing guards. Trigger deploy after approving the restart; complete optional push-webhook setup in your browser. Keep the project in your own repository as the durable source of truth. Revoke the agent token when finished. If you delete the bot later, inspect its current state and approve the exact-name delete call. A canceled subscription is not resumed by a recovery request.
Read the agent quickstart, tool reference, API reference, complete deployment example and troubleshooting guide.
Still stuck? Contact support