Why
LinkedIn export + local notes cover a lot, but many writers keep their longform on Substack / Medium / Ghost. Broader ingest = richer article-channel voice indexes and a bigger potential user base discovering the repo.
Scope
Extend ingest so these sources land as proper Piece rows (prefer linkedin_article-equivalent longform or a new source label that write --channel article can use).
Suggested sources
| Source |
Input shape |
Notes |
| Substack |
export ZIP or posts/ markdown |
Dates + titles from front matter |
| Medium |
export ZIP (posts/ HTML) |
Strip Medium chrome/CSS (see corpus_text.py patterns) |
| Ghost |
JSON export or markdown |
Map lexical/html → clean text |
CLI sketch:
personality-protect ingest --substack ~/Exports/substack.zip
personality-protect ingest --medium ~/Exports/medium.zip
personality-protect ingest --ghost ~/Exports/ghost.json
Acceptance criteria
Pointers
src/personality_protect/ingest.py
src/personality_protect/corpus_text.py (Medium/Ghost CSS stripping already exists)
src/personality_protect/models.py (Piece.source)
Privacy
Never commit real exports. Ship only synthetic fixtures under tests/fixtures/.
Difficulty
Medium — parsing + tests; high user value.
Why
LinkedIn export + local notes cover a lot, but many writers keep their longform on Substack / Medium / Ghost. Broader ingest = richer article-channel voice indexes and a bigger potential user base discovering the repo.
Scope
Extend
ingestso these sources land as properPiecerows (preferlinkedin_article-equivalent longform or a newsourcelabel thatwrite --channel articlecan use).Suggested sources
posts/markdownposts/HTML)corpus_text.pypatterns)lexical/html→ clean textCLI sketch:
Acceptance criteria
sourcefieldPointers
src/personality_protect/ingest.pysrc/personality_protect/corpus_text.py(Medium/Ghost CSS stripping already exists)src/personality_protect/models.py(Piece.source)Privacy
Never commit real exports. Ship only synthetic fixtures under
tests/fixtures/.Difficulty
Medium — parsing + tests; high user value.