Los comandos de barra de mi bot no aparecen: sincronizarlos en discord.py y discord.js
Un comando con barra no aparece hasta que tu bot lo publica en Discord: definirlo en el código no basta. En discord.py se publica con tree.sync() y en discord.js con rest.put(Routes.applicationCommands…). Para probar, publícalo en tu servidor, que sale al momento; y si aun así no lo ves, mira el scope applications.commands y los permisos.
Por qué no aparecen: hay que publicarlos
Discord guarda la lista de comandos de cada bot. Tu código define los comandos y los atiende, pero la lista solo cambia cuando el bot la manda a Discord (sincronizar, o registrar). Si nunca la mandas, o la mandas antes de definir los comandos, en Discord no sale nada al escribir /.
Basta con publicarlos una vez y cada vez que cambies el nombre, la descripción o las opciones de un comando. Cambiar lo que hace por dentro no pide publicar otra vez. Ojo con el límite: Discord deja crear 200 comandos al día por servidor.
¿Prefieres no montarlo tú? Hosting de bots de Discord desde 1,50 € al mes, sin permanencia y con devolución íntegra en 72 horas. O crea un bot de Discord gratis, sin tarjeta.
Globales o de un servidor: cuánto tardan
Un comando se publica de dos formas. Global: sale en todos los servidores donde está tu bot (y en sus mensajes directos). De un servidor: solo en ese servidor, y no en mensajes directos.
Los de un servidor salen al momento, según la documentación de Discord, que recomienda usarlos para probar y pasar a globales cuando estén listos. Para los globales, la documentación de Discord ya no da plazo; el ejemplo oficial de discord.py dice que pueden tardar hasta una hora en llegar. Si un comando global no te sale, cierra y abre Discord antes de tocar nada.
Si publicas el mismo comando como global y en tu servidor, en tu servidor salen los dos (Discord lo permite). Cuando pases a globales, borra los de tu servidor como se explica abajo.
Sincronizar en discord.py: tree.sync()
En discord.py 2.7, los comandos con barra viven en el CommandTree (tree; con commands.Bot ya viene como bot.tree). tree.sync() publica los globales; tree.sync(guild=…) los de un servidor, y tree.copy_global_to(guild=…) copia antes los globales a tu servidor de pruebas para que salgan al momento.
Haz la sincronización en setup_hook, que se ejecuta una vez al arrancar y ya con los comandos definidos. En on_ready también funciona, pero on_ready puede repetirse en cada reconexión. El ID de tu servidor se copia con el modo desarrollador de Discord activado: clic derecho en el servidor → «Copiar ID del servidor».
import os
import discord
from discord import app_commands
from dotenv import load_dotenv
load_dotenv()
MI_SERVIDOR = discord.Object(id=int(os.environ["GUILD_ID"])) # tu servidor de pruebas
class MiBot(discord.Client):
def __init__(self):
super().__init__(intents=discord.Intents.default())
self.tree = app_commands.CommandTree(self)
async def setup_hook(self):
# Para probar: copia los comandos a tu servidor (salen al momento)
self.tree.copy_global_to(guild=MI_SERVIDOR)
publicados = await self.tree.sync(guild=MI_SERVIDOR)
print(f"Publicados {len(publicados)} comandos en tu servidor")
# Listos para todos: cambia las dos líneas de arriba por
# await self.tree.sync()
client = MiBot()
@client.tree.command(name="hola", description="Te saluda")
async def hola(interaction: discord.Interaction):
await interaction.response.send_message(f"¡Hola, {interaction.user.mention}!")
client.run(os.environ["DISCORD_TOKEN"])Registrar en discord.js: REST.put y Routes
En discord.js 14, los comandos se publican con una petición a la API: rest.put con Routes.applicationGuildCommands(id de la aplicación, id del servidor) para los de un servidor, o Routes.applicationCommands(id de la aplicación) para los globales. put cambia la lista entera por la que mandas: un comando que no esté en la lista se borra.
La guía oficial de discord.js lo hace en un script aparte que se ejecuta solo cuando cambias los comandos («node deploy-commands.js»), y no en cada arranque. Como solo habla con la API de Discord, puedes ejecutarlo en tu ordenador aunque el bot esté alojado en otro sitio. El id de la aplicación está en el portal, en «General Information» → «Application ID».
DISCORD_TOKEN=pega-aquí-tu-token
CLIENT_ID=el-application-id
GUILD_ID=el-id-de-tu-servidorrequire("dotenv").config();
const { REST, Routes, SlashCommandBuilder } = require("discord.js");
const comandos = [
new SlashCommandBuilder().setName("hola").setDescription("Te saluda"),
].map((c) => c.toJSON());
const rest = new REST().setToken(process.env.DISCORD_TOKEN);
(async () => {
// Para probar: solo en tu servidor (salen al momento)
const ruta = Routes.applicationGuildCommands(process.env.CLIENT_ID, process.env.GUILD_ID);
// Listos para todos: Routes.applicationCommands(process.env.CLIENT_ID)
const publicados = await rest.put(ruta, { body: comandos });
console.log(`Publicados ${publicados.length} comandos`);
})().catch(console.error);Publica los comandos
Con el .env relleno, «node deploy-commands.js». Tiene que decir «Publicados 1 comandos»; si da un error, léelo: suele ser el token, el id o el scope.
Atiéndelos en el bot
Tu index.js tiene que escuchar Events.InteractionCreate y contestar a cada comando (como en tu primer bot en JavaScript). Publicados pero sin atender, aparecen y dan error al usarlos.
Pruébalo con /
Escribe / en tu servidor y busca tu bot en la lista. Cuando funcione, cambia la ruta a Routes.applicationCommands y vuelve a ejecutar el script.
Sigue sin salir: el scope applications.commands
Para que un bot tenga comandos en un servidor, tiene que estar autorizado allí con el scope applications.commands. La documentación de Discord dice que el scope bot ya lo incluye; aun así, si al sincronizar en un servidor discord.py da un error Forbidden (su documentación lo atribuye a que falta ese scope) o discord.js da el error 50001 (Missing Access), vuelve a abrir el enlace de invitación con «bot» y «applications.commands» marcados. No hace falta echar al bot antes. Puedes sacar el enlace con la calculadora de permisos de bot.
Comprueba también que el GUILD_ID es el del servidor donde miras y el CLIENT_ID el de tu aplicación, no el de otra.
Lo ves tú pero no los demás: permisos «Usar comandos de aplicaciones»
Que alguien vea los comandos de tu bot depende de sus permisos, no de los del bot. Si su rol, o el canal, tiene denegado «Usar comandos de aplicaciones», no le salen. Revísalo en los ajustes del rol y en «Editar canal» → «Permisos».
Además, los administradores del servidor pueden limitar los comandos de cada bot por rol o canal en los ajustes del servidor → «Integraciones», y tu código puede pedir permisos para usar un comando (default_permissions en discord.py, setDefaultMemberPermissions en discord.js): quien no los tenga no lo ve. Prueba con una cuenta que no sea administradora, porque a un administrador le salen todos.
Comandos repetidos o viejos: cómo borrarlos
Si un comando sale dos veces es que está publicado como global y en tu servidor. Si sale uno que ya no existe en tu código, sigue en la lista de Discord. Se arregla publicando la lista buena otra vez, o una lista vacía donde sobran:
En discord.py, para vaciar los de tu servidor: tree.clear_commands(guild=MI_SERVIDOR) y después await tree.sync(guild=MI_SERVIDOR). En discord.js: rest.put(Routes.applicationGuildCommands(CLIENT_ID, GUILD_ID), { body: [] }). Los globales se borran igual con tree.sync() sin ese comando en el código o con Routes.applicationCommands.
Si tu bot está en NapNodes
La publicación de comandos es cosa de tu código: funciona igual en tu PC que alojado. En discord.py, el setup_hook de arriba publica al encender el bot, y su «Publicados N comandos» sale en la «Consola» del panel. En discord.js, ejecuta deploy-commands.js en tu ordenador, o publica desde el propio bot al arrancar como en tu primer bot en JavaScript. Si el bot ni siquiera se conecta, empieza por mi bot de Discord no responde.
Preguntas frecuentes
¿Cuánto tardan en salir los comandos con barra?
Los publicados en un servidor, al momento. Los globales pueden tardar más (el ejemplo oficial de discord.py habla de hasta una hora): para probar, publícalos en tu servidor.
¿Cómo sincronizo los comandos en discord.py?
Con await tree.sync() (globales) o await tree.sync(guild=…) (en un servidor), mejor dentro de setup_hook. Con commands.Bot es bot.tree.sync().
¿Cómo registro los comandos en discord.js?
Con rest.put(Routes.applicationGuildCommands(clientId, guildId), { body: comandos }) para un servidor o Routes.applicationCommands(clientId) para todos, normalmente en un script deploy-commands.js que se ejecuta al cambiar los comandos.
¿Por qué me salen los comandos repetidos?
Porque están publicados como globales y también en tu servidor. Borra los de tu servidor publicando una lista vacía en él.
Yo veo los comandos y mis amigos no, ¿por qué?
Por permisos: su rol o el canal tienen denegado «Usar comandos de aplicaciones», o el servidor limita los comandos de tu bot en «Integraciones». A un administrador le salen siempre todos.
¿Lo montamos?
Hosting de bots de Discord desde 1,50 € al mes, sin sobreventa: tu RAM es solo tuya. Y si quieres empezar sin pagar, tienes un bot de Discord gratis, sin tarjeta.
Herramienta gratis: Permisos de un bot de Discord. Marca los permisos de tu bot en castellano y sal con el número y el enlace de invitación; o pega un número y mira qué permisos da.