A multi-agent deliberation system for editorial manuscript analysis.
Plume orchestrates a council of five specialized AI agents that analyze book manuscripts in parallel, cross-validate their findings through peer review, and synthesize actionable editorial feedback with convergence scoring. It is a full-stack AI application built on Next.js 16 and the Vercel AI SDK, designed for real-world literary workflows -- from raw draft to publishable book.
The UI is in French (Plume is a French literary tool), but the entire codebase, documentation, and API layer are in English.
- Council of 5 AI agents deliberating in parallel on structure, characters, style, commercial viability, and market trends
- Convergence scoring using pairwise Jaccard similarity to measure inter-agent agreement
- Evaluation framework with coherence, completeness, and response quality metrics -- zero additional LLM calls
- Per-request observability: latency, token count, and cost estimation tracked per model and route
- Multi-provider LLM support: Claude, GPT-4o, Llama, Mistral, or fully local via Ollama
- Structured outputs with Zod schemas on every API route
- Full manuscript editor with chapter splitting, voice dictation, and PDF/DOCX/TXT import
- Privacy-first: all data stored locally as flat files -- no database, no cloud
┌─────────────────────────────────────────────┐
│ Council Engine (parallel) │
│ │
Manuscript ──────────────► │ ┌─────────────┐ ┌─────────────┐ │
(up to 400k+ chars) │ │ Structure │ │ Character │ │
│ │ Agent │ │ Agent │ │
│ └──────┬───────┘ └──────┬──────┘ │
│ │ │ │
│ ┌──────┴───────┐ ┌──────┴──────┐ │
│ │ Style │ │ Commercial │ │
│ │ Agent │ │ Agent │ │
│ └──────┬───────┘ └──────┬──────┘ │
│ │ │ │
│ ┌──────┴─────────────────┴──────┐ │
│ │ Market Trends Agent │ │
│ └──────────────┬────────────────┘ │
└─────────────────┼───────────────────────────┘
│
▼
┌──────────────────────────────────┐
│ Peer Review │
│ • Pairwise Jaccard similarity │
│ • Cross-validation of findings │
│ • Blind spot detection │
└────────────────┬─────────────────┘
│
▼
┌──────────────────────────────────┐
│ Synthesis │
│ • Unified editorial feedback │
│ • Convergence score (0-1) │
│ • Token & cost tracking │
└────────────────┬─────────────────┘
│
▼
┌──────────────────────────────────┐
│ Actionable Tasks │
│ • Revision questions │
│ • One-click chapter integration │
│ • Council verification loop │
└──────────────────────────────────┘
The deliberate() function in council-engine.ts launches all agents via Promise.all -- wall-clock latency equals the slowest agent, not the sum. Each agent runs with its own system prompt and is instrumented for latency, token usage, and cost.
After parallel deliberation, the engine computes a pairwise Jaccard similarity coefficient across all agent responses. This measures how much the agents agree on key terms -- a score above 0.5 indicates strong convergence, below 0.3 signals noise or ambiguous input.
Three heuristic metrics computed without additional LLM calls:
- Coherence -- inter-agent term overlap (Jaccard)
- Completeness -- checklist coverage via keyword matching
- Response Quality -- weighted composite of length, markdown structure, and type-token ratio (specificity gets 50% weight as the best proxy for "did the LLM actually analyze the text vs. repeat a template")
Every LLM call is tracked with: requestId, provider, model, inputTokens, outputTokens, latencyMs, costEstimate, route, and timestamp. Aggregation functions provide breakdowns by model and by route. Storage is append-only JSON per project.
All API routes validate inputs with Zod schemas (validation.ts). UUID-only project IDs prevent path traversal. LLM config, chat messages, and project context all have strict runtime validation.
A single config.ts module resolves any provider to a Vercel AI SDK LanguageModel instance:
| Provider | SDK Package |
|---|---|
| Anthropic (Claude) | @ai-sdk/anthropic |
| OpenRouter / Groq / Ollama | @ai-sdk/openai (OpenAI-compatible) |
| Claude Code CLI | Native CLI spawn via claude server |
| Layer | Technology |
|---|---|
| Framework | Next.js 16 -- App Router, Server Components |
| UI | React 19, Tailwind CSS 4 |
| AI Orchestration | Vercel AI SDK 4 -- streamText, generateText, generateObject |
| LLM Providers | @ai-sdk/anthropic, @ai-sdk/openai (OpenRouter, Ollama, Groq) |
| Validation | Zod -- structured outputs, input validation |
| Document Import | mammoth (DOCX), pdf-parse (PDF) |
| Sanitization | isomorphic-dompurify (XSS prevention) |
| Testing | Vitest 4 |
| Voice | Web Speech API (native browser) |
Prerequisites: Node.js 18+ and npm 9+.
git clone https://github.com/azelbanks/plume.git
cd plume
npm install
npm run devOpen http://localhost:3000. Configure your AI provider in the settings page (gear icon).
Local-only mode (free, no API key):
brew install ollama && ollama pull llama3.1
# Select "Ollama" in Plume settingsWith an API key:
cp .env.example .env.local
# Add: ANTHROPIC_API_KEY=sk-ant-...plume/
├── src/
│ ├── app/
│ │ ├── page.tsx # Home -- project list
│ │ ├── projet/[id]/
│ │ │ ├── import/page.tsx # Manuscript import & Phase 1 analysis
│ │ │ └── manuscrit/page.tsx # Editor & Phase 2 revision
│ │ ├── settings/page.tsx # LLM provider configuration
│ │ └── api/
│ │ ├── analyze/ # Council analysis (5 types)
│ │ ├── chapters/ # CRUD, suggestions, tasks, Q&A
│ │ ├── chat/route.ts # Agent chat (AI SDK streaming)
│ │ ├── evals/route.ts # Evaluation metrics endpoint
│ │ ├── upload/route.ts # DOCX/PDF/TXT import
│ │ └── export/pdf/route.ts # PDF export
│ ├── agents/index.ts # 10 literary agents with system prompts
│ ├── lib/
│ │ ├── council-engine.ts # Multi-agent deliberation engine
│ │ ├── evals.ts # Evaluation framework
│ │ ├── metrics.ts # LLM observability & cost tracking
│ │ ├── validation.ts # Zod schemas (shared)
│ │ └── config.ts # Multi-provider LLM resolution
│ ├── styles-litteraires/index.ts # 14 literary style layers
│ ├── components/ # React components
│ └── types/ # TypeScript type definitions
└── template-book/ # Book project template
- Input validation: Zod schemas on all API routes with strict typing
- Path traversal protection: project IDs are UUID-only (
z.string().uuid()) - XSS prevention:
isomorphic-dompurifysanitizes all user-generated HTML - HTML escaping: dedicated
escapeHtml()utility for template injection prevention
67 tests covering configuration, agent definitions, input validation, and the council engine.
npm testTest files:
src/lib/__tests__/config.test.ts-- LLM provider configurationsrc/lib/__tests__/council-engine.test.ts-- Deliberation engine and convergence scoringsrc/agents/__tests__/agents.test.ts-- Agent definitions and system promptssrc/app/api/__tests__/validation.test.ts-- Zod schema validation
Contributions are welcome. See CONTRIBUTING.md for guidelines.
Priority areas: internationalization (English UI), EPUB export, accessibility, and mobile responsiveness.
Azel Banks -- github.com/azelbanks
Built with Claude Code.
Demo coming soon.