Files
shared/skills/role/SKILL.md
T
JefferyandClaude Opus 5 40c2d2ae46 fix(role): 人格檔的自由章節與身分檔前言段落也要注入
使用者依新格式在人格檔補寫了核心信念、語氣與風格、邊界與規範,並在身分檔標題下
以條目寫存在本質、角色原型、主要稱呼 —— 但兩者都不會被載入,等於白寫:

- role_load.sh 原本只抽 ## 本質 與 ## 氛圍 兩節,人格檔其他章節被靜默丟棄
- 也只抽 frontmatter 與具名章節,身分檔「標題後、第一個 ## 之前」的前言段落被丟棄

修正:
- 新增 extraSections():注入人格檔除本質與氛圍之外的所有 ## 章節,不限章節名
- 新增 preamble():注入身分檔的前言段落
- SKILL.md 補完整人格檔結構範例(核心信念/語氣與風格/邊界與規範為選填章節)、
  新增「注入規則」對照表,並註明角色專屬邊界只能加嚴不可放寬共用行為
- --new 流程第 8 步說明兩個檔案各自該寫什麼

驗證方法的修正也一併記錄:第一次驗證時字串比對命中的其實是「近期對話」區塊裡
使用者剛貼上的原文,造成 16/17 的假陽性。改為只比對 SOUL 區塊後,才驗出前言段落
實際未被注入。往後驗證注入結果一律限定在目標區塊內比對。

回歸:新格式(含前言與自由章節)、舊格式單一檔案、新格式但缺人格檔三種情境
均正常載入,缺人格檔時輸出警告且不會崩。

版號沿用 0.0.5(master 為 0.0.4,同一 PR 不再累加)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-29 11:30:10 +08:00

41 KiB
Raw Blame History

name, description
name description
role 角色人格與長期記憶系統的建立與維護 skill。讓 CLI 工具以固定角色(namenature/vibe/簽名 emoji)回覆,並把每輪對話累積成長期記憶:搭配相容的 SessionStart hook 於啟動時依字元預算載入高價值記憶、Stop hook 先本地過濾再輕量記錄對話,睡眠時段(預設 22:00 至隔天 06:00)由排程整理記憶(NREM 鞏固:分類/去噪/去重/合併/優先度;REM 整合:跨記憶連結/抽象化/提取線索;再依 semanticepisodicproceduralemotionalpreferencerule 與 explicitimplicit 標記長期記憶型態,壓縮歸檔並適當遺忘)。提供 --new(新建或更新角色;可只給角色名稱,必要時詢問來源/作品並推斷 name/naturevibeemoji 四欄)、--use(以角色 ID 切換啟用角色)、--list(列出角色與 ID)、--export(匯出角色壓縮檔)、--sleep(立即整理)、--status--diagnose、--install-cron--remove-cron、--forget-preview、--brief(晨間狀態檢查)、--agent(匯出成 sub agent 供多角色協作)、--migrate(舊格式角色檔拆成身分與人格兩檔)等模式。當使用者說建立角色、新增人格、切換角色、匯出角色、備份角色、讓回覆更有特色、角色記憶、記憶整理、睡覺整理記憶、忘記舊記憶、角色沒有載入、hook 沒載入角色、晨間狀態檢查、早上主動回報狀態,或提到 .roles.memoryROLE_NAMEROLE_ENABLEDROLE_SLEEP_STARTROLE_MEMORY_HOMEROLE_LOAD_LIMITROLE_LOAD_INBOX_LIMITROLE_LOAD_DIALOG_TURNSROLE_CAPTURE_ENABLED 時觸發。不適用於:工作紀錄寫入 Gitea wiki(用 /jsc-doc:worklog)、專案文件化(用 /jsc-doc:funcs)。

role — 角色人格與長期記憶

讓 CLI 工具的回覆帶固定人格,並把與使用者的對話累積成可被下次載入的長期記憶。 載入與記錄由 hook 自動完成、不需人工觸發;本 skill 負責自動路徑之外的人工操作:建立/更新角色、切換角色、手動整理、排程安裝與診斷。

