Skip to main content
I Built a TIL Pipeline with OpenClaw + Telegram

February 21, 2026β€’3 min read

I wanted a dead-simple workflow: write a messy β€œTIL”, and have it show up on my website.

No admin panel. No extra CMS. Just one message and magic πŸͺ„.

Why I changed my workflow

I used to keep TILs in a local file on my laptop.
It worked, but the UX was basically filesystem + editor for writing, and no great visualizer for consuming it later.

That created friction: if I learned something while away from my laptop, I either forgot it or postponed writing it.
Moving capture to Telegram + OpenClaw fixed that. Now I can log ideas anywhere, then let the pipeline curate and publish.

The idea

I’m using OpenClaw with Telegram integration as the capture layer.

Then I added a curation flow:

  1. I send a raw TIL: ... note in Telegram
  2. OpenClaw curates it into a proper entry file
  3. It updates an entries/index.json
  4. It creates a branch, commits, pushes, and opens a PR
  5. After merge, the content is displayed in a website til.yusefhabib.com

That’s it. Capture fast, clean up automatically, review in GitHub.

Hosting the TIL app on a VPS

I run the TIL app on a subdomain and front it with Caddy.

server setup
sudo apt update
sudo apt install caddy -y
sudo systemctl enable --now caddy
/etc/caddy/Caddyfile
til.yourdomain.com {
    root * /var/www/til.yourdomain.com
    encode gzip zstd
    file_server
}

Then DNS:

  • Type: A
  • Host: til
  • Value: <your-vps-ip>

Quick propagation check:

dns check
dig +short til.<yourdomain>.com

If it returns your VPS IP, you’re good.

Small deployment detail: symlinks > copy

At first I copied files into /var/www/.... It worked, but every content change required another copy.

So I switched to symlinks:

link live files to source
ln -s /srv/til/docs/index.html /var/www/til.<yourdomain>.com/index.html
ln -s /srv/til/docs/app.js /var/www/til.<yourdomain>.com/app.js
ln -s /srv/til/docs/style.css /var/www/til.<yourdomain>.com/style.css
ln -s /srv/til/entries /var/www/til.<yourdomain>.com/entries

Now source changes are reflected immediately on the live app.

The Telegram β†’ PR workflow

I keep one convention: prefix raw notes with TIL:.

telegram input
TIL: dig +short <domain> to verify DNS changes and confirm A record is correct

OpenClaw turns that into:

  • entries/YYYY-MM-DDTHHMM_slug.md
  • a new item in entries/index.json (newest first)
  • a branch + commit + PR

Always branch + PR. No direct pushes to main.

How the TIL repository is structured

The repo is intentionally simple:

til/
β”œβ”€β”€ entries/
β”‚   β”œβ”€β”€ index.json
β”‚   └── YYYY-MM-DDTHHMM_slug.md
└── docs/
    β”œβ”€β”€ index.html
    β”œβ”€β”€ entry.html
    β”œβ”€β”€ app.js
    └── style.css

Here’s the split of responsibilities:

  • entries/*.md: one markdown file per learning
  • entries/index.json: metadata used by the UI (title, date, tags, file)
  • docs/: static frontend that reads index.json and renders list/detail pages

This separation keeps authoring and presentation decoupled: I write markdown entries, and the UI automatically picks them up from metadata.

Why this setup is better

It removes friction at capture time.

When I learn something, I dump it quickly in Telegram and keep moving. OpenClaw handles formatting, metadata, and git workflow. I only review/merge.

Fast input, clean output, full history, and content flowing into til.yusefhabib.com.

If you want to replicate it

Start with these rules:

  • OpenClaw + Telegram for capture
  • static TIL app on til.<yourdomain>.com
  • markdown entries + index.json
  • TIL: prefix for ingestion
  • branch + PR only

Minimal moving parts, high leverage.

Bonus

My website pulls the latest 5 TILs directly from the repo for my Latest Activity section.


Do you like this setup? Share your thoughts with me @yhabibf