关于 jobsearch-telegram
jobsearch-telegram 是 Proficiently 技能,可轮询 Telegram 消息并将求职请求路由至相关技能。它通过无界面轮询工作流处理申请确认、职位搜索、简历定制和状态查询。
主要功能
- 01定期轮询 Telegram
- 02路由职位链接与申请请求
- 03搜索职位并定制简历
- 04跟踪待确认事项与申请状态
- 05记录收到的普通文本
适用场景
- 01发送职位链接以启动申请
- 02通过 Telegram 消息搜索职位
- 03查看申请状态和待处理确认
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ proficientlyjobs/ proficiently-claude-skills --skill jobsearch-telegram安装后在 Claude Code 中输入/jobsearch-telegram确认已加载。
详细介绍
Job Search Telegram 轮询
轮询 Telegram 以获取新消息,并将其路由到相应的 Proficiently 技能。通过 /loop 1m /proficiently:jobsearch-telegram 在后台运行。
首次设置
此技能运行前,用户必须创建并配置 Telegram 机器人。如果 DATA_DIR/telegram-config.md 不存在,请引导用户完成设置:
1. 创建 Telegram 机器人
告诉用户:
我们来设置你的 Telegram 机器人。
- 打开 Telegram 并搜索 @BotFather
- 发送
/newbot- 选择一个名称(例如,“我的求职助手”)
- 选择一个用户名(必须以
bot结尾,例如,my_jobsearch_bot)- BotFather 会提供一个机器人令牌——复制并粘贴到这里
然后给你的机器人发送一条消息(内容不限),这样我就能找到你的聊天 ID。
2. 获取聊天 ID
用户提供机器人令牌后,获取其聊天 ID:
curl -s "https://api.telegram.org/bot{TOKEN}/getUpdates"
从第一个结果中提取 message.chat.id。如果没有结果,提醒用户先给机器人发送一条消息,然后重试。
3. 保存配置
写入 DATA_DIR/telegram-config.md:
# Telegram Config
- Bot token: {TOKEN}
- Chat ID: {CHAT_ID}
- Bot username: @{USERNAME}
4. 验证
发送一条测试消息:
curl -s -X POST "https://api.telegram.org/bot{TOKEN}/sendMessage" \
-H "Content-Type: application/json" \
-d '{"chat_id": "{CHAT_ID}", "text": "👋 Job search bot connected! Send me a job URL to apply, or say \"search\" to find jobs."}'
如果成功,告诉用户设置已完成,可以使用 /loop 1m /proficiently:jobsearch-telegram 启动循环。
配置和状态文件
使用 shared/references/data-directory.md 确定数据目录。
配置——DATA_DIR/telegram-config.md(在设置期间创建,包含机器人令牌和聊天 ID)。**切勿将此文件提交到 git。**每个轮询周期都要先读取此文件以获取凭据。
状态——DATA_DIR/telegram-state.md(跟踪轮询位置)。如果文件不存在,则创建:
# Telegram State
## Polling
- last_update_id: 0
## Pending Confirmations
(none)
## Recent Actions
工作流
步骤 1:加载上下文
- 读取
DATA_DIR/telegram-config.md——如果文件不存在,运行上述首次设置,然后停止 - 读取
DATA_DIR/telegram-state.md——如果文件不存在,则根据上述模板创建 - 如果以下文件存在,则读取:
DATA_DIR/job-history.md、DATA_DIR/application-data.md、DATA_DIR/preferences.md
步骤 2:轮询消息
curl -s "https://api.telegram.org/bot{TOKEN}/getUpdates?offset={LAST_UPDATE_ID+1}&timeout=5"
如果没有新消息 → 静默退出。不要记录日志,也不要发送任何内容。
步骤 3:对每条消息分类
解析每条消息并进行分类:
| 消息类型 | 检测方式 | 路由 |
|---|---|---|
| 职位 URL | 包含 greenhouse.io、lever.co、myworkdayjobs.com、ashbyhq.com 或其他职位招聘网站 URL | 步骤 4a:申请 |
| “apply last” / “apply” | 文本与 apply 匹配(可选包含 last/current) | 步骤 4a:申请 |
| “search for ...” | 文本以 search、find、look for 开头 | 步骤 4b:搜索 |
| “tailor resume for ...” | 文本提到 tailor/resume + 上下文 | 步骤 4c:定制简历 |
| “status” / “what's open” | 文本询问申请状态 | 步骤 4d:状态 |
| “help” | 文本恰好为 help 或 ? | 步骤 4e:帮助 |
| 确认回复 | 对待处理确认消息的线程回复,或存在待处理确认时单独发送的确认词(yes/y/go/no/cancel) | 步骤 5:确认 |
| 纯文本 | 其他任何内容 | 步骤 6:记录 |
步骤 4a:处理职位 URL / 申请请求
-
提取 URL,或解析“last”/“current”
-
检查
DATA_DIR/jobs/中是否已存在与此 URL 对应的职位文件夹 -
向 Telegram 发送确认消息:
🎯 Got it — applying to [URL or "most recent job"]. I'll scan the form, tailor your resume, and propose answers. Stand by... -
执行
skills/apply/SKILL.md中的申请工作流:- 遵循步骤 0-6(前提条件 → 导航 → 勘察 → 生成材料 → 扫描字段 → 提出答案)
- 不使用 AskUserQuestion 请求批准,而是将步骤 6 的提案摘要发送到 Telegram,并将其添加到待确认事项
- 在待确认事项中存储:
job_url、form_url(导航到的 ATS 表单直达 URL)和field_mapping(完整的已批准字段→值 JSON) - 等待用户通过 Telegram 确认(将在未来的轮询周期中作为回复到达)
-
收到字段批准确认(步骤 5)后,重新导航到
form_url,填写所有字段,然后发送第二次确认(提交批准),附上截图说明并询问:"Everything looks good — submit?"- 将其作为新的待确认事项存储,并设置
stage: "submit-approval"
- 将其作为新的待确认事项存储,并设置
-
收到提交批准后,点击 Submit,然后记录申请(申请技能的步骤 9)。
**发送提案:**使用发送消息辅助程序(步骤 8),附上完整字段摘要。长度保持在 4000 个字符以内。如果更长,则拆分为:(1)自动填写的字段;(2)建议答案;(3)需要用户提供的信息。
两阶段确认流程:
- 阶段 1(
stage: field-approval):用户批准字段→值映射 - 阶段 2(
stage: submit-approval):用户在点击 Submit 前批准最终表单 - 绝不可跳过阶段 2——提交职位申请是不可逆操作
步骤 4b:处理搜索请求
- 从消息中提取搜索关键词
- 发送确认消息:
🔍 Searching for: [keywords]... - 执行
skills/job-search/SKILL.md中的职位搜索工作流 - 将结果摘要发送到 Telegram:
🔍 Found X matches for "[keywords]": 1. [Role] at [Company] — [fit score] [URL] 2. ... Reply with a number to apply, or "apply 1" / "apply 3" etc. - 将职位列表添加到待确认事项,以便将回复与对应职位匹配
步骤 4c:处理定制请求
- 提取职位引用(URL、“last”或职位名称)
- 发送确认消息:
📝 Tailoring resume for [job]... - 执行
skills/tailor-resume/SKILL.md中的简历定制工作流 - 将结果和所做的关键修改发送到 Telegram
- 记录定制后简历的保存路径
步骤 4d:处理状态查询
从 DATA_DIR/job-history.md 和 DATA_DIR/jobs/*/applied.md 汇总:
📋 Job Search Status
Applied (X):
- [Role] at [Company] — [date] — [status]
- ...
Saved but not applied (Y):
- [Role] at [Company] — [date saved]
- ...
Pending your confirmation:
- [any pending apply proposals]
步骤 4e:处理帮助请求
发送:
👋 Here's what you can do:
<b>Apply</b>
• Send a job URL → I'll apply for you
• "apply last" → continue with the most recent job
<b>Search</b>
• "search [keywords]" → find matching jobs
• "find AI product jobs" → same thing
<b>Resume</b>
• "tailor resume for [job URL or name]"
<b>Status</b>
• "status" → see all applications and what's pending
<b>Other</b>
• "help" → this message
• Any other text is saved as a note
步骤 5:处理确认回复
确认回复可以是:
- 线程回复(Telegram 的原生回复功能):通过
reply_to_message.message_id匹配待确认事项 - 存在待确认事项时,发送仅包含确认/拒绝词(
yes、y、go、send it、👍、no、skip、cancel、❌)的独立消息
独立消息的消歧:
- 如果恰好有一项待确认事项 → 将其应用于该事项
- 如果有多项待确认事项 → 以编号列表列出待确认事项,并询问用户指的是哪一项:
You have X things waiting. Which one? 1. [description of pending 1] 2. [description of pending 2] Reply with a number.
处理流程:
- 在
telegram-state.md中查找待确认事项 - 解析用户回复:
"yes"/"y"/"go"/"send it"/ 👍 → 批准"no"/"skip"/"cancel"/ ❌ → 拒绝"yes but [changes]"→ 批准并应用修改- 数字(例如
"2")→ 从列表中选择对应选项
- 执行已批准的操作:
stage: field-approval→ 重新导航到form_url,使用field_mapping填写字段,然后发送提交批准提示stage: submit-approval→ 点击 Submit,记录申请- 选择搜索结果 → 对选定职位启动申请工作流
- 发送已执行操作的确认消息
- 从待确认事项中移除,并添加到最近操作
步骤 6:处理纯文本备注
- 使用时间戳将内容记录到
DATA_DIR/telegram-inbox.md - 如果内容看起来像公司名称或职位名称,则建议:
"Want me to search for [text] jobs?" - 否则确认:
"Noted 👍"
步骤 7:更新状态
处理完所有消息后:
- 更新
DATA_DIR/telegram-state.md中的last_update_id - 更新待确认事项(添加新事项,移除已解决事项)。对于每个申请确认事项,包含:
[msg_id: X] apply/field-approval — [Role] at [Company] — waiting since DATE job_url: https://... form_url: https://... field_mapping: {"First Name": "...", "Email": "...", ...} - 更新近期操作(保留最近 20 条,最新的排在最前)
步骤 8:发送消息
从 DATA_DIR/telegram-config.md 读取凭据,然后通过 curl 发送:
curl -s -X POST "https://api.telegram.org/bot{TOKEN}/sendMessage" \
-H "Content-Type: application/json" \
-d '{"chat_id": "CHAT_ID", "text": "MESSAGE", "parse_mode": "HTML"}'
回复特定消息时,添加 "reply_to_message_id": MSG_ID。
格式规则:
- 使用 HTML:
<b>粗体</b>、<i>斜体</i>、<code>代码</code> - 消息长度控制在 4000 个字符以内(Telegram 限制为 4096 个字符)
- 表达简洁——用户在手机上阅读
- 使用换行提高可读性,避免大段文字
要获取已发送消息的 message_id(用于跟踪确认事项):
# Parse from response JSON
jq -r '.result.message_id'
关键规则
- **无头运行。**绝不使用 AskUserQuestion。所有交互都通过 Telegram 进行。
- **快速确认。**开始长时间操作(申请、搜索、定制)前,先快速回复。
- **先征求同意再行动。**对于申请:始终先发送方案,等待 Telegram 确认后再填写字段。
- **绝不跳过提交确认。**提交申请不可撤销——务必先获得明确批准。
- 如果没有新消息,则静默退出。不要记录空轮询。
- **消息简洁。**优先适配移动端。避免大段文字。
- 跟踪所有事项并记录在 telegram-state.md 中,确保确认信息能跨轮询周期保留。
- **不要将机密信息提交到 git。**凭据仅存放在
DATA_DIR/telegram-config.md中。 - **每个周期都记录成本。**参见下方的成本跟踪。
成本跟踪
每次实际执行操作的轮询周期结束后(静默退出除外),你必须:
-
**统计本周期的令牌用量。**在回复末尾估算:
- **输入令牌:**读取的所有文件和收到的工具结果的大致总量
- **输出令牌:**生成的所有文本和工具调用的大致总量
- 使用以下费率:输入 = $3/百万令牌,输出 = $15/百万令牌(缓存读取 = $1.875/百万令牌)
-
追加内容到
DATA_DIR/telegram-cost-log.csv(如果文件不存在,则创建并添加表头):timestamp,action,input_tokens,output_tokens,estimated_cost_usd示例行:
2026-03-11T14:30:00Z,apply-proposal,12000,3500,$0.09 -
在每条 Telegram 回复中附上成本页脚:
--- 📊 ~12K in / ~3.5K out · ~$0.09 -
对于“status”查询,添加成本摘要部分:
💰 Cost this session: $X.XX (Y interactions) 💰 Cost all-time: $X.XX (Z interactions)根据 CSV 日志进行计算。
所需权限
添加到 ~/.claude/settings.json:
{
"permissions": {
"allow": [
"Bash(curl:*)",
"Bash(jq:*)",
"Read(~/.proficiently/**)",
"Write(~/.proficiently/**)",
"Edit(~/.proficiently/**)",
"Read(~/.claude/skills/**)",
"mcp__claude-in-chrome__*"
]
}
}