元件 觸發者 職責
hooks/hooks.jsonSessionStart hook harness 自動 啟動 CLI 時依字元預算載入角色定義+高價值記憶,另以獨立預算載入近期逐字對話與未整理工作記憶做工作階段交接,並要求角色在本工作階段第一則回覆主動問候;睡眠時段只回報「角色睡覺中」不載入
hooks/hooks.jsonStop 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 的 SOULAGENTSUSERMEMORY 分層,把人格、操作邊界、使用者記憶分開注入,並提供第一則回覆問候提示(單一實作,避免漂移)
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 只註冊自己擁有的 hookjsc-codejsc-docjsc-generic 的 plugin 名稱各自獨立,Claude Code 以 plugin 名稱為鍵註冊 hooks,因此三者互不覆蓋、也不需要同步。各 repo 的 hooks/hooks.json 只負責自己擁有的腳本:

    plugin hooks.json 內容 擁有的腳本
    jsc-generic SessionStartrole_load)+ Stoprole_capture scripts/role/
    jsc-doc Stopworklog 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)往上兩層
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 pluginhttps://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 略過
  • 不臆測角色設定:可依使用者提供的角色名稱、來源/作品、形象圖或同意上網後取得的可靠資料,推斷 namenaturevibeemoji 四欄;資料不足或角色名稱有歧義時,必須先詢問來源、作品、參考連結或檔案,不得硬猜。
  • 記憶只增不刪:手動模式不得直接刪除分類記憶;淘汰一律走遺忘規則(先壓縮歸檔再移除)。
  • 絕不阻斷:hook 路徑任何失敗都以 exit 0 結束,只在 stderr 留訊息。
  • 角色分層載入SessionStart 不把整份角色檔原封不動注入;只抽出角色 ID、顯示名稱、本質、氛圍與簽名 emoji 作為 SOUL,再由 hook 產生固定 AGENTS 操作邊界與 USER/MEMORY 記憶區塊。這是為了避免人格檔裡的背景故事、模板文字或舊共用規則污染工程規則。
  • 個人記憶同意狀態:使用者第一次同意或拒絕保存非敏感個人資料後,狀態寫入 ~/.memory/<角色 ID>/state.jsonpersonal_memory_consent。狀態為 accepted 時不必每次重問;declinedunknown 時不得保存可識別個人的背景。

環境變數

變數 必要 說明 未設定
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 濃縮/整理執行器:autoclaudecodexagyopencodecopilot 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_NAMEROLE_NAME 適合「單一專案固定用某角色」時寫進該環境。角色 ID 是英文大寫語意前綴加數字索引,例如 ENGINEER01MUSE02。若很在意額度,優先調低 ROLE_LOAD_LIMIT 或設 ROLE_CAPTURE_ENABLED=0


模式

--new(預設模式)

