nyxcore-systems
6 min read

Unlocking Narrative Power: Building nyxBook, a Multi-Agent Story Orchestrator

Dive into the journey of building nyxBook, a sophisticated multi-agent system designed to orchestrate the entire book creation process, from schema to UI, tackling backend services, AI personas, and frontend challenges along the way.

TypeScriptNext.jsPrismatRPCReactQueryMulti-AgentAIDevelopmentStorytellingFullstack

It's been an exhilarating sprint at nyxCore, where our mission is to empower creators with intelligent tools. This past week, we hit a major milestone: the completion of nyxBook, a full-fledged multi-agent book orchestration system. Imagine a platform where your narrative ideas come to life, not just with your input, but with the collaborative intelligence of specialized AI agents. That's nyxBook.

Our goal was ambitious: to build a comprehensive system covering everything from the foundational data schema and backend services to a dynamic workflow engine, a robust API, and an intuitive user interface. Today, I'm thrilled to report: all 10 core tasks are complete, type-check clean, lint clean, and ready for content import!

Let's pull back the curtain on how we brought nyxBook to life.

Laying the Foundations: Data and Services

A system this complex needs a rock-solid backend. We started by defining the very essence of a book within our database.

The Blueprint: Prisma Schema Evolution

We extended our Prisma schema to introduce the core entities of a narrative:

  • Book: The overarching container for a literary work.
  • BookChapter: Individual chapters, the building blocks of the story.
  • BookCharacter: The cast of your story, each with their own evolving profiles.
  • BookBeat: Key plot points and narrative progression markers.

Crucially, we also added a Persona.scope field ("global" | "book") and a Workflow.bookId relation. This seemingly small change is foundational for nyxBook's multi-agent capabilities. It allows us to scope AI personas and workflows directly to a specific book, meaning your "dialogue coach" AI won't interfere with your "world-building" AI for another project – true narrative specialization!

The Intelligent Core: Backend Services

This is where nyxBook truly starts to breathe. We developed a suite of services designed to handle the intricate dance of story creation:

  • nyxbook-import.ts: The gateway for existing content. This service handles filesystem imports with a dual-layer parsing mechanism, cleverly separating the raw narrative from the structured Aktenlage (our internal term for "case file" or "structured background data"). This ensures agents can process both the creative prose and the factual underpinnings.
  • nyxbook-context.ts: The narrative glue. This service resolves template variables like {{book.*}}, allowing our agents to pull dynamic information directly from the book's context into their prompts and analyses.
  • nyxbook-voice.ts: Giving characters their unique sound. This service generates CORS-formatted character voice prompts, complete with level-based evolution. Imagine your characters' voices maturing and adapting as the story progresses!
  • workflow-engine.ts Extension: The brain of the operation. We extended our core workflow engine to include bookContext in the ChainContext. This unlocks powerful new template variables ({{book.worldRules}}, {{book.characters}}, {{book.beats}}, {{book.character.HANDLE}}), enabling agents to access and manipulate rich narrative data during their tasks.

The API and User Experience

With the backend humming, we needed a seamless way to interact with nyxBook and provide a delightful user experience.

Type-Safe Interactions with tRPC

Our tRPC router, src/server/trpc/routers/nyxbook.ts, became the central hub for all book-related operations. It provides:

  • Full CRUD (Create, Read, Update, Delete) for all book entities.
  • An import mutation for bringing in external content.
  • Four powerful generation mutations: generateChapter, generateAktenlage, runVoiceTest, and runDialecticalReview. These are the triggers for our multi-agent workflows.
  • A pipelineStatus query to keep track of ongoing agent activities.

We also integrated nyxBookRouter into our main tRPC router and added a crucial scope filter to our personas.ts router, ensuring only relevant personas appear based on the context ("global", "book", or "all").

A Dashboard for Storytellers

