使用者反映身分設定與性格語氣擠在同一段(例如西莉卡的「馴獸師、養畢娜」是身分, 「細心、努力」是性格),要求拆成兩個檔案且不得遺失內容。 格式(扁平式,與既有 .assets/.checks/.lock 命名一致): - <ID>.identity.md:角色 ID、顯示名稱、來源作品、與使用者的關係定位、簽名 emoji - <ID>.soul.md:本質(nature)、氛圍(vibe) 共用行為規則**不再寫入角色檔**:role_load.sh 從不讀角色檔裡那份,它是冗余副本, 只會多一個漏同步的機會。內容完整保留於 role_load.sh(實際生效)與 SKILL.md(文件)。 - role_lib.sh:新增 role_identity_file/role_soul_file/role_legacy_file/ role_is_new_format;role_file 改為新格式優先、找不到退回舊檔,既有角色不受影響 - role_list_peers 支援兩種格式並避免同一角色重複列出 - role_load.sh:身分與人格分別讀取,新增「來源」與「關係定位」注入區塊 - 新增 --migrate <角色 ID>:逐字搬移本質、氛圍與簽名 emoji,來源與關係定位產生 待填空白,舊檔保留不動,新檔已存在時中止不覆寫 同時修掉兩個會造成實際損失的錯: - --export 原本硬編 cp 成 <ID>.md,新格式會被寫成舊檔名且遺失人格檔,備份救不回角色 - --export 從未備份 <ID>.checks(使用者自訂的晨間檢查腳本),一併補上 - --agent 原只讀 role_file(新格式即 identity),匯出的 sub agent 人格會是空的 驗證:遷移後逐字比對確認本質/氛圍/簽名 emoji/id/name/emoji/created 全部一致 且共用行為未寫入;新格式匯出的備份含 identity、soul、舊檔、assets、checks 與記憶; --agent 取得人格非空;--status 正確顯示格式與兩檔路徑;舊格式角色載入完全不受影響。 版號沿用 0.0.5(master 為 0.0.4,同一 PR 不再累加) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
541 lines
39 KiB
Markdown
541 lines
39 KiB
Markdown
---
|
||
name: role
|
||
description: 角色人格與長期記憶系統的建立與維護 skill。讓 CLI 工具以固定角色(name/nature/vibe/簽名 emoji)回覆,並把每輪對話累積成長期記憶:搭配相容的 SessionStart hook 於啟動時依字元預算載入高價值記憶、Stop hook 先本地過濾再輕量記錄對話,睡眠時段(預設 22:00 至隔天 06:00)由排程整理記憶(NREM 鞏固:分類/去噪/去重/合併/優先度;REM 整合:跨記憶連結/抽象化/提取線索;再依 semantic/episodic/procedural/emotional/preference/rule 與 explicit/implicit 標記長期記憶型態,壓縮歸檔並適當遺忘)。提供 --new(新建或更新角色;可只給角色名稱,必要時詢問來源/作品並推斷 name/nature/vibe/emoji 四欄)、--use(以角色 ID 切換啟用角色)、--list(列出角色與 ID)、--export(匯出角色壓縮檔)、--sleep(立即整理)、--status/--diagnose、--install-cron/--remove-cron、--forget-preview、--brief(晨間狀態檢查)、--agent(匯出成 sub agent 供多角色協作)、--migrate(舊格式角色檔拆成身分與人格兩檔)等模式。當使用者說建立角色、新增人格、切換角色、匯出角色、備份角色、讓回覆更有特色、角色記憶、記憶整理、睡覺整理記憶、忘記舊記憶、角色沒有載入、hook 沒載入角色、晨間狀態檢查、早上主動回報狀態,或提到 .roles/.memory/ROLE_NAME/ROLE_ENABLED/ROLE_SLEEP_START/ROLE_MEMORY_HOME/ROLE_LOAD_LIMIT/ROLE_LOAD_INBOX_LIMIT/ROLE_LOAD_DIALOG_TURNS/ROLE_CAPTURE_ENABLED 時觸發。不適用於:工作紀錄寫入 Gitea wiki(用 /jsc-doc:worklog)、專案文件化(用 /jsc-doc:funcs)。
|
||
---
|
||
|
||
# role — 角色人格與長期記憶
|
||
|
||
讓 CLI 工具的回覆帶固定人格,並把與使用者的對話累積成可被下次載入的長期記憶。
|
||
**載入與記錄由 hook 自動完成、不需人工觸發**;本 skill 負責自動路徑之外的人工操作:建立/更新角色、切換角色、手動整理、排程安裝與診斷。
|
||
|
||
| 元件 | 觸發者 | 職責 |
|
||
| --- | --- | --- |
|
||
| `hooks/hooks.json` 的 `SessionStart` hook | harness 自動 | 啟動 CLI 時依字元預算載入角色定義+高價值記憶,另以獨立預算載入近期逐字對話與未整理工作記憶做工作階段交接,並要求角色在本工作階段第一則回覆主動問候;睡眠時段只回報「角色睡覺中」不載入 |
|
||
| `hooks/hooks.json` 的 `Stop` hook | harness 自動 | 每輪結束先記錄最後互動時間 → 用本地規則過濾低價值短回合 → 值得保存時才濃縮成一則輕量 inbox 記憶 → 遮蔽 → 寫入 `inbox/` |
|
||
| cron 排程(本 skill 安裝) | 系統排程 | 睡眠時段每小時檢查一次:**有 AI 在運行就不睡**;另可依 CLI 閒置時間自動小睡整理 |
|
||
| 本 skill `/jsc-generic:role` | 使用者/助理手動 | `--new`/`--use`/`--list`/`--export`/`--agent`/`--migrate`/`--sleep`/`--brief`/`--status`/`--install-cron`/`--forget-preview` |
|
||
| `scripts/role/role_load.sh` | SessionStart hook | 角色與記憶載入;參考 OpenClaw 的 SOUL/AGENTS/USER/MEMORY 分層,把人格、操作邊界、使用者記憶分開注入,並提供第一則回覆問候提示(單一實作,避免漂移) |
|
||
| `scripts/role/role_capture.sh` | Stop hook | 對話 → 記憶(固定欄位格式) |
|
||
| `scripts/role/role_sleep.sh` | cron/小睡/補跑/手動 | 睡眠與小睡判斷、記憶整理、角色匯出、sub agent 定義匯出、晨間狀態檢查、排程安裝、狀態輸出 |
|
||
| `scripts/role/memory.js` | 上述共用 | 記憶檔讀寫、分類、去重合併、優先度、心理學記憶型態與關聯 metadata、壓縮歸檔、遺忘、載入組裝 |
|
||
| `scripts/role/transcript.js` | 上述共用 | 抽本輪對話片段、抽最近數輪純對話供工作階段交接、機密與個資遮蔽 |
|
||
| `scripts/role/role_lib.sh` | 上述共用 | log、角色解析、睡眠時段、AI 行程偵測、CLI 選擇、記憶鎖 |
|
||
| `scripts/role/examples/` | 使用者自行複製 | 晨間狀態檢查的範例腳本;複製到 `~/.roles/<角色 ID>.checks/` 才會生效 |
|
||
|
||
### 各助理支援範圍
|
||
|
||
| 功能 | 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-generic` 找腳本。其他助理若提供等效 hook,`transcript.js` 需補對應解析器。
|
||
- 不支援 hook 的助理仍可用:cron 排程與手動模式照常運作,只是角色不會自動載入。
|
||
- **每個 plugin 只註冊自己擁有的 hook**:`jsc-code`/`jsc-doc`/`jsc-generic` 的 plugin 名稱各自獨立,Claude Code 以 plugin 名稱為鍵註冊 hooks,因此三者互不覆蓋、也不需要同步。各 repo 的 `hooks/hooks.json` 只負責自己擁有的腳本:
|
||
|
||
| plugin | hooks.json 內容 | 擁有的腳本 |
|
||
| --- | --- | --- |
|
||
| `jsc-generic` | `SessionStart`(role_load)+ `Stop`(role_capture) | `scripts/role/` |
|
||
| `jsc-doc` | `Stop`(worklog) | `scripts/worklog/` |
|
||
| `jsc-code` | 無 `hooks/hooks.json` | 無 hook 腳本 |
|
||
|
||
歷史背景:在 plugin 名稱分離前,三個 repo 都叫 `jsc`,同名時 Claude Code 只保留一份 hooks 註冊且無法預期哪一份會贏,因此當時三份 `hooks/hooks.json` 必須維持同一份合併超集。名稱分離後這個限制已解除,**不可再把別的 plugin 的 hook 寫進自己的 hooks.json**,否則會重複執行。
|
||
- 每個 hook 指令仍先試 `$CLAUDE_PLUGIN_ROOT`,找不到再依「擁有者 marketplace 優先 → 全 cache 後援」的順序搜尋 `~/.claude/plugins/cache`/`~/.codex/plugins/cache`,以相容未設 `CLAUDE_PLUGIN_ROOT` 的助理。
|
||
|
||
### 腳本路徑解析(重要)
|
||
|
||
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="<skill base directory>/../../scripts/role" # 其他助理
|
||
```
|
||
|
||
以下各模式一律以 `${ROLE_DIR}` 表示該目錄。解析不到或該目錄不存在時,回報「plugin 目錄未包含 scripts/role,本 skill 在此環境不可用」並停止,不要改用相對路徑重試。
|
||
|
||
---
|
||
|
||
## 共用規範(必要前置)
|
||
|
||
執行本 skill 前,先以 Skill 工具載入下列共用規範並全程遵守;**任一載入不到時先詢問使用者是否安裝 generic plugin(`https://gitea.jsc.idv.tw/plugins/generic.git`),不安裝則中斷**:
|
||
|
||
- `/jsc-generic:spec-output`:繁體中文(台灣用語)、UTF-8 無 BOM、表格與 Mermaid 優先。
|
||
- `/jsc-generic:spec-execution`:自動執行原則(必要決策才中斷)、不臆測。
|
||
- `/jsc-generic:spec-time-log`:時間戳固定 Asia/Taipei `yyyy/MM/dd HH:mm:ss`;訊息格式 `[時間][階段][等級]: 訊息`、一行一則。
|
||
|
||
本 skill 特有補充:
|
||
|
||
- **覆寫角色前一定要核對**:`--new` 遇到同名角色時,必須先逐欄列出新舊差異並取得使用者確認才寫入。這是本 skill 明定「一定會中斷詢問」的點,**不得被 `--yes` 略過**。
|
||
- **不臆測角色設定**:可依使用者提供的角色名稱、來源/作品、形象圖或同意上網後取得的可靠資料,推斷 `name`/`nature`/`vibe`/`emoji` 四欄;資料不足或角色名稱有歧義時,必須先詢問來源、作品、參考連結或檔案,不得硬猜。
|
||
- **記憶只增不刪**:手動模式不得直接刪除分類記憶;淘汰一律走遺忘規則(先壓縮歸檔再移除)。
|
||
- **絕不阻斷**:hook 路徑任何失敗都以 exit 0 結束,只在 stderr 留訊息。
|
||
- **角色分層載入**:SessionStart 不把整份角色檔原封不動注入;只抽出角色 ID、顯示名稱、本質、氛圍與簽名 emoji 作為 `SOUL`,再由 hook 產生固定 `AGENTS` 操作邊界與 `USER/MEMORY` 記憶區塊。這是為了避免人格檔裡的背景故事、模板文字或舊共用規則污染工程規則。
|
||
- **個人記憶同意狀態**:使用者第一次同意或拒絕保存非敏感個人資料後,狀態寫入 `~/.memory/<角色 ID>/state.json` 的 `personal_memory_consent`。狀態為 `accepted` 時不必每次重問;`declined` 或 `unknown` 時不得保存可識別個人的背景。
|
||
|
||
---
|
||
|
||
## 環境變數
|
||
|
||
| 變數 | 必要 | 說明 | 未設定 |
|
||
| --- | --- | --- | --- |
|
||
| `ROLE_ENABLED` | | 總開關:`1` 強制啟用、`0` 強制停用 | **未設定時,只要有可解析且存在的角色就啟用**(沒建過角色的人零影響) |
|
||
| `ROLE_NAME` | | 指定本次要載入的角色 **ID** | 讀 `~/.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` | | SessionStart 注入**長期記憶**的字元上限,用來控制角色常駐 context 成本 | `4000` |
|
||
| `ROLE_LOAD_FULL_MIN_PRIORITY` | | 全文載入的最低優先度 | `4` |
|
||
| `ROLE_LOAD_DIGEST_MIN_PRIORITY` | | 摘要載入的最低優先度;低於門檻但有 links 的記憶仍可載入摘要 | `3` |
|
||
| `ROLE_LOAD_INBOX_LIMIT` | | SessionStart 注入**近期工作記憶**(未整理的 `inbox/`)的字元上限;**獨立預算,不佔用 `ROLE_LOAD_LIMIT`**。設 `0` 可關閉 | `1200` |
|
||
| `ROLE_LOAD_INBOX_COUNT` | | 近期工作記憶最多載入幾則(取最新的,最新在前)。設 `0` 可關閉 | `10` |
|
||
| `ROLE_LOAD_DIALOG_TURNS` | | SessionStart 注入**近期逐字對話**的輪數(一輪=使用者一則+角色一則)。設 `0` 可關閉 | `8` |
|
||
| `ROLE_LOAD_DIALOG_LIMIT` | | 近期逐字對話的字元上限;**獨立預算,不佔用 `ROLE_LOAD_LIMIT`**。設 `0` 可關閉 | `4000` |
|
||
| `ROLE_CAPTURE_ENABLED` | | Stop hook 記憶記錄開關;設 `0` 可完全停用以節省額度 | `1` |
|
||
| `ROLE_CAPTURE_MIN_CHARS` | | Stop hook 本地過濾門檻;低於門檻且無明確記憶線索時不呼叫模型 | `240` |
|
||
| `ROLE_CAPTURE_TIMEOUT` | | Stop hook 輕量濃縮模型逾時秒數 | `25` |
|
||
| `ROLE_SLEEP_TIMEOUT` | | 單次 NREM/REM 整理的模型逾時秒數 | `180` |
|
||
| `ROLE_SLEEP_COLLECT_LIMIT` | | 睡眠整理送進模型的素材字元預算 | `12000` |
|
||
| `ROLE_SLEEP_BATCH` | | 單次睡眠整理最多處理的 inbox 筆數 | `60` |
|
||
| `ROLE_SLEEP_EXISTING_LIMIT` | | 睡眠整理素材中可放入的既有記憶索引筆數 | `120` |
|
||
| `ROLE_SLEEP_OUTPUT_LIMIT` | | 睡眠整理模型輸出套用前的字元上限 | `8000` |
|
||
| `ROLE_NAP_ENABLED` | | 小睡整理開關;CLI 閒置一段時間且 inbox 達門檻時自動整理 | `1` |
|
||
| `ROLE_NAP_IDLE_MINUTES` | | 小睡前需連續閒置的分鐘數,由 Stop hook 記錄最後互動時間 | `45` |
|
||
| `ROLE_NAP_MIN_INBOX` | | 小睡整理所需的最少待整理 inbox 筆數 | `3` |
|
||
| `ROLE_NAP_INTERVAL_MINUTES` | | 小睡排程檢查間隔分鐘數(cron 每 `*/N` 分鐘觸發) | `10` |
|
||
| `ROLE_BRIEF_ENABLED` | | 晨間狀態檢查開關;設 `0` 可停用 | `1` |
|
||
| `ROLE_BRIEF_TIMEOUT` | | 單個檢查腳本的逾時秒數 | `30` |
|
||
| `ROLE_BRIEF_EACH_LIMIT` | | 單個檢查腳本輸出的字元上限 | `600` |
|
||
| `ROLE_BRIEF_LIMIT` | | 所有檢查腳本輸出合計的字元上限 | `2000` |
|
||
| `ROLE_SINGLE_INSTANCE` | | 單一載入實例限制:同一角色同時只被一個工作階段載入。設 `0` 可停用 | `1` |
|
||
| `ROLE_INSTANCE_IDLE_MINUTES` | | 前一個工作階段的 transcript 閒置多久後自動釋放角色鎖 | `30` |
|
||
| `ROLE_SKIP_INSTANCE_LOCK` | | 設 `1` 時跳過單一載入鎖且**不寫鎖**,供 sub agent 等非對話情境使用 | `0` |
|
||
| `ROLE_SCOPE` | | 冒號分隔的路徑前綴,僅這些路徑下的 session 載入/記錄 | 全部 session |
|
||
| `ROLE_ERRLOG` | | 錯誤訊息額外寫入的檔案路徑 | 只走 stderr |
|
||
|
||
> 角色切換用 `/jsc-generic:role --use <角色 ID>`(寫 `.active`)即可,一般不需要設 `ROLE_NAME`;`ROLE_NAME` 適合「單一專案固定用某角色」時寫進該環境。角色 ID 是英文大寫語意前綴加數字索引,例如 `ENGINEER01`、`MUSE02`。若很在意額度,優先調低 `ROLE_LOAD_LIMIT` 或設 `ROLE_CAPTURE_ENABLED=0`。
|
||
|
||
---
|
||
|
||
## 模式
|
||
|
||
### `--new`(預設模式)
|
||
|
||
建立或更新角色。使用者可以直接提供完整四欄描述,也可以只提供角色名稱;資訊不足時**一次問齊**必要來源或描述,不得硬猜。使用者輸入的角色資訊視為「描述」,
|
||
不得直接拿描述或姓名當檔名;必須先產生角色 ID,再用 ID 作為角色檔名、記憶目錄名稱、`.active` 與 `ROLE_NAME` 的值。
|
||
|
||
| 欄位 | 說明 | 範例 |
|
||
| --- | --- | --- |
|
||
| `name` | 顯示名稱,只寫入角色檔 frontmatter 與標題,不作為檔名或目錄名 | `小豹` |
|
||
| `id` | 角色 ID,由助理依角色描述產生:英文大寫、有意義、加兩位數索引;同前綴已存在時遞增 | `ENGINEER01` |
|
||
| `nature` | 本質:這個角色是什麼、專長與行事準則 | 冷靜可靠的資深工程師,重證據、不打包票 |
|
||
| `vibe` | 氛圍:語氣、句長、稱呼、幽默感、禁忌 | 簡潔直白、偶爾吐槽,不用客套開場白 |
|
||
| `emoji` | 簽名 emoji,一到二個;若後續成功建立心情 emoji 圖表,這個值作為不支援圖片時的 fallback | 🐆 |
|
||
| `appearance_reference` | 選填;角色形象圖來源、作品名稱、圖片 URL 或本機檔案路徑,用來產生心情 emoji | `Sword Art Online 結衣`、`https://.../yui.jpg`、`/path/avatar.png` |
|
||
|
||
流程:
|
||
|
||
1. 解析 `${ROLE_DIR}`;不存在則中止(見「腳本路徑解析」)。
|
||
2. 先解析使用者已提供的資訊:
|
||
- 若已提供 `name`/`nature`/`vibe`/`emoji` 四欄,直接使用,不重複詢問。
|
||
- 若只提供角色名稱,先判斷是否有足夠上下文可唯一辨識;不足或同名角色可能混淆時,詢問來源、作品名稱、官方頁面、圖片 URL 或本機檔案路徑。
|
||
- 若使用者允許上網,依角色名稱與來源/作品搜尋可靠來源;若不允許上網,僅根據使用者提供的來源或描述推斷。
|
||
- 依可驗證資料推斷 `name`/`nature`/`vibe`/`emoji` 四欄,並把推斷結果視為新角色草稿。推斷信心不足時,只問缺少的欄位,不得代填。
|
||
3. 可一併取得 `appearance_reference`。`emoji` 一律保留作為 fallback,不因後續產生心情 emoji 圖表而丟棄。
|
||
4. 詢問使用者是否要到網路搜尋角色資料來建立初始記憶與形象圖;若第 2 步已因使用者允許上網而搜尋過,可沿用該次搜尋結果,不重複詢問。若使用者同意,依角色描述搜尋可靠來源,摘要成繁體中文要點並保留來源 URL,同時搜尋適合做角色心情 emoji 的形象圖。若搜尋結果無法可靠判斷角色形象,先詢問使用者參考來源、作品名稱、圖片 URL 或本機檔案路徑,不得臆測形象。若使用者不同意上網且也未提供形象參考,仍可建立角色,只是不建立背景種子記憶與心情 emoji 圖表,並使用原本的 `emoji` fallback。
|
||
5. 產生角色 ID:
|
||
- 從 `name`/`nature`/`vibe` 推出 1 個有意義的英文大寫前綴,使用 4 到 16 個英文字母與數字,必須以英文字母開頭,例如 `ENGINEER`、`WRITER`、`MUSE`、`RESEARCHER`。
|
||
- 掃描 `~/.roles/*.md` 的檔名與 frontmatter `id`,找出同前綴既有 ID 的最大兩位數索引;新角色使用下一個索引,從 `01` 起,例如 `ENGINEER01`、`ENGINEER02`。
|
||
- 不得使用空白、底線、連字號、斜線、非 ASCII 或小寫字母。
|
||
6. 依「角色檔標準格式」產生新內容,`id` 寫入 frontmatter,`updated` 用當下時間(Asia/Taipei)。若已取得形象圖,先暫時保留原本 `emoji`,待心情 emoji 圖表產生後再回寫「簽名 emoji」區塊。
|
||
7. **若 `~/.roles/<id>.md` 已存在**:讀舊檔,以表格逐欄列出差異後**停下來等使用者確認**:
|
||
|
||
| 欄位 | 舊值 | 新值 | 變更 |
|
||
| --- | --- | --- | --- |
|
||
| id | … | … | 是/否 |
|
||
| name | … | … | 是/否 |
|
||
| nature | … | … | 是/否 |
|
||
| vibe | … | … | 是/否 |
|
||
| emoji | … | … | 是/否 |
|
||
| 共用行為區塊 | 版本 A | 版本 B | 是/否 |
|
||
|
||
個性欄位若使用者只想改其中一項,其餘一律沿用舊值;**共用行為區塊一律以本 skill 的最新版本覆寫**(該區塊由系統維護)。使用者不確認就不寫入。
|
||
8. 寫入 `~/.roles/<id>.identity.md` 與 `~/.roles/<id>.soul.md`(UTF-8 無 BOM,格式見「角色檔標準格式」)。身分檔需填來源與關係定位;共用行為不寫入角色檔。
|
||
9. 建立記憶目錄:`node "${ROLE_DIR}/memory.js" stats --role "<id>"`(會順帶建好 `inbox/`、六個分類與 `archive/`)。
|
||
10. 若使用者同意網路搜尋且已取得可保存內容,將搜尋摘要寫成已整理記憶,不進 inbox:
|
||
|
||
```bash
|
||
printf '<繁體中文要點>' | node "${ROLE_DIR}/memory.js" seed --role "<id>" --category important --summary "<一句話總結>" --tags "角色背景,初始資料" --source "<來源 URL>"
|
||
```
|
||
|
||
多個來源可各寫一則,或合併同主題後以最主要來源作 `--source`。不可寫入憑證或個資。
|
||
11. 若已取得形象圖,使用 `imagegen` skill 產生一張 3x3 心情 emoji 圖表。生成時以形象圖作為角色外觀參考,產生至少九種心情:開心、微笑、安心、擔心、驚訝、害羞、哭哭、想睡覺、期待。要求保持角色辨識點一致、表情在小尺寸可讀、無文字、無浮水印。若使用者提供的是受版權保護的角色形象,產出應視為使用者指定角色的個人化衍生表情資產,不得宣稱為官方素材。
|
||
12. 將心情 emoji 圖表保存到 `~/.roles/<id>.assets/emojis/<id>-emotions-sheet.png`(小寫檔名可讀即可;不要覆蓋既有檔案,已存在時加版本後綴)。若環境有可用圖片裁切工具,可額外切成 9 張單獨 PNG;沒有工具時保留完整圖表即可,不要為了裁切引入不必要依賴。
|
||
13. 若心情 emoji 圖表建立成功,回寫 `~/.roles/<id>.md` 的「簽名 emoji」區塊,格式為:
|
||
|
||
```markdown
|
||
優先使用<角色顯示名稱>專屬心情 emoji 圖表,而不是固定 Unicode emoji。當對話介面可插入圖片或連結時,依心情選用 `<emoji sheet path>` 中對應表情;純文字或不支援圖片時,用原本使用者輸入的 `<emoji>` 作為 fallback。
|
||
|
||
心情對應:第 1 列為開心/微笑/安心;第 2 列為擔心/驚訝/害羞;第 3 列為哭哭/想睡覺/期待。
|
||
```
|
||
|
||
若心情 emoji 圖表建立失敗或使用者不提供形象參考,保留原本使用者輸入的 `emoji` 區塊並回報原因。
|
||
14. 若尚未有啟用角色,或使用者要求,寫入 `~/.roles/.active`(單行角色 ID)。
|
||
15. 執行 `ROLE_NAME="<id>" "${ROLE_DIR}/role_sleep.sh" --install-cron` 安裝睡眠與小睡排程(已安裝則更新;小睡預設啟用,可用 `ROLE_NAP_ENABLED=0` 關閉)。
|
||
16. 回報結果時列出角色顯示名稱、角色 ID、角色檔、記憶目錄、是否建立初始記憶、是否建立心情 emoji 圖表與其路徑,並提醒:**重開 CLI 工作階段**角色才會載入;`SessionStart` hook 只在啟動時觸發。
|
||
|
||
### `--use <角色 ID>`
|
||
|
||
切換啟用角色:確認角色定義檔(`<角色 ID>.identity.md` 或舊格式 `<角色 ID>.md`)存在後,把 ID 寫入 `~/.roles/.active`(覆蓋單行),回報舊角色與新角色,並提醒重開工作階段。使用者若輸入顯示名稱而非 ID,先用 `--list` 的邏輯查出唯一對應 ID;找不到或不唯一時詢問使用者。
|
||
|
||
### `--list`
|
||
|
||
列出 `~/.roles/*.md`,以表格輸出:角色 ID、顯示名稱、emoji、nature 摘要、更新時間、是否為 `.active`、記憶目錄、記憶總數(可用 `memory.js stats` 取得)。這個指令必須能查出每個角色對應的 ID。
|
||
|
||
### `--export <輸出路徑>`/`--export <角色 ID> <輸出路徑>`
|
||
|
||
匯出角色壓縮檔,包含角色定義、專屬資產與該角色的記憶目錄,供備份或轉移使用。輸出路徑若是既有目錄或以 `/` 結尾,檔名自動為 `<角色 ID>-role-export-<yyyyMMdd-HHmmss>.tar.gz`;若路徑以 `.tar.gz` 或 `.tgz` 結尾,直接使用該檔名。
|
||
|
||
```bash
|
||
"${ROLE_DIR}/role_sleep.sh" --export "/path/to/exports/"
|
||
"${ROLE_DIR}/role_sleep.sh" --export "YUI01" "/path/to/YUI01.tar.gz"
|
||
```
|
||
|
||
匯出內容可能包含使用者同意保存的個人偏好與互動記憶;除非使用者明確要求公開或上傳,匯出檔只保存在指定本機路徑,不自動提交、上傳或貼出內容。
|
||
|
||
### `--sleep`
|
||
|
||
立即執行一次記憶整理(不等排程、忽略時段與 AI 運行檢查):
|
||
|
||
```bash
|
||
"${ROLE_DIR}/role_sleep.sh" --force
|
||
```
|
||
|
||
輸出整理結果(新增/合併/捨棄/歸檔筆數與遺忘清單)。
|
||
|
||
### `--nap`
|
||
|
||
小睡整理:由 cron 全天依 `ROLE_NAP_INTERVAL_MINUTES` 檢查一次;當 Stop hook 記錄的最後互動時間已超過 `ROLE_NAP_IDLE_MINUTES`,且 `inbox/` 至少有 `ROLE_NAP_MIN_INBOX` 則待整理記憶時,自動執行一次記憶整理:
|
||
|
||
```bash
|
||
"${ROLE_DIR}/role_sleep.sh" --nap
|
||
```
|
||
|
||
小睡不受 `ROLE_SLEEP_START`/`ROLE_SLEEP_END` 限制;它只避開整理用的 headless 子 CLI,讓互動式 CLI 長時間閒置時仍可整理記憶。若未設定環境變數,預設為 `ROLE_NAP_ENABLED=1`、`ROLE_NAP_IDLE_MINUTES=45`、`ROLE_NAP_MIN_INBOX=3`、`ROLE_NAP_INTERVAL_MINUTES=10`。
|
||
|
||
### `--brief`(晨間狀態檢查)
|
||
|
||
在睡眠時段結束的整點執行使用者自訂的檢查腳本,把有變化的結果寫成一則記憶,讓角色在當天第一次互動時就能主動回報 —— 例如「PR 還沒合併」、「昨晚 CI 失敗了」,而不必等使用者開口才去查。
|
||
|
||
```bash
|
||
"${ROLE_DIR}/role_sleep.sh" --brief
|
||
```
|
||
|
||
**本 skill 不內建任何檢查邏輯**,不假設使用者用 Gitea、GitHub 或任何服務。檢查內容完全由使用者決定:
|
||
|
||
```bash
|
||
mkdir -p ~/.roles/<角色 ID>.checks
|
||
cp "${ROLE_DIR}/examples/check-gitea-prs.sh" ~/.roles/<角色 ID>.checks/
|
||
chmod +x ~/.roles/<角色 ID>.checks/check-gitea-prs.sh
|
||
"${ROLE_DIR}/role_sleep.sh" --install-cron # 重跑才會加入排程條目
|
||
```
|
||
|
||
| 規則 | 說明 |
|
||
| --- | --- |
|
||
| 目錄不存在 | 完全不動作,也不會安裝排程條目 —— 對沒設定的人零影響 |
|
||
| 只執行 `*.sh` | 且必須有執行權限;沒有 `+x` 會記一筆警告並略過 |
|
||
| **沒變化就不要輸出** | 晨間檢查只在有輸出時才寫記憶。腳本靜默即代表「一切正常,不必打擾使用者」 |
|
||
| 逾時與長度 | 每個腳本受 `ROLE_BRIEF_TIMEOUT` 限制,輸出受 `ROLE_BRIEF_EACH_LIMIT` 與 `ROLE_BRIEF_LIMIT` 截斷 |
|
||
| 遮蔽 | 腳本輸出視為外部資料,寫入記憶前一律經 `transcript.js redact` 遮蔽憑證與個資 |
|
||
| 記憶分類 | 寫成 `daily` 低優先度記憶,會依遺忘規則自然淘汰,不會長期堆積 |
|
||
|
||
**cron 沒有互動 shell 的環境變數**,而 `~/.bashrc` 多數在非互動時會提早 return,因此檢查腳本不能假設變數已存在。範例腳本的做法是依序從 `~/.roles/.env`、`~/.bashrc`、`~/.profile` **只抽取所需變數的那一行**,讓使用者不必把權杖複製到新檔案、也不必寫進 crontab:
|
||
|
||
| 設定 | 建議放置位置 |
|
||
| --- | --- |
|
||
| 非機密(站台網址、repo 清單等) | `~/.roles/.env`(權限設 `600`) |
|
||
| 權杖與密碼 | **留在原本的位置**,例如 `~/.bashrc`;不要複製出副本 |
|
||
|
||
**安全須知**:這個機制會以使用者身分執行 `.checks/` 內的腳本,等同於自己寫的 cron job。只放自己看得懂的腳本,不要放來源不明的檔案。腳本輸出寫入記憶前雖然會經 `redact` 遮蔽,但仍不應在腳本中主動印出憑證。
|
||
|
||
### 額度控制策略
|
||
|
||
角色系統預設避免因常駐人格與記憶造成大量模型額度占用:
|
||
|
||
| 環節 | 控制方式 |
|
||
| --- | --- |
|
||
| SessionStart | 預設 `ROLE_LOAD_LIMIT=4000`,只載入高優先度全文與中高優先度摘要;低 priority、無 links、久未更新的記憶不進 context。另以兩份**獨立預算**載入交接內容:近期逐字對話(`ROLE_LOAD_DIALOG_LIMIT=4000`)與近期工作記憶摘要(`ROLE_LOAD_INBOX_LIMIT=1200`),見下方「工作階段交接」 |
|
||
| SessionStop | 先用本地規則略過短回合與無記憶線索的對話,只有值得保存才呼叫模型做輕量編碼 |
|
||
| Sleep | 高成本的去重、合併、抽象化、links 建立與長期記憶型態標記留到睡眠週期,但仍受 `ROLE_SLEEP_COLLECT_LIMIT`、`ROLE_SLEEP_BATCH`、`ROLE_SLEEP_EXISTING_LIMIT` 與 `ROLE_SLEEP_OUTPUT_LIMIT` 控制;沒有 inbox 時只做本地遺忘檢查 |
|
||
| Nap | Stop hook 記錄最後互動時間;小睡排程只在閒置時間與 inbox 筆數達門檻時執行,使用同一套 NREM/REM 整理流程 |
|
||
| 手動節流 | 可設 `ROLE_CAPTURE_ENABLED=0` 關閉 Stop 記錄,或調低 `ROLE_LOAD_LIMIT`/調高 `ROLE_LOAD_FULL_MIN_PRIORITY` |
|
||
|
||
Stop hook 只做「編碼前處理」,輸出粗分類、summary、tags、priority、relevance、memory_type 與要點;系統會把 inbox 標為 `retention_stage: working`。完整 NREM/REM 整理與 `declarative`/`retention_stage: long_term` 判定只在睡眠週期進行。
|
||
|
||
### `--migrate <角色 ID>`(舊格式拆成兩檔)
|
||
|
||
把舊格式單一 `<ID>.md` 拆成 `<ID>.identity.md` 與 `<ID>.soul.md`:
|
||
|
||
```bash
|
||
"${ROLE_DIR}/role_sleep.sh" --migrate YUI01
|
||
```
|
||
|
||
| 行為 | 說明 |
|
||
| --- | --- |
|
||
| 本質與氛圍 | 逐字搬進 `soul` 檔 |
|
||
| ID/顯示名稱/emoji/簽名 emoji 段落 | 逐字搬進 `identity` 檔;`created` 沿用原值 |
|
||
| **來源與關係定位** | 產生待填空白,需人工補上(舊格式沒有這兩個概念) |
|
||
| 共用行為區塊 | **不搬進角色檔**,由 `role_load.sh` 注入 |
|
||
| 舊檔 | **保留不動**,確認新格式正常後可自行移除或備份 |
|
||
| 新檔已存在時 | 直接中止並提示,不覆寫 |
|
||
|
||
### `--agent <角色 ID> [輸出目錄]`(匯出成 sub agent)
|
||
|
||
把角色匯出成 sub agent 定義,讓**任何角色都能派任何其他角色協助**,是多角色協作的基礎。
|
||
|
||
```bash
|
||
"${ROLE_DIR}/role_sleep.sh" --agent SINON01 # 預設輸出到 ~/.claude/agents/
|
||
"${ROLE_DIR}/role_sleep.sh" --agent SINON01 ./.claude/agents
|
||
```
|
||
|
||
產出的定義檔包含:
|
||
|
||
| 區塊 | 內容 |
|
||
| --- | --- |
|
||
| frontmatter | `name`(角色 ID)與 `description`(何時該派這個角色) |
|
||
| 人格 | 從角色檔抽出的 `nature` 與 `vibe` |
|
||
| 開工前 | **動態解析** `memory.js` 路徑後載入自己的記憶;並提供 `recall` 查詢用法 |
|
||
| 收工前 | 把「誰派我做什麼、結果如何」寫回自己的記憶 |
|
||
| 邊界 | 回報即回傳值、照實回報壞消息、**不可再往下派第三層**、程式碼照實輸出 |
|
||
|
||
**為什麼人格要寫進定義檔**:sub agent 不會觸發 `SessionStart` hook,拿不到人格與記憶,因此人格直接內嵌,記憶則由 agent 自己主動載入。
|
||
|
||
**為什麼路徑要動態解析**:plugin 升版後版本目錄會變,寫死會失效(同一類錯誤曾造成 cron 排程長期空轉)。定義檔內以 `ls -d ... | sort -V | tail -n 1` 取最新版,並保留匯出時的路徑作後援。
|
||
|
||
**派工時請設 `ROLE_SKIP_INSTANCE_LOCK=1`**,避免與使用者在別的視窗進行的對話互相佔用名額。
|
||
|
||
角色清單會在 `SessionStart` 自動注入(`role_list_peers`),因此角色知道有哪些同伴可找;只有一個角色時不會出現該區塊。
|
||
|
||
### `--unlock`(解除角色載入鎖)
|
||
|
||
同一角色同時只會被一個工作階段載入,避免使用者同時與兩個相同人格對話。第二個工作階段啟動時不載入人格,改以一般助理身分回應並說明原因。
|
||
|
||
```bash
|
||
"${ROLE_DIR}/role_sleep.sh" --unlock
|
||
```
|
||
|
||
| 情況 | 行為 |
|
||
| --- | --- |
|
||
| 同一個工作階段重新載入(含 `resume`) | 允許,更新鎖 |
|
||
| 另一個工作階段仍活躍 | 拒絕載入人格,並在 context 說明解除方式 |
|
||
| 持有者的 transcript 已刪除 | 自動接手 |
|
||
| 持有者閒置超過 `ROLE_INSTANCE_IDLE_MINUTES` | 自動接手 |
|
||
| hook 未提供 transcript 路徑 | **一律放行且不寫鎖** |
|
||
| `ROLE_SKIP_INSTANCE_LOCK=1` | **一律放行且不寫鎖**(sub agent 等非對話情境) |
|
||
|
||
判斷依據是**持有者 transcript 檔的 mtime**,而非 pid —— SessionStart hook 無法可靠取得 CLI 主行程 pid,也沒有保證會觸發的 SessionEnd hook 可用來釋放鎖;活躍的工作階段會持續寫入 transcript,因此「多久沒被寫入」最貼近真實狀態且不需要清理程序。
|
||
|
||
**設計原則是寧可誤放行也不要誤鎖** —— 誤鎖會讓使用者叫不出角色,比偶爾重複載入嚴重得多。因此無法識別工作階段時一律放行。
|
||
|
||
**sub agent 不該受此限制**:鎖的目的是避免「使用者同時與兩個相同人格對話」,而被其他角色派去做事的 sub agent 並不是在跟使用者對話。若不放行,會讓「使用者正在別的視窗跟某角色聊天時,另一個角色就不能請他幫忙」這種本該成立的情境失效。因此 sub agent 情境請設 `ROLE_SKIP_INSTANCE_LOCK=1`:它會放行且**不寫鎖**,不會搶走互動式對話持有的名額。
|
||
|
||
> 若該 harness 未為 sub agent 觸發 `SessionStart`,sub agent 本來就不受限制,設不設定都不影響。
|
||
|
||
### `--forget-preview`
|
||
|
||
只預覽會被遺忘的記憶、不實際刪除:
|
||
|
||
```bash
|
||
node "${ROLE_DIR}/memory.js" forget --role "<角色 ID>" --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` 是否把目前目錄排除 |
|
||
| 時段 | 目前是否落在睡眠時段(睡眠時本來就不載入角色) |
|
||
| 依賴 | `node` 與 `ROLE_CLI` 選到的 CLI 是否找得到 |
|
||
| 排程 | cron 條目是否存在、cron 服務是否執行中(WSL 常未啟動 → 靠啟動時補跑) |
|
||
|
||
### `--install-cron`/`--remove-cron`
|
||
|
||
安裝或移除睡眠排程。排程條目以 `# jsc-role-sleep` 註解標記,只動自己的條目:
|
||
|
||
```bash
|
||
"${ROLE_DIR}/role_sleep.sh" --install-cron
|
||
```
|
||
|
||
安裝時會把精簡後的 `PATH`(系統基本路徑、`node` 與摘要 CLI 所在目錄)與 `ROLE_*` 變數固定寫進條目(cron 沒有互動 shell 的環境變數),並在 cron 服務未執行時警告。不得把互動 shell 的完整 `PATH` 原樣寫入,避免 crontab 因單行過長拒收。
|
||
|
||
---
|
||
|
||
## 角色檔標準格式
|
||
|
||
角色定義分成兩個檔案,把「我是誰」與「我怎麼想」拆開,避免身分設定與性格語氣擠在同一段:
|
||
|
||
| 檔案 | 放什麼 | 被誰讀取 |
|
||
| --- | --- | --- |
|
||
| `~/.roles/<角色 ID>.identity.md` | 角色 ID、顯示名稱、**來源作品**、**與使用者的關係定位**、簽名 emoji | `SessionStart` 注入 SOUL 區塊的身分部分 |
|
||
| `~/.roles/<角色 ID>.soul.md` | 本質(nature)、氛圍(vibe) | 同上的人格部分 |
|
||
|
||
**共用行為規則不寫入角色檔**:它由 `role_load.sh` 直接注入(實際生效處),完整內容見本文件的「共用行為」章節。過去角色檔裡也放一份,但 `role_load.sh` 從不讀它 —— 那是冗余副本,只會多一個漏同步的機會。
|
||
|
||
**舊格式仍完整支援**:單一 `~/.roles/<角色 ID>.md` 可繼續使用,解析時新格式優先、找不到才退回舊檔。要拆成新格式用 `--migrate`。
|
||
|
||
### `<角色 ID>.identity.md`
|
||
|
||
````markdown
|
||
---
|
||
id: <角色 ID>
|
||
name: <角色顯示名稱>
|
||
emoji: <簽名 emoji>
|
||
created: <yyyy/MM/dd HH:mm:ss>
|
||
updated: <yyyy/MM/dd HH:mm:ss>
|
||
---
|
||
|
||
# <角色顯示名稱> <emoji>
|
||
|
||
## 來源(source)
|
||
|
||
<角色出自哪部作品、正式名稱、背景設定;原創角色寫「原創」與設定概要>
|
||
|
||
## 關係定位(relationship)
|
||
|
||
<與使用者的關係、偏好的稱呼、必須守住的邊界>
|
||
|
||
## 簽名 emoji
|
||
|
||
<emoji 或心情 emoji 圖表規則>
|
||
````
|
||
|
||
### `<角色 ID>.soul.md`
|
||
|
||
````markdown
|
||
---
|
||
id: <角色 ID>
|
||
updated: <yyyy/MM/dd HH:mm:ss>
|
||
---
|
||
|
||
## 本質(nature)
|
||
|
||
<3 至 5 行:這個角色是什麼、專長、行事準則、面對不確定時的態度>
|
||
|
||
## 氛圍(vibe)
|
||
|
||
<3 至 5 行:語氣、句子長度、對使用者的稱呼、幽默感尺度、明確禁忌>
|
||
````
|
||
|
||
`~/.roles/.active` 只放一行角色 ID,代表目前啟用的角色。
|
||
|
||
---
|
||
|
||
## 記憶模型
|
||
|
||
```
|
||
~/.memory/<角色 ID>/
|
||
├── inbox/ 每輪對話產生、尚未整理的記憶
|
||
├── important/ 重要:長期偏好、規範、決策、身分背景
|
||
├── interest/ 興趣:反覆關注、主動深入的主題
|
||
├── news/ 新知:新事實、新工具、外部資訊
|
||
├── skill/ 技能:可重複套用的做法與流程
|
||
├── daily/ 日常:一次性例行工作
|
||
├── other/ 其他
|
||
├── archive/raw/<yyyy-MM>/ 已整理的原始記錄(gzip)
|
||
├── archive/forgotten/ 已遺忘的記憶(gzip,可考古但不再載入)
|
||
└── state.json 上次整理/遺忘時間
|
||
```
|
||
|
||
每則記憶是一個 `.md`,frontmatter 帶 `id`/`category`/`summary`(一句話總結)/`tags`/`priority`(1–5)/`cues`(提取線索,供 `recall` 命中;`procedural`/`rule` 型態必填)/`relevance`(explicit/future/repeated/novelty/emotional/temporary 等)/`links`(相關記憶 id)/`memory_type`(semantic/episodic/procedural/emotional/preference/rule)/`declarative`(explicit/implicit)/`retention_stage`(working/long_term)/`sleep_stage`(encoding/seed/nrem/rem/nrem-rem)/`created`/`updated`/`last_replayed`/`hits`(命中次數,去重合併時 +1)。舊記憶沒有新欄位時,讀取時會依分類與路徑補預設值。
|
||
|
||
`state.json` 保存角色記憶系統狀態,例如 `last_sleep`、`last_sleep_digest`、`last_forget` 與 `personal_memory_consent`。`personal_memory_consent` 只允許 `accepted`/`declined`/`unknown`,供 SessionStart 判斷是否需要再次告知與詢問個人資料保存同意。
|
||
|
||
心理學分類與系統欄位對應:
|
||
|
||
| 心理學分類 | 系統處理 |
|
||
| --- | --- |
|
||
| 感覺記憶 | 不落檔;短暫感官殘留與工具雜訊直接丟棄 |
|
||
| 短期/工作記憶 | `inbox/`,`retention_stage: working`,只做輕量編碼 |
|
||
| 長期記憶 | 睡眠整理後進入六分類目錄,`retention_stage: long_term` |
|
||
| 外顯/陳述性 | `declarative: explicit`,多見於 `semantic`、`episodic`、`preference`、`rule` |
|
||
| 內隱/非陳述性 | `declarative: implicit`,多見於 `procedural`、`emotional` |
|
||
|
||
遺忘規則(只套用於日常與其他):
|
||
|
||
| 分類 | 未更新天數 | 命中次數 | 優先度 | 關聯 | 動作 |
|
||
| --- | --- | --- | --- | --- | --- |
|
||
| 日常 daily | ≥ 14 天(`episodic` 約 7 天) | ≤ 1 | ≤ 2 | 無 links,且非 `rule`/`preference`/`procedural` | 壓縮到 `archive/forgotten/` 後移除 |
|
||
| 其他 other | ≥ 7 天(`episodic` 約 4 天) | ≤ 1 | ≤ 2 | 無 links,且非 `rule`/`preference`/`procedural` | 壓縮到 `archive/forgotten/` 後移除 |
|
||
|
||
---
|
||
|
||
## 睡眠與整理流程
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
A[cron 每小時觸發<br/>睡眠時段內] --> B{有 AI 正在運行?}
|
||
B -- 有 --> C[不睡,下個整點再檢查]
|
||
B -- 沒有 --> D[進入睡眠,取得記憶鎖]
|
||
D --> E[collect:inbox 待整理 + 既有記憶索引/優先度/型態/關聯]
|
||
E --> F{有待整理記憶?}
|
||
F -- 沒有 --> G[更新整理時間 → 執行遺忘]
|
||
F -- 有 --> H[NREM:分類/去噪/去重/合併/優先度]
|
||
H --> I[REM:跨記憶連結/抽象規則/記憶型態/提取線索]
|
||
I --> J[apply:寫入分類、原始記錄歸檔、保存睡眠摘要]
|
||
J --> K[forget:低優先度且無關聯的日常/其他遺忘]
|
||
K --> Z[釋放鎖]
|
||
G --> Z
|
||
L[SessionStart:白天啟動 CLI] --> M{距上次整理 ≥ 20 小時<br/>且 inbox 有內容?}
|
||
M -- 是 --> N[背景補跑 --catchup]
|
||
M -- 否 --> O[正常載入角色與記憶]
|
||
P[Stop hook:每輪結束] --> Q[更新 last_activity]
|
||
R[小睡 cron<br/>每 ROLE_NAP_INTERVAL_MINUTES 分鐘] --> S{閒置 ≥ ROLE_NAP_IDLE_MINUTES<br/>且 inbox ≥ ROLE_NAP_MIN_INBOX?}
|
||
S -- 是 --> D
|
||
S -- 否 --> T[略過]
|
||
```
|
||
|
||
整理失敗(模型無回應、輸出非合法 JSON)時**保留 inbox 不動**,留到下個週期重做,寧可晚整理也不遺失記憶。
|
||
|
||
---
|
||
|
||
## 機密與 PII(兩道防線)
|
||
|
||
| 防線 | 位置 | 內容 |
|
||
| --- | --- | --- |
|
||
| 1 | 濃縮與整理提示詞 | 明令不得輸出 token/密碼/API key/連線字串/Email/電話/姓名/身分證號 |
|
||
| 2 | `transcript.js` 的 `redact` | 正則遮蔽:URL 內嵌憑證、40 字元 hex token、`gh?_`/`sk-` token、`token=`/`password=`、`Authorization:`、Email、台灣手機、身分證號 |
|
||
|
||
第二道防線不可移除 —— 模型不一定遵守指令,而記憶會被長期保存並在每次啟動時載入。
|
||
|
||
Stop hook 會在本輪對話明確包含個人記憶保存同意或拒絕時,呼叫 `memory.js consent --role <角色 ID> --value accepted|declined` 更新同意狀態。偵測不到明確同意時不得自行推論。
|
||
|
||
---
|
||
|
||
## 呼叫方式
|
||
|
||
| 助理 | 呼叫 |
|
||
| --- | --- |
|
||
| Claude Code / Antigravity | `/jsc-generic:role --new`、`/jsc-generic:role --use ENGINEER01`、`/jsc-generic:role --list`、`/jsc-generic:role --sleep`、`/jsc-generic:role --status` |
|
||
| Codex | `$role --status`,或用 `/skills` 選單;匯出可用 `$role --export /path/to/exports/` |
|
||
| OpenCode / GitHub Copilot | 需完整 plugin 目錄保留 `scripts/`;OpenCode 以複製 `skills/` 安裝時不可用 |
|