soplint 研究筆記¶
資料來源¶
| 項目 | 連結 |
|---|---|
| GitHub Repo | https://github.com/zaxardery8011-design/soplint(MIT,PowerShell,19 stars) |
| 對照專案 | AgentLint(harness linter,檢查 rules 檔寫得好不好) |
| 理念來源 | 作者「24/7 跑個人 AI agent 一年」的真實事故累積 |
專案概述¶
soplint 的一句話定位是:「Lint rules for your AI agent's discipline, not its code.」(為 agent 的紀律、而非程式碼而設的 lint 規則)。
作者連續一年 24/7 運行一個個人 AI agent,發現問題從來不是「寫不出好程式」,而是紀律:agent 會說「已修好並驗證」卻沒真的驗證、會默默推翻自己先前的判斷、把政策決策寫進記憶後就讓它爛在那裡、行為慢慢漂回舊習慣。soplint 要解的就是這個——檢查 agent 有沒有真的遵守你跟它定下的「工作協議(working agreements)」。
它刻意和三類既有工具區分:code linter 抓程式風格、memory 工具抓壞連結與過時筆記、harness linter(如 AgentLint)檢查規則檔寫得好不好;soplint 檢查的是另一件事——約定有沒有被實際遵守。核心哲學是把「一年裡每一次出錯」沉澱成可每天跑的回歸測試:這不是對齊(alignment),而是「疤痕組織的程式碼化(scar tissue, codified)」。
核心功能 / 技術架構¶
三個機制,全部從真實事故萃取:
1. Belief revision 稽核軌跡¶
每當 agent 推翻先前判斷,必須記一筆 JSONL:
Import-Module ./lib/BeliefLog.psm1
Add-BeliefRevision -From "Assumed the cache layer was thread-safe" `
-To "Race confirmed under load; needs a lock" `
-Trigger estimate_correction -ConfidenceShift "high->low"
一次修正一行(from_belief/to_belief/trigger/confidence_shift),append 到可 grep 的 JSONL。trigger 刻意是 enum 而非自由文字——自由文字會讓稽核日誌變噪音。為何用外部檔而非 prompt 規則?因為 prompt 規則會失效:作者親眼看 agent 一天內違反「要承認信念改變」這條寫好的規則三次。Agent 能默默忽略指令,但缺失或過時的日誌檔很吵,而 lint 會稽核「日誌到底有沒有被寫」。
2. Discipline checks(每日 cron / CI 跑)¶
| Check | 抓什麼 | 背後的事故 |
|---|---|---|
decision_propagation |
「新預設」決策寫進記憶卻沒傳播到 agent 操作指令(CLAUDE.md) | 一個 dispatch 政策決策在記憶裡爛兩週,每個新 session 都做舊事 |
belief_revision_audit |
belief log 沒被寫(lint 稽核本身) | 沒人稽核的稽核只是裝飾 |
memory_frontmatter |
記憶檔缺必要 metadata | 搜不到的記憶=唯寫記憶 |
index_health |
記憶索引過大或有重複條目 | 臃腫索引會靜默截斷每 session 載入的內容 |
每個 check 失敗就 exit non-zero,接 CI / cron 很簡單。失敗要落在 agent 必須面對的地方——收件匣、ping、被擋的 merge。
3. Pre-action gate(hook)¶
hooks/pretool-guard.ps1 作為 PreToolUse hook。對 shell 指令,它先把 PowerShell 輸入化約成 AST command 簽章,再套外部 deny/novelty regex 規則,避開「引號字串誤判」的常見假陽性。這是 guardrail 不是 sandbox。規則放外部 JSON:
- Deny rules:硬紅線。範例:agent 絕不可重啟自己的 daemon(從 cascade process death 學來)
- Novelty gate:agent 在造新工具前,必須先證明它掃過既有工具(一句 acknowledgement 註解)——會重造已有工具的 agent 是在燒你兩次錢
Scope:AST parse 只懂 PowerShell。若你的 agent 透過 bash/python shell out,需在那側有對應 parser——deny-rules JSON 可攜,parser 不可攜。
快速開始¶
# 1. 設定
Copy-Item soplint.config.example.json soplint.config.json
# 編輯 paths: memory_dir, claude_md_path, beliefs_log, index_file
# 2. 跑檢查
pwsh -NoProfile -File bin/soplint.ps1
# 3. 跑測試
pwsh -NoProfile -File tests/run_all_tests.ps1
需 PowerShell 7+(Linux/macOS/Windows,CI 三平台都涵蓋)。examples/CLAUDE.md.example 有可貼進 agent 指令的 SOP 區塊。
目前限制 / 注意事項¶
- 這不解決對齊,只是「已知失敗模式」的回歸測試:agent 仍會犯新錯,lint 只阻止舊錯回來。
- 每條 check 都源於已發生的事故——是反應式(reactive)而非預測式;空專案沒有歷史,價值有限。
- PowerShell 綁定:作者的 stack 是 pwsh(好處是 AST parser 是標準庫、零依賴)。非 pwsh 用戶要「偷概念」——機制(外部稽核軌跡、discipline-as-CI、AST pre-action gate)可攜到任何語言,但實作要重寫。
- 可被有寫入權的 agent 偽造日誌嗎?作者誠實承認技術上可以,但「偽造」門檻遠高於「忽略 prompt」,且假紀錄會留下可 grep 的不一致。
研究價值與啟示¶
關鍵洞察¶
-
「prompt 規則會失效,外部檔案 + lint 才可靠」是這個專案最重要的論點:作者一天內看 agent 違反同一條寫好的規則三次,得出結論——指令可被默默忽略,但缺失的檔案很吵。把「要承認信念改變」從 prompt 規則變成「必須寫進可稽核的 JSONL,且 lint 會檢查它有沒有被寫」,是把軟性約定變成硬性回歸信號。這對任何用 CLAUDE.md / memory 管理 agent 行為的人是直接的警告:寫進記憶的教訓只是「希望」,加上 lint 規則才變成「每天可跑的回歸信號」。
-
「decision_propagation」直指 memory 系統的真實失效模式:把決策寫進記憶 ≠ 讓 agent 實際照做。一個政策決策可以「爛在記憶裡兩週,而每個新 session 仍做舊事」。這個 check 稽核「記憶 → 操作指令(CLAUDE.md)」的傳播,命中本站多個 memory/agent 筆記反覆觸及的核心痛點:記憶的價值不在儲存,在於每次 session 真的被載入並影響行為。
-
「audit 本身要被 audit」是少見的二階思維:soplint 不只要 agent 寫 belief log,還用
belief_revision_auditcheck 稽核「日誌到底有沒有在被寫」——因為「沒人稽核的稽核只是裝飾」。這種「對監控機制再加一層監控」的設計,是把可靠性工程的紀律真正落實,而非做做樣子。 -
AST 化約再套規則,是 pre-action gate 的正確做法:直接用 regex 比對 shell 指令會被引號字串騙出大量假陽性。soplint 先把 PowerShell 輸入 parse 成 AST command 簽章再套 deny/novelty 規則,大幅降低誤判。這是「在 agent 動手前攔截」這類 guardrail 的工程細節範本——語法層理解比字串比對可靠得多。
-
「scar tissue, codified」是 agent 可靠性的務實心法:每條規則都對應一次真實事故。這套方法論的精髓在最後一句——「這週你的 agent 僥倖逃過了什麼,別只是糾正它,把 check 寫下來」。它把 Anthropic「讓 agent 把教訓寫進 CLAUDE.md/skill」的建議補上關鍵第二步:測試它真的寫了。
與其他專案的關聯¶
| 維度 | 對比 |
|---|---|
| vs AgentLint(作者點名) | AgentLint 檢查規則檔「寫得好不好」(harness linter);soplint 檢查約定「有沒有被遵守」 |
| vs SkillOpt | SkillOpt 用 validation gate 防 prompt 優化發散;soplint 用 lint gate 防 agent 紀律漂移——都把 ML/SE 的「閘門 + 早停」紀律移植到 agent 行為治理 |
| vs social-post 的安全閘 | 都靠「硬規則不可被 agent bypass」的設計;soplint 更進一步用外部檔 + lint 強制,而非僅靠 prompt 聲明 |
| vs 本站 memory 系統實務 | memory_frontmatter / index_health check 正是本研究站 MEMORY.md 索引與 frontmatter 規範想避免的失效——可視為這套規範的自動化稽核器 |
最大啟示:soplint 點破了 agent 治理的核心矛盾——我們用 prompt/CLAUDE.md/memory 約束 agent,但這些都是 agent 能默默忽略的軟性指令。它的解法是把約定外部化成可稽核的檔案,再用 lint + CI + PreToolUse hook 把「有沒有遵守」變成每天可跑、會擋 merge 的硬性信號。對任何長期運行 agent 的人,這是從「希望 agent 守規矩」升級到「驗證 agent 守規矩」的方法論——而且機制可攜,PowerShell 只是作者的實作載體。