今天要解的問題
Day26 把 navi 做出來了:一個 Claude Code 的 mod,在 session 旁邊畫出 vault 的狀態。為什麼選 mod 而不是 skill、hook、MCP,以及放在哪、怎麼算、哪些驗證錯誤,都在那篇。這篇寫的是另一半:畫面上放了什麼、每一塊要我關注什麼。
做到後來,問題不再是「能不能做出來」,而是「讀不讀得下去」、「看了之後能做什麼」。這篇整理的是 navi 每個位置背後的那個問題。
想法與取捨
四個位置,各管一種注意力
mod 能畫的位置有好幾個,我最後用了四個,分成「常駐」和「叫出來」兩層:
| 位置 | 要我關注什麼 | 什麼時候看 |
|---|---|---|
| 橫條(輸入框上方) | 跟舊頁重逢 | 每次打字前瞄到 |
| 狀態列(輸入框下方) | 現在有沒有事要做 | 一直都在 |
| 輸入框本身 | 我打的連結對不對 | 打字的當下 |
/navi 側邊面板 | 整個 vault 的結構 | 想看才開(打 /navi 或點橫條的 ☰ Navi) |
分層的原則是一句話:常駐的地方只放「要不要動」的訊號,細節收進面板。

上圖是示意,標出四個位置各在哪;下面面板的部分都是實際截圖。
橫條:今日三頁,替舊 wiki 造一個重逢的機會
橫條放的是從全部 wiki 隨機抽的三頁,點頁名在 Obsidian 開:

這個 session 抽到的是 💡 畫畫集中注意力 · 📚 震撼世界的海報 · 📚 眾神之島-系列,最右邊是面板開關 ☰ Navi。輸入框下方那行灰字 navi Inbox 4 待分類 · 4 域 raw 未消化 就是狀態列,跟模型名稱排在同一行。
它要我關注的不是「該做什麼」,而是我已經寫過什麼。wiki 寫完之後,除非被連到,否則很少再被打開。橫條等於替每一頁舊 wiki 造一個日常的入口:每開一個 session 就有三頁被拉回眼前。實際用起來比預期好用,看到某一頁常常又接上新的想法。
幾個細節:
- 一頁 → 三頁:抽到的舊頁常常能接上新的想法,所以多抽幾頁
- 每天一組 → 每個 session 一組:用日期當種子時,同一天開幾個 session 都是同三頁。我想要的是「根據不同 session 產生獨立的」,所以改用 session id 當種子,一天開幾個 session 就挖出幾組
- 抽了就不換:只在還沒抽過時才抽,30 分鐘一次的統計不會把它換掉,要換就
/navi reroll - 域用 emoji,不用圖:我問過能不能放圖片,Desktop 可以放小 SVG,但會把橫條撐高,所以域名換成 emoji
- 拿掉用不到的按鈕:原本後面還跟著
triage (3)快捷鍵,我用不到,拿掉了 - 最右邊放面板開關:
☰ Navi點一下開面板、再點一下關。原本要開面板只能打/navi,現在常駐的橫條上就有入口
狀態列:只回答「現在有沒有事要做」
狀態列第一版放了待辦數、Inbox 數、本週新增數。看了之後我的反應是「只顯示要處理的」。
現在它只會是兩種樣子之一:
navi: Inbox 4 待分類 · 4 域 raw 未消化navi: 一切正常
我只想知道「現在有沒有事要做」。待辦數和本週新增移到面板的分頁標籤上(TODO 62、近期 +N),想看的時候打開面板就有。
Inbox 待分類代表「iPhone 擷取的東西還沒 triage」;raw 未消化代表「某個域堆了 5 份以上沒被任何 wiki 引用的 raw」。兩者對應的動作很明確:/inbox-triage、/wiki-build。狀態列只列「看了就知道下一步」的訊號。
輸入框:打字的當下就知道連結對不對
這是我看 mod 能做什麼時最意外的一項:輸入框本身也能畫,而且只改顯示、不改我打的字。
vault 的連結有幾條規則:連 wiki 用裸名、連書頁必須寫 [[books/wiki/書名]](因為 books 的 raw 和 wiki 同名)、hub 是策展頁。這些規則以前只能等 /vault-maintain 巡檢事後抓。現在依「連到哪一層」上色:
| 標示 | 意思 |
|---|---|
| 綠 | 連到 wiki 頁 |
| 粗體青 | 連到 hub |
| 變暗 | 只存在於 raw/logs(連到沉澱,不是概念頁) |
| 黃 | books 裸連結,raw 和 wiki 同名、該寫路徑 |
| 紅+底線 | 找不到這頁/vault 路徑不存在 |
| 紅+刪除線 | 開頭的指令拼錯,例如 /note-enrcih |
顏色的語意是統一的:紅=錯了、黃=提醒、綠=正常、變暗=次要。我打 [[cfgc-cupping-form]] 看它變綠的那一刻,覺得這是整個 mod 最實用的一塊。
指令拼錯有一個小設計:要打完、按了空白才檢查。不然打到一半的 /note- 會一路被畫刪除線,反而變成干擾。
面板:五個分頁,數字放在標籤上
/navi 打開的側邊面板,頂端是「問 vault…」輸入框(Enter 把 /wiki-query 問題 填進輸入框),下面五個分頁:
| 分頁 | 快捷鍵 | 要我關注什麼 |
|---|---|---|
| TODO 62 | t | 還沒做的事,依 ## 分區配色 |
| 近期 +N | r | 這週長了哪些頁 |
| 統計 | s | vault 的結構哪裡還有洞 |
| 趣味 | f | 單篇頁面的事實 |
| 說明 | h | 標色圖例、狀態列意義、快捷鍵 |

