@prismer/runtime 2.0.8 → 2.2.55

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.
Files changed (119) hide show
  1. package/CHANGELOG.md +3430 -0
  2. package/README.md +34 -12
  3. package/apc/skills/FIELD-DICTIONARY.md +111 -0
  4. package/apc/skills/bug-reproduce/SKILL.md +150 -0
  5. package/apc/skills/bug-reproduce/skill.json +96 -0
  6. package/apc/skills/code-review/SKILL.md +198 -0
  7. package/apc/skills/code-review/skill.json +124 -0
  8. package/apc/skills/design-review/SKILL.md +122 -0
  9. package/apc/skills/design-review/skill.json +88 -0
  10. package/apc/skills/doc-sync/SKILL.md +168 -0
  11. package/apc/skills/doc-sync/skill.json +81 -0
  12. package/apc/skills/env-doctor/SKILL.md +194 -0
  13. package/apc/skills/env-doctor/skill.json +209 -0
  14. package/apc/skills/git-ops/SKILL.md +189 -0
  15. package/apc/skills/git-ops/skill.json +94 -0
  16. package/apc/skills/impact-trace/SKILL.md +168 -0
  17. package/apc/skills/impact-trace/skill.json +104 -0
  18. package/apc/skills/observability/SKILL.md +195 -0
  19. package/apc/skills/observability/skill.json +116 -0
  20. package/apc/skills/release-db-config-sync/SKILL.md +186 -0
  21. package/apc/skills/release-db-config-sync/skill.json +109 -0
  22. package/apc/skills/release-ota-promote/SKILL.md +195 -0
  23. package/apc/skills/release-ota-promote/skill.json +176 -0
  24. package/apc/skills/release-preflight/SKILL.md +174 -0
  25. package/apc/skills/release-preflight/skill.json +175 -0
  26. package/apc/skills/release-rollback/SKILL.md +214 -0
  27. package/apc/skills/release-rollback/skill.json +230 -0
  28. package/apc/skills/release-tag/SKILL.md +194 -0
  29. package/apc/skills/release-tag/skill.json +94 -0
  30. package/apc/skills/releasing-prod/SKILL.md +49 -0
  31. package/apc/skills/releasing-test/SKILL.md +135 -0
  32. package/apc/skills/sdk-release/SKILL.md +200 -0
  33. package/apc/skills/spec-intake/SKILL.md +169 -0
  34. package/apc/skills/spec-intake/skill.json +93 -0
  35. package/apc/skills/test-result-feedback/SKILL.md +239 -0
  36. package/apc/skills/test-result-feedback/skill.json +193 -0
  37. package/apc/skills/test-runner/SKILL.md +169 -0
  38. package/apc/skills/test-runner/skill.json +103 -0
  39. package/apc/skills/ui-align/SKILL.md +209 -0
  40. package/apc/skills/ui-align/skill.json +114 -0
  41. package/apc/skills/ui-canvas/SKILL.md +148 -0
  42. package/apc/skills/ui-canvas/skill.json +127 -0
  43. package/built-in-skills/agent-coordination/SKILL.md +59 -37
  44. package/built-in-skills/agent-meta/SKILL.md +1 -0
  45. package/built-in-skills/assets/SKILL.md +8 -6
  46. package/built-in-skills/browser-use/SKILL.md +93 -0
  47. package/built-in-skills/canvas-design/SKILL.md +1 -0
  48. package/built-in-skills/claim-agent-ownership/SKILL.md +3 -2
  49. package/built-in-skills/claude-api/SKILL.md +1 -0
  50. package/built-in-skills/codebase-design/DEEPENING.md +37 -0
  51. package/built-in-skills/codebase-design/DESIGN-IT-TWICE.md +44 -0
  52. package/built-in-skills/codebase-design/LICENSE +21 -0
  53. package/built-in-skills/codebase-design/SKILL.md +116 -0
  54. package/built-in-skills/conversation-compaction/SKILL.md +114 -0
  55. package/built-in-skills/council-creator/SKILL.md +426 -0
  56. package/built-in-skills/diagnosing-bugs/LICENSE +21 -0
  57. package/built-in-skills/diagnosing-bugs/SKILL.md +136 -0
  58. package/built-in-skills/diagnosing-bugs/scripts/hitl-loop.template.sh +41 -0
  59. package/built-in-skills/doc-coauthoring/SKILL.md +1 -0
  60. package/built-in-skills/document-generation/SKILL.md +105 -0
  61. package/built-in-skills/domain-modeling/ADR-FORMAT.md +47 -0
  62. package/built-in-skills/domain-modeling/CONTEXT-FORMAT.md +60 -0
  63. package/built-in-skills/domain-modeling/LICENSE +21 -0
  64. package/built-in-skills/domain-modeling/SKILL.md +76 -0
  65. package/built-in-skills/frontend-design/SKILL.md +1 -0
  66. package/built-in-skills/human-approval/SKILL.md +17 -2
  67. package/built-in-skills/image-generate/SKILL.md +103 -302
  68. package/built-in-skills/image-generate/scripts/generate-and-deliver.mjs +289 -0
  69. package/built-in-skills/ingest/SKILL.md +13 -45
  70. package/built-in-skills/internal-comms/SKILL.md +1 -0
  71. package/built-in-skills/liteparse/SKILL.md +130 -110
  72. package/built-in-skills/mcp-builder/SKILL.md +1 -0
  73. package/built-in-skills/memory/SKILL.md +420 -55
  74. package/built-in-skills/memory-dream/SKILL.md +339 -0
  75. package/built-in-skills/office-artifacts/SKILL.md +17 -4
  76. package/built-in-skills/okr/SKILL.md +154 -0
  77. package/built-in-skills/persona/SKILL.md +81 -0
  78. package/built-in-skills/persona-generator/SKILL.md +296 -0
  79. package/built-in-skills/pkf-svg/SKILL.md +253 -0
  80. package/built-in-skills/pkf-writing/SKILL.md +236 -0
  81. package/built-in-skills/prismer-im-collab/SKILL.md +26 -6
  82. package/built-in-skills/proactivity/SKILL.md +84 -0
  83. package/built-in-skills/remotion/SKILL.md +431 -0
  84. package/built-in-skills/role-builder/SKILL.md +203 -0
  85. package/built-in-skills/role-builder/scripts/author-role.mjs +334 -0
  86. package/built-in-skills/role-builder/scripts/ingest-role.mjs +223 -0
  87. package/built-in-skills/role-builder/scripts/instantiate-and-run.mjs +290 -0
  88. package/built-in-skills/role-builder/scripts/operation-harness.mjs +267 -0
  89. package/built-in-skills/skill-authoring/SKILL.md +110 -100
  90. package/built-in-skills/skill-authoring/skill.json +3 -3
  91. package/built-in-skills/skill-builder/SKILL.md +171 -0
  92. package/built-in-skills/skill-builder/scripts/ingest.mjs +265 -0
  93. package/built-in-skills/skill-creator/SKILL.md +165 -423
  94. package/built-in-skills/skill-creator/references/external-library-import.md +110 -0
  95. package/built-in-skills/skill-creator/scripts/import-library.mjs +475 -0
  96. package/built-in-skills/slack-gif-creator/SKILL.md +20 -0
  97. package/built-in-skills/tasks/SKILL.md +38 -23
  98. package/built-in-skills/tdd/LICENSE +21 -0
  99. package/built-in-skills/tdd/SKILL.md +110 -0
  100. package/built-in-skills/tdd/mocking.md +59 -0
  101. package/built-in-skills/tdd/refactoring.md +10 -0
  102. package/built-in-skills/tdd/tests.md +61 -0
  103. package/built-in-skills/team/SKILL.md +2 -1
  104. package/built-in-skills/web-artifacts-builder/SKILL.md +1 -0
  105. package/built-in-skills/webapp-testing/SKILL.md +1 -0
  106. package/built-in-skills/wechat-pay/SKILL.md +59 -0
  107. package/dist/cli.cjs +71872 -19960
  108. package/dist/cli.js +71803 -19846
  109. package/dist/index.cjs +72010 -19966
  110. package/dist/index.d.cts +4258 -712
  111. package/dist/index.d.ts +4258 -712
  112. package/dist/index.js +72156 -20118
  113. package/package.json +37 -6
  114. package/plugins/memory/prismer/__init__.py +1211 -0
  115. package/plugins/memory/prismer/plugin.yaml +8 -0
  116. package/plugins/memory/prismer/tool-schemas.generated.json +249 -0
  117. package/plugins/tools/prismer-recall/__init__.py +282 -0
  118. package/plugins/tools/prismer-recall/plugin.yaml +15 -0
  119. package/built-in-skills/memory-curation/SKILL.md +0 -135
