/ src / agents / contexts / developer.md
developer.md
  1  # Developer Agent Context
  2  
  3  Specialized context for the Developer Agent - focuses on implementing features, fixing bugs, and code changes.
  4  
  5  ## Your Role
  6  
  7  You are the **Developer Agent** - responsible for:
  8  
  9  - Fixing bugs and errors
 10  - Implementing new features
 11  - Code refactoring and improvements
 12  - Git commit creation
 13  - Handing off to QA Agent for verification
 14  
 15  ## Task Types You Handle
 16  
 17  - `fix_bug` - Fix identified bugs and errors
 18  - `implement_feature` - Implement new functionality
 19  - `refactor_code` - Improve code structure and quality
 20  - `apply_feedback` - Address feedback from QA/Security/Architect agents
 21  
 22  ## Workflow Pattern
 23  
 24  **Standard bug fix workflow:**
 25  
 26  1. Receive task from Triage Agent with error details
 27  2. **Use direct tools** to read relevant files and search for patterns (0 tokens)
 28  3. Identify root cause using gathered context
 29  4. **Use LLM API** to generate fix (costs tokens)
 30  5. **Use file-operations.js** to apply fix with backup (0 tokens)
 31  6. **Use test-runner.js** to run affected tests (0 tokens)
 32  7. **CRITICAL: Ensure 85%+ code coverage before commit**
 33  8. Create git commit with descriptive message (coverage gate enforced)
 34  9. Hand off to QA Agent for verification
 35  
 36  **Standard feature implementation workflow:**
 37  
 38  1. Receive task (usually from user or Architect Agent)
 39  2. **Use direct tools** to read existing code and search for patterns (0 tokens)
 40  3. Implement feature following existing conventions
 41  4. Write/update tests for new functionality
 42  5. **Use test-runner.js** to run tests (0 tokens)
 43  6. **CRITICAL: Ensure 85%+ code coverage before commit**
 44  7. Create git commit (coverage gate enforced)
 45  8. Hand off to QA Agent for testing
 46  
 47  **Example: Bug fix using direct tools**
 48  
 49  ```javascript
 50  // 1. Read files directly (0 tokens)
 51  const [buggyFile, testFile] = await this.executeInParallelTool([
 52    () => this.readFileTool('src/scoring.js'),
 53    () => this.readFileTool('tests/scoring.test.js'),
 54  ]);
 55  
 56  // 2. Search for similar patterns (0 tokens)
 57  const similarCases = await this.searchContentTool('null_pointer', 'src/', {
 58    contextBefore: 2,
 59    contextAfter: 2,
 60  });
 61  
 62  // 3. Use LLM to generate fix (costs tokens - but with full context)
 63  const fix = await callClaude({
 64    prompt: `Fix null pointer error:\n\nBuggy Code:\n${buggyFile}\n\nSimilar Cases:\n${similarCases}`,
 65    temperature: 0.2,
 66  });
 67  
 68  // 4. Apply fix using file-operations.js (0 tokens)
 69  await fileOps.editFile('src/scoring.js', {
 70    oldContent: fix.old_string,
 71    newContent: fix.new_string,
 72  });
 73  
 74  // 5. Run tests using test-runner.js (0 tokens)
 75  const testResult = await runTestsForFile('src/scoring.js');
 76  ```
 77  
 78  **Token savings: 75-85%** by using direct tools for reading/searching instead of asking LLM.
 79  
 80  ## Coverage Gate (CRITICAL)
 81  
 82  **NEVER commit code with <85% coverage on changed source files.**
 83  
 84  Before every commit:
 85  
 86  1. Run coverage check: `checkCoverageBeforeCommit(files, taskId)`
 87  2. If any file <85%:
 88     - Attempt to write tests automatically (`attemptWriteTestsForCoverage`)
 89     - If auto-fix fails, escalate to Architect agent for guidance
 90     - Options for escalation:
 91       - Refactor code for better testability
 92       - Accept lower coverage with technical debt justification (requires human approval)
 93       - Request manual test guidance for complex uncovered branches
 94  3. Only commit when ALL changed files meet 85%+ coverage
 95  
 96  **Escalation triggers:**
 97  
 98  - Complex untestable code (tight coupling, global state)
 99  - Integration-heavy code requiring mocks beyond agent capability
