🌐 English → README_en.md
Opus(作品)・Fable(伝説)・Mythos(神話)——Claude のモデルという"本"に挟む、魔法の栞。 本に栞を挟むように、どのモデルにも秘書の役割を授けます。Anthropic のサブスクだけ・専用サーバ不要で、サーバーレスな AI 秘書が誕生します。
栞が「どこまで読んだか」を覚えておくように、関係者・依頼・対応知・能力——そしてあなた自身の理解を記憶(registry)として蓄積し、あなたの文脈を見失いません。その実体は、Telegram を窓口とした 24-7 の対話チャネルです。
📦 設定の置き場 — 環境固有の値は
<INSTALL_DIR>/config.json(agent_name/private_dir/session_duration_sec/registry_*、雛型templates/config.template.json、init-configで生成)に集約します。秘匿(bot token / authorized chats)は env で注入。運用値の手置換は不要——人格名・private_dir は config.json、<INSTALL_DIR>は bootstrap が env 解決します(<INSTALL_DIR>=インストール先 /<OWNER>=運用主体 はドキュメント上の読み替え表記)。詳細は STRUCTURE.md。
Telegram Bot API の long-polling を Claude Code Routines(Anthropic のクラウド実行スケジュールエージェント基盤。Remote 実行=cloud routine)上で常駐させ、認可済みチャットからのメッセージに秘書エージェント(SecretaryRole を被った本体エージェント。人格名は config.json の agent_name)が即応する対話チャネル。
公開 ingress を持てない cloud routine 環境でも、long-polling と deadline 駆動ループで 24-7 の即応を実現します(watch --exit-on-message がメッセージ受信時に即座に exit → 返信 → 再起動)。応答は親プロセスのエージェント本人が起草し、本スキルは fetch / 認可 / 正規化 / 送信のみを担います(応答生成をサブプロセスに投げない設計)。
Clean Architecture 4層(Domain → UseCase → Interface → Infrastructure、依存は内向きのみ)。設計の理由は DESIGN.md、ディレクトリ構造は STRUCTURE.md を参照。
- テキスト即応 — Gmail より低レイテンシ(数秒)で
<OWNER>から呼べる 24-7 の対話チャネル - 能動 push(proactive-send) — 受信への返信だけでなく、秘書側から能動的に送る outbound(双方向化)も可能。秘書は基本 inbound(受信→返信)稼働だが、口頭での権限 grant(例: 自由時間の付与)により outbound も担う(能力境界の詳細は SecretaryRole、再送の冪等性設計は DESIGN.md §3.9)
- 受信メディアの中身理解 — file 転送で止まらず中身を読む:
- 画像 → Vision で解釈
- docx / pptx / xlsx → Markdown 化
- PDF → 全ページ画像化(Vision)+ オンデマンドの全文テキスト / 個別ページ抽出
- voice / audio / video → 音声を文字起こし(ローカル STT、音声が外部に出ない)
- 生成物の送り返し — 画像・レポート等を返信に添付(reply threading、typing 表示)
- 管理表 — 関係者(INDIVIDUALS)/依頼(TASKS)/対応知(KNOWLEDGE)/主題語彙(SUBJECTS)/能力カタログ(ABILITIES)を秘書が判断して記録。秘書は応答前に能力カタログを引き、依頼に使えるスキルがあれば行使する。対応知は category(認識の型・許可集合 10 種)と subjects(主題・SUBJECTS 表が語彙を持つ)の二軸で引ける。
registry_sync有効時は固定ブランチへ git 永続化(揮発 state と分離・イベント駆動 commit&push)。PROFILE / GOALS が蓄積すると秘書の役割が進化する(次節) - 言行一致の保証(WAL) —
registry_sync有効時、「登録しました」等の約束をする返信の前に intent を WAL ログへ先行 push(must-succeed=push 不能なら送信もしない)し、起動時に未反映分を registry へ redo。push 漏れによる「言ったのに未登録」を構造的に防ぐ。先行書込の入口と redo の双方に管理表addと同じ検証が掛かり、受理されない payload は WAL に入らない(入口で exit 2)/redo でdeadへ隔離されて記録に残る(正典へ黙って書かれない)
預けたデータで秘書の顔がデータ駆動で進化します——秘書(baseline)から始まり、プロファイルを預けると執事、目標を預けるとコーチ、両方そろうとアネゴへ。役割はフラグではなくデータの状態から立ち上がります(判定は role-status=決定論、演じ方は SecretaryRole。設計の理由は DESIGN.md §3.11)。
| 目標なし | 目標あり(GOALS / STEPS) | |
|---|---|---|
| プロファイルなし | 秘書(baseline) | コーチ(目標逆算とプロマネ巻き取り) |
| プロファイルあり(PROFILE) | 執事(嗜好を踏まえた先回り) | アネゴ(人物理解 × 伴走の両輪) |
- P 軸(パーソナライズ) — 人物理解の材料は3経路:同梱の三位占術スキル(
skills/precognitive-viewer、opt-in)/JSON 出力型占いサイトの紹介(ユーザー自身が取得した JSON を秘書が解釈)/MBTI 等の直接聴取 - A 軸(伴走) — 四大相談コース(お金・仕事・人間関係・健康)の目標逆算(GOALS → STEPS)+ proactive-send ナッジ
- 卒業まで設計済み — すべての目標が達成(achieved/abandoned)になると A 軸が降り、アネゴは自然に執事へ戻ります。伴走は預かりもの——変容を見届けたら手を離す仕様です(目標を足せば再びコーチ/アネゴへ、可逆)
cd <INSTALL_DIR>
# 依存インストール
python -m pip install -e ".[dev]"
# 環境変数(秘匿のみ=純2層)
$env:TELEGRAM_BOT_TOKEN = "<bot-token-from-botfather>"
$env:SHIORI_AUTHORIZED_CHATS = "[<your-chat-id>]"
$env:SHIORI_STATE_DIR = ".\state" # 任意(既定 ./state)
# 運用設定 config.json を生成(session_duration_sec 必須、範囲 1〜86400)
python scripts/main.py init-config --session-duration-sec 14400 --agent-name YourSecretary
# 設定検証 → 現設定の確認 → 疎通 ping → 1サイクル poll
python scripts/main.py validate-config
python scripts/main.py show-config
python scripts/main.py test --chat-id <your-chat-id>
python scripts/main.py poll --timeout 5
# deadline 駆動の常駐を試す(メッセージ受信で即応、窓満了で再起動)
python scripts/main.py lease acquire
python scripts/main.py watch --exit-on-message --max-duration 30 --timeout 5
# → メッセージが来たサイクルで即 exit 0/無ければ 30 秒の窓満了で exit 0
# (本番の常駐設定=4h 枠・540s 窓は ROUTINE_PROMPT.md 参照)
python scripts/main.py lease releasechat_id の発見(初回のみ手動)— bot に 1 通送ってから
pollを 1 回叩き、emit JSON のchat_idを読んでAUTHORIZED_CHATSに登録します(鶏卵問題ゆえ初回だけ手動)。
- 受信: bot に画像 / docx / PDF / voice 等を送ると、
poll/watchが中身を解釈して emit します。PDF の段階処理(先頭ページ Vision → 必要に応じrender-pdfで全文/個別ページ)や voice の文字起こしの詳細は SKILL.md。 - 送信:
send-reply --file <path>(複数可、画像→sendPhoto・他→sendDocument に自動振り分け)。--reply-to <message_id>で返信スレッドを張れます。
| Var | Required | 概要 |
|---|---|---|
TELEGRAM_BOT_TOKEN |
✅ | BotFather から取得 |
SHIORI_AUTHORIZED_CHATS |
✅ | JSON array of int(chat_id allowlist) |
SHIORI_STATE_DIR |
optional | offset/lease/media の保存先(既定 ./state) |
SHIORI_SESSION_ID |
optional | リース owner ID(省略時は uuid 自動生成)。source bootstrap.sh で自動 export され全コマンドで共有 |
| media / PDF / 音声 / 送信添付の optional 群 | optional | *_MEDIA_MAX_SIZE_BYTES(20MB)/ *_MEDIA_RETENTION_HOURS(24h)/ *_MEDIA_ENABLE_DOWNLOAD(Heavy/Medium)/ *_BUNDLE_VOICE(STT 同梱)/ *_OUTBOUND_MAX_SIZE_BYTES(50MB)/ *_PDF_IMAGE_MAX_PAGES(20)。各既定値・挙動は SKILL.md の env vars 表(SSoT)参照 |
継続時間は config.json の
session_duration_sec(範囲 1〜86400 秒、必須)。「9-17 時勤務」のような勤務帯は cloud routine の cron(例0 9-16 * * 1-5)+ duration で表現します(コードに時計を持たせない)。deadline 駆動ループの運用変数(SHIORI_SESSION_DEADLINE_EPOCH/SHIORI_POLL_SET_SEC/SHIORI_POLL_BASH_TIMEOUT_MS/SHIORI_MAX_TURNS)はbootstrap.shが config.json から算出して export します。詳細は ROUTINE_PROMPT.md。
| Command | 機能 | Exit code |
|---|---|---|
validate-config |
env + config.json の検証 | 0=OK, 2=設定欠損 |
show-config |
現設定を read-only 表示(秘匿はマスク) | 0(未設定でも 0) |
init-config [--session-duration-sec] [--agent-name] [--private-dir] [--force] |
config.json を生成(範囲検証、既存は --force で上書き) |
0, 2=範囲外/既存 |
lease acquire|renew|release [--owner] [--ttl SEC] |
リースロック操作(並走防止、--ttl 既定 300) |
0, 4=conflict, 2 |
poll [--timeout] |
getUpdates 1サイクル、認可・正規化済み update を JSON Lines で emit | 0, 1=fetch失敗, 3=auth失敗 |
watch [--max-duration SEC] [--exit-on-message] [--timeout SEC] [--max-iterations N] [--cleanup-interval N] [--owner] |
長期 long-poll ループ(サイクル毎に lease 自動 renew)。--max-duration=窓満了で exit 0、--exit-on-message=メッセージ受信サイクルで exit 0、--timeout=getUpdates long-poll 秒(既定 30) |
常駐 / 窓畳み |
send-reply --chat-id --update-id --text-file [--file ...] [--reply-to] [--owner] |
返信送信。--file で添付、--reply-to で threading |
0, 1=送信失敗, 2=添付不正, 3=auth, 4=lease |
proactive-send --chat-id --text-file [--file ...] [--reply-to] [--owner] |
秘書からの能動送信(inbound 非依存の outbound push、offset 非干渉)。--update-id 無しが send-reply との差分。--file で添付、--reply-to で threading |
0, 1=送信失敗, 2=添付不正, 3=auth, 4=lease |
render-pdf --path (--text | --pages N-M) |
受信済み PDF のオンデマンド抽出(--text=全文テキスト / --pages=指定ページ画像化) |
0, 2=不在/引数不正 |
lint-numbers <path> |
納品物・handoff(原稿 md)の裸数値スキャン。数字を含む各行に計器トークン(実測 / 見込み / 出典 等の出所マーカー)が同じ行にあるかを二値判定し JSON 1 行で emit(path / number_lines / covered / bare / bare_lines)。presence の検査であって正しさの検査ではない。read-only、裸 0 件でも 1 行出す。裸の有無は exit code でなく JSON の値(DESIGN §3.13) |
0=OK(裸の有無に依らず), 2=不在/不可読 |
test --chat-id |
疎通テスト(owner chat に ping 送信) | 0, 1, 3 |
cleanup-media |
retention 超過の保存 media を削除(watch は自動発火、手動/cron 用) |
0, 2 |
individuals|tasks|knowledge|subjects|abilities|profile|goals|steps {list|get|add|remove|import} |
管理表 CRUD(8 表、値オブジェクトで入力検証、不正は exit 2)。add / import はトップレベル未知キーを exit 2 で弾く(fail-closed。read 経路は警告どまりで読める)、import --json-file は全件置換(全件検証→置換ゆえ 1 件でも不正なら無置換)。registry_sync 有効時は add/remove/import 後に commit&push |
0, 2 |
orientation [--notes-tail N] [--topic-width N] [--handoff-latest N] [--handoff-cap N] [--knowledge-category CAT] [--knowledge-latest N] [--knowledge-subject ID] [--profile-cap N] [--individuals-cap N] [--abilities-cap N] [--goals-cap N] [--tasks-latest N] [--steps-latest N] [--artifacts-latest N] |
起動時オリエンテーションのダイジェスト(role + 8表の件数/バイト数 + outbound の最終送信確定行〔WAL の done 最新 created_at と pending 件数、v1.16.0〕 + 小表全文〔goals〕 + individuals / abilities / profile / tasks / subjects / steps の一行索引と active の notes 末尾 + tasks.notes 直後の ## artifacts〔active タスクごとの採択済み成果物のファイル名、--artifacts-latest N で群ごとに頭打ち。中身は開かない、v1.17.0〕 + knowledge 索引 + handoff 最新ブロック)を emit。幅の単位は UTF-8 バイトで丸めは文字境界、出力はレコード長に依存せず有界(DESIGN §3.12)。--knowledge-category で索引を category 完全一致に絞る(見出しの N of M に全件数が残る)、--knowledge-subject で subjects の要素一致に絞る、--knowledge-latest で新しい順 N 件に頭打ち(併用時は category → subject → latest の順)。--individuals-cap / --profile-cap / --abilities-cap は索引行の自由記述 1 列(context_notes / content / guidance)の頭の幅(individuals は v1.18.0、profile / abilities は v1.19.0、未指定なら 120。件数絞りは無く全件)、--goals-cap は goals の notes を丸めるバイト上限(未指定なら全文)、--tasks-latest は tasks 一行要約の終端(done / cancelled 等)だけを新しい順 N 件に絞り(active は件数絞りの対象外=常に全件、v1.15.2。notes も載った集合の active に連動)、--steps-latest は steps 索引を新しい順 N 件に絞る(--steps-latest は未指定なら全件。索引行の頭の幅 3 つを除き、いずれも未指定=全文・全件で、絞る値は自分のデータの実測から決める)。digest の総バイトは毎回 stderr に orientation digest: N bytes として出る(25,600 超は警告付き、stdout・exit code は不変) |
0, 2=設定欠損 |
knowledge search --query Q [--query Q2] [--any] [--category C] [--subject S] [--limit N] |
knowledge の read-only 検索(v1.17.0)。id / subjects / topic / content の部分文字列一致(NFKC・大小無視)、複数語は既定 AND・--any で OR、絞りは category → subject → query → limit。索引行で返り(本文は get --key)、見出しに N matches of M records を開示、0 件でも exit 0。総バイトは stderr に申告(25,600 超は警告)。新しい知見を焼く前の既出照合の口(意味論の正典は SKILL.md) |
0, 2=--query 無し/knowledge 以外 |
artifacts-sync |
成果物層 artifacts/(申し送りの handoff/ ブロックを含む)を固定ブランチへ commit & push。registry_sync 無効・artifacts/ 未作成は no-op |
0=OK(push 失敗は stdout の pushed=False、commit はローカルに残り次回再送), 1=同期処理の例外 |
handoff-archive <name>... |
消化済みの申し送りブロックを handoff/archive/ へ移して卒業させる(以後 orientation に載らない)。移動後は artifacts-sync 経路で push。不正名・不在・archive 側の同名既存は何も移動せず exit 2 |
0=OK(push 失敗は stdout の pushed=False、commit はローカルに残り次回再送), 1=同期処理の例外, 2=不正/不在 |
role-status |
PROFILE/GOALS から現在の役割(secretary/butler/coach/anego)をデータ駆動で判定し JSON 1行を emit | 0 |
registry-sync |
起動時に固定ブランチから管理表を fetch(registry_sync 有効時のみ、無効は no-op) |
0, 1 |
wal-append --kind <...> (--json|--json-file) / wal-push / wal-redo / wal-drop --kind --key |
WAL(言行一致): 登録系返信の前に intent を先行 push(must-succeed)、起動時に未反映分を registry へ redo。wal-append と wal-redo は管理表 add と同じ検証を通し、不正は入口なら exit 2(ログを書く前に停止)、redo なら dead へ隔離(exit 0・stderr に理由)。wal-drop は dead を明示的に畳む(pending は落とせない)。registry_sync 有効時のみ |
0, 1=push失敗, 2 |
--owner は省略可(source bootstrap.sh で env 経由自動同期、緊急時の上書きにのみ使用)。
常駐 routine 自体の cloud routine 登録・更新・停止は /shiori-secretary の schedule(登録 / 有効化 / 設定上書き=upsert)/ unschedule(停止=enabled:false)で行います。RemoteTrigger ツール手順(CLI ではない)で、手順は ROUTINE_PROMPT.md の「cloud routine ライフサイクル管理」節が SSoT。秘匿は cloud routine の Environment に注入、運用設定(session_duration_sec 等)は init-config。物理削除(list から消す)のみ claude.ai UI 手動です。
python -m pytest scripts/tests/ -v全層(Domain / UseCase / Adapter / Infrastructure / CLI)のテストを信頼性の証拠として公開しています。
| 依存 | 用途 | ライセンス |
|---|---|---|
httpx |
Telegram API 通信 | BSD |
markitdown[docx,pptx,xlsx] |
ドキュメント → Markdown 化 | MIT(再帰依存も MIT/BSD/Apache 系) |
pdfplumber |
PDF テキスト層抽出(ローカル完結) | MIT |
pypdfium2 + Pillow |
PDF 画像化(ローカル完結) | BSD/Apache 系 |
moonshine-voice + av(PyAV) |
音声 STT(ローカル推論、ffmpeg を wheel 内包) |
⚠️ moonshine のライセンス — Community License は年商 $1M 未満のみ商用無料です。年商 $1M 以上での本番利用は Enterprise License、またはSHIORI_BUNDLE_VOICE=falseで音声を外すか、kotoba-whisper(Apache-2.0)への差し替えが必要です(MediaRendererPort の差し替えで対応)。音声 STT はローカル推論のため、音声データが外部に送信されません(機密 voice メモにも安全)。
- SETUP.md — セットアップガイド(cloud routine 運用開始の順路。はじめての方はここから)
- SKILL.md — スキルマニフェスト(仕様の SSoT)
- ROUTINE_PROMPT.md — cloud routine 実行手順
- DESIGN.md — 設計正典(なぜこの設計か)
- STRUCTURE.md — 構造地図(どこに何を置くか)
- SECURITY.md — セキュリティ正典(脅威モデル・配布前チェックリスト)
- CHANGELOG.md — 変更履歴
