The Problem
On Monday you tested the 3 prompts in ChatGPT. You saw how task generation โ dependency mapping โ reminder scheduling works. But here's reality: you can't manually track 47 tasks across engineering, marketing, sales, support, and legal. Someone always misses their deadline. Dependencies get forgotten. Launches slip by weeks.
Watch It Orchestrate
See the 3 prompts chain together automatically. This is what you'll build - from launch brief to fully assigned, dependency-tracked task list.
The Code
Three levels: start simple with task generation, add dependency tracking, then build full orchestration. Pick where you are.
Level 1: Simple Task Generation
Good for: 1-5 launches/year | Setup time: 30 minutes
// Simple Task Generation (1-5 launches/year) import Anthropic from '@anthropic-ai/sdk'; import { Client as NotionClient } from '@notionhq/client'; interface LaunchTask { id: string; title: string; team: string; owner: string; duration_days: number; dependencies: string[]; deliverable: string; } interface LaunchPlan { launch_name: string; target_date: string; tasks: LaunchTask[]; } async function generateLaunchTasks( launchBrief: string ): Promise<LaunchPlan> { const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY!, }); // Step 1: Generate comprehensive task list const taskPrompt = `Break down this product launch into detailed tasks for each team. Include: Engineering, Marketing, Sales, Support, Legal. For each task provide: id, title, team, owner role, duration_days, dependencies (list of task IDs), deliverable. Launch brief: ${launchBrief} Output as JSON with structure: { "launch_name": string, "target_date": "YYYY-MM-DD", "tasks": [{ "id": "team-###", "title": string, "team": string, "owner": string, "duration_days": number, "dependencies": string[], "deliverable": string }] }`; const response = await anthropic.messages.create({ model: 'claude-3-5-sonnet-20241022', max_tokens: 4096, messages: [ { role: 'user', content: taskPrompt, }, ], }); const content = response.content[0]; if (content.type !== 'text') throw new Error('Invalid response'); const launchPlan: LaunchPlan = JSON.parse(content.text); // Step 2: Create tasks in Notion const notion = new NotionClient({ auth: process.env.NOTION_API_KEY!, }); const databaseId = process.env.NOTION_LAUNCH_DB_ID!; for (const task of launchPlan.tasks) { await notion.pages.create({ parent: { database_id: databaseId }, properties: { Name: { title: [ { text: { content: task.title }, }, ], }, 'Task ID': { rich_text: [ { text: { content: task.id }, }, ], }, Team: { select: { name: task.team }, }, Owner: { rich_text: [ { text: { content: task.owner }, }, ], }, Duration: { number: task.duration_days, }, Dependencies: { rich_text: [ { text: { content: task.dependencies.join(', ') }, }, ], }, Status: { select: { name: 'Not Started' }, }, Launch: { rich_text: [ { text: { content: launchPlan.launch_name }, }, ], }, }, }); } console.log( `Created ${launchPlan.tasks.length} tasks in Notion for ${launchPlan.launch_name}` ); return launchPlan; } // Usage const launchBrief = ` Launch: AI-powered analytics dashboard Target date: Sept 15 Teams: Engineering (backend, frontend), Marketing (landing, email, social), Sales (pricing, demo), Support (docs, training), Legal (terms) Key dependencies: API before frontend, pricing before landing page `; const plan = await generateLaunchTasks(launchBrief); console.log(`Generated ${plan.tasks.length} tasks`);
Level 2: With Dependency Tracking & Alerts
Good for: 5-20 launches/year | Setup time: 2 hours
# With Dependency Tracking & Alerts (5-20 launches/year) import anthropic import requests from datetime import datetime, timedelta from typing import List, Dict, Set import os class LaunchOrchestrator: def __init__(self): self.anthropic = anthropic.Anthropic(api_key=os.getenv('ANTHROPIC_API_KEY')) self.slack_webhook = os.getenv('SLACK_WEBHOOK_URL') self.linear_api_key = os.getenv('LINEAR_API_KEY') def generate_and_track_launch(self, launch_brief: str) -> Dict: """Generate tasks, map dependencies, create tracking""" # Step 1: Generate tasks tasks = self._generate_tasks(launch_brief) # Step 2: Build dependency graph dep_graph = self._build_dependency_graph(tasks) # Step 3: Calculate critical path critical_path = self._find_critical_path(dep_graph) # Step 4: Create issues in Linear linear_issues = self._create_linear_issues(tasks, dep_graph) # Step 5: Set up automated reminders self._schedule_reminders(tasks, dep_graph, linear_issues) return { 'tasks': tasks, 'dependency_graph': dep_graph, 'critical_path': critical_path, 'linear_issues': linear_issues } def _generate_tasks(self, launch_brief: str) -> List[Dict]: """Use Claude to generate comprehensive task list""" response = self.anthropic.messages.create( model='claude-3-5-sonnet-20241022', max_tokens=4096, messages=[{ 'role': 'user', 'content': f'''Generate detailed launch tasks as JSON. Launch brief: {launch_brief} Output format: {{ "launch_name": str, "target_date": "YYYY-MM-DD", "tasks": [{{ "id": "team-###", "title": str, "team": str, "owner": str, "duration_days": int, "dependencies": [str], "deliverable": str }}] }}''' }] ) import json return json.loads(response.content[0].text) def _build_dependency_graph(self, launch_data: Dict) -> Dict: """Build bidirectional dependency graph""" tasks = launch_data['tasks'] graph = {} # Initialize graph for task in tasks: graph[task['id']] = { 'task': task, 'blocks': [], # Tasks that depend on this 'blocked_by': task['dependencies'], 'can_start_immediately': len(task['dependencies']) == 0 } # Build "blocks" relationships for task in tasks: for dep_id in task['dependencies']: if dep_id in graph: graph[dep_id]['blocks'].append(task['id']) # Calculate latest start dates target_date = datetime.strptime(launch_data['target_date'], '%Y-%m-%d') for task_id in graph: task = graph[task_id]['task'] # Work backwards from target date latest_start = target_date - timedelta(days=task['duration_days']) graph[task_id]['latest_start_date'] = latest_start.strftime('%Y-%m-%d') return graph def _find_critical_path(self, dep_graph: Dict) -> List[str]: """Find longest path through dependency graph""" def calculate_path_length(task_id: str, visited: Set[str]) -> int: if task_id in visited: return 0 visited.add(task_id) task = dep_graph[task_id]['task'] if not dep_graph[task_id]['blocks']: return task['duration_days'] max_path = 0 for blocked_task in dep_graph[task_id]['blocks']: path_length = calculate_path_length(blocked_task, visited.copy()) max_path = max(max_path, path_length) return task['duration_days'] + max_path # Find task with longest path critical_tasks = [] max_length = 0 for task_id in dep_graph: if dep_graph[task_id]['can_start_immediately']: length = calculate_path_length(task_id, set()) if length > max_length: max_length = length # Reconstruct path (simplified) critical_tasks = [task_id] return critical_tasks def _create_linear_issues(self, launch_data: Dict, dep_graph: Dict) -> List[str]: """Create issues in Linear with dependencies""" headers = { 'Authorization': self.linear_api_key, 'Content-Type': 'application/json' } issue_ids = {} for task in launch_data['tasks']: # Create Linear issue mutation = ''' mutation CreateIssue($input: IssueCreateInput!) { issueCreate(input: $input) { issue { id identifier } } } ''' variables = { 'input': { 'title': task['title'], 'description': f"**Deliverable:** {task['deliverable']}\n\n**Duration:** {task['duration_days']} days\n\n**Owner:** {task['owner']}", 'teamId': self._get_team_id(task['team']), 'labelIds': [self._get_label_id(launch_data['launch_name'])] } } response = requests.post( 'https://api.linear.app/graphql', headers=headers, json={'query': mutation, 'variables': variables} ) issue_id = response.json()['data']['issueCreate']['issue']['id'] issue_ids[task['id']] = issue_id # Add dependency relationships for task in launch_data['tasks']: if task['dependencies']: for dep_id in task['dependencies']: if dep_id in issue_ids: self._add_linear_dependency( issue_ids[task['id']], issue_ids[dep_id] ) return list(issue_ids.values()) def _schedule_reminders(self, launch_data: Dict, dep_graph: Dict, linear_issues: List[str]): """Schedule Slack reminders for deadlines""" for task in launch_data['tasks']: task_id = task['id'] latest_start = dep_graph[task_id]['latest_start_date'] # Start reminder self._send_slack_reminder( date=latest_start, message=f"๐ Time to start: {task['title']}\nOwner: {task['owner']}\nDuration: {task['duration_days']} days", channel=self._get_team_channel(task['team']) ) # Midpoint check (if task > 5 days) if task['duration_days'] > 5: midpoint = datetime.strptime(latest_start, '%Y-%m-%d') + timedelta(days=task['duration_days'] // 2) self._send_slack_reminder( date=midpoint.strftime('%Y-%m-%d'), message=f"๐ Midpoint check: {task['title']}\nHow's it going? Need any blockers cleared?", channel=self._get_team_channel(task['team']) ) # Deadline warning (2 days before) deadline = datetime.strptime(latest_start, '%Y-%m-%d') + timedelta(days=task['duration_days'] - 2) self._send_slack_reminder( date=deadline.strftime('%Y-%m-%d'), message=f"โ ๏ธ 2 days until deadline: {task['title']}\n{len(dep_graph[task_id]['blocks'])} tasks are waiting on this.", channel=self._get_team_channel(task['team']) ) def _send_slack_reminder(self, date: str, message: str, channel: str): """Send reminder to Slack (simplified - use actual scheduling service)""" # In production, use a service like AWS EventBridge or Zapier payload = { 'channel': channel, 'text': message, 'scheduled_date': date } # Store in database for cron job to process print(f"Scheduled reminder for {date}: {message[:50]}...") def _get_team_id(self, team_name: str) -> str: # Map team names to Linear team IDs team_map = { 'Engineering': 'eng-team-id', 'Marketing': 'mkt-team-id', 'Sales': 'sales-team-id' } return team_map.get(team_name, 'default-team-id') def _get_team_channel(self, team_name: str) -> str: # Map team names to Slack channels channel_map = { 'Engineering': '#engineering', 'Marketing': '#marketing', 'Sales': '#sales' } return channel_map.get(team_name, '#general') def _get_label_id(self, launch_name: str) -> str: # Create or get label for this launch return 'launch-label-id' def _add_linear_dependency(self, issue_id: str, depends_on_id: str): # Add dependency relationship in Linear pass # Usage orchestrator = LaunchOrchestrator() launch_brief = ''' Launch: AI-powered analytics dashboard Target date: 2025-09-15 Teams: Engineering (backend API, frontend UI), Marketing (landing page, email, social), Sales (pricing, demo), Support (docs, training), Legal (terms) Key dependencies: API before frontend, pricing before landing page, frontend before docs ''' result = orchestrator.generate_and_track_launch(launch_brief) print(f"Created {len(result['tasks']['tasks'])} tasks") print(f"Critical path: {result['critical_path']}")
Level 3: Production Orchestration Platform
Good for: 20+ launches/year | Setup time: 1 week
// Production Orchestration Platform (20+ launches/year) import Anthropic from '@anthropic-ai/sdk'; import { Client as NotionClient } from '@notionhq/client'; import { WebClient as SlackClient } from '@slack/web-api'; import { google } from 'googleapis'; import { PrismaClient } from '@prisma/client'; import { Queue } from 'bullmq'; interface LaunchConfig { name: string; targetDate: Date; teams: string[]; stakeholders: string[]; integrations: { notion?: boolean; linear?: boolean; slack?: boolean; calendar?: boolean; }; } class ProductLaunchOrchestrator { private anthropic: Anthropic; private notion: NotionClient; private slack: SlackClient; private calendar: any; private db: PrismaClient; private reminderQueue: Queue; constructor() { this.anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY!, }); this.notion = new NotionClient({ auth: process.env.NOTION_API_KEY! }); this.slack = new SlackClient(process.env.SLACK_BOT_TOKEN!); this.calendar = google.calendar({ version: 'v3' }); this.db = new PrismaClient(); this.reminderQueue = new Queue('launch-reminders', { connection: { host: process.env.REDIS_HOST!, port: parseInt(process.env.REDIS_PORT!), }, }); } async orchestrateLaunch(config: LaunchConfig): Promise<string> { // Step 1: Generate comprehensive launch plan const launchPlan = await this.generateLaunchPlan(config); // Step 2: Analyze dependencies and optimize timeline const optimizedPlan = await this.optimizeTimeline(launchPlan); // Step 3: Create tasks across all platforms const taskIds = await this.createTasksEverywhere(optimizedPlan); // Step 4: Set up automated monitoring await this.setupMonitoring(taskIds, optimizedPlan); // Step 5: Schedule all reminders and check-ins await this.scheduleReminders(optimizedPlan, taskIds); // Step 6: Create launch dashboard const dashboardUrl = await this.createDashboard(optimizedPlan); return dashboardUrl; } private async generateLaunchPlan(config: LaunchConfig): Promise<any> { const prompt = `Generate a comprehensive product launch plan with the following: 1. Break down into tasks for each team: ${config.teams.join(', ')} 2. Identify all dependencies between tasks 3. Estimate realistic durations 4. Flag high-risk tasks that need extra attention 5. Suggest parallel work opportunities Launch: ${config.name} Target Date: ${config.targetDate.toISOString()} Stakeholders: ${config.stakeholders.join(', ')} Output as detailed JSON with: - tasks: [{ id, title, team, owner, duration_days, dependencies, risk_level, deliverable }] - milestones: [{ name, date, criteria }] - risks: [{ description, mitigation, owner }]`; const response = await this.anthropic.messages.create({ model: 'claude-3-5-sonnet-20241022', max_tokens: 8192, messages: [{ role: 'user', content: prompt }], }); const content = response.content[0]; if (content.type !== 'text') throw new Error('Invalid response'); const plan = JSON.parse(content.text); // Save to database await this.db.launch.create({ data: { name: config.name, targetDate: config.targetDate, plan: plan, status: 'planning', }, }); return plan; } private async optimizeTimeline(plan: any): Promise<any> { // Build dependency graph const graph = this.buildDependencyGraph(plan.tasks); // Find critical path const criticalPath = this.findCriticalPath(graph); // Identify parallelization opportunities const parallelGroups = this.findParallelTasks(graph); // Calculate buffer days for high-risk tasks const bufferedPlan = this.addBufferDays(plan, criticalPath); // Use AI to suggest optimizations const optimizationPrompt = `Analyze this launch timeline and suggest optimizations: Critical Path: ${criticalPath.map((t: any) => t.title).join(' โ ')} Total Duration: ${this.calculateDuration(criticalPath)} days Parallel Groups: ${parallelGroups.length} Suggest: 1. Tasks that could start earlier 2. Dependencies that might be unnecessary 3. Ways to reduce critical path 4. Resource allocation improvements Output as JSON with actionable recommendations.`; const response = await this.anthropic.messages.create({ model: 'claude-3-5-sonnet-20241022', max_tokens: 4096, messages: [{ role: 'user', content: optimizationPrompt }], }); const content = response.content[0]; if (content.type !== 'text') throw new Error('Invalid response'); const optimizations = JSON.parse(content.text); return { ...bufferedPlan, criticalPath, parallelGroups, optimizations, }; } private async createTasksEverywhere( plan: any ): Promise<Record<string, any>> { const taskIds: Record<string, any> = {}; // Create in Notion if (process.env.NOTION_API_KEY) { taskIds.notion = await this.createNotionTasks(plan); } // Create in Linear if (process.env.LINEAR_API_KEY) { taskIds.linear = await this.createLinearIssues(plan); } // Create calendar events if (process.env.GOOGLE_CALENDAR_ID) { taskIds.calendar = await this.createCalendarEvents(plan); } // Create Slack channels for launch if (process.env.SLACK_BOT_TOKEN) { taskIds.slack = await this.createSlackChannels(plan); } return taskIds; } private async setupMonitoring(taskIds: any, plan: any): Promise<void> { // Create monitoring jobs for (const task of plan.tasks) { await this.db.taskMonitor.create({ data: { taskId: task.id, notionId: taskIds.notion?.[task.id], linearId: taskIds.linear?.[task.id], checkInterval: this.getCheckInterval(task.risk_level), lastChecked: new Date(), }, }); } // Set up daily status check job await this.reminderQueue.add( 'daily-status-check', { launchId: plan.id }, { repeat: { pattern: '0 9 * * *', // 9 AM daily }, } ); } private async scheduleReminders(plan: any, taskIds: any): Promise<void> { for (const task of plan.tasks) { const startDate = this.calculateStartDate( plan.targetDate, task, plan.tasks ); // Start reminder await this.reminderQueue.add( 'task-start-reminder', { taskId: task.id, title: task.title, owner: task.owner, team: task.team, }, { delay: startDate.getTime() - Date.now(), } ); // Midpoint check (if task > 3 days) if (task.duration_days > 3) { const midpoint = new Date( startDate.getTime() + (task.duration_days / 2) * 24 * 60 * 60 * 1000 ); await this.reminderQueue.add( 'task-midpoint-check', { taskId: task.id, title: task.title, owner: task.owner, }, { delay: midpoint.getTime() - Date.now(), } ); } // Deadline warning (2 days before) const deadline = new Date( startDate.getTime() + task.duration_days * 24 * 60 * 60 * 1000 ); const warningDate = new Date(deadline.getTime() - 2 * 24 * 60 * 60 * 1000); await this.reminderQueue.add( 'task-deadline-warning', { taskId: task.id, title: task.title, owner: task.owner, blockedTasks: this.getBlockedTasks(task.id, plan.tasks), }, { delay: warningDate.getTime() - Date.now(), } ); // Dependency completion alerts if (task.dependencies.length > 0) { await this.reminderQueue.add( 'dependency-watch', { taskId: task.id, dependencies: task.dependencies, }, { repeat: { pattern: '0 */6 * * *', // Check every 6 hours }, } ); } } } private async createDashboard(plan: any): Promise<string> { // Create Notion dashboard page const page = await this.notion.pages.create({ parent: { database_id: process.env.NOTION_DASHBOARD_DB_ID! }, properties: { Name: { title: [ { text: { content: `${plan.name} - Launch Dashboard` }, }, ], }, 'Launch Date': { date: { start: plan.targetDate }, }, }, children: [ { object: 'block', type: 'heading_1', heading_1: { rich_text: [{ text: { content: 'Launch Overview' } }], }, }, { object: 'block', type: 'paragraph', paragraph: { rich_text: [ { text: { content: `Total Tasks: ${plan.tasks.length} | Critical Path: ${plan.criticalPath.length} tasks`, }, }, ], }, }, // Add more dashboard blocks ], }); return page.url; } // Helper methods private buildDependencyGraph(tasks: any[]): Map<string, any> { const graph = new Map(); for (const task of tasks) { graph.set(task.id, { task, dependencies: task.dependencies, dependents: [], }); } // Build dependents for (const task of tasks) { for (const depId of task.dependencies) { const dep = graph.get(depId); if (dep) { dep.dependents.push(task.id); } } } return graph; } private findCriticalPath(graph: Map<string, any>): any[] { // Implement longest path algorithm // Returns array of tasks on critical path return []; } private findParallelTasks(graph: Map<string, any>): any[][] { // Group tasks that can run in parallel return []; } private addBufferDays(plan: any, criticalPath: any[]): any { // Add buffer days to high-risk tasks return plan; } private calculateDuration(tasks: any[]): number { return tasks.reduce((sum, t) => sum + t.duration_days, 0); } private getCheckInterval(riskLevel: string): number { const intervals = { high: 6, // hours medium: 12, low: 24, }; return intervals[riskLevel as keyof typeof intervals] || 24; } private calculateStartDate( targetDate: Date, task: any, allTasks: any[] ): Date { // Calculate latest start date based on dependencies return new Date(); } private getBlockedTasks(taskId: string, allTasks: any[]): string[] { return allTasks .filter((t) => t.dependencies.includes(taskId)) .map((t) => t.title); } private async createNotionTasks(plan: any): Promise<Record<string, string>> { // Implementation return {}; } private async createLinearIssues(plan: any): Promise<Record<string, string>> { // Implementation return {}; } private async createCalendarEvents( plan: any ): Promise<Record<string, string>> { // Implementation return {}; } private async createSlackChannels(plan: any): Promise<Record<string, string>> { // Implementation return {}; } } // Usage const orchestrator = new ProductLaunchOrchestrator(); const config: LaunchConfig = { name: 'AI-powered analytics dashboard', targetDate: new Date('2025-09-15'), teams: ['Engineering', 'Marketing', 'Sales', 'Support', 'Legal'], stakeholders: ['CEO', 'VP Product', 'VP Engineering', 'VP Marketing'], integrations: { notion: true, linear: true, slack: true, calendar: true, }, }; const dashboardUrl = await orchestrator.orchestrateLaunch(config); console.log(`Launch dashboard: ${dashboardUrl}`);
When to Level Up
Start: Simple Task Generation
1-5 launches/year
- Generate task list from launch brief
- Create tasks in Notion or Linear
- Manual dependency tracking
- Email reminders for deadlines
Scale: Add Dependency Tracking
5-20 launches/year
- Automated dependency graph building
- Critical path calculation
- Slack reminders for task starts and deadlines
- Midpoint check-ins for long tasks
- Blocker detection and alerts
Production: Full Orchestration Platform
20-50 launches/year
- Multi-platform sync (Notion + Linear + Slack + Calendar)
- AI-powered timeline optimization
- Automated status monitoring with daily digests
- Risk detection and mitigation suggestions
- Launch dashboard with real-time progress
- Human-in-the-loop for high-risk decisions
Enterprise: Multi-Launch Coordination
50+ launches/year
- Portfolio-level resource allocation (prevent team overload)
- Cross-launch dependency detection (Launch B needs Launch A's API)
- Predictive analytics (forecast delays based on historical data)
- Automated post-launch retrospectives
- Integration with product analytics (measure launch success)
- Custom workflows per product line or region
Product Launch Gotchas
The code examples work for basic launches. But real product launches have unique challenges you need to handle.
Dependency Cycles and Deadlocks
Sometimes teams create circular dependencies: Marketing needs pricing from Sales, but Sales needs the landing page from Marketing to finalize pricing. Detect and break these cycles.
function detectDependencyCycles(tasks: Task[]): string[][] { const graph = buildGraph(tasks); const cycles: string[][] = []; const visited = new Set<string>(); const recStack = new Set<string>(); function dfs(taskId: string, path: string[]): boolean { visited.add(taskId); recStack.add(taskId); path.push(taskId); const task = graph.get(taskId); if (!task) return false; for (const depId of task.dependencies) { if (!visited.has(depId)) { if (dfs(depId, path)) return true; } else if (recStack.has(depId)) { // Found cycle const cycleStart = path.indexOf(depId); cycles.push(path.slice(cycleStart)); return true; } } recStack.delete(taskId); path.pop(); return false; } for (const taskId of graph.keys()) { if (!visited.has(taskId)) { dfs(taskId, []); } } if (cycles.length > 0) { // Alert stakeholders about cycles sendSlackAlert( '#launch-coordination', `โ ๏ธ Dependency cycle detected: ${cycles[0].join(' โ ')}\nOne of these tasks needs to start without waiting.` ); } return cycles; }
Resource Overallocation (Team Burnout)
Your AI might assign 5 tasks to the same person with overlapping deadlines. Track team capacity and flag overallocation before it becomes a problem.
from collections import defaultdict from datetime import datetime, timedelta def check_resource_overallocation(tasks: list[dict], team_capacity: dict) -> list[dict]: """Detect when team members are assigned too many concurrent tasks""" # Build timeline of who's working on what when person_timeline = defaultdict(list) for task in tasks: start_date = datetime.strptime(task['start_date'], '%Y-%m-%d') end_date = start_date + timedelta(days=task['duration_days']) person_timeline[task['owner']].append({ 'task_id': task['id'], 'task_title': task['title'], 'start': start_date, 'end': end_date, 'effort_hours_per_day': task.get('effort_hours', 8) # Default full-time }) # Check for overallocation overallocations = [] for person, timeline in person_timeline.items(): # Sort by start date timeline.sort(key=lambda x: x['start']) # Check each day for total hours current_date = min(t['start'] for t in timeline) end_date = max(t['end'] for t in timeline) while current_date <= end_date: daily_hours = 0 active_tasks = [] for task in timeline: if task['start'] <= current_date <= task['end']: daily_hours += task['effort_hours_per_day'] active_tasks.append(task['task_title']) # Flag if over capacity (default 8 hours/day) max_hours = team_capacity.get(person, 8) if daily_hours > max_hours: overallocations.append({ 'person': person, 'date': current_date.strftime('%Y-%m-%d'), 'allocated_hours': daily_hours, 'max_hours': max_hours, 'active_tasks': active_tasks, 'severity': 'high' if daily_hours > max_hours * 1.5 else 'medium' }) current_date += timedelta(days=1) if overallocations: # Send alert to launch coordinator high_severity = [o for o in overallocations if o['severity'] == 'high'] if high_severity: send_slack_alert( channel='#launch-coordination', message=f"๐จ Resource overallocation detected!\n{high_severity[0]['person']} is assigned {high_severity[0]['allocated_hours']}h on {high_severity[0]['date']} (max: {high_severity[0]['max_hours']}h)\nTasks: {', '.join(high_severity[0]['active_tasks'])}" ) return overallocations # Usage team_capacity = { 'john@company.com': 8, # Full-time 'sarah@company.com': 6, # Part-time on this project } overallocs = check_resource_overallocation(tasks, team_capacity) if overallocs: print(f"Found {len(overallocs)} overallocation issues")
Scope Creep Detection
Launches always grow in scope. Track when new tasks are added mid-launch and automatically recalculate the timeline. Alert stakeholders if launch date is at risk.
interface ScopeChange { newTasks: Task[]; impactOnTimeline: number; // days added affectedTeams: string[]; riskLevel: 'low' | 'medium' | 'high'; } async function detectScopeCreep( originalPlan: LaunchPlan, currentTasks: Task[] ): Promise<ScopeChange | null> { // Compare current tasks to original plan const originalTaskIds = new Set(originalPlan.tasks.map((t) => t.id)); const newTasks = currentTasks.filter((t) => !originalTaskIds.has(t.id)); if (newTasks.length === 0) return null; // Recalculate critical path with new tasks const newCriticalPath = calculateCriticalPath(currentTasks); const originalCriticalPath = calculateCriticalPath(originalPlan.tasks); const timelineImpact = newCriticalPath.totalDays - originalCriticalPath.totalDays; // Determine risk level let riskLevel: 'low' | 'medium' | 'high' = 'low'; if (timelineImpact > 7) riskLevel = 'high'; else if (timelineImpact > 3) riskLevel = 'medium'; const scopeChange: ScopeChange = { newTasks, impactOnTimeline: timelineImpact, affectedTeams: [...new Set(newTasks.map((t) => t.team))], riskLevel, }; // Alert stakeholders if (riskLevel === 'high') { await sendSlackAlert( '#launch-coordination', `๐จ Scope creep detected!\n\n` + `${newTasks.length} new tasks added\n` + `Timeline impact: +${timelineImpact} days\n` + `Launch date now at risk: ${calculateNewLaunchDate(originalPlan.targetDate, timelineImpact)}\n\n` + `New tasks:\n${newTasks.map((t) => `- ${t.title} (${t.team})`).join('\n')}\n\n` + `Action needed: Review with stakeholders to prioritize or push launch date.` ); // Also use AI to suggest what to cut const cutSuggestions = await suggestTasksToCut(currentTasks, newTasks); await sendSlackAlert( '#launch-coordination', `๐ก AI suggests cutting these tasks to stay on schedule:\n${cutSuggestions.map((t) => `- ${t.title} (saves ${t.days} days)`).join('\n')}` ); } return scopeChange; } async function suggestTasksToCut( allTasks: Task[], newTasks: Task[] ): Promise<Array<{ title: string; days: number }>> { const anthropic = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY! }); const response = await anthropic.messages.create({ model: 'claude-3-5-sonnet-20241022', max_tokens: 2048, messages: [ { role: 'user', content: `We added ${newTasks.length} new tasks to a product launch, pushing the date back ${calculateDelay(allTasks)} days.\n\nSuggest 3-5 tasks we could cut or defer to post-launch to stay on schedule.\n\nAll tasks:\n${JSON.stringify(allTasks)}\n\nNew tasks:\n${JSON.stringify(newTasks)}\n\nOutput as JSON: [{ title, reason_to_cut, days_saved }]`, }, ], }); const content = response.content[0]; if (content.type !== 'text') throw new Error('Invalid response'); return JSON.parse(content.text); }
Cross-Launch Dependencies
Launch B needs Launch A's new API. Your orchestrator needs to detect when launches depend on each other and coordinate across launch teams.
from typing import List, Dict import anthropic def detect_cross_launch_dependencies(launches: List[Dict]) -> List[Dict]: """Use AI to detect when launches depend on each other""" client = anthropic.Anthropic(api_key=os.getenv('ANTHROPIC_API_KEY')) # Prepare launch summaries launch_summaries = [] for launch in launches: launch_summaries.append({ 'id': launch['id'], 'name': launch['name'], 'target_date': launch['target_date'], 'key_deliverables': [t['deliverable'] for t in launch['tasks'][:10]] # Top 10 }) # Ask AI to find dependencies prompt = f"""Analyze these product launches and identify dependencies between them. Launches: {json.dumps(launch_summaries, indent=2)} For each dependency found, output JSON: {{ "dependent_launch": "launch_id", "depends_on_launch": "launch_id", "dependency_description": "what Launch A needs from Launch B", "risk_if_delayed": "impact on Launch A if Launch B is late", "mitigation": "how to reduce dependency or work in parallel" }} Output as JSON array.""" response = client.messages.create( model='claude-3-5-sonnet-20241022', max_tokens=4096, messages=[{'role': 'user', 'content': prompt}] ) dependencies = json.loads(response.content[0].text) # Alert launch coordinators for dep in dependencies: dependent = next(l for l in launches if l['id'] == dep['dependent_launch']) depends_on = next(l for l in launches if l['id'] == dep['depends_on_launch']) send_slack_alert( channel='#launch-coordination', message=f"๐ Cross-launch dependency detected!\n\n" f"{dependent['name']} depends on {depends_on['name']}\n" f"Dependency: {dep['dependency_description']}\n" f"Risk: {dep['risk_if_delayed']}\n\n" f"Mitigation: {dep['mitigation']}\n\n" f"Coordinators: Please sync on timelines." ) return dependencies # Usage active_launches = get_active_launches_from_db() cross_deps = detect_cross_launch_dependencies(active_launches) print(f"Found {len(cross_deps)} cross-launch dependencies")
Post-Launch Task Tracking
Launch day isn't the end. Track post-launch tasks like bug fixes, customer feedback incorporation, and performance monitoring. Don't let these fall through the cracks.
interface PostLaunchTask { id: string; title: string; type: 'bug_fix' | 'feedback' | 'monitoring' | 'optimization'; priority: 'p0' | 'p1' | 'p2'; owner: string; dueDate: Date; linkedToLaunch: string; } async function setupPostLaunchTracking( launchId: string, launchDate: Date ): Promise<void> { // Generate post-launch checklist const postLaunchTasks: PostLaunchTask[] = [ { id: 'post-001', title: 'Monitor error rates for first 48 hours', type: 'monitoring', priority: 'p0', owner: 'engineering_oncall', dueDate: new Date(launchDate.getTime() + 2 * 24 * 60 * 60 * 1000), linkedToLaunch: launchId, }, { id: 'post-002', title: 'Review customer feedback from first 100 users', type: 'feedback', priority: 'p1', owner: 'product_manager', dueDate: new Date(launchDate.getTime() + 7 * 24 * 60 * 60 * 1000), linkedToLaunch: launchId, }, { id: 'post-003', title: 'Optimize slow queries identified in production', type: 'optimization', priority: 'p1', owner: 'backend_team', dueDate: new Date(launchDate.getTime() + 14 * 24 * 60 * 60 * 1000), linkedToLaunch: launchId, }, { id: 'post-004', title: 'Update help docs based on support tickets', type: 'feedback', priority: 'p2', owner: 'support_docs', dueDate: new Date(launchDate.getTime() + 14 * 24 * 60 * 60 * 1000), linkedToLaunch: launchId, }, ]; // Create tasks in Linear with "Post-Launch" label for (const task of postLaunchTasks) { await createLinearIssue({ title: task.title, description: `Post-launch task for ${launchId}`, priority: task.priority, assignee: task.owner, dueDate: task.dueDate, labels: ['post-launch', launchId], }); } // Schedule reminder 1 week after launch await scheduleSlackReminder( new Date(launchDate.getTime() + 7 * 24 * 60 * 60 * 1000), '#launch-coordination', `๐ 1 week post-launch check-in for ${launchId}\n\n` + `Post-launch tasks status:\n` + postLaunchTasks .map((t) => `- ${t.title} (${t.priority})${t.owner})`) .join('\n') + `\n\nSchedule retrospective meeting this week.` ); } // Auto-trigger after launch date await setupPostLaunchTracking('launch-123', new Date('2025-09-15'));
Cost Calculator
Manual Launch Coordination
Limitations:
- โข Can't track more than 2 launches simultaneously
- โข 30% of launches slip by 1-2 weeks
- โข High team stress and burnout
- โข No visibility into bottlenecks until too late
Automated Orchestration
Benefits:
- โ Handle 10+ launches simultaneously
- โ 95% on-time launch rate (vs 70% manual)
- โ Automatic dependency tracking and alerts
- โ Real-time visibility for all stakeholders
- โ Team capacity monitoring prevents burnout