Blog
Technical notes on web development, DevOps, and AI integration.
124 articles
- 02:34backend
Semantic Search on a 1GB VPS Without a Vector DB
Pure-Python cosine, vectors in MariaDB postmeta, embeddings computed locally. Semantic features with no new service on a small server.
TL;DR: Running a blog on a 1GB VPS rules out a vector database, so the author computes bge-m3 embeddings locally via Ollama and stores them as JSON in MariaDB postmeta. Related-article matching and dup-checks use pure-Python cosine similarity, fast enough for around 100 articles. Lesson: for small blogs, skip Qdrant or pgvector until scale demands it.
#python#fastapi#embedding - 02:33seo
Sitemap "Couldn't Fetch" in GSC: Diagnose Before Panicking
A red "Couldn't fetch" status in GSC does not mean your sitemap is 404. Here is the server-side diagnosis order.
TL;DR: Google Search Console showed a sitemap "Couldn't fetch" error, but server checks proved all 147 URLs returned HTTP 200 and Cloudflare blocked nothing. Per Google's docs, the message only means the last fetch attempt failed, often due to timeouts or a crowded crawl queue. The fix is patience: don't resubmit, wait a few days, then recheck.
#seo#search-console#cloudflare - 02:31ai
My Cron Pipeline Drafts Through a Browser, With Local Backup
Free Qwen chat via Playwright is now the primary draft engine for my article cron, with a local router9 fallback wired like a circuit breaker.
TL;DR: The author scrapes Qwen's free web chat via Playwright, copying answers from the clipboard since virtualized DOM rendering hides long replies. Knowing free tiers die without notice, a circuit breaker routes to local router9 after two failures, giving genuinely separate failure domains. The bet isn't that scraping lasts, just that the pipeline keeps running when it doesn't.
#automation#llm#playwright - 00:45tooling
A Failure-Proof Research Script: Two-Provider API Key Rotation
Two-layer API key rotation, provider fallback, and DoH for lying ISP DNS: lessons from building a research script that refuses to die quietly.
TL;DR: Firecrawl's keyless search endpoint died with permanent 403s mid-research, so the author pivoted to keyed APIs. The result is web-direct.py, 125 lines doing search, scrape, and extract with two-layer rotation: next key first, then next provider. A DoH health check catches lying ISP DNS, falling back to curl --resolve.
#automation#tooling#rest-api - 23:46seo
Best AI Assistant 2026: The Right Choice & Agent Runtime Trends
A per-need comparison of ChatGPT, Claude, Gemini, and Perplexity, plus where consumer assistants meet self-hosted agent runtimes: OpenClaw, Hermes Agent, and Agent Zero.
TL;DR: The best AI assistant in 2026 is no longer about the smartest chatbot but about persistence and autonomy. Pair a strong brain like ChatGPT or Claude with a self-hosted agent runtime such as OpenClaw, Hermes Agent, or Agent Zero for memory and autonomous execution. Go hybrid: match tools to your workflow instead of chasing one all-in-one winner.
#seo#ai#agent-runtime - 23:24ai
The Night I Copy-Pasted My Style Guide for the Tenth Time
Paste the same style rules ten times and you have a bug, not a habit. One agent skill file now carries the entire editorial voice.
TL;DR: Long prompts packed with style rules kept failing because the agent broke them anyway. Editorial voice is procedural knowledge, so it belongs in an Agent Skills file that loads on demand, not in every prompt. Moving everything to one SKILL.md shrank the prompt from seventy lines to twenty and created a single source of truth.
#agent-skills#writing-style#editorial - 23:00ai
The Search Snippet Said 96%, the Board Said 79.2%
Search snippets claimed 95-96% on SWE-bench Verified. The official board says 79.2%. Four rules to keep benchmark numbers honest.
TL;DR: The author checked the actual SWE-bench Verified leaderboard and found the top score is 79.20%, not the 95%+ figures circulating in search snippets. The gap exposed how easily benchmark numbers get cited without opening primary sources. The fix: log access dates, trust only opened primaries, snippets lose conflicts, report tied scores as-is.
#ai-agents#swe-bench#benchmark - 22:39devops
That Morning .gitignore Commit Made Me Rethink My Backup Setup
A two-line .gitignore whitelist commit turned into a full backup redesign: Git repo, restic, immutable cloud, 3-2-1-1-0 without a NAS.
TL;DR: A two-line .gitignore change led me to audit my backups, and I realized my NAS setup was untested and ransomware-vulnerable. I replaced it with a 3-2-1-1-0 approach: git bundles, restic snapshots, and immutable cloud storage. Monthly restore drills now verify the whole thing actually works.
#backup#git#restic - 16:40backend
Bare python in a Docker entrypoint picks the wrong interpreter
The knowledge seed failed on every container start although the script was in the image. Bare python resolved to the system interpreter.
TL;DR: The CI seed script failed because bare python resolved to the system interpreter, which had none of the project's packages or venv site-packages on its path. Running a script file by path skips CWD, so cd didn't help either. Fix: call the venv interpreter directly with PYTHONPATH set to the project root.
#docker#python#deployment