# How We Built an Autonomous AI Feed on a 1 GB RAM VPS for $18/mo: a pet project that started running on its own

> AI Release · @ai_release1 · https://ai-release.org/guides/kak-my-sobrali-telegram-kanal-ob-ii_en.html

It all started with a mundane pain point: every day dozens of news items about neural networks come out — new models, updates, benchmarks, and papers. Monitoring dozens of RSS feeds, X (Twitter), Habr, Hacker News, and manually scraping it all from search engines is a hellish overhead and burnout. We just wanted a single clean channel with a digest of all search engines and primary sources — no fluff, clickbait, or repeats. And exclusively for personal use: check once a day and absorb the whole context in a couple of minutes.

Eventually, a quick-and-dirty home script grew into a fully autonomous pipeline. It all runs on a crappy $5 VPS with 1 GB of RAM, no desktop, no human in the loop, and no bloated orchestrators. In a month, this setup generated nearly 450 posts, gathered 700+ subscribers, and saved us a ton of hours. Here's how we built it, what pitfalls we hit, and how we save tokens.

## Idea and prerequisites: why the dumb "RSS + ChatGPT" tutorial doesn't work

At first, we thought we could get by with a hack like "download RSS → feed to OpenAI → blast to Telegram." Spoiler: that scheme died on day one.

Here's what we ran into:

- **Duplicates everywhere.** Fifteen outlets write about the same release, changing only the headline.
- **LLM hallucinations.** Models love to invent numbers, fabricate reasons, and draw conclusions that never existed in the source.
- **Insane image generation limits.** Paying for Midjourney or DALL-E for every post is bankruptcy.
- **1 GB RAM is a death sentence for local models.** You can't run Ollama or Llama on such a potato.
- **You need an SEO pipeline.** If you make a mirror site without proper links, search engines simply won't see it.

In the end, we assembled a lean but mean stack: pure Python, systemd timers (no Celery/Redis overhead!), external LLM APIs, lightweight metasearch, and a static web mirror.

## Budget: pinching pennies

This was a pet project for ourselves, so nobody was going to inflate the budget. We kept it to $18.8 per month:

| Expense item | Cost |
|---|---|
| VPS (1 GB RAM / 1 vCPU) | ~$5 / mo |
| OpenCode Zen GO subscription (LLM API) | $10 / mo |
| Domain ai-release.org | ~$1.8 / mo ($22/yr) |
| Telegram Premium (for the bot) | ~$2 / mo ($25/yr) |
| **Total** | **~$18.8 / mo** |

The biggest line item is the neural network API, but this subscription covers everything: from rewriting news to a personal chat responder. And we don't spend a cent on cover images — we source them from open sources.

## Architecture: ditch Celery, use systemd

Why drag Redis, RabbitMQ, and Celery into a project when you can get by with built-in Linux tools? For a project of this scale, systemd timers are the perfect solution. Each task runs in its own isolated process: if one times out, it doesn't take down the whole server.

Scripts are scheduled via `OnCalendar`:

```ini
# ai-release-hourly.timer (*:15) — 1 news item per hour
# ai-release-video.timer  (0:30, 8:30, 16:30) — video every 8 hours
# ai-release-daily.timer  (18:00 MSK) — daily digest
# ai-release-stats.timer  (18:00 UTC) — metrics collection
# ai-release-chat.service (daemon) — AI bot in DMs
# ai-release-web.service  — web mirror

[Timer]
OnCalendar=*-*-* *:15:00
Persistent=true
```

Publishing goes directly through the Telegram Bot API.

**Where we source content:**

- **RSS aggregators:** Habr, Ars Technica, TechCrunch, VentureBeat, The Register, The Decoder.
- **Primary sources:** OpenAI blogs, Google Research, ArXiv API, Hugging Face Daily Papers, GitHub Trending, Hacker News (via Algolia API).
- **Personal blogs:** Simon Willison, Andrej Karpathy, Sebastian Raschka, Nathan Lambert.
- **Fallback:** local SearXNG in Docker for quick metasearches.

## Triple filtering and deduplication

To keep the feed from turning into a dump of 10 identical stories about "OpenAI released a new model," we applied a three-stage filter:

1. **Scoring.** We calculate a news item's weight based on freshness, source authority, and headline. Primary sources and engineers' personal blogs get priority over reposts.
2. **Headline normalization and hashing.** We strip junk like `BREAKING:`, `URGENT:`, tails like `— TechCrunch` or `| The Verge`, normalize quotes, and check `sha256` in SQLite:

```python
def normalize_title(t: str) -> str:
    t = re.sub(r"\s*[-—|]\s*(TechCrunch|Engadget|The Verge|WindowsLatest).*$", "", t, flags=re.I)
    t = re.sub(r"^(BREAKING|СРОЧНО|EXCLUSIVE)\s*:?\s*", "", t, flags=re.I)
    t = t.replace("«", '"').replace("»", '"').strip()
    return t.lower()
```

3. **Semantic dedup via LLM.** Headlines can differ while the essence is the same. Before posting, the candidate is compared with the texts of recent channel posts. Similar? Reject it.