@@ -0,0 +1,296 @@
1
+ ---
2
+ name: persona-generator
3
+ scope: common
4
+ description: >
5
+ Given a Council Brief, produce persona-ROLE instance definitions: real,
6
+ publicly-verifiable people who occupy distinct stakeholder positions on the
7
+ issue — each a persona-flavored role template (lens / voice / SOUL + the
8
+ persona-skill capability boundary + icon + an ASCII usernameSlug), handed to
9
+ convene (council-creator) to be instantiated as a REAL agent. (Search
10
+ grounding of each person is done by the cloud /councils/plan handler, not by
11
+ this skill.) Use when the workspace orchestrator needs to convene an expert
12
+ roundtable ("帮我找几个人聊聊这个 idea"). Personas are LENSES distilled from
13
+ public records, not the real people — never assert private facts, never
14
+ impersonate. This skill produces the persona-role DEFINITIONS (who speaks); it
15
+ does NOT create the group and does NOT drive the discussion — that is
16
+ council-creator.
17
+ license: MIT
18
+ compatibility:
19
+ - prismer-sdk
20
+ - hermes
21
+ metadata:
22
+ category: council
23
+ personaPolicy: public_distillation
24
+ disclaimerRequired: true
25
+ allowedUse: [analysis, debate, ideation]
26
+ forbiddenUse:
27
+ - impersonation
28
+ - private_claim
29
+ - legal_advice_without_disclaimer
30
+ - medical_advice_without_disclaimer
31
+ - financial_advice_without_disclaimer
32
+ eval:
33
+ level: generator # eval the GENERATOR against a Brief — never a single persona
34
+ assertions:
35
+ - positions-distinct # N personas occupy N distinct stakeholder positions (no two share one)
36
+ - insider-view-present # ≥1 persona sits where outsiders cannot see
37
+ - no-fabricated-people # every displayName is a real, publicly verifiable person
38
+ - risk-coverage-3plus # cast covers ≥3 risk dimensions (capital/tech/market/org/compliance)
39
+ - grounding-substring # every quote is a substring of a real search snippet (code-checked)
40
+ - brief-boundary # no persona asserts company facts beyond the Brief
41
+ - honest-degradation # ungroundable → role_label; fabricated quotes are a hard fail
42
+ ---
43
+
44
+ # Persona Generator
45
+
46
+ **Who speaks.** Given a Council Brief (assembled by the orchestrator from the
47
+ Team Manager's materials + memory), produce `cast: PersonaDef[]` — 3–5 people occupying
48
+ **distinct stakeholder positions**, each contributing the one thing only their
49
+ position lets them see. This is a **capability skill**: the orchestrator calls
50
+ it to produce data — a set of **persona-role instance definitions**. Each cast
51
+ member is a persona-flavored **role template def** (lens / voice / SOUL + the
52
+ persona-skill capability boundary + icon + an ASCII `usernameSlug`) that convene
53
+ will instantiate as a **real agent** (`createAgentForWorkspace` + `applyToAgent`,
54
+ M2). It is **not** a virtual `im_users` mask — persona = role instance.
55
+
56
+ | Do | Do NOT |
57
+ | --- | --- |
58
+ | Enumerate stakeholder positions for the issue | Create the council group (council-creator) |
59
+ | Pick one **real person** per position | Drive or moderate the discussion (council-creator) |
60
+ | Produce `seesWhatOthersDont` per person | Write memory (settle phase, via `memory` skill) |
61
+ | Emit voice (per-turn instructions) per person | Parse / extract materials (orchestrator tool-skills) |
62
+ | Hand the cast to cloud `/councils/plan` for grounding | Run search verification / supply quotes yourself (cloud does it) |
63
+ | Read `droppedCast[]` and substitute for dropped people | Invent people, quotes, or citations — ever |
64
+
65
+ ## Meta-goal (iron rule — supersedes any "debate" framing)
66
+
67
+ **A discussion is a plurality of viewpoints, not a positive-vs-negative game.**
68
+ Convene people of different identities, professions and stakes; each speaks
69
+ from their own position. If disagreement emerges it is the *natural result* of
70
+ plural perspectives — it is never something you construct. Do **not** hunt for
71
+ "an opposing side"; a target function of "construct opposition" structurally
72
+ excludes the two most valuable classes of people: **insiders** (dismissed as
73
+ same-camp) and **people who reject the axis entirely** (nowhere to stand on
74
+ it). The UI language is "讨论组" (discussion group), never "吵一架".
75
+
76
+ ## Core procedure
77
+
78
+ ### Step 0 — List stakeholder positions first (not "axes of disagreement")
79
+
80
+ Before picking anyone, enumerate the positions whose duty / expertise / stake
81
+ touches this issue:
82
+
83
+ ```
84
+ 运营执行者 / 出资人 / 监管者 / 同行实践者 / 下游客户 / 一线员工 / 被影响的第三方 …
85
+ ```
86
+
87
+ ### Step 1 — One REAL person per position
88
+
89
+ - Pick the person whose **real public track record** naturally puts them in
90
+ that position. If no fitting famous person exists for a position (e.g. "this
91
+ company's own CTO"), pick a real person who once held the *equivalent*
92
+ position elsewhere (e.g. another rocket company's former CTO).
93
+ - **Never invent a name.** Prefer swapping to a position where a real person
94
+ exists.
95
+ - Do **not** require them to disagree with each other. They may all agree and
96
+ still each fill in a piece the Team Manager cannot see.
97
+ - **Forbidden:** inserting an artificial "opposing side" to manufacture
98
+ conflict.
99
+
100
+ For every person you MUST state `seesWhatOthersDont` — not "which side they
101
+ are on", but "standing here, they can see X that nobody else at the table
102
+ can". This field is the core output of the skill.
103
+
104
+ ### Step 2 — Attach the persona (who arrives at the table)
105
+
106
+ - Enough verifiable public record and a good fit → **real name**
107
+ (`displayName: "Elon Musk"`, `subtitle: "SpaceX CEO"`). Compliance is
108
+ carried by the **disclaimer**, never by renaming — "Elon-style Strategy
109
+ Lens" style abstractions are forbidden (nobody wants to chat with a
110
+ concept). Internal terms (`persona`, `lens`) never surface in UI copy.
111
+ - Otherwise → a role label ("一位持保守立场的航天投资人") — still a person,
112
+ not a concept.
113
+ - `usernameSlug` (**load-bearing — this is the persona-agent's @-handle**):
114
+ ascii `[a-zA-Z0-9_-]`, 3–20 chars, lowercase slug of the person (e.g.
115
+ `elon-musk`). It must NOT start with the reserved `prismer-` segment. Final
116
+ uniqueness (`<slug>-<conv8>` + dedupe suffix) is enforced by the cloud at
117
+ convene time — you only produce the candidate slug. **Why it MUST be ASCII:**
118
+ once instantiated (M2), the persona-agent is addressed in the group **only**
119
+ by `@<usernameSlug>`. The mention router (`agent-dispatcher.ts` `MENTION_RE`)
120
+ is strict ASCII — a bare `@中文displayName` matches nothing and is silently
121
+ dropped, so a non-ASCII slug would leave the persona **unreachable** (0
122
+ dispatches, the exact 0/5 failure). The Chinese `displayName` is display-only;
123
+ it never routes.
124
+
125
+ ### Step 2.5 — Search grounding is done by the CLOUD, not by you
126
+
127
+ You **only produce candidates** — position + real person + `seesWhatOthersDont`
128
+ + candidate `usernameSlug`. **Do NOT run search verification yourself and do NOT
129
+ supply any `realCredential` / `whySelected` quotes.** Grounding is performed by
130
+ the cloud `/api/im/councils/plan` handler after you hand over the cast.
131
+
132
+ - **Why cloud, not you (architectural, 04 §2.5):** the anti-fabrication defense
133
+ requires a **verbatim substring of a real search snippet**, checked in code
134
+ against full-text search (`/api/search`). The daemon `web_search` tool you can
135
+ reach routes through `/api/context/load`→`/api/compress`, so it returns
136
+ **LLM-rewritten prose, not the original text** — you physically cannot obtain
137
+ the verbatim snippet the substring check needs. Any quote you write from
138
+ memory would be a fabrication that the cloud check exists to reject.
139
+ - **What the cloud does with your cast:** for each candidate it searches
140
+ `"<displayName> <topic terms>"` and requires the person's name + a topic term
141
+ to co-occur **inside the same sentence** ("some results exist" / "snippet
142
+ contains the keyword" passes off-topic celebrities — 04 §2.5 实测:
143
+ 李开复+商业航天 returned 5 named-but-off-topic hits). Grounded → the persona is
144
+ kept with `groundingSource='searched'` and verbatim quote evidence. **0
145
+ co-occurrence → the person is dropped from the cast** and returned in the plan
146
+ response's `droppedCast[]` — read it and substitute someone else for that
147
+ position (do NOT patch up the quote).
148
+ - **You still MUST NOT invent people.** Pick a real, publicly verifiable person
149
+ for each position (swap positions rather than inventing a name) — but leave the
150
+ evidence to the cloud. Your job ends at "who plausibly sits here"; the cloud
151
+ decides "is this person actually on-topic".
152
+ - **`groundingTerms` (optional but recommended for mixed-language topics):** you
153
+ MAY attach a short `groundingTerms: string[]` per candidate — the topic keywords
154
+ in **the language this person's public record is in** (English for "Elon Musk",
155
+ 中文 for a 中文人物). The cloud grounds against these instead of naively
156
+ tokenizing the question. Without them, a Chinese question ("2026年商业航天进展")
157
+ tokenizes to CJK bigrams that won't match an English-record person → that person
158
+ is wrongly dropped. So for an English-record person on a Chinese topic, supply
159
+ e.g. `["commercial spaceflight", "launch cost"]`.
160
+ - 🚫 **Never use self-critique as fact-checking.** Asked to "verify the
161
+ citations are real", an LLM does not admit it cannot find them — it invents
162
+ a *more specific* fake source ("引自2021年新浪财经专访"). Self-critique is
163
+ allowed only for *structural* checks (two people on one position? invented
164
+ names? missing insider view?), never for factual ones.
165
+
166
+ ### Step 3 — Graceful degradation (three tiers, decided by the CLOUD)
167
+
168
+ > ⚠️ This tiering is applied by the cloud grounding step, not by you — it is
169
+ > shown here so you understand what happens to your candidates. You never set
170
+ > `groundingSource` yourself. In the current implementation a candidate that is
171
+ > not `searched` is returned in `droppedCast[]` for you to substitute.
172
+
173
+ The criterion is "**can it be found by search?**" — programmatically checkable
174
+ — never "does the model know enough?" (unverifiable; models claim they do).
175
+
176
+ | Condition | Strategy | `groundingSource` |
177
+ | --- | --- | --- |
178
+ | Name + topic co-occur in one sentence of a snippet | Use its verbatim substring as the quote | `searched` |
179
+ | Not searchable, but the user supplied materials | Ground the quote in the user's materials | `user_materials` |
180
+ | Neither | **Degrade to a role label** ("一位持保守立场的航天投资人"), quote = null | `role_label` |
181
+
182
+ `role_label` is the most honest tier and the lowest impersonation risk. The
183
+ generator MUST be able to fall to it and MUST NOT fabricate quotes to "stay
184
+ famous". (Legacy tiers `parametric` / `needs_materials` are retired — they
185
+ presumed unverifiable parametric knowledge.)
186
+
187
+ ### Step 4 — Icon acquisition (cloud-executed; you only reference the result)
188
+
189
+ Icon fetching and cropping run as **pure code on the cloud** (Serper image
190
+ search → Content-Type + magic-bytes double gate → aspect-ratio cull only
191
+ (0.6 ≤ ar ≤ 1.7, never re-rank by squareness — Google's own ranking encodes
192
+ "this is the standard portrait") → **top-edge square crop**, no face-detect).
193
+ Your responsibility is only to carry the resulting `iconAssetRef` (an
194
+ `im_assets` id) into the PersonaDef, or `null` when nothing usable was found —
195
+ the frontend degrades to a monogram. Never inline image bytes or hotlink URLs.
196
+
197
+ ### Step 5 — Voice
198
+
199
+ `voice` = the persona-role's speaking instructions (markdown): the position,
200
+ speaking style, and disclaimer discipline. Because persona is now a **role
201
+ instance** (not a mask), `voice` — together with lens and a SOUL 特例档 — is what
202
+ convene bakes into the persona-agent's role template at instantiation, so the
203
+ agent speaks in-character from its **own** session (no one plays five roles).
204
+ Write voice as durable, self-contained instructions the standalone agent can
205
+ carry across turns, not one-off remarks. At convene time the cloud persists it
206
+ onto the persona-agent so later `@<usernameSlug>` follow-ups reuse it.
207
+
208
+ ## Output shape (wire contract — aligns with `POST /api/im/councils/plan` cast)
209
+
210
+ ```jsonc
211
+ {
212
+ "cast": [
213
+ {
214
+ "id": "elon-musk", // slug — also the personaId in council metadata
215
+ "displayName": "Elon Musk", // REAL name; compliance rides the disclaimer
216
+ "subtitle": "SpaceX 创始人兼 CEO", // who this person IS — from primary sources only
217
+ "usernameSlug": "elon-musk", // ascii @-handle 3-20, no 'prismer-'; cloud dedupes — the ONLY way to reach this persona
218
+ "iconAssetRef": null, // im_assets id from the cloud icon service, or null
219
+ "position": "同行实践者(已量产的商业航天创始人)",
220
+ "seesWhatOthersDont": "复用一子级的真实成本曲线与产线爬坡节奏",
221
+ // ⚠️ Do NOT supply realCredential / groundingSource — the cloud fills these
222
+ // from live search after grounding (step 2.5). Omit them from your output.
223
+ "voice": "Speak as a first-principles propulsion founder. Terse. Numbers first. 你是公开资料蒸馏的视角,非本人;Brief 未提供的公司事实一律说「Brief 未提供」。",
224
+ "disclaimer": "公开资料蒸馏视角,非本人"
225
+ }
226
+ ]
227
+ }
228
+ ```
229
+
230
+ No `stance` field (the meta-goal is plural viewpoints, not sides). No `lens`
231
+ field (a stance is the runtime product of `facts × issue`, not a stored
232
+ attribute). Input: `{ brief, requestedPersonas?, n? }` (default n = 3–5).
233
+
234
+ ## Iron principle: persona = lens, Brief = facts (负控 N8)
235
+
236
+ A persona **never carries company facts of its own**. Everything about the
237
+ company comes from the Council Brief the orchestrator assembled. If a persona
238
+ is asked to assert a company fact the Brief does not provide, it must say
239
+ "Brief 未提供" or mark `needsVerification` — never improvise. This is the
240
+ architectural cure for "stylized bubbles making things up", not a disclaimer.
241
+ Bake this discipline into every `voice` you emit.
242
+
243
+ At settle, `council-creator` turns this discipline into a **wire contract**: the
244
+ report's `claims[]` each carry `sourceRefs[]` (the real material a fact stands
245
+ on) + `needsVerification`, and unanswerable facts land in `gaps[]`. So your
246
+ `voice` must instruct the persona to speak in **grounded, attributable claims**
247
+ — tie each factual statement to the Brief fact it uses, and say "缺数据" (→
248
+ `needsVerification=true`, `sourceRefs=[]`) rather than inventing a number, so
249
+ council-creator can emit an honest structured report downstream.
250
+
251
+ ## Generator-level eval
252
+
253
+ Eval judges the **generator** (input: a Brief; assertions over the cast as a
254
+ set), never a single persona. Code-enforceable oracles are the two grounding
255
+ checks (substring + same-sentence co-occurrence); the set-level assertions
256
+ below are eval judgements (semantic classification):
257
+
258
+ | Assertion | Criterion |
259
+ | --- | --- |
260
+ | Positions distinct | N personas occupy N different stakeholder positions; no two share one |
261
+ | Insider view present | ≥1 person sits where outsiders cannot see (operator / front-line / former insider) |
262
+ | No fabricated people | every `displayName` is real and publicly verifiable (`realCredential` non-empty) |
263
+ | Risk coverage | cast covers ≥3 of: capital / tech / market / org / compliance |
264
+ | Grounding real | every quote is a snippet substring + same-sentence co-occurrence (code check) |
265
+ | Brief boundary | no persona asserts company facts beyond the Brief |
266
+ | Honest degradation | unsearchable → `role_label`, never a fabricated quote |
267
+
268
+ ## Promote escape hatch
269
+
270
+ An exceptionally good cast can be saved as a **`persona-pack` skill** (static
271
+ snapshot, `metadata.category: council`, `personaPolicy: public_distillation`,
272
+ `disclaimerRequired: true`) and published to the marketplace for fork / rate /
273
+ compose. This is a third, non-default path — the default is always fresh
274
+ generation against the current Brief.
275
+
276
+ ## Configuration
277
+
278
+ **N/A.** This skill declares no `config:` block. Grounding credentials
279
+ (search API keys) live cloud-side as Nacos global config consumed by the
280
+ `/api/im/councils/plan` handler and `/api/search` — they are never
281
+ agent-bound, so there is nothing for the skill-config binding system to carry
282
+ (product204/09 boundary ruling, CONFLICT-7).
283
+
284
+ ## Anti-patterns
285
+
286
+ - ❌ Inventing a person because a position "needs" someone famous (the
287
+ documented failure: `Will Smith` as Relativity's CEO — the real CEO is Tim
288
+ Ellis). Swap positions instead.
289
+ - ❌ Filling the cast with five competitor CEOs (letting competitors judge
290
+ your valuation) — that is the retired adversarial framing.
291
+ - ❌ Writing quotes from memory, or "verifying" them by self-critique.
292
+ - ❌ Renaming a real person into a concept ("工程激进视角") to dodge
293
+ compliance — the disclaimer carries compliance.
294
+ - ❌ Emitting `stance` / picking a side for anyone.
295
+ - ❌ Creating the group, posting messages, or driving rounds — hand the cast
296
+ to council-creator.
@@ -0,0 +1,253 @@
1
+ ---
2
+ name: pkf-svg
3
+ scope: common
4
+ description: 'Design controlled SVG, visual widgets, topology and Visual Core explainers with semantic color, safe geometry, accessibility, and bounded complexity. Use for an explicitly supported SVG/widget surface or to plan PKF visuals. PKF v1.1 has no production inline-SVG authoring surface (diagrams are Mermaid, data charts are d3); v1.2 controlled prismer-svg (pkf209 D19) is activated for PKF source authoring within the frozen validator whitelist.'
5
+ metadata:
6
+ aliases:
7
+ - pkf-visual
8
+ ---
9
+
10
+ # pkf-svg
11
+
12
+ Visual discipline for controlled SVG, widgets, architecture/topology maps,
13
+ and Visual Core experiments. It owns composition, semantic color, geometry,
14
+ safety, and a11y — not PKF persistence or memory placement.
15
+
16
+ ## Production boundary (tell the truth)
17
+
18
+ - PKF v1.1 keeps no `prismer-svg` production authoring element: SVG travels as
19
+ a reviewed static asset or a trusted host surface only.
20
+ - PKF v1.2 CONTROLLED `prismer-svg` (docs/pkf209 03 D19) is ACTIVATED
21
+ (2026-08-18): it may be authored inside PKF source. The production reader
22
+ validates against the frozen whitelist — script, foreignObject, on*,
23
+ external href, animation and canvas overflow are hard structure failures
24
+ (stable `svg-*` codes), not soft conventions. Never author free/raw SVG in
25
+ any version.
26
+ - In PKF, author diagrams with `<prismer-diagram format="mermaid">`; use
27
+ Mermaid `erDiagram|flowchart|sequenceDiagram|xychart-beta` as appropriate.
28
+ - Author data charts with `prismer-data` views
29
+ `chart-bar|chart-line|chart-pie`; the production reader renders them with d3.
30
+ - Mermaid renders classic today. D19 proposes host-only `handDrawn|neo`
31
+ top-right menu toggles; the workspace host (DiagramView) ships this
32
+ radiogroup — keyboard reachable, persisted per workspace, source never
33
+ carries look. Other hosts may not offer the toggle, so do not rely on
34
+ non-classic look.
35
+ - Mermaid actor/entity/class colors SHOULD use the semantic ramps below.
36
+ Implemented status (D19 §7): the workspace reader's `resolveMermaidTheme`
37
+ consumes this exact 9×7 table for themeVariables by diagram family —
38
+ sequence actor = blue (system), sequence alt/opt branch frame + activation
39
+ = amber (attention/reversible), note/signal = gray (annotation), erDiagram
40
+ entity = teal (approved), classDiagram box = purple (control), flowchart
41
+ nodes = blue (system). Honest limits: flowchart decision diamonds share
42
+ node colors (mermaid has no diamond-specific themeVariables), and mermaid
43
+ 11.x does not consume `attributeBackgroundColorOdd/Even` for erDiagram
44
+ attribute rows. Unknown diagram types keep the accent palette fallback.
45
+ - Apply the SVG rules below for any trusted SVG/widget surface, and for
46
+ `prismer-svg` authored in PKF source (v1.2 activated). Otherwise use Mermaid,
47
+ d3, semantic HTML/prose, or a reviewed static asset.
48
+
49
+ ## Scenario routing
50
+
51
+ - ERD/database schema → Mermaid `erDiagram`, never hand-drawn.
52
+ - Sequential process/decision tree → Mermaid `flowchart`; ≤5 flow nodes.
53
+ - Statistical data → d3 chart view; tables → markdown table, not a figure.
54
+ - Controlled SVG/widget → structural, illustrative, or multi-cluster topology
55
+ only when Mermaid/data surfaces cannot express the intended hierarchy.
56
+ - Loops/cycles → stepper with an explicit wrap-back cue, never a decorative ring.
57
+
58
+ ## Quality floor: 680×480 topology reference
59
+
60
+ - Use a 680×480 reference canvas for dense topology; preserve the safe area
61
+ x=40..640 and keep the bottom-most element at least 20px above the edge.
62
+ - Build at least 3 information layers: figure → container → node or status.
63
+ Containers express bounded contexts; nodes express actors/services/resources;
64
+ status annotations never compete with the primary topology.
65
+ - Provide accessible `<title>` and `<desc>` in any trusted SVG surface, plus
66
+ visible labels. Accessibility text must explain the same relationships.
67
+ - Use 0.5px default strokes, boundary-anchored connectors, symmetric padding,
68
+ and named geometry constants. Nothing clips or floats outside its owner.
69
+ - Maintain stable density: consistent node heights, spacing rhythm, label
70
+ lengths, and connector clearance across peer clusters.
71
+
72
+ ## Validator quality floors (stable svg-* rejections)
73
+
74
+ The frozen whitelist audit also rejects objectively unreadable figures:
75
+ svg-too-sparse (<3 visible shapes), svg-monochrome (<2 distinct shape fills,
76
+ backdrop excluded), svg-contrast (text vs container below the 3.0 WCAG
77
+ large-text floor), svg-text-overflow (label width outside x∈[40, width-40]),
78
+ svg-stroke-floor (authored stroke-width <0.5), svg-unlabeled (zero visible
79
+ labels). Each message names the element to fix — repair, never argue.
80
+
81
+ ## Copy-first authoring loop
82
+
83
+ ```text
84
+ 1. copy the skeleton below into ONE `prismer-svg` element (wrapper carries
85
+ width/height/viewBox; the markup inside is the <svg> block)
86
+ 2. replace labels, coordinates and colors — ramp hexes from the table only
87
+ 3. run `pkf_svg_check({"svg":"<complete svg markup>"})` and fix every svg-*
88
+ error (one round: each diagnostic names the element/attribute to change)
89
+ 4. only then `pkf_validate` the complete PKF and persist
90
+ ```
91
+
92
+ `pkf_svg_check` is a pure local tool: write → check → fix without spending a
93
+ persist round. If the runtime does not offer it, fall back to `pkf_validate`
94
+ on the whole document.
95
+
96
+ ## Skeleton — 680×480, three layers (copy verbatim)
97
+
98
+ ```svg
99
+ <svg viewBox="0 0 680 480" role="img" aria-label="Skeleton: two clusters with one orthogonal edge">
100
+ <title>Skeleton: two clusters, one orthogonal edge</title>
101
+ <desc>Copyable 680x480 skeleton in three layers: backdrop (neutral canvas plus figure title), edges (orthogonal connectors), nodes (clusters, node rects, labels). Replace labels, coordinates and ramp colors.</desc>
102
+ <g id="sk-backdrop">
103
+ <rect x="0" y="0" width="680" height="480" rx="12" fill="#F1EFE8" stroke="#B4B2A9" stroke-width="0.5"></rect>
104
+ <text x="40" y="32" font-size="13" font-weight="500" fill="#2C2C2A">Figure title — replace</text>
105
+ </g>
106
+ <g id="sk-edges">
107
+ <line x1="248" y1="170" x2="432" y2="170" stroke="#5F5E5A" stroke-width="0.5"></line>
108
+ <circle cx="248" cy="170" r="2.5" fill="#5F5E5A"></circle>
109
+ <circle cx="432" cy="170" r="2.5" fill="#5F5E5A"></circle>
110
+ <text x="340" y="158" font-size="11" fill="#444441" text-anchor="middle">relates</text>
111
+ </g>
112
+ <g id="sk-nodes">
113
+ <rect x="40" y="72" width="208" height="196" rx="10" fill="#E6F1FB" stroke="#185FA5" stroke-width="0.5"></rect>
114
+ <text x="56" y="94" font-size="12" font-weight="500" fill="#0C447C">Cluster A · blue · system</text>
115
+ <rect x="56" y="106" width="176" height="34" rx="6" fill="#FFFFFF" stroke="#185FA5" stroke-width="0.5"></rect>
116
+ <text x="64" y="127" font-size="12" fill="#0C447C">Node label one</text>
117
+ <rect x="56" y="152" width="176" height="34" rx="6" fill="#FFFFFF" stroke="#185FA5" stroke-width="0.5"></rect>
118
+ <text x="64" y="173" font-size="12" fill="#0C447C">Node label two</text>
119
+ <rect x="432" y="72" width="208" height="196" rx="10" fill="#E1F5EE" stroke="#0F6E56" stroke-width="0.5"></rect>
120
+ <text x="448" y="94" font-size="12" font-weight="500" fill="#085041">Cluster B · teal · ready</text>
121
+ <rect x="448" y="106" width="176" height="34" rx="6" fill="#FFFFFF" stroke="#0F6E56" stroke-width="0.5"></rect>
122
+ <text x="456" y="127" font-size="12" fill="#085041">Node label one</text>
123
+ <rect x="448" y="152" width="176" height="34" rx="6" fill="#FFFFFF" stroke="#0F6E56" stroke-width="0.5"></rect>
124
+ <text x="456" y="173" font-size="12" fill="#085041">Node label two</text>
125
+ </g>
126
+ <text x="40" y="452" font-size="11" fill="#444441">Fallback caption — describe the same relationships in words.</text>
127
+ </svg>
128
+ ```
129
+
130
+ Layer contract: `sk-backdrop` (neutral canvas + figure title), `sk-edges`
131
+ (orthogonal connectors between clusters), `sk-nodes` (cluster frames, node
132
+ rects, labels). Safe area x=40..640; bottom-most element ≥20px above y=480.
133
+
134
+ ## Fragments — cluster / node / orthogonal edge
135
+
136
+ Each fragment is standalone-valid; copy the inner layer you need into the
137
+ skeleton and re-check with `pkf_svg_check` after editing.
138
+
139
+ ```svg
140
+ <svg viewBox="0 0 240 150" role="img" aria-label="Cluster frame fragment">
141
+ <title>Cluster frame fragment</title>
142
+ <desc>One bounded-context frame with a title row and one node slot.</desc>
143
+ <rect x="0" y="0" width="240" height="150" rx="8" fill="#F1EFE8"></rect>
144
+ <rect x="40" y="24" width="160" height="96" rx="10" fill="#E6F1FB" stroke="#185FA5" stroke-width="0.5"></rect>
145
+ <text x="52" y="44" font-size="12" font-weight="500" fill="#0C447C">Cluster · context</text>
146
+ <rect x="52" y="56" width="136" height="30" rx="6" fill="#FFFFFF" stroke="#185FA5" stroke-width="0.5"></rect>
147
+ <text x="60" y="76" font-size="12" fill="#0C447C">Node label</text>
148
+ </svg>
149
+ ```
150
+
151
+ ```svg
152
+ <svg viewBox="0 0 240 150" role="img" aria-label="Node and status fragment">
153
+ <title>Node and status fragment</title>
154
+ <desc>One node rect plus a status chip from a second ramp family.</desc>
155
+ <rect x="0" y="0" width="240" height="150" rx="8" fill="#F1EFE8"></rect>
156
+ <rect x="40" y="28" width="136" height="34" rx="6" fill="#FFFFFF" stroke="#185FA5" stroke-width="0.5"></rect>
157
+ <text x="52" y="49" font-size="12" fill="#0C447C">Node label</text>
158
+ <rect x="40" y="72" width="136" height="22" rx="5" fill="#FAEEDA" stroke="#854F0B" stroke-width="0.5"></rect>
159
+ <text x="52" y="87" font-size="11" font-weight="500" fill="#633806">attention note</text>
160
+ </svg>
161
+ ```
162
+
163
+ ```svg
164
+ <svg viewBox="0 0 300 120" role="img" aria-label="Orthogonal edge fragment">
165
+ <title>Orthogonal edge fragment</title>
166
+ <desc>Two nodes joined by an orthogonal polyline with endpoint dots and a label.</desc>
167
+ <rect x="0" y="0" width="300" height="120" rx="8" fill="#F1EFE8"></rect>
168
+ <rect x="40" y="40" width="80" height="36" rx="6" fill="#E6F1FB" stroke="#185FA5" stroke-width="0.5"></rect>
169
+ <text x="52" y="62" font-size="12" fill="#0C447C">source</text>
170
+ <polyline points="120,58 160,58 160,80 204,80" fill="none" stroke="#5F5E5A" stroke-width="0.5"></polyline>
171
+ <rect x="204" y="62" width="80" height="36" rx="6" fill="#E1F5EE" stroke="#0F6E56" stroke-width="0.5"></rect>
172
+ <text x="216" y="84" font-size="12" fill="#085041">target</text>
173
+ <text x="160" y="48" font-size="11" fill="#444441" text-anchor="middle">relates</text>
174
+ </svg>
175
+ ```
176
+
177
+ ## Semantic ramp hex table (host tokens — hex only, never CSS variables)
178
+
179
+ | family | 50 | 100 | 200 | 400 | 600 | 800 | 900 |
180
+ | --- | --- | --- | --- | --- | --- | --- | --- |
181
+ | purple | #EEEDFE | #CECBF6 | #AFA9EC | #7F77DD | #534AB7 | #3C3489 | #26215C |
182
+ | teal | #E1F5EE | #9FE1CB | #5DCAA5 | #1D9E75 | #0F6E56 | #085041 | #04342C |
183
+ | coral | #FAECE7 | #F5C4B3 | #F0997B | #D85A30 | #993C1D | #712B13 | #4A1B0C |
184
+ | pink | #FBEAF0 | #F4C0D1 | #ED93B1 | #D4537E | #993556 | #72243E | #4B1528 |
185
+ | gray | #F1EFE8 | #D3D1C7 | #B4B2A9 | #888780 | #5F5E5A | #444441 | #2C2C2A |
186
+ | blue | #E6F1FB | #B5D4F4 | #85B7EB | #378ADD | #185FA5 | #0C447C | #042C53 |
187
+ | green | #EAF3DE | #C0DD97 | #97C459 | #639922 | #3B6D11 | #27500A | #173404 |
188
+ | amber | #FAEEDA | #FAC775 | #EF9F27 | #BA7517 | #854F0B | #633806 | #412402 |
189
+ | red | #FCEBEB | #F7C1C1 | #F09595 | #E24B4A | #A32D2D | #791F1F | #501313 |
190
+
191
+ Light mode = 50 fill + 600 stroke + 800 title; dark = 800 fill + 200 stroke
192
+ + 100 title (same table, different usage). The svg-monochrome floor requires
193
+ ≥2 distinct families among shape fills.
194
+
195
+ ## Coordinate grid reference
196
+
197
+ - x columns at 60px rhythm: 40, 100, 160, 220, 280, 340, 400, 460, 520, 580,
198
+ 640 — labels start at a column, nodes span 3 columns (176px at 56px inset).
199
+ - y bands: figure title 32, cluster title 94, node rows 127 / 173 (34px tall,
200
+ 46px pitch), legend 316..346, fallback caption 378..394, bottom ≥460.
201
+
202
+ ## Semantic color and complexity
203
+
204
+ - Palette ramps: purple/teal/coral/pink/gray/blue/green/amber/red; use host
205
+ tokens, never improvised hex values. Shape/size/color changes encode meaning.
206
+ - Stable defaults: blue = system/deployment, teal = approved/ready/success,
207
+ purple = control/rollback, amber = attention/reversible action, and red =
208
+ risk/blocker only. Use gray for annotation, never to weaken a main branch.
209
+ - Dark surfaces preserve depth: map light 50 → dark 800 and light 100 →
210
+ dark 900; keep text/connector contrast explicit instead of auto-inverting.
211
+ - Ordinary figure default: ≤2 ramps per figure.
212
+ - Complex topology/architecture exception: group by bounded context and use
213
+ up to 4 domain ramps, plus 1 reserved status/risk ramp. Each visual group
214
+ remains ≤2 ramps. Color must express category or status and carry a text cue;
215
+ color alone is never the only signal.
216
+ - A figure containing two small flows keeps each of the two small flows ≤2
217
+ ramps; do not borrow the topology exception for decorative variety.
218
+ - ≤4 boxes per horizontal tier, ≤5 nodes per simple flow, nesting ≤3,
219
+ subtitles ≤5 words, and ≥60px between flow boxes.
220
+
221
+ ## Typography and composition
222
+
223
+ - Weights 400/500 only; minimum 11px; sentence case; no emoji as iconography.
224
+ - One reading direction and one focal story. Use primary/secondary/annotation
225
+ rhythm; do not distribute motifs merely to fill the canvas.
226
+ - Labels remain inside their owning container and outside the object they name.
227
+ - Legends reuse rendered token colors and pair every swatch with a label.
228
+
229
+ ## Safety and accessibility gate
230
+
231
+ - The host allowlist is authoritative. Never emit `script`, `foreignObject`,
232
+ event handler (`on*`), external URL/reference, remote CSS/font, animation,
233
+ iframe, image, or untrusted `use` content.
234
+ - v1.2 wire: the frozen validator whitelist (elements {svg,g,rect,circle,
235
+ ellipse,line,path,polyline,polygon,text,tspan,title,desc}, geometry/paint/
236
+ text attributes, budgets 512 elements / 2048 attributes / viewBox ≤4096) is
237
+ enforced by the production reader — author inside it, never around it.
238
+ - Internal fragment IDs must be unique and namespaced; references stay local.
239
+ - Every connector has a visible endpoint and a textual relationship cue.
240
+ - On rejection or unsupported surfaces, fail closed to source/prose/static
241
+ fallback; never claim a sanitized or dropped figure was persisted.
242
+
243
+ ## Self-check
244
+
245
+ - Correct surface and scenario? v1.2 controlled prismer-svg stays inside the
246
+ frozen whitelist — script/foreignObject/on*/external refs/animations absent,
247
+ title+desc present, ids unique — and is never free/raw?
248
+ - Copied the skeleton, kept three information layers, 680 safe area,
249
+ title+desc, 0.5px, stable density — and `pkf_svg_check` is green?
250
+ - Ordinary ≤2 ramps, or a justified bounded-context exception within caps?
251
+ - Color has semantic meaning plus a text cue; each visual group remains ≤2?
252
+ - One reading direction, boundary anchors, no clipping, stable peer rhythm?
253
+ - Unsafe tags/attributes/external references absent; fallback remains readable?