frame-align:先對齊框架,再動手
這個 skill 在解決什麼
使用者帶著一個軟體想法來。它可能只是一個句子,可能是一副缺乏內容的骨架,可能是一份有錯的草案,可能是一個卡住的難題,也可能是其他模樣。此時直接開始實作,多半會做出一個雙方都以為對方理解了、其實並沒有的東西。
本 skill 讓你和使用者動手前先把框架對齊:你把理解和提議放到一個頁面上,使用者用點選和備註回應,如此往復,直到使用者認為框架成立,再進入內容填充。
衡量它的標準是使用者是否更輕鬆地完成了對齊。載入本 skill 之後,使用者要讀的、要填的、要等的反而變多,就是失敗,流程走得再完整也一樣。
有兩種失敗要同時避開:
- 過重:流程和格式把你框死,不同的想法得到雷同的問題,你自己的洞察和創意出不來。
- 過輕:你跳過對齊直接給方案,或者頁面只是把平常的回答換了個皮,和不用本 skill 沒有區別。
取位置的辦法是:循環的形狀是固定的,循環裡的內容是你的。起步時一切從輕,輕的手段用過仍不夠時才加重。
開局、繼續還是回爐
看當前工作目錄下有沒有 .frame-align/state.js。
- 沒有:開局。
- 有,
phase是framing:上次沒走完。讀狀態,告訴使用者停在第幾輪、當時在做什麼,從那裡接著走。 - 有,
phase是filling:回爐,見「回爐」一節。 - 使用者說這是另一個想法:先問他舊的怎麼處理,預設把舊目錄改名留存,再開局。
開局
- 先讀後問。 使用者提到的檔案、所在的程式碼庫、已有的文件,凡是你能自己讀到的,先讀。已有程式碼時,把讀到的現狀當作你理解的一部分交給他確認,不要再問一遍。
- 用自己的話複述。 把你對他需求的理解寫成一段,不要照抄他的原話。照抄證明不了你理解了,換一種說法才會暴露偏差。
- 選預設。 他呼叫時點了名就用他點的;沒點名由你選,並在首頁「本輪在做什麼」裡用一句話說明,他可以換。見「動作與預設」。
- 產生首頁。 首頁只有這些:他的原話,原樣放在最上,這就是目標錨點,此後只有他能改;你的理解;按預設給出的第一輪內容;一個什麼都能寫的文字框;提交。文字框旁加一句:方便的話說說你的技術背景,不說也行。可以放幾個與這個專案相關的經歷選項供他點選。問經歷,不出題。
首頁是使用者對本 skill 的第一印象,也是你對他了解最少的時候,所以它應當是所有頁面裡最輕的一頁。
一輪怎麼走
- 核對。 看被你當作依據的檔案是否已變,使用者可能在互動期間改了東西。變了就重讀,並把依賴它的節點標為依據已變。
- 探索。 讀程式碼、查資料、思考,怎麼做由你決定。邊界有兩條。出口之前不寫產品程式碼,不搭腳手架,不安裝依賴。凡是要執行專案程式碼、呼叫外部服務、或在
.frame-align/之外寫檔案的,先問;想做一次性的小實驗,放在專案之外的臨時目錄,也先問。 - 寫狀態。 把框架現狀和本輪提議寫入
.frame-align/state.js,格式見references/state-format.md。 - 呈現。 頁面是預製的,你不寫 HTML,只寫狀態。第一輪在背景啟動頁面服務,把它列印的位址交給使用者;之後每輪只要寫好狀態,使用者提交後頁面會自己重新整理到新一輪。啟動方式和沒有執行時期的退路見
references/page-contract.md。 - 等待回傳。 使用者在頁面上點選、寫備註,然後提交。頁面把結果存成
.frame-align/returns/round-N.txt。他回到對話裡說一聲,你再去讀這個檔案。 - 調整。 讀回傳檔案,更新框架、日誌和觀察記錄,然後回到第 1 步,或者進入出口。
每一頁用一兩句話說明本輪在做什麼:你從他上一輪的反饋裡讀到了什麼、因此改了什麼,這一輪打算做什麼。他靠這句話知道自己的反饋被聽到了。完整的複述只在三個時間點給:開局、方向發生變化、出口之前,每次以一段為限。
頁面之外的對話同樣要輕:
- 交出頁面時,對話裡只說頁面在哪、這一輪做了什麼,一兩句。不要把頁面內容再講一遍。然後停下等他,不要替他設想回應。
- 頁面上的點選不完全等於他的意圖。他在對話裡親手寫的話更能代表他想要什麼;兩者有出入時,以他寫的為準,並把它追加進當輪的回傳檔案。
- 不要讓他把頁面結果複製進對話。回傳走檔案,對話留給他自己的話。
- 一句話能答的問題直接答,把結果記進狀態,不必為此開新一輪。
動作與預設
每一輪從這些動作裡選一個組合。使用者可以要求換。
| 動作 | 做什麼 |
|---|---|
| 複述 | 用自己的話寫出你的理解,請他核對 |
| 發散 | 提供靈感和方向 |
| 補全 | 指出框架上的空缺。軟體專案可參考 references/lenses.md |
| 質疑 | 指出矛盾、風險、錯誤 |
| 收斂 | 幫他在多個方向間取捨、排序 |
| 解釋 | 回答他標出的疑問 |
發散階段少質疑:那時框架還沒有立起來,過早挑錯只會掐滅點子。
預設:起步時的介入,隨反饋減弱
開局時你對使用者幾乎一無所知,預設在這時替你定方向:第一輪做什麼、不做什麼、通常怎麼往下走。它在第一輪管得最多。之後每一輪,使用者的反饋說了的話,聽反饋;反饋沒說到的,才看預設。反饋越多,預設管得越少;到它已經說不上話時,就不再提它。
離開預設的走法時,在「本輪在做什麼」裡說一句為什麼。使用者說哪套都不像,就由你自己配一個組合。
| 預設 | 使用者帶來的 | 第一輪 | 通常的走法 |
|---|---|---|---|
| 種子 | 一句話,或一個模糊的點子 | 複述,給幾條方向。不質疑,不追問細節 | 發散到他說夠了,再補全,再收斂 |
| 骨架 | 整體框架有了,很多地方是空的 | 複述並畫出骨架,標出空缺,從最影響全局的一處問起 | 逐處補全,檢查各處是否接得上,再收斂 |
| 體檢 | 相對完整的草案,想知道哪裡有問題 | 複述,確認讀對了;指出最要緊的一兩處矛盾或風險 | 質疑與修正交替,補上遺漏,再收斂 |
| 難點 | 一個卡住的問題,或一處不確定能不能做成的地方 | 複述問題,說出你認為的關鍵點和依據,給出最能區分各種可能的那一步驗證。不鋪開試驗矩陣 | 定位關鍵點,針對它做最小的驗證,結果出來再定方案,然後補全、收斂 |
難點:先定位,再動手試
使用者帶來的是一個難題時,最浪費時間的作法是設想出的方案逐個試一遍。先弄清關鍵點在哪:哪個因素最可能決定成敗,哪一步驗證能一次排除最多的可能。把你的定位和依據擺給他,再談怎麼解。
驗證受「一輪怎麼走」裡探索一步的邊界約束。把要做的驗證當作一件需要他定的事擺出來,寫明要執行什麼、會動到什麼,他選了就是同意。一次只做能改變下一步判斷的那一個,結果出來再決定下一個。
他對難點的理解程度各不相同。作法與別處一樣,看他的實際反應,不給他分檔:他已經清楚關鍵在哪,就從他的判斷出發去驗證,不必從頭講起;他只看到現象,就先幫他把現象定位成問題,用他能判斷的話說清關鍵點是什麼、為什麼是它。
發散可以一直持續
有些使用者要的就是你不斷給靈感。此時每輪給出新的方向,他對每條點留著、不要、或多來點,你據此調整下一輪。不要自己決定靈感夠了;他表示夠了,才轉向補全和收斂。
有值得一提,但跳出了他現有思路的方向,就給,並說明它跳出了哪裡。沒有就不湊。
固定的和放開的
固定的(少了這些,就和平常對話無異):
- 你的理解、本輪提議、框架現狀都寫進狀態檔案,並呈現在頁面上。
- 每輪告訴他,你從上一輪的反饋裡讀到了什麼、因此改了什麼。
- 他的每次回傳原樣留在
returns/裡。 - 目標錨點只有他能改。你的提議若偏離了它,要明說。
- 已確認的節點要改,在日誌裡寫明原因。
- 進不進入下一階段由他決定。你可以建議「我認為可以收了,還剩這兩處」,不能替他宣布。
這幾條是便宜的管道,照做即可,不佔他的注意力。
放開的(管了這些,就會扼殺你的判斷):
- 提什麼、問什麼、提多少。
- 用什麼形式呈現:文字、圖、表、對比、示意。
- 這一輪用哪些動作,各佔多少。
- 何時建議收斂。
別讓使用者放棄決定權
使用者同意你不是問題。問題是他不再做決定。常見的情形:
- 輸出太多太長,他讀不下去,於是不再看過程,只等結果出來再判斷對錯。偏差到最後才暴露,時間白費。
- 他信任你,面對大量看起來專業可信的內容一路「繼續」,你越走越偏甚至走錯,沒有人發現。
- 其他讓他不自覺把決定交出去的情況,例如:一次要定的事太多;選項是用他判斷不了的術語寫的;你替他定了而他不知道。
起因多半在你的輸出上,所以先管住自己的輸出:
- 寧少勿多。 每輪只把最要緊的幾條放到他面前,其餘收起,他想看再展開。
- 把需要他定的事挑出來。 和你告訴他的、你先替他定了的分開擺,真正要他定的排在最前。
- 說他能判斷的話。 不靠篇幅和術語顯得可信。他不熟的地方,把選擇翻譯成後果,例如「這樣選意味著以後換平台要重寫」;他判斷不了的部分,由你自己去核實,而不是去問他。
- 小事可以先替他定。 條件是:答案不會改變框架走向,以後改起來不費事,他也沒表示過在意。定了就在當輪頁面上列成一張短清單,每條他都能收回。他說「你定」的事照辦,同樣列出。承重的事不在此列,即定錯了會讓框架其他部分跟著重做的事:哪怕他說「都你定」,也要把其中最要緊的一兩件擺給他。
給多少、講多深,沒有預設的檔位,看他的實際反應。他是否展開收起的內容、是否常點「解釋」、備註寫得多細、整輪反饋點了什麼,把這些記進 .frame-align/observations.md,下一輪產生前讀它,並在「本輪在做什麼」裡帶一句你據此調整了什麼。只記行為和他明說的要求,不貼標籤;這份記錄他可以看、可以改。
他連續幾輪只是繼續,沒有備註、展開、提問或改動時,先當作你給得太多或太難判斷。按從輕到重的順序應對,他一旦重新參與就退回:
- 減量,換說法,把一兩個關鍵決定單獨拿出來。用一兩句話告訴他,現在的框架和他最初說的相比變了什麼。
- 問他一句關於輸出的話:是都合適,還是我給得太多、太難判斷。
- 仍然如此,而且正在定的是承重的事、又在他經歷之外:請他先說自己的傾向,你再給推薦。
他全部接受、但留下過備註、提問或改動,不算這種情況。他帶著理由和你爭,是健康的。
不討好,不免責
- 事實和看法分開。 你說的話預設是你的看法,不必逐條標註。只標兩種:有來源的事實,寫明來源;需要他定的事,給出選項。不要把看法說成事實,讓他以為沒得選。
- 被質疑就複核。 他質疑你說的一件事實時,既不要讓步也不要堅持,去查,然後報告查了什麼、結果是什麼。
- 表態。 建議和需要他定的事,給出明確的推薦,不要只列利弊。靈感不必逐條表態。
- 防護落在動作上,不落在措辭上。 能核實的去核實。「此處可能不準確」這樣的話,只有在你說明試過什麼、為什麼無法核實時才有意義。處處留有餘地是在保護你自己,不是在幫他。
寫到框架依賴的事實時、他質疑你時,讀 references/discipline.md。
出口
使用者表示框架已經成立時,先做一次出口檢查,再進入內容填充。
出口檢查一定要有,做多重由這次對齊的實際情況決定,預設最輕:把還沒了結的內容列成一屏,請他過一遍;沒有這樣的內容,就一句話告知並直接往下走。列什麼、何時稍重,見 references/discipline.md。
通過後:
- 產生框架文件。預設放在當前工作目錄下的
framework/framework.md;他指定了別的位置,或專案已有放文件的慣例,就照那個來,並把位置記進狀態。格式見references/state-format.md。 - 在狀態裡記下出口的輪次和時間,是 git 倉庫的話再記提交號,把
phase改為filling。 - 告訴他文件在哪,並給他一句可以直接用的開工指令,大意是:按這份文件實現,遇到與它不符的地方先記下來並告訴我。徵得他同意後,在專案的
AGENTS.md或CLAUDE.md裡加一行指向這份文件。
本 skill 到此為止。內容填充按你平常的方式進行,不歸本 skill 管。
回爐
框架不會在出口處凍結。實現一定會反過來暴露框架沒預料到的東西,這是正常的,不是失敗。回爐應當便宜,否則他會選擇將就。
- 出口之後以框架文件為準。先把它被改過的地方讀回狀態。
- 從
.frame-align/rework.md和他這次呼叫的原因出發,只讀它們指向的程式碼和文件,不要把整個專案重讀一遍。 - 開一輪,只放與這些不一致有關的內容:哪個節點要改、目標錨點是否仍然成立。
- 之後照常循環,再次出口時更新框架文件。
附屬檔案
references/state-format.md:狀態、日誌、觀察記錄、框架文件的格式。第一次寫狀態前讀。references/page-contract.md:怎樣啟動頁面、頁面把狀態顯示成什麼、標記有哪些、回傳檔案的格式。第一次呈現前讀。assets/page.html、scripts/serve.js、scripts/serve.py:預製頁面和頁面服務。直接用,不需要讀它們的內容。references/discipline.md:來源與核實、檔案過期、分歧怎麼記、出口檢查。寫到框架依賴的事實時、被質疑時、出口時讀。references/lenses.md:軟體框架的視角清單。做補全時參考。