mosaic-headless 1.17.1 → 1.17.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.ja.md CHANGED
@@ -19,6 +19,21 @@ npx mosaic-headless cursor --to ./my-project
19
19
  npx mosaic-headless --list # 対応 8 プラットフォーム
20
20
  ```
21
21
 
22
+ | プラットフォーム | 何が入るか | どこに |
23
+ |---|---|---|
24
+ | Claude Code | スキル一式:SKILL.md + references/ + tools/ + data/ + sites/ | `~/.claude/skills/` または `./.claude/skills/` |
25
+ | Codex CLI | スキル一式 | `~/.codex/` |
26
+ | Gemini CLI | スキル一式 | `~/.gemini/` |
27
+ | GitHub Copilot | スキル一式に加え、`copilot-instructions.md` へ追記 | `./.github/` |
28
+ | Cursor | references を埋め込んだ `.mdc` ルール 1 本 | `~/.cursor/rules/` |
29
+ | Windsurf | references を埋め込んだルールファイル 1 本 | `./.devin/` |
30
+ | Continue | references を埋め込んだルールファイル 1 本 | `~/.continue/` |
31
+ | Claude.ai | プロジェクトスキルとしてアップロードする zip | 保存した場所 |
32
+
33
+ 各プラットフォームのインストールはリリースゲートがテンプレートに対して検証する。ツールの
34
+ 実行には Python 3 と Playwright が必要。ルールファイル型のプラットフォームには知識だけが
35
+ 入り、ツールは入らない。
36
+
22
37
  **更新は自動では起きない。** npm に新版が出ても、エージェントが読み込むフォルダは変わらない。
23
38
  インストーラを `--force` 付きで再実行する(付けないと、手を入れた可能性のある SKILL.md の
24
39
  上書きを拒否する):
@@ -27,7 +42,6 @@ npx mosaic-headless --list # 対応 8 プラットフォーム
27
42
  npx mosaic-headless@latest claude-code --global --force
28
43
  ```
29
44
 
30
- Python 3 と Playwright はツールを*動かす*ときに必要で、インストールには不要。
31
45
 
32
46
  ## これは何か
33
47
 
@@ -40,6 +54,40 @@ fractional-index の文字列。エディタはこのモデルの一クライア
40
54
  計測したもの — と、モデルを通して書き、出てきたものを検証し、Elementor からページを持ち込む
41
55
  ためのツール群である。
42
56
 
57
+ ## 部品のつながり
58
+
59
+ ```mermaid
60
+ flowchart LR
61
+ subgraph measure["一度だけ、実サイトに対して計測"]
62
+ SRC[プラグインのソース] -->|extract_*.py| D[(data/*.csv)]
63
+ SW[sweep_*.py / probe_*.py] -->|commit・描画・断言| D
64
+ end
65
+
66
+ subgraph write["あなたが作るすべてのページ"]
67
+ Q[mo.py] -->|答えは一つ、計測結果が先頭| SPEC[ページ spec]
68
+ EL[Elementor _elementor_data] -->|from_elementor.py| SPEC
69
+ SPEC -->|build_page.py が壊れるものを拒否| REST[Mosaic REST:checkout・check・commit]
70
+ REST --> DB[(23 テーブル)]
71
+ DB --> PAGE[配信されたページ]
72
+ end
73
+
74
+ subgraph verify["commit を信用しない"]
75
+ PAGE --> V1[verify_rwd.py]
76
+ PAGE --> V2[verify_browser.py + デザイン監査]
77
+ PAGE --> V3[verify_intro.py / verify_loop.py]
78
+ PAGE --> V4[verify_conversion.py]
79
+ V1 & V2 & V3 & V4 --> CSV[(検証 CSV)]
80
+ CSV --> GATE[check-release.mjs]
81
+ end
82
+
83
+ D --> Q
84
+ D --> SPEC
85
+ ```
86
+
87
+ 左から右へ:表は一度だけ計測して同梱される;すべてのページは表を通して書かれ、表が否と
88
+ 言えば拒否される;配信されたページを読み戻し、結果がリリースゲートの見る表に記録される
89
+ までは何も信用しない。
90
+
43
91
  ## 唯一のルール
44
92
 
45
93
  **ノード型、プロパティ名、列挙値、スタイルキー、Free/Pro の判断を記憶から書かない。
@@ -110,6 +158,25 @@ commit の成功はページが動く証拠ではないし、正しいスタイ
110
158
  `SKIPPED`、`NO_HOST`、`INCONCLUSIVE` は合格率に決して繰り込まない。自らの盲点を成功として
111
159
  数えるスイープこそ、このスキルが反対しているものだ。
112
160
 
161
+ ## 引くのに何トークンかかるか
162
+
163
+ Mosaic のノード型やスタイルキーが実際に何を受け取るかをエージェントが知る方法は三つ。
164
+ 同じ六つの課題を tiktoken で計測(`tools/benchmark_tokens.py`、自分で実行できる):
165
+
166
+ | 課題 | ソースを読む | 全テーブル読込 | `mo.py` で引く |
167
+ |---|---:|---:|---:|
168
+ | 見出し・段落・リンク付きボタンを置く | 10,005 | 259,539 | **961** |
169
+ | padding・ボーダー・角丸をレスポンシブに設定 | 3,490 | 259,539 | **396** |
170
+ | アコーディオンが使えるか、どう入れ子にするか | 15,615 | 259,539 | **397** |
171
+ | 実際にコンパイルされる hover/focus 状態を探す | 3,619 | 259,539 | **1,054** |
172
+ | ある CSS を出す Mosaic のキーを探す | 1,862 | 259,539 | **51** |
173
+ | commit 前に何が危険かを知る | 63,172 | 259,539 | **288** |
174
+
175
+ **ソースを読むより 71〜99.5%、全テーブル読込より 99.6% 以上トークンが少ない** — しかも
176
+ 六つのうち四つはソースでは答えられない。「宣言されている」と「コンパイルされる」は別の
177
+ 問いで、後者を問うたのはスイープだけだからだ。テーブルは合計 259,539 トークン。決して
178
+ まとめて読み込まないこと。`mo.py` がクエリである。
179
+
113
180
  ### 書く前に知っておくべき結果