分頁標籤直接帶數字:TODO 62、近期 +2(這週新增 2 頁)。目前所在的分頁反白,每個分頁旁邊標著快捷鍵。
TODO 分頁:點一項就把對應的 skill 指令填進輸入框,例如 /note-explore ideas/raw/為何而寫-explore.md。能這樣對應,是因為 /inbox-triage 寫進 TODO.md 的格式固定是 - [ ] {動作}:{摘要} → \{路徑}``。區段配色讓我一眼分出是 triage 丟進來的(黃)、文章(洋紅)、研究(青)還是思考(紅)。
近期分頁:git 紀錄裡最近新增的 10 頁 wiki,點了在 Obsidian 開;旁邊的「路徑」按鈕把路徑插進輸入框,方便接著叫 Claude 處理它。
統計 vs 趣味:一個幫我擴展,一個讓我認識
這是我自己定的分工:統計放幫我擴展想法的網路視角,趣味放單篇的事實。
兩者的差別在「看完之後能做什麼」。統計的每個數字都指向一個動作:補連結、擴寫、外提書的概念。趣味的數字不要求動作,是讓我重新認識自己寫過的東西:哪一頁最長、誰是網路的中心、N 個月前的今天寫了什麼。
統計分頁中間原本還有一張各域 wiki 長條圖,跟表格的 wiki 欄重複,拿掉了。
統計分頁:用三個問題分區
統計分頁分成四個大區,每個大區的標題後面直接寫它在回答的問題:
| 大區 | 回答的問題 |
|---|---|
| 🔗 連結網路 | 哪裡還沒連起來 |
| ✍️ 內容待補 | 哪裡值得再寫 |
| 📚 書的擴散 | 書的概念流到哪些域 |
| 🗂️ 策展展間 | hub 的規模 |

🔗 連結網路,四個小節:
- 跨域引用:wiki 之間 832 條連結裡有 307 條跨域(37%)。表格一開始只有「跨域連出」「跨域連入」兩欄,我看了說:「要補上 wiki,不然我無法判斷是因為 wiki 太少,沒有連結是正常的」。補上 wiki 頁數和每頁平均、依每頁平均由少到多排之後,結論完全不同:finance 只有 1 頁,0 條不意外;engineer 有 35 頁、每頁卻只有 1.3 條,才是真正孤立的域,對照 books 每頁 4.8、art 4.5。每頁不到 1 條的用粗體
- 從未互連的域:列出哪兩個域之間一條連結都沒有。目前有 10 組,其中 art ↔ engineer、engineer ↔ others 也在裡面,跟上一張表的 engineer 對得上
- 可以互連的頁:共享 2 個以上主題 tag、卻互相沒連的兩頁,跨域的排前面。例如「情緒是一時的 ↔ 象與騎象人比喻」共享情緒、自我覺察、心理學三個 tag,卻互不相連。tag 一樣代表我自己認為它們談同一件事,卻沒寫出關係
- 沒有連入的 wiki:沒有任何頁連進來的 wiki(5 頁,art 就佔 3 頁)。沒人連的頁,除非被橫條抽到,很難再被看到

✍️ 內容待補:
- 值得擴充的短頁:被 3 頁以上連入、卻不到 1000 字。很多頁都指向它,代表它是個重要的概念,但內容撐不起那麼多指向。排第一的是「fun的力量」,13 頁連入、只有 597 字
- raw 與 wiki:每個域的 raw 堆積、已歸檔、wiki 數。堆積 ≥ 5 用粗體加
●:ideas 12、engineer 34、coffee 21、others 15,這四個就是狀態列上的「4 域 raw 未消化」。books 那欄畫—:books 的 raw 是讀書筆記本身,不算堆積。表格下方是對應的wiki-build ideas、wiki-build engineer… 按鈕
📚 書的擴散:
- 影響最多跨域 wiki 的書:其他域有幾頁 wiki 連到這本書(概念頁的
sources也算)。最多的是《好藝術-誰說了算》8 頁(art、ideas),其次是《6個月學會任何一種外語》7 頁(engineer、ideas)。影響的域幾乎都是「本來的主題域+ideas」——書的概念還沒真正擴散出去。另外,《好藝術-誰說了算》同時出現在上面的短頁清單:12 頁連入、書頁只有 507 字。影響最多頁的書,書頁本身最薄 - 還沒外提的書:書頁存在,但沒有任何其他域的 wiki 連到它,目前 2 本,旁邊附
book-review。這代表讀完、寫完心得,概念卻沒有離開 books 域。原本跟上一項擠在同一個小節,我說「與上面過於接近」,拆成獨立小節
每個數字旁邊都有一個「只填不送」的動作
統計分頁上幾乎每個小節都附一個按鈕:
| 小節 | 按鈕 | 填進輸入框的是 |
|---|---|---|
| 可以互連的頁 | 互連 | 請 Claude 看兩頁怎麼連,列理由給我確認 |
| 沒有連入的 wiki | 建連結 | 請 Claude 找 3 個可互連的頁,含跨域 |
| 值得擴充的短頁 | wiki-build | /wiki-build 頁名 |
| raw 堆積 | wiki-build | /wiki-build 域 |
| 還沒外提的書 | book-review | /book-review 書名 |
所有按鈕都只填不送:把指令或一段請求填進輸入框,按 Enter 的是我。理由是 session 在 worktree 裡,直接開跑的結果要等合回 main 才看得到,決定權要留在我手上。「互連」和「建連結」填的請求最後都寫著「列出理由給我確認後再寫入雙向連結」,這跟 vault 的跨域連結規則(經使用者確認才寫入)是同一件事。
這讓統計分頁從「報表」變成「待辦的來源」:看到 engineer 每頁 1.3 條,下一步不是記在心裡,而是點旁邊的按鈕。
趣味分頁:認識自己寫過的東西
趣味分頁也是四個大區,同樣把問題寫在標題上:
| 大區 | 問題 | 小節 |
|---|---|---|
| ⏳ 時間 | 什麼時候寫的 | N 個月前的今天、最早、最新 |
| 🔗 連結 | 誰是網路的中心 | 最多頁連進來、連出去最多、最常被引用的 raw |
| 📏 長度與結構 | 哪一頁最厚、最薄 | 最長、最短、章節最多、外部來源最多、圖片最多 |
| 🏷️ tag | 主題怎麼分布 | tag 最多的頁、最常用的主題 tag |

