This document provides comprehensive guidelines for AI agents (Roo, Cursor, etc.) working on the Vica Discord bot project.
- Project Overview
- Project Structure
- Working with Commands
- Working with Events
- Working with Core Modules
- Working with MCP Servers
- Code Style Guidelines
- Database Operations
- AI Integration
- Testing Guidelines
- Deployment
- Common Tasks
- Important Notes
- References
Purpose: Guide AI agents in understanding and working with the Vica Discord bot
Language: English (for code comments and documentation), Portuguese (for user-facing messages)
Project Context: Node.js Discord bot with AI features, deployed on Raspberry Pi 3b+
Key Technologies:
- Discord.js (v14)
- OpenAI API (GPT-4, embeddings, function calling)
- Model Context Protocol (MCP)
- SQLite database
- Node.js
vica/
├── bot.js # Main entry point - bot initialization and event registration
├── config.example.json # Configuration template (copy to config.json for use)
├── deploy-commands.js # Command deployment script for Discord API
├── delete-commands.js # Command deletion script
├── commands/ # Slash commands (18 files)
│ ├── canal_noticia.js # News channel configuration
│ ├── chat_blacklist.js # Chat blacklist management
│ ├── comment.js # Comment on messages
│ ├── config.js # Bot configuration
│ ├── deslurkar.js # Remove slur words
│ ├── enex.js # Enable/disable features
│ ├── gmemories.js # Global memory search
│ ├── mmemories.js # Memory management
│ ├── noticia.js # News posting
│ ├── perguntar.js # Ask questions to AI
│ ├── rank_blacklist.js # Rank blacklist management
│ ├── rank_reset.js # Reset user rank
│ ├── rank_rolexp.js # Set role XP multiplier
│ ├── rank_setxp.js # Set user XP
│ ├── rank.js # Display rank
│ ├── reaction_emoji.js # Emoji reaction configuration
│ ├── reaction_thread.js # Thread reaction configuration
│ ├── system_channel.js # System channel configuration
│ ├── trigger.js # Trigger word configuration
│ └── up_role.js # Role upgrade configuration
├── core/ # Core modules (8 files)
│ ├── auditCache.js # LRU cache for audit log deduplication
│ ├── database.js # All database operations with prepared statements
│ ├── mcp_client.js # MCP client for communicating with MCP servers
│ ├── oai_interface.js # OpenAI API integration with retry logic
│ ├── static_data.js # Loads questions and system prompt
│ ├── tagParser.js # SGML tag parser for memory tags
│ ├── tool_loader.js # Dynamic tool loading from data/tools.json (supports MCP)
│ └── transcriber.js # Audio transcription
├── events/ # Discord event handlers (7 files)
│ ├── guildBanAdd.js # Handle user bans
│ ├── guildMemberAdd.js # Handle new members
│ ├── guildMemberRemove.js # Handle member removals
│ ├── guildMemberUpdate.js # Handle member updates
│ ├── interactionCreate.js # Handle slash command interactions
│ ├── messageCreate.js # Handle new messages
│ └── messageReactionAdd.js # Handle message reactions
├── helpers/ # Helper utilities (1 file)
│ └── embeddingHelper.js # Embedding-related helpers
├── tools/ # OpenAI function tools (2 files)
│ ├── calculate.js # Calculator tool
│ └── get_current_time.js # Current time tool
├── data/ # Data files
│ └── tools.json # Tool definitions for OpenAI function calling and MCP servers
├── test_mcp.js # Test script for MCP integration
└── .roo/ # Roo-specific rules
Each command file in the commands/ folder must export:
data: ASlashCommandBuilderobject defining the commandexecute: An async function that handles the command execution
/*
** caminho: commands/example.js
** últimaMod: YYYY-MM-DD HH:MM
** autor: Vico
** colaboração: [AI assistants]
*/
const { SlashCommandBuilder } = require('discord.js');
module.exports = {
data: new SlashCommandBuilder()
.setName('example')
.setDescription('Example command description')
.addStringOption(option =>
option.setName('input')
.setDescription('Input parameter')
.setRequired(true)),
async execute(interaction) {
// Permission check
if (!interaction.member.permissions.has('ADMINISTRATOR')) {
await interaction.reply({
content: 'Você não tem permissão para usar este comando.',
ephemeral: true
});
return;
}
try {
// Command logic here
const input = interaction.options.getString('input');
await interaction.reply(`Resposta: ${input}`);
} catch (error) {
console.error('[EXAMPLE][ERROR]', error);
await interaction.reply({
content: 'Ocorreu um erro ao executar o comando.',
ephemeral: true
});
}
}
};- Permission Checks: Always verify user permissions before executing actions
- Ephemeral Responses: Use ephemeral responses for admin commands and error messages
- Error Handling: Wrap command logic in try/catch blocks
- Logging: Use
[MODULE][LEVEL]format for consistent logging - User Messages: Use Portuguese for all user-facing messages
- Code Comments: Use English for code comments and documentation
- Create a new file in the
commands/folder - Follow the command structure template above
- Add the command to
deploy-commands.jsfor deployment - Test the command thoroughly before deployment
Each event file in the events/ folder must export:
name: The event name (string)execute: An async function that handles the event
/*
** caminho: events/exampleEvent.js
** últimaMod: YYYY-MM-DD HH:MM
** autor: Vico
** colaboração: [AI assistants]
*/
module.exports = {
name: 'exampleEvent',
async execute(...args) {
try {
// Event logic here
console.log('[EXAMPLE_EVENT][INFO] Event triggered');
} catch (error) {
console.error('[EXAMPLE_EVENT][ERROR]', error);
}
}
};Events are registered in bot.js using the client's event emitter:
const exampleEvent = require('./events/exampleEvent');
client.on(exampleEvent.name, (...args) => exampleEvent.execute(...args));- Error Handling: Always wrap event logic in try/catch blocks
- Logging: Log event triggers and errors with consistent format
- Performance: Keep event handlers efficient to avoid blocking
- Validation: Validate event data before processing
- Create a new file in the
events/folder - Follow the event structure template above
- Register the event in
bot.js - Test the event with various scenarios
Database Module (core/database.js)
Handles all database operations using prepared statements.
Key Functions:
db.prepare(): Create prepared statementsdb.run(): Execute INSERT/UPDATE/DELETE operationsdb.get(): Retrieve a single rowdb.all(): Retrieve multiple rows
Best Practices:
- Always use prepared statements to prevent SQL injection
- Validate input before database operations
- Handle errors gracefully with user-friendly messages
- Follow the existing database schema
OpenAI Interface Module (core/oai_interface.js)
Handles OpenAI API integration with retry logic.
Key Functions:
chatCompletion(): GPT-4 chat completionscreateEmbedding(): Create text embeddingstranscribeAudio(): Transcribe audio files
Best Practices:
- Implement retry logic for API failures
- Use appropriate timeout values
- Handle rate limiting gracefully
- Log API calls for debugging
Tag Parser Module (core/tagParser.js)
SGML tag parser for memory tags.
Usage: Parse and extract tags from memory entries for better organization and retrieval.
Tool Loader Module (core/tool_loader.js)
Dynamic tool loading from data/tools.json.
Usage: Load and manage OpenAI function calling tools dynamically.
Static Data Module (core/static_data.js)
Loads questions and system prompt from configuration files.
Usage: Access static data like system prompts and predefined questions.
Transcriber Module (core/transcriber.js)
Audio transcription using OpenAI Whisper API.
Usage: Transcribe voice messages and audio attachments.
Audit Cache Module (core/auditCache.js)
LRU cache for audit log deduplication.
Usage: Prevent duplicate audit log entries within a time window.
The Vica bot now supports Model Context Protocol (MCP) servers, which allow extending the bot's capabilities with external tools. MCP is a protocol that enables AI assistants to communicate with external services through a standardized interface.
The core/mcp_client.js module provides functions for communicating with MCP servers:
startServer(config)- Start an MCP server with the given configurationstopServer(server)- Stop a running MCP serverinitializeServer(server)- Initialize MCP connection and handshakelistTools(server)- List available tools from an MCP servercallTool(server, toolName, args)- Call a tool on an MCP servergetServer(name)- Get a running server by namegetAllServers()- Get all running serversstopAllServers()- Stop all running servers
Add MCP servers to data/tools.json. MCP servers are identified by "type": "mcp" in their configuration.
stdio transport (local npx):
{
"name": "memory",
"type": "mcp",
"transport": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-memory@latest"],
"env": {
"MEMORY_FILE_PATH": "./data/memory.json"
}
}http transport (hosted servers):
{
"name": "example_server",
"type": "mcp",
"transport": "http",
"url": "https://example.com/mcp-endpoint"
}MCP servers can receive environment variables via the env field in the configuration. These are merged with the existing process environment variables.
Example for the memory server:
"env": {
"MEMORY_FILE_PATH": "d:/Projetos/Discord/vica/data/memory.json"
}| Server | Transport | Status | Tools |
|---|---|---|---|
| Memory | stdio | ✅ Working | 9 tools (knowledge graph operations) |
| Sequential Thinking | http | - | |
| Time | http | - |
The memory MCP server provides the following tools for knowledge graph operations:
- create_entities - Create multiple new entities in knowledge graph
- create_relations - Create multiple new relations between entities
- add_observations - Add new observations to existing entities
- delete_entities - Delete multiple entities and their relations
- delete_observations - Delete specific observations from entities
- delete_relations - Delete multiple relations from knowledge graph
- read_graph - Read entire knowledge graph
- search_nodes - Search for nodes based on a query
- open_nodes - Open specific nodes by their names
The core/tool_loader.js module automatically loads MCP tools and makes them available for OpenAI function calling:
const tool_loader = require('./core/tool_loader');
// Load all tools (including MCP tools)
const tools = tool_loader.loadTools();
// Use tools in OpenAI chat completion
const response = await oai.chatCompletion(messages, tools);MCP servers are managed in bot.js:
- Startup: All configured MCP servers are started when the bot initializes
- Runtime: Tools are available for AI function calling
- Shutdown: All MCP servers are gracefully stopped when the bot exits
HTTP-based servers returning HTML:
The mcp.so URLs may not be correct MCP HTTP endpoints. They might require:
- Different protocol (SSE, WebSocket)
- Authentication headers
- Different endpoint format
Windows compatibility:
- Use
npm.cmd execinstead ofnpxon Windows - The
mcp_client.jsautomatically addsshell: truefor Windows
Server startup failures:
- Check that the command is available in the system PATH
- Verify environment variables are correctly set
- Ensure required dependencies are installed
- Check server logs for detailed error messages
Run the test script to verify MCP server connectivity:
node test_mcp.jsThis will:
- Start all configured MCP servers
- List available tools from each server
- Test a simple tool call
- Stop all servers
- Add the server configuration to
data/tools.json - Choose the appropriate transport type (stdio or http)
- Configure any required environment variables
- Test the server using
node test_mcp.js - Restart the bot to load the new server
- Verify tools are available in the AI function calling context
- Use stdio transport for local servers: More reliable and easier to debug
- Configure environment variables: Use absolute paths for file-based servers
- Test before deployment: Always test MCP servers in development first
- Monitor server health: Check logs for MCP server errors
- Handle failures gracefully: Implement fallback logic when MCP tools fail
When the vibe_check tool is available, it must be used for reflection before major actions.
ALWAYS include the full user prompt in every vibe_check call to preserve context awareness.
As an autonomous agent:
- Treat
vibe_checkas a high-priority collaborative pattern interrupt for course correction, not as optional output - Use
vibe_checkat strategic points: after planning and before implementation, when complexity increases, and before significant system changes - Always provide the current phase in the call (
planning,implementation, orreview) for context-appropriate feedback - Adapt the approach based on
vibe_checkfeedback unless it is clearly irrelevant; if ignored, document why - Chain
vibe_checkwithvibe_learnafter resolving mistakes to record recurring patterns and successful corrections - If
vibe_checkis temporarily unavailable, continue with explicit self-review and log the limitation
Every file must include a header with the following format:
/*
** caminho: path/to/file.js
** últimaMod: YYYY-MM-DD HH:MM
** autor: Vico
** colaboração: [AI assistants]
*/Use the [MODULE][LEVEL] format for consistent logging:
console.log('[MODULE][INFO] Information message');
console.warn('[MODULE][WARN] Warning message');
console.error('[MODULE][ERROR] Error message');Always use async/await for asynchronous operations:
async function example() {
try {
const result = await someAsyncOperation();
return result;
} catch (error) {
console.error('[EXAMPLE][ERROR]', error);
throw error;
}
}Wrap all potentially error-prone code in try/catch blocks:
try {
// Code that might throw an error
} catch (error) {
console.error('[MODULE][ERROR]', error);
// Handle error appropriately
}- User-facing messages: Portuguese
- Code comments: English
- Documentation: English
- Variable names: English (camelCase)
- Function names: English (camelCase)
- Use 4 spaces for indentation
- Use semicolons at the end of statements
- Use single quotes for strings (unless string contains single quotes)
- Add spaces around operators
- Add spaces after commas
Always use prepared statements from database.js:
const db = require('./core/database');
// Insert
const stmt = db.prepare('INSERT INTO table (column1, column2) VALUES (?, ?)');
stmt.run(value1, value2);
// Update
const stmt = db.prepare('UPDATE table SET column1 = ? WHERE id = ?');
stmt.run(newValue, id);
// Select single row
const stmt = db.prepare('SELECT * FROM table WHERE id = ?');
const row = stmt.get(id);
// Select multiple rows
const stmt = db.prepare('SELECT * FROM table WHERE status = ?');
const rows = stmt.all(status);Always validate input before database operations:
if (!input || typeof input !== 'string' || input.length > 1000) {
throw new Error('Invalid input');
}Handle database errors gracefully:
try {
const stmt = db.prepare('INSERT INTO table (column) VALUES (?)');
stmt.run(value);
} catch (error) {
console.error('[MODULE][ERROR] Database error:', error);
await interaction.reply({
content: 'Erro ao salvar no banco de dados.',
ephemeral: true
});
}Follow the existing database schema when making modifications. Common tables include:
users: User information and XPguilds: Guild-specific settingsmemories: AI memory entriesblacklist: Chat blacklist entriestriggers: Trigger word configurations
Use oai_interface.js for all OpenAI API calls:
const oai = require('./core/oai_interface');
// Chat completion
const response = await oai.chatCompletion(messages, tools);
// Create embedding
const embedding = await oai.createEmbedding(text);
// Transcribe audio
const transcription = await oai.transcribeAudio(audioBuffer);Implement retry logic for API failures:
const MAX_RETRIES = 3;
const RETRY_DELAY = 1000; // 1 second
async function callWithRetry(fn) {
for (let i = 0; i < MAX_RETRIES; i++) {
try {
return await fn();
} catch (error) {
if (i === MAX_RETRIES - 1) throw error;
await new Promise(resolve => setTimeout(resolve, RETRY_DELAY * (i + 1)));
}
}
}Use embeddings for semantic memory retrieval:
// Create embedding for query
const queryEmbedding = await oai.createEmbedding(query);
// Search for similar memories
const similarMemories = await searchMemories(queryEmbedding);Follow the tool calling pattern for function execution:
// Define tool in data/tools.json
{
"name": "tool_name",
"description": "Tool description",
"parameters": {
"type": "object",
"properties": {
"param1": {
"type": "string",
"description": "Parameter description"
}
},
"required": ["param1"]
}
}
// Implement tool in tools/tool_name.js
module.exports = {
name: 'tool_name',
async execute(params) {
// Tool logic
return result;
}
};Test commands with different permission levels:
- Administrator permissions
- Moderator permissions
- Regular user permissions
- No permissions
Test edge cases:
- Missing required parameters
- Invalid parameter types
- Empty inputs
- Very long inputs
- Special characters
Test event handlers with various scenarios:
- Normal operation
- Error conditions
- Rate limiting
- Concurrent events
- Missing data
Test database operations with edge cases:
- Empty results
- Duplicate entries
- Foreign key constraints
- Large datasets
- Concurrent operations
Test AI integration with various inputs:
- Normal queries
- Ambiguous queries
- Malicious inputs
- Very long inputs
- Special characters
- Multiple languages
- Hardware: Raspberry Pi 3b+
- OS: Linux (Raspberry Pi OS)
- Service Manager: systemd
The bot runs as a systemd service (vica.service):
[Unit]
Description=Vica Discord Bot
After=network.target
[Service]
Type=simple
User=vico
WorkingDirectory=/home/vico/discord_bots/vica
ExecStart=/usr/bin/node /home/vico/discord_bots/vica/bot.js
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target# SSH into the production server
ssh <username>@<hostname>
# Navigate to the project directory
cd <path/to/vica>
# Pull latest changes
git pull
# Restart the service
sudo systemctl restart vica.service
# Check service status
sudo systemctl status vica.service
# View logs if needed
sudo journalctl -u vica.service -f- All tests pass
- Code follows style guidelines
- Database migrations are applied
- Configuration is updated
- Commands are deployed
- Documentation is updated
- Create a new file in
commands/folder - Implement the command following the template
- Add the command to
deploy-commands.js - Deploy commands:
node deploy-commands.js - Test the command thoroughly
- Update documentation if needed
- Create a new file in
events/folder - Implement the event following the template
- Register the event in
bot.js - Test the event with various scenarios
- Update documentation if needed
- Create a new file in
tools/folder - Implement the tool following the template
- Add tool definition to
data/tools.json - Test the tool with AI integration
- Update documentation if needed
- Add server configuration to
data/tools.json - Choose transport type (stdio or http)
- Configure environment variables if needed
- Test with
node test_mcp.js - Restart the bot to load the server
- Verify tools are available for AI function calling
- Plan the schema changes
- Add migration logic to
database.js - Test migration on development environment
- Update all affected code
- Test thoroughly before deployment
- Document the changes
- Update
config.example.jsonwith new settings - Document new configuration options
- Update code to use new configuration
- Test with various configurations
- Deploy configuration changes
- User-facing messages: Must be in Portuguese
- Code comments: Must be in English
- Documentation: Must be in English
- Variable/function names: Must be in English
All Discord API calls should have appropriate permission checks:
- Verify user has required permissions
- Verify bot has required permissions
- Handle permission errors gracefully
Rate limiting is implemented (5 seconds per user):
- Respect Discord API rate limits
- Implement cooldowns for expensive operations
- Use queue systems for bulk operations
Messages are split to respect Discord's 2000 character limit:
- Use helper functions to split long messages
- Preserve message integrity when splitting
- Handle code blocks and special formatting
Conversation context includes the last 6 messages:
- Maintain context for AI responses
- Implement context window management
- Handle context overflow gracefully
Provide user-friendly error messages in Portuguese:
- Explain what went wrong
- Suggest how to fix the issue
- Include relevant details for debugging
- GEMINI.MD: Comprehensive project documentation with detailed technical specifications
- README.MD: User-facing documentation with installation and usage instructions
- config.example.json: Configuration template with all available options
- Roo: AI coding assistant with project-specific rules in
.roo/ - Cursor: AI-powered code editor
- VS Code: Primary development environment
const { SlashCommandBuilder } = require('discord.js');
const db = require('./core/database');
const oai = require('./core/oai_interface');Permission Check:
if (!interaction.member.permissions.has('ADMINISTRATOR')) {
await interaction.reply({
content: 'Você não tem permissão para usar este comando.',
ephemeral: true
});
return;
}Error Handling:
try {
// Code
} catch (error) {
console.error('[MODULE][ERROR]', error);
await interaction.reply({
content: 'Ocorreu um erro ao executar a operação.',
ephemeral: true
});
}Database Query:
const stmt = db.prepare('SELECT * FROM table WHERE id = ?');
const result = stmt.get(id);AI Chat:
const response = await oai.chatCompletion(messages, tools);For questions or issues:
- Check GEMINI.MD for detailed documentation
- Review existing code for patterns
- Test changes thoroughly before deployment
- Document any modifications made
Last Updated: 2026-03-09 Maintained By: Vico Contributors: AI assistants (Roo, Cursor, etc.)