Skip to content

Repository files navigation

tutorio

Tutorio is a local-first desktop application that reconstructs long-form tutorials as practical learning manuals. It is intentionally not a summariser: generated guides preserve procedures, explanations, commands, warnings, mistakes, shortcuts, and source timestamps.

Everything runs on the user's machine. There are no cloud services, accounts, or authentication.

Tutorio library showing PDF and YouTube guides

Compile a YouTube tutorial or local document, then return to it from the local guide library.

Requirements

Tutorio keeps processing local, but its runtime dependencies are installed separately and are not bundled with release downloads:

  • Ollama running locally with the configured model. Tutorio recommends gemma4:e4b.
  • yt-dlp for YouTube sources.
  • Poppler's pdftotext and pdftocairo for PDF extraction and page previews.

For example, on macOS:

brew install yt-dlp poppler
ollama pull gemma4:e4b

Ensure the Ollama service is running before compiling. The Ollama desktop application normally manages it automatically. If you installed only the command-line service and nothing else is running it, start ollama serve in a terminal and leave that process open. An “address already in use” error means an Ollama service is already listening, so a second one is unnecessary.

Scanned or image-only PDFs are detected but require a future OCR adapter; Tutorio does not silently generate a guide from missing text. Developer requirements such as Go, Wails, and Node.js are listed under Development.

Tool paths in downloaded applications

Running wails dev from a terminal gives Tutorio the terminal's PATH. A downloaded application launched from Finder, the Windows desktop, or a graphical Linux launcher may receive a different, more restricted PATH. The tool can therefore be installed and work during development while the packaged application cannot find it.

Find each executable from a terminal:

command -v yt-dlp
command -v pdftotext
command -v pdftocairo

On Windows PowerShell, use Get-Command yt-dlp, Get-Command pdftotext, and Get-Command pdftocairo, then read each command's Source value.

Then place the returned absolute paths in the installed application's config.yaml. On Apple Silicon Homebrew, this commonly looks like:

tools:
  yt_dlp_path: /opt/homebrew/bin/yt-dlp
  pdftotext_path: /opt/homebrew/bin/pdftotext
  pdftocairo_path: /opt/homebrew/bin/pdftocairo

Intel macOS Homebrew commonly uses /usr/local/bin instead. Use the paths reported by your own system rather than assuming either location. See Configuration for the platform-specific config.yaml location. Bare command names remain suitable when the application's environment already contains the installation directory.

Download

Prebuilt macOS, Windows, and Linux artifacts are published on the GitHub Releases page.

To try Tutorio:

  1. Open the latest release.
  2. Download the artifact for your platform.
  3. Extract the archive.
  4. Run tutorio.

macOS security

macOS release builds are signed with Developer ID and notarized by Apple.

Current foundation

This repository provides a buildable Wails application and the architectural spine for the MVP:

  • YouTube subtitle retrieval through yt-dlp.
  • local .txt, .srt, and .vtt transcript ingestion.
  • local text-based PDF ingestion with durable source chunks and page-aware evidence through Poppler.
  • transcript cleaning and source-aware, cue-preserving segmentation.
  • structured JSON generation through a local Ollama model.
  • structural verification before persistence.
  • a single-worker background compilation queue with cancellation and automatic restart recovery.
  • interrupted-job-first recovery and user-controlled “Run first” preemption for pending compilations; completed sections and source identity are retained.
  • persistent per-section results with targeted retry after interruption.
  • active-section timing, slow-call indicators, inspectable local model diagnostics, source-neutral extracted-text metrics, and separate prompt/generation token rates for model speed comparisons.
  • verified transcript excerpts, clickable source timestamps, and exact PDF evidence previews.
  • section-level overviews, prerequisite deduplication, and locally bundled KaTeX formula rendering.
  • visible source sections, guide editing, single-section regeneration, source-grounded deep dives, and portable HTML/Markdown export.
  • collapsible guide sections that double as a compact index, plus compact reference blocks for supporting material.
  • SQLite storage and a Wails guide library/reader.

The UI is deliberately small. Model setup and native transcript-file selection remain in the usable-MVP phase described in the roadmap.

Architecture

Dependency direction points inward. Domain and orchestration packages do not import Wails, SQLite, Ollama, or process-execution details.

Wails UI ─> jobs.Manager ─> jobs.Pipeline ─> source / transcript / guide interfaces
yt-dlp ───┤                         ▲            ▲
Ollama ───┤                         │            │
SQLite ───┘                    domain models  use-case rules

How compilation works