114
181
 
115
182
  **`group` に属するプロパティは単独で設定しても無効。** 両方向で厳密:グループ外の 78 個は
@@ -167,14 +234,13 @@ loop grid、フォーム、カウントダウン、サードパーティ addon
167
234
  | `sweep_*.py` / `probe_*.py` | 表を作った計測器そのもの |
168
235
  | `bootstrap_probe_theme.php` / `mint_session.php` | ライセンス不要の実験用テーマと、WP-CLI から作る REST セッション |
169
236
 
170
- ## 実例、ライブで
237
+ ## 実例
171
238
 
172
- `sites/_moksa.py` はテーブルだけで本物のスタジオサイトを構築し、参照実装として同梱される。
173
- **https://mosaic.moksaweb.com/** で公開中:1,286 ノードのホームページに、名前付き view timeline
174
- によるスクロール追従の条項インデックス;浮世絵の版を一枚ずつ刷っていく入場シーケンス;
175
- 隅で永遠に刷り続け、タップで拡大する版;そして UI 全体が shortcode を実行する 1 つの `code`
176
- ノードから届く WooCommerce の [My Account](https://mosaic.moksaweb.com/my-account/) ページ。
177
- 自前の JavaScript はどこにもない。
239
+ `sites/_moksa.py` はテーブルだけで本物のスタジオサイトを構築し、参照実装として同梱される:
240
+ 1,286 ノードのホームページに、名前付き view timeline によるスクロール追従の条項インデックス;
241
+ 浮世絵の版を一枚ずつ刷っていく入場シーケンス;隅で永遠に刷り続け、タップで拡大する版;
242
+ そして UI 全体が shortcode を実行する 1 つの `code` ノードから届く WooCommerce の My Account
243
+ ページ。自前の JavaScript はどこにもない。`data/` のすべての検証表はこれに対して作られた。
178
244
 
179
245
  ## どこから始めるか
180
246
 
package/README.ko.md CHANGED
@@ -19,6 +19,20 @@ npx mosaic-headless cursor --to ./my-project
19
19
  npx mosaic-headless --list # 지원하는 8개 플랫폼
20
20
  ```
21
21
 
22
+ | 플랫폼 | 무엇이 설치되나 | 어디에 |
23
+ |---|---|---|
24
+ | Claude Code | 스킬 전체: SKILL.md + references/ + tools/ + data/ + sites/ | `~/.claude/skills/` 또는 `./.claude/skills/` |
25
+ | Codex CLI | 스킬 전체 | `~/.codex/` |
26
+ | Gemini CLI | 스킬 전체 | `~/.gemini/` |
27
+ | GitHub Copilot | 스킬 전체, 그리고 `copilot-instructions.md`에 섹션 추가 | `./.github/` |
28
+ | Cursor | references를 내장한 `.mdc` 규칙 파일 하나 | `~/.cursor/rules/` |
29
+ | Windsurf | references를 내장한 규칙 파일 하나 | `./.devin/` |
30
+ | Continue | references를 내장한 규칙 파일 하나 | `~/.continue/` |
31
+ | Claude.ai | 프로젝트 스킬로 업로드할 zip | 저장한 곳 |
32
+
33
+ 모든 플랫폼 설치는 릴리스 게이트가 템플릿에 대해 검증한다. 도구 실행에는 Python 3와
34
+ Playwright가 필요하다; 규칙 파일 플랫폼은 지식만 받고 도구는 받지 않는다.
35
+
22
36
  **업데이트는 저절로 되지 않는다.** npm에 새 버전이 올라가도 에이전트가 읽는 폴더는 그대로다.
23
37
  인스톨러를 `--force`와 함께 다시 실행할 것(없으면 손댔을지 모르는 SKILL.md 덮어쓰기를 거부한다):
24
38
 
@@ -26,7 +40,6 @@ npx mosaic-headless --list # 지원하는 8개 플랫폼
26
40
  npx mosaic-headless@latest claude-code --global --force
27
41
  ```
28
42
 
29
- Python 3와 Playwright는 도구를 *실행*할 때 필요하고, 설치에는 필요 없다.
30
43
 
31
44
  ## 이것은 무엇인가
32
45
 
@@ -37,6 +50,40 @@ Mosaic은 페이지를 **23개의 커스텀 테이블**에 보관한다. `post_c
37
50
  이 스킬은 그 모델의 지도 — 소스를 읽어 얻은 것이 아니라 실제 설치에 대해 측정한 것 — 에,
38
51
  모델을 통해 쓰고, 나온 것을 검증하고, Elementor에서 페이지를 들여오는 도구를 더한 것이다.
39
52
 
53
+ ## 부품이 맞물리는 방식
54
+
55
+ ```mermaid
56
+ flowchart LR
57
+ subgraph measure["한 번만, 실제 사이트에 대해 측정"]
58
+ SRC[플러그인 소스] -->|extract_*.py| D[(data/*.csv)]
59
+ SW[sweep_*.py / probe_*.py] -->|commit·렌더·단언| D
60
+ end
61
+
62
+ subgraph write["당신이 만드는 모든 페이지"]
63
+ Q[mo.py] -->|답 하나, 측정 판정이 먼저| SPEC[페이지 spec]
64
+ EL[Elementor _elementor_data] -->|from_elementor.py| SPEC
65
+ SPEC -->|build_page.py가 깨질 것을 거부| REST[Mosaic REST: checkout·check·commit]
66
+ REST --> DB[(23 테이블)]
67
+ DB --> PAGE[전달된 페이지]
68
+ end
69
+
70
+ subgraph verify["commit을 믿지 않는다"]
71
+ PAGE --> V1[verify_rwd.py]
72
+ PAGE --> V2[verify_browser.py + 디자인 감사]
73
+ PAGE --> V3[verify_intro.py / verify_loop.py]
74
+ PAGE --> V4[verify_conversion.py]
75
+ V1 & V2 & V3 & V4 --> CSV[(검증 CSV)]
76
+ CSV --> GATE[check-release.mjs]
77
+ end
78
+
79
+ D --> Q
80
+ D --> SPEC
81
+ ```
82
+
83
+ 왼쪽에서 오른쪽으로: 표는 한 번만 측정해 동봉한다; 모든 페이지는 표를 통해 쓰이고 표가
84
+ 아니라고 하면 거부된다; 전달된 페이지를 읽어 되돌리고 그 결과가 릴리스 게이트가 검사하는
85
+ 표에 기록되기 전까지는 아무것도 믿지 않는다.
86
+
40
87
  ## 단 하나의 규칙
41
88
 
42
89
  **노드 타입, 프로퍼티 이름, 열거값, 스타일 키, Free/Pro 판단을 기억으로 쓰지 말 것.
@@ -107,6 +154,24 @@ commit 성공은 페이지가 동작한다는 증거가 아니고, 올바른 스
107
154
  `SKIPPED`, `NO_HOST`, `INCONCLUSIVE`는 결코 합격률에 섞지 않는다. 자기 사각지대를 성공으로
108
155
  세는 스윕이야말로 이 스킬이 반대하는 것이다.
109
156
 
157
+ ## 조회 한 번의 비용
158
+
159
+ Mosaic 노드 타입이나 스타일 키가 실제로 무엇을 받는지 에이전트가 알아내는 방법은 셋. 같은
160
+ 여섯 과제를 tiktoken으로 측정(`tools/benchmark_tokens.py`, 직접 실행 가능):
161
+
162
+ | 과제 | 소스 읽기 | 전체 표 로드 | `mo.py` 조회 |
163
+ |---|---:|---:|---:|
164
+ | 제목, 문단, 링크 버튼 배치 | 10,005 | 259,539 | **961** |
165
+ | padding, 테두리, 둥근 모서리를 반응형으로 | 3,490 | 259,539 | **396** |
166
+ | 아코디언이 쓸 만한지, 어떻게 중첩하는지 | 15,615 | 259,539 | **397** |
167
+ | 실제로 컴파일되는 hover/focus 상태 찾기 | 3,619 | 259,539 | **1,054** |
168
+ | 어떤 CSS를 내는 Mosaic 키 찾기 | 1,862 | 259,539 | **51** |
169
+ | commit 전에 무엇이 위험한지 알기 | 63,172 | 259,539 | **288** |
170
+
171
+ **소스 읽기보다 71–99.5%, 전체 표 로드보다 99.6% 이상 적은 토큰** — 게다가 여섯 중 넷은
172
+ 소스로는 애초에 답할 수 없다. "선언됨"과 "컴파일됨"은 다른 질문이고, 후자를 물은 것은
173
+ 스윕뿐이다. 표는 합쳐서 259,539 토큰; 절대 통째로 로드하지 말 것. `mo.py`가 쿼리다.
174
+
110
175
  ### 쓰기 전에 알아둘 결과
111
176
 
112
177
  **`group`에 속한 프로퍼티는 단독으로 설정하면 무효다.** 양방향 모두 정확: 그룹 밖 78개는
@@ -163,14 +228,13 @@ loop grid, 폼, 카운트다운, 서드파티 addon — 은 동적이라 될 노
163
228
  | `sweep_*.py` / `probe_*.py` | 표를 만든 계측기 그 자체 |
164
229
  | `bootstrap_probe_theme.php` / `mint_session.php` | 라이선스 없는 실험용 테마와 WP-CLI에서 만드는 REST 세션 |
165
230
 
166
- ## 실제 예제, 라이브로
231
+ ## 실제 예제
167
232
 
168
- `sites/_moksa.py`는 테이블만으로 진짜 스튜디오 사이트를 구축하며 참조 구현으로 동봉된다.
169
- **https://mosaic.moksaweb.com/** 에 올라가 있다: 1,286 노드의 홈페이지에 이름 있는 view
170
- timeline으로 스크롤을 추적하는 조항 인덱스; 우키요에 판을 한 장씩 찍어내는 진입 시퀀스;
171
- 구석에서 영원히 찍어내고 탭하면 확대되는 판; 그리고 UI 전체가 shortcode를 실행하는 하나의
172
- `code` 노드로 들어오는 WooCommerce [My Account](https://mosaic.moksaweb.com/my-account/)
173
- 페이지. 자체 JavaScript는 어디에도 없다.
233
+ `sites/_moksa.py`는 테이블만으로 진짜 스튜디오 사이트를 구축하며 참조 구현으로 동봉된다:
234
+ 1,286 노드의 홈페이지에 이름 있는 view timeline으로 스크롤을 추적하는 조항 인덱스; 우키요에
235
+ 판을 한 장씩 찍어내는 진입 시퀀스; 구석에서 영원히 찍어내고 탭하면 확대되는 판; 그리고 UI
236
+ 전체가 shortcode를 실행하는 하나의 `code` 노드로 들어오는 WooCommerce My Account 페이지.
237
+ 자체 JavaScript는 어디에도 없다. `data/`의 모든 검증 표는 이것에 대해 만들어졌다.
174
238
 
175
239
  ## 어디서 시작할까
176
240
 
package/README.md CHANGED
@@ -19,6 +19,21 @@ npx mosaic-headless cursor --to ./my-project
19
19
  npx mosaic-headless --list # all eight platforms
20
20
  ```
21
21
 
22
+ | platform | what is installed | where |
23
+ |---|---|---|
24
+ | Claude Code | full skill: SKILL.md + references/ + tools/ + data/ + sites/ | `~/.claude/skills/` or `./.claude/skills/` |
25
+ | Codex CLI | full skill | `~/.codex/` |
26
+ | Gemini CLI | full skill | `~/.gemini/` |
27
+ | GitHub Copilot | full skill, plus a section appended to `copilot-instructions.md` | `./.github/` |
28
+ | Cursor | one `.mdc` rule with the references embedded | `~/.cursor/rules/` |
29
+ | Windsurf | one rule file with the references embedded | `./.devin/` |
30
+ | Continue | one rule file with the references embedded | `~/.continue/` |
31
+ | Claude.ai | a zip to upload as a project skill | wherever you save it |
32
+
33
+ Every platform install is verified by the release gate against its template. The
34
+ tools need Python 3 and Playwright to run; the rule-file platforms get the knowledge
35
+ without the tools.
36
+
22
37
  **Updating does not happen on its own.** A new version on npm changes nothing in
23
38
  the folder your agent loads; re-run the installer with `--force` (without it, it
24
39
  refuses to overwrite a SKILL.md you may have edited):
@@ -27,7 +42,6 @@ refuses to overwrite a SKILL.md you may have edited):
27
42
  npx mosaic-headless@latest claude-code --global --force
28
43
  ```
29
44
 
30
- Python 3 and Playwright are needed to *run* the tools, not to install.
31
45
 
32
46
  ## What this is
33
47
 
@@ -40,6 +54,41 @@ This skill is the map of that model — measured against a live install rather t
40
54
  read off the source — plus the tools to write through it, check what came out, and
41
55
  bring pages in from Elementor.
42
56
 
57
+ ## How the pieces fit
58
+
59
+ ```mermaid
60
+ flowchart LR
61
+ subgraph measure["measured once, against a live install"]
62
+ SRC[plugin source] -->|extract_*.py| D[(data/*.csv)]
63
+ SW[sweep_*.py / probe_*.py] -->|commit, render, assert| D
64
+ end
65
+
66
+ subgraph write["every page you build"]
67
+ Q[mo.py] -->|one answer, verdict first| SPEC[page spec]
68
+ EL[Elementor _elementor_data] -->|from_elementor.py| SPEC
69
+ SPEC -->|build_page.py refuses what breaks| REST[Mosaic REST: checkout, check, commit]
70
+ REST --> DB[(23 tables)]
71
+ DB --> PAGE[served page]
72
+ end
73
+
74
+ subgraph verify["never trust the commit"]
75
+ PAGE --> V1[verify_rwd.py]
76
+ PAGE --> V2[verify_browser.py + design audit]
77
+ PAGE --> V3[verify_intro.py / verify_loop.py]
78
+ PAGE --> V4[verify_conversion.py]
79
+ V1 & V2 & V3 & V4 --> CSV[(verification CSVs)]
80
+ CSV --> GATE[check-release.mjs]
81
+ end
82
+
83
+ D --> Q
84
+ D --> SPEC
85
+ ```
86
+
87
+ Left to right: the tables are measured once and shipped; every page is written
88
+ through them and refused when they say no; and nothing is believed until the
89
+ delivered page has been read back and the result recorded in a table that the
90
+ release gate checks.
91
+
43
92
  ## The one rule
44
93
 
45
94
  **Never write a node type, property name, enum value, style key or Free/Pro claim
@@ -114,6 +163,26 @@ factories, so Pro types register and render regardless.
114
163
  `SKIPPED`, `NO_HOST` and `INCONCLUSIVE` are never folded into a pass rate. A sweep
115
164
  that scores its own blind spots as successes is the thing this skill argues against.
116
165
 
166
+ ## What it costs to consult
167
+
168
+ Three ways an agent can learn what a Mosaic node type or style key actually takes,
169
+ priced on the same six tasks with tiktoken (`tools/benchmark_tokens.py`; run it
170
+ yourself):
171
+
172
+ | task | read the source | load every table | `mo.py` query |
173
+ |---|---:|---:|---:|
174
+ | place a heading, a paragraph and a linked button | 10,005 | 259,539 | **961** |
175
+ | set padding, a border and a radius, responsively | 3,490 | 259,539 | **396** |
176
+ | decide whether the accordion is usable, and how to nest it | 15,615 | 259,539 | **397** |
177
+ | find which hover/focus states actually compile | 3,619 | 259,539 | **1,054** |
178
+ | find which Mosaic key drives one CSS property | 1,862 | 259,539 | **51** |
179
+ | know what is unsafe before committing anything | 63,172 | 259,539 | **288** |
180
+
181
+ **71–99.5% fewer tokens than reading the source, 99.6%+ fewer than loading the
182
+ tables** — and the source could not have answered four of the six at all, because
183
+ "declared" and "compiles" are different questions and only the sweeps asked the
184
+ second one. The tables total 259,539 tokens; never load them. `mo.py` is the query.
185
+
117
186
  ### Results worth knowing before you write anything
118
187
 
119
188
  **A property that belongs to a `group` is inert when set on its own.** Exact in both
@@ -174,15 +243,15 @@ and heading level — and it earned its place at once: it caught the converter l
174
243
  | `sweep_*.py` / `probe_*.py` | the instruments the tables were made with |
175
244
  | `bootstrap_probe_theme.php` / `mint_session.php` | a licence-free scratch theme and a REST session from WP-CLI |
176
245
 
177
- ## The worked example, live
246
+ ## The worked example
178
247
 
179
248
  `sites/_moksa.py` builds a real studio site through the tables alone and ships as
180
- the reference. It is up at **https://mosaic.moksaweb.com/**: a homepage of 1,286
181
- nodes with a scroll-tracking clause index on named view timelines, an entrance
182
- sequence that prints an ukiyo-e sheet one carved block at a time, a corner plate
183
- that keeps printing forever and opens when tapped, and a WooCommerce
184
- [My Account](https://mosaic.moksaweb.com/my-account/) page whose UI arrives through
185
- one `code` node running a shortcode. No JavaScript of its own anywhere.
249
+ the reference: a homepage of 1,286 nodes with a scroll-tracking clause index on named
250
+ view timelines, an entrance sequence that prints an ukiyo-e sheet one carved block
251
+ at a time, a corner plate that keeps printing forever and opens when tapped, and a
252
+ WooCommerce My Account page whose UI arrives through one `code` node running a
253
+ shortcode. No JavaScript of its own anywhere. Every verification table in `data/`
254
+ was produced against it.
186
255
 
187
256
  ## Where to start
188
257
 
package/README.zh-TW.md CHANGED
@@ -19,6 +19,20 @@ npx mosaic-headless cursor --to ./my-project
19
19
  npx mosaic-headless --list # 全部八個平台
20
20
  ```
21
21
 
22
+ | 平台 | 裝什麼 | 裝到哪 |
23
+ |---|---|---|
24
+ | Claude Code | 完整技能:SKILL.md + references/ + tools/ + data/ + sites/ | `~/.claude/skills/` 或 `./.claude/skills/` |
25
+ | Codex CLI | 完整技能 | `~/.codex/` |
26
+ | Gemini CLI | 完整技能 | `~/.gemini/` |
27
+ | GitHub Copilot | 完整技能,外加一段附到 `copilot-instructions.md` | `./.github/` |
28
+ | Cursor | 一個內嵌 references 的 `.mdc` 規則檔 | `~/.cursor/rules/` |
29
+ | Windsurf | 一個內嵌 references 的規則檔 | `./.devin/` |
30
+ | Continue | 一個內嵌 references 的規則檔 | `~/.continue/` |
31
+ | Claude.ai | 一個 zip,上傳為專案技能 | 你存的地方 |
32
+
33
+ 每個平台的安裝都由發布閘門對照其模板驗證。工具要跑需要 Python 3 和 Playwright;規則檔類的
34
+ 平台拿到的是知識,沒有工具。
35
+
22
36
  **更新不會自己發生。** npm 上有新版,不代表你的 agent 載入的那個資料夾有變;要重跑安裝器並加
23
37
  `--force`(不加的話它會拒絕覆蓋你可能改過的 SKILL.md):
24
38
 
@@ -26,7 +40,6 @@ npx mosaic-headless --list # 全部八個平台
26
40
  npx mosaic-headless@latest claude-code --global --force
27
41
  ```
28
42
 
29
- Python 3 和 Playwright 是*跑工具*時才需要,安裝不用。
30
43
 
31
44
  ## 這是什麼
32
45
 
@@ -37,6 +50,39 @@ Mosaic 把一個頁面放在 **23 張自訂資料表**裡,不在 `post_content
37
50
  這個技能就是那個模型的地圖——對照真實站台量出來的,不是讀原始碼讀出來的——外加一組
38
51
  工具:透過模型寫入、檢查寫出來的東西、把 Elementor 的頁面搬進來。
39
52
 
53
+ ## 各部分怎麼接起來
54
+
55
+ ```mermaid
56
+ flowchart LR
57
+ subgraph measure["量一次,對著真實站台"]
58
+ SRC[外掛原始碼] -->|extract_*.py| D[(data/*.csv)]
59
+ SW[sweep_*.py / probe_*.py] -->|寫入、渲染、斷言| D
60
+ end
61
+
62
+ subgraph write["你建的每一頁"]
63
+ Q[mo.py] -->|一個答案,量測結論在前| SPEC[頁面 spec]
64
+ EL[Elementor _elementor_data] -->|from_elementor.py| SPEC
65
+ SPEC -->|build_page.py 拒絕量到會壞的| REST[Mosaic REST:checkout、check、commit]
66
+ REST --> DB[(23 張表)]
67
+ DB --> PAGE[送出的頁面]
68
+ end
69
+
70
+ subgraph verify["永遠不信任 commit"]
71
+ PAGE --> V1[verify_rwd.py]
72
+ PAGE --> V2[verify_browser.py + 設計稽核]
73
+ PAGE --> V3[verify_intro.py / verify_loop.py]
74
+ PAGE --> V4[verify_conversion.py]
75
+ V1 & V2 & V3 & V4 --> CSV[(驗證表)]
76
+ CSV --> GATE[check-release.mjs]
77
+ end
78
+
79
+ D --> Q
80
+ D --> SPEC
81
+ ```
82
+
83
+ 由左到右:表格量一次、隨套件出貨;每一頁都透過表格寫入、表格說不行就拒絕;在送出的頁面被
84
+ 讀回來、結果記進發布閘門會檢查的表之前,什麼都不信。
85
+
40
86
  ## 唯一的規則
41
87
 
42
88
  **絕對不要憑記憶寫任何節點型別、屬性名稱、列舉值、樣式鍵或 Free/Pro 的判斷。去 `data/` 查。**
@@ -102,6 +148,24 @@ commit 成功不代表頁面能用,樣式表正確也不代表。這裡每個
102
148
  `SKIPPED`、`NO_HOST`、`INCONCLUSIVE` 從不折算進通過率。把自己的盲點算成成功的掃描,
103
149
  正是這個技能反對的東西。
104
150
 
151
+ ## 查一次要花多少
152
+
153
+ agent 要知道一個 Mosaic 節點型別或樣式鍵到底吃什麼,有三條路。同樣六個任務,用 tiktoken
154
+ 算(`tools/benchmark_tokens.py`,可以自己跑):
155
+
156
+ | 任務 | 讀原始碼 | 整包表格載入 | `mo.py` 查詢 |
157
+ |---|---:|---:|---:|
158
+ | 放一個標題、一段文字、一顆帶連結的按鈕 | 10,005 | 259,539 | **961** |
159
+ | 設定 padding、邊框、圓角,含響應式 | 3,490 | 259,539 | **396** |
160
+ | 判斷 accordion 能不能用、怎麼嵌套 | 15,615 | 259,539 | **397** |
161
+ | 找出哪些 hover/focus 狀態真的會編譯 | 3,619 | 259,539 | **1,054** |
162
+ | 找出哪個 Mosaic 鍵驅動某條 CSS | 1,862 | 259,539 | **51** |
163
+ | commit 之前知道什麼不安全 | 63,172 | 259,539 | **288** |
164
+
165
+ **比讀原始碼省 71–99.5% 的 token,比整包載入省 99.6% 以上**——而且六題裡有四題原始碼根本
166
+ 答不了:「有宣告」和「會編譯」是兩個問題,只有掃描問了第二個。表格總共 259,539 tokens;
167
+ 永遠不要整包載入,`mo.py` 才是查詢。
168
+
105
169
  ### 動手前值得知道的結果
106
170
 
107
171
  **屬於某個 `group` 的屬性單獨設定時無效。** 兩個方向都精確:78 個未分組屬性給出 58 COMPILED、
@@ -154,13 +218,13 @@ button / html / icon-list / divider / image 佔了全部元素的 99.6%。長尾
154
218
  | `sweep_*.py` / `probe_*.py` | 那些表格是用這些儀器量出來的 |
155
219
  | `bootstrap_probe_theme.php` / `mint_session.php` | 免授權的實驗主題,以及從 WP-CLI 鑄出 REST session |
156
220
 
157
- ## 線上的工作範例
221
+ ## 工作範例
158
222
 
159
- `sites/_moksa.py` 只透過資料表建出一個真實的工作室網站,隨套件出貨作為參考。它就在
160
- **https://mosaic.moksaweb.com/**:1,286 個節點的首頁,用具名 view timeline 做捲動追蹤的條款索引;
161
- 一段一次印一塊版、把浮世繪印出來的入口動畫;一塊在角落永遠印下去、點了會放大的版子;
162
- 還有一個 WooCommerce [My Account](https://mosaic.moksaweb.com/my-account/) 頁,它的 UI 全部
163
- 透過一個跑 shortcode 的 `code` 節點進來。全程沒有自己寫任何 JavaScript。
223
+ `sites/_moksa.py` 只透過資料表建出一個真實的工作室網站,隨套件出貨作為參考:1,286 個節點的
224
+ 首頁,用具名 view timeline 做捲動追蹤的條款索引;一段一次印一塊版、把浮世繪印出來的入口動畫;
225
+ 一塊在角落永遠印下去、點了會放大的版子;還有一個 WooCommerce My Account 頁,它的 UI 全部透過
226
+ 一個跑 shortcode 的 `code` 節點進來。全程沒有自己寫任何 JavaScript。`data/` 裡每一張驗證表
227
+ 都是對著它量出來的。
164
228
 
165
229
  ## 從哪裡開始
166
230
 
package/SKILL.md CHANGED
@@ -4,7 +4,7 @@ description: |
4
4
  Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface with `mo.py`, which joins every source table to the live sweeps so a lookup leads with the measured verdict rather than the declaration (122 node types, 181 properties, 98 style properties with 20 structured value shapes pinned down, 53 style states, 151 element classes, 74 dynamic variables, 12 interaction triggers, 114 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, the design-token and element-class layers verified against compiled CSS, the @VAR() dynamic language verified against rendered output, nine designed pages built through the tables themselves, and the delivered pages re-read in Chromium at three viewports so a rule that is present, correct and still wrong cannot pass. Drives Mosaic's own theme export/import from outside the editor and holds the copy against the source tree for tree.
5
5
  license: "MIT"
6
6
  author: "moksa (https://moksaweb.com)"
7
- version: "1.17.1"
7
+ version: "1.17.2"
8
8
  ---
9
9
 
10
10
  # Headless Mosaic
@@ -449,6 +449,7 @@ so the pattern is in the data, not just in this paragraph.
449
449
  | `data/accordion-verification.csv` | 7 | **driven live** - the accordion family nested the way its factory requires, against the guard that refuses it unparented. Resolves two BROKE_PAGE rows |
450
450
  | `data/conversion-verification.csv` | 8 | **converted then checked live** - an Elementor page rebuilt as Mosaic and held against its source (text, images, links, heading levels), then put through rwd, browser and the design audit with every finding classified inherited-or-introduced |
451
451
  | `data/conversion-batch.csv` | 19 | **converted, built and checked live, one page after another** - every Elementor page of a production site through the converter, with per-page element and content counts |
452
+ | `data/token-benchmark.csv` | 6 | **measured with tiktoken** - the same six lookups priced three ways: reading the plugin source, loading every table, querying `mo.py`. 71-99.5% fewer tokens than the source and 99.6%+ fewer than the tables, which total 259,539 - never load them, query them |
452
453
  | `data/theme-zip-verification.csv` | 22 | **round-tripped live** - Mosaic's own ZIP export imported in test mode and compared to its source, table by table and tree by tree |
453
454
  | `data/node-type-notes.csv` | 8 | where a sweep outcome is true but misleading on its own, why. Surfaced by `mo.py type` |
454
455
  | `data/interaction-verification.csv` | 7 | **probed live** - interaction animation shapes, with negative controls and the stored row beside the payload |
@@ -622,6 +623,7 @@ post — `build_all.py` resets first for that reason.
622
623
  | tool | does |
623
624
  |---|---|
624
625
  | `mo.py` | query the measured surface - **the front door** |
626
+ | `benchmark_tokens.py` | reproduce the token figures: source vs tables vs query, six tasks |
625
627
  | `build_page.py` | commit one page spec through the verified write path |
626
628
  | `build_site.py` | a whole site: one master with the shell, one document per page |
627
629
  | `verify_rwd.py` | does every `_t`/`_m` declaration reach the served stylesheet? |
@@ -20,7 +20,7 @@
20
20
  "description": "Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface (122 node types, 181 node properties, 98 style properties, 53 style states, 151 element classes, 74 dynamic variables, 114 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, every style and node property swept against the compiled CSS and markup, and 569 responsive declarations checked against the stylesheet the site actually served.",
21
21
  "license": "MIT",
22
22
  "author": "moksa (https://moksaweb.com)",
23
- "version": "1.17.1"
23
+ "version": "1.17.2"
24
24
  },
25
25
  "loaderBehaviour": "Upload via Settings -> Skills -> Upload. Claude.ai parses SKILL.md frontmatter and surfaces the skill in your library. The extraction tool (extract-block-schema.php) needs a live WP-CLI connection and won't run in the sandbox; use it from a local terminal against your own site instead.",
26
26
  "uploadSteps": [
@@ -20,7 +20,7 @@
20
20
  "description": "Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface (122 node types, 181 node properties, 98 style properties, 53 style states, 151 element classes, 74 dynamic variables, 114 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, every style and node property swept against the compiled CSS and markup, and 569 responsive declarations checked against the stylesheet the site actually served.",
21
21
  "license": "MIT",
22
22
  "author": "moksa (https://moksaweb.com)",
23
- "version": "1.17.1"
23
+ "version": "1.17.2"
24
24
  },
25
25
  "loaderBehaviour": "Auto-loads on session start when SKILL.md frontmatter parses successfully.",
26
26
  "verified": true,
@@ -20,7 +20,7 @@
20
20
  "description": "Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface (122 node types, 181 node properties, 98 style properties, 53 style states, 151 element classes, 74 dynamic variables, 114 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, every style and node property swept against the compiled CSS and markup, and 569 responsive declarations checked against the stylesheet the site actually served.",
21
21
  "license": "MIT",
22
22
  "author": "moksa (https://moksaweb.com)",
23
- "version": "1.17.1"
23
+ "version": "1.17.2"
24
24
  },
25
25
  "loaderBehaviour": "Confirmed (2026-07-11): Codex CLI natively supports the SKILL.md spec. Place SKILL.md under .codex/skills/<name>/ (project) or ~/.codex/skills/<name>/ (personal) and Codex loads the name+description at session start, then the full body on demand. A parallel, broader convention .agents/skills/ (searched from cwd up to repo root, then ~/.agents/skills/) also exists across multiple tools - if your Codex CLI version prioritizes that path instead, mirror the same SKILL.md there.",
26
26
  "verified": true,
@@ -20,7 +20,7 @@
20
20
  "description": "Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface (122 node types, 181 node properties, 98 style properties, 53 style states, 151 element classes, 74 dynamic variables, 114 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, every style and node property swept against the compiled CSS and markup, and 569 responsive declarations checked against the stylesheet the site actually served.",
21
21
  "license": "MIT",
22
22
  "author": "moksa (https://moksaweb.com)",
23
- "version": "1.17.1"
23
+ "version": "1.17.2"
24
24
  },
25
25
  "loaderBehaviour": "CHANGED as of 2026-07-11: GitHub Copilot added a proper '.github/skills/' Agent Skills directory (December 2025), alongside the older single-file .github/copilot-instructions.md convention. This config targets the new skills-directory form. If your Copilot version predates this (pre Dec 2025), use the instructions-append fallback instead (see fallback below).",
26
26
  "fallback": {
@@ -20,7 +20,7 @@
20
20
  "description": "Build and modify Mosaic Pro (Nextend) sites by writing the underlying data model directly - no visual editor, no DOM. Query the real surface (122 node types, 181 node properties, 98 style properties, 53 style states, 151 element classes, 74 dynamic variables, 114 REST routes, 23 tables) instead of guessing, with every node type placed on a live site one at a time and asserted against the delivered HTML, every style and node property swept against the compiled CSS and markup, and 569 responsive declarations checked against the stylesheet the site actually served.",
21
21
  "license": "MIT",
22
22
  "author": "moksa (https://moksaweb.com)",
23
- "version": "1.17.1"
23
+ "version": "1.17.2"
24
24
  },
25
25
  "loaderBehaviour": "CHANGED as of 2026-07-11: Gemini CLI now natively supports the same SKILL.md standard as Claude Code and Codex CLI - the same directory-based skill works unmodified. Gemini CLI discovers skills in this precedence order: built-in, extension skills, ~/.gemini/skills/ (personal), .gemini/skills/ (project, shared via version control). At session start Gemini injects each discovered skill's name+description into the system prompt and calls activate_skill when a task matches.",
26
26
  "verified": true,
@@ -0,0 +1,7 @@
1
+ task,commands,tokens_read_source,tokens_load_tables,tokens_query,saving_vs_source_pct,saving_vs_tables_pct
2
+ "Place a heading, a paragraph and a linked button",mo.py params text ; mo.py params button ; mo.py prop url,10005,259539,961,90.4,99.63
3
+ "Set padding, a border and a radius, responsively",mo.py style --grouped ; mo.py css border-left-width ; mo.py css border-radius,3490,259539,396,88.7,99.85
4
+ "Decide whether the accordion is usable, and how to nest it",mo.py type accordion-content ; mo.py placement accordion-item,15615,259539,397,97.5,99.85
5
+ Find which hover/focus states actually compile,mo.py states --verified,3619,259539,1054,70.9,99.59
6
+ Find which Mosaic key drives one CSS property,mo.py css grid-column,1862,259539,51,97.3,99.98
7
+ Know what is unsafe before committing anything,mo.py stats ; mo.py check div text button accordion-content,63172,259539,288,99.5,99.89
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mosaic-headless",
3
- "version": "1.17.1",
3
+ "version": "1.17.2",
4
4
  "description": "AI-agent skill: build Mosaic Pro (Nextend) WordPress sites by writing the underlying data model directly - 23 custom tables, no visual editor, no DOM. Every node type, style property and node property swept against a live install and asserted on the delivered HTML and compiled CSS. Installs into Claude Code, Cursor, Codex CLI, Gemini CLI, Copilot, Continue, Windsurf and Claude.ai.",
5
5
  "keywords": [
6
6
  "wordpress",
@@ -0,0 +1,155 @@
1
+ #!/usr/bin/env python3
2
+ """benchmark_tokens.py - what this skill costs to consult, and what it saves.
3
+
4
+ pip install tiktoken
5
+ python tools/benchmark_tokens.py --mosaic-src ./mosaic --csv data/token-benchmark.csv
6
+
7
+ Every token figure in the README comes from this script. Run it yourself.
8
+
9
+ WHAT IS BEING COMPARED
10
+
11
+ An agent about to write a Mosaic page needs, for the node types it is touching:
12
+ which properties exist, what values they take, which style keys emit CSS, what may
13
+ be nested where, and which of those claims survive contact with the compiler.
14
+ Three ways to get that, priced on the same tasks:
15
+
16
+ A. READ THE SOURCE open the plugin's PHP for the types and style records the
17
+ task touches. Accurate about what is *declared*; silent
18
+ about what is measured (a declared style key that emits
19
+ nothing looks identical to one that works).
20
+ B. LOAD THE TABLES put every data/*.csv in context. Complete, and wasteful:
21
+ you pay for all of it to use one row.
22
+ C. QUERY run tools/mo.py and read back only the answer, which
23
+ leads with the measured verdict. This is what the skill
24
+ does.
25
+
26
+ HONESTY NOTES
27
+
28
+ - Token counts use tiktoken cl100k_base - OpenAI's tokenizer, not Claude's, so
29
+ absolute counts differ by roughly +-10% on Claude. The RATIOS are what matter,
30
+ and a ratio between two texts measured with the same tokenizer is stable.
31
+ - Baseline A counts exactly the files an agent would have to open to answer the
32
+ task from source: the node type's three files (factory, data, resource) plus
33
+ the style-property records and the validators those files lean on. Mosaic
34
+ spreads a type across a directory and its style surface across a hundred
35
+ small classes; the count is the files that hold the answer, not the whole
36
+ plugin - counting the whole plugin would flatter the skill.
37
+ - Baseline A also understates the real cost: source cannot answer "does this
38
+ compile?" at all, so the honest source-reading agent still has to commit and
39
+ render to find out. That round trip is not priced here.
40
+ - The mo.py outputs are captured by running the commands for real.
41
+ - Baseline B is charged once, not per task.
42
+ """
43
+ from __future__ import annotations
44
+
45
+ import argparse
46
+ import csv
47
+ import glob
48
+ import io
49
+ import os
50
+ import subprocess
51
+ import sys
52
+
53
+ try:
54
+ import tiktoken
55
+ except ImportError:
56
+ sys.exit("pip install tiktoken")
57
+
58
+ ENC = tiktoken.get_encoding("cl100k_base")
59
+ HERE = os.path.dirname(os.path.abspath(__file__))
60
+ ROOT = os.path.dirname(HERE)
61
+
62
+
63
+ def toks(text):
64
+ return len(ENC.encode(text, disallowed_special=()))
65
+
66
+
67
+ def read_all(paths):
68
+ out = ""
69
+ for p in paths:
70
+ with io.open(p, encoding="utf-8", errors="replace") as fh:
71
+ out += fh.read()
72
+ return out
73
+
74
+
75
+ def src(mosaic, *rel_globs):
76
+ paths = []
77
+ for g in rel_globs:
78
+ paths += glob.glob(os.path.join(mosaic, "Mosaic", g), recursive=True)
79
+ return sorted(set(p for p in paths if p.endswith(".php")))
80
+
81
+
82
+ def run_mo(args):
83
+ r = subprocess.run([sys.executable, os.path.join(HERE, "mo.py")] + args,
84
+ capture_output=True, text=True, encoding="utf-8", errors="replace",
85
+ cwd=ROOT)
86
+ return r.stdout
87
+
88
+
89
+ # task -> (mo.py commands, source globs that hold the declared answer)
90
+ TASKS = [
91
+ ("Place a heading, a paragraph and a linked button",
92
+ [["params", "text"], ["params", "button"], ["prop", "url"]],
93
+ ["NodeTypes/Text/*.php", "NodeTypes/Button/*.php", "NodeTypes/Wysiwyg/**/*.php",
94
+ "Validators/Validate/ValidatorURL*.php", "Validators/Validate/ValidatorAcceptedValues.php"]),
95
+ ("Set padding, a border and a radius, responsively",
96
+ [["style", "--grouped"], ["css", "border-left-width"], ["css", "border-radius"]],
97
+ ["Builder/Style/BorderRadius/*.php", "Builder/Style/CSSGrouppedPropertyFactory.php",
98
+ "Builder/Style/CSSPropertyFactory.php", "Builder/Style/CSSProperty.php",
99
+ "Builder/Style/AbstractCSSProperty.php", "Builder/Breakpoint/*.php"]),
100
+ ("Decide whether the accordion is usable, and how to nest it",
101
+ [["type", "accordion-content"], ["placement", "accordion-item"]],
102
+ ["NodeTypes/Accordion/**/*.php", "NodeTypes/ElementAbstract/*.php"]),
103
+ ("Find which hover/focus states actually compile",
104
+ [["states", "--verified"]],
105
+ ["Builder/Style/StatesMeta.php", "Builder/Style/LocalStatesMeta.php",
106
+ "Builder/Style/CSS.php"]),
107
+ ("Find which Mosaic key drives one CSS property",
108
+ [["css", "grid-column"]],
109
+ ["Builder/Style/GridArea/*.php", "Builder/Style/GridTemplate/*.php",
110
+ "Builder/Style/CSSPropertyFactory.php"]),
111
+ ("Know what is unsafe before committing anything",
112
+ [["stats"], ["check", "div", "text", "button", "accordion-content"]],
113
+ ["NodeTypes/**/*TypeFactory.php"]),
114
+ ]
115
+
116
+
117
+ def main():
118
+ ap = argparse.ArgumentParser()
119
+ ap.add_argument("--mosaic-src", help="path to the Mosaic plugin (for baseline A)")
120
+ ap.add_argument("--csv")
121
+ a = ap.parse_args()
122
+
123
+ tables = sorted(glob.glob(os.path.join(ROOT, "data", "*.csv")))
124
+ load_all = toks(read_all(tables))
125
+ print("baseline B - every table in data/ loaded at once: %s tokens (%d files)\n"
126
+ % (format(load_all, ","), len(tables)))
127
+
128
+ rows = []
129
+ print("%-58s %10s %10s %8s %8s" % ("task", "read src", "query", "vs src", "vs load"))
130
+ for label, cmds, globs in TASKS:
131
+ q = sum(toks(run_mo(c)) for c in cmds)
132
+ s = None
133
+ if a.mosaic_src:
134
+ files = src(a.mosaic_src, *globs)
135
+ s = toks(read_all(files)) if files else None
136
+ sv = (100.0 * (1 - q / s)) if s else None
137
+ lv = 100.0 * (1 - q / load_all)
138
+ print("%-58s %10s %10s %7s %7.2f%%" % (
139
+ label[:58], format(s, ",") if s else "-", format(q, ","),
140
+ "%.1f%%" % sv if sv is not None else "-", lv))
141
+ rows.append([label, " ; ".join("mo.py " + " ".join(c) for c in cmds),
142
+ s or "", load_all, q, "%.1f" % sv if sv is not None else "",
143
+ "%.2f" % lv])
144
+
145
+ if a.csv:
146
+ with open(a.csv, "w", newline="", encoding="utf-8") as fh:
147
+ w = csv.writer(fh)
148
+ w.writerow(["task", "commands", "tokens_read_source", "tokens_load_tables",
149
+ "tokens_query", "saving_vs_source_pct", "saving_vs_tables_pct"])
150
+ w.writerows(rows)
151
+ print("\nwrote", a.csv)
152
+
153
+
154
+ if __name__ == "__main__":
155
+ main()