> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/darkzOGx/youtube-automation-agent/llms.txt
> Use this file to discover all available pages before exploring further.

# Customization

> Extend and customize the YouTube Automation Agent to fit your specific needs

## Overview

The YouTube Automation Agent is built with extensibility in mind. You can customize agents, add new content types, modify workflows, and integrate custom services.

## Custom Agent Development

### Creating a Custom Agent

All agents follow a consistent pattern. Here's how to create your own:

```javascript agents/custom-agent.js theme={null}
const { Logger } = require('../utils/logger');

class CustomAgent {
  constructor(db, credentials) {
    this.db = db;
    this.credentials = credentials;
    this.logger = new Logger('CustomAgent');
  }

  async initialize() {
    this.logger.info('Initializing Custom Agent...');
    // Load any required data or setup connections
    return true;
  }

  async performTask(input) {
    try {
      this.logger.info('Starting custom task...');
      
      // Your custom logic here
      const result = await this.processInput(input);
      
      // Save results to database
      await this.db.saveCustomData(result);
      
      this.logger.success('Custom task completed');
      return result;
    } catch (error) {
      this.logger.error('Custom task failed:', error);
      throw error;
    }
  }

  async processInput(input) {
    // Implement your custom processing logic
    return { processed: true, data: input };
  }
}

module.exports = { CustomAgent };
```

### Integrating the Agent

Add your agent to the main application in `index.js:69-84`:

```javascript index.js theme={null}
const { CustomAgent } = require('./agents/custom-agent');

async initializeAgents() {
  this.agents = {
    strategy: new ContentStrategyAgent(this.db, this.credentials),
    scriptWriter: new ScriptWriterAgent(this.db, this.credentials),
    thumbnailDesigner: new ThumbnailDesignerAgent(this.db, this.credentials),
    seoOptimizer: new SEOOptimizerAgent(this.db, this.credentials),
    production: new ProductionManagementAgent(this.db, this.credentials),
    publishing: new PublishingSchedulingAgent(this.db, this.credentials),
    analytics: new AnalyticsOptimizationAgent(this.db, this.credentials),
    custom: new CustomAgent(this.db, this.credentials) // Add your agent
  };

  for (const [name, agent] of Object.entries(this.agents)) {
    await agent.initialize();
    this.logger.info(`✓ ${name} agent initialized`);
  }
}
```

## Custom Content Pipeline

### Modifying the Generation Workflow

The content generation pipeline is defined in `index.js:149-186`. You can customize it:

```javascript theme={null}
async generateContent(topic = null, style = null, length = 'medium') {
  this.logger.info('Starting custom content generation pipeline...');
  
  // Step 1: Strategy
  const strategy = await this.agents.strategy.generateContentStrategy(topic);
  
  // Step 2: Script Writing
  const script = await this.agents.scriptWriter.generateScript(strategy);
  
  // Step 3: Add your custom processing
  const customData = await this.agents.custom.processScript(script);
  
  // Step 4: Thumbnail Design
  const thumbnail = await this.agents.thumbnailDesigner.generateThumbnail(script);
  
  // Step 5: SEO Optimization
  const seoData = await this.agents.seoOptimizer.optimize(script, strategy);
  
  // Step 6: Production Management
  const productionData = await this.agents.production.processContent({
    strategy,
    script,
    thumbnail,
    seo: seoData,
    custom: customData // Include custom data
  });
  
  // Step 7: Save to database
  const contentId = await this.db.saveProductionData(productionData);
  
  return {
    contentId,
    title: script.title,
    scheduledFor: productionData.scheduledPublishTime,
    customData
  };
}
```

## Custom Scheduled Tasks

### Adding New Automation Tasks

Extend the scheduler in `schedules/daily-automation.js:25-84`:

```javascript theme={null}
async setupScheduledTasks() {
  // Existing tasks...
  
  // Add your custom scheduled task
  this.scheduledTasks.set('custom-hourly-task',
    cron.schedule('0 * * * *', async () => {
      if (this.isEnabled) {
        await this.runCustomTask();
      }
    }, { scheduled: false })
  );

  // Start all scheduled tasks
  this.scheduledTasks.forEach((task, name) => {
    task.start();
    this.logger.info(`Started scheduled task: ${name}`);
  });
}

async runCustomTask() {
  try {
    this.logger.info('Running custom scheduled task...');
    
    // Your custom logic here
    const result = await this.performCustomOperation();
    
    await this.logAutomationEvent('custom_task', 'success', {
      result
    });
    
  } catch (error) {
    this.logger.error('Custom task failed:', error);
    
    await this.logAutomationEvent('custom_task', 'error', {
      error: error.message
    });
  }
}
```

