@event4u/agent-config 2.16.0 → 2.17.0

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 (88) hide show
  1. package/.agent-src/commands/ghostwriter/delete.md +118 -0
  2. package/.agent-src/commands/ghostwriter/fetch.md +185 -0
  3. package/.agent-src/commands/ghostwriter/list.md +102 -0
  4. package/.agent-src/commands/ghostwriter/show.md +113 -0
  5. package/.agent-src/commands/ghostwriter/write.md +160 -0
  6. package/.agent-src/commands/ghostwriter.md +96 -0
  7. package/.agent-src/commands/post-as/ghostwriter.md +66 -0
  8. package/.agent-src/commands/post-as/me.md +124 -0
  9. package/.agent-src/commands/post-as.md +58 -0
  10. package/.agent-src/ghostwriter/README.md +61 -0
  11. package/.agent-src/ghostwriter/fictional-fixture-v1.md +94 -0
  12. package/.agent-src/personas/README.md +8 -0
  13. package/.agent-src/rules/domain-safety-disclaimer-consulting.md +52 -0
  14. package/.agent-src/rules/domain-safety-disclaimer-financial.md +54 -0
  15. package/.agent-src/rules/domain-safety-disclaimer-legal.md +49 -0
  16. package/.agent-src/rules/domain-safety-disclaimer-medical.md +56 -0
  17. package/.agent-src/rules/domain-safety-export-redact.md +65 -0
  18. package/.agent-src/rules/domain-safety-logging-pii-floor.md +55 -0
  19. package/.agent-src/rules/domain-safety-pii-finance.md +57 -0
  20. package/.agent-src/rules/domain-safety-pii-marketing.md +60 -0
  21. package/.agent-src/rules/domain-safety-pii-recruiting.md +56 -0
  22. package/.agent-src/rules/domain-safety-pii-support.md +57 -0
  23. package/.agent-src/rules/domain-safety-retention-finance.md +48 -0
  24. package/.agent-src/rules/domain-safety-retention-support.md +55 -0
  25. package/.agent-src/skills/api-design/SKILL.md +3 -0
  26. package/.agent-src/skills/authz-review/SKILL.md +3 -0
  27. package/.agent-src/skills/competitive-moat-analysis/SKILL.md +3 -0
  28. package/.agent-src/skills/competitive-positioning/SKILL.md +3 -0
  29. package/.agent-src/skills/content-funnel-design/SKILL.md +3 -0
  30. package/.agent-src/skills/contracts-cognition/SKILL.md +3 -0
  31. package/.agent-src/skills/dashboard-design/SKILL.md +3 -0
  32. package/.agent-src/skills/data-handling-judgment/SKILL.md +3 -0
  33. package/.agent-src/skills/dcf-modeling/SKILL.md +3 -0
  34. package/.agent-src/skills/deal-qualification-meddic/SKILL.md +3 -0
  35. package/.agent-src/skills/discovery-interview/SKILL.md +3 -0
  36. package/.agent-src/skills/editorial-calendar/SKILL.md +3 -0
  37. package/.agent-src/skills/forecast-accuracy/SKILL.md +3 -0
  38. package/.agent-src/skills/forecasting/SKILL.md +3 -0
  39. package/.agent-src/skills/fundraising-narrative/SKILL.md +3 -0
  40. package/.agent-src/skills/gtm-launch/SKILL.md +3 -0
  41. package/.agent-src/skills/incident-commander/SKILL.md +3 -0
  42. package/.agent-src/skills/launch-readiness/SKILL.md +3 -0
  43. package/.agent-src/skills/messaging-architecture/SKILL.md +3 -0
  44. package/.agent-src/skills/okr-tree-modeling/SKILL.md +3 -0
  45. package/.agent-src/skills/pipeline-strategy/SKILL.md +3 -0
  46. package/.agent-src/skills/playwright-architect/SKILL.md +3 -0
  47. package/.agent-src/skills/privacy-review/SKILL.md +4 -1
  48. package/.agent-src/skills/quality-tools/SKILL.md +3 -0
  49. package/.agent-src/skills/release-comms/SKILL.md +3 -0
  50. package/.agent-src/skills/runway-cognition/SKILL.md +3 -0
  51. package/.agent-src/skills/scenario-modeling/SKILL.md +3 -0
  52. package/.agent-src/skills/secrets-management/SKILL.md +3 -0
  53. package/.agent-src/skills/tech-debt-tracker/SKILL.md +3 -0
  54. package/.agent-src/skills/unit-economics-modeling/SKILL.md +3 -0
  55. package/.agent-src/skills/voc-extract/SKILL.md +3 -0
  56. package/.agent-src/skills/voice-and-tone-design/SKILL.md +3 -0
  57. package/.agent-src/templates/agents/agent-project-settings.example.yml +16 -1
  58. package/.claude-plugin/marketplace.json +10 -1
  59. package/CHANGELOG.md +69 -0
  60. package/README.md +44 -23
  61. package/config/gitignore-block.txt +8 -0
  62. package/docs/announcements/2026-05-non-dev-launch.md +79 -0
  63. package/docs/architecture.md +2 -2
  64. package/docs/case-studies/_template.md +60 -0
  65. package/docs/catalog.md +24 -3
  66. package/docs/contracts/agent-user-schema.md +1 -0
  67. package/docs/contracts/command-clusters.md +2 -0
  68. package/docs/contracts/file-ownership-matrix.json +490 -0
  69. package/docs/contracts/ghostwriter-schema.md +337 -0
  70. package/docs/contracts/init-telemetry.md +133 -0
  71. package/docs/contracts/router-blending.md +71 -0
  72. package/docs/contracts/universal-skills.md +92 -0
  73. package/docs/contracts/write-engine.md +142 -0
  74. package/docs/getting-started-by-role.md +89 -0
  75. package/docs/getting-started-laravel.md +72 -0
  76. package/docs/getting-started.md +2 -2
  77. package/docs/safety.md +30 -0
  78. package/package.json +1 -1
  79. package/scripts/bench_runner.py +158 -0
  80. package/scripts/check_role_doc_links.py +110 -0
  81. package/scripts/compress.py +11 -0
  82. package/scripts/ghostwriter_fixture_allowlist.txt +16 -0
  83. package/scripts/install.py +133 -1
  84. package/scripts/lint_ghostwriter_source.py +240 -0
  85. package/scripts/measure_skill_reduction.py +102 -0
  86. package/scripts/schemas/rule.schema.json +5 -0
  87. package/scripts/schemas/skill.schema.json +6 -0
  88. package/scripts/update-github-metadata.sh +84 -0
