A scalable, event-driven platform designed to automate the creation of exceptional narratives by strictly adhering to proven storytelling principles from the "Storyteller" framework. MANOE uses a multi-agent architecture where specialized AI agents collaborate in real-time to generate compelling stories.
✅ Production Ready - MANOE is a mature, fully-implemented system with complete backend infrastructure, comprehensive documentation, and CI/CD pipeline.
# Clone the repository
git clone https://github.com/IShalkin/manoe.git
cd manoe
# Configure your API keys
cp .env.example .env
# Edit .env with your API keys (at least one LLM provider required)
# Start frontend + Redis + Qdrant (local UI)
docker compose up -d
# Or start the full VPS stack (API Gateway + observability)
docker compose -f docker-compose.vps.yml up -d --build- 9 Specialized AI Agents: Architect, Profiler, Worldbuilder, Strategist, Writer, Critic, Originality, Impact, Archivist
- Multi-Provider LLM Support: OpenAI, Anthropic, Google Gemini, OpenRouter, DeepSeek, Venice AI
- Real-Time Streaming: SSE via Redis for live progress updates
- Vector Memory: Qdrant for narrative consistency and context
- Observability: Langfuse tracing, Prometheus metrics, Grafana dashboards
- Complete CI/CD: GitHub Actions with automated builds, comprehensive test suite (270 cases), and linting
- Production-Ready: Docker containerization, security features, deployment scripts
MANOE is a distributed system with a React frontend, TypeScript orchestrator (ts.ed), and multiple infrastructure services. The architecture follows an event-driven pattern where the orchestrator publishes events to Redis Streams, and the frontend subscribes via Server-Sent Events (SSE) for real-time updates.
flowchart TB
subgraph Client["Frontend - React + Vite"]
UI["GenerationPage + AgentChat"]
SSE["useGenerationStream"]
Supabase_Auth["Supabase Auth"]
end
subgraph Gateway["API Gateway - ts.ed"]
API["OrchestrationController"]
Orchestrator["StorytellerOrchestrator"]
subgraph Agents["9 Specialized AI Agents"]
Architect["Architect"]
Profiler["Profiler"]
Worldbuilder["Worldbuilder"]
Strategist["Strategist"]
Writer["Writer"]
Critic["Critic"]
Originality["Originality"]
Impact["Impact"]
Archivist["Archivist"]
end
LLMService["LLMProviderService"]
LangfuseService["LangfuseService"]
end
subgraph Infrastructure["Infrastructure Services"]
Redis[("Redis Streams")]
Supabase[("Supabase")]
Qdrant[("Qdrant")]
Langfuse[("Langfuse")]
end
subgraph LLMProviders["LLM Providers BYOK"]
OpenAI["OpenAI"]
Anthropic["Anthropic"]
Gemini["Google Gemini"]
OpenRouter["OpenRouter"]
DeepSeek["DeepSeek"]
Venice["Venice AI"]
end
UI -->|POST /generate| API
API -->|startGeneration| Orchestrator
Orchestrator --> Agents
Agents --> LLMService
LLMService --> LLMProviders
LLMService --> LangfuseService
LangfuseService -->|Traces| Langfuse
Orchestrator -->|publishEvent| Redis
Redis -->|streamEvents| SSE
SSE -->|Real-time updates| UI
Orchestrator -->|saveArtifact| Supabase
Agents -->|storeMemory| Qdrant
UI -->|Auth| Supabase_Auth
Supabase_Auth --> Supabase
This sequence diagram shows the complete flow from when a user clicks "Generate" to receiving real-time updates:
sequenceDiagram
participant U as User
participant FE as Frontend
participant GW as API Gateway
participant O as Orchestrator
participant R as Redis Streams
participant L as LLM Provider
participant S as Supabase
participant Q as Qdrant
rect rgb(240, 248, 255)
Note over U,GW: 1. Request Initiation
U->>FE: Click Generate
FE->>GW: POST /orchestrate/generate
GW->>O: startGeneration(options)
O-->>GW: runId
GW-->>FE: 202 Accepted + runId
end
rect rgb(255, 250, 240)
Note over FE,R: 2. SSE Connection
FE->>GW: GET /orchestrate/stream/{runId}
GW->>R: Subscribe to run:{runId}
end
rect rgb(240, 255, 240)
Note over O,Q: 3. Generation Loop (12 phases)
O->>R: generation_started
R-->>FE: SSE event
O->>Q: Retrieve character/world context
Q-->>O: Vector search results
O->>L: Generate with context
L-->>O: AI response
O->>S: Save artifact to run_artifacts
O->>Q: Store embeddings
O->>R: agent_complete
R-->>FE: SSE event
end
rect rgb(255, 240, 245)
Note over O,FE: 4. Completion
O->>R: generation_complete
R-->>FE: Final SSE event
FE->>U: Display generated story
end
MANOE implements a 12-phase generation workflow with revision loops and quality gates:
flowchart LR
subgraph Planning["Phase 1-6: Planning"]
direction LR
G[Genesis] --> C[Characters]
C --> N[Narrator Design]
N --> W[Worldbuilding]
W --> O[Outlining]
O --> AP[Advanced Planning]
end
subgraph Execution["Phase 7-9: Drafting Loop"]
direction LR
D[Drafting] --> CR[Critique]
CR -->|score < 7| R[Revision]
R --> CR
CR -->|score >= 7| PASS[Pass]
end
subgraph Quality["Phase 10-12: Quality"]
direction LR
OC[Originality Check] --> IA[Impact Assessment]
IA --> P[Polish]
end
AP --> D
PASS --> OC
P --> DONE((Done))
Workflow Details:
- Planning (6 phases): Architect creates narrative possibility, Profiler builds characters, Worldbuilder creates setting, Strategist plans scenes
- Drafting Loop: Writer drafts scene → Critic scores (threshold 7/10) → Revision if needed (max 2 iterations)
- Archivist: Runs every 3 scenes to update Key Constraints, track world state changes (character status, locations, timeline events), and prevent context drift
- Quality Gates: Originality check (plagiarism), Impact assessment (emotional resonance), Polish (final refinement)
Each of the 9 agents has specific data inputs and outputs:
flowchart TB
subgraph Inputs["Data Sources"]
Seed[/"User Seed Idea"/]
Outline[("Outline from Supabase")]
Memory[("Vector Memory from Qdrant")]
Constraints["Key Constraints"]
end
subgraph PlanningAgents["Planning Agents"]
direction LR
Architect["Architect"]
Profiler["Profiler"]
Worldbuilder["Worldbuilder"]
Strategist["Strategist"]
end
subgraph ExecutionAgents["Execution Agents"]
direction LR
Writer["Writer"]
Critic["Critic"]
end
subgraph QualityAgents["Quality Agents"]
direction LR
Originality["Originality"]
Impact["Impact"]
Archivist["Archivist"]
end
subgraph Storage["Persistence Layer"]
DB[(Supabase)]
Vec[(Qdrant)]
Stream[(Redis Streams)]
end
Seed --> Architect
Architect --> DB
Architect --> Stream
Profiler --> DB
Profiler --> Vec
Worldbuilder --> DB
Worldbuilder --> Vec
Outline --> Writer
Memory --> Writer
Constraints --> Writer
Writer --> DB
Writer --> Vec
Writer <--> Critic
Archivist --> Constraints
Originality --> DB
Impact --> DB
Agent Responsibilities:
| Agent | Phase | Input | Output |
|---|---|---|---|
| Architect | Genesis, Outlining | Seed idea | Narrative possibility, Scene outline |
| Profiler | Characters | Seed idea | Character profiles + embeddings |
| Worldbuilder | Worldbuilding | Characters | World elements + embeddings |
| Strategist | Advanced Planning | Outline | Detailed scene plans |
| Writer | Drafting, Revision | Outline, Context, Constraints | Scene drafts + embeddings |
| Critic | Critique | Draft | Score (1-10) + feedback |
| Originality | Originality Check | Full draft | Plagiarism score |
| Impact | Impact Assessment | Full draft | Emotional resonance score |
| Archivist | Every 3 scenes | Raw facts | Updated Key Constraints |
erDiagram
USERS ||--o{ PROJECTS : owns
PROJECTS ||--o{ RUN_ARTIFACTS : contains
PROJECTS ||--o{ CHARACTERS : has
PROJECTS ||--o{ WORLDBUILDING : has
PROJECTS ||--o{ OUTLINES : has
PROJECTS ||--o{ DRAFTS : has
PROJECTS ||--o{ RESEARCH_RESULTS : has
DRAFTS ||--o{ CRITIQUES : receives
PROJECTS {
uuid id PK
uuid user_id FK
string seed_idea
jsonb settings
timestamp created_at
}
RUN_ARTIFACTS {
uuid id PK
uuid project_id FK
string run_id
string phase
string artifact_type
jsonb content
}
CHARACTERS {
uuid id PK
uuid project_id FK
string name
string archetype
uuid qdrant_id FK
}
DRAFTS {
uuid id PK
uuid project_id FK
int scene_number
text content
int revision_count
}
CRITIQUES {
uuid id PK
uuid draft_id FK
float score
jsonb feedback
boolean passed
}
Key Tables:
projects- User projects with seed idea and generation settingsrun_artifacts- All phase outputs (JSONB content for flexibility)characters/worldbuilding/drafts- Linked to Qdrant viaqdrant_idfor vector memory synccritiques- Quality scores and revision feedbackresearch_results- "Eternal Memory" for cross-project reuse
flowchart TB
subgraph Embedding["Embedding Pipeline"]
Text["Text Content"] --> Embed["text-embedding-3-small"]
Embed --> Vector["1536-dim Vector"]
end
subgraph Collections["Qdrant Collections"]
Characters[("characters
Character profiles")]
World[("worldbuilding
World elements")]
Scenes[("scenes
Scene content")]
end
subgraph Agents["Agent Operations"]
direction LR
Profiler["Profiler"] -->|store| Characters
Worldbuilder["Worldbuilder"] -->|store| World
Writer["Writer"] -->|store| Scenes
end
subgraph Retrieval["Context Retrieval"]
Query["Scene Context Query"]
Query -->|similarity search| Characters
Query -->|similarity search| World
Query -->|similarity search| Scenes
Characters --> Context["Combined Context"]
World --> Context
Scenes --> Context
Context --> Writer
end
Vector Memory Features:
- Embedding Model: OpenAI text-embedding-3-small (1536 dimensions)
- Similarity Search: Cosine similarity for context retrieval
- Cross-Collection Queries: Writer retrieves from all 3 collections for scene context
- Eternal Memory: Embeddings persist across generation runs for continuity
flowchart TB
subgraph Root["manoe/"]
subgraph FE["frontend/ - React + Vite"]
FE_Pages["pages/
GenerationPage.tsx
DashboardPage.tsx"]
FE_Comp["components/
AgentChat.tsx (orchestrator)
SettingsModal.tsx"]
FE_Chat["components/chat/
ChatHeader, RoundSwitcher, ResultSection,
ConversationTimeline, AgentCard, AgentStatusGrid,
EditConfirmModal, SceneSelectModal, MotifLayerPanel,
CheckpointsPanel, DiagnosticPanel, ErrorDisplay,
MarkdownContent"]
FE_Hooks["hooks/
useGenerationStream, useProjects,
useChatEditor, useFinalResult,
useGenerationControls, useAgentStates"]
end
subgraph GW["api-gateway/ - ts.ed"]
GW_Ctrl["controllers/
OrchestrationController.ts"]
GW_Svc["services/
StorytellerOrchestrator.ts
LLMProviderService.ts
QdrantMemoryService.ts"]
GW_Models["models/
AgentModels.ts
LLMModels.ts"]
end
subgraph Infra["Infrastructure"]
Docker["docker-compose.yml"]
Supabase["supabase/migrations/"]
GHA[".github/workflows/"]
end
end
Key Files:
| File | Lines | Description |
|---|---|---|
frontend/src/components/AgentChat.tsx |
~350 | Thin orchestrator composing chat UI components |
frontend/src/components/chat/*.tsx |
~1490 | Modular chat components (13 files) |
frontend/src/hooks/use{ChatEditor,FinalResult,GenerationControls,AgentStates}.ts |
~708 | New chat hooks (4 files) |
api-gateway/src/services/StorytellerOrchestrator.ts |
1435 | Main orchestration logic |
api-gateway/src/models/AgentModels.ts |
- | 9 agents, 12 phases definitions |
api-gateway/src/models/LLMModels.ts |
- | 6 LLM provider configurations |
The orchestrator publishes events to Redis Streams for real-time frontend updates via Server-Sent Events:
flowchart TB
subgraph Lifecycle["Generation Lifecycle Events"]
Start["generation_started"] --> Phase["phase_start"]
Phase --> Agent["agent_start"]
Agent --> Complete["agent_complete"]
Complete -->|next phase| Phase
Complete -->|all done| Done["generation_complete"]
end
subgraph Special["Special Events"]
Archivist["new_developments_collected"]
Heartbeat["heartbeat (15s)"]
end
subgraph Errors["Error Events"]
Cancel["generation_cancelled"]
Error["generation_error"]
end
Complete -->|every 3 scenes| Archivist
Archivist --> Complete
Event Payload Structure:
| Event | Key Fields | Description |
|---|---|---|
generation_started |
runId, projectId | Run initialized |
phase_start |
phase, phaseNumber | New phase beginning |
agent_start |
agentName, phase | Agent activated |
agent_complete |
agentName, output | Agent output ready |
new_developments_collected |
constraints | Archivist update |
generation_complete |
totalPhases, duration | All phases done |
heartbeat |
timestamp | Keep-alive (15s interval) |
MANOE implements a 12-phase narrative generation workflow with revision loops and quality gates:
flowchart LR
subgraph Planning["Planning Phases"]
G[Genesis] --> C[Characters]
C --> N[Narrator Design]
N --> W[Worldbuilding]
W --> O[Outlining]
O --> AP[Advanced Planning]
end
subgraph Execution["Execution Loop (per scene)"]
D[Drafting] --> CR[Critique]
CR -->|"needs work"| R[Revision]
R -->|"max 2 iterations"| CR
CR -->|"passed"| D2[Next Scene]
end
subgraph Quality["Quality Gates"]
OC[Originality Check] --> IA[Impact Assessment]
IA --> P[Polish]
end
AP --> D
D2 -->|"all scenes done"| OC
style G fill:#e1f5fe
style P fill:#c8e6c9
The workflow is orchestrated by StorytellerOrchestrator.ts (1435 lines) which manages phase transitions, revision loops, and the Archivist agent that runs every 3 scenes to update Key Constraints for continuity.
The Genesis agent accepts a "Seed Idea" from the user (What If? questions, image prompts) and configures the "Moral Compass" (Ethical, Unethical, Amoral, Ambiguous). It generates a structured "Narrative Possibility" JSON that defines the story's foundation, including plot summary, setting, main conflict, and thematic elements.
The Profiler assigns archetypes (Hero, Shadow, Trickster) to characters and generates "Core Psychological Wound" and "Inner Trap" for protagonists. Character attributes are stored as vectors in Qdrant for consistency across the narrative.
The Narrator Design phase generates the narrative voice configuration including POV type (first person, third person limited/omniscient), tense, voice characteristics, and style guidelines. This artifact is used by the Writer agent during the Drafting phase to maintain consistent narrative voice.
The Worldbuilder creates detailed world elements including locations, cultures, rules, and atmosphere. These elements are stored in Qdrant vector memory for retrieval during scene writing.
The Architect maps the plot onto "Mythic Structure" (Hero's Journey, Three-Act Structure) and creates a scene-by-scene outline with conflict, emotional beats, and subtext.
Generates detailed planning artifacts including contradiction maps, emotional beat sheets, sensory blueprints, subtext design, and complexity checklists to ensure narrative coherence.
The Writer drafts scenes using "Show, Don't Tell" principles. Each scene is written with full context from Qdrant memory including relevant characters, worldbuilding elements, and previous scenes for continuity.
The Editor refines the draft with iterative quality checks, validating pacing, originality, dialogue, and subtext. This phase involves up to 2 revision rounds per scene until quality standards are met.
MANOE supports two types of selective regeneration for iterative refinement:
Phase-Based Regeneration: Edit any agent's output and regenerate from that phase onwards. Previous phases are preserved using stored artifacts from Supabase. Use the "What did you change?" field to pass instructions to the AI about your modifications.
Scene-Level Regeneration: Select specific scenes to regenerate via the Writer agent's modal UI. The system maintains continuity between old and new scenes using Qdrant memory context.
The system uses Qdrant vector database to maintain narrative consistency:
- Character Memory: Character profiles are embedded and retrieved based on scene relevance
- Worldbuilding Memory: World elements are stored and retrieved for consistent world details
- Scene Memory: Previous scenes are embedded for continuity in subsequent scenes
MANOE maintains a dynamic world state that tracks changes throughout the narrative generation process. This ensures consistency in character status, locations, and timeline events across scenes.
World State Components:
- Character Updates: Tracks character status (alive, dead, unknown, transformed), current location, and new attributes discovered during the story
- New Locations: Records new locations introduced in scenes with type and description
- Timeline Events: Logs significant events with their narrative importance (major, minor, background)
How It Works:
- World state is initialized after the Characters phase using character profiles
- The Archivist agent runs every 3 scenes and outputs a
worldStateDiffwith changes - Diffs are applied to the world state, maintaining a consistent view of the story world
- The world state is available to agents for context during drafting and revision
All generation artifacts are stored in Supabase for resuming interrupted generations, phase-based selective regeneration, scene-level selective regeneration, and project history/versioning. Characters, drafts, and critiques are also persisted to normalized database tables for efficient querying and cross-project analysis.
MANOE includes an optional Marketing Researcher feature that uses AI-powered deep research to analyze your target audience before generation begins. This helps create more targeted and resonant narratives.
Supported Research Providers:
- Perplexity (sonar-deep-research model) - Fast, comprehensive web research
- OpenAI Deep Research (Responses API with background mode) - In-depth analysis taking 5-15 minutes
Features:
- BYOK (Bring Your Own Key) - Add your Perplexity or OpenAI API key in Settings > Research
- Eternal Memory - Research results are stored in Supabase and vectorized in Qdrant for reuse across projects
- Semantic Similarity Search - Before conducting new research, the system checks for similar existing research (>50% similarity threshold) to save costs
- Prompt Context Injection - Research insights are automatically injected into Genesis and Characters agent prompts
How to Use:
- Add your Perplexity or OpenAI API key in Settings > Research tab
- On the project creation page, click the "Research" button next to Target Audience
- Select your preferred provider and click "Start Research"
- View research history in Settings > Research History
MANOE includes self-hosted Langfuse for complete LLM observability:
- Langfuse Dashboard: https://langfuse.iliashalkin.com
- Trace Visualization: See the full trace tree for each generation run
- Token Usage Tracking: Monitor input/output tokens per agent call
- Latency Metrics: Track response times across different LLM providers
- Error Debugging: Inspect failed LLM calls with full request/response data
Langfuse Prompt Management:
MANOE uses Langfuse Prompt Management for versioned prompts with production labels:
manoe-architect-v1- Story structure and narrative designmanoe-profiler-v1- Character creation and psychologymanoe-worldbuilder-v1- Setting and world detailsmanoe-writer-v1- Prose generationmanoe-critic-v1- Quality evaluation and feedback
Model Selection Architecture:
The model used for generation is determined by the following precedence:
- Request
llmConfig.model- User's selection from frontend settings (highest priority) - Environment variable - Server-side default (e.g.,
OPENAI_API_KEYenables OpenAI) DEFAULT_MODELS- Code defaults inLLMModels.ts(gpt-5.2 for OpenAI)
The config.model field in Langfuse prompts is metadata/documentation only - it does not override the user's model selection. Langfuse tracing shows the actual model used in each generation, not the prompt's config.model.
Self-Hosted Stack:
| Service | Description |
|---|---|
| langfuse-web | Web UI and API (Next.js) |
| langfuse-worker | Background job processor |
| langfuse-postgres | PostgreSQL database |
| langfuse-clickhouse | Analytics database |
| langfuse-redis | Caching and queues |
| langfuse-minio | S3-compatible blob storage |
Tracing is automatically enabled when LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY are configured in the orchestrator environment.
MANOE includes automatic quality evaluation using LLM-as-a-Judge methodology. The EvaluationService runs lightweight evaluations to score generation quality without manual review.
Evaluation Types:
- Faithfulness: Measures how well Writer output matches the Architect's plan (score 0-1)
- Relevance: Measures how well Profiler character output matches the user's seed idea (score 0-1)
Features:
- Uses cost-effective models (default: gpt-4o-mini) for evaluations
- Records scores in both Langfuse (for tracing) and Prometheus (for dashboards)
- Configurable via environment variables:
EVALUATION_LLM_PROVIDER,EVALUATION_LLM_MODEL,EVALUATION_LLM_API_KEY
Metrics:
| Metric | Type | Description |
|---|---|---|
manoe_evaluation_score |
Gauge | LLM-as-a-Judge evaluation scores by type and agent |
manoe_evaluation_calls_total |
Counter | Total evaluation calls by type, status |
manoe_evaluation_duration_seconds |
Histogram | Evaluation latency |
MANOE includes comprehensive Prometheus metrics for production monitoring:
Metrics Endpoint: GET /api/metrics - Prometheus-compatible metrics endpoint
Available Metrics:
| Metric | Type | Description |
|---|---|---|
manoe_agent_executions_total |
Counter | Total agent executions by agent_name, status, error_type |
manoe_agent_execution_duration_seconds |
Histogram | Agent execution duration with p50/p95/p99 buckets |
manoe_llm_calls_total |
Counter | LLM API calls by provider, model, agent_name, status |
manoe_llm_call_duration_seconds |
Histogram | LLM call latency |
manoe_llm_tokens_total |
Counter | Token usage by provider, model, token_type (prompt/completion) |
manoe_llm_cost_total |
Counter | LLM cost in USD by provider, model, agent_name, run_id |
manoe_db_queries_total |
Counter | Database queries by operation (select/insert), table, status |
manoe_qdrant_operations_total |
Counter | Qdrant operations by operation (upsert/search), collection, status |
manoe_redis_stream_length |
Gauge | Current length of Redis streams |
manoe_redis_consumer_lag |
Gauge | Redis consumer group lag (messages behind) |
manoe_user_feedback_total |
Counter | User feedback by feedback_type (thumbs_up/thumbs_down), agent_name |
manoe_regeneration_requests_total |
Counter | Regeneration requests (implicit negative feedback) |
Grafana Dashboard: The monitoring/grafana/dashboards/manoe-agents.json provides a pre-built dashboard with 8 panels covering agent success rates, latency, LLM costs, token usage, Redis lag, and user feedback.
Alert Rules: The monitoring/alerts.yml defines Prometheus alerting rules:
AgentSuccessRateLow- Agent success rate below 90%AgentLatencyHigh- p95 latency above 45 secondsAgentLatencyCritical- p95 latency above 60 secondsRedisStreamsLagHigh- Consumer lag above 1000 messagesLLMRateLimitErrors- Rate limit errors detectedHighTokenCost- Hourly cost exceeds thresholdHighRegenerationRate- High regeneration rate (implicit negative feedback)LowUserSatisfaction- Low thumbs up ratio
User Feedback Integration: The frontend includes FeedbackButtons component for explicit user feedback (thumbs up/down) on agent outputs. Feedback is recorded in both Langfuse (for quality scoring) and Prometheus metrics.
MANOE includes robust error handling for long-running generations:
- Automatic Retry - Transient errors (429 rate limits, 5xx server errors, timeouts) are automatically retried with exponential backoff (up to 3 attempts)
- Phase Checkpointing - Each completed phase is saved to Supabase, allowing resume from the last successful phase
- Graceful Interruption Handling - If the orchestrator restarts during generation, the frontend receives a clear error message with resume information instead of hanging
MANOE supports multiple LLM providers with BYOK (Bring Your Own Key). Configure at least one provider to get started.
Automated Testing Suite:
- 270 test cases across 10 test suites (entrypoints in
tests/, implementations inapi-gateway/src/__tests__/):- CORS configuration
- Agent implementations (Critic, Writer)
- Services (Evaluation, WorldBible Embedding, Data Consistency)
- Utilities (Schema Normalizers, String Utils, Token Limit Cache)
- Supabase schemas
- Automatic execution on every pull request via GitHub Actions
- Coverage reporting via Jest with configured paths to
api-gateway/src/
Code Quality Tools:
- Qodo: AI-powered code review and recommendations
- Greptile: Automated code analysis and pattern detection
- ESLint: JavaScript/TypeScript linting
- TypeScript: Static type checking
MANOE supports both local development and production deployments using Docker Compose.
Use docker-compose.yml for local development with a minimal stack:
docker-compose up -dUse docker-compose.vps.yml for production deployment with the complete stack including:
- API Gateway (TypeScript/Ts.ED)
- Full Langfuse observability stack (PostgreSQL, ClickHouse, Redis, MinIO)
- Qdrant vector database with proper ulimits
- Redis message broker
- Integration with nginx-proxy for SSL certificates
docker compose -f docker-compose.vps.yml up -d --buildCreate a .env file in the root directory. The .env.example file provides comprehensive configuration options.
Required: At least one LLM provider
OPENAI_API_KEY=your-openai-key
# Or: ANTHROPIC_API_KEY, GEMINI_API_KEY, VENICE_API_KEYSee .env.example for complete configuration options including:
- Individual agent model selection
- Redis, Qdrant, and Supabase connection settings
- Langfuse observability configuration
- CORS and security settings
MANOE supports multiple LLM providers with BYOK (Bring Your Own Key):
| Provider | Models | Best For |
|---|---|---|
| OpenAI | GPT-4o, GPT-4o-mini, o1, o3 | Reasoning, general purpose |
| Google Gemini | Gemini 2.0 Flash, Gemini 1.5 Pro | Long context, complex logic |
| Anthropic Claude | Claude 3.5 Sonnet, Claude 3 Haiku | Creative writing, prose quality |
| OpenRouter | Access to multiple providers via single API | Cost optimization, model variety |
Generate narratives through different ethical lenses:
- Ethical: Traditional hero's journey with clear moral lessons
- Unethical: Villain protagonists, morally dark narratives
- Amoral: Neutral perspective without moral judgment
- Ambiguous: Complex moral situations without clear answers
manoe/
├── frontend/ # React + TypeScript + Vite Frontend
│ ├── src/
│ │ ├── components/ # UI components
│ │ │ ├── AgentChat.tsx # Thin orchestrator (~350 lines)
│ │ │ ├── chat/ # Modular chat components
│ │ │ │ ├── ChatHeader.tsx
│ │ │ │ ├── RoundSwitcher.tsx
│ │ │ │ ├── ResultSection.tsx
│ │ │ │ ├── ConversationTimeline.tsx
│ │ │ │ ├── AgentCard.tsx
│ │ │ │ ├── AgentStatusGrid.tsx
│ │ │ │ ├── EditConfirmModal.tsx
│ │ │ │ ├── SceneSelectModal.tsx
│ │ │ │ ├── MotifLayerPanel.tsx
│ │ │ │ ├── CheckpointsPanel.tsx
│ │ │ │ ├── DiagnosticPanel.tsx
│ │ │ │ ├── ErrorDisplay.tsx
│ │ │ │ └── MarkdownContent.tsx
│ │ │ ├── Layout.tsx # App layout
│ │ │ └── SettingsModal.tsx
│ │ ├── contexts/ # React contexts (Auth, Settings)
│ │ ├── hooks/ # Custom hooks
│ │ │ ├── useGenerationStream.ts # SSE connection
│ │ │ ├── useProjects.ts # Project CRUD
│ │ │ ├── useSettings.ts # Settings management
│ │ │ ├── useAuth.ts # Authentication
│ │ │ ├── useChatEditor.ts # Edit/lock logic
│ │ │ ├── useFinalResult.ts # Result extraction
│ │ │ ├── useGenerationControls.ts # Stop/resume
│ │ │ └── useAgentStates.ts # Agent state computation
│ │ ├── pages/
│ │ │ ├── GenerationPage.tsx # Main generation UI
│ │ │ ├── DashboardPage.tsx
│ │ │ └── ...
│ │ └── lib/ # Utilities and Supabase client
│ └── package.json
├── api-gateway/ # TypeScript ts.ed API Gateway
│ ├── src/
│ │ ├── controllers/ # ts.ed controllers with Swagger decorators
│ │ │ └── OrchestrationController.ts # Generation endpoints
│ │ ├── services/ # Business logic services
│ │ │ ├── LLMProviderService.ts # Multi-provider LLM client (BYOK)
│ │ │ ├── StorytellerOrchestrator.ts # Multi-agent orchestration engine
│ │ │ ├── LangfuseService.ts # Tracing + Prompt Management
│ │ │ ├── RedisStreamsService.ts # SSE event streaming
│ │ │ ├── QdrantMemoryService.ts # Vector memory
│ │ │ └── SupabaseService.ts # Artifact persistence
│ │ ├── models/ # DTOs and type definitions
│ │ │ ├── LLMModels.ts # LLM provider types and defaults
│ │ │ └── AgentModels.ts # Agent types and phase configs
│ │ └── Server.ts # ts.ed server configuration
│ └── package.json
├── supabase/ # Supabase configuration and migrations
├── docs/ # Documentation
├── docker-compose.yml # Docker Compose for local development
└── docker-compose.vps.yml # Docker Compose for VPS deployment
The following tables are used for persistence:
| Table | Description |
|---|---|
| projects | User projects with seed_idea, settings, moral_compass |
| run_artifacts | Phase artifacts (project_id UUID FK, run_id, phase, artifact_type, content JSONB) |
| research_results | Marketing research results with prompt_context for AI injection, citations, and Qdrant point_id for semantic search |
| characters | Generated character profiles |
| worldbuilding | World elements and settings |
| outlines | Plot outlines with scene breakdowns |
| drafts | Scene drafts with narrative content |
| critiques | Editor feedback and quality scores |
| Endpoint | Method | Description |
|---|---|---|
/api/health |
GET | Health check |
/orchestrate/generate |
POST | Start multi-agent generation |
/orchestrate/stream/{run_id} |
GET | SSE stream for real-time events |
/orchestrate/runs/{run_id}/events |
GET | SSE stream (legacy route) |
/orchestrate/runs/{run_id}/state |
GET | Get run state for recovery |
/orchestrate/runs/{run_id}/cancel |
POST | Cancel a running generation |
/api/research |
POST | Conduct market research |
/api/research/history |
GET | Get user's research history |
{
"seed_idea": "What if a detective could see the last 10 seconds of a murder victim's life?",
"moral_compass": "ambiguous",
"target_audience": "Adult thriller readers",
"themes": "justice,memory,truth",
"provider": "openai",
"model": "gpt-4o",
"api_key": "your-api-key",
"supabase_project_id": "uuid-of-project",
"start_from_phase": "characters",
"previous_run_id": "uuid-of-previous-run",
"scenes_to_regenerate": [2, 5],
"constraints": {
"edit_comment": "Make the protagonist more conflicted about their abilities"
}
}VITE_SUPABASE_URL- Supabase project URLVITE_SUPABASE_ANON_KEY- Supabase anonymous keyVITE_ORCHESTRATOR_URL- Orchestrator API URL
REDIS_URL- Redis connection URLSUPABASE_URL- Supabase project URLSUPABASE_KEY- Supabase service key (required for artifact persistence)QDRANT_URL- Qdrant server URL (required for memory context features)QDRANT_API_KEY- Qdrant API key (if authentication enabled)LANGFUSE_PUBLIC_KEY- Langfuse public key (enables tracing)LANGFUSE_SECRET_KEY- Langfuse secret key (enables tracing)LANGFUSE_HOST- Langfuse host URL (default: http://langfuse-web:3000 for self-hosted)OPENAI_API_KEY- OpenAI API key (optional, for embeddings and generation)ANTHROPIC_API_KEY- Anthropic API key (optional)GEMINI_API_KEY- Google Gemini API key (optional)
cd frontend
npm install
cp .env.example .env
# Configure environment variables
npm run devcd api-gateway
npm install
cp .env.example .env
# Configure environment variables
npm run devFor VPS deployment, use the provided docker-compose.vps.yml:
# On your VPS
docker compose -f docker-compose.vps.yml up -dThe VPS configuration includes nginx-proxy integration for automatic SSL certificates via Let's Encrypt.
For detailed deployment instructions, including Qdrant ulimits configuration, Langfuse internal networking, Supabase RLS setup, and troubleshooting common issues, see docs/DEPLOYMENT.md.
The frontend is fully implemented and containerized. The api-gateway is fully implemented with a complete multi-agent system (~23,000 lines of TypeScript). The database layer is production-ready with 9 Supabase migrations. CI/CD is configured with GitHub Actions including comprehensive test suite (270 test cases with Jest), TypeScript linting, and automated Docker builds. Documentation is comprehensive.
Status: PRODUCTION READY
What's already working: Complete TypeScript API Gateway (~23,000 lines) with 9 AI Agents fully implemented, real-time SSE streaming via Redis, CI/CD pipeline with automated builds, comprehensive test suite (270 test cases), TypeScript linting, Docker containerization, Supabase database with 9 migrations, Qdrant vector memory integration, Redis caching layer with TTL-based caching, rate limiting middleware with fail-secure behavior, Prometheus metrics, Grafana dashboards, and multi-provider LLM support (OpenAI, Anthropic, Google Gemini, OpenRouter, DeepSeek, Venice AI).
The system aims for high-quality narrative output measured by structural adherence (100% of scenes match the generated outline), psychological depth (every protagonist has defined "Inner Trap" and "Breaking Point"), and sensory density (every scene contains at least 3 distinct sensory details).
This project is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License (CC BY-NC-SA 4.0).
You are free to share and adapt this work for non-commercial purposes, provided you give appropriate credit and distribute any derivative works under the same license.
Citation:
Shalkin, I. (2025). MANOE: Multi-Agent Narrative Orchestration Engine.
GitHub. https://github.com/IShalkin/manoe
For commercial licensing inquiries, contact: mailtoshalkin@gmail.com
See LICENSE for full details.
Contributions are welcome! Please read the contributing guidelines before submitting PRs.