flowchart TD
    A[YouTube URL or transcript file] --> B[Source adapter]
    B --> C[Timestamped transcript or page-aware source chunks]
    C --> D[Clean and split into bounded segments]
    D --> E[Generate structured JSON and source chunk IDs with Ollama]
    E --> F[Validate citations and resolve exact source evidence]
    F --> G[Merge sections, deduplicate, and build cheat sheet]
    G --> H[Synthesize a concise guide overview]
    H --> I[Verify guide structure]
    I --> J[(Save complete guide in SQLite)]
    J --> K[Display in library and guide reader]
Loading
  1. The UI persists a pending job and returns immediately; a single background worker runs queued jobs without competing Ollama requests.
  2. The source registry selects the YouTube or local-file adapter.
  3. yt-dlp retrieves YouTube subtitles; TXT, SRT, and VTT files are parsed directly; Poppler extracts text PDFs by physical page.
  4. Transcript text is cleaned while timestamps are preserved. PDF text is persisted as immutable, content-addressed source chunks before generation.
  5. Tutorio prefers explicit YouTube chapters and conservative PDF heading boundaries, then uses long transcript pauses as a soft boundary when enough content has accumulated. The configured Unicode-character budget remains a hard maximum and fallback.
  6. Ollama reconstructs each segment as structured guide content and must return a concise title specific to that section; live progress is sent to Wails.
  7. Model variations are normalized. For PDFs, returned chunk IDs are checked against the exact chunks supplied to that request, deduplicated, capped, and resolved to stored text. Unknown IDs are discarded and unsupported steps remain uncited.
  8. Each completed section and its performance metadata are persisted so failed work can resume without repeating successful sections.
  9. A small, non-blocking Ollama request synthesizes a guide-level overview from stored section titles and summaries. If it fails, the complete guide is still saved and the reader offers a retry.
  10. The result is verified, stored as structured JSON in SQLite, and loaded by the library reader after restart.

Package responsibilities:

Package Responsibility
repository main.go Wails-required composition root and lifecycle
cmd/app Desktop frontend assets (kept under the conventional app shell)
internal/source Source contract and adapter registry
internal/source/youtube yt-dlp process adapter
internal/source/local Local transcript-file adapter
internal/transcript Source-neutral parsing, cleaning, segmentation
internal/llm Model-provider contract and Ollama HTTP adapter
internal/guide Guide domain, generation and verification contracts
internal/evidence Registered sources, immutable source chunks, evidence resolution
internal/jobs Background queue, pipeline use case, recovery, and stage orchestration
internal/storage/sqlite SQLite connection, schema, guide repository
internal/config YAML configuration and local defaults
internal/ui Thin Wails-facing application API
internal/exporter Output contract and portable HTML/Markdown implementations

Interfaces are owned near the code that consumes their behavior and kept small. context.Context crosses every operation that can block. Dependencies are assembled only in the root main.go; no package-level mutable state is used. Wails v2's binding generator requires its Go entrypoint at the project root, so this is the one intentional variation from the usual cmd/app/main.go layout.

Extension strategy

New content sources implement source.Source and register at startup. Whisper can become another source/transcription adapter; screenshots can be introduced as an optional enrichment stage; vision models can implement a provider boundary parallel to llm.Provider. Exporters and learning-artifact generators should be independent use cases over persisted guide.Guide values. Playlist support should compose child jobs rather than enlarge the YouTube adapter.

This keeps future media capabilities out of the text-only MVP while leaving clear seams for them.

Guide model

The stored guide includes a synthesized overview with readiness metadata, prerequisites, final outcome, ordered steps, citations, transcript evidence, important concepts, commands, keyboard shortcuts, warnings, common mistakes, cheat sheet, appendix, source timestamps, source-grounded deep dives, and generation metadata. SQLite stores searchable identity/summary columns plus the complete versionable guide as validated JSON. Registered sources, immutable source chunks, and evidence identities are normalized for reuse. Jobs and individual transcript/model sections are persisted separately for recovery, targeted regeneration, overview retry, timing, and local diagnostics. The base schema is in internal/storage/sqlite/schema.sql, with numbered changes in internal/storage/sqlite/migrations.

Tutorio guide showing generation details and collapsible sections

Generated guides are organised into navigable sections that can be expanded, regenerated, or explored in more depth.

For a newly generated PDF guide, selecting a citation opens a lightweight evidence drawer containing the exact extracted chunk, its neighbouring chunks, the source title, physical PDF page, and a locally rendered page preview for figures, tables, and formatting. “Open full PDF” remains a secondary native-viewer fallback. Older saved guides with page-only references still show the source and physical page, but correctly show no excerpt; recompile the PDF to create durable evidence. See the evidence architecture decision.

Tutorio evidence drawer showing a cited PDF page preview

PDF citations open exact extracted evidence alongside a page preview, with the original document still available when more context is needed.

