The AI chat now knows what I am working on
The blog's AI chat now answers 'what are you working on' from local commit history: a narrow port, a version namespace bump, and term mining.
The "What Are You Working On" Problem
Last Thursday morning, a visitor typed into the blog's AI chat: "What are you working on right now?" The bot answered with a generic summary pulled from my published articles. Accurate, but it felt like talking about the weather. The real answer lived somewhere else entirely: in the commit history of repos being pushed every day. The LLM was not wrong. Its grounding data simply had no connection to git history.
Per-Key Delete Felt Wrong
My first guess was the usual cache dance: every time a new commit lands, delete the Redis keys holding the "what are you working on" answer, let the next read repopulate. Classic cache-aside. But the question repeats constantly, and each answer would hit the commits table on every miss. Under traffic, per-key deletes mean readers keep hitting stale answers while the cache silently repopulates behind them.
The Redis cache-aside documentation says the opposite: never try to keep the cache and primary in sync directly, just delete the cache entry and let the next read repopulate it [6]. What I actually needed was a way to retire an entire class of cached answers in one atomic step when the grounding data changed. That is the generation-counter pattern: version keys with a counter, bump the counter, old keys become unreachable and expire naturally [2]. Redis also recommends prefixing cache keys per application so services cannot clobber each other's entries [6].
The second issue was architecture. The articles module in my API is not allowed to import the activity module directly. It needed a narrow bridge instead.
Narrow Port, Adapter, and the Version Bump
The fix is three layers. First, a port named ActivityCommitReader in the articles module. The data shape is small: repo, message, timestamp. One adapter, SqlModelActivityReader, translates to the activity module's own repository. This matches FastAPI dependency-injection guidance: application scope is built once via lifespan and app.state, and dependencies hand out handles rather than constructing pools per request [3].
Second, intent detection. A function matches work-related phrases in Indonesian and English, such as "what are you working on" and a few local variants. When matched, the pipeline pulls the last 3 days of commits from the local GitHub sync. No GitHub API call happens at ask time.
Third, invalidation. Every time the sync service discovers new commits, it bumps the Redis version namespace for activity. All previously cached work answers become orphans immediately. They expire on their own TTL. The implementation is two lines in the sync module:
# github_sync.py
if total_new > 0:
redis_core.bump_version("act")
Commit Words Became Article Queries
An unplanned bonus: words mined from commit messages can drive the related-article search. Terms get stopword-filtered, keep the newest-first commit order, and cap at six. This connects to query expansion in full-text search: the search runs twice, terms from the most relevant documents in the first pass are added to the second search [1]. MySQL documents the same mechanism as blind query expansion, where the second search phrase is the original plus the most relevant documents from the first pass [4]. It suits short and exploratory queries, where users do not spell things the way the documents do [5].
One constraint I kept: graceful degradation. If the activity store is unavailable, the pipeline logs a warning and answers without the commit block. The bounded numbers here, 3 days and 30 commits across 5 repos with a 0.5 minimum FTS score, are my own heuristics rather than figures from any documentation.
Sources
[1] MariaDB Full-Text Index Overview
[2] Configuring the Django Redis Cache Backend
[3] FastAPI Best Practices for Dependency Injection
[4] MySQL 8.4 Full-Text Searches with Query Expansion
[5] How to Use MySQL Full-Text Search
[6] Redis Cache-aside with StackExchange.Redis