<Note>
  Cron syntax: `minute hour day month weekday`

  * `0 6 * * *` - Daily at 6:00 AM
  * `*/15 * * * *` - Every 15 minutes
  * `0 8 * * 0` - Sundays at 8:00 AM
</Note>

## Custom Logger Configuration

### Creating Specialized Loggers

The logging system (from `utils/logger.js:90-101`) supports custom loggers:

```javascript theme={null}
const { Logger } = require('./utils/logger');

// Create specialized loggers for different components
const apiLogger = Logger.createAPILogger();
const systemLogger = Logger.createSystemLogger();
const customLogger = Logger.createAgentLogger('MyCustomComponent');

// Use structured logging for events
customLogger.logEvent('custom_event', {
  userId: 'user123',
  action: 'processed_video',
  duration: 1500
});

// Log with performance timing
const timer = customLogger.startTimer('Video Processing');
// ... do work ...
timer.end(); // Logs: "Video Processing completed in Xms"

// Log errors with context
customLogger.logErrorWithContext(error, {
  videoId: 'vid123',
  stage: 'thumbnail_generation',
  retryCount: 2
});
```

### Custom Log Transports

Extend logging to external services:

```javascript theme={null}
const winston = require('winston');
const { Logger } = require('./utils/logger');

class CustomLogger extends Logger {
  createWinstonLogger() {
    const baseLogger = super.createWinstonLogger();
    
    // Add custom transport (e.g., send to external service)
    baseLogger.add(new winston.transports.Http({
      host: 'logging.example.com',
      port: 8080,
      path: '/logs'
    }));
    
    return baseLogger;
  }
}
```

## Environment Configuration

### Custom Environment Variables

Add custom settings to `.env`:

```bash .env theme={null}
# Custom AI Model Settings
CUSTOM_AI_MODEL=gpt-4-turbo-preview
CUSTOM_AI_TEMPERATURE=0.7
CUSTOM_MAX_TOKENS=2000

# Custom Content Settings
CUSTOM_VIDEO_LENGTH=10-15
CUSTOM_THUMBNAIL_STYLE=minimalist
CUSTOM_CONTENT_TONE=professional

# Custom Integration Keys
CUSTOM_WEBHOOK_URL=https://example.com/webhook
CUSTOM_ANALYTICS_KEY=your-analytics-key
```

Access them in your code:

```javascript theme={null}
const customModel = process.env.CUSTOM_AI_MODEL || 'gpt-4';
const temperature = parseFloat(process.env.CUSTOM_AI_TEMPERATURE) || 0.7;
const webhookUrl = process.env.CUSTOM_WEBHOOK_URL;

if (webhookUrl) {
  await sendWebhook(webhookUrl, data);
}
```

## Database Extensions

### Adding Custom Tables

Extend the database schema in `database/db.js:34-195`:

```javascript theme={null}
async createCustomTables() {
  const customTables = [
    `CREATE TABLE IF NOT EXISTS custom_data (
      id TEXT PRIMARY KEY,
      content_id TEXT NOT NULL,
      custom_field_1 TEXT,
      custom_field_2 INTEGER,
      metadata TEXT,
      created_at TEXT DEFAULT CURRENT_TIMESTAMP,
      FOREIGN KEY (content_id) REFERENCES productions(id)
    )`
  ];

  for (const tableQuery of customTables) {
    await this.executeQuery(tableQuery);
  }
}

// Add custom methods
async saveCustomData(data) {
  const id = this.generateId('custom');
  await this.executeQuery(
    `INSERT INTO custom_data (
      id, content_id, custom_field_1, custom_field_2, metadata
    ) VALUES (?, ?, ?, ?, ?)`,
    [
      id,
      data.contentId,
      data.field1,
      data.field2,
      JSON.stringify(data.metadata)
    ]
  );
  return id;
}

async getCustomData(contentId) {
  return await this.getRow(
    'SELECT * FROM custom_data WHERE content_id = ?',
    [contentId]
  );
}
```

## API Endpoint Customization

### Adding Custom Routes

Extend the Express API in `index.js:87-147`:

```javascript theme={null}
setupAPI() {
  this.app.use(express.json());
  this.app.use(express.static(path.join(__dirname, 'dashboard')));
  
  // Existing routes...
  
  // Add custom endpoint
  this.app.post('/api/custom/process', async (req, res) => {
    try {
      const { input } = req.body;
      const result = await this.agents.custom.performTask(input);
      res.json({ success: true, result });
    } catch (error) {
      res.status(500).json({ success: false, error: error.message });
    }
  });
  
  // Custom analytics endpoint
  this.app.get('/api/custom/metrics', async (req, res) => {
    try {
      const metrics = await this.getCustomMetrics();
      res.json(metrics);
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  });
  
  // Webhook receiver
  this.app.post('/webhook/:service', async (req, res) => {
    try {
      const { service } = req.params;
      await this.handleWebhook(service, req.body);
      res.json({ received: true });
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  });
}
```