For production evolution, add numbered embedded migrations rather than editing an already-released migration.

Exporting guides

The reader's Export menu offers:

  • HTML — the recommended sharing format. It produces one dependency-free, responsive file with embedded styling, print rules, structured steps, commands, shortcuts, warnings, and source links. It can be opened offline in phone and desktop browsers or printed to PDF by the recipient.
  • Markdown — a lightweight source format for note-taking tools, version control, and further editing.

YouTube timestamp links remain portable. PDF citations are grouped once per physical page and link to deduplicated exact-text evidence embedded later in the HTML file. The complete original PDF and page images are not included, which keeps exports compact and avoids exposing absolute filesystem paths. Older page-only citations remain clearly labelled but cannot include evidence that was never stored; share the original PDF separately when recipients need diagrams, formatting, or broader context.

Generation metrics

Generation details describe model workload and speed, not guide quality:

  • Model is the Ollama model that generated the guide sections.
  • Sections is the number of bounded source segments sent as separate generation requests. More sections can add request overhead even when total token counts are similar.
  • Duration is the sum of Ollama's total duration for the successful section requests. It includes more than token evaluation, so it will be longer than the two evaluation times alone. It does not currently include source extraction, final verification/storage, or overview synthesis.
  • Tokens in/out are Ollama's prompt and generated token counts. Input tokens include the extracted source plus Tutorio's repeated instructions, structured-output schema, timestamps, and source metadata; they are therefore a model-workload measure rather than the exact size of the original source.
  • Prompt speed is prompt tokens divided by Ollama's prompt-evaluation duration. Prompt processing is highly parallel and is normally much faster than output generation.
  • Generation speed is output tokens divided by Ollama's output-evaluation duration. Output is generated autoregressively, so each token depends on the preceding token.
  • Source content is the word and Unicode-character count of the cleaned text before it is sent to the model. It is independent of Ollama's tokenizer and does not include Tutorio's prompts.
  • Source records the extraction method plus a source-specific extent when available: transcript duration for timed media or the highest physical page containing extracted PDF text.

The speed figures are weighted aggregates across all sections: total tokens divided by total corresponding evaluation time. They are useful for comparing inference speed on the same hardware and broadly similar workloads, but they do not measure completeness, accuracy, concision, or source fidelity. Older guides created before evaluation timing was stored omit these rates rather than estimate them.

Raw file bytes are intentionally not shown as an ingestion metric. They are not comparable across PDFs, subtitles, videos, and future source types, and may include images or compression unrelated to extracted text. Extracted words and characters provide the source-neutral comparison instead. Word counts are whitespace-delimited and therefore less representative for languages that do not separate words with spaces; the Unicode-character count remains the more stable cross-language measure. Changing caption, transcription, OCR, or cleaning implementations can still change both counts, so the stored extraction method provides necessary context.

Configuration

Tutorio resolves configuration in this order:

  1. The path in TUTORIO_CONFIG_PATH, when set.
  2. config.yaml in the current working directory (convenient for wails dev).
  3. The platform user config directory:
    • macOS: ~/Library/Application Support/tutorio/config.yaml
    • Linux: $XDG_CONFIG_HOME/tutorio/config.yaml, or ~/.config/tutorio/config.yaml
    • Windows: %AppData%\tutorio\config.yaml

If no configuration exists, Tutorio creates one at the resolved platform path on first launch. It records absolute paths for supported tools when they can be discovered from the application environment or common installation locations, and otherwise retains editable command-name defaults. Existing configuration files are never overwritten.

Copy config.example.yaml to config.yaml in the repository root when you want a project-specific development configuration for wails dev. The startup log reports the selected path and Ollama model. The library also shows a non-blocking local-setup panel when Ollama, the configured model, or a source-specific tool cannot be found. Each executable path can be validated and saved independently in that panel; Tutorio updates only that tool-path setting and activates it immediately for new work. No restart is required.

Missing yt-dlp disables YouTube compilation only. Missing pdftotext disables PDF import, while TXT/SRT/VTT import remains available. Missing pdftocairo disables PDF page previews but does not prevent PDF guide generation or access to saved guides. The generated configuration path remains visible for users who prefer to edit YAML manually; values changed outside Tutorio are applied on the next launch.

ollama:
  base_url: http://127.0.0.1:11434
  model: gemma4:e4b
  max_output_tokens: 8192
  context_window: 32768
tools:
  yt_dlp_path: yt-dlp
  pdftotext_path: pdftotext
  pdftocairo_path: pdftocairo
processing:
  segment_characters: 12000

The database path can be overridden when needed:

database:
  path: /absolute/path/to/tutorio.db

