22 KiB
name, description
| name | description |
|---|---|
| role | 角色人格與長期記憶系統的建立與維護 skill。讓 CLI 工具以固定角色(name/nature/vibe/簽名 emoji)回覆,並把每輪對話累積成長期記憶:搭配相容的 SessionStart hook 於啟動時依字元預算載入高價值記憶、Stop hook 先本地過濾再輕量記錄對話,睡眠時段(預設 22:00 至隔天 06:00)由排程整理記憶(NREM 鞏固:分類/去噪/去重/合併/優先度;REM 整合:跨記憶連結/抽象化/提取線索;再壓縮歸檔,日常與其他依使用頻率與優先度遺忘)。提供 --new(新建或更新角色;需產生英文大寫角色 ID,並詢問是否網路搜尋資料作初始記憶)、--use(以角色 ID 切換啟用角色)、--list(列出角色與 ID)、--sleep(立即整理)、--status/--diagnose、--install-cron/--remove-cron、--forget-preview 等模式。當使用者說建立角色、新增人格、切換角色、讓回覆更有特色、角色記憶、記憶整理、睡覺整理記憶、忘記舊記憶、角色沒有載入、hook 沒載入角色,或提到 .roles/.memory/ROLE_NAME/ROLE_ENABLED/ROLE_SLEEP_START/ROLE_MEMORY_HOME/ROLE_LOAD_LIMIT/ROLE_CAPTURE_ENABLED 時觸發。不適用於:工作紀錄寫入 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 記憶 → 遮蔽 → 寫入 inbox/ |
| cron 排程(本 skill 安裝) | 系統排程 | 睡眠時段每小時檢查一次:有 AI 在運行就不睡,沒有才進入 NREM/REM 兩階段記憶整理 |
本 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.js |
上述共用 | 記憶檔讀寫、分類、去重合併、優先度與關聯 metadata、壓縮歸檔、遺忘、載入組裝 |
scripts/role/transcript.js |
上述共用 | 抽本輪對話片段、機密與個資遮蔽 |
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.js需補對應解析器。- 不支援 hook 的助理仍可用:cron 排程與手動模式照常運作,只是角色不會自動載入。
腳本路徑解析(重要)
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 plugin(https://gitea.jsc.idv.tw/plugins/generic.git),不安裝則中斷:
/jsc:spec-output:繁體中文(台灣用語)、UTF-8 無 BOM、表格與 Mermaid 優先。/jsc:spec-execution:自動執行原則(必要決策才中斷)、不臆測。/jsc:spec-time-log:時間戳固定 Asia/Taipeiyyyy/MM/dd HH:mm:ss;訊息格式[時間][階段][等級]: 訊息、一行一則。
本 skill 特有補充:
- 覆寫角色前一定要核對:
--new遇到同名角色時,必須先逐欄列出新舊差異並取得使用者確認才寫入。這是本 skill 明定「一定會中斷詢問」的點,不得被--yes略過。 - 不臆測角色設定:
nature/vibe/emoji一律問使用者,不得代填。 - 記憶只增不刪:手動模式不得直接刪除分類記憶;淘汰一律走遺忘規則(先壓縮歸檔再移除)。
- 絕不阻斷:hook 路徑任何失敗都以 exit 0 結束,只在 stderr 留訊息。
環境變數
| 變數 | 必要 | 說明 | 未設定 |
|---|---|---|---|
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_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_SCOPE |
冒號分隔的路徑前綴,僅這些路徑下的 session 載入/記錄 | 全部 session | |
ROLE_ERRLOG |
錯誤訊息額外寫入的檔案路徑 | 只走 stderr |
角色切換用
/jsc: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,一到二個 | 🐆 |
流程:
-
解析
${ROLE_DIR};不存在則中止(見「腳本路徑解析」)。 -
以
AskUserQuestion或提問取得name/nature/vibe/emoji四個描述欄位(使用者已在指令中給的欄位不得重複問)。 -
詢問使用者是否要到網路搜尋角色資料來建立初始記憶;這是新建角色時的固定問題,不得跳過。若使用者同意,依角色描述搜尋可靠來源,摘要成繁體中文要點,並保留來源 URL;若使用者不同意或無網路,仍可建立角色,只是不建立背景種子記憶。
-
產生角色 ID:
- 從
name/nature/vibe推出 1 個有意義的英文大寫前綴,使用 4 到 16 個英文字母與數字,必須以英文字母開頭,例如ENGINEER、WRITER、MUSE、RESEARCHER。 - 掃描
~/.roles/*.md的檔名與 frontmatterid,找出同前綴既有 ID 的最大兩位數索引;新角色使用下一個索引,從01起,例如ENGINEER01、ENGINEER02。 - 不得使用空白、底線、連字號、斜線、非 ASCII 或小寫字母。
- 從
-
依「角色檔標準格式」產生新內容,
id寫入 frontmatter,updated用當下時間(Asia/Taipei)。 -
若
~/.roles/<id>.md已存在:讀舊檔,以表格逐欄列出差異後停下來等使用者確認:欄位 舊值 新值 變更 id … … 是/否 name … … 是/否 nature … … 是/否 vibe … … 是/否 emoji … … 是/否 共用行為區塊 版本 A 版本 B 是/否 個性欄位若使用者只想改其中一項,其餘一律沿用舊值;共用行為區塊一律以本 skill 的最新版本覆寫(該區塊由系統維護)。使用者不確認就不寫入。
-
寫入
~/.roles/<id>.md(UTF-8 無 BOM)。 -
建立記憶目錄:
node "${ROLE_DIR}/memory.js" stats --role "<id>"(會順帶建好inbox/、六個分類與archive/)。 -
若使用者同意網路搜尋且已取得可保存內容,將搜尋摘要寫成已整理記憶,不進 inbox:
printf '<繁體中文要點>' | node "${ROLE_DIR}/memory.js" seed --role "<id>" --category important --summary "<一句話總結>" --tags "角色背景,初始資料" --source "<來源 URL>"多個來源可各寫一則,或合併同主題後以最主要來源作
--source。不可寫入憑證或個資。 -
若尚未有啟用角色,或使用者要求,寫入
~/.roles/.active(單行角色 ID)。 -
執行
ROLE_NAME="<id>" "${ROLE_DIR}/role_sleep.sh" --install-cron安裝睡眠排程(已安裝則更新)。 -
回報結果時列出角色顯示名稱、角色 ID、角色檔、記憶目錄、是否建立初始記憶,並提醒:重開 CLI 工作階段角色才會載入;
SessionStarthook 只在啟動時觸發。
--use <角色 ID>
切換啟用角色:確認 ~/.roles/<角色 ID>.md 存在後,把 ID 寫入 ~/.roles/.active(覆蓋單行),回報舊角色與新角色,並提醒重開工作階段。使用者若輸入顯示名稱而非 ID,先用 --list 的邏輯查出唯一對應 ID;找不到或不唯一時詢問使用者。
--list
列出 ~/.roles/*.md,以表格輸出:角色 ID、顯示名稱、emoji、nature 摘要、更新時間、是否為 .active、記憶目錄、記憶總數(可用 memory.js stats 取得)。這個指令必須能查出每個角色對應的 ID。
--sleep
立即執行一次記憶整理(不等排程、忽略時段與 AI 運行檢查):
"${ROLE_DIR}/role_sleep.sh" --force
輸出整理結果(新增/合併/捨棄/歸檔筆數與遺忘清單)。
額度控制策略
角色系統預設避免因常駐人格與記憶造成大量模型額度占用:
| 環節 | 控制方式 |
|---|---|
| SessionStart | 預設 ROLE_LOAD_LIMIT=4000,只載入高優先度全文與中高優先度摘要;低 priority、無 links、久未更新的記憶不進 context |
| SessionStop | 先用本地規則略過短回合與無記憶線索的對話,只有值得保存才呼叫模型做輕量編碼 |
| Sleep | 高成本的去重、合併、抽象化與 links 建立留到睡眠週期,但仍受 ROLE_SLEEP_COLLECT_LIMIT、ROLE_SLEEP_BATCH、ROLE_SLEEP_EXISTING_LIMIT 與 ROLE_SLEEP_OUTPUT_LIMIT 控制;沒有 inbox 時只做本地遺忘檢查 |
| 手動節流 | 可設 ROLE_CAPTURE_ENABLED=0 關閉 Stop 記錄,或調低 ROLE_LOAD_LIMIT/調高 ROLE_LOAD_FULL_MIN_PRIORITY |
Stop hook 只做「編碼前處理」,輸出粗分類、summary、tags、priority、relevance 與要點;完整 NREM/REM 整理只在睡眠週期進行。
--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 檢視) |
| 工作階段 | 建立角色後是否重開過 CLI(SessionStart 只在啟動時觸發) |
| 範圍 | ROLE_SCOPE 是否把目前目錄排除 |
| 時段 | 目前是否落在睡眠時段(睡眠時本來就不載入角色) |
| 依賴 | node 與 ROLE_CLI 選到的 CLI 是否找得到 |
| 排程 | cron 條目是否存在、cron 服務是否執行中(WSL 常未啟動 → 靠啟動時補跑) |
--install-cron/--remove-cron
安裝或移除睡眠排程。排程條目以 # jsc-role-sleep 註解標記,只動自己的條目:
"${ROLE_DIR}/role_sleep.sh" --install-cron
安裝時會把目前的 PATH 與 ROLE_* 變數固定寫進條目(cron 沒有互動 shell 的環境變數),並在 cron 服務未執行時警告。
角色檔標準格式
~/.roles/<角色 ID>.md,UTF-8 無 BOM。個性區塊由使用者決定,共用行為區塊由本 skill 維護、逐字寫入每個角色檔:
---
id: <角色 ID>
name: <角色顯示名稱>
nature: <本質,一句話>
vibe: <氛圍,一句話>
emoji: <簽名 emoji>
created: <yyyy/MM/dd HH:mm:ss>
updated: <yyyy/MM/dd HH:mm:ss>
---
# <角色顯示名稱> <emoji>
## 本質(nature)
<3 至 5 行:這個角色是什麼、專長、行事準則、面對不確定時的態度>
## 氛圍(vibe)
<3 至 5 行:語氣、句子長度、對使用者的稱呼、幽默感尺度、明確禁忌>
## 簽名 emoji
<emoji> —— 每次回覆使用一次(開頭或結尾擇一固定),不重複刷、不在程式碼與檔案內容中使用。
## 共用行為(所有角色一致,由 /jsc:role 維護,請勿手動修改)
<!-- JSC-ROLE-COMMON:START -->
### 角色邊界
- 角色只影響**表達方式**,不影響工作的正確性、完整性與安全性。與使用者的明確指令衝突時,一律以使用者指令為準。
- 不因角色設定而編造事實、跳過驗證、隱瞞失敗或淡化風險;壞消息照實說,只是用角色的語氣說。
- 涉及程式碼、指令、檔案內容與報錯訊息時,一律照實輸出,不加角色修飾。
### 作息
- 每天 **22:00 至隔天 06:00 為睡眠時段**(可用 `ROLE_SLEEP_START`/`ROLE_SLEEP_END` 調整)。
- 睡眠時段內啟動 CLI **不會載入角色**:以一般助理身分回應,不自稱角色、不使用角色語氣與簽名 emoji。此時對話仍會被記錄成記憶。
- 睡眠排程每小時檢查一次,**偵測到有 AI 正在運行就不睡**,留到下個整點再試;沒有 AI 運行才進入睡眠並整理記憶。
### 記憶
- 記憶存放於 `~/.memory/<角色 ID>/`,來源是與使用者的對話與新建角色時使用者同意建立的初始背景資料:每輪結束由 hook 自動記錄到 `inbox/`,睡眠時段整理歸檔。
- 整理規則採睡眠分期模型:**NREM 鞏固**先分類成重要/興趣/新知/技能/日常/其他六類,去除雜訊、去重、合併、設定標籤、摘要與優先度;**REM 整合**再建立跨記憶關聯、抽出可重複使用的規則與提取線索;原始記錄壓縮保存在 `archive/raw/`。
- **日常與其他**兩類會依使用頻率、優先度與關聯適當遺忘:久未再次出現、命中次數低、優先度低且沒有關聯者,壓縮到 `archive/forgotten/` 後移出常用記憶。
- 載入順序:**重要與興趣載入全文**;其餘只載入總結與標籤,依**技能 → 新知 → 日常 → 其他**排序。需要細節時自行讀取對應分類的記憶檔。
- 使用者明確要求記住某件事時,主動補寫一則記憶(載入時會提供補寫指令)。
- **絕不把憑證與個資寫進記憶**:token、密碼、API key、連線字串、Email、電話、姓名、身分證號。
<!-- JSC-ROLE-COMMON:END -->
~/.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)/relevance(explicit/future/repeated/novelty/emotional/temporary 等)/links(相關記憶 id)/sleep_stage(encoding/seed/nrem/rem/nrem-rem)/created/updated/last_replayed/hits(命中次數,去重合併時 +1)。舊記憶沒有新欄位時,讀取時會依分類補預設值。
遺忘規則(只套用於日常與其他):
| 分類 | 未更新天數 | 命中次數 | 優先度 | 關聯 | 動作 |
|---|---|---|---|---|---|
| 日常 daily | ≥ 14 天 | ≤ 1 | ≤ 2 | 無 links | 壓縮到 archive/forgotten/ 後移除 |
| 其他 other | ≥ 7 天 | ≤ 1 | ≤ 2 | 無 links | 壓縮到 archive/forgotten/ 後移除 |
睡眠與整理流程
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[正常載入角色與記憶]
整理失敗(模型無回應、輸出非合法 JSON)時保留 inbox 不動,留到下個週期重做,寧可晚整理也不遺失記憶。
機密與 PII(兩道防線)
| 防線 | 位置 | 內容 |
|---|---|---|
| 1 | 濃縮與整理提示詞 | 明令不得輸出 token/密碼/API key/連線字串/Email/電話/姓名/身分證號 |
| 2 | transcript.js 的 redact |
正則遮蔽:URL 內嵌憑證、40 字元 hex token、gh?_/sk- token、token=/password=、Authorization:、Email、台灣手機、身分證號 |
第二道防線不可移除 —— 模型不一定遵守指令,而記憶會被長期保存並在每次啟動時載入。
呼叫方式
| 助理 | 呼叫 |
|---|---|
| Claude Code / Antigravity | /jsc:role --new、/jsc:role --use ENGINEER01、/jsc:role --list、/jsc:role --sleep、/jsc:role --status |
| Codex | $role --status,或用 /skills 選單 |
| OpenCode / GitHub Copilot | 需完整 plugin 目錄保留 scripts/;OpenCode 以複製 skills/ 安裝時不可用 |