jobsearch-telegram について
jobsearch-telegram は、Telegram のメッセージをポーリングし、求職依頼を関連スキルに振り分ける Proficiently のスキルです。ヘッドレスのポーリングで、段階的な確認を伴う応募、求人検索、履歴書の調整、状況確認を扱います。
主な機能
- 01Telegram の定期ポーリング
- 02求人 URL と応募依頼の振り分け
- 03求人検索と履歴書の調整
- 04確認待ち項目と応募状況の追跡
- 05通常テキストメッセージの記録
活用シーン
- 01求人 URL を送って応募を開始
- 02Telegram のメッセージから求人検索
- 03応募状況と確認待ち項目の確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ proficientlyjobs/ proficiently-claude-skills --skill jobsearch-telegramインストール後、Claude Code で/jobsearch-telegramを入力して読み込まれたか確認します。
詳細
求職活動の Telegram ポーリング
Telegram をポーリングして受信メッセージを適切な Proficiently スキルに振り分けます。/loop 1m /proficiently:jobsearch-telegram を使ってヘッドレスで実行します。
初回セットアップ
このスキルを実行する前に、ユーザーが Telegram ボットを作成して設定する必要があります。DATA_DIR/telegram-config.md が存在しない場合は、セットアップ手順を案内します。
1. Telegram ボットを作成する
ユーザーに次のように伝えます。
Telegram ボットをセットアップしましょう。
- Telegram を開き、@BotFather を検索します
/newbotを送信します- 名前を選びます(例:「My Job Search Assistant」)
- ユーザー名を選びます(末尾は
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:メモ |
Step 4a:求人 URL/応募リクエストの処理
-
URL を抽出するか、「last」/「current」を解決します
-
この URL に対応する求人フォルダーが
DATA_DIR/jobs/にすでに存在するか確認します -
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の応募ワークフローを実行します:- Steps 0-6(前提条件 → 移動 → 調査 → 書類の作成 → フィールドのスキャン → 回答案の提示)に従います
- 承認に AskUserQuestion を使う代わりに、Step 6 の提案の概要をTelegram に送信し、「Pending Confirmations」に追加します
- 保留中の確認には、
job_url、form_url(移動先の ATS フォームの直接 URL)、field_mapping(承認済みのフィールド→値の完全な JSON)を保存します - Telegram 経由でユーザーの確認を待ちます(次回以降のポーリングサイクルで返信として届きます)
-
フィールド承認の確認が届いたら(Step 5)、
form_urlに再度移動してすべてのフィールドに入力し、スクリーンショットの説明とともに2 回目の確認(送信承認)を送り、"Everything looks good — submit?"と尋ねます- これを
stage: "submit-approval"の新しい保留中の確認として保存します
- これを
-
送信承認が届いたら、Submit をクリックして応募を記録します(応募スキルの Step 9)。
提案の送信: 全フィールドの概要を含め、送信メッセージのヘルパー(Step 8)を使用します。4000 文字以内にしてください。超える場合は、(1)自動入力されるフィールド、(2)回答案、(3)入力が必要な項目に分割します。
2 段階の確認フロー:
- Phase 1(
stage: field-approval):ユーザーがフィールド→値のマッピングを承認します - Phase 2(
stage: submit-approval):Submit をクリックする前に、ユーザーが最終フォームを承認します - 応募の送信は取り消せないため、Phase 2 を省略しないでください
Step 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. - 返信と照合できるよう、求人リストとともに「Pending Confirmations」に追加します
Step 4c:カスタマイズリクエストの処理
- 求人の参照情報(URL、「last」、または求人名)を抽出します
- 受領確認を送信します:
📝 Tailoring resume for [job]... skills/tailor-resume/SKILL.mdの履歴書カスタマイズワークフローを実行します- 主な変更点を添えて結果を Telegram に送信します
- カスタマイズした履歴書の保存先ファイルパスを記録します
Step 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]
Step 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
Step 5:確認返信の処理
確認返信は次のいずれかです:
- スレッド形式の返信(Telegram のネイティブ返信機能):
reply_to_message.message_idを使って保留中の確認と照合します - 保留中の確認がある場合に、確認/拒否を表す語句(
yes、y、go、send it、👍、no、skip、cancel、❌)のみを含む単独のメッセージ
単独メッセージの曖昧さを解消する方法:
- 保留中の確認が 1 件だけの場合 → その確認に適用します
- 保留中の確認が複数ある場合 → 保留中の項目を番号付きリストで提示し、どれを指しているか尋ねます:
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 をクリックし、応募を記録します- 検索結果の選択 → 選択された求人の応募ワークフローを開始します
- 実行した内容を確認するメッセージを送信します
- 「Pending Confirmations」から削除し、「Recent Actions」に追加します
Step 6:通常のテキストメモの処理
- タイムスタンプとともに
DATA_DIR/telegram-inbox.mdに記録します - 会社名または求人タイトルのようであれば、
"Want me to search for [text] jobs?"と提案します - それ以外の場合は、
"Noted 👍"と確認します
ステップ 7:状態を更新する
すべてのメッセージを処理した後:
DATA_DIR/telegram-state.mdのlast_update_idを更新します- Pending Confirmations(新規のものを追加し、解決済みのものを削除)を更新します。各適用確認について、次を含めます:
[msg_id: X] apply/field-approval — [Role] at [Company] — waiting since DATE job_url: https://... form_url: https://... field_mapping: {"First Name": "...", "Email": "...", ...} - Recent Actions(最新の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/M トークン、出力=$15/M トークン(キャッシュ読み取り=$1.875/M)
-
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__*"
]
}
}