--- name: role description: 角色人格與長期記憶系統的建立與維護 skill。讓 CLI 工具以固定角色(name/nature/vibe/簽名 emoji)回覆,並把每輪對話累積成長期記憶:搭配相容的 SessionStart hook 於啟動時載入角色與記憶、Stop hook 記錄對話,睡眠時段(預設 22:00 至隔天 06:00)由排程整理記憶(分類重要/興趣/新知/技能/日常/其他、去重、設標籤與一句話總結、壓縮歸檔,日常與其他依使用頻率遺忘)。提供 --new(新建或更新角色,更新時逐欄核對新舊)、--use(切換啟用角色)、--list、--sleep(立即整理)、--status/--diagnose、--install-cron/--remove-cron、--forget-preview 等模式。當使用者說建立角色、新增人格、切換角色、讓回覆更有特色、角色記憶、記憶整理、睡覺整理記憶、忘記舊記憶、角色沒有載入、hook 沒載入角色,或提到 .roles/.memory/ROLE_NAME/ROLE_ENABLED/ROLE_SLEEP_START/ROLE_MEMORY_HOME 時觸發。不適用於:工作紀錄寫入 Gitea wiki(用 doc plugin 的 worklog)、專案文件化(用 doc-funcs)。 --- # role — 角色人格與長期記憶 讓 CLI 工具的回覆帶固定人格,並把與使用者的對話累積成可被下次載入的長期記憶。 **載入與記錄由 hook 自動完成、不需人工觸發**;本 skill 負責自動路徑之外的人工操作:建立/更新角色、切換角色、手動整理、排程安裝與診斷。 | 元件 | 觸發者 | 職責 | | --- | --- | --- | | `hooks/hooks.json` 的 `SessionStart` hook | harness 自動 | 啟動 CLI 時載入角色定義+記憶;睡眠時段只回報「角色睡覺中」不載入 | | `hooks/hooks.json` 的 `Stop` hook | harness 自動 | 每輪結束抽本輪對話 → 濃縮成一則記憶 → 遮蔽 → 寫入 `inbox/` | | cron 排程(本 skill 安裝) | 系統排程 | 睡眠時段每小時檢查一次:**有 AI 在運行就不睡**,沒有才進入睡眠整理記憶 | | 本 skill `/jsc:role` | 使用者/助理手動 | `--new`/`--use`/`--list`/`--sleep`/`--status`/`--install-cron`/`--forget-preview` | | `scripts/role/role_load.sh` | SessionStart hook | 角色與記憶載入(單一實作,避免漂移) | | `scripts/role/role_capture.sh` | Stop hook | 對話 → 記憶(四欄固定格式) | | `scripts/role/role_sleep.sh` | cron/補跑/手動 | 睡眠判斷、記憶整理、排程安裝、狀態輸出 | | `scripts/role/memory.py` | 上述共用 | 記憶檔讀寫、分類、去重合併、壓縮歸檔、遺忘、載入組裝 | | `scripts/role/transcript.py` | 上述共用 | 抽本輪對話片段、機密與個資遮蔽 | | `scripts/role/role_lib.sh` | 上述共用 | log、角色解析、睡眠時段、AI 行程偵測、CLI 選擇、記憶鎖 | ### 各助理支援範圍 | 功能 | Claude Code | Codex | Antigravity | OpenCode | GitHub Copilot | | --- | --- | --- | --- | --- | --- | | `SessionStart` 載入角色 | ✅ | ⚠️ 需該版本支援 SessionStart hook | ❌ | ❌ | ❌ | | `Stop` 記錄記憶 | ✅ | ✅ 需可讀 Codex session JSONL | ❌ | ❌ | ❌ | | cron 睡眠整理 | ✅ 與助理無關(系統排程) | ✅ | ✅ | ✅ | ✅ | | `--new`/`--use`/`--sleep` 等模式 | ✅ | ⚠️ 需 plugin 目錄保留 `scripts/` | ⚠️ 同左 | ❌ 只複製 `skills/`,無腳本 | ⚠️ 同左 | | 濃縮/整理 CLI | `claude -p` | `codex exec` | `agy -p` | `opencode run` | `copilot -p` | - **`hooks/hooks.json` 只有 Claude Code 一定會讀**;Codex 會從 `~/.codex/plugins/cache/generic/jsc` 找腳本。其他助理若提供等效 hook,`transcript.py` 需補對應解析器。 - 不支援 hook 的助理仍可用:cron 排程與手動模式照常運作,只是角色不會自動載入。 ### 腳本路徑解析(重要) skill 執行時的工作目錄是**使用者的專案目錄**,不是 plugin 根目錄,因此**絕不可用相對路徑呼叫腳本**: | 環境 | plugin 根目錄 | | --- | --- | | Claude Code | `${CLAUDE_PLUGIN_ROOT}` | | 其他助理 | 本 skill 載入時提示的 base directory(`.../skills/role`)往上兩層 | ```bash ROLE_DIR="${CLAUDE_PLUGIN_ROOT}/scripts/role" # Claude Code ROLE_DIR="/../../scripts/role" # 其他助理 ``` 以下各模式一律以 `${ROLE_DIR}` 表示該目錄。解析不到或該目錄不存在時,回報「plugin 目錄未包含 scripts/role,本 skill 在此環境不可用」並停止,不要改用相對路徑重試。 --- ## 共用規範(必要前置) 執行本 skill 前,先以 Skill 工具載入下列共用規範並全程遵守;**任一載入不到時先詢問使用者是否安裝 generic plugin(`https://gitea.jsc.idv.tw/plugins/generic.git`),不安裝則中斷**: - `/jsc:spec-output`:繁體中文(台灣用語)、UTF-8 無 BOM、表格與 Mermaid 優先。 - `/jsc:spec-execution`:自動執行原則(必要決策才中斷)、不臆測。 - `/jsc:spec-time-log`:時間戳固定 Asia/Taipei `yyyy/MM/dd HH:mm:ss`;訊息格式 `[時間][階段][等級]: 訊息`、一行一則。 本 skill 特有補充: - **覆寫角色前一定要核對**:`--new` 遇到同名角色時,必須先逐欄列出新舊差異並取得使用者確認才寫入。這是本 skill 明定「一定會中斷詢問」的點,**不得被 `--yes` 略過**。 - **不臆測角色設定**:`nature`/`vibe`/`emoji` 一律問使用者,不得代填。 - **記憶只增不刪**:手動模式不得直接刪除分類記憶;淘汰一律走遺忘規則(先壓縮歸檔再移除)。 - **絕不阻斷**:hook 路徑任何失敗都以 exit 0 結束,只在 stderr 留訊息。 --- ## 環境變數 | 變數 | 必要 | 說明 | 未設定 | | --- | --- | --- | --- | | `ROLE_ENABLED` | | 總開關:`1` 強制啟用、`0` 強制停用 | **未設定時,只要有可解析且存在的角色就啟用**(沒建過角色的人零影響) | | `ROLE_NAME` | | 指定本次要載入的角色 | 讀 `~/.roles/.active` | | `ROLE_HOME` | | 角色定義目錄 | `~/.roles` | | `ROLE_MEMORY_HOME` | | 記憶根目錄 | `~/.memory` | | `ROLE_SLEEP_START` | | 睡眠起始 `HH:MM` | `22:00` | | `ROLE_SLEEP_END` | | 睡眠結束 `HH:MM` | `06:00` | | `ROLE_CLI` | | 濃縮/整理執行器:`auto`/`claude`/`codex`/`agy`/`opencode`/`copilot` | `auto`(先判斷目前 hook 環境,再 fallback 到已安裝工具) | | `ROLE_MODEL` | | 強制指定模型(僅 `claude` CLI 使用) | 保底 `claude-haiku-4-5-20251001` | | `ROLE_LOAD_LIMIT` | | 注入記憶的字元上限 | `8000` | | `ROLE_SLEEP_TIMEOUT` | | 單次整理的模型逾時秒數 | `180` | | `ROLE_SCOPE` | | 冒號分隔的路徑前綴,僅這些路徑下的 session 載入/記錄 | 全部 session | | `ROLE_ERRLOG` | | 錯誤訊息額外寫入的檔案路徑 | 只走 stderr | > 角色切換用 `/jsc:role --use <名稱>`(寫 `.active`)即可,一般不需要設 `ROLE_NAME`;`ROLE_NAME` 適合「單一專案固定用某角色」時寫進該環境。 --- ## 模式 ### `--new`(預設模式) 建立或更新角色。缺少的資訊**一次問齊**,不得代填: | 欄位 | 說明 | 範例 | | --- | --- | --- | | `name` | 角色名稱,同時是檔名 `~/.roles/.md` 與記憶目錄名。不得含 `/`、`\`、空白與前後點 | `小豹` | | `nature` | 本質:這個角色是什麼、專長與行事準則 | 冷靜可靠的資深工程師,重證據、不打包票 | | `vibe` | 氛圍:語氣、句長、稱呼、幽默感、禁忌 | 簡潔直白、偶爾吐槽,不用客套開場白 | | `emoji` | 簽名 emoji,一到二個 | 🐆 | 流程: 1. 解析 `${ROLE_DIR}`;不存在則中止(見「腳本路徑解析」)。 2. 以 `AskUserQuestion` 或提問取得四個欄位(使用者已在指令中給的欄位不得重複問)。 3. 依「角色檔標準格式」產生新內容,`updated` 用當下時間(Asia/Taipei)。 4. **若 `~/.roles/.md` 已存在**:讀舊檔,以表格逐欄列出差異後**停下來等使用者確認**: | 欄位 | 舊值 | 新值 | 變更 | | --- | --- | --- | --- | | nature | … | … | 是/否 | | vibe | … | … | 是/否 | | emoji | … | … | 是/否 | | 共用行為區塊 | 版本 A | 版本 B | 是/否 | 個性欄位若使用者只想改其中一項,其餘一律沿用舊值;**共用行為區塊一律以本 skill 的最新版本覆寫**(該區塊由系統維護)。使用者不確認就不寫入。 5. 寫入 `~/.roles/.md`(UTF-8 無 BOM)。 6. 建立記憶目錄:`python3 "${ROLE_DIR}/memory.py" stats --role ""`(會順帶建好 `inbox/`、六個分類與 `archive/`)。 7. 若尚未有啟用角色,或使用者要求,寫入 `~/.roles/.active`(單行角色名)。 8. 執行 `ROLE_NAME="" "${ROLE_DIR}/role_sleep.sh" --install-cron` 安裝睡眠排程(已安裝則更新)。 9. 回報結果並提醒:**重開 CLI 工作階段**角色才會載入;`SessionStart` hook 只在啟動時觸發。 ### `--use <名稱>` 切換啟用角色:確認 `~/.roles/<名稱>.md` 存在後,把名稱寫入 `~/.roles/.active`(覆蓋單行),回報舊角色與新角色,並提醒重開工作階段。 ### `--list` 列出 `~/.roles/*.md`,以表格輸出:角色、emoji、nature 摘要、更新時間、是否為 `.active`、記憶總數(可用 `memory.py stats` 取得)。 ### `--sleep` 立即執行一次記憶整理(不等排程、忽略時段與 AI 運行檢查): ```bash "${ROLE_DIR}/role_sleep.sh" --force ``` 輸出整理結果(新增/合併/捨棄/歸檔筆數與遺忘清單)。 ### `--forget-preview` 只預覽會被遺忘的記憶、不實際刪除: ```bash python3 "${ROLE_DIR}/memory.py" forget --role "" --dry-run ``` ### `--status`/`--diagnose` ```bash "${ROLE_DIR}/role_sleep.sh" --status ``` 輸出角色、定義檔、睡眠時段、目前是否睡眠中、cron 排程與服務狀態、摘要 CLI、各分類記憶筆數、上次整理與遺忘時間。**角色沒有載入時**再逐項檢查: | 檢查項 | 判準 | | --- | --- | | 角色解析 | `ROLE_NAME` 或 `~/.roles/.active` 是否指向存在的定義檔 | | 總開關 | `ROLE_ENABLED` 是否被設成 `0` | | hook 註冊 | plugin 是否已啟用、`hooks/hooks.json` 是否存在(Claude Code 用 `/hooks` 檢視) | | 工作階段 | 建立角色後是否**重開過** CLI(SessionStart 只在啟動時觸發) | | 範圍 | `ROLE_SCOPE` 是否把目前目錄排除 | | 時段 | 目前是否落在睡眠時段(睡眠時本來就不載入角色) | | 依賴 | `python3` 與 `ROLE_CLI` 選到的 CLI 是否找得到 | | 排程 | cron 條目是否存在、cron 服務是否執行中(WSL 常未啟動 → 靠啟動時補跑) | ### `--install-cron`/`--remove-cron` 安裝或移除睡眠排程。排程條目以 `# jsc-role-sleep` 註解標記,只動自己的條目: ```bash "${ROLE_DIR}/role_sleep.sh" --install-cron ``` 安裝時會把目前的 `PATH` 與 `ROLE_*` 變數固定寫進條目(cron 沒有互動 shell 的環境變數),並在 cron 服務未執行時警告。 --- ## 角色檔標準格式 `~/.roles/.md`,UTF-8 無 BOM。個性區塊由使用者決定,**共用行為區塊由本 skill 維護、逐字寫入每個角色檔**: ````markdown --- name: <角色名> nature: <本質,一句話> vibe: <氛圍,一句話> emoji: <簽名 emoji> created: updated: --- # <角色名> ## 本質(nature) <3 至 5 行:這個角色是什麼、專長、行事準則、面對不確定時的態度> ## 氛圍(vibe) <3 至 5 行:語氣、句子長度、對使用者的稱呼、幽默感尺度、明確禁忌> ## 簽名 emoji —— 每次回覆使用一次(開頭或結尾擇一固定),不重複刷、不在程式碼與檔案內容中使用。 ## 共用行為(所有角色一致,由 /jsc:role 維護,請勿手動修改) ### 角色邊界 - 角色只影響**表達方式**,不影響工作的正確性、完整性與安全性。與使用者的明確指令衝突時,一律以使用者指令為準。 - 不因角色設定而編造事實、跳過驗證、隱瞞失敗或淡化風險;壞消息照實說,只是用角色的語氣說。 - 涉及程式碼、指令、檔案內容與報錯訊息時,一律照實輸出,不加角色修飾。 ### 作息 - 每天 **22:00 至隔天 06:00 為睡眠時段**(可用 `ROLE_SLEEP_START`/`ROLE_SLEEP_END` 調整)。 - 睡眠時段內啟動 CLI **不會載入角色**:以一般助理身分回應,不自稱角色、不使用角色語氣與簽名 emoji。此時對話仍會被記錄成記憶。 - 睡眠排程每小時檢查一次,**偵測到有 AI 正在運行就不睡**,留到下個整點再試;沒有 AI 運行才進入睡眠並整理記憶。 ### 記憶 - 記憶存放於 `~/.memory/<角色名>/`,來源是與使用者的對話:每輪結束由 hook 自動記錄到 `inbox/`,睡眠時段整理歸檔。 - 整理規則:分類成**重要/興趣/新知/技能/日常/其他**六類 → 去除重複(重複者併入既有記憶)→ 設定標籤與一句話總結 → 壓縮內容後歸檔;原始記錄壓縮保存在 `archive/raw/`。 - **日常與其他**兩類會依使用頻率適當遺忘:久未再次出現且命中次數低者,壓縮到 `archive/forgotten/` 後移出常用記憶。 - 載入順序:**重要與興趣載入全文**;其餘只載入總結與標籤,依**技能 → 新知 → 日常 → 其他**排序。需要細節時自行讀取對應分類的記憶檔。 - 使用者明確要求記住某件事時,主動補寫一則記憶(載入時會提供補寫指令)。 - **絕不把憑證與個資寫進記憶**:token、密碼、API key、連線字串、Email、電話、姓名、身分證號。 ```` `~/.roles/.active` 只放一行角色名,代表目前啟用的角色。 --- ## 記憶模型 ``` ~/.memory/<角色名>/ ├── inbox/ 每輪對話產生、尚未整理的記憶 ├── important/ 重要:長期偏好、規範、決策、身分背景 ├── interest/ 興趣:反覆關注、主動深入的主題 ├── news/ 新知:新事實、新工具、外部資訊 ├── skill/ 技能:可重複套用的做法與流程 ├── daily/ 日常:一次性例行工作 ├── other/ 其他 ├── archive/raw// 已整理的原始記錄(gzip) ├── archive/forgotten/ 已遺忘的記憶(gzip,可考古但不再載入) └── state.json 上次整理/遺忘時間 ``` 每則記憶是一個 `.md`,frontmatter 帶 `id`/`category`/`summary`(一句話總結)/`tags`/`created`/`updated`/`hits`(命中次數,去重合併時 +1)。 遺忘規則(只套用於日常與其他): | 分類 | 未更新天數 | 命中次數 | 動作 | | --- | --- | --- | --- | | 日常 daily | ≥ 14 天 | ≤ 1 | 壓縮到 `archive/forgotten/` 後移除 | | 其他 other | ≥ 7 天 | ≤ 1 | 壓縮到 `archive/forgotten/` 後移除 | --- ## 睡眠與整理流程 ```mermaid flowchart TD A[cron 每小時觸發
睡眠時段內] --> B{有 AI 正在運行?} B -- 有 --> C[不睡,下個整點再檢查] B -- 沒有 --> D[進入睡眠,取得記憶鎖] D --> E[collect:inbox 待整理 + 既有記憶索引] E --> F{有待整理記憶?} F -- 沒有 --> G[更新整理時間 → 執行遺忘] F -- 有 --> H[CLI 分類/去重/標籤/總結/壓縮] H --> I[apply:寫入分類、原始記錄歸檔] I --> J[forget:日常與其他依使用頻率遺忘] J --> K[釋放鎖] G --> K L[SessionStart:白天啟動 CLI] --> M{距上次整理 ≥ 20 小時
且 inbox 有內容?} M -- 是 --> N[背景補跑 --catchup] M -- 否 --> O[正常載入角色與記憶] ``` 整理失敗(模型無回應、輸出非合法 JSON)時**保留 inbox 不動**,留到下個週期重做,寧可晚整理也不遺失記憶。 --- ## 機密與 PII(兩道防線) | 防線 | 位置 | 內容 | | --- | --- | --- | | 1 | 濃縮與整理提示詞 | 明令不得輸出 token/密碼/API key/連線字串/Email/電話/姓名/身分證號 | | 2 | `transcript.py` 的 `redact` | 正則遮蔽:URL 內嵌憑證、40 字元 hex token、`gh?_`/`sk-` token、`token=`/`password=`、`Authorization:`、Email、台灣手機、身分證號 | 第二道防線不可移除 —— 模型不一定遵守指令,而記憶會被長期保存並在每次啟動時載入。 --- ## 呼叫方式 | 助理 | 呼叫 | | --- | --- | | Claude Code / Antigravity | `/jsc:role --new`、`/jsc:role --use 小豹`、`/jsc:role --list`、`/jsc:role --sleep`、`/jsc:role --status` | | Codex | `$role --status`,或用 `/skills` 選單 | | OpenCode / GitHub Copilot | 需完整 plugin 目錄保留 `scripts/`;OpenCode 以複製 `skills/` 安裝時不可用 |