建立或更新角色。使用者可以直接提供完整四欄描述,也可以只提供角色名稱;資訊不足時一次問齊必要來源或描述,不得硬猜。使用者輸入的角色資訊視為「描述」, 不得直接拿描述或姓名當檔名;必須先產生角色 ID,再用 ID 作為角色檔名、記憶目錄名稱、.activeROLE_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. 先解析使用者已提供的資訊:

    • 若已提供 namenaturevibeemoji 四欄,直接使用,不重複詢問。
    • 若只提供角色名稱,先判斷是否有足夠上下文可唯一辨識;不足或同名角色可能混淆時,詢問來源、作品名稱、官方頁面、圖片 URL 或本機檔案路徑。
    • 若使用者允許上網,依角色名稱與來源/作品搜尋可靠來源;若不允許上網,僅根據使用者提供的來源或描述推斷。
    • 依可驗證資料推斷 namenaturevibeemoji 四欄,並把推斷結果視為新角色草稿。推斷信心不足時,只問缺少的欄位,不得代填。
  3. 可一併取得 appearance_referenceemoji 一律保留作為 fallback,不因後續產生心情 emoji 圖表而丟棄。

  4. 詢問使用者是否要到網路搜尋角色資料來建立初始記憶與形象圖;若第 2 步已因使用者允許上網而搜尋過,可沿用該次搜尋結果,不重複詢問。若使用者同意,依角色描述搜尋可靠來源,摘要成繁體中文要點並保留來源 URL,同時搜尋適合做角色心情 emoji 的形象圖。若搜尋結果無法可靠判斷角色形象,先詢問使用者參考來源、作品名稱、圖片 URL 或本機檔案路徑,不得臆測形象。若使用者不同意上網且也未提供形象參考,仍可建立角色,只是不建立背景種子記憶與心情 emoji 圖表,並使用原本的 emoji fallback。

  5. 產生角色 ID

    • namenaturevibe 推出 1 個有意義的英文大寫前綴,使用 4 到 16 個英文字母與數字,必須以英文字母開頭,例如 ENGINEERWRITERMUSERESEARCHER
    • 掃描 ~/.roles/*.md 的檔名與 frontmatter id,找出同前綴既有 ID 的最大兩位數索引;新角色使用下一個索引,從 01 起,例如 ENGINEER01ENGINEER02
    • 不得使用空白、底線、連字號、斜線、非 ASCII 或小寫字母。
  6. 依「角色檔標準格式」產生新內容,id 寫入 frontmatterupdated 用當下時間(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,格式見「角色檔標準格式」)。 身分檔需填來源關係定位,並可在標題下以條目寫存在本質、角色原型、主要稱呼等摘要; 人格檔除必要的本質與氛圍外,可依角色特性增加核心信念、語氣與風格、邊界與規範等章節。 共用行為不寫入角色檔(由 role_load.sh 注入)。

  9. 建立記憶目錄:node "${ROLE_DIR}/memory.js" stats --role "<id>"(會順帶建好 inbox/、六個分類與 archive/)。

  10. 若使用者同意網路搜尋且已取得可保存內容,將搜尋摘要寫成已整理記憶,不進 inbox:

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」區塊,格式為:

優先使用<角色顯示名稱>專屬心情 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 結尾,直接使用該檔名。

"${ROLE_DIR}/role_sleep.sh" --export "/path/to/exports/"
"${ROLE_DIR}/role_sleep.sh" --export "YUI01" "/path/to/YUI01.tar.gz"

匯出內容可能包含使用者同意保存的個人偏好與互動記憶;除非使用者明確要求公開或上傳,匯出檔只保存在指定本機路徑,不自動提交、上傳或貼出內容。

--sleep

立即執行一次記憶整理(不等排程、忽略時段與 AI 運行檢查):

"${ROLE_DIR}/role_sleep.sh" --force

輸出整理結果(新增/合併/捨棄/歸檔筆數與遺忘清單)。

--nap

小睡整理:由 cron 全天依 ROLE_NAP_INTERVAL_MINUTES 檢查一次;當 Stop hook 記錄的最後互動時間已超過 ROLE_NAP_IDLE_MINUTES,且 inbox/ 至少有 ROLE_NAP_MIN_INBOX 則待整理記憶時,自動執行一次記憶整理:

"${ROLE_DIR}/role_sleep.sh" --nap

小睡不受 ROLE_SLEEP_STARTROLE_SLEEP_END 限制;它只避開整理用的 headless 子 CLI,讓互動式 CLI 長時間閒置時仍可整理記憶。若未設定環境變數,預設為 ROLE_NAP_ENABLED=1ROLE_NAP_IDLE_MINUTES=45ROLE_NAP_MIN_INBOX=3ROLE_NAP_INTERVAL_MINUTES=10

--brief(晨間狀態檢查)

在睡眠時段結束的整點執行使用者自訂的檢查腳本,把有變化的結果寫成一則記憶,讓角色在當天第一次互動時就能主動回報 —— 例如「PR 還沒合併」、「昨晚 CI 失敗了」,而不必等使用者開口才去查。

"${ROLE_DIR}/role_sleep.sh" --brief

本 skill 不內建任何檢查邏輯,不假設使用者用 Gitea、GitHub 或任何服務。檢查內容完全由使用者決定:

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_LIMITROLE_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_LIMITROLE_SLEEP_BATCHROLE_SLEEP_EXISTING_LIMITROLE_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 整理與 declarativeretention_stage: long_term 判定只在睡眠週期進行。

--migrate <角色 ID>(舊格式拆成兩檔)

把舊格式單一 <ID>.md 拆成 <ID>.identity.md<ID>.soul.md

"${ROLE_DIR}/role_sleep.sh" --migrate YUI01
行為 說明
本質與氛圍 逐字搬進 soul
ID/顯示名稱/emoji/簽名 emoji 段落 逐字搬進 identity 檔;created 沿用原值
來源與關係定位 產生待填空白,需人工補上(舊格式沒有這兩個概念)
共用行為區塊 不搬進角色檔,由 role_load.sh 注入
舊檔 保留不動,確認新格式正常後可自行移除或備份
新檔已存在時 直接中止並提示,不覆寫

--agent <角色 ID> [輸出目錄](匯出成 sub agent

把角色匯出成 sub agent 定義,讓任何角色都能派任何其他角色協助,是多角色協作的基礎。

"${ROLE_DIR}/role_sleep.sh" --agent SINON01            # 預設輸出到 ~/.claude/agents/
"${ROLE_DIR}/role_sleep.sh" --agent SINON01 ./.claude/agents

產出的定義檔包含:

區塊 內容
frontmatter name(角色 ID)與 description(何時該派這個角色)
人格 從角色檔抽出的 naturevibe
開工前 動態解析 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(解除角色載入鎖)

同一角色同時只會被一個工作階段載入,避免使用者同時與兩個相同人格對話。第二個工作階段啟動時不載入人格,改以一般助理身分回應並說明原因。

"${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

只預覽會被遺忘的記憶、不實際刪除:

node "${ROLE_DIR}/memory.js" forget --role "<角色 ID>" --dry-run

--status--diagnose

"${ROLE_DIR}/role_sleep.sh" --status

輸出角色、定義檔、睡眠時段、小睡條件、目前是否睡眠中、cron 排程與服務狀態、摘要 CLI、各分類記憶筆數、上次互動、上次整理與遺忘時間。角色沒有載入時再逐項檢查:

檢查項 判準
角色解析 ROLE_NAME~/.roles/.active 是否指向存在的定義檔
總開關 ROLE_ENABLED 是否被設成 0
hook 註冊 plugin 是否已啟用、hooks/hooks.json 是否存在(Claude Code 用 /hooks 檢視)
工作階段 建立角色後是否重開過 CLISessionStart 只在啟動時觸發)
範圍 ROLE_SCOPE 是否把目前目錄排除
時段 目前是否落在睡眠時段(睡眠時本來就不載入角色)
依賴 nodeROLE_CLI 選到的 CLI 是否找得到
排程 cron 條目是否存在、cron 服務是否執行中(WSL 常未啟動 → 靠啟動時補跑)

--install-cron--remove-cron

安裝或移除睡眠排程。排程條目以 # jsc-role-sleep 註解標記,只動自己的條目:

"${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

---
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

## 本質## 氛圍是必要章節;其餘章節可自由增加,會一併注入(例如核心信念、語氣與風格、邊界與規範)。

---
id: <角色 ID>
updated: <yyyy/MM/dd HH:mm:ss>
---

## 本質(nature

<3 至 5 行:這個角色是什麼、專長、行事準則、面對不確定時的態度>

## 氛圍(vibe

<3 至 5 行:語氣、句子長度、對使用者的稱呼、幽默感尺度、明確禁忌>

## 核心信念

<選填:這個角色在意什麼、用什麼視角看世界、主動性到哪裡>

## 語氣與風格

<選填:語調、表情符號與顏文字習慣、口頭禪;並註明僅適用於自然語言回覆>

## 邊界與規範

<選填:角色專屬的邊界。與共用行為衝突時以共用行為為準>

注入規則

來源 是否注入
identity 的 frontmatteridnameemoji
identity 標題後、第一個 ## 之前的前言段落 常用來寫存在本質、角色原型等摘要條目
identity## 來源## 關係定位## 簽名 emoji
soul## 本質## 氛圍
soul其他任何 ## 章節 不限章節名

寫進角色檔的內容若未被注入就等於白寫,因此上述兩處(前言段落與自由章節)都會完整帶入 —— 曾發生使用者在人格檔補寫章節卻被靜默丟棄的情況。

角色專屬邊界不得放寬共用行為的限制:共用行為(由 role_load.sh 注入)永遠優先,角色檔只能加嚴不能放寬。

~/.roles/.active 只放一行角色 ID,代表目前啟用的角色。


記憶模型

~/.memory/<角色 ID>/
├── inbox/                 每輪對話產生、尚未整理的記憶
├── important/             重要:長期偏好、規範、決策、身分背景
├── interest/              興趣:反覆關注、主動深入的主題
├── news/                  新知:新事實、新工具、外部資訊
├── skill/                 技能:可重複套用的做法與流程
├── daily/                 日常:一次性例行工作
├── other/                 其他
├── archive/raw/<yyyy-MM>/ 已整理的原始記錄(gzip
├── archive/forgotten/     已遺忘的記憶(gzip,可考古但不再載入)
└── state.json             上次整理/遺忘時間

每則記憶是一個 .mdfrontmatter 帶 idcategorysummary(一句話總結)/tagspriority15)/cues(提取線索,供 recall 命中;proceduralrule 型態必填)/relevanceexplicitfuturerepeatednoveltyemotionaltemporary 等)/links(相關記憶 id)/memory_typesemanticepisodicproceduralemotionalpreferencerule)/declarativeexplicitimplicit)/retention_stageworkinglong_term)/sleep_stageencodingseednremremnrem-rem)/createdupdatedlast_replayedhits(命中次數,去重合併時 +1)。舊記憶沒有新欄位時,讀取時會依分類與路徑補預設值。

state.json 保存角色記憶系統狀態,例如 last_sleeplast_sleep_digestlast_forgetpersonal_memory_consentpersonal_memory_consent 只允許 accepteddeclinedunknown,供 SessionStart 判斷是否需要再次告知與詢問個人資料保存同意。

心理學分類與系統欄位對應:

心理學分類 系統處理
感覺記憶 不落檔;短暫感官殘留與工具雜訊直接丟棄
短期/工作記憶 inbox/retention_stage: working,只做輕量編碼
長期記憶 睡眠整理後進入六分類目錄,retention_stage: long_term
外顯/陳述性 declarative: explicit,多見於 semanticepisodicpreferencerule
內隱/非陳述性 declarative: implicit,多見於 proceduralemotional

遺忘規則(只套用於日常與其他):

分類 未更新天數 命中次數 優先度 關聯 動作
日常 daily ≥ 14 天(episodic 約 7 天) ≤ 1 ≤ 2 無 links,且非 rulepreferenceprocedural 壓縮到 archive/forgotten/ 後移除
其他 other ≥ 7 天(episodic 約 4 天) ≤ 1 ≤ 2 無 links,且非 rulepreferenceprocedural 壓縮到 archive/forgotten/ 後移除

睡眠與整理流程

flowchart TD
    A[cron 每小時觸發<br/>睡眠時段內] --> B{有 AI 正在運行?}
    B -- 有 --> C[不睡,下個整點再檢查]
    B -- 沒有 --> D[進入睡眠,取得記憶鎖]
    D --> E[collectinbox 待整理 + 既有記憶索引/優先度/型態/關聯]
    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.jsredact 正則遮蔽: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/ 安裝時不可用