Prefer an absolute path for this override. Relative paths are resolved from the application's current working directory and can therefore select a different database depending on how Tutorio is launched.

segment_characters is a hard Unicode-character budget, not a tokenizer target. Explicit YouTube chapters may create shorter sections. PDF headings and long transcript pauses are used only after enough content has accumulated, which avoids turning every small heading or silence into a separate section. When no trustworthy structure exists, Tutorio falls back to cue boundaries near the configured limit. A future semantic segmenter can replace these heuristics without changing the pipeline.

Tutorio invokes configured tools locally and sends model requests only to the configured Ollama URL.

Local data and upgrades

Tutorio stores its SQLite library outside the executable or application bundle. Replacing Tutorio with a newer build therefore preserves generated guides, jobs, source chunks, citations, and stored text evidence. On startup, the application opens the existing database and applies any required embedded migrations.

The default database is:

  • macOS: ~/Library/Application Support/tutorio/tutorio.db
  • Linux: $XDG_CONFIG_HOME/tutorio/tutorio.db, or ~/.config/tutorio/tutorio.db
  • Windows: %AppData%\tutorio\tutorio.db

This platform-native location is intentional. It follows operating-system conventions and is preferable to creating a hidden $HOME/.tutorio directory.

Imported files are not copied into the database. The generated guide and extracted text evidence remain available if an original PDF is moved or deleted, but opening the full PDF or rendering its page preview requires the file to remain at its registered path.

For a basic backup, close Tutorio and copy tutorio.db. Restoring that file to the same configured location restores the local library. A future in-app backup/export flow can package the database and registered source files more comprehensively.

Choosing an Ollama model

There is no universal best model: tutorial reconstruction trades generation time, completeness, concision, schema reliability, and local memory use.

Model Expected fit for tutorio
gemma4:e4b Recommended quality baseline when concise, tightly scoped guide sections matter more than generation speed. In initial testing it was slower but less verbose.
qwen3.5:9b Useful detail-oriented alternative. Initial testing extracted more material, but sometimes produced overly verbose or unnecessary content.
qwen3.5:4b A useful newer, smaller Qwen competitor for speed/quality experiments against Gemma 4 E4B. It has not yet been validated by this project.
qwen3:8b Older text-only Qwen 3 baseline. The tag means “Qwen 3, 8B parameters”; it is not a Qwen 3.8 release and does not supersede Qwen 3.5.

Keep max_output_tokens, context_window, segmentation, source URL, and prompt settings identical when comparing models. Compare total duration, step usefulness, timestamp accuracy, shortcut/command extraction, schema reliability, and unnecessary repetition—not output length alone.

Development

Development additionally requires:

Install dependencies and run tests:

go mod tidy
go test ./...

Run the desktop app with live frontend reload:

wails dev

Build the production desktop bundle:

wails build

Useful equivalents are available through make test, make dev, and make build.

When adding a feature, put domain data/rules in an inner package, define the smallest needed interface, implement infrastructure in an adapter package, and wire it at the composition root. Use fakes at the interface boundary in unit tests. External-process and HTTP adapters should additionally have fixture-driven contract tests.

Run the opt-in local integration test against a real URL and the configured Ollama model with:

TUTORIO_CONFIG_PATH="$PWD/config.yaml" \
TUTORIO_TEST_URL="https://www.youtube.com/watch?v=VIDEO_ID" \
go test -tags=integration ./internal/integration -run TestCompileYouTube -v -count=1 -timeout=20m

The test uses a temporary SQLite database and does not add its output to the desktop library.

Release builds

The release workflow builds macOS, Windows, and Linux artifacts from tags matching v* and publishes them to a GitHub Release.

Current release limitations:

  • Windows signing is not configured.
  • Linux packaging contains the Wails build output rather than a distribution-specific package.
  • Runtime tools such as Ollama, yt-dlp, and Poppler are not bundled.

Deliberate limitations

  • Long transcripts are generated section-by-section and merged deterministically. A later synthesis pass may improve cross-section narrative cohesion without sacrificing provenance.
  • Deep dives deliberately use only the saved source transcript and current section steps; optional cited web research is not implemented.
  • PDF step citations are grounded to exact extracted chunks. Broader claim-level semantic verification and support classification remain future work.
  • The queue deliberately runs one compilation at a time to avoid concurrent local-model memory pressure.
  • The backend supports transcript-file import, while native file selection and its frontend control are Phase 1 UI work.
  • Audio transcription, screenshots, vision, playlists, PDF export, flashcards, quizzes, and progressive learning are architecture extension points only.

See docs/ROADMAP.md for phased delivery criteria.

About

Tutorio is a local-first desktop application that reconstructs long-form tutorials as practical learning manuals

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages