Skip to content

Architecture Overview

Inkfeed follows a clean pipeline architecture: fetch → process → write.

High-Level Flow

┌─────────────┐     ┌──────────────┐     ┌──────────────┐
│   Config    │────▸│   Archivers  │────▸│   Writers    │
│  (TOML)     │     │  (fetch data)│     │ (format out) │
└─────────────┘     └──────────────┘     └──────────────┘
                           │                     │
                    ┌──────┴──────┐        ┌─────┴─────┐
                    │  Download   │        │  Jinja2   │
                    │  Images     │        │  Templates│
                    └─────────────┘        └───────────┘

Module Layout

inkfeed/
├── __init__.py
├── __main__.py          # Entry point (python -m inkfeed)
├── main.py              # CLI main function and orchestration
├── config.py            # TOML config loading and validation
├── archiver/            # Source-specific content fetchers
│   ├── base.py          # ArchiveResult, GroupResult, Article models
│   ├── hackernews.py    # Hacker News API archiver
│   ├── kaginews.py      # Kagi News API archiver
│   └── rss.py           # Generic RSS/Atom feed archiver
├── output/              # Format-specific output writers
│   ├── base.py          # FormatWriter base class, IndexEntry model
│   ├── html.py          # HTML writer
│   ├── markdown.py      # Markdown writer
│   ├── gemtext.py       # Gemtext (Gemini) writer
│   ├── epub.py          # EPUB writer
│   └── sleepscreen.py   # E-ink display writer
├── templates/           # Jinja2 HTML templates
│   ├── base.html
│   ├── html_article.html
│   ├── html_index.html
│   ├── main_index.html
│   ├── hn_story.html
│   ├── kagi_story.html
│   ├── rss_story.html
│   └── sleepscreen_*.html
├── utils/               # Shared utilities
│   ├── images.py        # Image downloading and embedding
│   ├── readability.py   # Article content extraction
│   └── retry.py         # Retry logic for HTTP requests
└── assets/
    └── fonts/           # Bundled fonts for self-contained output

Key Concepts

Archivers

An archiver knows how to fetch content from a specific source. Each archiver produces an ArchiveResult containing one or more GroupResult objects, each with a list of Article objects.

See Archivers for details.

Writers

A writer knows how to serialize articles into a specific output format. All writers implement the FormatWriter base class.

See Output Formats for details.

Templates

HTML-based output formats use Jinja2 templates. Templates are stored in inkfeed/templates/ and bundled with the package.

See Templates for details.

Execution Flow

  1. Load config — Parse config.toml into typed dataclasses
  2. Initialize writers — Create a writer instance for each requested format, call setup()
  3. For each enabled source:
    1. Look up the archiver class from ARCHIVER_MAP
    2. Run the archiver to get an ArchiveResult
    3. Download images for each group (parallel, with progress bar)
    4. Pass the result to each writer's write_source() method
  4. Write indices — Each writer generates date-level and source-level index pages
  5. Teardown — Writers clean up any resources (e.g., Playwright browsers)