StoryMatrix uses CrewAI crews to plan stories, produce timelines, generate image prompts, and cast voices.

🎭 Crews

CrewSourceProcessAgents and tasks
Story generationcrew/configs/story_crew.yaml, loaded by CrewFactory.load_crew("story_crew", ...)Sequential; the factory defaults a missing process to sequentialSix agents and five tasks
Timeline generationcrew/configs/timeline_crew.yaml, loaded by CrewFactory.load_crew("timeline_crew", ...)Sequentialaudio_director, audio_intelligence_agent, and audio_direction_task
Image-prompt generationcrew/image_prompt_crew.py:create_image_prompt_generation_crewSequentialThree visual agents and three image-prompt tasks
Voice castingcrew/voice_casting_crew.py:create_voice_casting_crewSequential default; the Crew constructor omits an explicit processcasting_director and casting_task

The factory maps the YAML values sequential and hierarchical to CrewAI process types and falls back to sequential for any other value (crew/factory.py). No crew configuration selects hierarchical processing.

πŸ§‘β€πŸ’» Story agents

The story YAML defines six agents. The factory ignores each agent’s llm and tools keys: every agent receives the crew-level LLM, and no tools argument is passed (crew/configs/story_crew.yaml, crew/factory.py).

YAML keyRoleLLM actually wiredTools actually wiredWired into a crew?
planner_agentStory PlannerCrew-level LLMNoneYes, story crew
persona_architect_agentAuthor Persona ArchitectCrew-level LLMNoneYes, story crew
authorial_voice_agentAuthorial Voice SpecialistCrew-level LLMNoneYes, story crew
visionary_agentCreative Visionary & Style CoordinatorCrew-level LLMNoneYes, story crew
reviewer_agentNarrative Coherence AnalystCrew-level LLMNoneYes, story crew
writer_agentCreative WriterCrew-level LLMNoneYes, story crew

🧾 Story tasks and schemas

YAML keyOwning agentOutput schema class
planning_taskplanner_agentstorymatrix.crew.schemas.StoryPlan
review_taskreviewer_agentstorymatrix.crew.schemas.StoryPlanReview
persona_selection_taskpersona_architect_agentstorymatrix.crew.schemas.AuthorPersonaSelection
writing_taskwriter_agentstorymatrix.crew.schemas.StoryData
style_consistency_taskvisionary_agentstorymatrix.crew.schemas.StoryPlanReview (reused for the consistency assessment)

The task contexts form a sequential dependency: review follows planning; persona selection consumes planning and review; writing consumes all three; style consistency consumes the produced story as well (crew/configs/story_crew.yaml).

🧰 Tool registry

crew/tools/registry.py registers the following exact names when ensure_defaults_loaded() runs:

Registry nameUsed by
audio_timing_validatorTimeline crew
sfx_duration_classifierTimeline crew
sfx_type_classifierTimeline crew
music_segmentation_analyzerTimeline crew
audio_conflict_resolverTimeline crew
timeline_sequence_optimizerTimeline crew
music_scene_mapperTimeline crew
visual_style_mapperStory YAML
aesthetic_coherence_analyzerStory YAML
cross_modal_consistency_checkerStory YAML
voice_consistency_checkerStory YAML
style_analysis_toolStory YAML
dialogue_attribution_validatorStory YAML

The factory calls ensure_defaults_loaded() during initialization, which populates the registry, but it does not resolve YAML tool names into agents (crew/factory.py).

βœ… Timeline contract

TimelineContractValidator.validate() accepts either a dictionary with tracks or an object exposing .tracks; each track may be a dictionary or an object exposing track_type and events (crew/validators/timeline_contract.py). It normalizes track names such as background_music / bgm to music and sound_effects / sound_effect / effects to sfx in the compatibility function.

RuleAcceptedRejected
StructureAt least one trackEmpty or missing tracks
Event timingmetadata.start_time_ms and metadata.end_time_ms; start is non-negative and end is greater than startMissing metadata, missing timing keys, negative start, non-numeric timing, or end not greater than start
LayerMissing layer or integer layer 0, 1, or 2Non-integer layer or any other layer
VolumeMissing volume or numeric volume_db from -12.0 through 0.0Non-numeric volume or a value outside that range
Scene indexMissing scene index or non-negative integerNon-integer or negative scene index
Requested SFXNo extra track requirement when disabled; when enabled, an sfx track with at least two events per sceneMissing sfx or fewer than max(2 Γ— scenes_count, 2) SFX events
Requested musicWhen enabled, a music track with at least one event; when disabled, no music trackMissing enabled music, zero music events, or music present while disabled

Strict mode is enabled by default and raises TimelineValidationError when issues exist. Non-strict mode returns the issue list. The compatibility function validate_timeline_contract() returns (ok, message) with the same required-track, count, and timing checks.

🧩 Persona selection

The persona-selection task names three genre choices inline: Sci-Fi selects Dr. Elias Voss, Fantasy selects Lady Elowen Stormweaver, and Mystery selects Detective Inspector Marcus Hale (crew/configs/story_crew.yaml). The corresponding templates are crew/prompts/personas/sci_fi_author_template.md, fantasy_author_template.md, and mystery_author_template.md; each defines genre, influences, core characteristics, writing approach, voice guidelines, and signature elements. The task selects by genre alignment, requested style guide, character requirements, and thematic consistency, then emits AuthorPersonaSelection.

No source code references the three template filenames, so the current runtime path does not load those Markdown files; the selection prompt carries the persona descriptions instead. The factory does support a file: prefix for agent backstories and resolves such files below crew/prompts/, but the story YAML uses inline backstories for all six agents. The standalone crew/prompts/planner.md, reviewer.md, and writer.md files therefore remain unwired.

⚠️ Known crew breaks and gaps

  • B2 β€” legacy fallback: _create_legacy_story_crew_inline() references the undefined name llm while constructing its fallback LLM, so that path raises NameError rather than creating the legacy crew. Track it at index > b2.
  • B5 β€” mock image-prompt crew: create_image_prompt_generation_crew() assigns the sentinel model string mock-provider/mock-response for MockLLMService; that string reaches LiteLLM and fails because no provider is supplied, so mock mode cannot complete image-prompt generation. Track it at index > b5.
  • Duplicate timeline configuration: crew/timeline_crew.yaml exists beside crew/configs/timeline_crew.yaml. CrewFactory resolves configs_dir / "timeline_crew.yaml", and create_timeline_generation_crew() requests that factory path, so crew/configs/timeline_crew.yaml is live; the root-level crew/timeline_crew.yaml is dead and remains in the repository.