The frontend received a significant upgrade to accommodate nyxBook:

  • Dashboard Integration: nyxBook processes now light up our dashboard with distinct amber icons and colors, making it easy to monitor agent activity.
  • Sidebar Navigation: A new "BookOpen" icon under the "Knowledge" group in our sidebar provides quick access to the nyxBook section.
  • Dedicated Book Page: src/app/(dashboard)/dashboard/nyxbook/page.tsx now hosts a beautiful 5-tab layout: Overview, Chapters, Beat Board, Characters, Workshop. This uses our InPageSidebar pattern for excellent navigation.
  • Specialized UI Components:
    • book-pipeline.tsx: A horizontal 5-stage visualization with elegant SVG connectors, showing the journey of your book through various agent stages.
    • chapter-flow.tsx: Per-chapter step indicators, giving you a granular view of progress.
    • beat-board.tsx: A dynamic grid for visualizing plot beats, complete with status color-coding.
    • character-card.tsx: Rich displays for character bible entries, an XP bar (tracking character development!), and a voice test button to hear their unique prompt in action.
  • Chapter Editor: src/app/(dashboard)/dashboard/nyxbook/[bookId]/chapters/[num]/page.tsx is where the magic happens. A tabbed editor allows you to refine narrative, Aktenlage, and notes, all backed by a robust save mutation.

The Literary Team: Seeding Intelligent Personas

To kickstart the multi-agent collaboration, we added six book-scoped literary personas and a dedicated nyxBook Literary Team to our prisma/seed.ts. These initial agents are ready to assist with plot development, character voice, world-building, and more, all tailored to the specific context of your book.

Lessons Learned from the Trenches

No development sprint is without its challenges. Here are a couple of valuable lessons we picked up:

React Query v5 onSuccess Callback

We initially tried to use the onSuccess callback in tRPC v11 with React Query v5's useQuery().

typescript
// Failed attempt
useQuery(trpc.chapter.getById, {
  onSuccess: (data) => {
    // This won't work in React Query v5
    setEditorState(data);
  }
});

The Problem: TS2769: 'onSuccess' does not exist in type 'UseTRPCQueryOptions'. React Query v5 removed onSuccess from useQuery options, favoring a more explicit approach for side effects. The Fix: We pivoted to using useEffect to watch the data returned by the query. This is the idiomatic way to handle side effects once data is loaded in React Query v5.

typescript
// Correct approach
const { data: chapterData } = trpc.chapter.getById.useQuery(...);

useEffect(() => {
  if (chapterData) {
    setEditorState(chapterData);
  }
}, [chapterData]);

Lesson: Always double-check API changes when upgrading major library versions, especially for core functionalities like data fetching and side effects. useEffect is your friend for reacting to data changes.

The Case of the Missing UI Component

During UI development, we attempted to import a Textarea component:

typescript
// Failed attempt
import { Textarea } from '@/components/ui/textarea';

The Problem: TS2307: Cannot find module '@/components/ui/textarea'. Turns out, the component simply didn't exist in our project's UI library! The Fix: A quick workaround was to use the native <textarea> HTML element and apply our internal nyx-* CSS classes for styling. Lesson: Before importing, verify the existence of UI components. Sometimes, a native element with custom styling is faster and perfectly adequate, especially for rapid prototyping or when a specific component isn't strictly necessary.

What's Next? The Road to Storytelling Excellence

The code is clean, the features are implemented, and the stage is set. Our immediate next steps are all about validation and bringing nyxBook to life:

  1. Seed the Database: Run npm run db:seed to populate our system with the new book personas and the nyxBook Literary Team.
  2. Import Test: Use the nyxBook UI's "Import" button with our inselWerk source path to bring in existing narrative content.
  3. Chapter Editor Verification: Dive into a chapter, edit the narrative and Aktenlage, and confirm that the save mutation works flawlessly.
  4. Generation Test: Trigger "Generate Chapter" from the Workshop tab and verify that a new workflow is created and executed by our agents.
  5. End-to-End Persona Scoping: Crucially, we'll test that book-scoped personas do not appear in regular workflow or discussion selectors, ensuring agents remain focused on their designated tasks.

This is more than just a feature; it's a leap forward in how we envision collaborative storytelling. nyxBook is poised to become an indispensable partner for authors, empowering them with intelligent assistance at every stage of the creative process.

Stay tuned for more updates as we continue to push the boundaries of AI-assisted creativity!