@@ -0,0 +1,337 @@
1
+ ---
2
+ stability: beta
3
+ keep-beta-until: 2026-08-13
4
+ ---
5
+
6
+ # `ghostwriter/<slug>.md` schema (v1)
7
+
8
+ > **Status:** beta — locked for the `/ghostwriter` cluster roadmap.
9
+ > Re-evaluate fields after the cluster has shipped + been in use
10
+ > for ≥ 1 week.
11
+
12
+ A **ghostwriter profile** is a single Markdown file that captures the
13
+ public writing voice of a documented public figure so the `/ghostwriter:write`
14
+ and `/post-as:ghostwriter` commands can emit copyable drafts in that
15
+ voice. Ghostwriter is the third voice primitive in the package, peer
16
+ to `personas/*.md` (review-lens, internal) and `.agent-user.md` (the
17
+ maintainer themselves).
18
+
19
+ The file is owned by the user. The agent never edits it without an
20
+ explicit `accept` step on `/ghostwriter:fetch` re-runs.
21
+
22
+ ## Storage model (dual)
23
+
24
+ - **Consumer projects** — `agents/ghostwriter/<slug>.md`. Real-person
25
+ profiles live here. **Gitignored by default** via the package-managed
26
+ `.gitignore` block. A `--shared` opt-in to commit profiles is
27
+ deferred to v2; only the doc note lands in v1.
28
+ - **Package source** — `.agent-src.uncompressed/ghostwriter/` ships
29
+ the README, this schema doc, and `fictional: true` fixtures only.
30
+ **Zero real-person profiles ever ship with the OSS package.** A CI
31
+ lint (`task lint-ghostwriter-source`) enforces this rule by failing
32
+ on any non-allowlisted file or any file lacking the `fictional: true`
33
+ frontmatter key.
34
+
35
+ Slug = full-name kebab-case (`alice-walker`). Optional `-<discriminator>`
36
+ suffix for disambiguation (`alice-walker-novelist` vs `alice-walker-cyclist`).
37
+ Namespace conflict resolution is consumer-owned — the package does not
38
+ deduplicate across consumers.
39
+
40
+ ## Locked frontmatter (v1)
41
+
42
+ ```yaml
43
+ ---
44
+ version: 1
45
+ fictional: false # required — true for package-side fixtures, false for real-person consumer profiles
46
+ identity:
47
+ name: "Alice Walker" # required — public name
48
+ role_or_title: "novelist" # required — short role label
49
+ era: "1944–" # optional — birth–death range; "1944–" if living
50
+ public_figure_category: "public_artist" # required — enum below
51
+ source_urls: # required — public sources only, ≥ 3 distinct items
52
+ - "https://example.org/walker/interview-1"
53
+ - "https://example.org/walker/essay-collection"
54
+ - "https://example.org/walker/lecture-2018"
55
+ fetched_at: "2026-05-15" # required — ISO date of last fetch
56
+ confidence: "med" # required — low | med | high (see § Confidence)
57
+ attestation_recorded_at: "2026-05-15T10:00:00Z" # required — when the user attested (NOT consent, see § Ethics floor)
58
+ aliases: # optional, consumer-only — alternative names that resolve to this slug
59
+ - "Hawking" # case-insensitive match, case-preserving storage
60
+ - "Prof. Hawking" # min 2 chars, no homoglyphs (see § Aliases)
61
+ style:
62
+ fingerprint:
63
+ sentence_length_avg: 18 # avg words per sentence across samples
64
+ vocab_register: "literary" # casual | conversational | professional | literary | academic
65
+ opener_patterns: ["personal anecdote", "rhetorical question"]
66
+ closer_patterns: ["call to reflection", "quoted aphorism"]
67
+ hashtag_rules: "never" # always | sometimes | never
68
+ emoji_rules: "never" # always | sometimes | never
69
+ paragraph_cadence: "long-form, 4–6 sentence paragraphs"
70
+ free_form_notes: |
71
+ Tends to weave personal narrative with broader social observation.
72
+ Rarely uses imperatives; prefers invitations.
73
+ voice_samples: # required — max 3 items, each ≤ 200 words, source-attributed
74
+ - source_url: "https://example.org/walker/interview-1"
75
+ length_words: 142
76
+ text: |
77
+ [actual public excerpt, max 200 words]
78
+ taboos: # required — what the target never does in public writing
79
+ - "political endorsements"
80
+ - "profanity"
81
+ - "hashtag-driven posts"
82
+ source_provenance: # required
83
+ count: 3 # number of distinct source URLs
84
+ last_fetched_at: "2026-05-15"
85
+ types: ["interview", "essay", "lecture"] # platforms/formats represented
86
+ verification: "fetched" # required — fetched | user-asserted (see § Verification)
87
+ last_updated: "2026-05-15" # YYYY-MM-DD — bumped on every accepted change
88
+ ---
89
+ ```
90
+
91
+ After the frontmatter, the body is a single freeform **`# Notes`**
92
+ section for the user's own observations on the profile. Hard cap:
93
+ **200 lines** total file size (frontmatter + body + Notes).
94
+
95
+ ## Field reference
96
+
97
+ | Field | Required | Purpose |
98
+ |---|---|---|
99
+ | `version` | yes | Schema version. v1 is the only valid value today. |
100
+ | `fictional` | yes | `true` for package fixtures, `false` for real-person consumer profiles. Drives `task lint-ghostwriter-source`. |
101
+ | `identity.name` | yes | Public name of the figure. |
102
+ | `identity.role_or_title` | yes | Short role label (novelist, executive, …). |
103
+ | `identity.era` | no | Birth–death range. Trailing `–` for living figures. |
104
+ | `identity.public_figure_category` | yes | Enum: `author` \| `executive` \| `academic` \| `politician` \| `journalist` \| `public_speaker` \| `public_artist` \| `deceased_historical`. |
105
+ | `identity.source_urls` | yes | ≥ 3 public source URLs. Drives `confidence`. |
106
+ | `identity.fetched_at` | yes | ISO date of the most recent fetch. |
107
+ | `identity.confidence` | yes | `low` \| `med` \| `high` — derived from source count/diversity. |
108
+ | `identity.attestation_recorded_at` | yes | ISO timestamp the user attested the public-figure gate. |
109
+ | `aliases` | no | Consumer-only list of alternative names that resolve to this profile's slug. See [§ Aliases](#aliases). Banned on `fictional: true` fixtures. |
110
+ | `style.fingerprint.*` | yes | Structured shape of the voice. All sub-fields required. |
111
+ | `style.free_form_notes` | yes | Free-form supplement to the structured fingerprint. |
112
+ | `voice_samples` | yes | Max 3 items; each `≤ 200 words`; each source-attributed. |
113
+ | `taboos` | yes | What the target never does — feeds the write engine's negative-constraint pass. |
114
+ | `source_provenance.count` | yes | Distinct source URLs. |
115
+ | `source_provenance.last_fetched_at` | yes | ISO date — drives the 90-day stale warning. |
116
+ | `source_provenance.types` | yes | Platforms/formats (interview, essay, post, book, …). |
117
+ | `source_provenance.verification` | yes | `fetched` (host agent retrieved) \| `user-asserted` (user pasted; not verifiable). |
118
+ | `last_updated` | yes | ISO date, bumped on every accept. |
119
+
120
+ ## Confidence
121
+
122
+ Derived deterministically from `source_provenance.count` and `types`:
123
+
124
+ | Sources × types | Confidence |
125
+ |---|---|
126
+ | 3 sources, same platform | `low` |
127
+ | 3+ sources, 2+ platforms | `med` |
128
+ | 5+ sources, 3+ platforms, ≥ 1 canonical (Wikipedia / official site / published book) | `high` |
129
+
130
+ `/ghostwriter:fetch` refuses to write a profile with fewer than 3 distinct
131
+ authoritative sources.
132
+
133
+
134
+ ## Aliases
135
+
136
+ `aliases` is an **optional, consumer-only** field listing alternative
137
+ names that resolve to this profile's slug. It is a portability win
138
+ over per-user shell aliases — team-shared profiles become immediately
139
+ usable without per-developer config.
140
+
141
+ The list is read by `/ghostwriter:write --as=<value>` (and the
142
+ `/post-as:ghostwriter` thin alias) when resolving the style source:
143
+
144
+ 1. Exact slug match (case-insensitive on filename stem).
145
+ 2. **If no slug match**, scan every consumer profile's `aliases` list
146
+ for a case-insensitive equality match against `<value>`.
147
+ 3. If neither matches, fall through to the interactive numbered menu.
148
+
149
+ ### Storage rules
150
+
151
+ - **Case-insensitive match, case-preserving storage** — the resolver
152
+ treats `--as=hawking` and `--as=Hawking` as identical, but the YAML
153
+ preserves the author's chosen casing.
154
+ - **Minimum length: 2 characters** — single-character aliases are
155
+ collision magnets and are rejected by the consumer-side lint.
156
+ - **No homoglyphs** — aliases must use Latin script (ASCII letters,
157
+ digits, common punctuation, common Latin diacritics). Cyrillic,
158
+ Greek, or other confusable scripts are rejected. Prevents spoofing
159
+ like `Stephеn` (Cyrillic `е`) shadowing `Stephen`.
160
+ - **Case-insensitive uniqueness within a profile** — a single profile
161
+ cannot list both `"Hawking"` and `"hawking"`.
162
+ - **Case-insensitive uniqueness across consumer profiles** — two
163
+ different profiles in the same consumer tree cannot share an alias
164
+ (including alias-vs-slug collisions). Conflicts fail the consumer-side
165
+ lint (Option B — lint-time rejection, never a runtime disambiguation
166
+ menu). Determinism contract trumps UX convenience.
167
+
168
+ ### Footer integrity (canonical name only)
169
+
170
+ The mandatory [disclosure footer](#mandatory-disclosure-footer-deterministic)
171
+ **always** uses `identity.name`, never the alias that triggered the
172
+ command. A user invoking `/ghostwriter:write --as=Hawking` against a
173
+ profile with `identity.name: "Stephen Hawking"` produces a footer
174
+ reading *"Written in the style of Stephen Hawking, not by them."* —
175
+ not *"…of Hawking, not by them."* This makes aliases UX-only; identity
176
+ attribution stays deterministic.
177
+
178
+ ### Package-source ban
179
+
180
+ `aliases:` is **forbidden** on any file with `fictional: true`. Package
181
+ fixtures are schema examples for a single canonical name; aliases are a
182
+ consumer-only deployment feature. The package-source lint
183
+ (`task lint-ghostwriter-source`) fails on `aliases:` in
184
+ `.agent-src.uncompressed/ghostwriter/`.
185
+
186
+ ### Settings toggle (consumer-only)
187
+
188
+ The consumer enables alias resolution via `.agent-project-settings.yml`:
189
+
190
+ ```yaml
191
+ ghostwriter:
192
+ aliases: true # default: true — set to false to disable resolver
193
+ ```
194
+
195
+ Toggling `aliases: false` makes `/ghostwriter:write --as=<value>` resolve
196
+ against slug names only; any `aliases:` entries in profiles are ignored
197
+ at resolve time (but the lint still validates them on commit).
198
+
199
+ ## Verification
200
+
201
+ `source_provenance.verification` distinguishes two acquisition paths:
202
+
203
+ - `fetched` — the host agent retrieved the source URLs via its built-in
204
+ web-fetch / web-search capability. Default for `/ghostwriter:fetch`.
205
+ - `user-asserted` — the host agent could not fetch and the user pasted
206
+ the material manually. The package cannot independently verify these
207
+ sources. `/ghostwriter:show` surfaces user-asserted profiles with a
208
+ visible `⚠️ user-asserted sources — not independently verified` line.
209
+
210
+ This split exists because the package contains zero network code (see
211
+ [§ Determinism floor](#determinism-floor)); the agent cannot otherwise
212
+ distinguish first-party fetch from paste-and-trust.
213
+
214
+ ## Ethics floor
215
+
216
+ ### Public-figure-only gate (advisory)
217
+
218
+ Before `/ghostwriter:fetch` writes any file, the user must explicitly
219
+ attest that:
220
+
221
+ 1. The target is a documented public figure with a public-facing role
222
+ matching `public_figure_category`.
223
+ 2. The source URLs are public, not paywalled, not login-walled, not
224
+ leaked, not retracted.
225
+ 3. The user accepts the right-of-publicity and defamation surface — the
226
+ user owns the legal call, not the package.
227
+ 4. The user understands the disclosure footer on every `/ghostwriter:write`
228
+ output is non-removable.
229
+
230
+ The attestation timestamp is recorded in `identity.attestation_recorded_at`.
231
+
232
+ **The gate is advisory by design.** The package has no network code and
233
+ cannot verify the target's public-figure status against Wikidata or any
234
+ external source. The user's attestation is a documented user-asserted
235
+ checkpoint, not legal consent on the figure's behalf — for living
236
+ figures, no consent path exists short of direct opt-in (deferred to v2).
237
+
238
+ ### Mandatory disclosure footer (deterministic)
239
+
240
+ Every `/ghostwriter:write` and `/post-as:ghostwriter` output ends with
241
+ this literal footer:
242
+
243
+ ```
244
+ Written in the style of <identity.name>, not by them.
245
+ ```
246
+
247
+ The footer is appended by the command's procedural output template as
248
+ a literal string — **not** generated by the model. There is no
249
+ `--no-disclosure` flag. The acceptance criteria grep-verify the absence
250
+ of any opt-out flag in the command source.
251
+
252
+ ### Banned content (always)
253
+
254
+ Even for documented public figures, `/ghostwriter:fetch` refuses:
255
+
256
+ - Leaked drafts or material marked private / draft / internal.
257
+ - Paywalled or login-walled content.
258
+ - Private DMs, private email leaks, retracted posts.
259
+ - Medical, financial, or legal data attributed to the figure.
260
+ - Opinions the figure has not publicly stated.
261
+
262
+ ### Excluded targets
263
+
264
+ Private individuals (a random LinkedIn user who is not a public figure)
265
+ remain out of scope. This carve-out only widens the persona-roadmap's
266
+ "no third-party PII" floor for documented public figures, never for
267
+ anyone else.
268
+
269
+ ## Determinism floor (inherited)
270
+
271
+ The `agent-config` package contains **zero network code**. `/ghostwriter:fetch`
272
+ is a procedural document that delegates the fetch or search to the host
273
+ agent's built-in capability. The package only reads the returned data
274
+ and proposes a diff for user acceptance.
275
+
276
+ ## Staleness
277
+
278
+ When `source_provenance.last_fetched_at` is older than 90 days, any
279
+ `/ghostwriter:*` command surfaces a one-line warning (non-blocking):
280
+
281
+ ```
282
+ ⚠️ ghostwriter/<slug>.md was last fetched YYYY-MM-DD (>90 days ago). Run /ghostwriter:fetch <slug> --force-refresh.
283
+ ```
284
+
285
+ ## Re-fetch flow
286
+
287
+ `/ghostwriter:fetch` on an existing slug routes through a diff-and-accept
288
+ flow mirroring `/agents user accept` — the user reviews the proposed
289
+ diff before any write. `--force-refresh` rebuilds the profile from scratch
290
+ instead of merging.
291
+
292
+ ## Lint enforcement (`task lint-ghostwriter-source`)
293
+
294
+ The lint runs in `task ci` and fails on:
295
+
296
+ 1. Any file under `.agent-src.uncompressed/ghostwriter/` whose stem is
297
+ **not** on the fixture allowlist (`scripts/ghostwriter_fixture_allowlist.txt`).
298
+ 2. Any allowlisted file missing `fictional: true` in frontmatter.
299
+ 3. Any package-source file (`fictional: true`) carrying an `aliases:`
300
+ field (aliases are a consumer-only feature; see [§ Aliases](#aliases)).
301
+ 4. Any consumer-side file under `agents/ghostwriter/` with `fictional: true`
302
+ (fictional profiles belong in the package source, not consumer trees).
303
+ 5. Any consumer-side `aliases:` entry that violates the storage rules:
304
+ shorter than 2 characters, non-Latin scripts (homoglyph protection),
305
+ duplicate within a profile (case-insensitive), or colliding across
306
+ profiles (case-insensitive — alias-vs-alias or alias-vs-slug).
307
+
308
+ New package-side fixtures require updating the allowlist + reviewer
309
+ sign-off.
310
+
311
+ ## Commands
312
+
313
+ | Command | Role |
314
+ |---|---|
315
+ | `/ghostwriter:fetch` | Creates or refreshes a profile from URL or name input. Runs the public-figure gate. |
316
+ | `/ghostwriter:write` | Generates a draft in the chosen voice. Appends the mandatory disclosure footer. |
317
+ | `/ghostwriter:list` | Numbered listing of available profiles. |
318
+ | `/ghostwriter:show` | Read-only render of one profile. |
319
+ | `/ghostwriter:delete` | Two-step confirmation, hard-deletes the file. |
320
+ | `/post-as:me` | Separate top-level command. Reads `.agent-user.md`; shares the write engine. |
321
+ | `/post-as:ghostwriter` | Thin alias to `/ghostwriter:write`. |
322
+
323
+ See [`command-clusters.md`](command-clusters.md) for the locked
324
+ cluster registration.
325
+
326
+ ## Gitignore
327
+
328
+ `agents/ghostwriter/*.md` (except `README.md`) is added to the
329
+ package-managed `.gitignore` block ([`config/gitignore-block.txt`](../../config/gitignore-block.txt))
330
+ and ignored by default. A `--shared` opt-in to commit profiles is
331
+ deferred to v2.
332
+
333
+ ## See also
334
+
335
+ - [`agent-user-schema`](agent-user-schema.md) — the maintainer-self primitive that `/post-as:me` consumes.
336
+ - [`persona-schema`](persona-schema.md) — the review-lens primitive, distinct from ghostwriter.
337
+ - [`command-clusters`](command-clusters.md) — the canonical cluster registry.
@@ -0,0 +1,133 @@
1
+ ---
2
+ stability: beta
3
+ keep-beta-until: 2026-08-15
4
+ ---
5
+
6
+ # Init Telemetry v1
7
+
8
+ > **Status:** beta · **Owner:** step-12 Phase 7 (`agents/roadmaps/step-12-universal-os-reframe.md`) · **Depends on:** [`step-9-user-types-axis`](../../agents/roadmaps/step-99-north-star-restructure.md) telemetry wire-up · **Stability:** additive only
9
+
10
+ ## Purpose
11
+
12
+ Define the wire-shape, redaction floor, opt-in semantics, and producer/consumer split for anonymous telemetry emitted by `agent-config init --interactive`. Used to validate the **Universal-OS reframe hypothesis**: that real `init` runs distribute across non-developer `user_type` values, not only `developer`.
13
+
14
+ This contract ships **ahead of execution**. The producer (`scripts/install.py`) and consumer (aggregation endpoint) are gated on `step-9` user-type filtering — until that ships, this document is the binding shape for the deferred implementation.
15
+
16
+ ## Scope
17
+
18
+ Defines:
19
+
20
+ - The single event emitted (`init.user_type.selected`).
21
+ - Field allowlist (no PII, no free-form text, no host fingerprints).
22
+ - Opt-out default (no event without explicit `--telemetry=on` or `.agent-config.local.json` opt-in).
23
+ - Endpoint contract (HTTPS POST, JSON, retention).
24
+
25
+ Does **not** define:
26
+
27
+ - Aggregation queries or dashboards (consumer concern).
28
+ - Other agent-config events — this contract is `init`-scoped.
29
+
30
+ ## Iron Law — opt-out by default
31
+
32
+ ```
33
+ NO TELEMETRY UNLESS THE USER OPTED IN THIS RUN OR IN .agent-config.local.json.
34
+ NO IP, NO HOSTNAME, NO PATH, NO USERNAME, NO FREE-FORM TEXT.
35
+ ```
36
+
37
+ The `--interactive` flag MUST surface the telemetry choice on first run with a clear default (`off`). The choice is persisted to `.agent-config.local.json` under `telemetry.init: true|false`. Re-runs read the persisted value; `--telemetry=on|off` overrides for that run only.
38
+
39
+ ## Event shape
40
+
41
+ One JSON object per emitted event. UTF-8, no trailing newline:
42
+
43
+ ```json
44
+ {
45
+ "event": "init.user_type.selected",
46
+ "schema_version": 1,
47
+ "ts": "2026-05-15T00:00:00Z",
48
+ "user_type": "creator",
49
+ "stack": "none",
50
+ "verbosity": "normal",
51
+ "interactive": true,
52
+ "agent_config_version": "1.4.2",
53
+ "install_id": "anon-7f3a2b1c"
54
+ }
55
+ ```
56
+
57
+ **Field rules:**
58
+
59
+ | Field | Type | Required | Allowed values |
60
+ |---|---|---|---|
61
+ | `event` | string | yes | `init.user_type.selected` (only event in v1) |
62
+ | `schema_version` | int | yes | `1` |
63
+ | `ts` | string | yes | ISO-8601 UTC, second precision |
64
+ | `user_type` | string | yes | `creator` · `founder` · `consultant` · `gtm` · `finance` · `ops` · `developer` |
65
+ | `stack` | string | yes | `none` · `laravel` · `nextjs` · `python` · `symfony` · `generic` |
66
+ | `verbosity` | string | yes | `quiet` · `normal` · `verbose` |
67
+ | `interactive` | bool | yes | `true` if `--interactive`, `false` if env-var path |
68
+ | `agent_config_version` | string | yes | semver from `package.json` |
69
+ | `install_id` | string | yes | random 8-char hex, generated on first opt-in, persisted to `.agent-config.local.json` under `telemetry.install_id` |
70
+
71
+ **Forbidden fields:** IP, hostname, OS user, working-directory path, project name, git remote, env vars beyond the version stamp, any free-form text.
72
+
73
+ ## Install-id semantics
74
+
75
+ - Generated **only** when the user opts in.
76
+ - Random 8 hex chars (`secrets.token_hex(4)`) — collision space is sufficient for "is this the same install retrying?" without identifying the install.
77
+ - Persisted to `.agent-config.local.json` under `telemetry.install_id`.
78
+ - Deleting the file regenerates the id on next opt-in — by design.
79
+ - Never sent if opt-out is active.
80
+
81
+ ## Endpoint contract
82
+
83
+ - **URL:** `https://telemetry.event4u.app/v1/agent-config/init` (placeholder; final URL pinned when consumer ships).
84
+ - **Method:** POST, `Content-Type: application/json`, body is one event object.
85
+ - **Auth:** none — anonymous by design.
86
+ - **Timeout:** 2 s connect, 3 s total. Failure is silent — `init` MUST NOT block or error on telemetry failure.
87
+ - **Retention:** events aggregated to user-type counts per day; raw events purged after 30 d. Aggregate retention 24 months.
88
+ - **Region:** EU-hosted (GDPR Art. 3 footprint; no Standard Contractual Clauses needed for EU installs).
89
+
90
+ ## Opt-out mechanics
91
+
92
+ `.agent-config.local.json`:
93
+
94
+ ```json
95
+ {
96
+ "telemetry": {
97
+ "init": false
98
+ }
99
+ }
100
+ ```
101
+
102
+ When `telemetry.init: false`, the producer:
103
+
104
+ 1. Skips event construction entirely.
105
+ 2. Does NOT generate or persist `install_id`.
106
+ 3. Logs nothing to stderr.
107
+ 4. `--telemetry=on` for the run overrides only that invocation (does not persist).
108
+
109
+ ## GDPR fit
110
+
111
+ - **Lawful basis:** consent (Art. 6(1)(a)). The `--interactive` prompt is the consent surface.
112
+ - **Data minimization:** Art. 5(1)(c) — only the seven fields above; the field allowlist is the redaction floor.
113
+ - **Storage limitation:** Art. 5(1)(e) — 30 d raw, 24 mo aggregate.
114
+ - **Right to withdraw:** Art. 7(3) — `telemetry.init: false` revokes consent; no further events emitted. Already-collected events remain in the aggregate counts (anonymous, no link to person).
115
+ - **Right of access / erasure:** Arts. 15 / 17 — `install_id` is the only handle; the user can rotate it by deleting `.agent-config.local.json`, breaking the link from current to future events.
116
+
117
+ ## Producer / consumer split
118
+
119
+ | Side | Responsibility | Where |
120
+ |---|---|---|
121
+ | **Producer** | Construct + POST the event when opt-in is active. Silent failure. | `scripts/install.py::_emit_init_telemetry()` (deferred to `step-9` wire-up). |
122
+ | **Consumer** | Receive + validate against this schema; aggregate per UTC day; purge raw after 30 d. | Telemetry endpoint (not in this repo; pinned URL ships with `step-9`). |
123
+
124
+ ## Cross-references
125
+
126
+ - [`step-12-universal-os-reframe.md`](../../agents/roadmaps/step-12-universal-os-reframe.md) Phase 7 L127 — the box this contract pre-authors.
127
+ - [`universal-skills.md`](universal-skills.md) — sibling contract for the allowlist this telemetry validates against.
128
+ - [`router-blending.md`](router-blending.md) — the user-type → skill blend that telemetry confirms is being used.
129
+ - [`STABILITY.md`](STABILITY.md) — schema_version bump rules.
130
+
131
+ ## Versioning
132
+
133
+ `schema_version=1` is additive-only. Field additions require an `init-telemetry.md` patch and producer support. Field removals or type changes require a new `schema_version` and a producer that emits both shapes for ≥ 1 minor release.
@@ -0,0 +1,71 @@
1
+ ---
2
+ stability: beta
3
+ keep-beta-until: 2026-08-13
4
+ ---
5
+
6
+
7
+ # Router Blending — Cross-Domain Skill Mix Contract
8
+
9
+ > **Status:** beta · **Owner:** router governance · **Depends on:** [`universal-skills.md`](universal-skills.md), the user-types axis (axis seeds — schema field defined under [`skill.schema.json`](../../scripts/schemas/skill.schema.json) → `recommended_for_user_types`).
10
+
11
+ ## Purpose
12
+
13
+ A founder doing technical due diligence needs both `runway-cognition` and `data-flow-mapper`. A consultant pitching ghost-written thought leadership needs both `ghostwriter` and `competitive-positioning`. Pure prefix-filtering — "load consulting/* for consultants" — silos these workflows and forces the operator to re-enable skills manually.
14
+
15
+ Router blending defines the mix-ratio per user-type so the resolved skill set covers the **dominant** domain plus the **bridge** skills that real workflows demand.
16
+
17
+ ## The blend formula
18
+
19
+ ```
20
+ loaded_skills(user_type) =
21
+ universal_allowlist (always — see universal-skills.md)
22
+ ∪ dominant_pool(user_type) (primary domain, ≈70%)
23
+ ∪ bridge_pool(user_type) (cross-domain, ≈20%)
24
+ ∪ context_pool(user_type) (content / writing / safety, ≈10%)
25
+ ```
26
+
27
+ Percentages are **soft caps** measured against the post-filter skill count, not hard quotas. Drift > ±10% on any pool triggers a re-tag pass and a finding in `agents/eval-findings/`.
28
+
29
+ ## Per user-type blends
30
+
31
+ | user_type | Dominant (~70%) | Bridge (~20%) | Context (~10%) |
32
+ |---|---|---|---|
33
+ | **creator** | `voice-and-tone-design`, `editorial-calendar`, `content-funnel-design`, `messaging-architecture`, `release-comms` | `customer-research`, `competitive-positioning`, `voc-extract` | `privacy-review`, `accessibility-auditor` |
34
+ | **founder** | `runway-cognition`, `unit-economics-modeling`, `fundraising-narrative`, `scenario-modeling`, `okr-tree-modeling` | `data-flow-mapper`, `threat-modeling`, `api-design` | `voice-and-tone-design`, `release-comms` |
35
+ | **consultant** | `discovery-interview`, `competitive-moat-analysis`, `competitive-positioning`, `stakeholder-tradeoff`, `customer-research` | `messaging-architecture`, `voice-and-tone-design`, `release-comms` | `privacy-review`, `data-handling-judgment` |
36
+ | **gtm** | `pipeline-strategy`, `forecast-accuracy`, `deal-qualification-meddic`, `gtm-launch`, `release-comms` | `voice-and-tone-design`, `messaging-architecture`, `voc-extract` | `privacy-review`, `unit-economics-modeling` |
37
+ | **finance** | `runway-cognition`, `unit-economics-modeling`, `scenario-modeling`, `forecasting`, `dcf-modeling` | `data-handling-judgment`, `privacy-review`, `contracts-cognition` | `voice-and-tone-design`, `stakeholder-tradeoff` |
38
+ | **ops** | `incident-commander`, `data-handling-judgment`, `privacy-review`, `dashboard-design`, `launch-readiness` | `threat-modeling`, `secrets-management`, `api-design` | `voice-and-tone-design`, `release-comms` |
39
+ | **developer** | language-/framework-keyed pool (laravel · nextjs-patterns · php-coder · …) | `api-design`, `authz-review`, `playwright-architect`, `threat-modeling` | `voice-and-tone-design`, `release-comms` |
40
+
41
+ Each pool entry is a `recommended_for_user_types:` frontmatter tag on the skill. A skill with no tag is **universal** (see [`universal-skills.md`](universal-skills.md)).
42
+
43
+ ## How the loader resolves a profile
44
+
45
+ 1. **Read** `.agent-config.local.json` → `user_type`.
46
+ 2. **Filter** all 210 skills: keep the skill iff `user_type ∈ recommended_for_user_types` **or** `recommended_for_user_types` is absent (universal).
47
+ 3. **Stack overlay.** If `stack` is set (laravel / nextjs / python / …), also keep skills whose body cites that stack — language-keyed bridge. Implementation: pattern match on the skill `description:` frontmatter; details land with the schema-rigor contract once the schema bridge for stack-keyed bridge tagging is finalised.
48
+ 4. **Cap.** No filter is applied if the result drops below 50 skills (safety floor — under-filtering is recoverable, over-filtering hides essentials).
49
+ 5. **Surface** `loaded_skills_count` + per-pool counts in the agent debug output.
50
+
51
+ ## Drift detection
52
+
53
+ `scripts/check_router_blend.py` (to ship with Phase 5) walks each user-type and reports:
54
+
55
+ - Dominant-pool fraction (must be ≥ 0.55).
56
+ - Bridge-pool fraction (≥ 0.15).
57
+ - Empty-pool sentinel: any user-type with zero bridge tags fails the check.
58
+
59
+ Wired into `task ci` as a non-blocking warning until the user-types axis stabilizes; promoted to blocking once `step-9` ships its three seed user-types.
60
+
61
+ ## Open questions (tracked for Phase 5 → Phase 6 transition)
62
+
63
+ - Stack overlay precedence: framework tag vs. user-type tag — currently union, may want intersection for the `developer + laravel` combo. Empirical question, tested by corpus.
64
+ - Cross-domain explicit opt-in: `agent-config skills enable <name>` to override the filter on demand. Not in scope for Phase 5 — opens once the filter ships.
65
+ - Persona ↔ user-type mapping: a `consultant` user_type may default to `discovery-lead` persona, but personas are role-axis, not user-axis. Final mapping resolved with [`docs/contracts/persona-schema.md`](persona-schema.md).
66
+
67
+ ## Related
68
+
69
+ - [`universal-skills.md`](universal-skills.md) — the always-loaded floor under the blend.
70
+ - [`skill.schema.json`](../../scripts/schemas/skill.schema.json) — `recommended_for_user_types` field that carries the tags.
71
+ - [`tests/eval/corpus-non-dev.yaml`](../../tests/eval/corpus-non-dev.yaml) — empirical validation of the blends.
@@ -0,0 +1,92 @@
1
+ ---
2
+ stability: beta
3
+ keep-beta-until: 2026-08-13
4
+ ---
5
+
6
+
7
+ # Universal Skills — Allowlist Contract
8
+
9
+ > **Status:** beta · **Owner:** step-12 Phase 3 · **Stability:** additive only (no removals without a migration note in `STABILITY.md`)
10
+
11
+ ## Purpose
12
+
13
+ When `agent-config init --interactive` writes a `.agent-config.local.json` with a `user_type` (e.g., `creator`, `founder`, `consultant`), the host agent filters its loaded skill set to that user-type's recommended skills + this allowlist. **Skills on this allowlist are loaded for every user-type regardless of profile.**
14
+
15
+ The allowlist solves the over-siloing risk identified by the AI Council 2026-05-15 review: a `consultant` user still needs `decision-record` and `risk-officer`; a `creator` still needs `refine-prompt` and `verify-completion-evidence`. These are not domain skills — they are agent-OS primitives.
16
+
17
+ ## The 15
18
+
19
+ | Skill | Why universal |
20
+ |---|---|
21
+ | [`refine-prompt`](../../.agent-src/skills/refine-prompt/SKILL.md) | Every free-form request needs AC + assumption + confidence band before the engine runs. |
22
+ | [`refine-ticket`](../../.agent-src/skills/refine-ticket/SKILL.md) | Every ticket (Jira / Linear / GH issue) needs scoped AC before plan. |
23
+ | [`estimate-ticket`](../../.agent-src/skills/estimate-ticket/SKILL.md) | Sizing + split + risk — applies to any work item, technical or not. |
24
+ | [`verify-completion-evidence`](../../.agent-src/skills/verify-completion-evidence/SKILL.md) | Iron-Law gate: fresh evidence before any "done" claim. Survives every mode. |
25
+ | [`threat-modeling`](../../.agent-src/skills/threat-modeling/SKILL.md) | Pre-implementation abuse-case enumeration — same lens applies to a marketing form and a payment endpoint. |
26
+ | [`systematic-debugging`](../../.agent-src/skills/systematic-debugging/SKILL.md) | Reproduce → isolate → hypothesize → verify — works on broken pipelines, broken docs, broken funnels. |
27
+ | [`doc-coauthoring`](../../.agent-src/skills/doc-coauthoring/SKILL.md) | 3-stage write loop (context → section → reader-test) for any long-form doc. |
28
+ | [`deep-reading-analyst`](../../.agent-src/skills/deep-reading-analyst/SKILL.md) | Article / long-form analysis via SCQA + mental models — used by every role that reads. |
29
+ | [`decision-record`](../../.agent-src/skills/decision-record/SKILL.md) | Trade-off framing before any commit. ADR-shape works for tech, hiring, and pricing. |
30
+ | [`adr-create`](../../.agent-src/skills/adr-create/SKILL.md) | Naming + numbering + index regen — the file mechanics of `decision-record`. |
31
+ | [`risk-officer`](../../.agent-src/skills/risk-officer/SKILL.md) | Blast-radius framing + residual-risk verdict before any commit. |
32
+ | [`adversarial-review`](../../.agent-src/skills/adversarial-review/SKILL.md) | Devil's advocate stress-test — opt-in but always available. |
33
+ | [`customer-research`](../../.agent-src/skills/customer-research/SKILL.md) | Discovery-slice shaping (JTBD, switch-event) — used by founder, GTM, consultant, creator. |
34
+ | [`stakeholder-tradeoff`](../../.agent-src/skills/stakeholder-tradeoff/SKILL.md) | Per-lens framing when stakeholders disagree — applies in every org. |
35
+ | [`md-language-check`](../../.agent-src/skills/md-language-check/SKILL.md) | Hard gate: `.md` files stay English; the agent translates at runtime. |
36
+
37
+ ## Inclusion criteria
38
+
39
+ A skill earns the universal label when **all three** hold:
40
+
41
+ 1. **Cross-role payback.** ≥ 4 of the 6 seeded user-types (creator / founder / consultant / GTM / finance-ops / developer) reach for it in week-one workflows. The non-dev eval corpus ([`tests/eval/corpus-non-dev.yaml`](../../tests/eval/corpus-non-dev.yaml)) is the empirical test.
42
+ 2. **No stack assumption.** The skill body does not rely on a specific language, framework, or repo shape. `laravel`, `nextjs-patterns`, `pest-testing` are domain skills, not universal.
43
+ 3. **Agent-OS primitive.** The skill encodes a meta-pattern of agent behavior (refine, verify, decide, debug, document, threat-model) rather than a domain deliverable (write a launch email, draft an ADR for the auth module).
44
+
45
+ ## Exclusion criteria
46
+
47
+ - **Domain anchor.** `voice-and-tone-design` (creator), `runway-cognition` (founder), `quality-tools` (developer), `pipeline-strategy` (GTM) — strong-fit for one user-type, weak for the other five. These tag via the `recommended_for_user_types:` frontmatter field defined in [`skill.schema.json`](../../scripts/schemas/skill.schema.json).
48
+ - **Tool-specific.** `laravel-horizon`, `nextjs-patterns`, `mcp-builder`, `terraform` — load only when the matching stack flag is set.
49
+ - **Council / role review.** `judge-bug-hunter`, `judge-security-auditor`, `architecture-review-lens` — load via subagent orchestration, not via universal allowlist.
50
+
51
+ ## How loading works (forward-compatible)
52
+
53
+ ```json
54
+ // .agent-config.local.json — written by `agent-config init --interactive`
55
+ {
56
+ "user_type": "consultant",
57
+ "stack": "none",
58
+ "verbosity": "normal",
59
+ "enabled_skill_prefixes": ["consulting/*", "writing/*"],
60
+ "default_persona": "discovery-lead"
61
+ }
62
+ ```
63
+
64
+ The host agent's skill loader is expected to:
65
+
66
+ 1. Resolve `enabled_skill_prefixes` against the per-user-type recommendation list (Phase 5 `recommended_for_user_types:` tags).
67
+ 2. Union with this universal allowlist (always, no opt-out).
68
+ 3. Surface a `loaded_skills_count` in the agent's debug / status output so the operator can verify filtering ran.
69
+
70
+ **Runtime filter status:** the prefix-filter pass is gated on the user-types axis shipping the `user-types/` directory and `--user-type` flag. Until then, every skill loads (current v2.x behavior); this contract is the forward declaration of the eventual filter, not its implementation.
71
+
72
+ ## Change procedure
73
+
74
+ Adding a skill to this allowlist:
75
+
76
+ 1. Open a PR that edits this file + the relevant skill's `recommended_for_user_types:` (omitted = universal).
77
+ 2. Cite ≥ 4 user-type prompts from `tests/eval/corpus-non-dev.yaml` that select the skill.
78
+ 3. Require approval from one Tier-1 reviewer (architecture-review-lens or skill-writing).
79
+ 4. Document the inclusion in `agents/eval-findings/` with the supporting eval prompts.
80
+
81
+ Removing a skill is breaking. It must be announced in `STABILITY.md` with a deprecation window ≥ one minor release.
82
+
83
+ ## Versioning
84
+
85
+ - This contract is **beta**. Once non-dev selection-accuracy ≥ 0.60 sustains across two consecutive `task bench --corpus non-dev` runs, status promotes to **stable** and entries become semver-protected.
86
+
87
+ ## Related
88
+
89
+ - [`STABILITY.md`](STABILITY.md) — public-identifier stability surface.
90
+ - [`agent-memory-contract.md`](agent-memory-contract.md) — companion contract for the cross-cutting memory layer.
91
+ - [`docs/getting-started-by-role.md`](../getting-started-by-role.md) — consumer-facing role docs that reference these skills.
92
+ - [`tests/eval/corpus-non-dev.yaml`](../../tests/eval/corpus-non-dev.yaml) — empirical test corpus.