Cicero
by Luissalet
README.md
# Cicero's Hoard
A local workspace that turns a brief and source documents into an editable presentation. You give it an objective,
an audience and the material; it proposes an outline, writes the slides with speaker notes, lets you review and
approve each slide one by one, applies a theme and exports the result. It is meant for a person and for an assistant
working together: everything is available as a REST API for the bundled UI and as MCP tools, built from the same
code, so the two cannot disagree.
## What it does
- **Decks**: title, brief, audience, tone, language (Spanish or English), number of slides (3 to 40) and theme.
The status is derived, never typed: `draft` (nothing yet), `outline` (an outline exists), `review` (slides exist,
some not approved), `ready` (every slide approved).
- **Sources**: paste text or add a `.txt`, `.md`, `.pdf`, `.docx` or `.pptx` file (text only; scanned PDFs need OCR
elsewhere). Sources are numbered and each slide can cite the sources it draws on.
- **Outline**: generated by the local model from the brief and the numbered source excerpts, or written by hand.
Each item has a title, a purpose, a few points and an optional layout hint.
- **Slides**: eight layouts (`title`, `section`, `bullets`, `two_column`, `image_text`, `quote`, `chart`, `closing`)
built from blocks (bullets, text, image, quote, columns, chart). Every slide has speaker notes.
- **Per-slide review**: approve or unapprove a slide, regenerate it with feedback, edit it by hand. Every change
creates a revision; reverting restores an old revision as a new one. Generating slides again keeps approved slides
and rewrites drafts.
- **No invented numbers**: the model may only use figures that appear in the sources. A chart is kept only when all
its values appear in the sources, and `deck_check` lists every figure on a slide that no source contains. Number
formats are compared across notations (`1.234`, `1,234`, `1.234,5`, `1,5`).
- **Automatic fitting**: text is measured and the font is stepped down until it fits, in the preview, the HTML and
the PPTX alike (the three are drawn from one geometry). Text that cannot fit even at the smallest size is reported
by the check instead of being clipped silently.
- **Themes**: seven built-in themes (`claro`, `oscuro`, `editorial`, `carmesi`, `pizarra`, `tecnico`, `oceano`), all
with a contrast of at least 4.5:1 for text, muted text and accents. Fonts are ones present on Windows.
- **Exports**:
- PPTX with real text boxes, bullet paragraphs, speaker notes and native charts (editable in the office suite),
16:9.
- PDF, one page per slide, rendered by a local Chromium.
- HTML, one self-contained file (styles, script and images inline) with arrow-key navigation. Speaker notes are
left out on purpose because the file is meant to be shared.
- Markdown, slides separated by `---`, notes as comments, charts as tables.
- **Images**: upload your own, or ask the family's image studio (Prospero's Hoard) for a picture per slide. The
studio is optional.
- **Works without a model**: when no model is reachable, the outline and the slides are built from the sources by
fixed rules and the result says `"generator": "fallback"`. Regenerating one slide with feedback needs a model and
says so instead of pretending.
## Responsible use
- **Figures.** A generated deck is a draft. The number check finds figures that are not in the sources; it cannot
tell whether a source is right. Read the notes and the figures before presenting.
- **Sources stay local.** Documents are read on this computer. Only short numbered excerpts are sent to the model,
through Hoard Link, to whatever backend you configured (a local one by default).
- **Local files.** Adding a file by path only accepts document types (`.txt`, `.md`, `.pdf`, `.docx`, `.pptx`) and can
be limited to folders with `CICERO_FILE_ROOTS`.
- **Quotes.** A quote block should reproduce a quote that appears in a source. The check does not verify quotations.
- **Deletes** (a deck, a slide, a source) need an explicit confirmation, also over MCP.
## Install
Requirements: Python 3.11+ (Windows target 3.13), Node.js 22+ only to rebuild the client.
```bash
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -r requirements.txt
python -m playwright install chromium # only for the PDF export
python -m cicero_hoard # http://127.0.0.1:5194
```
The built client is committed under `cicero_hoard/static`, so `npm` is only needed to change the UI (`npm install`,
`npm run build`). During UI work `python scripts/dev.py` starts the API and the Vite dev server together, and
`python scripts/launch.py` starts the app and opens it in the browser.
| variable | default | meaning |
| --- | --- | --- |
| `CICERO_PORT` / `PORT` | `5194` | port; with `PORT_STRICT=1` the app fails instead of moving to another port |
| `CICERO_DATA_DIR` | `./data` | database, `assets/`, `exports/`, `mcp-token`, `url`, `backend.json` |
| `CICERO_ALLOWED_HOSTS` | local only | extra host names the server accepts |
| `CICERO_FILE_ROOTS` | empty | folders (separated by the OS path separator) that local-file sources may come from |
| `CICERO_IMAGE_STUDIO_URL` | discovered | address of the image studio, to skip discovery |
| `CICERO_IMAGE_TIMEOUT` | `600` | seconds to wait for one render in the image studio (10-86400) |
| `CICERO_PARALLEL_SLIDES` | `3` | slides written at the same time by the model after the first one (1-8); a local server with several slots finishes a deck sooner |
| `CICERO_SLIDE_EFFORT` | `low` | reasoning effort asked of the model for each slide and rewrite (`off`, `low`, `medium`, `high`); the outline always asks `medium` |
The model comes from Hoard Link (`data/backend.json` or the Hoard environment variables); the model name can also be
chosen in Settings.
## MCP
`mcp_server.py` is a stdio bridge. It never opens the database: it reads `data/mcp-token`, fetches the tool list
from the running app and forwards each call. When the app is not running it starts it (`CICERO_BRIDGE_AUTOSTART=0`
turns that off). Register it in any MCP client:
```json
{"mcpServers": {"cicero": {"command": "python", "args": ["/path/to/cicero/mcp_server.py"],
"env": {"CICERO_URL": "http://127.0.0.1:5194", "CICERO_TOKEN_FILE": "/path/to/cicero/data/mcp-token"}}}}
```
`faustus-plugin.json` describes the same setup for the Faustus workspace.
### Tools
| tool | what it does |
| --- | --- |
| `cicero_status` | health, counts, model and PDF availability |
| `deck_create`, `deck_list`, `deck_get`, `deck_update`, `deck_delete` | decks; `deck_get` returns a summary unless `detail=full`; delete needs `confirm=true` |
| `source_add`, `source_list`, `source_get`, `source_remove` | sources from pasted text or a local file; paged reading; removal needs `confirm=true` |
| `outline_generate`, `outline_update` | generate the outline or replace it by hand |
| `slides_generate` | write the slides from the outline; approved slides are kept |
| `slide_get`, `slide_update`, `slide_add`, `slide_delete`, `slides_reorder` | read, edit, add, remove (`confirm=true`) and reorder slides |
| `slide_regenerate` | rewrite one slide following feedback (needs a model) |
| `slide_approve` | approve or unapprove a slide |
| `slide_revert` | list a slide's revisions, or restore one as a new revision |
| `deck_check` | review: overflow, figures not in the sources, missing notes, unapproved slides |
| `deck_theme` | list the themes or apply one |
| `deck_export` | export to `pptx`, `pdf`, `html` or `md`; returns the file path and the download URL |
| `slide_image` | generate a picture for a slide with the image studio |
Results sent to an assistant are trimmed to about 20 KB with a hint to narrow the request. Approving a slide is the
person's decision: an assistant should not approve slides on its own.
## Family
Cicero works alone. Decks are addressable as `hoard://cicero/deck/<id>`. It emits `cicero.deck.created`,
`cicero.deck.deleted`, `cicero.outline.generated`, `cicero.slides.generated` and `cicero.deck.exported` on the hub
bus (ids and short titles only). Pictures come from Prospero's Hoard when it runs: the studio is looked up through
`CICERO_IMAGE_STUDIO_URL`, the hub's app list, or its default local port (8815), and is used through its local REST
API, which needs no token. Slide pictures go into a studio project named "Cicero's Hoard slides" (reused, or created
the first time); each request submits one 16:9 render, waits for it and stores the resulting image in the deck. Only
loopback addresses are ever contacted.
## Development
```bash
pip install -r requirements.txt
python -m pytest -q # no network: the model and the image studio are faked
```
The PDF tests run only when a Chromium is available. Documentation of the HTTP API is in `docs/API.md`.
## A real run
On a Windows PC with a local 27B model served by llama.cpp: a seven-slide sales plan for a fictional shop, from a
brief and one pasted report. The outline took 155 s; with slides written one after another each took about 75 s, which
is why they are now written three at a time. The model used only the report's figures: a bar chart of the four
quarters, the customer figures in two columns, and, after the feedback "remove the gross-margin sentence, it is not in
the report; show the 70,000 EUR breakdown as a bar chart", a slide with that exact breakdown and without the sentence.
The check reported no unsourced figure. PPTX and PDF exports were opened: native charts, speaker notes, the theme's
fonts embedded in the PDF. The image studio drew a 16:9 picture for one slide in 79 s. An assistant connected over
MCP listed the decks, ran the check and exported the PDF in four rounds. Four faults found in that run are fixed and
covered by tests: theme fonts lost in the HTML, bare thousands on native charts, a bridge that called a running app
stopped when it could not read its token, and an image call to a tool the studio does not have.
## Limits
- A picture takes as long as the studio needs to render it; the request waits up to `CICERO_IMAGE_TIMEOUT` seconds.
If that time passes the render keeps running in the studio and is not submitted again. Only one image is taken
per request, from a studio on this machine; images over 15 MB or not PNG, JPEG or WEBP are refused.
- The PDF export needs Chromium (`python -m playwright install chromium`, or a system Edge or Chrome). Without it,
exporting `pdf` fails with the code `pdf_unavailable` and the other formats keep working.
- Fonts are those of the theme; a machine without them substitutes another and lines may wrap differently. The
fitting leaves a small safety margin for that.
- Text fitting is an estimate from character widths, not a font-metrics measurement.
- Charts: bar, line and pie; one or several series (a pie uses the first).
- Speaker notes are not included in the HTML export.
- Scanned PDFs have no text and are refused with a message.
## License
See `LICENSE`.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues