.maigo/ Artifacts Reference
.maigo/ 全貌型錄:這個目錄底下有哪些檔、各自的正典(code + skill)是誰、
生命週期多長。找不到某個 .maigo/ 檔案該歸哪一類時,先查這頁;機器判斷
邏輯(哪個檔案屬於哪一類)由 scripts/maigo_dir_catalog.py 執行,不是散文
自己判斷——見 /maigo:doctor 的「.maigo/ 型錄」段。
.maigo/ 人讀產物(plan、review 報告、rubric、草稿、board 與 i/ 細節檔)的版面規範見 vim-friendly-artifacts。
實體位置
.maigo 預設不是真目錄,而是指向本機集中 root 的 symlink:
$MAIGO_STATE_HOME(預設 ~/.local/share/maigo/state)/<owner>/<repo>/。同一個 repo
identity 的所有 worktree 共用一份;路徑仍寫成 .maigo/...,下面的版面與 artifact_path.py
都不變。identity 規則、既有真目錄的遷移與行為變更見
.maigo/ 集中儲存。
佈局總覽
.maigo/
├── board.md Work Board 索引(人讀)
├── i/<slug>.md Work Board 細節檔(人讀)
├── pr/<id>/ 自己的 PR:plan.md、rubric.md、review.md、reply-draft.md …
├── review/<id>/ 別人的 PR:review.md、rubric.md、draft.md、pr-comments.md …
├── issue/<id>/ issue:plan.md、rubric.md
├── topic/<slug>/ 沒有 PR / issue 的任務:plan[-n].md
├── _archive/<原相對路徑> 已結案項目,鏡射上面的相對路徑(review/、pr/、i/ 由 /maigo:board 與 /maigo:tidy 封存;issue/、topic/ 由 /maigo:tidy 封存)
└── _internal/ 只給機器讀:board/、log/、tidy/backup/
plan的 group 依 URL 決定:PR URL →pr/、issue URL →issue/,其餘 →topic/。 在預設分支(main/master/develop/trunk)上,識別碼不用分支名,用--slug(優先)或--topic的 H1 slug;兩者都推不出來就報錯,不退回短 SHA。- 同一個 group 目錄收同一顆 PR / issue / topic 的所有產物;conflict 的第 2 個 attempt
起落在檔名層(
plan-2.md),不另開目錄。 - 頂層
plan-<id>[-n].md是舊形狀,只可讀;scripts/migrate_legacy_artifacts.py會把它搬到topic/<id>/plan[-n].md(不推測 PR / issue 歸屬);-n只在同批有plan-<id>.md同伴時才當 attempt 後綴。
帶識別碼命名的產物
所有 kind 全部由 scripts/artifact_path.py 的 _KNOWN_KINDS 單一正典定義,
resolve_for_write() 負責一般產物的歸屬檢查(最終 review 報告用下述 publisher)——同一路徑撞到不同主題時回
status: conflict,呼叫端必須先問使用者再決定要不要用建議的候選路徑(從第 2 個 attempt 起第一個未被其他主題占用者;也可能指到 H1 相同的既有檔,status 仍是 conflict),
不擅自覆寫。兩種形狀都是巢狀:
plan(巢狀,<group>/<id>/plan.md,group 依 URL 分 pr / issue / topic)
| 種類 | 檔名規則 | 誰寫的 | 正典來源 | 生命週期 |
|---|---|---|---|---|
plan |
.maigo/pr/<id>/plan.md(PR URL)/.maigo/issue/<id>/plan.md(issue URL)/.maigo/topic/<slug>/plan.md(其餘;預設分支用 --slug) |
🩵 Tomori | scripts/artifact_path.py + artifact-ownership |
單次任務的實作計畫,任務結束後仍留存供追溯 |
review / pr / issue(巢狀,<group>/<id>/<stem>.md)——按 PR/issue 分資料夾
同一顆 PR 的 review / review-rubric / review-draft / pr-comments / reply-draft
收進同一個目錄,並依 PR 作者分流:別人的 PR 放 .maigo/review/<id>/,自己的 PR
(含本地 branch / commit range)放 .maigo/pr/<id>/,下表檔名規則裡的 review/ 都適用這兩組。
作者由 scripts/pr_owner.py
查,以 --owner mine|others 傳給 scripts/artifact_path.py;另一組已有同 id 同名檔時,
artifact_path.py 多印 other_group_exists: 供讀取。既有的 review/<id>/ 可用
scripts/migrate_legacy_artifacts.py --split-own-prs 把自己的 PR 搬進 pr/<id>/。
同一條 issue 的 triage-rubric 收進
.maigo/issue/<id>/;conflict 後綴(第 2 個 attempt 起)落在檔名層
(rubric-2.md),不落在目錄層。
| 種類 | 檔名規則 | 誰寫的 | 正典來源 | 生命週期 |
|---|---|---|---|---|
review-rubric |
.maigo/review/<id>/rubric.md |
🩵 Tomori | scripts/artifact_path.py + artifact-ownership |
對照基準,review 全程比對用;review 結束後留存 |
review |
.maigo/review/<id>/review.md |
orchestrator(/maigo:review) |
scripts/review_report.py(重用 artifact_path 命名) |
同 source 只留最新完整 report;內含原作者(--author)、最後 review 時間、reviewed commit 與本地已看完標記 |
review-draft |
.maigo/review/<id>/draft.md |
orchestrator(/maigo:review §4.5) |
同上 | 待貼上 GitHub 的 review body 草稿;board_state.py 的 待送出 next_action 在這個檔存在時給 gh pr review --body-file 指令,不存在時改提示先起草 |
pr-comments |
.maigo/review/<id>/pr-comments.md |
orchestrator(/maigo:address-comments) |
同上 | PR 既有 review comment 的抓取與分類結果 |
reply-draft |
.maigo/review/<id>/reply-draft.md(自己的 PR 在 .maigo/pr/<id>/) |
orchestrator(/maigo:address-comments §6) |
同上 | 每則回覆草稿的正本檔,每則標明在哪裡回(inline thread / PR conversation 底部)、連結與前置條件;對話只印路徑與對照表 |
inline-comments |
.maigo/review/<id>/inline-comments.md(自己的 PR 在 .maigo/pr/<id>/) |
orchestrator(/maigo:review 裁決 gate) |
同上 | inline review comment 的草稿正本,裁決 gate 用;隨 PR 目錄一起封存 |
triage-rubric |
.maigo/issue/<id>/rubric.md |
🩵 Tomori | 同上 | issue triage 的對照基準 |
review_report.py publish 先原子寫入最新 review.md,才清理同目錄 review-N.md 與
.maigo/review-<id>.md 中可確認同 source 的舊報告;未知歸屬、較新的 timestamp、
草稿、rubric、手寫檔與其他 PR 保留。歸屬看 metadata 的 source 或舊 report 明確 PR URL,
不因為檔名相似就刪。清理結果回傳給 caller,同步修正 board 細節檔的報告連結。
review_report.py acknowledge 記「使用者已看完這版」,不送 GitHub、不改最後 review
時間;使用者在 board 把 👀 行勾成 [x],下次 /maigo:board 刷新就會呼叫它(--reviewed 等同勾上)。
新 head/作者留言讓 board 重新排入待看(👀 行自動取消勾);新 report 清除上一輪確認。
分目錄前的扁平檔(flat_exists:,只可讀)
巢狀佈局採用前寫下的 <kind>-<id>.md(例:review-rubric-42.md)——resolve_for_write()
發現這種檔案存在時,Resolution.flat_path 會填值(CLI 印 flat_exists: 那行),
只供讀取退路,永遠不當寫入目標;Write / Edit 寫進這個形狀會被
hooks/legacy_artifact_path_check.py
擋下。既有的這類檔案可用
scripts/migrate_legacy_artifacts.py
(先 dry-run 看清單,使用者同意後 --apply)搬進巢狀佈局,順手把 .maigo/i/*.md
的 ## 筆記 段裡指到舊檔名的連結改成新相對路徑。--apply 中途中斷時,重跑同一
條指令即可:它照第一次寫下的搬移對應表續跑,不重新規劃。
Work Board(board.md + i/<slug>.md)
| 種類 | 檔名規則 | 誰寫的 | 正典來源 | 生命週期 |
|---|---|---|---|---|
| Work Board 索引 | .maigo/board.md |
orchestrator(/maigo:board / /maigo:review) |
scripts/board_state.py + work-board skill |
跨 session 常駐,不隨單次任務結束而收檔 |
| Work Board 細節檔 | .maigo/i/<slug>.md |
同上 | 同上 | 跟著對應 issue/PR 的追蹤狀態走;沒有索引行引用的孤兒細節檔視為 dd(使用者刪了那一行),見 work-board skill §3a |
| 已結案封存 | .maigo/_archive/review/<id>/、.maigo/_archive/pr/<id>/、.maigo/_archive/i/<id>.md |
orchestrator(board_sync.py archive) |
scripts/board_sync.py + work-board skill §3「細節檔生命週期」 |
merged/closed/老化項目的 review/pr 目錄與細節檔從 review/、pr/、i/ 搬來這裡留存;不覆蓋既有封存,不被 board 對帳讀取 |
board 這條線是全 repo 最佳實踐——code 定正典(board_state.py)、skill 鏡射
人讀版本(work-board)、test 守一致(tests/test_board_state.py),三方鎖住,
本頁不重寫它的行文法,只在型錄裡佔一個位置。索引行的 @<login>(GitHub author.login)是必填:缺作者的行,
board_sync.py 的嚴格解析會報錯,refresh 讀現檔時放寬並補回;補不到就在旁註標 作者待補(警告,不是錯誤)。board 的內部狀態(排除紀錄、快照)放在
.maigo/_internal/board/,對帳、discovery 與排除規則見 work-board skill §3a。
_internal/:只給機器讀
.maigo/_internal/ 底下的所有內容都只給機器讀,使用者在 .maigo/ 根目錄只會看到給人讀的檔案。
型錄(maigo_dir_catalog 的 scan())與 /maigo:doctor 不列這個目錄(--tree 只計檔數)。board 部分
由 scripts/board_sync.py 自行建立與寫入;其餘列在同一張表:
| 檔案 | 用途 |
|---|---|
_internal/board/dropped.jsonl |
排除紀錄:每行一個 drop / revive 事件,只 append;dd 掉的項目之後不會被 discovery 補回,除非重新被指名 |
_internal/board/snapshot.json |
上次刷新結束時 board 上的項目與勾選狀態,用來偵測 dd 與 [x] 變化 |
_internal/log/* |
hook 寫的機器 log(見下節「非 markdown 機器狀態檔」) |
_internal/migrate-legacy-artifacts.manifest.json |
migrate_legacy_artifacts.py --apply 中斷時留存的搬移對應表,跑完即刪 |
_internal/tidy/backup/<UTC ts>/ |
/maigo:tidy --apply 動手前複製的備份,路徑是相對 .maigo/ 的原路徑;還原=複製回 .maigo/;不自動清,要刪由你自己決定 |
_internal/board/backup/<UTC ts>/ |
refresh --apply 寫回前複製的 board.md 與細節檔,只留最新 10 份;寫入失敗時用來還原 |
生命週期與 /maigo:tidy
每一類產物有一個 owner、一個結案條件、一個去向。結案之後的搬移與清理都走
/maigo:tidy(預設 dry-run,--apply 只做規則型動作);下面的門檻數字是
scripts/maigo_tidy.py 裡的常數,可以調整。
| 產物 | owner | 結案條件 | 去向 |
|---|---|---|---|
pr/<id>/、review/<id>/、issue/<id>/ |
該 PR/issue 的處理者(orchestrator 與 agent 寫入) | id 是純數字,且 GitHub 狀態是 merged 或 closed(gh pr view/gh issue view);查不到就不動,非純數字的 id(<repo>-<n>、slug)不逐筆列、在統計段彙總一行 |
鏡射搬到 _archive/<原相對路徑>(規則型,--apply 會做) |
i/<id>.md |
/maigo:board |
id 是純數字且對應 PR/issue merged 或 closed;<repo>-<n> 形的由 /maigo:board 處理,tidy 只在統計段彙總 |
同上 |
topic/<slug>/ |
寫 plan 的人 | 沒有外部訊號可查,只能由你勾選 | 勾選後封存到 _archive/topic/<slug>/ |
頂層舊檔(plan.md、plan-<id>.md、<kind>-<id>.md …) |
升級前的 maigo | 一律視為待遷移 | 遷移成巢狀佈局(規則型) |
頂層機器日誌(session-head.json、三個 jsonl) |
升級前的 hook | 一律視為待搬 | 搬進 _internal/log/,jsonl 新舊都在時把舊檔接在新檔前面(舊在前、新在後;session-head.json 以新檔為準)(規則型) |
_internal/log/*.jsonl |
hook | 超過 2,000 行 | 舊的搬成 <name>.1.jsonl,只留一代(規則型,門檻 LOG_ROTATE_MAX_LINES);/maigo:doctor 的統計只看現行檔,不含 .1.jsonl |
_archive/ 的項目 |
/maigo:board、/maigo:tidy |
封存後超過 90 天(ARCHIVE_RETENTION;以封存單位的 mtime 計——單位是 _archive/<group>/<id>(pr/review/issue/topic/i)或其餘 _archive/<name> 本身,單位內部檔的 mtime 不看;/maigo:board 與 /maigo:tidy 封存時都會把它重設成封存當下) |
列為 delete-candidate,一律要你逐項勾選;確認=備份後刪除 |
未登記檔(evals/、__titles.json、local-model-dispatch-plan.md 這類) |
不明 | catalog 判為 unregistered |
不隨 --apply 動;--confirm <path>=備份後刪除,--confirm-archive <path>=備份後封存到 _archive/,不點名就保留 |
.maigo/.maigo/ |
hook 在子目錄 cwd 下的殘留 | 一律視為殘留 | 同上(刪除或封存);要合併回上層請手動處理 |
規則型動作之外沒有「全部同意」的開關:刪除類與 topic/ 封存只對 --confirm 點名的那一筆動手。
每個動作前都先備份到 _internal/tidy/backup/<UTC ts>/。
非 markdown 機器狀態檔
一行帶過,內部用,非 agent 面向格式。四個 hook 寫的機器 log 在
.maigo/_internal/log/:session-head.json(session 開始時的 HEAD SHA)、
token-usage.jsonl(token usage metadata)、
test-failures.jsonl / soyo-must-fix.jsonl(retry / failure log)。
hook 一律寫到 repo 根目錄的 .maigo/(hooks/_maigo_root.py:git toplevel,
git 不可用時退回 payload cwd),不管 session 的 cwd 在哪個子目錄,也不會再長出
.maigo/.maigo/。讀取端先讀 _internal/log/ 的新檔,沒有才讀舊的頂層同名檔
(新舊都在時只讀新的、不合併);舊檔不由 hook 搬,留給 /maigo:tidy 處理。
其餘:__titles.json(內部快取)、_internal/migrate-legacy-artifacts.manifest.json
(scripts/migrate_legacy_artifacts.py --apply 的搬移對應表,只在一次 apply
沒跑完時留存,重跑時照它續跑,跑完即刪;升級前放在 .maigo/ 頂層的舊位置
讀取時也認、清理時一併刪)。
舊固定檔名與未登記檔案
升級前留下的舊固定檔名(.maigo/plan.md 這類,legacy_fixed_name)、分目錄前的
扁平檔(flat_identifier,見上一節)與不屬於上述任何種類的未登記檔案
(unregistered),預設只列不刪(要處理走 /maigo:tidy,刪除只對你勾選的那一筆動手)——正典邏輯見 scripts/maigo_dir_catalog.py
(六類:nested / identifier_named / flat_identifier / legacy_fixed_name /
registered_non_artifact / unregistered),人讀報告見
/maigo:doctor。要不要清由使用者自己決定,這份型錄與
doctor 報告都不建議刪除哪一個。
兩個字面上像 review kind 產物、但不是的檔名——categorize() 特別排除,
不會被搬移或擋下:review-batch-state.md(本 repo 找不到 producer,型錄列為
unregistered)、review-board.md(舊版 Work Board 檔名,
commands/board.md 仍會偵測並遷移它,型錄列為
registered_non_artifact)。