尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證正在載入完整 README。 以下為已儲存的摘錄。
A Telegram agent that keeps a student's job applications up to date from their Gmail. It reads job emails (confirmations, online assessments, interviews, rejections, offers) and proposes each status change in Telegram, quoting the exact sentence that justifies it. Nothing changes until you tap Approve.
• Telegram bot: @jobapplicationtracker1907bot
• Web app (dashboard): https://home-assignment-henna.vercel.app
• How and why it's built this way: DECISIONS.md
For reviewers: how action approval works for testers · how it's deployed, and the environment variables to redeploy it檢視完整 README ↗A Telegram agent that keeps a student's job applications up to date from their Gmail. It reads job emails (confirmations, online assessments, interviews, rejections, offers) and proposes each status change in Telegram, quoting the exact sentence that justifies it. Nothing changes until you tap Approve.
For reviewers: how action approval works for testers · how it's deployed, and the environment variables to redeploy it
Disclosure: The demo does not keep at with the platform's feature, and does not mimic the cron job working every 5 minutes to scan your mail. It only displays how an alert would look like, and let you explore the dashboard.
Who approves: you, for your own tracker. Where: in your private Telegram chat with the bot, by tapping ✅ Approve on the card.
The action: creating or updating an application in your tracker (a new application, a status change, a job ID saved).
Who approves: only the Telegram account that owns the tracker, by tapping Approve on that specific card in its private chat with the bot. As a tester, that's you, for your own tracker. One card is one change; there is no "approve all".
What's refused:
Group chats are ignored.
What can't approve: the agent never changes your tracker by itself, and other agents (MCP) can only read. On the web app you can correct a status by hand when an email was missed. That's your own change, recorded as such.
list_applications lists your tracker; generate_prep_brief writes a grounded brief for an interview or assessment. Both are read-only.The deployment:
pg_cron calls the sync every 5 minutes, because Vercel's free plan runs scheduled jobs only once a day.To redeploy your own copy:
Supabase: create a project, set DATABASE_URL and DIRECT_URL (below), and run npm install && npm run db:deploy to create the tables.
Google Cloud:
gmail.readonly, home page <APP_URL>, privacy page <APP_URL>/privacy) and publish it. In "Testing", Gmail access expires after 7 days.<APP_URL>/api/gmail/callback.Gemini: create an API key in a billed project. On the paid tier, email content isn't used for training.
Telegram: create a bot with BotFather.
Vercel:
APP_URL=https://<your-app> npm run bot:setup -- --webhook. This sets the command menu and the webhook.The 5-minute sync: in Supabase, enable the pg_cron and pg_net extensions, then run this in the SQL editor with your values. The secret is kept in Supabase Vault.
select vault.create_secret('<CRON_SECRET>', 'job_hunt_cron_secret');
select vault.create_secret('https://<your-app>/api/cron/sync', 'job_hunt_cron_url');
select cron.schedule('job-hunt-sync', '*/5 * * * *', $$
select net.http_post(
url := (select decrypted_secret from vault.decrypted_secrets where name = 'job_hunt_cron_url'),
headers := jsonb_build_object(
'Authorization', 'Bearer ' || (select decrypted_secret from vault.decrypted_secrets where name = 'job_hunt_cron_secret'),
'Content-Type', 'application/json'),
body := '{}'::jsonb,
timeout_milliseconds := 60000);
$$);
Check: https://<your-app>/api/health returns {"ok":true,...}; send /start to your bot.
No keys or tokens are committed to this repository. Set them in Vercel's project settings; for local use, copy .env.example to .env.local, which git ignores.
| Variable | What it is |
|---|---|
DATABASE_URL | Supabase transaction pooler URL (port 6543), used by the app |
DIRECT_URL | Supabase session pooler URL (port 5432), used by migrations |
TELEGRAM_BOT_TOKEN | The bot's token, from BotFather |
TELEGRAM_BOT_USERNAME | The bot's username, without @ |
TELEGRAM_WEBHOOK_SECRET | Any random string (letters, digits, _, -); Telegram sends it with every update and the webhook refuses requests without it |
ADMIN_TELEGRAM_USER_ID | Your numeric Telegram id: shared-budget notices and the admin view in Settings |
APP_URL | The app's public address, e.g. https://your-app.vercel.app |
TOKEN_ENCRYPTION_KEY | 32 random bytes, base64 (openssl rand -base64 32); encrypts Gmail access tokens |
SESSION_SECRET | Random string (openssl rand -base64 32); signs sign-in links and sessions |
CRON_SECRET | Random string; the sync endpoint accepts only calls that carry it |
GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET | The OAuth client from Google Cloud |
GEMINI_API_KEY | Gemini API key |
LLM_MONTHLY_BUDGET_USD, LLM_USER_MONTHLY_BUDGET_USD | Optional: the shared and per-person monthly AI caps (default 25 and 5) |
GEMINI_MODEL, GEMINI_FALLBACK_MODEL | Optional: the model (default gemini-3.5-flash-lite) and the lighter one used near a cap (default gemini-3.1-flash-lite, none to turn off) |
npm test runs the unit tests. npm run evals runs the evals that make no model calls, and npm run evals -- --all runs all ten, including the five that call the model (about $0.05). What each eval proves is in DECISIONS.md §11.