<Accordion title="Complete Custom Agent Example">
  ```javascript agents/brand-voice-agent.js theme={null}
  const { Logger } = require('../utils/logger');
  const { Configuration, OpenAIApi } = require('openai');

  /**
   * Brand Voice Agent
   * Ensures all content matches specific brand guidelines and tone
   */
  class BrandVoiceAgent {
    constructor(db, credentials) {
      this.db = db;
      this.credentials = credentials;
      this.logger = new Logger('BrandVoice');
      this.brandGuidelines = null;
    }

    async initialize() {
      this.logger.info('Initializing Brand Voice Agent...');
      
      // Load brand guidelines from database or config
      this.brandGuidelines = await this.loadBrandGuidelines();
      
      // Initialize OpenAI client
      const configuration = new Configuration({
        apiKey: this.credentials.credentials.openai.apiKey,
      });
      this.openai = new OpenAIApi(configuration);
      
      return true;
    }

    async loadBrandGuidelines() {
      return {
        tone: process.env.BRAND_TONE || 'professional and friendly',
        vocabulary: {
          preferred: ['innovative', 'efficient', 'streamlined'],
          avoid: ['cheap', 'basic', 'simple']
        },
        style: {
          sentenceLength: 'short to medium',
          paragraphLength: '2-3 sentences',
          activeVoice: true
        }
      };
    }

    async reviewScript(script) {
      try {
        this.logger.info(`Reviewing script for brand voice: ${script.title}`);
        
        const fullText = this.extractScriptText(script);
        const analysis = await this.analyzeBrandAlignment(fullText);
        
        if (analysis.score < 80) {
          this.logger.warn(`Brand alignment score low: ${analysis.score}/100`);
          const improved = await this.improveAlignment(fullText, analysis);
          return { ...script, improved, brandScore: analysis.score };
        }
        
        this.logger.success('Brand voice alignment verified');
        return { ...script, brandScore: analysis.score };
      } catch (error) {
        this.logger.error('Brand voice review failed:', error);
        throw error;
      }
    }

    extractScriptText(script) {
      let text = script.title + '\n\n';
      text += script.hook.text + '\n\n';
      text += script.introduction.greeting + ' ';
      text += script.introduction.topicIntro + '\n\n';
      
      script.mainContent.sections.forEach(section => {
        if (Array.isArray(section.content)) {
          text += section.content.join(' ') + '\n\n';
        } else {
          text += section.content + '\n\n';
        }
      });
      
      return text;
    }

    async analyzeBrandAlignment(text) {
      const prompt = `Analyze the following text for brand voice alignment.

  Brand Guidelines:
  - Tone: ${this.brandGuidelines.tone}
  - Preferred vocabulary: ${this.brandGuidelines.vocabulary.preferred.join(', ')}
  - Words to avoid: ${this.brandGuidelines.vocabulary.avoid.join(', ')}

  Text to analyze:
  ${text}

  Provide a score (0-100) and specific feedback.`;

      const response = await this.openai.createChatCompletion({
        model: this.credentials.credentials.openai.model,
        messages: [{ role: 'user', content: prompt }],
        temperature: 0.3
      });

      // Parse AI response for score and feedback
      return {
        score: 85, // Extracted from response
        feedback: response.data.choices[0].message.content
      };
    }

    async improveAlignment(text, analysis) {
      // Use AI to improve brand alignment
      const prompt = `Rewrite the following text to better align with these brand guidelines:
  ${JSON.stringify(this.brandGuidelines, null, 2)}

  Original text:
  ${text}

  Provide improved version.`;

      const response = await this.openai.createChatCompletion({
        model: this.credentials.credentials.openai.model,
        messages: [{ role: 'user', content: prompt }],
        temperature: 0.5
      });

      return response.data.choices[0].message.content;
    }
  }

  module.exports = { BrandVoiceAgent };
  ```
</Accordion>

<Warning>
  When extending the system:

  * Always use the Logger class for consistent logging
  * Follow the existing error handling patterns
  * Use database transactions for multi-step operations
  * Validate inputs before processing
  * Add appropriate try-catch blocks
</Warning>

## Next Steps

<CardGroup cols={2}>
  <Card title="Custom Content Types" icon="file-lines" href="/advanced/custom-content-types">
    Learn how to add new content formats
  </Card>

  <Card title="Multiple Channels" icon="users" href="/advanced/multiple-channels">
    Manage multiple YouTube channels
  </Card>
</CardGroup>
