Lectern docs
Everything you need to run Lectern, connect models, drive it from other agents and build on its API.
Overview
Lectern turns a prompt, plus spreadsheets, documents and links, into a finished presentation. It has two parts that share one engine:
server/: a FastAPI service with the agents, the layout engine, the Critic and the exporters. It stores everything in a local SQLite database.web/: a Next.js 15 app for the whole flow, from new deck to present mode.
The same engine is also an MCP server, so Claude Code, Codex, Cursor or Antigravity can make decks without the web app.
Quick start
You need Python 3.12+ with uv, and Node 20+ with pnpm.
git clone https://github.com/mrigankad/Lectern.git
cd Lectern
# 1. Backend · http://localhost:8000 (API docs at /docs)
cd server
uv sync
uv run uvicorn lectern.main:app --port 8000
# 2. Web app · http://localhost:3000 (in a second terminal)
cd web
pnpm install
pnpm dev
Open http://localhost:3000 and start a deck. With no keys, every agent uses the built-in offline provider: it writes a sensible deck from the prompt alone, with no network, so you can try the whole flow first.
pnpm dev:mock runs the web app on mock data with no backend at all, which is handy for UI work.Connect a model
Open Connections and models in the sidebar, add a key and press Test. Then pick a preset (Best quality, Balanced, Lowest cost) or choose a provider and model for each agent.
| Provider | How it connects |
|---|---|
| Claude Code | Uses your local claude login. No API key needed. |
| Anthropic | ANTHROPIC_API_KEY or a key saved in Connections. |
| OpenAI-compatible | OpenAI, OpenRouter, a LiteLLM gateway, Gemini, Groq, DeepSeek, Mistral and Ollama, all through one client with a base URL. |
| Offline | Deterministic, no network. The default, and what the tests use. |
Keys are stored in your local database and the API never returns them. A role whose provider has no key falls back to offline.
How a deck is built
- Brief.
POST /api/deckswith a prompt and optional audience, goal, length and sources. - Interview. The Strategist asks only the questions the brief leaves open. If audience, goal and length are already set, it skips straight to the outline.
- Outline. You edit and reorder the headlines, then approve. Nothing is built before approval.
- Build. Slides are built three at a time: Writer, Art Director, Renderer, then Critic. You can pause and resume.
- Review. A slide with a high or medium finding goes back to the Writer once and is checked again.
- Edit and export. Ask for changes in chat, edit directly, then export.
Every step is recorded as a run with a one-sentence summary, which feeds the live activity view.
The agents
| Agent | What it does |
|---|---|
| Strategist | Runs the interview and drafts the storyline, with every headline written as a claim. |
| Analyst | Deterministic. Computes figures from real cells in your sources, so every number traces back to a cell. |
| Writer | Fills headlines, body text, chart labels and speaker notes. If the brief can't fill a slide, it writes what still needs finding out instead of template text. |
| Art Director | Chooses one of 21 layouts, the chart type and the visuals. |
| Renderer | Fits the content into the layout's slots on the canvas. |
| Critic | Deterministic lint over every slide (see below). |
| Editor | Applies chat requests to one slide or the whole deck. |
| Exporter | Writes PPTX, PDF, PNG and notes, plus an editability report. |
Your rules ("never use the word synergy", "always show currency in USD") are added to every agent prompt. A rule that bans a word is also enforced by the lint.
Scene graph
A slide is typed JSON: a layout id plus nodes (headline, text, bullets, stat, chart, table, image, quote). The placer turns it into a RenderedSlide on a 1920×1080 canvas. The web canvas, PowerPoint, PDF and PNG are all drawn from that one rendered form, so every format matches. The full schema is in docs/SPEC.md.
The Critic
The Critic runs without a model. Its rules:
- Story: long or topic-only headlines, missing notes, placeholder text left on a slide.
- Design: text overflow, text that is too small, more than five bullets, long bullets, low contrast, the wrong chart for the data.
- Accuracy: a number in the text or notes that differs from the slide's chart or stat value.
- Your rules and brand: banned words, brand colours, fonts and minimum sizes.
Each slide starts at 100 and loses points by severity; the deck score is the mean, with Story, Design and Editability sub-scores. For each finding you can Fix it, or Keep it, which adds a rule so the Critic stops raising it.
Undo
- Slide undo takes back the latest change to a slide, whoever made it, one version at a time.
- Ask undo (under a chat reply) reverts exactly what that request changed. If you edited a field again afterwards, your later edit is kept.
Removed slides are not restored yet.
Data and charts
Attach spreadsheets, CSVs, documents or links as sources. Charts and stats link to sheet ranges. Refresh from sheet re-reads them and also rewrites matching figures in headlines, text and notes; anything it can't trace to a single changed cell is flagged for you.
Brand kits
Upload a .potx or .pptx (and optionally a brand PDF). Lectern reads the colour scheme, fonts, logos and layouts, builds a theme, and suggests rules the Critic checks. A branded deck's PowerPoint export is built on your template's master.
Images and video
| Provider | Setup |
|---|---|
| Higgsfield | Uses the Higgsfield CLI's own login. Test it under Connections to enable it. It bills credits. |
| Google Imagen and Veo | GEMINI_API_KEY |
| OpenAI Images | OPENAI_API_KEY |
| FLUX (fal.ai) | FAL_KEY |
| Runway | RUNWAYML_API_SECRET |
| Stock (Pexels) | PEXELS_API_KEY |
| Upload / offline | Built in. Offline draws flat placeholders in the deck colours. |
Export
- PPTX: native text boxes, tables and charts you can edit in PowerPoint, with speaker notes.
- PDF: vector, 960×540 pt pages, Urbanist embedded, optional notes pages.
- Images: a zip of 1920×1080 PNGs.
- Notes: a Markdown speaker script.
Every export comes with a report that counts editable objects, charts, tables and pictures. Urbanist isn't embedded in PPTX files, so a machine without the font shows a fallback; the PDF always looks right.
MCP server
Lectern runs as an MCP server in two ways, on the same engine and database:
- stdio:
uv --directory /path/to/server run lectern-mcp. The agent starts Lectern itself. - HTTP:
http://localhost:8000/mcp, served by the running API. Builds show live in the web app.
Claude Code
claude mcp add lectern -- uv --directory "/path/to/Lectern/server" run lectern-mcp
# or, with the API running
claude mcp add --transport http lectern http://localhost:8000/mcp
Claude desktop, Cursor, Gemini CLI, Antigravity
{
"mcpServers": {
"lectern": {
"command": "uv",
"args": ["--directory", "/path/to/Lectern/server", "run", "lectern-mcp"]
}
}
}
Codex
# ~/.codex/config.toml
[mcp_servers.lectern]
command = "uv"
args = ["--directory", "/path/to/Lectern/server", "run", "lectern-mcp"]
The web app's Claude Code and agents page shows these with your machine's path filled in.
Tools
create_deck, get_interview, answer_interview, skip_interview, get_outline, update_outline, regenerate_outline, approve_outline, get_status, wait_until_ready, get_critic_report, fix_findings, ask, edit_slide, list_decks, export_deck. Resources: lectern://decks/{id} and lectern://decks/{id}/outline.
approve_outline is never called automatically. Clients should show the outline and wait for a yes. The HTTP endpoint accepts localhost only and has no authentication, so keep the API on localhost.HTTP API
All routes are under /api and return JSON. Errors are an HTTP status plus { "detail": "..." } in plain language. Interactive docs are at http://localhost:8000/docs.
| Method | Path | Purpose |
|---|---|---|
| GET | /health | Health and active provider |
| GET · POST | /decks | List decks · create one (starts the outline) |
| GET · PATCH · DELETE | /decks/{id} | Read, rename or set icon, delete |
| PUT | /decks/{id}/outline | Edit, reorder, add or remove outline slides |
| POST | /decks/{id}/outline/regenerate | Redraft, e.g. "make it shorter" |
| POST | /decks/{id}/approve · /pause · /resume | Start, pause or resume the build |
| GET | /decks/{id}/render | All rendered slides |
| PATCH | /decks/{id}/slides/{sid} | Manual edit, re-linted |
| POST | /decks/{id}/ask | A change in plain words, for a slide or the deck |
| POST | /decks/{id}/slides/{sid}/undo | Slide undo |
| POST | /decks/{id}/messages/{mid}/undo | Ask undo |
| GET | /decks/{id}/critic | Scores and findings |
| POST | /decks/{id}/critic/findings/{fid} · /critic/fix-all | Fix, keep or reopen findings |
| GET · POST · DELETE | /rules | Your standing rules |
| POST | /decks/{id}/export | pptx, pdf, images or notes |
| GET | /files/{file_id} | Download an export |
| GET | /layouts | The 21 layouts and their slots |
| GET · PUT | /settings/connections · /settings/routing | Providers, keys and model per agent |
| GET | /decks/{id}/events | Server-Sent Events |
Events
GET /api/decks/{id}/events streams Server-Sent Events: deck.updated, outline.ready, slide.updated, run.updated (one plain sentence per agent step), message.updated, finding.updated, and a ping every 20 seconds.
Environment
| Variable | Default | Purpose |
|---|---|---|
LECTERN_DATA_DIR | server/data | Database and exported files |
LECTERN_OFFLINE_DELAY | 0.6 | Seconds per offline step, so the live build has something to show |
LECTERN_CORS_ORIGINS | http://localhost:3000 | Origins allowed to call the API |
LECTERN_REFERENCES_DIR | ../references | Layout and deck-type knowledge for the agents |
LECTERN_FORCE_OFFLINE | unset | 1 routes every agent to offline |
LECTERN_WEB_URL, LECTERN_API_URL, LECTERN_MCP_URL | localhost | Links returned by MCP tools |
| Provider keys | unset | ANTHROPIC_API_KEY, OPENAI_API_KEY, OPENROUTER_API_KEY, GEMINI_API_KEY and others. A key saved in the app takes precedence. |
Repository
| Path | What it is |
|---|---|
server/lectern/agents | Strategist, Writer, Art Director, Renderer, Critic, Editor and the pipeline |
server/lectern/engine | Placement on the canvas and the lint rules |
server/lectern/layouts | The 21 layouts and their slots |
server/lectern/export | PPTX, PDF, images, notes and the editability report |
server/lectern/llm, media | Model and media routers and providers |
server/lectern/mcp | The MCP server |
web/src | The Next.js app |
docs/SPEC.md | The contract between backend and web app |
references/ | Layout, deck-type and visual-design knowledge |
Run the checks with cd server && uv run pytest (offline) and cd web && pnpm typecheck && pnpm lint.
Status
Lectern is early. Built and tested: the full flow from brief to export, chat edits and undo, the Critic, data sources, brand kits, share links, present mode and the MCP server. Not built yet: invite by email, comments, Google Slides export, restoring removed slides, and accounts. Paid image providers are wired in but need your own keys or credits.