rcrewai 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1692 @@
1
+ ---
2
+ layout: tutorial
3
+ title: Working with Multiple Crews
4
+ description: Learn how to coordinate multiple AI crews for complex, multi-phase operations and large-scale workflows
5
+ ---
6
+
7
+ # Working with Multiple Crews
8
+
9
+ This tutorial demonstrates how to work with multiple crews to handle complex, multi-phase operations that require different specialized teams working together. You'll learn crew coordination, inter-crew communication, resource sharing, and orchestration patterns.
10
+
11
+ ## Table of Contents
12
+ 1. [Understanding Multi-Crew Architecture](#understanding-multi-crew-architecture)
13
+ 2. [Crew Coordination Patterns](#crew-coordination-patterns)
14
+ 3. [Sequential Crew Execution](#sequential-crew-execution)
15
+ 4. [Parallel Crew Operations](#parallel-crew-operations)
16
+ 5. [Resource Sharing Between Crews](#resource-sharing-between-crews)
17
+ 6. [Cross-Crew Communication](#cross-crew-communication)
18
+ 7. [Orchestration Strategies](#orchestration-strategies)
19
+ 8. [Production Multi-Crew Systems](#production-multi-crew-systems)
20
+
21
+ ## Understanding Multi-Crew Architecture
22
+
23
+ Multiple crews are useful when you have distinct phases or domains that require different specialized teams.
24
+
25
+ ### When to Use Multiple Crews
26
+
27
+ - **Phase-based workflows**: Development → Testing → Deployment
28
+ - **Domain separation**: Research → Engineering → Marketing
29
+ - **Scale requirements**: Multiple independent operations
30
+ - **Resource optimization**: Different crews need different resources
31
+ - **Fault isolation**: Failures in one crew don't affect others
32
+
33
+ ### Basic Multi-Crew Setup
34
+
35
+ ```ruby
36
+ require 'rcrewai'
37
+
38
+ # Configure RCrewAI
39
+ RCrewAI.configure do |config|
40
+ config.llm_provider = :openai
41
+ config.temperature = 0.3
42
+ end
43
+
44
+ # ===== RESEARCH CREW =====
45
+ research_crew = RCrewAI::Crew.new("research_team")
46
+
47
+ market_researcher = RCrewAI::Agent.new(
48
+ name: "market_researcher",
49
+ role: "Market Research Analyst",
50
+ goal: "Gather comprehensive market intelligence and consumer insights",
51
+ backstory: "Expert analyst with deep knowledge of market trends and consumer behavior.",
52
+ tools: [RCrewAI::Tools::WebSearch.new]
53
+ )
54
+
55
+ trend_analyst = RCrewAI::Agent.new(
56
+ name: "trend_analyst",
57
+ role: "Trend Analysis Specialist",
58
+ goal: "Identify emerging trends and forecast market direction",
59
+ backstory: "Specialist in trend analysis with predictive modeling expertise.",
60
+ tools: [RCrewAI::Tools::WebSearch.new, RCrewAI::Tools::FileReader.new]
61
+ )
62
+
63
+ research_crew.add_agent(market_researcher)
64
+ research_crew.add_agent(trend_analyst)
65
+
66
+ # ===== DEVELOPMENT CREW =====
67
+ dev_crew = RCrewAI::Crew.new("development_team", process: :hierarchical)
68
+
69
+ tech_lead = RCrewAI::Agent.new(
70
+ name: "tech_lead",
71
+ role: "Technical Lead",
72
+ goal: "Coordinate development efforts and ensure technical excellence",
73
+ backstory: "Senior technical leader with expertise in system architecture and team coordination.",
74
+ manager: true,
75
+ allow_delegation: true,
76
+ tools: [RCrewAI::Tools::FileWriter.new]
77
+ )
78
+
79
+ senior_developer = RCrewAI::Agent.new(
80
+ name: "senior_developer",
81
+ role: "Senior Software Developer",
82
+ goal: "Build robust and scalable software solutions",
83
+ backstory: "Experienced developer skilled in multiple programming languages and frameworks.",
84
+ tools: [RCrewAI::Tools::FileWriter.new, RCrewAI::Tools::FileReader.new]
85
+ )
86
+
87
+ dev_crew.add_agent(tech_lead)
88
+ dev_crew.add_agent(senior_developer)
89
+ ```
90
+
91
+ ## Crew Coordination Patterns
92
+
93
+ ### 1. Pipeline Pattern (Sequential)
94
+
95
+ Crews execute one after another, passing results downstream:
96
+
97
+ ```ruby
98
+ class CrewPipeline
99
+ def initialize(*crews)
100
+ @crews = crews
101
+ @pipeline_results = []
102
+ end
103
+
104
+ def execute(initial_data = {})
105
+ current_data = initial_data
106
+
107
+ @crews.each_with_index do |crew, index|
108
+ puts "🚀 Executing pipeline stage #{index + 1}: #{crew.name}"
109
+
110
+ # Pass previous results as context
111
+ if index > 0
112
+ crew.add_shared_context(@pipeline_results[index - 1])
113
+ end
114
+
115
+ # Execute crew
116
+ stage_result = crew.execute
117
+ @pipeline_results << stage_result
118
+
119
+ # Transform result for next stage
120
+ current_data = transform_for_next_stage(stage_result, index)
121
+
122
+ puts "✅ Stage #{index + 1} completed"
123
+ end
124
+
125
+ {
126
+ pipeline_results: @pipeline_results,
127
+ final_result: current_data,
128
+ success_rate: calculate_success_rate
129
+ }
130
+ end
131
+
132
+ private
133
+
134
+ def transform_for_next_stage(result, stage_index)
135
+ # Transform data between pipeline stages
136
+ {
137
+ stage: stage_index + 1,
138
+ previous_result: result,
139
+ timestamp: Time.now
140
+ }
141
+ end
142
+
143
+ def calculate_success_rate
144
+ successful = @pipeline_results.count { |r| r[:success_rate] > 80 }
145
+ (successful.to_f / @pipeline_results.length * 100).round(1)
146
+ end
147
+ end
148
+
149
+ # Usage
150
+ pipeline = CrewPipeline.new(research_crew, dev_crew)
151
+ results = pipeline.execute(project_requirements: "Build AI-powered analytics dashboard")
152
+ ```
153
+
154
+ ### 2. Fan-Out Pattern (Parallel)
155
+
156
+ Multiple crews work on different aspects simultaneously:
157
+
158
+ ```ruby
159
+ class ParallelCrewOrchestrator
160
+ def initialize
161
+ @crews = []
162
+ @execution_threads = []
163
+ end
164
+
165
+ def add_crew(crew, priority: :normal)
166
+ @crews << { crew: crew, priority: priority }
167
+ end
168
+
169
+ def execute_parallel(max_concurrency: 3)
170
+ puts "🚀 Starting parallel execution of #{@crews.length} crews"
171
+
172
+ # Sort by priority
173
+ sorted_crews = @crews.sort_by do |crew_config|
174
+ priority_order = { high: 0, normal: 1, low: 2 }
175
+ priority_order[crew_config[:priority]]
176
+ end
177
+
178
+ results = {}
179
+
180
+ # Execute crews in batches
181
+ sorted_crews.each_slice(max_concurrency) do |crew_batch|
182
+ threads = crew_batch.map do |crew_config|
183
+ Thread.new do
184
+ crew = crew_config[:crew]
185
+
186
+ begin
187
+ puts " Starting crew: #{crew.name}"
188
+ start_time = Time.now
189
+
190
+ result = crew.execute
191
+ duration = Time.now - start_time
192
+
193
+ {
194
+ crew_name: crew.name,
195
+ success: true,
196
+ result: result,
197
+ duration: duration,
198
+ priority: crew_config[:priority]
199
+ }
200
+ rescue => e
201
+ {
202
+ crew_name: crew.name,
203
+ success: false,
204
+ error: e.message,
205
+ duration: Time.now - start_time
206
+ }
207
+ end
208
+ end
209
+ end
210
+
211
+ # Wait for batch to complete
212
+ threads.each do |thread|
213
+ result = thread.value
214
+ results[result[:crew_name]] = result
215
+
216
+ status = result[:success] ? "✅" : "❌"
217
+ puts " #{status} #{result[:crew_name]} completed in #{result[:duration].round(2)}s"
218
+ end
219
+ end
220
+
221
+ results
222
+ end
223
+ end
224
+
225
+ # Create specialized crews
226
+ content_crew = RCrewAI::Crew.new("content_creation")
227
+ seo_crew = RCrewAI::Crew.new("seo_optimization")
228
+ social_media_crew = RCrewAI::Crew.new("social_media")
229
+
230
+ # Setup orchestrator
231
+ orchestrator = ParallelCrewOrchestrator.new
232
+ orchestrator.add_crew(content_crew, priority: :high)
233
+ orchestrator.add_crew(seo_crew, priority: :normal)
234
+ orchestrator.add_crew(social_media_crew, priority: :low)
235
+
236
+ # Execute all crews in parallel
237
+ parallel_results = orchestrator.execute_parallel(max_concurrency: 2)
238
+ ```
239
+
240
+ ## Sequential Crew Execution
241
+
242
+ Complex workflows often require sequential execution with data flow between crews:
243
+
244
+ ```ruby
245
+ # ===== E-COMMERCE LAUNCH PIPELINE =====
246
+
247
+ # Crew 1: Market Research
248
+ research_crew = RCrewAI::Crew.new("market_research")
249
+
250
+ research_crew.add_agent(RCrewAI::Agent.new(
251
+ name: "market_analyst",
252
+ role: "Market Research Analyst",
253
+ goal: "Analyze market opportunity and customer segments",
254
+ tools: [RCrewAI::Tools::WebSearch.new]
255
+ ))
256
+
257
+ research_task = RCrewAI::Task.new(
258
+ name: "market_analysis",
259
+ description: "Conduct comprehensive market research for new e-commerce platform. Analyze target demographics, competition, pricing strategies, and market size.",
260
+ expected_output: "Detailed market analysis report with customer personas, competitive landscape, and go-to-market recommendations"
261
+ )
262
+
263
+ research_crew.add_task(research_task)
264
+
265
+ # Crew 2: Product Development
266
+ product_crew = RCrewAI::Crew.new("product_development")
267
+
268
+ product_crew.add_agent(RCrewAI::Agent.new(
269
+ name: "product_manager",
270
+ role: "Product Manager",
271
+ goal: "Define product requirements based on market research",
272
+ tools: [RCrewAI::Tools::FileWriter.new]
273
+ ))
274
+
275
+ product_crew.add_agent(RCrewAI::Agent.new(
276
+ name: "ux_designer",
277
+ role: "UX Designer",
278
+ goal: "Design user experience based on customer insights",
279
+ tools: [RCrewAI::Tools::FileWriter.new]
280
+ ))
281
+
282
+ product_task = RCrewAI::Task.new(
283
+ name: "product_specification",
284
+ description: "Based on market research findings, create detailed product specifications and user experience designs for the e-commerce platform.",
285
+ expected_output: "Product requirements document with feature specifications, user journeys, and design wireframes"
286
+ )
287
+
288
+ product_crew.add_task(product_task)
289
+
290
+ # Crew 3: Technical Implementation
291
+ tech_crew = RCrewAI::Crew.new("technical_team", process: :hierarchical)
292
+
293
+ tech_lead = RCrewAI::Agent.new(
294
+ name: "tech_lead",
295
+ role: "Technical Lead",
296
+ goal: "Coordinate technical implementation",
297
+ manager: true,
298
+ allow_delegation: true,
299
+ tools: [RCrewAI::Tools::FileWriter.new]
300
+ )
301
+
302
+ backend_dev = RCrewAI::Agent.new(
303
+ name: "backend_developer",
304
+ role: "Backend Developer",
305
+ goal: "Build scalable backend systems",
306
+ tools: [RCrewAI::Tools::FileWriter.new]
307
+ )
308
+
309
+ tech_crew.add_agent(tech_lead)
310
+ tech_crew.add_agent(backend_dev)
311
+
312
+ tech_task = RCrewAI::Task.new(
313
+ name: "technical_implementation",
314
+ description: "Implement the e-commerce platform based on product specifications. Build API, database, and core functionality.",
315
+ expected_output: "Working e-commerce platform with API documentation and deployment guide"
316
+ )
317
+
318
+ tech_crew.add_task(tech_task)
319
+
320
+ # Sequential Execution with Data Flow
321
+ class ECommerceOrchestrator
322
+ def initialize(research_crew, product_crew, tech_crew)
323
+ @research_crew = research_crew
324
+ @product_crew = product_crew
325
+ @tech_crew = tech_crew
326
+ @execution_log = []
327
+ end
328
+
329
+ def execute_launch_pipeline
330
+ puts "🚀 Starting E-commerce Launch Pipeline"
331
+ puts "="*50
332
+
333
+ # Phase 1: Market Research
334
+ log_phase("Market Research Phase")
335
+ research_results = @research_crew.execute
336
+
337
+ @execution_log << {
338
+ phase: "research",
339
+ crew: @research_crew.name,
340
+ results: research_results,
341
+ timestamp: Time.now
342
+ }
343
+
344
+ # Phase 2: Product Development (uses research data)
345
+ log_phase("Product Development Phase")
346
+
347
+ # Pass research context to product crew
348
+ research_context = extract_key_insights(research_results)
349
+ @product_crew.add_shared_context(research_context)
350
+
351
+ product_results = @product_crew.execute
352
+
353
+ @execution_log << {
354
+ phase: "product",
355
+ crew: @product_crew.name,
356
+ results: product_results,
357
+ context_from: "research",
358
+ timestamp: Time.now
359
+ }
360
+
361
+ # Phase 3: Technical Implementation (uses product specs)
362
+ log_phase("Technical Implementation Phase")
363
+
364
+ # Pass product specs to tech crew
365
+ product_context = extract_technical_requirements(product_results)
366
+ @tech_crew.add_shared_context(product_context)
367
+
368
+ tech_results = @tech_crew.execute
369
+
370
+ @execution_log << {
371
+ phase: "technical",
372
+ crew: @tech_crew.name,
373
+ results: tech_results,
374
+ context_from: "product",
375
+ timestamp: Time.now
376
+ }
377
+
378
+ # Generate final report
379
+ generate_launch_report
380
+ end
381
+
382
+ private
383
+
384
+ def log_phase(phase_name)
385
+ puts "\n🎯 #{phase_name}"
386
+ puts "-" * phase_name.length
387
+ end
388
+
389
+ def extract_key_insights(research_results)
390
+ # Extract actionable insights for product team
391
+ {
392
+ target_customers: "Extract customer personas from research",
393
+ market_size: "Extract market opportunity data",
394
+ competitive_analysis: "Extract competitive insights",
395
+ pricing_strategy: "Extract pricing recommendations"
396
+ }
397
+ end
398
+
399
+ def extract_technical_requirements(product_results)
400
+ # Extract technical requirements for development team
401
+ {
402
+ feature_list: "Extract feature specifications",
403
+ performance_requirements: "Extract performance criteria",
404
+ integration_needs: "Extract third-party integrations",
405
+ scalability_targets: "Extract scaling requirements"
406
+ }
407
+ end
408
+
409
+ def generate_launch_report
410
+ puts "\n📊 LAUNCH PIPELINE COMPLETED"
411
+ puts "="*50
412
+
413
+ total_duration = @execution_log.last[:timestamp] - @execution_log.first[:timestamp]
414
+
415
+ puts "Total Execution Time: #{total_duration.round(2)} seconds"
416
+ puts "Phases Completed: #{@execution_log.length}"
417
+
418
+ @execution_log.each_with_index do |phase, index|
419
+ success_rate = phase[:results][:success_rate] || 0
420
+ status = success_rate > 80 ? "✅" : "⚠️"
421
+
422
+ puts "#{index + 1}. #{status} #{phase[:phase].capitalize} Phase (#{phase[:crew]})"
423
+ puts " Success Rate: #{success_rate}%"
424
+ puts " Context: #{phase[:context_from] || 'None'}"
425
+ end
426
+
427
+ # Save comprehensive report
428
+ save_launch_report
429
+ end
430
+
431
+ def save_launch_report
432
+ report = {
433
+ pipeline: "E-commerce Launch",
434
+ execution_log: @execution_log,
435
+ summary: {
436
+ phases: @execution_log.length,
437
+ overall_success: @execution_log.all? { |p| p[:results][:success_rate] > 80 },
438
+ total_crews: 3
439
+ }
440
+ }
441
+
442
+ File.write("ecommerce_launch_report.json", JSON.pretty_generate(report))
443
+ puts "\n💾 Launch report saved: ecommerce_launch_report.json"
444
+ end
445
+ end
446
+
447
+ # Execute the complete pipeline
448
+ orchestrator = ECommerceOrchestrator.new(research_crew, product_crew, tech_crew)
449
+ orchestrator.execute_launch_pipeline
450
+ ```
451
+
452
+ ## Parallel Crew Operations
453
+
454
+ When crews can work independently, parallel execution dramatically improves performance:
455
+
456
+ ```ruby
457
+ # ===== CONTENT MARKETING CAMPAIGN =====
458
+
459
+ # Multiple specialized crews working in parallel
460
+ class ContentMarketingCampaign
461
+ def initialize
462
+ @crews = {}
463
+ @shared_resources = {
464
+ brand_guidelines: "Brand voice and style guidelines",
465
+ target_audience: "Target customer personas",
466
+ campaign_theme: "Q4 Holiday Campaign"
467
+ }
468
+ end
469
+
470
+ def setup_crews
471
+ # Content Creation Crew
472
+ @crews[:content] = create_content_crew
473
+
474
+ # SEO Optimization Crew
475
+ @crews[:seo] = create_seo_crew
476
+
477
+ # Social Media Crew
478
+ @crews[:social] = create_social_crew
479
+
480
+ # Email Marketing Crew
481
+ @crews[:email] = create_email_crew
482
+
483
+ # Analytics Crew
484
+ @crews[:analytics] = create_analytics_crew
485
+ end
486
+
487
+ def execute_campaign
488
+ puts "🚀 Launching Multi-Crew Content Marketing Campaign"
489
+ puts "Crews: #{@crews.keys.join(', ')}"
490
+ puts "="*60
491
+
492
+ # Execute crews in parallel with different priorities
493
+ parallel_executor = ThreadPoolExecutor.new(max_threads: 3)
494
+
495
+ futures = {}
496
+
497
+ @crews.each do |crew_type, crew|
498
+ futures[crew_type] = parallel_executor.submit do
499
+ execute_crew_with_monitoring(crew_type, crew)
500
+ end
501
+ end
502
+
503
+ # Wait for all crews to complete
504
+ results = {}
505
+ futures.each do |crew_type, future|
506
+ results[crew_type] = future.value
507
+ end
508
+
509
+ parallel_executor.shutdown
510
+
511
+ # Analyze cross-crew results
512
+ analyze_campaign_results(results)
513
+ end
514
+
515
+ private
516
+
517
+ def create_content_crew
518
+ crew = RCrewAI::Crew.new("content_creation")
519
+
520
+ content_strategist = RCrewAI::Agent.new(
521
+ name: "content_strategist",
522
+ role: "Content Strategy Lead",
523
+ goal: "Create compelling content that drives engagement and conversions",
524
+ tools: [RCrewAI::Tools::WebSearch.new, RCrewAI::Tools::FileWriter.new]
525
+ )
526
+
527
+ copywriter = RCrewAI::Agent.new(
528
+ name: "copywriter",
529
+ role: "Senior Copywriter",
530
+ goal: "Write persuasive copy that connects with target audience",
531
+ tools: [RCrewAI::Tools::FileWriter.new]
532
+ )
533
+
534
+ crew.add_agent(content_strategist)
535
+ crew.add_agent(copywriter)
536
+
537
+ # Add shared context
538
+ crew.add_shared_context(@shared_resources)
539
+
540
+ # Content tasks
541
+ crew.add_task(RCrewAI::Task.new(
542
+ name: "blog_content",
543
+ description: "Create 5 high-quality blog posts for Q4 campaign",
544
+ expected_output: "5 blog posts with SEO optimization and engagement hooks",
545
+ async: true
546
+ ))
547
+
548
+ crew.add_task(RCrewAI::Task.new(
549
+ name: "landing_pages",
550
+ description: "Create compelling landing page copy for campaign",
551
+ expected_output: "Landing page copy with clear CTAs and value propositions",
552
+ async: true
553
+ ))
554
+
555
+ crew
556
+ end
557
+
558
+ def create_seo_crew
559
+ crew = RCrewAI::Crew.new("seo_optimization")
560
+
561
+ seo_specialist = RCrewAI::Agent.new(
562
+ name: "seo_specialist",
563
+ role: "SEO Specialist",
564
+ goal: "Optimize content for maximum organic visibility",
565
+ tools: [RCrewAI::Tools::WebSearch.new, RCrewAI::Tools::FileReader.new]
566
+ )
567
+
568
+ crew.add_agent(seo_specialist)
569
+ crew.add_shared_context(@shared_resources)
570
+
571
+ crew.add_task(RCrewAI::Task.new(
572
+ name: "keyword_research",
573
+ description: "Research high-value keywords for Q4 campaign",
574
+ expected_output: "Keyword strategy with search volumes and competition analysis",
575
+ async: true
576
+ ))
577
+
578
+ crew.add_task(RCrewAI::Task.new(
579
+ name: "content_optimization",
580
+ description: "Optimize existing content for SEO best practices",
581
+ expected_output: "SEO-optimized content with meta descriptions and schema markup",
582
+ async: true
583
+ ))
584
+
585
+ crew
586
+ end
587
+
588
+ def create_social_crew
589
+ crew = RCrewAI::Crew.new("social_media")
590
+
591
+ social_manager = RCrewAI::Agent.new(
592
+ name: "social_manager",
593
+ role: "Social Media Manager",
594
+ goal: "Create engaging social content that drives community growth",
595
+ tools: [RCrewAI::Tools::FileWriter.new]
596
+ )
597
+
598
+ crew.add_agent(social_manager)
599
+ crew.add_shared_context(@shared_resources)
600
+
601
+ crew.add_task(RCrewAI::Task.new(
602
+ name: "social_content",
603
+ description: "Create 30 days of social media content for multiple platforms",
604
+ expected_output: "Social media calendar with platform-specific content and hashtags",
605
+ async: true
606
+ ))
607
+
608
+ crew
609
+ end
610
+
611
+ def create_email_crew
612
+ crew = RCrewAI::Crew.new("email_marketing")
613
+
614
+ email_specialist = RCrewAI::Agent.new(
615
+ name: "email_specialist",
616
+ role: "Email Marketing Specialist",
617
+ goal: "Create high-converting email campaigns",
618
+ tools: [RCrewAI::Tools::FileWriter.new]
619
+ )
620
+
621
+ crew.add_agent(email_specialist)
622
+ crew.add_shared_context(@shared_resources)
623
+
624
+ crew.add_task(RCrewAI::Task.new(
625
+ name: "email_sequence",
626
+ description: "Create automated email sequence for Q4 campaign",
627
+ expected_output: "Email sequence with subject lines, templates, and automation rules",
628
+ async: true
629
+ ))
630
+
631
+ crew
632
+ end
633
+
634
+ def create_analytics_crew
635
+ crew = RCrewAI::Crew.new("analytics_tracking")
636
+
637
+ data_analyst = RCrewAI::Agent.new(
638
+ name: "data_analyst",
639
+ role: "Marketing Data Analyst",
640
+ goal: "Set up tracking and measurement for campaign success",
641
+ tools: [RCrewAI::Tools::FileWriter.new]
642
+ )
643
+
644
+ crew.add_agent(data_analyst)
645
+ crew.add_shared_context(@shared_resources)
646
+
647
+ crew.add_task(RCrewAI::Task.new(
648
+ name: "tracking_setup",
649
+ description: "Set up comprehensive tracking for all campaign channels",
650
+ expected_output: "Analytics setup guide with KPIs, tracking codes, and dashboards",
651
+ async: true
652
+ ))
653
+
654
+ crew
655
+ end
656
+
657
+ def execute_crew_with_monitoring(crew_type, crew)
658
+ start_time = Time.now
659
+
660
+ puts "🔄 Starting #{crew_type} crew..."
661
+
662
+ begin
663
+ results = crew.execute
664
+ duration = Time.now - start_time
665
+
666
+ puts "✅ #{crew_type} crew completed in #{duration.round(2)}s"
667
+
668
+ {
669
+ crew_type: crew_type,
670
+ success: true,
671
+ results: results,
672
+ duration: duration,
673
+ crew_name: crew.name
674
+ }
675
+ rescue => e
676
+ duration = Time.now - start_time
677
+
678
+ puts "❌ #{crew_type} crew failed: #{e.message}"
679
+
680
+ {
681
+ crew_type: crew_type,
682
+ success: false,
683
+ error: e.message,
684
+ duration: duration,
685
+ crew_name: crew.name
686
+ }
687
+ end
688
+ end
689
+
690
+ def analyze_campaign_results(results)
691
+ puts "\n📊 CAMPAIGN EXECUTION RESULTS"
692
+ puts "="*50
693
+
694
+ successful_crews = results.values.count { |r| r[:success] }
695
+ total_duration = results.values.map { |r| r[:duration] }.max
696
+
697
+ puts "Success Rate: #{successful_crews}/#{results.length} crews (#{(successful_crews.to_f/results.length*100).round(1)}%)"
698
+ puts "Total Duration: #{total_duration.round(2)} seconds (parallel execution)"
699
+ puts "Sequential Duration: #{results.values.sum { |r| r[:duration] }.round(2)} seconds (estimated)"
700
+ puts "Time Saved: #{((results.values.sum { |r| r[:duration] } - total_duration) / results.values.sum { |r| r[:duration] } * 100).round(1)}%"
701
+
702
+ puts "\nCrew Performance:"
703
+ results.each do |crew_type, result|
704
+ status = result[:success] ? "✅" : "❌"
705
+ puts " #{status} #{crew_type.to_s.capitalize}: #{result[:duration].round(2)}s"
706
+
707
+ if result[:success]
708
+ success_rate = result[:results][:success_rate] || 0
709
+ puts " Success Rate: #{success_rate}%"
710
+ puts " Tasks: #{result[:results][:completed_tasks] || 0}/#{result[:results][:total_tasks] || 0}"
711
+ else
712
+ puts " Error: #{result[:error]}"
713
+ end
714
+ end
715
+
716
+ # Save campaign results
717
+ campaign_report = {
718
+ campaign: "Q4 Content Marketing",
719
+ execution_type: "parallel",
720
+ crews: results,
721
+ summary: {
722
+ success_rate: (successful_crews.to_f/results.length*100).round(1),
723
+ total_duration: total_duration,
724
+ time_saved_percentage: ((results.values.sum { |r| r[:duration] } - total_duration) / results.values.sum { |r| r[:duration] } * 100).round(1)
725
+ }
726
+ }
727
+
728
+ File.write("campaign_results.json", JSON.pretty_generate(campaign_report))
729
+ puts "\n💾 Campaign report saved: campaign_results.json"
730
+ end
731
+ end
732
+
733
+ # Thread pool executor for parallel crew execution
734
+ class ThreadPoolExecutor
735
+ def initialize(max_threads: 5)
736
+ @max_threads = max_threads
737
+ @threads = []
738
+ end
739
+
740
+ def submit(&block)
741
+ Future.new(&block).tap do |future|
742
+ if @threads.length < @max_threads
743
+ thread = Thread.new { future.execute }
744
+ @threads << thread
745
+ else
746
+ # Wait for a thread to finish
747
+ @threads.first.join
748
+ @threads.shift
749
+ thread = Thread.new { future.execute }
750
+ @threads << thread
751
+ end
752
+ end
753
+ end
754
+
755
+ def shutdown
756
+ @threads.each(&:join)
757
+ end
758
+ end
759
+
760
+ class Future
761
+ def initialize(&block)
762
+ @block = block
763
+ @executed = false
764
+ @result = nil
765
+ @error = nil
766
+ end
767
+
768
+ def execute
769
+ return if @executed
770
+
771
+ begin
772
+ @result = @block.call
773
+ rescue => e
774
+ @error = e
775
+ ensure
776
+ @executed = true
777
+ end
778
+ end
779
+
780
+ def value
781
+ return @result if @executed && @error.nil?
782
+ raise @error if @error
783
+ @result
784
+ end
785
+ end
786
+
787
+ # Execute the campaign
788
+ campaign = ContentMarketingCampaign.new
789
+ campaign.setup_crews
790
+ campaign.execute_campaign
791
+ ```
792
+
793
+ ## Resource Sharing Between Crews
794
+
795
+ Crews can share resources, data, and configurations:
796
+
797
+ ```ruby
798
+ class SharedResourceManager
799
+ def initialize
800
+ @shared_data = {}
801
+ @resource_locks = {}
802
+ end
803
+
804
+ def store_resource(key, value, crew_name)
805
+ @shared_data[key] = {
806
+ value: value,
807
+ created_by: crew_name,
808
+ created_at: Time.now,
809
+ accessed_by: []
810
+ }
811
+
812
+ puts "📦 Resource '#{key}' stored by #{crew_name}"
813
+ end
814
+
815
+ def get_resource(key, crew_name)
816
+ return nil unless @shared_data[key]
817
+
818
+ resource = @shared_data[key]
819
+ resource[:accessed_by] << crew_name unless resource[:accessed_by].include?(crew_name)
820
+
821
+ puts "📤 Resource '#{key}' accessed by #{crew_name}"
822
+ resource[:value]
823
+ end
824
+
825
+ def lock_resource(key, crew_name)
826
+ @resource_locks[key] = crew_name
827
+ puts "🔒 Resource '#{key}' locked by #{crew_name}"
828
+ end
829
+
830
+ def unlock_resource(key, crew_name)
831
+ if @resource_locks[key] == crew_name
832
+ @resource_locks.delete(key)
833
+ puts "🔓 Resource '#{key}' unlocked by #{crew_name}"
834
+ end
835
+ end
836
+
837
+ def resource_stats
838
+ @shared_data.each do |key, resource|
839
+ puts "Resource: #{key}"
840
+ puts " Created by: #{resource[:created_by]}"
841
+ puts " Accessed by: #{resource[:accessed_by].join(', ')}"
842
+ puts " Created at: #{resource[:created_at]}"
843
+ puts
844
+ end
845
+ end
846
+ end
847
+
848
+ # Global resource manager
849
+ $resource_manager = SharedResourceManager.new
850
+
851
+ # Enhanced crew with resource sharing
852
+ class ResourceAwareCrew < RCrewAI::Crew
853
+ def initialize(name, **options)
854
+ super
855
+ @resource_manager = $resource_manager
856
+ end
857
+
858
+ def share_resource(key, value)
859
+ @resource_manager.store_resource(key, value, @name)
860
+ end
861
+
862
+ def get_shared_resource(key)
863
+ @resource_manager.get_resource(key, @name)
864
+ end
865
+
866
+ def execute_with_resources
867
+ puts "🚀 #{@name} starting execution with shared resources"
868
+
869
+ # Get shared resources before execution
870
+ setup_shared_context
871
+
872
+ # Execute normally
873
+ results = execute
874
+
875
+ # Share results with other crews
876
+ share_execution_results(results)
877
+
878
+ results
879
+ end
880
+
881
+ private
882
+
883
+ def setup_shared_context
884
+ # Get available shared resources
885
+ shared_config = get_shared_resource("global_config")
886
+ shared_data = get_shared_resource("processed_data")
887
+
888
+ if shared_config
889
+ add_shared_context(shared_config)
890
+ end
891
+
892
+ if shared_data
893
+ add_shared_context({ shared_data: shared_data })
894
+ end
895
+ end
896
+
897
+ def share_execution_results(results)
898
+ # Share key results with other crews
899
+ share_resource("#{@name}_results", {
900
+ success_rate: results[:success_rate],
901
+ key_outputs: extract_key_outputs(results),
902
+ execution_time: Time.now
903
+ })
904
+ end
905
+
906
+ def extract_key_outputs(results)
907
+ # Extract the most useful outputs for other crews
908
+ results[:results]&.map { |r| r[:result] }&.join("\n\n")[0..500] || ""
909
+ end
910
+ end
911
+
912
+ # Example: Product Launch with Resource Sharing
913
+ research_crew = ResourceAwareCrew.new("market_research")
914
+ development_crew = ResourceAwareCrew.new("product_development")
915
+ marketing_crew = ResourceAwareCrew.new("marketing_launch")
916
+
917
+ # Share global configuration
918
+ $resource_manager.store_resource("global_config", {
919
+ product_name: "AI Analytics Platform",
920
+ target_market: "B2B SaaS",
921
+ launch_date: "2024-Q2",
922
+ budget: "$500K"
923
+ }, "orchestrator")
924
+
925
+ # Execute crews with resource sharing
926
+ puts "🌐 Multi-Crew Product Launch with Resource Sharing"
927
+ puts "="*60
928
+
929
+ # Research phase shares market data
930
+ research_results = research_crew.execute_with_resources
931
+
932
+ # Development phase uses market data
933
+ development_results = development_crew.execute_with_resources
934
+
935
+ # Marketing phase uses both previous results
936
+ marketing_results = marketing_crew.execute_with_resources
937
+
938
+ # Show resource usage
939
+ puts "\n📊 SHARED RESOURCE STATISTICS"
940
+ puts "-"*40
941
+ $resource_manager.resource_stats
942
+ ```
943
+
944
+ ## Cross-Crew Communication
945
+
946
+ Enable crews to communicate and coordinate during execution:
947
+
948
+ ```ruby
949
+ class CrewCommunicationHub
950
+ def initialize
951
+ @message_queues = {}
952
+ @subscriptions = {}
953
+ @message_history = []
954
+ end
955
+
956
+ def register_crew(crew_name)
957
+ @message_queues[crew_name] = []
958
+ @subscriptions[crew_name] = []
959
+ end
960
+
961
+ def subscribe(subscriber_crew, publisher_crew, message_types: :all)
962
+ @subscriptions[subscriber_crew] << {
963
+ publisher: publisher_crew,
964
+ message_types: message_types
965
+ }
966
+
967
+ puts "📞 #{subscriber_crew} subscribed to #{publisher_crew}"
968
+ end
969
+
970
+ def send_message(from_crew, to_crew, message_type, content)
971
+ message = {
972
+ from: from_crew,
973
+ to: to_crew,
974
+ type: message_type,
975
+ content: content,
976
+ timestamp: Time.now,
977
+ id: SecureRandom.uuid[0..8]
978
+ }
979
+
980
+ @message_queues[to_crew] << message
981
+ @message_history << message
982
+
983
+ puts "💌 Message sent from #{from_crew} to #{to_crew}: #{message_type}"
984
+
985
+ # Notify subscribers
986
+ notify_subscribers(message)
987
+ end
988
+
989
+ def broadcast_message(from_crew, message_type, content)
990
+ @message_queues.keys.each do |crew_name|
991
+ next if crew_name == from_crew
992
+ send_message(from_crew, crew_name, message_type, content)
993
+ end
994
+ end
995
+
996
+ def get_messages(crew_name)
997
+ messages = @message_queues[crew_name] || []
998
+ @message_queues[crew_name] = [] # Clear after reading
999
+ messages
1000
+ end
1001
+
1002
+ def get_messages_by_type(crew_name, message_type)
1003
+ get_messages(crew_name).select { |m| m[:type] == message_type }
1004
+ end
1005
+
1006
+ private
1007
+
1008
+ def notify_subscribers(message)
1009
+ @subscriptions.each do |subscriber, subscriptions|
1010
+ subscriptions.each do |sub|
1011
+ if sub[:publisher] == message[:from]
1012
+ if sub[:message_types] == :all || sub[:message_types].include?(message[:type])
1013
+ @message_queues[subscriber] << message.merge(subscription: true)
1014
+ end
1015
+ end
1016
+ end
1017
+ end
1018
+ end
1019
+ end
1020
+
1021
+ # Global communication hub
1022
+ $comm_hub = CrewCommunicationHub.new
1023
+
1024
+ class CommunicatingCrew < RCrewAI::Crew
1025
+ def initialize(name, **options)
1026
+ super
1027
+ @comm_hub = $comm_hub
1028
+ @comm_hub.register_crew(@name)
1029
+ end
1030
+
1031
+ def send_message(to_crew, message_type, content)
1032
+ @comm_hub.send_message(@name, to_crew, message_type, content)
1033
+ end
1034
+
1035
+ def broadcast(message_type, content)
1036
+ @comm_hub.broadcast_message(@name, message_type, content)
1037
+ end
1038
+
1039
+ def get_messages(type: nil)
1040
+ if type
1041
+ @comm_hub.get_messages_by_type(@name, type)
1042
+ else
1043
+ @comm_hub.get_messages(@name)
1044
+ end
1045
+ end
1046
+
1047
+ def subscribe_to(other_crew, message_types: :all)
1048
+ @comm_hub.subscribe(@name, other_crew, message_types: message_types)
1049
+ end
1050
+
1051
+ def execute_with_communication
1052
+ puts "🚀 #{@name} starting execution with communication enabled"
1053
+
1054
+ # Check for incoming messages before execution
1055
+ process_incoming_messages
1056
+
1057
+ # Notify others of start
1058
+ broadcast(:status, "Starting execution")
1059
+
1060
+ # Execute with periodic message checking
1061
+ results = execute_with_message_monitoring
1062
+
1063
+ # Notify completion
1064
+ broadcast(:completion, {
1065
+ success_rate: results[:success_rate],
1066
+ key_results: summarize_results(results)
1067
+ })
1068
+
1069
+ results
1070
+ end
1071
+
1072
+ private
1073
+
1074
+ def process_incoming_messages
1075
+ messages = get_messages
1076
+
1077
+ messages.each do |message|
1078
+ puts "📨 #{@name} received #{message[:type]} from #{message[:from]}: #{message[:content].to_s[0..50]}..."
1079
+
1080
+ case message[:type]
1081
+ when :status
1082
+ handle_status_message(message)
1083
+ when :request_help
1084
+ handle_help_request(message)
1085
+ when :share_data
1086
+ handle_data_sharing(message)
1087
+ when :coordination
1088
+ handle_coordination(message)
1089
+ end
1090
+ end
1091
+ end
1092
+
1093
+ def execute_with_message_monitoring
1094
+ # Custom execution with message checking
1095
+ total_tasks = @tasks.length
1096
+ completed_tasks = 0
1097
+ results = []
1098
+
1099
+ @tasks.each_with_index do |task, index|
1100
+ # Check messages before each task
1101
+ process_incoming_messages
1102
+
1103
+ # Execute task
1104
+ begin
1105
+ result = task.execute
1106
+ completed_tasks += 1
1107
+
1108
+ results << {
1109
+ task: task,
1110
+ result: result,
1111
+ status: :completed
1112
+ }
1113
+
1114
+ # Notify progress
1115
+ progress = (completed_tasks.to_f / total_tasks * 100).round
1116
+ broadcast(:progress, { task: task.name, progress: progress })
1117
+
1118
+ rescue => e
1119
+ results << {
1120
+ task: task,
1121
+ error: e,
1122
+ status: :failed
1123
+ }
1124
+
1125
+ # Request help if task fails
1126
+ send_message("support_crew", :request_help, {
1127
+ failed_task: task.name,
1128
+ error: e.message
1129
+ })
1130
+ end
1131
+ end
1132
+
1133
+ # Calculate final results
1134
+ success_rate = (completed_tasks.to_f / total_tasks * 100).round
1135
+
1136
+ {
1137
+ success_rate: success_rate,
1138
+ total_tasks: total_tasks,
1139
+ completed_tasks: completed_tasks,
1140
+ results: results
1141
+ }
1142
+ end
1143
+
1144
+ def handle_status_message(message)
1145
+ puts "📊 Status update from #{message[:from]}: #{message[:content]}"
1146
+ end
1147
+
1148
+ def handle_help_request(message)
1149
+ puts "🆘 Help request from #{message[:from]}: #{message[:content]}"
1150
+
1151
+ # Offer assistance if available
1152
+ send_message(message[:from], :offer_help, {
1153
+ from_crew: @name,
1154
+ available_agents: @agents.map(&:name),
1155
+ response_to: message[:id]
1156
+ })
1157
+ end
1158
+
1159
+ def handle_data_sharing(message)
1160
+ puts "📊 Data shared from #{message[:from]}"
1161
+ add_shared_context(message[:content])
1162
+ end
1163
+
1164
+ def handle_coordination(message)
1165
+ puts "🤝 Coordination message from #{message[:from]}"
1166
+ # Handle coordination logic
1167
+ end
1168
+
1169
+ def summarize_results(results)
1170
+ # Create summary for other crews
1171
+ completed = results[:results].select { |r| r[:status] == :completed }
1172
+ completed.map { |r| r[:result][0..100] }.join(" | ")
1173
+ end
1174
+ end
1175
+
1176
+ # Example: Coordinated Product Development
1177
+ frontend_crew = CommunicatingCrew.new("frontend_team")
1178
+ backend_crew = CommunicatingCrew.new("backend_team")
1179
+ qa_crew = CommunicatingCrew.new("qa_team")
1180
+
1181
+ # Setup communication subscriptions
1182
+ frontend_crew.subscribe_to("backend_team", message_types: [:api_ready, :schema_update])
1183
+ qa_crew.subscribe_to("frontend_team", message_types: [:feature_complete])
1184
+ qa_crew.subscribe_to("backend_team", message_types: [:api_ready])
1185
+
1186
+ puts "🌐 Coordinated Product Development with Cross-Crew Communication"
1187
+ puts "="*70
1188
+
1189
+ # Execute crews with communication
1190
+ backend_results = backend_crew.execute_with_communication
1191
+ frontend_results = frontend_crew.execute_with_communication
1192
+ qa_results = qa_crew.execute_with_communication
1193
+
1194
+ puts "\n💬 Communication completed successfully!"
1195
+ ```
1196
+
1197
+ ## Orchestration Strategies
1198
+
1199
+ Advanced patterns for managing complex multi-crew operations:
1200
+
1201
+ ```ruby
1202
+ class MultiCrewOrchestrator
1203
+ def initialize
1204
+ @crews = {}
1205
+ @execution_graph = {}
1206
+ @resource_manager = SharedResourceManager.new
1207
+ @communication_hub = CrewCommunicationHub.new
1208
+ end
1209
+
1210
+ def add_crew(name, crew, dependencies: [], priority: :normal)
1211
+ @crews[name] = {
1212
+ crew: crew,
1213
+ dependencies: dependencies,
1214
+ priority: priority,
1215
+ status: :pending
1216
+ }
1217
+
1218
+ @execution_graph[name] = dependencies
1219
+ end
1220
+
1221
+ def execute_orchestrated
1222
+ puts "🎼 Starting Multi-Crew Orchestration"
1223
+ puts "Crews: #{@crews.keys.join(', ')}"
1224
+ puts "="*60
1225
+
1226
+ # Calculate execution order based on dependencies
1227
+ execution_order = calculate_execution_order
1228
+
1229
+ puts "Execution Order: #{execution_order.join(' → ')}"
1230
+
1231
+ results = {}
1232
+
1233
+ execution_order.each do |crew_name|
1234
+ puts "\n🎯 Executing #{crew_name}"
1235
+
1236
+ crew_config = @crews[crew_name]
1237
+ crew = crew_config[:crew]
1238
+
1239
+ # Wait for dependencies
1240
+ wait_for_dependencies(crew_name)
1241
+
1242
+ # Mark as running
1243
+ crew_config[:status] = :running
1244
+
1245
+ begin
1246
+ # Execute crew
1247
+ result = crew.execute
1248
+
1249
+ # Mark as completed
1250
+ crew_config[:status] = :completed
1251
+ results[crew_name] = {
1252
+ success: true,
1253
+ result: result,
1254
+ crew_config: crew_config
1255
+ }
1256
+
1257
+ puts "✅ #{crew_name} completed successfully"
1258
+
1259
+ # Share results with dependent crews
1260
+ share_results_with_dependents(crew_name, result)
1261
+
1262
+ rescue => e
1263
+ crew_config[:status] = :failed
1264
+ results[crew_name] = {
1265
+ success: false,
1266
+ error: e.message,
1267
+ crew_config: crew_config
1268
+ }
1269
+
1270
+ puts "❌ #{crew_name} failed: #{e.message}"
1271
+
1272
+ # Handle failure - may need to skip dependent crews
1273
+ handle_crew_failure(crew_name, e)
1274
+ end
1275
+ end
1276
+
1277
+ generate_orchestration_report(results)
1278
+ end
1279
+
1280
+ private
1281
+
1282
+ def calculate_execution_order
1283
+ # Topological sort for dependency resolution
1284
+ visited = Set.new
1285
+ temp_visited = Set.new
1286
+ result = []
1287
+
1288
+ def visit_crew(crew_name, visited, temp_visited, result)
1289
+ return if visited.include?(crew_name)
1290
+
1291
+ if temp_visited.include?(crew_name)
1292
+ raise "Circular dependency detected involving #{crew_name}"
1293
+ end
1294
+
1295
+ temp_visited.add(crew_name)
1296
+
1297
+ @execution_graph[crew_name].each do |dependency|
1298
+ visit_crew(dependency, visited, temp_visited, result)
1299
+ end
1300
+
1301
+ temp_visited.delete(crew_name)
1302
+ visited.add(crew_name)
1303
+ result.unshift(crew_name)
1304
+ end
1305
+
1306
+ @crews.keys.each do |crew_name|
1307
+ visit_crew(crew_name, visited, temp_visited, result) unless visited.include?(crew_name)
1308
+ end
1309
+
1310
+ result
1311
+ end
1312
+
1313
+ def wait_for_dependencies(crew_name)
1314
+ dependencies = @execution_graph[crew_name]
1315
+ return if dependencies.empty?
1316
+
1317
+ puts "⏳ Waiting for dependencies: #{dependencies.join(', ')}"
1318
+
1319
+ dependencies.each do |dep_name|
1320
+ while @crews[dep_name][:status] != :completed
1321
+ if @crews[dep_name][:status] == :failed
1322
+ raise "Dependency #{dep_name} failed, cannot execute #{crew_name}"
1323
+ end
1324
+
1325
+ sleep(1)
1326
+ end
1327
+ end
1328
+
1329
+ puts "✅ All dependencies ready for #{crew_name}"
1330
+ end
1331
+
1332
+ def share_results_with_dependents(crew_name, results)
1333
+ # Find crews that depend on this one
1334
+ dependents = @execution_graph.select { |name, deps| deps.include?(crew_name) }.keys
1335
+
1336
+ dependents.each do |dependent_name|
1337
+ dependent_crew = @crews[dependent_name][:crew]
1338
+
1339
+ # Share results as context
1340
+ if dependent_crew.respond_to?(:add_shared_context)
1341
+ dependent_crew.add_shared_context({
1342
+ "#{crew_name}_results" => results
1343
+ })
1344
+ end
1345
+ end
1346
+ end
1347
+
1348
+ def handle_crew_failure(failed_crew, error)
1349
+ # Find all crews that depend on the failed crew
1350
+ affected_crews = find_affected_crews(failed_crew)
1351
+
1352
+ puts "⚠️ Failure in #{failed_crew} affects: #{affected_crews.join(', ')}"
1353
+
1354
+ # Mark affected crews as blocked
1355
+ affected_crews.each do |crew_name|
1356
+ @crews[crew_name][:status] = :blocked
1357
+ end
1358
+ end
1359
+
1360
+ def find_affected_crews(failed_crew)
1361
+ affected = []
1362
+
1363
+ @execution_graph.each do |crew_name, dependencies|
1364
+ if dependencies.include?(failed_crew) ||
1365
+ dependencies.any? { |dep| find_affected_crews(dep).include?(failed_crew) }
1366
+ affected << crew_name
1367
+ end
1368
+ end
1369
+
1370
+ affected
1371
+ end
1372
+
1373
+ def generate_orchestration_report(results)
1374
+ puts "\n📊 ORCHESTRATION RESULTS"
1375
+ puts "="*50
1376
+
1377
+ successful = results.values.count { |r| r[:success] }
1378
+ total = results.length
1379
+
1380
+ puts "Overall Success Rate: #{successful}/#{total} (#{(successful.to_f/total*100).round(1)}%)"
1381
+ puts
1382
+
1383
+ results.each do |crew_name, result|
1384
+ status = result[:success] ? "✅" : "❌"
1385
+ priority = result[:crew_config][:priority]
1386
+
1387
+ puts "#{status} #{crew_name} (#{priority})"
1388
+
1389
+ if result[:success]
1390
+ success_rate = result[:result][:success_rate] || 0
1391
+ puts " Success Rate: #{success_rate}%"
1392
+ puts " Tasks: #{result[:result][:completed_tasks]}/#{result[:result][:total_tasks]}"
1393
+ else
1394
+ puts " Error: #{result[:error]}"
1395
+ end
1396
+
1397
+ dependencies = result[:crew_config][:dependencies]
1398
+ puts " Dependencies: #{dependencies.empty? ? 'None' : dependencies.join(', ')}"
1399
+ puts
1400
+ end
1401
+
1402
+ # Save orchestration report
1403
+ File.write("orchestration_report.json", JSON.pretty_generate({
1404
+ orchestration: "Multi-Crew Execution",
1405
+ results: results,
1406
+ execution_graph: @execution_graph,
1407
+ summary: {
1408
+ success_rate: (successful.to_f/total*100).round(1),
1409
+ total_crews: total,
1410
+ successful_crews: successful
1411
+ }
1412
+ }))
1413
+
1414
+ puts "💾 Orchestration report saved: orchestration_report.json"
1415
+ end
1416
+ end
1417
+
1418
+ # Example: Complex Software Release Pipeline
1419
+ orchestrator = MultiCrewOrchestrator.new
1420
+
1421
+ # Add crews with dependencies
1422
+ orchestrator.add_crew("planning", planning_crew, dependencies: [])
1423
+ orchestrator.add_crew("development", dev_crew, dependencies: ["planning"])
1424
+ orchestrator.add_crew("testing", qa_crew, dependencies: ["development"])
1425
+ orchestrator.add_crew("security", security_crew, dependencies: ["development"])
1426
+ orchestrator.add_crew("deployment", deploy_crew, dependencies: ["testing", "security"])
1427
+ orchestrator.add_crew("monitoring", monitoring_crew, dependencies: ["deployment"])
1428
+
1429
+ # Execute orchestrated pipeline
1430
+ orchestrator.execute_orchestrated
1431
+ ```
1432
+
1433
+ ## Production Multi-Crew Systems
1434
+
1435
+ Production-ready patterns with monitoring, error handling, and scalability:
1436
+
1437
+ ```ruby
1438
+ class ProductionMultiCrewSystem
1439
+ def initialize
1440
+ @logger = Logger.new($stdout)
1441
+ @metrics = MetricsCollector.new
1442
+ @health_monitor = HealthMonitor.new
1443
+ @crew_registry = {}
1444
+ end
1445
+
1446
+ def register_crew(name, crew, config = {})
1447
+ @crew_registry[name] = {
1448
+ crew: crew,
1449
+ config: config.merge(
1450
+ max_retries: config[:max_retries] || 3,
1451
+ timeout: config[:timeout] || 300,
1452
+ health_check_interval: config[:health_check_interval] || 60
1453
+ ),
1454
+ status: :registered,
1455
+ health: :unknown,
1456
+ last_execution: nil
1457
+ }
1458
+
1459
+ @logger.info("Crew registered: #{name}")
1460
+ end
1461
+
1462
+ def execute_system(execution_plan)
1463
+ @logger.info("Starting production multi-crew system execution")
1464
+ @metrics.start_execution
1465
+
1466
+ begin
1467
+ results = execute_with_monitoring(execution_plan)
1468
+ @metrics.record_success
1469
+ results
1470
+ rescue => e
1471
+ @metrics.record_failure(e)
1472
+ @logger.error("System execution failed: #{e.message}")
1473
+ raise
1474
+ ensure
1475
+ @metrics.finish_execution
1476
+ end
1477
+ end
1478
+
1479
+ private
1480
+
1481
+ def execute_with_monitoring(execution_plan)
1482
+ # Start health monitoring
1483
+ monitoring_thread = start_health_monitoring
1484
+
1485
+ # Execute according to plan
1486
+ results = case execution_plan[:type]
1487
+ when :sequential
1488
+ execute_sequential(execution_plan[:crews])
1489
+ when :parallel
1490
+ execute_parallel(execution_plan[:crews])
1491
+ when :orchestrated
1492
+ execute_orchestrated(execution_plan)
1493
+ else
1494
+ raise "Unknown execution plan type: #{execution_plan[:type]}"
1495
+ end
1496
+
1497
+ # Stop monitoring
1498
+ monitoring_thread.kill if monitoring_thread
1499
+
1500
+ results
1501
+ end
1502
+
1503
+ def start_health_monitoring
1504
+ Thread.new do
1505
+ loop do
1506
+ @crew_registry.each do |name, crew_info|
1507
+ check_crew_health(name, crew_info)
1508
+ end
1509
+
1510
+ sleep(30) # Check every 30 seconds
1511
+ end
1512
+ end
1513
+ end
1514
+
1515
+ def check_crew_health(name, crew_info)
1516
+ begin
1517
+ # Basic health check
1518
+ crew = crew_info[:crew]
1519
+
1520
+ health_status = if crew.respond_to?(:health_check)
1521
+ crew.health_check
1522
+ else
1523
+ # Default health check
1524
+ { status: :healthy, agents: crew.agents.length }
1525
+ end
1526
+
1527
+ crew_info[:health] = health_status[:status]
1528
+ crew_info[:last_health_check] = Time.now
1529
+
1530
+ @health_monitor.record_health_check(name, health_status)
1531
+
1532
+ rescue => e
1533
+ crew_info[:health] = :unhealthy
1534
+ @logger.error("Health check failed for #{name}: #{e.message}")
1535
+ end
1536
+ end
1537
+ end
1538
+
1539
+ class MetricsCollector
1540
+ def initialize
1541
+ @metrics = {
1542
+ executions: 0,
1543
+ successes: 0,
1544
+ failures: 0,
1545
+ total_duration: 0,
1546
+ crew_performance: {}
1547
+ }
1548
+ @current_execution = nil
1549
+ end
1550
+
1551
+ def start_execution
1552
+ @current_execution = {
1553
+ start_time: Time.now,
1554
+ crew_metrics: {}
1555
+ }
1556
+ end
1557
+
1558
+ def record_crew_start(crew_name)
1559
+ @current_execution[:crew_metrics][crew_name] = {
1560
+ start_time: Time.now
1561
+ }
1562
+ end
1563
+
1564
+ def record_crew_completion(crew_name, success, result = nil)
1565
+ crew_metrics = @current_execution[:crew_metrics][crew_name]
1566
+ crew_metrics[:end_time] = Time.now
1567
+ crew_metrics[:duration] = crew_metrics[:end_time] - crew_metrics[:start_time]
1568
+ crew_metrics[:success] = success
1569
+ crew_metrics[:result_size] = result&.to_s&.length || 0
1570
+
1571
+ # Update overall metrics
1572
+ @metrics[:crew_performance][crew_name] ||= {
1573
+ executions: 0,
1574
+ successes: 0,
1575
+ avg_duration: 0
1576
+ }
1577
+
1578
+ crew_perf = @metrics[:crew_performance][crew_name]
1579
+ crew_perf[:executions] += 1
1580
+ crew_perf[:successes] += 1 if success
1581
+ crew_perf[:avg_duration] = (
1582
+ crew_perf[:avg_duration] * (crew_perf[:executions] - 1) + crew_metrics[:duration]
1583
+ ) / crew_perf[:executions]
1584
+ end
1585
+
1586
+ def record_success
1587
+ @metrics[:executions] += 1
1588
+ @metrics[:successes] += 1
1589
+ end
1590
+
1591
+ def record_failure(error)
1592
+ @metrics[:executions] += 1
1593
+ @metrics[:failures] += 1
1594
+ @metrics[:last_error] = error.message
1595
+ end
1596
+
1597
+ def finish_execution
1598
+ return unless @current_execution
1599
+
1600
+ duration = Time.now - @current_execution[:start_time]
1601
+ @metrics[:total_duration] += duration
1602
+ @metrics[:avg_duration] = @metrics[:total_duration] / @metrics[:executions]
1603
+
1604
+ @current_execution = nil
1605
+ end
1606
+
1607
+ def get_metrics
1608
+ @metrics.merge(
1609
+ success_rate: @metrics[:executions] > 0 ?
1610
+ (@metrics[:successes].to_f / @metrics[:executions] * 100).round(1) : 0
1611
+ )
1612
+ end
1613
+ end
1614
+
1615
+ class HealthMonitor
1616
+ def initialize
1617
+ @health_history = {}
1618
+ end
1619
+
1620
+ def record_health_check(crew_name, health_status)
1621
+ @health_history[crew_name] ||= []
1622
+ @health_history[crew_name] << {
1623
+ timestamp: Time.now,
1624
+ status: health_status[:status],
1625
+ details: health_status
1626
+ }
1627
+
1628
+ # Keep only last 100 health checks
1629
+ @health_history[crew_name] = @health_history[crew_name].last(100)
1630
+ end
1631
+
1632
+ def get_health_summary
1633
+ summary = {}
1634
+
1635
+ @health_history.each do |crew_name, checks|
1636
+ recent_checks = checks.last(10)
1637
+ healthy_count = recent_checks.count { |c| c[:status] == :healthy }
1638
+
1639
+ summary[crew_name] = {
1640
+ current_status: recent_checks.last&.[](:status) || :unknown,
1641
+ health_percentage: (healthy_count.to_f / recent_checks.length * 100).round(1),
1642
+ last_check: recent_checks.last&.[](:timestamp)
1643
+ }
1644
+ end
1645
+
1646
+ summary
1647
+ end
1648
+ end
1649
+ ```
1650
+
1651
+ ## Best Practices
1652
+
1653
+ ### 1. **Crew Design Principles**
1654
+ - **Clear Boundaries**: Each crew should have distinct responsibilities
1655
+ - **Minimal Coupling**: Reduce dependencies between crews
1656
+ - **Resource Isolation**: Crews should manage their own resources
1657
+ - **Communication Protocols**: Establish clear communication patterns
1658
+
1659
+ ### 2. **Execution Patterns**
1660
+ - **Sequential**: Use for workflows with strict dependencies
1661
+ - **Parallel**: Use when crews can work independently
1662
+ - **Orchestrated**: Use for complex coordination requirements
1663
+ - **Hybrid**: Combine patterns for optimal performance
1664
+
1665
+ ### 3. **Resource Management**
1666
+ - **Shared Resources**: Use resource managers for shared data
1667
+ - **Resource Locking**: Prevent conflicts with locking mechanisms
1668
+ - **Resource Cleanup**: Ensure resources are released properly
1669
+ - **Resource Monitoring**: Track resource usage and performance
1670
+
1671
+ ### 4. **Error Handling**
1672
+ - **Graceful Degradation**: Handle crew failures without system collapse
1673
+ - **Retry Logic**: Implement intelligent retry strategies
1674
+ - **Fallback Options**: Provide alternative execution paths
1675
+ - **Error Propagation**: Manage error propagation between crews
1676
+
1677
+ ### 5. **Monitoring and Observability**
1678
+ - **Health Checks**: Monitor crew health continuously
1679
+ - **Performance Metrics**: Track execution times and success rates
1680
+ - **Resource Usage**: Monitor memory, CPU, and other resources
1681
+ - **Alerting**: Set up alerts for critical failures
1682
+
1683
+ ## Next Steps
1684
+
1685
+ Now that you understand multi-crew operations:
1686
+
1687
+ 1. Try the [Production Deployment]({{ site.baseurl }}/tutorials/deployment) tutorial
1688
+ 2. Review the [API Documentation]({{ site.baseurl }}/api/) for detailed reference
1689
+ 3. Check out [Advanced Examples]({{ site.baseurl }}/examples/) for complex scenarios
1690
+ 4. Explore [Integration Patterns]({{ site.baseurl }}/guides/) for enterprise use
1691
+
1692
+ Multi-crew systems are essential for building scalable AI operations that can handle complex, enterprise-level workflows with reliability and efficiency.