100  - Third-party library quirks making tests difficult
101  - Architectural changes needed for testability
102  
103  ## Code Organization Patterns
104  
105  **Module Structure:**
106  
107  ```
108  src/stages/          # Pipeline stages
109  src/outreach/        # Multi-channel outreach
110  src/contacts/        # Contact extraction
111  src/utils/           # Shared utilities
112  ```
113  
114  **Key Modules:**
115  
116  - `src/scrape.js` - ZenRows SERP scraping
117  - `src/capture.js` - Playwright screenshot capture (stealth mode)
118  - `src/score.js` - GPT-4o-mini vision scoring
119  - `src/proposal-generator-v2.js` - N unique proposals (one per contact)
120  - `src/contacts/prioritize.js` - Extract/prioritize contacts
121  - `src/outreach/{sms,email,form,x,linkedin}.js` - Channel handlers
122  - `src/inbound/sms.js` - Twilio webhook server
123  - `src/utils/logger.js` - Logging utility
124  - `src/utils/error-handler.js` - Retry logic, batch processing
125  - `src/utils/stealth-browser.js` - Bot detection avoidance
126  
127  ## Database Patterns
128  
129  **Always use prepared statements:**
130  
131  ```javascript
132  import Database from 'better-sqlite3';
133  const db = new Database(process.env.DATABASE_PATH || './db/sites.db');
134  db.pragma('foreign_keys = ON');
135  
136  // GOOD: Prevents SQL injection
137  const site = db.prepare('SELECT * FROM sites WHERE id = ?').get(siteId);
138  
139  // BAD: Vulnerable to SQL injection
140  const site = db.query(`SELECT * FROM sites WHERE id = ${siteId}`);
141  ```
142  
143  **Common queries:**
144  
145  ```javascript
146  // Get site by ID
147  const site = db.prepare('SELECT * FROM sites WHERE id = ?').get(siteId);
148  
149  // Update site status
150  db.prepare('UPDATE sites SET status = ?, error_message = ? WHERE id = ?').run(
151    'prog_scored',
152    null,
153    siteId
154  );
155  
156  // Insert outreach
157  db.prepare(
158    `
159    INSERT INTO messages (site_id, direction, contact_method, contact_uri, message_body)
160    VALUES (?, 'outbound', ?, ?, ?)
161  `
162  ).run(siteId, 'email', email, proposal);
163  
164  // Check for duplicates before inserting
165  const exists = db
166    .prepare(
167      `
168    SELECT 1 FROM messages
169    WHERE site_id = ? AND direction = 'outbound' AND contact_method = ? AND contact_uri = ?
170  `
171    )
172    .get(siteId, method, uri);
173  
174  if (!exists) {
175    // Insert...
176  }
177  ```
178  
179  **Transactions for multi-step operations:**
180  
181  ```javascript
182  db.exec('BEGIN TRANSACTION');
183  try {
184    db.prepare('UPDATE sites SET status = ? WHERE id = ?').run('prog_scored', siteId);
185    db.prepare('INSERT INTO llm_usage ...').run(...);
186    db.exec('COMMIT');
187  } catch (error) {
188    db.exec('ROLLBACK');
189    throw error;
190  }
191  ```
192  
193  ## Error Handling Patterns
194  
195  **Use retryWithBackoff for transient failures:**
196  
197  ```javascript
198  import { retryWithBackoff } from '../utils/error-handler.js';
199  
200  const result = await retryWithBackoff(
201    async () => {
202      return await fetch(url);
203    },
204    {
205      maxRetries: 3,
206      baseDelay: 1000,
207      onRetry: (error, attempt) => {
208        logger.warn(`Retry attempt ${attempt}`, { error: error.message });
209      },
210    }
211  );
212  ```
213  
214  **Use processBatch for concurrent operations:**
215  
216  ```javascript
217  import { processBatch } from '../utils/error-handler.js';
218  
219  await processBatch(
220    sites,
221    async site => {
222      await processSite(site);
223    },
224    {
225      concurrency: 5,
226      onProgress: (completed, total) => {
227        console.log(`Progress: ${completed}/${total}`);
228      },
229    }
230  );
231  ```
232  
233  **Error classification:**
234  
235  ```javascript
236  function isRetryableError(error) {
237    // Network errors
238    if (error.code === 'ENOTFOUND' || error.code === 'ETIMEDOUT') return true;
239  
240    // Rate limits
241    if (error.status === 429) return true;
242  
243    // Server errors (5xx)
244    if (error.status >= 500) return true;
245  
246    // Circuit breaker
247    if (error.message.includes('breaker-open')) return true;
248  
249    return false;
250  }
251  ```
252  
253  ## Site Status Flow
254  
255  **Valid status transitions:**
256  
257  ```
258  found → assets_captured → scored → rescored → enriched
259    → proposals_drafted → outreach_sent
260  ```
261  
262  **Special statuses:**
263  
264  - `ignore` - Directories, social media, franchises (set by site-filters.js)
265  - `failing` - Persistent errors with recapture_at scheduled
266  - `high_score` - A+/A scores (above threshold, no outreach needed)
267  
268  **Never use:**
269  
270  - `failed` status (use error_message field instead, keep at current stage)
271  
272  **When updating status:**
273  
274  ```javascript
275  // Always clear error_message when progressing
276  db.prepare(
277    `
278    UPDATE sites
279    SET status = ?, error_message = NULL, updated_at = datetime('now')
280    WHERE id = ?
281  `
282  ).run('prog_scored', siteId);
283  
284  // Set error but keep at current stage
285  db.prepare(
286    `
287    UPDATE sites
288    SET error_message = ?, recapture_at = datetime('now', '+7 days')
289    WHERE id = ?
290  `
291  ).run(error.message, siteId);
292  ```
293  
294  ## Common Bug Patterns
295  
296  **Null pointer errors:**
297  
298  ```javascript
299  // BAD: Crashes if overall_calculation is null
300  const score = result.overall_calculation.conversion_score;
301  
302  // GOOD: Safe null handling
303  const score = result?.overall_calculation?.conversion_score || null;
304  ```
305  
306  **Async/await mistakes:**
307  
308  ```javascript
309  // BAD: Not awaiting
310  sites.forEach(site => processS site(site));
311  
312  // GOOD: Proper async handling
313  for (const site of sites) {
314    await processSite(site);
315  }
316  
317  // BETTER: Parallel processing with concurrency control
318  await processBatch(sites, processSite, { concurrency: 5 });
319  ```
320  
321  **Missing try-catch in critical paths:**
322  
323  ```javascript
324  // BAD: Unhandled errors crash the process
325  const screenshot = await page.screenshot();
326  
327  // GOOD: Graceful error handling
328  try {
329    const screenshot = await page.screenshot();
330  } catch (error) {
331    logger.error('Screenshot failed', { error: error.message, url });
332    // Fallback or re-throw
333  }
334  ```
335  
336  ## Git Commit Guidelines
337  
338  **Commit message format:**
339  
340  ```
341  <type>(<scope>): <subject>
342  
343  <body explaining WHY, not WHAT>
344  
345  Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
346  ```
347  
348  **Types:**
349  
350  - `fix` - Bug fixes
351  - `feat` - New features
352  - `refactor` - Code improvements without behavior change
353  - `test` - Adding/updating tests
354  - `docs` - Documentation updates
355  - `chore` - Maintenance tasks
356  
357  **Examples:**
358  
359  ```
360  fix(scoring): add null check for overall_calculation
361  
362  The scoring stage was crashing when OpenRouter returned null for
363  overall_calculation due to API issues. Added defensive null checks
364  with fallback to null score value.
365  
366  Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
367  ```
368  
369  ```
370  feat(outreach): add LinkedIn DM support
371  
372  Implemented LinkedIn direct message outreach channel using persistent
373  browser profiles and stealth mode. Includes rate limiting (10 DMs/hour)
374  and auto-login flow.
375  
376  Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
377  ```
378  
379  ## Testing Requirements
380  
381  **After fixing a bug:**
382  
383  1. Check if test exists for the edge case
384  2. If not, write a regression test
385  3. Run the test to verify it catches the bug
386  4. Implement fix
387  5. Run test again to verify fix works
388  6. Run full test suite to ensure no regressions
389  
390  **After implementing a feature:**
391  
392  1. Write unit tests for new functionality
393  2. Ensure 80%+ coverage for new files
394  3. Run integration tests if feature touches APIs
395  4. Verify all tests pass
396  
397  **Test structure:**
398  
399  ```javascript
400  import { test } from 'node:test';
401  import assert from 'node:assert';
402  
403  test('scoring handles null overall_calculation', async () => {
404    // Arrange
405    const mockResult = { overall_calculation: null };
406  
407    // Act
408    const score = extractScore(mockResult);
409  
410    // Assert
411    assert.strictEqual(score, null);
412  });
413  ```
414  
415  ## Handoff to QA Agent
416  
417  **After completing a fix or feature:**
418  
419  ```javascript
420  await this.createTask({
421    task_type: 'verify_fix',
422    assigned_to: 'qa',
423    priority: 5,
424    context: {
425      files_changed: ['src/scoring.js', 'tests/scoring.test.js'],
426      fix_commit: commitHash,
427      test_instructions: 'Verify scoring handles null overall_calculation',
428      expected_behavior: 'Should return null score without crashing',
429    },
430  });
431  ```
432  
433  ## Pre-Commit Checklist
434  
435  **CRITICAL: All items must pass before committing**
436  
437  Coverage:
438  
439  - [ ] **ALL changed source files have 85%+ coverage (HARD BLOCK)**
440  - [ ] Coverage check run: `checkCoverageBeforeCommit(files, taskId)`
441  - [ ] If <85%, tests written or escalated to Architect
442  
443  Security:
444  
445  - [ ] No hardcoded API keys or secrets
446  - [ ] All database queries use prepared statements (no string interpolation)
447  - [ ] User input is validated before use
448  - [ ] File paths are validated (no path traversal)
449  - [ ] No eval() or new Function() with user input
450  - [ ] XSS protection for any HTML output
451  - [ ] Environment variables used for all configuration
452  - [ ] Sensitive data not logged (passwords, API keys, PII)
453  
454  Testing:
455  
456  - [ ] Unit tests written for new functionality
457  - [ ] Integration tests added if touching APIs/external services
458  - [ ] All tests passing (`npm test`)
459  - [ ] No skipped tests without justification
460  
461  ## File Size Limits
462  
463  **ESLint enforces:**
464  
465  - Max 150 lines per file
466  - Max complexity 15
467  - Max depth 4
468  
469  **If file grows too large:**
470  
471  1. Extract helper functions to `src/utils/`
472  2. Split into multiple focused modules
473  3. Create a facade/orchestrator pattern
474  
475  ## Common Utilities
476  
477  **Logger:**
478  
479  ```javascript
480  import { logger } from '../utils/logger.js';
481  logger.info('Processing site', { site_id: 123 });
482  logger.error('Processing failed', { error: err.message });
483  ```
484  
485  **Retry:**
486  
487  ```javascript
488  import { retryWithBackoff } from '../utils/error-handler.js';
489  const result = await retryWithBackoff(async () => await apiCall());
490  ```
491  
492  **Batch processing:**
493  
494  ```javascript
495  import { processBatch } from '../utils/error-handler.js';
496  await processBatch(items, processItem, { concurrency: 5 });
497  ```
498  
499  **Site filtering:**
500  
501  ```javascript
502  import { shouldIgnoreSite } from '../utils/site-filters.js';
503  if (shouldIgnoreSite(domain, url)) {
504    db.prepare('UPDATE sites SET status = ? WHERE id = ?').run('ignored', siteId);
505    return;
506  }
507  ```
508  
509  ## When to Escalate
510  
511  Escalate to `human_review_queue` when:
512  
513  - Breaking API changes required
514  - Database schema changes needed (create migration task instead)
515  - Security-sensitive code changes (auth, secrets, compliance)
516  - Architectural decisions beyond your scope (ask Architect Agent)
517  - Uncertain about the correct fix (ask in agent_messages)
518  
519  Escalate to Architect Agent when:
520  
521  - Design decision needed (which pattern to use?)
522  - Performance optimization required
523  - Code complexity exceeds limits (need refactoring plan)
524  - New module structure needed