Skip to main content
notewise is a Python CLI application built with a clean layered architecture. Each layer has a single responsibility and strict import boundaries.

Layer overview

┌─────────────────────────────────────────────────────────────┐
│                      CLI Layer (Typer)                      │
│  cli/app.py · _batch_runner.py · _single_runner.py         │
└───────────────────────┬─────────────────────────────────────┘

┌───────────────────────▼─────────────────────────────────────┐
│                    Pipeline Layer                           │
│  pipeline/core.py · generation.py · _execution.py          │
└──────────┬────────────────────────────────┬─────────────────┘
           │                                │
┌──────────▼──────────┐          ┌──────────▼──────────────────┐
│   YouTube Layer     │          │        LLM Layer            │
│  youtube/parser.py  │          │   llm/provider.py           │
│  youtube/transcript │          │   llm/prompts/              │
│  youtube/metadata   │          └─────────────────────────────┘
│  youtube/extractor/ │
└──────────┬──────────┘

┌──────────▼──────────────────────────────────────────────────┐
│                    Storage Layer                            │
│  storage/repository.py · models.py · schemas.py            │
└──────────┬──────────────────────────────────────────────────┘
           │  (all layers can read)
┌──────────▼──────────────────────────────────────────────────┐
│                    Domain Layer                             │
│  domain/events.py · results.py · youtube.py                │
└─────────────────────────────────────────────────────────────┘

Layer responsibilities

CLI Layer

The only entry point for human users. Uses Typer for argument parsing and Rich for terminal output. Heavy dependencies are loaded lazily inside each command body to keep startup time low.
FileRole
cli/app.pyCommand definitions
cli/_batch_runner.pyMulti-video orchestration, feeds events to PipelineDashboard
cli/_single_runner.pySingle-video run path
cli/_runtime.pyCliProcessRunner top-level coordinator
cli/_display.pyRich table and panel helpers
cli/_admin.pyinfo / stats / history / cache / logs implementations
The CLI layer may import from all other layers. It must not contain business logic — it delegates entirely to the pipeline.
Owns the core processing workflow. The only layer that coordinates between YouTube extraction, LLM generation, and storage.
FileRole
pipeline/core.pyCorePipeline: state, semaphores, DB singleton, public run()
pipeline/_execution.pyprocess_single_video and run_pipeline implementations
pipeline/generation.pyStudyMaterialGenerator: token counting, chunking, LLM calls
May import from YouTube, LLM, storage, and domain layers. Must not import from the CLI layer.
Handles all YouTube-specific I/O: transcript fetching, metadata retrieval, playlist enumeration, and URL parsing.
FileRole
youtube/parser.pyURL and bare-ID parsing → ParsedURL
youtube/transcript.pyfetch_transcript() with language fallback and retries
youtube/metadata.pyget_video_metadata(), get_playlist_info(), get_source_metadata()
youtube/playlist.pyextract_playlist_videos()
youtube/extractor/Low-level HTTP client built from mixins
Must not import from the LLM or pipeline layers.
Provider-agnostic interface over LiteLLM.
FileRole
llm/provider.pyLLMProvider, UsageTotals, get_provider() factory
llm/prompts/study_notes.pyStudy note generation prompts
llm/prompts/chapter_notes.pyPer-chapter generation prompts
llm/prompts/quiz.pyQuiz generation prompts
Must not import from the YouTube, pipeline, or CLI layers.
Thread-safe SQLite persistence built on SQLAlchemy 2.0.
FileRole
storage/repository.pyDatabaseRepository: singleton per path, sync/async read/write
storage/models.pyORM models: VideoRecord, TranscriptRecord, RunStatsRecord, ExportRecord
storage/schemas.pyPydantic schemas for reading data out of the DB
storage/migrations.pyHand-rolled migration runner (no Alembic)
Must not import from YouTube, LLM, pipeline, or CLI layers.
Pure Python value objects — no I/O of any kind. Safe to import from everywhere.
FileRole
domain/youtube.pyVideoMetadata, VideoTranscript, TranscriptSegment, VideoChapter, ParsedURL
domain/events.pyEventType enum, PipelineEvent dataclass
domain/results.pyPipelineResult, PipelineMetrics

Cross-cutting concerns

Configuration

config.py exports a module-level settings object (a _LazyAppSettings facade over AppSettings). All modules import from notewise.config. Loaded once on first access and cached.

Error handling

All custom exceptions are defined in errors.py. No other module defines project-specific exceptions. See Error Reference for the full hierarchy.

Logging

logging.py configures structlog at CLI startup. All modules obtain a logger via structlog.get_logger(__name__). API keys and other sensitive values are automatically redacted before writing to log files.

State directory

~/.notewise/
├── config.env                         # User configuration
├── .notewise_cache.db                 # SQLite cache
└── logs/
    ├── notewise-20260101-120000.log
    └── ...
Override the location with NOTEWISE_HOME.