Development workflow¶
How to work on SlideStream: setup, layout, rules, tests and releases. Design decisions are in the ADRs; planned work is in the roadmap.
Setup¶
You need Python 3.10+ and uv. FFmpeg is
bundled; LibreOffice is only needed to try --preserve-style by hand (the
tests mock it).
git clone https://github.com/michael-borck/slide-stream.git
cd slide-stream
uv sync --all-extras --group dev
uv run pytest && uv run ruff check . && uv run basedpyright
A plain uv sync installs only the core and removes extras from .venv;
use --all-extras --group dev for development.
On an exFAT drive macOS writes ._* files beside every file. They are
git-ignored; code that globs files should skip them.
Layout¶
src/slide_stream/
cli.py Typer commands: create, doctor, draft, enrich, scan,
presenton, serve, init, providers, voices, avatars
config_loader.py Layered YAML config, starter and full reference templates
parser.py Markdown decks: content, code blocks, tables, Markdown body
powerpoint.py .pptx input, speaker notes
narration.py Narration source choice, scripts, stage directions
llm.py LLM clients
media.py Slide frames, presenter overlay, video assembly
code_render.py Pygments syntax colouring
export_pptx.py Plain .pptx output (ADR-0008)
doctor.py Preflight report
draft.py Document to Markdown deck
enrich.py Pictures and AI notes into a new deck
scan.py Name picture folders
presenton.py Presenton client and design review (ADR-0009, ADR-0013)
fidelity.py Designed deck vs source check (ADR-0013)
code_slides.py SlideStream-built code slides in designed decks
slide_render.py PDF and .pptx to frames (pypdfium2, LibreOffice)
ffmpeg_bin.py ffmpeg on PATH, else moviepy's bundled copy
serve.py FastAPI web UI (demo, local and hosted modes)
web_security.py Host checks and request limits for serve
avatars.py Built-in mascots
providers/ base.py, factory.py, tts.py, images.py, avatar.py
tests/ Mocked suite; tests/live/ for real services
e2e/ Render matrix (run.sh) and the Presenton trial
deploy/ Docker image and compose files
desktop/ Tauri desktop shell
landing/ Website front page
docs/ This site (MkDocs)
Rules¶
- Zero basedpyright errors, ruff clean. Use
# type: ignore[...]only for missing stubs, with the specific code. - Tests first for new behaviour; every bug fix gets a regression test.
- Hermetic tests (ADR-0007):
no network, a fake home folder, provider variables scrubbed, the voice
floor pinned to gTTS (
tests/conftest.py). Mock HTTP at the session orrequestsboundary. - New features are a pipeline stage or a provider/adapter (ADR-0010, ADR-0011). Add a roadmap entry and, for decisions, an ADR.
- Every role keeps a fallback
(ADR-0012);
--strictmust fail rather than fall back for a provider the user chose. - Dependencies are permissively licensed (MIT, BSD, Apache); no AGPL. Check the licence before adding one, and record new external engines in SERVICES.md.
- Docs follow code. Provider changes update PROVIDERS.md
(a test checks every registered provider is listed); config changes go in
config_loader.py's template, then regenerate the example file (below).
Adding a provider¶
- Subclass the role's base class in
providers/base.py(TTSProvider,ImageProvider,AvatarProvider) and implementname,is_available()and the role method. - Register it in
providers/factory.py(the class map and thelist_*_providersdescription). - Route per-call failures to the fallback (for TTS,
self._fallback_to_floor), respecting strict mode. - Add mocked tests, a row in PROVIDERS.md, a commented example in the config template, and for a server a row in SERVICES.md.
Tests¶
uv run pytest # mocked suite
uv run pytest tests/test_parser.py -q # one file
uv run pytest --cov=slide_stream --cov-config="$PWD/pyproject.toml" # with coverage
uv run pytest --run-live tests/live # real services from ~/.slidestream.yaml
e2e/run.sh fast # render matrix against your stack
Live tests and e2e/ use your real config and servers and are never run in
CI. e2e/presenton/run.sh repeats the Presenton trial.
CI (.github/workflows/ci.yml) runs ruff, basedpyright and the suite with
coverage on Python 3.10 to 3.13.
Regenerating generated files¶
# The full config reference (a test checks they match):
uv run python -c "from slide_stream.config_loader import create_example_config; open('slidestream.example.yaml','w').write(create_example_config())"
# Preview the docs site:
uvx --with mkdocs-material mkdocs serve
Releases¶
Use twine, not uv publish.
- Add the release to CHANGELOG.md.
- Bump the version in
pyproject.tomlandsrc/slide_stream/__init__.py; runuv lock. uv run pytest && uv run ruff check . && uv run basedpyrightuv build, thentwine check dist/slide_stream-X.Y.Z*.twine upload dist/slide_stream-X.Y.Z*- Commit (
chore: release X.Y.Z (…)), tagvX.Y.Z(annotated), push both. gh release create vX.Y.Zwith notes from the changelog.
Pushing a version change rebuilds the Docker image from PyPI. The desktop
app picks up the new engine on its own; bump desktop/ only to raise its
minimum version or change the shell.