skill
AgenticWiki
Personal second-brain Telegram bot — voice/text/link → LLM-maintained wiki on GitHub. Karpathy LLM Wiki pattern + Telegram capture.
Set up
Skills are installed by placing their folder where your agent loads skills.
The download comes from github.com/Enabridge/AgenticWiki itself, not from our server, so what you get is exactly what its author published.
Install instructions come from the README
README
synced Oct 26, 2026AgenticWiki
ขี้เกียจจด → AI ถามเอง → Wiki โตเอง
Personal second-brain Telegram bot. Voice / text / link → committed as raw on GitHub → Claude compiles to a wiki nightly → Telegram brief in the morning.
Implements Karpathy's LLM Wiki pattern with a full autonomous loop: voice-in via Telegram (or LINE) → morning ingest → research sub-loop → Telegram brief. You touch nothing. The wiki grows while you sleep.
Status — v0.1 production
Working: Telegram bot, voice/text/link dump, Gemini 3.1 STT/TTS, GitHub commits,
evening escalation with /eod marker, Cloudflare named tunnel for local dev,
Railway auto-deploy on push.
In progress: Cowork morning Routine (manual one-time setup per user), full wiki layer auto-compile on first real production day.
⚠️ Before you copy this for yourself
This is a personal data system. Your instance will hold your raw voice transcripts, late-night thoughts, TODOs, and unfiltered notes. Adopt with care:
- Don't fork — clone + push to a fresh private repo. GitHub forks stay linked to upstream; you don't want your private dumps relatable to the public template. Use the "Setup Step 1" pattern below.
- Make your repo private. Non-negotiable.
- Rotate every secret. Don't paste tokens in commits, PRs, or issues — even on your own private repo.
- PRs upstream are welcome — but only for code/doc/feature fixes, never with personal data. See CONTRIBUTING.md.
Visual references
Three illustrated posters render the system at a glance — architecture,
daily flow, and setup. Each is brand-locked to Enabridge palette +
Newsreader/Inter typography, generated from
prompts/ via Nano Banana Pro.
Architecture
Components and where each runs
| Component | Runtime | Talks to | Why |
|---|---|---|---|
| Telegram bot | Railway (FastAPI) | Telegram, GitHub, Gemini | Receive messages, transcribe voice, commit raw, Q&A on demand |
| evening-prompt.yml | GitHub Actions | Telegram, GitHub | Ping at 21/22/23 BKK with smart escalation |
| morning Routine | Claude Cowork | GitHub, Web | 06:30 BKK compile + research + brief |
| LINE Cloudflare Worker (optional) | Cloudflare | LINE, GitHub, Gemini | Voice-only LINE ingest path |
3rd-party services and what each is for
| Service | Used for | Cost |
|---|---|---|
| Telegram | Primary user interface | Free |
| Google AI Studio (Gemini) | STT, TTS, Q&A LLM | Free tier 1500 req/day on Flash |
| GitHub | Source of truth — raw/, wiki/, outputs/ | Free for private repos |
| Railway | Bot hosting | Free or $5/mo credit |
| Claude Cowork (Pro/Max) | Scheduled morning Routine | $20/mo Pro or $200 Max |
| Cloudflare (optional) | Named tunnel for local dev | Free |
Setup — 30 minutes total
1. Create your private repo (3 min)
Don't fork. Clone the source, then push to a fresh private repo so there's no upstream link to leak personal commits:
gh repo create your-name/AgenticWiki --private
mkdir AgenticWiki && cd AgenticWiki
curl -L https://github.com/Enabridge/AgenticWiki/archive/refs/heads/main.tar.gz \
| tar xz --strip-components=1
git init -b main
git add .
git commit -m "init: AgenticWiki from upstream"
git remote add origin https://github.com/your-name/AgenticWiki.git
git push -u origin main
2. Create your Telegram bot (5 min)
- In Telegram, search @BotFather →
/newbot - Choose a display name then a username ending in
bot(e.g.yoh_brain_bot) - Copy the token → save as
TELEGRAM_BOT_TOKEN(looks like8706...:AAG...) - Send
/startto your new bot in Telegram (so it's allowed to message you back) - Get your chat ID:
Save ascurl "https://api.telegram.org/bot<TOKEN>/getUpdates" # find the integer in result[0].message.chat.idTELEGRAM_OWNER_CHAT_ID. Only this ID will be allowed to use the bot. - Generate a webhook secret:
Save asopenssl rand -hex 16TELEGRAM_WEBHOOK_SECRET.
3. Get a Gemini API key (1 min)
- https://aistudio.google.com → top-right Get API key → Create API key
- Save as
GEMINI_API_KEY
4. Generate a GitHub PAT (2 min)
- https://github.com/settings/personal-access-tokens/new (logged in as the repo owner)
- Token name:
AgenticWikiBot - Resource owner: your account
- Repository access: Only select repositories → tick
AgenticWiki - Repository permissions:
- Contents: Read and write
- Metadata: Read-only (auto)
- Generate → copy → save as
GITHUB_TOKEN
5. Deploy to Railway (5 min)
- https://railway.com → New Project → Deploy from GitHub repo
- Configure GitHub App for your account → select
AgenticWikionly → Install - Pick the repo → Deploy. Railway auto-detects
Dockerfile+railway.json - Tab Variables → Raw Editor → paste:
That's the 6 required vars. Everything else has sensible defaults inTELEGRAM_BOT_TOKEN=8706... TELEGRAM_OWNER_CHAT_ID=... TELEGRAM_WEBHOOK_SECRET=... GEMINI_API_KEY=AIza... GITHUB_TOKEN=github_pat_... GITHUB_REPO=your-name/AgenticWikiagentic_wiki/config.py(see Reference below). - Wait for build (~2 min) → Settings → Networking → Generate Domain →
copy the
*.up.railway.appURL - Set the Telegram webhook to your Railway domain:
Should returncurl -X POST "https://api.telegram.org/bot<TOKEN>/setWebhook" \ -d "url=https://<railway-domain>/webhook/telegram" \ -d "secret_token=<webhook-secret>" \ -d "drop_pending_updates=true"{"ok":true,"description":"Webhook was set"}. - Send
/startto your bot in Telegram. You should see the DUMP keyboard.
6. Add GHA secrets for evening prompt (1 min)
The 21/22/23 BKK ping fires from GitHub Actions, separate from the bot:
gh secret set TELEGRAM_BOT_TOKEN -b "<token>" --repo your-name/AgenticWiki
gh secret set TELEGRAM_OWNER_CHAT_ID -b "<id>" --repo your-name/AgenticWiki
Test: https://github.com/your-name/AgenticWiki/actions/workflows/evening-prompt.yml → Run workflow. You should get the 3-question ping in Telegram within 10s.
7. Set up the Claude Cowork morning Routine (5 min)
Requires Claude Pro ($20/mo, 5 daily routines) or Max ($200/mo, 15 daily routines). Cowork = Claude's scheduled-task workspace.
- Install Claude's GitHub App on your account first. This is the step
the Claude.ai OAuth flow often skips silently — without it, Cowork's repo
dropdown will be empty no matter how many times you reconnect. Open:
Choose your account → Only select repositories → tickhttps://github.com/apps/claude/installations/newAgenticWiki→ Install. After this, https://github.com/settings/installations should list Claude under Installed GitHub Apps. - https://claude.ai → switch to Cowork → New Routine
- Schedule: Daily 06:30 Asia/Bangkok
- Connectors:
- GitHub (write access to
your-name/AgenticWiki) - Web Search
- GitHub (write access to
- Secrets / env to inject in the Routine:
TELEGRAM_BOT_TOKEN= same valueTELEGRAM_OWNER_CHAT_ID= same value
- Prompt: copy the block below the
---fromroutines/00-morning.md. It's ~6 lines — the actual procedure lives in.claude/skills/morning/SKILL.mdso you can update it via PR without touching the Routine. - Save → Test run → review the first PR on mobile and merge if it looks right.
8. (optional) Local dev with Cloudflare named tunnel
If you want to run the bot locally for development, see
agentic_wiki/README.md. Polling mode is the
zero-config default; the named-tunnel script is for webhook parity with prod.
9. (optional) Add a LINE channel
See SETUP.md — the LINE Cloudflare Worker handles voice ingest
directly without the Python bot. Useful as a backup channel or if you prefer
LINE OA on iOS.
Daily user journey
21:00 BKK 📩 GHA pings Telegram with 3 questions
"วันนี้ทำอะไรไปบ้าง / อะไรหลุดไป / เรื่องไหนน่าสนใจ"
21:00– you reply throughout the night — voice, text, links, forwards
late-night each message → bot → Gemini STT (if voice) → committed to
raw/sessions/{date}/{HHMM}-{type}.md + .ogg for audio
bot replies with the file path so you know it landed
22:00 BKK GHA checks: does raw/sessions/{date}/daily-log-{date}.md exist?
- yes → silent skip
- no → softer ping: "ยังไม่เห็น /eod"
23:00 BKK same check → last-call ping if marker still missing
[when ready] you type: /eod ดีๆเลยวันนี้, นอนล่ะ
bot writes raw/sessions/{date}/daily-log-{date}.md with
a marker, your optional note, and the list of today's items
→ GHA stops escalating tonight
00:00+ no more pings until tomorrow
06:30 BKK 🤖 Claude Cowork Routine fires
reads yesterday's raw + the daily-log marker (your note seeds
the recap) → compiles wiki updates, researches flagged links,
writes outputs/daily/{yesterday}.md, opens PR, sends Telegram brief
plus on Sunday: outputs/weekly/{YYYY-WW}.md
plus on month-end: outputs/monthly/{YYYY-MM}.md
morning 📅 you wake up to a Telegram brief on your phone
review the PR → merge → wiki grows
TODOs + reminders
Every dump message goes through a quick Gemini classifier. If it looks
actionable (action verb + maybe a deadline), the bot ALSO writes a markdown
file under todos/open/ with frontmatter:
---
created: 2026-04-27T18:30:00+07:00
due_at: 2026-04-28T14:00:00+07:00
tag: HMN # HMN | ENB | PERS
status: open
source: raw/sessions/2026-04-27/1830-voice.md
confidence: 0.92
summary: "โอนเงิน Supplier A"
pinged_at: null
---
Tags:
- HMN — Hanuman: factory ops, supplier, machine, packaging, production
- ENB — Enabridge: client, proposal, OpenBridge, AI agent, deck, business
- PERS — personal: family, health, errand, hobby, weekend, friends
The bot reply on a recognized TODO looks like:
📥 voice บันทึก
_ทดสอบบันทึก_
raw/sessions/2026-04-27/1830-voice.md
⚡ TODO [HMN] · _โอนเงิน Supplier A_ · 📅 28 Apr 14:00
todos/open/2026-04-27-1830-supplier-a.md
If confidence < TODO_CONFIDENCE_THRESHOLD (default 0.7), only the raw
dump is committed — no todo file. Adjust the threshold in your env.
Listing + completing
- List: just ask via
/ask— "วันนี้มีอะไรต้องทำอีก" — the Q&A handler pullstodos/open/*into context automatically (grouped by tag). - Done:
/done <fuzzy>finds the best matching open TODO by summary text and moves it totodos/done/. - Voice/text done: speak/type a completion ("supplier A เสร็จแล้ว",
"เพิ่งจ่ายเงิน") and the classifier auto-detects
action_type=done, fuzzy-matches an open TODO, and closes it. No/donecommand needed. - Cancel:
/cancel_todo <fuzzy>same logic, target istodos/cancelled/. History is preserved — you can mine "what I gave up on" later.
Notes by tag (status logs)
Not every dump is a TODO. "เพิ่งจ่าย supplier A 635k เรียบร้อย", "เครื่องเดินพะโล้มีปัญหา", "ลูกค้าใหม่ 5 ราย" — all worth tracking but not actionable.
The classifier outputs action_type as one of:
todo— saves totodos/open/done— auto-closes a matching open TODO; falls back to a note if nonenote— saves tonotes/{HMN|ENB|PERS}/{date}-{HHMM}-{slug}.mdnone— only the raw dump is saved (no extra)
Notes are pulled into /ask context just like TODOs, so questions like
"เดือนนี้ HMN ทำอะไรไปบ้าง" work out of the box.
Links — auto-fetched + summarized
When a dump message is a pure URL, the bot fetches it, asks Gemini to
extract {title, summary, body}, and writes the summary into the raw
markdown alongside the URL. The Telegram reply previews the title +
3–5-sentence Thai summary. This protects against link rot and gives the
morning routine cleaner content to work with.
Reminders
A separate GHA workflow todo-reminder.yml runs every 30 minutes between
08:00–21:30 BKK. It:
- Lists
todos/open/*.mdvia the GitHub API - Filters for
due_atwithin the next 30 minutes ANDpinged_at == null - Sends Telegram:
⏰ อีก N นาที: {summary} [{tag}] - Stamps
pinged_aton the file (no double-ping)
Stateless, no in-bot scheduler needed. Cost: ~28 runs/day on GHA, well within the 2000 min/mo free tier.
Q&A on demand (/ask mode)
Anytime, type /ask to switch to Q&A mode. The bot fetches your current
wiki + recent daily summaries, stuffs them as context, and answers via
Gemini chat. Multi-turn (rolling 5 turns of history). Voice-in works —
ask while driving, get text back + voice reply via Gemini TTS.
/done returns to DUMP mode. Idle 10 min in ASK auto-reverts.
Reference
Environment variables
Required (6):
| Var | Source |
|---|---|
TELEGRAM_BOT_TOKEN | @BotFather |
TELEGRAM_OWNER_CHAT_ID | getUpdates after sending /start |
TELEGRAM_WEBHOOK_SECRET | openssl rand -hex 16 |
GEMINI_API_KEY | aistudio.google.com |
GITHUB_TOKEN | fine-grained PAT, Contents r/w |
GITHUB_REPO | your-name/AgenticWiki |
Optional (have defaults; override in Railway/.env to change):
| Var | Default | Override when |
|---|---|---|
GITHUB_BRANCH | main | working in a feature branch |
GEMINI_CHAT_MODEL | gemini-3.1-flash-lite-preview | want gemini-3.1-pro-preview (smarter, costlier) or gemini-flash-latest (Google-managed alias) |
GEMINI_STT_MODEL | gemini-3.1-flash-lite-preview | rarely; this model handles audio fine |
GEMINI_TTS_MODEL | gemini-3.1-flash-tts-preview | want a different voice tier |
GEMINI_TTS_VOICE | Kore | check Google's voice catalog for alternatives |
TIMEZONE | Asia/Bangkok | live elsewhere |
ASK_IDLE_TIMEOUT_MIN | 10 | want longer ASK sessions |
QA_HISTORY_TURNS | 5 | want longer/shorter conversation memory |
WIKI_CACHE_TTL_SEC | 3600 | how long the bot caches wiki content in memory between /ask calls (1 hour default — wiki only really changes at the 06:30 PR merge; /refresh forces invalidate at any time) |
TODO_CONFIDENCE_THRESHOLD | 0.7 | classifier needs ≥ this to actually create a todo file from a dump |
TODO_DEFAULT_HOUR | 9 | when classifier extracts a date with no time (e.g. "พรุ่งนี้"), default the hour to this |
DUMP_SESSION_TIMEOUT_MIN | 5 | consecutive dump messages within this gap share a session id in frontmatter — morning routine reads them as one continuous thought |
LOG_LEVEL | INFO | want DEBUG |
Local-dev only (don't put in Railway): CF_API_TOKEN, CF_ACCOUNT_ID,
CF_ZONE_ID, TUNNEL_NAME, TUNNEL_HOSTNAME — for scripts/dev_tunnel.sh.
Bot commands
| Command | Mode | Effect |
|---|---|---|
/start | any | show keyboard + intro |
/help | any | show current mode + command list |
/ask [q] | DUMP → ASK | enter Q&A; with q answers immediately |
/done | ASK → DUMP | exit Q&A back to default |
/clear | ASK | reset Q&A context (stay in ASK) |
/eod [note] | DUMP | mark today complete — write daily-log-{date}.md, cancel evening escalation |
/done <fuzzy> | DUMP | fuzzy-match an open TODO, move it to todos/done/ |
/cancel_todo <fuzzy> | DUMP | fuzzy-match an open TODO, move it to todos/cancelled/ |
/refresh | any | invalidate the wiki cache — next /ask re-fetches from GitHub |
Repo structure
AgenticWiki/
├── README.md ← you are here
├── SETUP.md ← optional LINE setup
├── CLAUDE.md ← wiki schema (read by Routine)
├── agentic_wiki/ ← Python bot package
│ ├── README.md ← dev/architecture doc
│ ├── main.py ← FastAPI + webhook
│ ├── config.py ← env settings
│ ├── state.py ← in-memory mode + Q&A history
│ ├── adapters/telegram.py ← aiogram dispatcher
│ ├── handlers/ ← ingest, qa
│ └── integrations/ ← github_client, gemini_client
├── line-webhook/ ← (optional) LINE Cloudflare Worker
├── routines/00-morning.md ← Cowork Routine prompt (paste this)
├── .claude/skills/morning/SKILL.md ← canonical procedure (Routine reads this)
├── .github/workflows/
│ └── evening-prompt.yml ← 21/22/23 BKK ping
├── scripts/
│ ├── dev_polling.py ← local dev: bot in polling mode
│ └── dev_tunnel.sh ← local dev: Cloudflare named tunnel
├── raw/ ← (immutable) voice/text/link dumps
│ └── sessions/{YYYY-MM-DD}/
│ ├── {HHMM}-text.md
│ ├── {HHMM}-voice.md
│ ├── {HHMM}-voice.ogg
│ ├── {HHMM}-link.md
│ └── daily-log-{date}.md ← /eod marker
├── wiki/ ← (LLM-maintained) interlinked pages
├── outputs/ ← (LLM-generated) daily/weekly/monthly
└── followups/ ← research queue
Mode states
[Mode.DUMP] (default for any user_id)
│
│ /ask [q]
▼
[Mode.ASK] ────── multi-turn Q&A, rolling 5-turn history
│ voice replies via TTS
│
│ /done OR idle 10 min
▼
[Mode.DUMP]
State is in-memory (single Railway replica). Restart resets all sessions —
accepted for v0.1; /eod markers persist on GitHub.
How /ask reads the wiki — data flow
The bot is stateless with respect to wiki content. Nothing is preloaded
on Railway. Each /ask call:
- Fetches
wiki/*.md,outputs/daily/{recent}.md,todos/open/*,notes/*from GitHub via the Contents API - Caches the result in-memory for
WIKI_CACHE_TTL_SEC(default 5 min) - Stuffs everything as context into a single Gemini call
- Returns the answer; rolls a 5-turn history per chat
Cache is per-process, lost on Railway restart — that's fine because GitHub is the source of truth. The bot never holds the canonical copy.
The 06:30 Cowork morning routine runs in Anthropic's cloud, not Railway. It uses Claude's GitHub connector (separate from the bot's PAT) to read the same repo fresh, write a PR back. Bot and Cowork don't talk to each other directly — they coordinate through GitHub commits.
GitHub repo ── single source of truth
│
├─ Bot (Railway) : pulls /ask context (5-min cache), pushes raw + todos
└─ Cowork (cloud) : pulls all (fresh each run), opens morning PR
Cost estimate
Free tier is plenty for personal use if you stay inside it. Concrete math at moderate use (50 voice + 20 text dumps + 10 ASK + 10 TTS replies/day):
| Flow | Tokens/day | Paid-tier cost/day |
|---|---|---|
| STT (50 × 30s voice = 37.5K audio in) | 37,500 in | $0.019 |
| Classifier on 70 dumps | 14K in / 3.5K out | $0.009 |
| ASK input (10 × 50K wiki context) | 500K in | $0.125 |
| ASK output | 5K out | $0.008 |
| TTS audio out (10 × 30s) | 7,500 out | $0.150 |
| URL fetch + summarize (5/day) | 150K in | $0.038 |
| Total | ~$0.35/day = ~$10.50/month |
Free vs paid:
- Free tier project key → $0 if you stay under quota; preview models hit
rate limits you'll feel as
⏳ Gemini quota...Telegram replies - Paid tier → ~$10/mo for the above use, no rate-limit anxiety
Force free-tier-only by creating the API key in a Google Cloud Project that
doesn't have billing enabled. AI Studio → API keys → choose project →
key is bound to that project's billing state. Update GEMINI_API_KEY in
Railway + .env to switch.
Other costs:
- Railway free credit ($5/mo) → 0
- GitHub private repo → 0
- Claude Pro/Max → $20 / $200 (one routine/day = 1/5 or 1/15 quota)
- Cloudflare named tunnel → 0
Optimization (if you go paid)
- Context cache for ASK — wiki is stable within a day; cache once, reuse → ASK input cost drops 10× ($0.025/M instead of $0.25/M)
- Disable TTS — set
GEMINI_TTS_MODEL=empty if you don't want voice replies; saves the largest single line item - Batch tier for classifier — 50% cheaper but adds 1–2 min latency,
trade-off depending on whether you want immediate
⚡ TODOreply
Customization
Different LLM for Q&A
Set in Railway:
GEMINI_CHAT_MODEL=gemini-3.1-pro-preview # smarter, costlier
# or
GEMINI_CHAT_MODEL=gemini-3-flash-preview # full Gen 3 Flash (vs lite-preview)
Different schedule
- Evening prompt: edit
.github/workflows/evening-prompt.ymlcron lines - Morning routine: edit the schedule in Cowork directly
- Q&A idle timeout:
ASK_IDLE_TIMEOUT_MIN=20in Railway
Different language for prompts/replies
- Bot replies: edit strings in
agentic_wiki/adapters/telegram.pyandagentic_wiki/handlers/ - Morning compile output language: edit
.claude/skills/morning/SKILL.md - Evening prompt text:
.github/workflows/evening-prompt.yml
Disable voice replies (TTS)
Don't set GEMINI_TTS_MODEL or set it to empty in Railway. Voice replies in
ASK mode will silently skip; text-only replies still work.
Add a new skill the Routine can use
Drop .claude/skills/{name}/SKILL.md. Reference it from the Routine prompt
or call from morning/SKILL.md.
Troubleshooting
Telegram says Failed to resolve host when setting webhook
- Telegram blacklists
*.trycloudflare.com. Use a named Cloudflare tunnel (free with any zone) or just deploy to Railway.
Bot returns 500 on every webhook
- Check Railway Deploy Logs for
event: bot.start_failed. UsuallyTELEGRAM_BOT_TOKENgot pasted with quotes / extra chars.
webhook.bot_not_initialized in logs
- The bot started but couldn't init the Telegram client. Same root cause as above — fix the token env.
Push refused: "Personal Access Token cannot update workflow"
- Fine-grained PATs default without Actions:write. Either add Actions r/w to
the PAT, or push workflow files using
ghCLI (which hasworkflowscope via OAuth) instead of the PAT.
Railway healthcheck fails on first deploy
- Container probably bound to wrong port. Make sure your Dockerfile CMD
expands
${PORT}(the repo'sDockerfiledoes this —sh -c "..."shell form is required for variable expansion).
Cowork "Connect GitHub" works but the repo dropdown is empty
- The Claude.ai OAuth flow authorizes Claude on your GitHub account but
often skips installing the GitHub App, which is what actually grants
repo access. Symptom:
github.com/settings/installationsshows no Claude entry; onlyAuthorized GitHub Appsdoes. - Fix: open https://github.com/apps/claude/installations/new directly, pick your account, select the AgenticWiki repo, install. The repo will then appear in Cowork.
Repo not visible in Cowork after transferring it between accounts
- Same root cause as above — the App installation is per-account and doesn't follow a transferred repo. Re-install on the new owner account via the URL above.
Related repos / inspiration
- Karpathy's LLM Wiki gist — the three-layer pattern (raw / wiki / outputs)
- Anthropic's Claude Cowork docs — Routines + Skills