We also cut SEO junk: unknown domains are allowed only if there's a concrete signal (a model name, company, or event), while abstract "AI/neural network" stuff gets banned immediately.

## Training the LLM: making the model stop embellishing

The main problem with basic prompts was that the model constantly tried to infer "why this happened" and write profound conclusions that weren't in the source.

How we made it work properly:

- **We clamped `temperature` from 0.8 down to 0.5.**
- **We introduced a strict system prompt:** "Write ONLY what's in the text. No hypotheses, embellishments, or predictions. If numbers are given, take them strictly from the source. Always preserve attribution (who exactly said this)."
- **We baked in hard rules.** A clear example: in a Windows 10 news story, the model decided to advise staying on it. We hardcoded a rule: "Windows 10 support ended on October 14, 2025; there are no free security updates." Now the editor automatically pulls in appropriate security context.

## Token savings and model routing

Since the LLM is the only thing we pay real money for, we save on every request:

- **Smart routing.** The main flow goes through DeepSeek V4 Flash. If the endpoint fails or returns 5xx, we switch to the backup GLM-5.3-Flash. The post isn't lost, and the pipeline doesn't crash.
- **Response caching.** In the chat bot, frequent questions are parsed by SHA-1 hash (TTL 30 days). A repeat question gets an instant answer from the database without an API call.
- **Prompt caching.** We pass the `x-opencode-session` header. The provider caches the system part of the prompt and doesn't charge for it on subsequent calls.
- **Batching into one call.** For long digests, we don't make a chain of requests; we send everything in one prompt with a reasonable `max_tokens` so the model doesn't burn tokens on unnecessary reasoning.

## Free cover images: building without DALL-E

Generating images via API is expensive and slow. We built a cascading fallback for finding illustrations:

1. Pull `og:image` from the original article.
2. If `og:image` is missing or broken, we go to metasearch across free stock sites (Unsplash, Pexels, Pixabay, Wikimedia, Flickr).
3. Nothing found? We pull a themed art or anime/manga illustration.
4. Completely empty? We use the default fallback pack.

Before sending, the image is validated with a quick HEAD request. If Telegram returns `400 Bad Request`, the script swaps the cover on the fly and retries.

## Fault tolerance: not crashing at the slightest API hiccup

External endpoints love to lag. To avoid babysitting the server over SSH, we built in several safeguards:

- **Retries with exponential backoff** for all network calls (`BrokenPipeError`, `ConnectionError`, `TimeoutError`).
- **Send buffer (deferred queue).** A finished news item is saved to SQLite before sending to Telegram. If the Telegram API is down, the next timer pass first drains unpublished items from the buffer.
- **Fallback scenarios for media.** In video scripts, if the text-to-speech (TTS) service fails, a silent version of the video with captions is assembled.

## AI SEO and a static-site mirror

For each post, a page is automatically generated on the web mirror ai-release.org (in two languages — RU and EN). But regular SEO isn't enough these days; you need to optimize for AI crawlers (Perplexity, ChatGPT Search, Claude):

- `llms.txt` and `llms-full.txt` — files following the llmstxt.org standard, with the site structure spelled out for RAG systems.
- Markdown versions (`.md`) for all posts — AI bots love reading clean markdown without HTML tags.
- Instant IndexNow — we ping Yandex and Bing on publication.
- An open `robots.txt` for all major AI bots (GPTBot, PerplexityBot, ClaudeBot, Google-Extended).

As a result, referral traffic comes not only from search but also directly from Perplexity and ChatGPT answers.

## Bot security in DMs: fending off prompt injections

The channel is linked to the bot in DMs. Open user input always carries the risk that someone will try to "prompt-inject" the bot, extract the system context, or API keys.

Protection in three layers:

1. **Prompt guardrail.** The model is strictly instructed to ignore any attempts to change its role, "forget previous instructions," or "reveal the system prompt."
2. **Rate limiting.** No more than 20 requests per 10 minutes per user. You can't extract context or spam the API.
3. **Environment isolation.** All API keys live in `.env` with `chmod 600` permissions. The chat process runs in a separate environment and physically has no access to the publisher code or database.

## What we got in the end

- 0 people on staff, 0 minutes of daily manual work.
- A single penny-pinching VPS (1 GB RAM) easily handles the entire infrastructure.
- ~$18.8/month in total costs for the whole pipeline.
- ~450 clean posts and 700+ subscribers in the first month.
- And most importantly, we got the perfect personal news feed that started it all.

## Key takeaways

1. You don't need an expensive GPU server with local models to build smart services. Proper pipeline architecture and external APIs solve 99% of the tasks.
2. Fighting hallucinations and deduplication at the code level gives 10x more quality than blindly switching to a more expensive model.
3. If you want AI systems to cite your content, give them `.md` and add `llms.txt`.

You can follow the feed in the channel [@ai_release1](https://t.me/ai_release1), and read articles and guides on the site [ai-release.org](https://ai-release.org).

💬 **Questions and discussion — in the comments below.**