「N 個月前的今天」列出日期的「日」跟今天相同、月份更早的頁:不是隨機,而是一個月前、兩個月前的同一天寫了什麼。截圖這天有 33 頁符合,只列 3 頁,標題上寫明「共 33 頁,列 3 頁」,讓我知道還有更多。
「最多頁連進來」是 harness-engineering(15 頁)、llm-wiki-build-your-own(14 頁)、fun的力量(13 頁)。這些是網路的中心,對照統計分頁,fun的力量同時也是最該擴寫的短頁。
「最常用的主題 tag」會排除 review、explore、hub:這三個是 vault 規定的型別 tag,標的是頁面種類,不是主題。
讀得下去:兩層結構
功能做齊之後,問題換成讀不讀得下去。統計分頁所有小節原本平鋪在一起,我的反應是「閱讀起來極為吃力」。改成兩層:
- 大區:圓角框+青色粗體標題+灰字的問題
- 小節:
▸標題+灰字說明(門檻寫在這裡,例如「被 3 頁以上連入、卻不到 1000 字」),小節之間一條虛線
門檻直接寫在小節標題旁邊,是因為數字本身不會說話:不知道「短頁」的定義,就不知道該不該在意。
實作
下面挑幾段,對應上面的設計。
狀態列:只列要處理的事
// 狀態列只列要處理的事;都沒有就一句「一切正常」
function statusLine(inbox: number, stats: DomainStat[]): string {
const parts: string[] = []
if (inbox > 0) parts.push(`Inbox ${inbox} 待分類`)
const piled = stats.filter(s => s.rawOrphans >= PILE).length
if (piled > 0) parts.push(`${piled} 域 raw 未消化`)
return parts.length > 0 ? parts.join(' · ') : '一切正常'
}
PILE 是 5,對應 CLAUDE.md「raw 聚集 ≥ 5 檔提議 /wiki-build」。兩項都沒有時回傳「一切正常」。
被移出狀態列的數字放到分頁標籤:
const tabs: [string, string, string][] = [
['todo', `TODO ${ov.todo}`, 't'],
['recent', `近期 +${ov.week}`, 'r'],
['stats', '統計', 's'],
['facts', '趣味', 'f'],
['help', '說明', 'h'],
]
橫條:今日三頁
// 輸入框上方的橫條:今日三頁(域 emoji+頁名,點了在 Obsidian 開)+最右邊的面板開關
// 沒抽到頁或出錯時三頁隱藏,開關照樣留著
on('ui.render', { component: 'AbovePrompt' }, async ($, e, next) => {
if (e.props.hasSurvey) return next(e)
const today = (await read($, error)) ? [] : ((await read($, picks)) ?? [])
const { Box, Text, Button } = $.ui.resolve(e)
const togglePane = async () => {
const isUp = (await $.ui.panes()).some(pane => pane.id === PANE)
if (isUp) await $.ui.close({ id: PANE })
else await $.ui.open({ id: PANE, title: 'Navi' })
}
return (
<Box flexDirection="row" justifyContent="space-between">
<Box flexDirection="row" gap={1}>
{today.length > 0 && <Text dimColor>🎲</Text>}
{today.map((p, i) => (
<Box flexDirection="row">
{i > 0 && <Text dimColor> · </Text>}
<Text color={domainColor(p.domain)}>{domainEmoji(p.domain)} </Text>
<Button plain label={p.name} onPress={() => void openInObsidian($, p)} />
</Box>
))}
</Box>
<Button plain label="☰ Navi" onPress={() => void togglePane()} />
</Box>
)
})
橫條原本還讀了總覽數字,結果每 30 秒跟著重畫一次;拿掉那個讀取之後,它只在三頁換了才動。hasSurvey 時讓位給 Claude Code 自己的問卷,不搶位置。
最右邊的 ☰ Navi 是開關:$.ui.panes() 查面板是不是開著,開著就關、關著就開。外層用 justifyContent="space-between" 把三頁推到左邊、開關推到右邊。第一版是「沒抽到頁或讀取出錯就整條不畫」,現在改成只有三頁隱藏,開關照樣留著——面板的入口不該跟著今日三頁一起消失。
跨域引用:附上分母
// 附上 wiki 頁數與「每頁平均跨域連結」,才分得出是頁太少還是真的孤立;依每頁平均由少到多
const crossByDomain = domains
.map(domain => {
const wiki = pages.filter(p => domainOf(p.path) === domain).length
const out = crossOut.get(domain) ?? 0
const inn = crossIn.get(domain) ?? 0
return { domain, wiki, out, in: inn, perPage: wiki > 0 ? (out + inn) / wiki : 0 }
})
.sort((a, b) => a.perPage - b.perPage)
由少到多排,最該補的域排第一。只算 wiki 頁之間的連結,hub 不算:hub 本來就是跨域策展頁,算進來會讓每個域看起來都連得很好。
可以互連的頁、值得擴充的短頁
// 共同 tag 卻沒互連的頁:共享 ≥ 2 個主題 tag、兩邊都沒連對方;跨域優先
const tagPairs: PairItem[] = []
for (let i = 0; i < pages.length; i++) {
for (let j = i + 1; j < pages.length; j++) {
const a = pages[i]
const b = pages[j]
const shared = a.tags.filter(t => b.tags.includes(t))
if (shared.length < 2 || linkedEither(a.path, b.path)) continue
tagPairs.push({
a: item(a, 0),
b: item(b, 0),
note: shared.join('、'),
score: shared.length * 10 + (domainOf(a.path) !== domainOf(b.path) ? 5 : 0),
})
}
}
tagPairs.sort((x, y) => y.score - x.score)
// 被連很多但還很短的頁:連入 ≥ 3、不到 1000 字,值得擴充
const stubs = pages
.filter(p => (incoming.get(p.path) ?? 0) >= 3 && p.chars < 1000)
.sort((a, b) => (incoming.get(b.path) ?? 0) - (incoming.get(a.path) ?? 0))
.slice(0, 5)
.map(p => item(p, incoming.get(p.path) ?? 0, `${p.chars} 字`))
門檻是共享 2 個以上 tag。分數裡共享 tag 數是主項(每個 10 分),跨域只加 5 分:同樣共享 2 個 tag 時,跨域的那對排前面。
動作按鈕:填一段請求,不是填一個指令
const askLinks = (label: string, path: string) =>
void $.prompt.fill({
text: `幫 [[${label}]](${path}.md)找 3 個可以互相連結的頁面,含跨域,列出理由給我確認後再寫入雙向連結`,
})
<Button
plain
label="互連"
onPress={() =>
void $.prompt.fill({
text: `[[${pair.a.label}]] 和 [[${pair.b.label}]] 都有「${pair.note}」卻互不相連,幫我看兩頁之間可以怎麼連,列出理由給我確認後再寫入雙向連結`,
})
}
/>
不是每個動作都有對應的 skill。補連結沒有專門的指令,所以按鈕填的是一段寫好的請求,把「為什麼這兩頁該看」(共享的 tag)和「先列理由給我確認」都帶進去。填進輸入框之後還能改。
兩層結構
// 兩層結構:group(圓角框+彩色大標)裡放 section(▸ 小標),小節之間用虛線分開
const section = (title: string, hint: string, children: unknown) => (
<Box flexDirection="column">
<Text dimColor>{'┄'.repeat(24)}</Text>
<Text bold>
▸ {title} <Text dimColor>{hint}</Text>
</Text>
{children}
</Box>
)
const group = (title: string, hint: string, children: unknown[]) => (
<Box flexDirection="column" borderStyle="round" borderDimColor paddingX={1} marginBottom={1}>
<Text bold color="cyan">
{title} <Text dimColor>{hint}</Text>
</Text>
{children}
</Box>
)
hint 就是放問題和門檻的地方:大區放「哪裡還沒連起來」,小節放「被 3 頁以上連入、卻不到 1000 字」。統計和趣味兩個分頁共用這兩個函式,所以長相一致。
踩到的坑
這次的坑幾乎都不是程式錯誤,而是看到畫面之後才發現的設計問題。
1. 去框之後,分頁反而點不下去
Day26 嫌「框有點醜」,把清單的 Button 全部改成 plain 無框。
分頁也跟著無框,結果「有時候點不太下去」:可點的只有字本身,目前所在那頁還畫成普通文字,整排分不出哪些能點。分頁反過來改成有邊框的按鈕、目前頁用 primary 強調色,再加快捷鍵。同一個元件,樣式要跟著用途:清單裡大量的項目用無框,少數、要瞄準的導覽用有框。
2. 黃字看不清
raw 堆積原本用黃字標示,在淺色背景下我說「請用易閱讀的顏色」。改成粗體加 ● 標記,顏色只留給真正的警示。
3. 截圖時才看到:長頁名把一列撐爆
為這篇截圖時又看到兩處跑版。「可以互連的頁」裡,explore-feature-deferral-2026-05-06 ↔ from-executor-to-chooser-2026-05… 兩個頁名太長,整列超出面板寬度,後面的 tag 和「互連」按鈕被擠到看不見,上下還多出空行;「raw 與 wiki」表下方那排 wiki-build 按鈕也一樣,最後一顆被截掉。面板窄的時候表格和長列最先壞,這跟 TODO.md 裡「窄螢幕時表格改成清單」那一項是同一件事。
小結
navi 的畫面現在是這樣分工的:
- 橫條:今日三頁,每個 session 一組,替舊 wiki 造重逢的機會
- 狀態列:只回答「現在有沒有事要做」,沒事就說一切正常
- 輸入框:連結依層上色、路徑與指令拼錯即時標出
- 面板:統計以「哪裡還沒連起來、哪裡值得再寫、書的概念流到哪些域」分區,每個數字旁邊有一個只填不送的動作;趣味讓我重新認識寫過的頁
整理成幾條原則:常駐的地方只放「要不要動」的訊號;數字要有分母、門檻寫在標題旁;每個數字都要能接到一個動作;動作只填不送。
本文同步發表於 kiwi-walk.com:https://kiwi-walk.com/blogs/engineer/ironman-2026-day27-claude-code-mods/
