news / engineering
assembling the story intelligence chain

assembling the story intelligence chain

how nine PRs wired co-appearance graphs, dialogue sampling, journey chunking, and relationship synthesis into a single evidence-driven character analysis pipeline.

the central design problem in screenwriting analysis is that the meaningful unit of information is not the scene. the scene is the container. what matters to a writer — and what distinguishes useful analysis from structural extraction — is the accumulated cross-scene picture: where a character’s arc breaks, which relationship changes direction in act two, whether a location’s emotional register has drifted from how it opened. that picture requires aggregating evidence across a whole screenplay before synthesis, not analyzing one scene at a time.

the story intelligence chain shipped across nine core PRs in one drain on 2026-05-17. the design walks this aggregation problem in layers: relationships, character context, journey. each layer produces evidence; the CharacterContextAssembler composes that evidence before the LLM sees it.

relationship graph

the first layer is structural. khaos-tools extracts a co-appearance graph from scene elements — characters who share a scene are connected. this is a deterministic graph walk, no LLM involved. the graph captures which relationships exist and how frequently the parties share scenes, but not what those relationships mean narratively.

the design choice here was to keep the graph extraction separate from the synthesis step, and to represent the pre-synthesis data as an evidence bag rather than a synthesized summary. an evidence bag is a collection of structured text drawn directly from the screenplay — dialogue exchanges, shared stage directions, the sequence in which two characters appear across a scene’s composition. a synthesized summary would already be an LLM interpretation layered on top of that evidence. keeping them separate means the synthesis is auditable: you can read the evidence and the synthesis side by side and ask whether the LLM’s interpretation is warranted. collapsing them at collection time removes that check.

meaning comes from the per-scene interaction evidence collector (PR #180/#194). for each edge in the co-appearance graph, it collects the scene-level evidence of their interaction: dialogue exchanges, shared stage directions, sequence in the scene’s composition. this evidence is a bag of structured text, not a synthesized summary.

StageRelationshipSynthesis (PR #183/#200) is a DAG node in the WFL workflow. it takes the interaction evidence for each character pair and calls the LLM once per pair, producing a relationship-{char-a}-{char-b}.json artifact. the synthesis prompt is constrained to the evidence the node was handed — not the full screenplay. this bounds the context window and makes the result auditable: if the synthesis says two characters have a mentor relationship, the evidence bag shows why.

character context assembly

CharacterContextAssembler (PR #174/#189) is the composition point. it is not a generator — it is a collector. on each call it pulls four evidence streams:

  • scene analyses from the analysis pipeline (previously shipped)
  • synthesized relationship artifacts from the relationship chain
  • dialogue samples from the character’s speaking turns
  • journey timeline from the appearance collector

the assembler’s composition pattern matters because it determines what the LLM sees at synthesis time. rather than concatenating all available evidence into a single prompt, the assembler structures it by evidence type: scene context here, relationship evidence here, voice sample here, journey timeline here. the structure tells the LLM which evidence to weigh for which kind of claim. a claim about character arc should reference the journey timeline; a claim about a specific relationship should reference the relationship artifact. the structured prompt makes those connections explicit rather than leaving the model to infer which evidence supports which claim.

for a 53-scene screenplay like Breaking_Even.kspd — where a lead character may appear across nearly every scene — the assembled context for that character will include dozens of scene analysis references, several synthesized relationship artifacts, a dialogue sample drawn from across the arc, and a journey timeline that spans the full structure. the bounded context window is not a limitation that gets worked around; it is a constraint that shapes what the assembler selects. the chunker and sampler exist because unbounded context is not available, and the design choice was to make the selection explicit and auditable rather than silently truncating.

dialogue sampling (PR #179/#195) does not summarize dialogue. it pulls representative lines from across the screenplay’s structure — one from the first act, one from the midpoint, one from the climax. the goal is to give the LLM the character’s voice in their own words, spaced across the arc, without condensing the voice into a paraphrase.

the journey timeline (PR #175/#199) is a deterministic appearance collector: a pure walker over the composition, emitting scene IDs in order for every scene the character appears in. for characters who appear in more than 50 scenes — the lead in a feature-length screenplay — the high-appearance timeline chunker (PR #178/#201) segments the journey into acts and samples within each segment. this keeps the context window manageable without discarding arc information.

the uncertainty contract

the assembler’s prompt includes a section for what the LLM was not given. if the relationship synthesis for a particular pair was not available — because that relationship edge was below the weight threshold — the prompt says so. if the dialogue sample is sparse — because the character has few speaking turns — the prompt says so. the LLM is told what evidence it does not have, not just what it does.

this is a small structural decision with a large practical effect. without the uncertainty section, the LLM fills gaps with plausible-sounding invention. with it, the LLM hedges appropriately. the difference shows up most clearly on minor characters: a character with two scenes and no synthesized relationships produces a short, appropriately uncertain analysis rather than a confident fabrication.

what changed operationally

the story intelligence chain is triggered by the WFL full-analysis DAG as a stage that runs after scene-level analysis completes. it is not optional; if scene analysis succeeded, relationship synthesis and character assembly run. the outputs are character-{id}.json artifacts alongside the existing scene-{id}.json artifacts. the coverage report assembler (already shipped before this chain) is the downstream consumer.

the chain runs concurrently across characters once the relationship graph is built. entity gating (PR #211 — baseline metadata + stale detection + DDB cache, gating infrastructure introduced in the same release cycle) prevents re-analyzing characters whose evidence inputs have not changed since the last run.

related engineering posts: story intelligence chain lands — relationships, character context, journey