Filaxy Herald
June 24, 2026 · View on GitHub
Filaxy Herald
Your GitHub work → posts on X, automatically.
Filaxy Herald watches your public repos. When you ship something, an AI writes a real
build-in-public post about it, makes a branded image, and sends it to your Telegram.
You tap ✅ — and it's live on X. You also get an /announce command for private projects.
No "I pushed 3 commits" spam. Real posts. You approve every one. It runs itself.

Self-hosted · Runs free on Vercel · MIT
See it in action
When you ship code, you get a message like this on Telegram. One tap and it's live — no dashboards, no copy-paste:

↓ It really posts. See a real post it published on X →
Table of contents
- What it does
- How it works (architecture)
- Prerequisites
- Setup — step by step
- Configuration
- Usage
- Safety: it never posts secrets
- What it costs
- Troubleshooting
- License
What it does
There are two ways posts get created:
A — Automatic (your public repos). Once a day, Herald reads your public GitHub
activity. If you shipped something worth sharing (a release, a new repo, or real
commits to main), it drafts a post and sends it to you on Telegram for approval.
It posts one suggestion per repo, so you approve or discard each independently.
B — Manual (/announce, for anything — even private projects). Send the bot a
message like /announce my-app: shipped a live dashboard with real-time charts. It
writes a polished post from your description (never from your code, so nothing private
leaks). Attach a screenshot and it uses your real image instead of the generated card.
Every post goes through a safety filter (no API keys, secrets, or security bugs) and you approve it on Telegram before it ever reaches X.
How it works (architecture)
You ship code ─▶ GitHub
│ (public activity feed — read once a day, no private repos)
▼
┌──────────────┐ "write the post" ┌──────────┐
│ The Engine │ ──────────────────────▶ │ Claude │
│ (Vercel) │ ◀────────────────────── │ AI │
└──────┬───────┘ the draft └──────────┘
│
│ ① safety check (block secrets / bugs)
│ ② render a branded "ship card" image
│ ③ store the draft ┌──────────┐
│ ─────────────────────────▶│ Upstash │ (memory)
▼ └──────────┘
Telegram ──(you tap ✅ Approve)──▶ X / Twitter ──▶ your audience grows
- The Engine is a few serverless functions on Vercel. A daily cron triggers the digest; a webhook receives your Telegram button taps.
- It reads your activity from GitHub's public events feed — no GitHub App, no webhook on GitHub's side, and private repos physically can't appear there.
- Claude writes the copy. Upstash Redis holds the pending draft between "drafted" and "approved". Telegram is your approval inbox. X is the destination.
| File | What it is |
|---|---|
api/digest.ts | Daily cron: read activity → write → image → send to Telegram |
api/telegram-webhook.ts | Handles your ✅/❌ taps and the /announce command → posts to X |
api/announce.ts | Builds a post from your /announce description |
lib/github.ts | Reads & filters your public activity |
lib/compose.ts | Prompts Claude to write the post |
lib/safety.ts | The content guardrail (regex + AI review) |
lib/card-og.ts | Renders the branded image |
lib/redis.ts · lib/telegram.ts | Memory + Telegram helpers |
Prerequisites
You'll need free accounts on these (all have free tiers; two need a few dollars of prepaid credit):
| Service | Why | Cost |
|---|---|---|
| GitHub | the activity it reads | free |
| Telegram | your approval inbox | free |
| Anthropic | Claude writes the posts | ~$5 prepaid lasts months |
| X / Twitter Developer | publishing | pay-per-use, ~$0.02/post |
| Upstash | Redis memory | free tier |
| Vercel | hosting | free (Hobby) |
Also install Node.js 18+ and the
Vercel CLI: npm i -g vercel.
Then clone and install:
git clone https://github.com/othmarodev/filaxy-herald.git
cd filaxy-herald
npm install
cp .env.example .env.local
You'll fill .env.local as you go through the steps below. It's git-ignored — your
keys never get committed.
Setup — step by step
1. Telegram bot (2 min)
This is where you'll approve posts.
- Open Telegram, search for @BotFather (the one with the blue checkmark).
- Send
/newbot. Give it a name, then a username ending inbot(e.g.my_herald_bot). - BotFather replies with a token like
8123456789:AAH.... →TELEGRAM_BOT_TOKEN. - Now get your chat ID: search @userinfobot, press Start. It replies with your
Id(a number). →TELEGRAM_CHAT_ID. - Open your own bot (
t.me/your_bot_username) and press Start once. (A bot can't message you until you've messaged it first — skip this and you'll get "chat not found".)
Test it:
npx tsx scripts/test-telegram.ts # should send you a message
2. Anthropic (Claude) API key (5 min)
This writes your posts.
- Go to console.anthropic.com, sign in.
- API Keys → Create Key → name it
filaxy-herald. Copy thesk-ant-...value (shown once). →ANTHROPIC_API_KEY. - Plans & Billing → Buy credits → add ~$5. (The free "evaluation" plan has no usable credits — the key won't work until you add a little balance.)
npx tsx scripts/test-compose.ts # generates a real sample post
3. X / Twitter developer app (15 min)
The fiddly one. Read carefully — there's one step that trips everyone.
- Go to developer.x.com, sign in with the account you'll post from. Accept the Free developer plan.
- You'll get a Project + an App. Open the App.
- 🚨 Before generating any tokens: open User authentication settings → Set up:
- App permissions → Read and Write. (If you leave it on "Read", your tokens will be read-only and posting fails. This is THE gotcha.)
- Type of App → Web App / Automated App or Bot.
- Callback URI →
https://example.com/callback(placeholder is fine). - Website URL → your site (anything valid).
- Save.
- Now go to Keys and tokens and grab four values:
- API Key + API Key Secret →
X_API_KEY,X_API_SECRET - Access Token + Access Token Secret (Generate) →
X_ACCESS_TOKEN,X_ACCESS_SECRET. Confirm it says Read and Write under the token. If it says "Read", fix step 3 and regenerate.
- API Key + API Key Secret →
- The new X API is pay-per-use. Add a few dollars of credits in the developer console so it can publish.
npx tsx scripts/test-x-auth.ts # verifies the 4 keys (without posting)
4. Upstash Redis (3 min)
The bot's short-term memory (holds a draft between "written" and "approved").
- Go to console.upstash.com, create a Redis database (free tier, pick a region).
- In the database page, find the REST API section. Copy:
UPSTASH_REDIS_REST_URLUPSTASH_REDIS_REST_TOKEN
5. Deploy to Vercel (5 min)
vercel login
vercel link --yes # creates the project
Add your environment variables to the Vercel project (Production). Either paste them in the Vercel dashboard (Project → Settings → Environment Variables) or via CLI:
# for each variable: pipe the value from .env.local so it's never printed
grep '^TELEGRAM_BOT_TOKEN=' .env.local | cut -d= -f2- | vercel env add TELEGRAM_BOT_TOKEN production
# ...repeat for every var in .env.example...
Two extra variables to add:
# stops Vercel from downloading a browser it doesn't need in the cloud
printf '1' | vercel env add PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD production
# protects your cron endpoint (Vercel sends this automatically to the cron)
printf '%s' "$(openssl rand -hex 16)" | vercel env add CRON_SECRET production
# lets the webhook call the announce endpoint internally
printf '%s' "$(openssl rand -hex 16)" | vercel env add INTERNAL_SECRET production
Deploy:
vercel --prod
The daily cron is configured in vercel.json (0 15 * * * = 09:00 in UTC-6 / Costa Rica
— change it to your timezone).
6. Connect the Telegram webhook (1 min)
So your button taps reach the cloud. Edit the URL in scripts/set-webhook.ts to your
deployed domain, then:
npx tsx scripts/set-webhook.ts
Done. 🎉
Configuration
All in .env.local (and mirrored in your Vercel project). See .env.example.
| Variable | What it is |
|---|---|
TELEGRAM_BOT_TOKEN / TELEGRAM_CHAT_ID | your approval bot + your chat |
ANTHROPIC_API_KEY | Claude (writes posts + runs the AI safety check) |
X_API_KEY / X_API_SECRET / X_ACCESS_TOKEN / X_ACCESS_SECRET | X OAuth 1.0a (Read+Write) |
UPSTASH_REDIS_REST_URL / UPSTASH_REDIS_REST_TOKEN | memory |
GITHUB_USER | the GitHub username to watch |
ALLOWLIST | comma-separated owner/repo. Leave empty = all your public repos (skips your profile repo and forks). |
CRON_SECRET / INTERNAL_SECRET | endpoint protection (random strings) |
Usage
- Automatic: just ship code to your public repos. Each day at your cron time, Herald DMs you a draft per repo that had activity. Tap ✅ to post, ❌ to skip.
- Manual: message your bot
/announce <project>: <what you shipped>. Works for any project, public or private. Attach a photo to use a real screenshot instead of the generated card. Write in any language — the post comes out in English.
Safety: it never posts secrets
Every post — automatic or manual — runs through lib/safety.ts before it can reach
approval:
- Regex backstop — instantly blocks anything matching an API key, token, private key, Stripe/AWS/GitHub secret, or a security-bug disclosure.
- AI reviewer — Claude flags anything sensitive the regex might miss (secrets, vulnerabilities, private data, brand-damaging content). Fails closed (blocks on doubt).
And of course: it only ever reads your public GitHub feed, and /announce posts from
your description, never your code. Private repos can't leak.
npx tsx scripts/test-safety.ts # see the guardrail block fake secrets
What it costs
| Item | Per post |
|---|---|
| X (publish) | ~$0.02 |
| Claude (writing + safety check) | < $0.01 |
| Branded image / screenshot | $0 |
| Hosting (Vercel Hobby) | $0 |
| Total | ~2–3 cents |
One post a day ≈ under $1/month. A $5 X balance ≈ 250 posts. Set a spending limit in the X console for peace of mind.
Troubleshooting
| Symptom | Fix |
|---|---|
| Telegram: "chat not found" | Open your bot and press Start once (step 1.5). |
| Anthropic: "credit balance too low" | Add ~$5 in Plans & Billing — the free plan has no credits. |
| X: tokens are read-only / posting 403 | Set Read and Write in User auth settings, then regenerate the access token. |
| X: "CreditsDepleted" | Add credits in the X developer console (pay-per-use). |
| Webhook returns 500 / ERR_MODULE_NOT_FOUND | Vercel Node functions need self-contained imports — keep api/telegram-webhook.ts dependency-light (it is, by design). |
| Cron runs but nothing posts | That's correct if you had no post-worthy public activity that day — it never invents posts. |
The /announce post links the wrong place | Private projects link to your GitHub profile by design (never the private repo). |
License
MIT © Othmaro Fallas Rojas — @Othmaro_dev · github.com/othmarodev
Built in public. This bot announces its own updates. 🤖