Cortex
An early, private pipeline I run for myself: it pulls finance and business news from RSS feeds, runs it through three passes on local models served by Ollama, and writes a daily Markdown note. Raw article text is encrypted with Fernet before it is stored.
Context
A personal system for turning a day of finance and business news into one short daily note, using models served locally through Ollama rather than a hosted API. It is early, private, and has one user: me.
Problem
The problems are the ones any LLM pipeline has: getting model output that code can use, and storing what the pipeline collects safely.
What I did
- Wired one source: a list of finance and business RSS feeds, fetched on each run.
- Tagged each article with a keyword-based category before any model call; the first model pass then usually re-classifies it.
- Ran three passes on local models through Ollama: classify each article and extract people, organizations, dates and key points; write insights, each with a suggested action, from the day's stored records; and turn the last four days of insights into a daily note.
- Asked each pass for JSON; insights are stored as typed Pydantic records. When a response does not parse, the code repairs what it can and otherwise falls back to default values rather than rejecting the record.
- Encrypted each raw article payload with Fernet before writing it to Qdrant; generated insights are stored unencrypted.
- Wrote the result as a dated Markdown note for Obsidian.
Result
- Every model call goes to a local model served through Ollama.
- Raw article text encrypted at rest with Fernet.
- An early, private, single-user pipeline. There is no production scale behind it, no users besides me, and no uptime claim.
Technical detail
How a run works
- Fetch recent articles from the configured RSS feeds and give each one a keyword-based category.
- Pass 1: a local model classifies each article and extracts people, organizations, dates and key points. Its category usually replaces the keyword tag.
- Encrypt each article payload with Fernet and store the classified record in Qdrant.
- Pass 2: a model writes short insights, each with a suggested action, from the day's stored records. Insights without an action are dropped.
- Pass 3, run as a separate command: read the last four days of insights by date and write the daily note as Markdown.
Encryption at the storage boundary
Raw article payloads are encrypted with Fernet before they are written to Qdrant. On the way back, a read fails only if a stored record is not in the encrypted shape; a payload that fails to decrypt comes back as a placeholder record.
The protection stops there. Record metadata and the generated insights are stored unencrypted.
Limits in this version
- RSS is the only wired source.
- Reading stored articles back is unreliable in this version: a payload that fails to decrypt comes back as a placeholder record, so later passes can work from the extracted metadata rather than the article text.
- Records are stored in Qdrant, but the vectors are placeholders (zeros for articles, a hash-derived pattern for insights), and nothing searches by similarity. The daily note reads insights by date.
- Output that fails to parse is not rejected: the classification pass falls back to a
defaultcategory or keeps the keyword tag, and the insight pass substitutes a generic summary, so a bad model run still produces generic insights. - Generated insights and record metadata are not encrypted.
- Tests cover only the encryption helpers.
Python, Ollama, Qdrant, Pydantic, Fernet, feedparser, Obsidian