@event4u/agent-config 2.15.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 (106) 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/.agent-src/templates/scripts/work_engine/_lib/agent_settings.py +299 -20
  59. package/.claude-plugin/marketplace.json +10 -1
  60. package/CHANGELOG.md +200 -211
  61. package/README.md +55 -23
  62. package/config/gitignore-block.txt +8 -0
  63. package/docs/announcements/2026-05-non-dev-launch.md +79 -0
  64. package/docs/architecture.md +2 -2
  65. package/docs/archive/CHANGELOG-pre-2.15.0.md +244 -0
  66. package/docs/case-studies/_template.md +60 -0
  67. package/docs/catalog.md +24 -3
  68. package/docs/contracts/agent-user-schema.md +1 -0
  69. package/docs/contracts/command-clusters.md +2 -0
  70. package/docs/contracts/file-ownership-matrix.json +490 -0
  71. package/docs/contracts/ghostwriter-schema.md +337 -0
  72. package/docs/contracts/init-telemetry.md +133 -0
  73. package/docs/contracts/router-blending.md +71 -0
  74. package/docs/contracts/universal-skills.md +92 -0
  75. package/docs/contracts/write-engine.md +142 -0
  76. package/docs/getting-started-by-role.md +89 -0
  77. package/docs/getting-started-laravel.md +72 -0
  78. package/docs/getting-started.md +2 -2
  79. package/docs/installation.md +221 -2
  80. package/docs/safety.md +30 -0
  81. package/package.json +1 -1
  82. package/scripts/_cli/cmd_doctor.py +238 -8
  83. package/scripts/_cli/cmd_migrate.py +6 -1
  84. package/scripts/_cli/cmd_prune.py +8 -3
  85. package/scripts/_cli/cmd_sync.py +7 -3
  86. package/scripts/_cli/cmd_uninstall.py +4 -3
  87. package/scripts/_cli/cmd_update.py +5 -1
  88. package/scripts/_cli/cmd_validate.py +6 -3
  89. package/scripts/_cli/cmd_versions.py +15 -2
  90. package/scripts/_lib/agent_settings.py +299 -20
  91. package/scripts/agent-config +64 -0
  92. package/scripts/bench_runner.py +158 -0
  93. package/scripts/check_role_doc_links.py +110 -0
  94. package/scripts/compress.py +11 -0
  95. package/scripts/ghostwriter_fixture_allowlist.txt +16 -0
  96. package/scripts/install +39 -2
  97. package/scripts/install.py +304 -1
  98. package/scripts/install.sh +20 -0
  99. package/scripts/lint_ghostwriter_source.py +240 -0
  100. package/scripts/measure_skill_reduction.py +102 -0
  101. package/scripts/schemas/rule.schema.json +5 -0
  102. package/scripts/schemas/skill.schema.json +6 -0
  103. package/scripts/update-github-metadata.sh +84 -0
  104. package/templates/agent-config-wrapper.sh +7 -0
  105. package/templates/minimal/.agent-settings.yml +23 -0
  106. package/templates/minimal/agents-gitkeep +2 -0
@@ -0,0 +1,118 @@
1
+ ---
2
+ name: ghostwriter:delete
3
+ tier: 2
4
+ cluster: ghostwriter
5
+ sub: delete
6
+ description: Hard-delete a ghostwriter profile at agents/ghostwriter/<slug>.md after a two-step confirmation. No backup, no soft delete — the file is gone after acceptance.
7
+ disable-model-invocation: true
8
+ suggestion:
9
+ eligible: true
10
+ trigger_description: "delete ghostwriter profile, remove public-figure voice, drop ghostwriter, retire captured profile"
11
+ trigger_context: "user wants to permanently remove a captured ghostwriter profile from agents/ghostwriter/"
12
+ ---
13
+
14
+ # /ghostwriter:delete
15
+
16
+ Hard-delete a single `agents/ghostwriter/<slug>.md` profile after a
17
+ **two-step confirmation**. The file is gone after acceptance — no
18
+ backup, no soft delete, no trash directory. Mirrors the destructive
19
+ posture of `/agents:user:delete`.
20
+
21
+ ## Steps
22
+
23
+ ### 1. Resolve target
24
+
25
+ Argument shapes:
26
+
27
+ - `/ghostwriter:delete <slug>` → positional slug.
28
+ - `/ghostwriter:delete` → interactive: print the same numbered table
29
+ as [`/ghostwriter:list`](list.md) and ask the user to pick one by
30
+ number or slug. One question per turn.
31
+
32
+ | State | Action |
33
+ |---|---|
34
+ | File missing | Abort. Print: *"No profile at `agents/ghostwriter/<slug>.md`. Run `/ghostwriter:list` to see what exists."* |
35
+ | File present, `fictional: true` | Abort. Print: *"`<slug>.md` is a package-side fixture. Delete it via the source tree, not this command."* |
36
+ | File present, real | Proceed to Step 2 |
37
+
38
+ ### 2. Print a minimal summary
39
+
40
+ Show the user **exactly** what is about to disappear, sourced from
41
+ the file's frontmatter (do not render the full profile body):
42
+
43
+ ```
44
+ About to delete agents/ghostwriter/<slug>.md
45
+ identity.name: <name>
46
+ role: <role_or_title>
47
+ category: <public_figure_category>
48
+ confidence: <low|med|high>
49
+ source count: <source_provenance.count>
50
+ last_fetched_at: <ISO date>
51
+ verification: <fetched|user-asserted>
52
+ ```
53
+
54
+ This is the only summary surface — the full profile is one
55
+ `/ghostwriter:show <slug>` away if the user wants to re-inspect
56
+ before answering.
57
+
58
+ ### 3. First confirmation (intent)
59
+
60
+ Ask, verbatim, one question per turn:
61
+
62
+ > *"Delete this ghostwriter profile? `<slug>.md` will be hard-deleted
63
+ > with no backup. Type `delete` to continue, anything else to cancel."*
64
+
65
+ Anything other than the literal token `delete` (case-insensitive,
66
+ trimmed) → abort with: *"Cancelled. No file was deleted."*
67
+
68
+ ### 4. Second confirmation (irreversibility)
69
+
70
+ Ask, verbatim:
71
+
72
+ > *"Last chance. This is hard-delete — no `.bak`, no trash, no undo
73
+ > from this command. Type the slug `<slug>` exactly to confirm."*
74
+
75
+ User must type the slug literally (case-sensitive, trimmed). Any
76
+ other input → abort with the same cancel line as Step 3.
77
+
78
+ ### 5. Delete + print confirmation
79
+
80
+ Remove the file. Then print:
81
+
82
+ ```
83
+ ✅ agents/ghostwriter/<slug>.md deleted.
84
+ /ghostwriter:list now shows N profiles.
85
+ ```
86
+
87
+ `N` reflects the post-delete count under `agents/ghostwriter/`
88
+ (excluding `README.md`).
89
+
90
+ ### 6. Stale-warning surface (optional)
91
+
92
+ After the delete, if any remaining profile is stale (>90 days), print
93
+ the standard stale-warning lines (one per stale slug). Mirrors the
94
+ post-write surface in `/ghostwriter:fetch` Step 7. Non-blocking.
95
+
96
+ ## Rules
97
+
98
+ - **Hard-delete only.** No `.bak`, no soft delete, no trash directory.
99
+ Mirrors `/agents:user:delete`.
100
+ - **Two-step confirmation is mandatory.** Skipping either step is a
101
+ contract violation. The two prompts must be distinct turns; do not
102
+ batch them into one numbered-options block.
103
+ - **Do NOT commit, push, or open a PR.** The user owns the git surface;
104
+ consumer ghostwriter files are gitignored by default.
105
+ - **Do NOT delete package-side fixtures.** `fictional: true` files
106
+ belong to the source tree and are out of scope for this command.
107
+ - **Do NOT delete `agents/ghostwriter/README.md`.** The directory
108
+ anchor is not a profile.
109
+ - **Do NOT bulk-delete.** One slug per invocation, even when the user
110
+ passes a glob.
111
+
112
+ ## See also
113
+
114
+ - [`/ghostwriter`](../ghostwriter.md) — parent cluster.
115
+ - [`/ghostwriter:list`](list.md) — pick a slug to delete.
116
+ - [`/ghostwriter:show`](show.md) — re-inspect before deleting.
117
+ - [`/ghostwriter:fetch`](fetch.md) — re-create a profile from scratch (no recovery from this command).
118
+ - [`/agents:user:delete`](../agents/user/delete.md) — sibling destructive command this one mirrors.
@@ -0,0 +1,185 @@
1
+ ---
2
+ name: ghostwriter:fetch
3
+ tier: 2
4
+ cluster: ghostwriter
5
+ sub: fetch
6
+ description: Build or refresh a public-figure voice profile at agents/ghostwriter/<slug>.md from a URL or bare name; runs the public-figure attestation gate; delegates web-fetch / web-search to the host agent.
7
+ disable-model-invocation: true
8
+ suggestion:
9
+ eligible: true
10
+ trigger_description: "fetch public figure writing voice, capture LinkedIn / blog / Substack style, build ghostwriter profile from name, refresh stale profile"
11
+ trigger_context: "user wants to capture a documented public figure's writing voice from a URL or by name into agents/ghostwriter/<slug>.md"
12
+ ---
13
+
14
+ # /ghostwriter:fetch
15
+
16
+ Build (or refresh) a ghostwriter profile at
17
+ `agents/ghostwriter/<slug>.md` from one of two inputs:
18
+
19
+ | Input | Mode | Host-agent capability used |
20
+ |---|---|---|
21
+ | URL (LinkedIn / blog / Substack / personal site) | **URL mode** | web-fetch |
22
+ | Bare name (`"Alice Walker"`) | **Name-only mode** | web-search |
23
+
24
+ Zero network code in the package — the host agent performs the fetch /
25
+ search; this command is procedural only. Schema:
26
+ [`ghostwriter-schema`](../../../docs/contracts/ghostwriter-schema.md).
27
+
28
+ ## Steps
29
+
30
+ ### 1. Parse input + resolve slug
31
+
32
+ Argument shape: `/ghostwriter:fetch <input> [--force-refresh]`.
33
+
34
+ - Looks like a URL (`https?://`) → URL mode. Derive slug from the
35
+ page's primary author / persona name (kebab-case).
36
+ - Otherwise → name-only mode. Slug = full name kebab-case
37
+ (`alice-walker`). If a slug already exists with a different role,
38
+ ask the user for a discriminator suffix (`alice-walker-novelist`).
39
+
40
+ Existing `agents/ghostwriter/<slug>.md`?
41
+
42
+ | State | Action |
43
+ |---|---|
44
+ | Missing | Proceed to fresh-fetch flow |
45
+ | Exists, no `--force-refresh` | Diff-and-accept flow (Step 6) |
46
+ | Exists, `--force-refresh` | Back up to `<slug>.md.bak`, rebuild from scratch |
47
+
48
+ ### 2. Public-figure attestation gate (BLOCKING)
49
+
50
+ Print verbatim, one question per turn, **all four** required before any
51
+ write. Mirrors the deterministic gate in
52
+ [`ghostwriter-schema § public-figure gate`](../../../docs/contracts/ghostwriter-schema.md).
53
+
54
+ 1. *"Is the target a documented public figure with a public-facing role
55
+ (author / executive / academic / politician / journalist /
56
+ public-speaker / public-artist / deceased-historical)? Which category?"*
57
+ 2. *"Are all sources you intend to use public — not paywalled,
58
+ login-walled, leaked, or retracted?"*
59
+ 3. *"Do you accept the right-of-publicity and defamation surface? The
60
+ package documents the gate but the legal call is yours."*
61
+ 4. *"Do you understand the disclosure footer on every `/ghostwriter:write`
62
+ output is non-removable?"*
63
+
64
+ Any "no" / silence / decline → abort. Do not write the file.
65
+ Record the UTC ISO timestamp of the fourth "yes" into
66
+ `identity.attestation_recorded_at`.
67
+
68
+ ### 3a. URL mode — host-agent fetch
69
+
70
+ Instruct the host agent: *"Fetch the URL `<input>` and any linked
71
+ author archive / post index. Return public posts (target: last 100;
72
+ floor: 3 distinct items). Exclude paywalled / login-walled / private
73
+ content."*
74
+
75
+ | Result | Action |
76
+ |---|---|
77
+ | Host has web-fetch + ≥ 3 distinct items returned | `source_provenance.verification: fetched`; proceed to Step 4 |
78
+ | Host has web-fetch but < 3 items | Abort; report the floor; suggest name-only mode for broader sources |
79
+ | Host cannot fetch | Emit paste-prompt (Step 3c) |
80
+
81
+ ### 3b. Name-only mode — host-agent search
82
+
83
+ Instruct the host agent: *"Search authoritative public sources for
84
+ `<name>`: Wikipedia, official site, verified social, archived
85
+ interviews, published books (for deceased figures). Return ≥ 3
86
+ distinct authoritative items."*
87
+
88
+ | Result | Action |
89
+ |---|---|
90
+ | ≥ 3 distinct authoritative items | `verification: fetched`; proceed to Step 4 |
91
+ | < 3 items | Abort; report the floor; ask the user to supply URLs |
92
+ | Host cannot search | Emit paste-prompt (Step 3c) |
93
+
94
+ ### 3c. Paste-prompt fallback
95
+
96
+ Print: *"Host agent cannot fetch / search. Paste ≥ 3 public-source
97
+ excerpts with their URLs; one excerpt per code block, max ~200 words
98
+ each. Type `done` when finished."*
99
+
100
+ Collected material → `source_provenance.verification: user-asserted`.
101
+ `/ghostwriter:show` will surface a `⚠️ user-asserted` warning on this
102
+ profile.
103
+
104
+ ### 4. Derive frontmatter
105
+
106
+ From the gathered material, populate the locked frontmatter per
107
+ [`ghostwriter-schema § locked frontmatter (v1)`](../../../docs/contracts/ghostwriter-schema.md):
108
+
109
+ - `identity.*` — name, role, category (from Step 2), source URLs,
110
+ `fetched_at` (today, ISO date), `attestation_recorded_at` (Step 2).
111
+ - `style.fingerprint.*` — derive `sentence_length_avg`, `vocab_register`,
112
+ opener / closer patterns, hashtag / emoji rules, paragraph cadence
113
+ from the gathered excerpts.
114
+ - `style.free_form_notes` — short prose summary.
115
+ - `voice_samples` — pick up to 3 public excerpts, ≤ 200 words each,
116
+ source-attributed.
117
+ - `taboos` — what the figure demonstrably never does in public writing.
118
+ - `source_provenance.{count, last_fetched_at, types, verification}`.
119
+ - `confidence` — derived deterministically:
120
+
121
+ | Sources × types | Confidence |
122
+ |---|---|
123
+ | 3 sources, same platform | `low` |
124
+ | 3+ sources, 2+ platforms | `med` |
125
+ | 5+ sources, 3+ platforms, ≥ 1 canonical | `high` |
126
+
127
+ - `fictional: false` (always, for consumer-side files).
128
+ - `last_updated` — today, ISO date.
129
+
130
+ Body: a single `# Notes` section, empty for fresh fetches.
131
+ **Hard cap: 200 lines total.**
132
+
133
+ ### 5. Propose + confirm (fresh-fetch path)
134
+
135
+ Print the proposed file content as a fenced markdown block. Ask:
136
+
137
+ > 1. write — save to `agents/ghostwriter/<slug>.md`
138
+ > 2. edit — open in IDE first (per `file-editor` skill), save after
139
+ > 3. cancel — discard
140
+
141
+ Only on choice 1 or 2 (after save) write the file. Print the
142
+ post-write summary:
143
+
144
+ ```
145
+ ✅ agents/ghostwriter/<slug>.md written.
146
+ confidence: <low|med|high> · sources: <n> · verification: <fetched|user-asserted>
147
+ ```
148
+
149
+ ### 6. Diff-and-accept (re-fetch path, no `--force-refresh`)
150
+
151
+ Re-run Steps 2–4 against the existing file. Show a **field-by-field
152
+ diff** (frontmatter keys + voice samples). Ask the user to accept
153
+ per-field changes (numbered options). Bump `last_updated` and
154
+ `source_provenance.last_fetched_at` on accept. Mirrors
155
+ [`/agents:user:accept`](../agents/user/accept.md).
156
+
157
+ ### 7. Stale-warning surface (always)
158
+
159
+ After any write (or no-op accept), if any other profile under
160
+ `agents/ghostwriter/*.md` has `source_provenance.last_fetched_at` >
161
+ 90 days old, print one line per stale profile:
162
+
163
+ ```
164
+ ⚠️ ghostwriter/<other-slug>.md last fetched YYYY-MM-DD (>90 days). Run /ghostwriter:fetch <other-slug> --force-refresh.
165
+ ```
166
+
167
+ Non-blocking.
168
+
169
+ ## Rules
170
+
171
+ - **Do NOT commit, push, or open a PR.** The user owns the git surface.
172
+ - **Do NOT write the file before the attestation gate completes** with
173
+ four explicit "yes" answers.
174
+ - **Do NOT bypass the < 3 distinct sources floor** under any flag.
175
+ - **Do NOT introduce network code in the package** — the host agent
176
+ performs every fetch / search; this command only orchestrates.
177
+ - **Do NOT accept private / paywalled / leaked / retracted material**
178
+ even when the user pastes it (Step 3c).
179
+
180
+ ## See also
181
+
182
+ - [`ghostwriter-schema`](../../../docs/contracts/ghostwriter-schema.md) — locked v1 frontmatter, verification levels, confidence derivation.
183
+ - [`/ghostwriter`](../ghostwriter.md) — parent cluster.
184
+ - [`/ghostwriter:write`](write.md) — consume side; appends the mandatory disclosure footer.
185
+ - [`/agents:user:accept`](../agents/user/accept.md) — the diff-and-accept flow this command mirrors on re-fetch.
@@ -0,0 +1,102 @@
1
+ ---
2
+ name: ghostwriter:list
3
+ tier: 2
4
+ cluster: ghostwriter
5
+ sub: list
6
+ description: List captured ghostwriter profiles under agents/ghostwriter/ as a numbered table with confidence, last-fetched, and stale-warning flags. Read-only.
7
+ disable-model-invocation: true
8
+ suggestion:
9
+ eligible: true
10
+ trigger_description: "list ghostwriter profiles, show available public-figure voices, which ghostwriters do I have, ghostwriter inventory"
11
+ trigger_context: "user wants to see which ghostwriter profiles exist locally and which are stale"
12
+ ---
13
+
14
+ # /ghostwriter:list
15
+
16
+ Read-only listing of every consumer-side ghostwriter profile under
17
+ `agents/ghostwriter/`. Numbered, with the fields needed to pick one
18
+ for `/ghostwriter:write` or to spot stale profiles that need a
19
+ re-fetch.
20
+
21
+ ## Steps
22
+
23
+ ### 1. Scan
24
+
25
+ Enumerate `agents/ghostwriter/*.md`, excluding:
26
+
27
+ - `README.md` (directory anchor, not a profile).
28
+ - Any file whose frontmatter carries `fictional: true` (package-side
29
+ fixtures are not consumer profiles; they should never appear in
30
+ `agents/ghostwriter/` — surface a warning if one is found).
31
+
32
+ For each remaining file, read the frontmatter and extract:
33
+
34
+ | Field | Source |
35
+ |---|---|
36
+ | Slug | filename without `.md` |
37
+ | Name | `identity.name` |
38
+ | Role | `identity.role_or_title` |
39
+ | Category | `identity.public_figure_category` |
40
+ | Confidence | `identity.confidence` (`low` / `med` / `high`) |
41
+ | Verification | `source_provenance.verification` (`fetched` / `user-asserted`) |
42
+ | Last fetched | `source_provenance.last_fetched_at` (ISO date) |
43
+ | Stale | `last_fetched_at` older than 90 days → `⚠️` |
44
+ | User-asserted | `verification == user-asserted` → `⚠️` |
45
+
46
+ ### 2. Render
47
+
48
+ Empty result → print and exit:
49
+
50
+ ```
51
+ No ghostwriter profiles found under agents/ghostwriter/.
52
+ Run /ghostwriter:fetch <url-or-name> to capture one.
53
+ ```
54
+
55
+ Otherwise, print a numbered table sorted by slug:
56
+
57
+ ```
58
+ # Ghostwriters (N profiles)
59
+
60
+ # Slug Name Confidence Last fetched Flags
61
+ 1 alice-walker Alice Walker high 2026-04-12
62
+ 2 jane-doe-author Jane Doe med 2025-11-03 ⚠️ stale
63
+ 3 bob-smith Bob Smith low 2026-05-01 ⚠️ user-asserted
64
+
65
+ Next: /ghostwriter:show <slug> · /ghostwriter:write --as=<slug>
66
+ /ghostwriter:fetch <slug> --force-refresh # for stale profiles
67
+ ```
68
+
69
+ Column widths are illustrative — pick the widest entry per column.
70
+
71
+ ### 3. Fixture leak warning (defensive)
72
+
73
+ If Step 1 encountered a `fictional: true` file under
74
+ `agents/ghostwriter/`, print **after** the table:
75
+
76
+ ```
77
+ ⚠️ agents/ghostwriter/<file>.md carries `fictional: true` — fixtures
78
+ belong in the package source, not in consumer ghostwriter/. Move
79
+ or delete this file.
80
+ ```
81
+
82
+ This should not normally happen — `scripts/lint_ghostwriter_source.py`
83
+ guards the package side (run via the package's CI), and consumer-side
84
+ `fetch` always writes `fictional: false`.
85
+
86
+ ## Rules
87
+
88
+ - **Read-only.** Do not modify or move any file.
89
+ - **Do NOT commit, push, or open a PR.** No git ops.
90
+ - **Do NOT inline voice samples.** Use `/ghostwriter:show <slug>` for
91
+ the full profile body — this command is an index, not a renderer.
92
+ - **Do NOT include `fictional: true` profiles in the main table** —
93
+ they are package-side schema examples, not consumable styles. Surface
94
+ any leak as a separate warning (Step 3).
95
+
96
+ ## See also
97
+
98
+ - [`/ghostwriter`](../ghostwriter.md) — parent cluster.
99
+ - [`/ghostwriter:show`](show.md) — render a single profile in full.
100
+ - [`/ghostwriter:fetch`](fetch.md) — refresh stale profiles with `--force-refresh`.
101
+ - [`/ghostwriter:write`](write.md) — consume side; reuses the slugs listed here via `--as=<slug>`.
102
+ - [`ghostwriter-schema`](../../../docs/contracts/ghostwriter-schema.md) — field definitions used in the table.
@@ -0,0 +1,113 @@
1
+ ---
2
+ name: ghostwriter:show
3
+ tier: 2
4
+ cluster: ghostwriter
5
+ sub: show
6
+ description: Render a single ghostwriter profile in full — identity, style fingerprint, voice samples, taboos, source URLs. Read-only.
7
+ disable-model-invocation: true
8
+ suggestion:
9
+ eligible: true
10
+ trigger_description: "show ghostwriter profile, inspect public-figure voice, view ghostwriter details, what does this profile contain"
11
+ trigger_context: "user wants to inspect a single captured ghostwriter profile before writing with it or deciding to refresh / delete it"
12
+ ---
13
+
14
+ # /ghostwriter:show
15
+
16
+ Read-only render of a single `agents/ghostwriter/<slug>.md` profile.
17
+ Surfaces every field needed to decide whether to consume the voice
18
+ (`/ghostwriter:write`), refresh it (`/ghostwriter:fetch <slug>
19
+ --force-refresh`), or delete it (`/ghostwriter:delete`).
20
+
21
+ ## Steps
22
+
23
+ ### 1. Resolve target
24
+
25
+ Argument shapes:
26
+
27
+ - `/ghostwriter:show <slug>` → positional slug.
28
+ - `/ghostwriter:show <n>` → numeric index from the most recent
29
+ `/ghostwriter:list` ordering (re-derive by listing slugs sorted
30
+ ascending; index is 1-based).
31
+ - `/ghostwriter:show` → interactive — print the same numbered table
32
+ as [`/ghostwriter:list`](list.md) and ask the user to pick one
33
+ by number or slug, one question per turn.
34
+
35
+ Resolution table:
36
+
37
+ | State | Action |
38
+ |---|---|
39
+ | File missing | Abort. Print: *"No profile at `agents/ghostwriter/<slug>.md`. Run `/ghostwriter:list` to see what exists."* |
40
+ | File present, `fictional: true` | Print a one-line warning before rendering: *"⚠️ This is a package-side fixture, not a real-person profile."* Then render normally. |
41
+ | File present, real | Render (Step 2) |
42
+
43
+ ### 2. Render
44
+
45
+ Print the profile as fenced sections in the user's language. Sections,
46
+ in order:
47
+
48
+ 1. **Header** — name, slug, public-figure category.
49
+ 2. **Identity** — `role_or_title`, `era`, source URLs as a bullet list,
50
+ `fetched_at`, `attestation_recorded_at`, `confidence`.
51
+ 3. **Source provenance** — `count`, `last_fetched_at`, `types` (bullet
52
+ list), `verification`. If `verification: user-asserted`, prefix the
53
+ section header with `⚠️`.
54
+ 4. **Style fingerprint** — `sentence_length_avg`, `vocab_register`,
55
+ `opener_patterns`, `closer_patterns`, `hashtag_rules`, `emoji_rules`,
56
+ `paragraph_cadence`.
57
+ 5. **Free-form notes** — `style.free_form_notes` verbatim.
58
+ 6. **Voice samples** — each sample as a fenced quote block with the
59
+ source URL underneath. Truncate samples > 200 words with `[…]` and
60
+ note the cap.
61
+ 7. **Taboos** — bullet list.
62
+ 8. **Body — `# Notes`** — the in-file Notes section, verbatim (may be
63
+ empty for fresh fetches).
64
+
65
+ ### 3. Footer hints
66
+
67
+ After the rendered profile, print the available next actions:
68
+
69
+ ```
70
+ Next:
71
+ /ghostwriter:write --as=<slug> # draft in this voice
72
+ /ghostwriter:fetch <slug> --force-refresh # rebuild from scratch
73
+ /ghostwriter:delete <slug> # hard-delete the file
74
+ ```
75
+
76
+ ### 4. Stale + user-asserted surface
77
+
78
+ If `last_fetched_at` is > 90 days old, append a one-line warning:
79
+
80
+ ```
81
+ ⚠️ Last fetched YYYY-MM-DD (>90 days). Consider /ghostwriter:fetch <slug> --force-refresh.
82
+ ```
83
+
84
+ If `verification: user-asserted`, append:
85
+
86
+ ```
87
+ ⚠️ Profile is user-asserted (no host-fetched verification). Style fidelity may be lower.
88
+ ```
89
+
90
+ Non-blocking.
91
+
92
+ ## Rules
93
+
94
+ - **Read-only.** Do not modify, move, or write the file.
95
+ - **Do NOT commit, push, or open a PR.** No git ops.
96
+ - **Do NOT redact voice samples by topic.** The whole sample (capped at
97
+ 200 words per `ghostwriter-schema`) is part of the schema contract;
98
+ partial rendering would mislead the consumer about the captured
99
+ style.
100
+ - **Do NOT auto-trigger a re-fetch on stale profiles.** Surface the
101
+ warning and let the user run `/ghostwriter:fetch <slug>
102
+ --force-refresh` explicitly.
103
+ - **Do NOT consume `personas/*.md` or `.agent-user.md`.** Wrong
104
+ primitive — those are not ghostwriters.
105
+
106
+ ## See also
107
+
108
+ - [`/ghostwriter`](../ghostwriter.md) — parent cluster.
109
+ - [`/ghostwriter:list`](list.md) — index of profiles (use first to pick a slug).
110
+ - [`/ghostwriter:fetch`](fetch.md) — refresh path; `--force-refresh` rebuilds from scratch.
111
+ - [`/ghostwriter:delete`](delete.md) — hard-delete the profile.
112
+ - [`/ghostwriter:write`](write.md) — consume the rendered voice.
113
+ - [`ghostwriter-schema`](../../../docs/contracts/ghostwriter-schema.md) — field definitions used here.
@@ -0,0 +1,160 @@
1
+ ---
2
+ name: ghostwriter:write
3
+ tier: 2
4
+ cluster: ghostwriter
5
+ sub: write
6
+ description: Draft a markdown post in the voice of a captured public-figure ghostwriter profile; appends the mandatory non-removable disclosure footer.
7
+ disable-model-invocation: true
8
+ suggestion:
9
+ eligible: true
10
+ trigger_description: "draft post in style of public figure, write in someone's voice, ghostwriter draft, LinkedIn post in style of X"
11
+ trigger_context: "user wants to generate a copyable draft in a previously captured public-figure voice with the mandatory disclosure footer"
12
+ ---
13
+
14
+ # /ghostwriter:write
15
+
16
+ Generate a copyable markdown draft in the voice of a captured
17
+ ghostwriter profile under `agents/ghostwriter/<slug>.md`. Implements
18
+ the [`write-engine`](../../../docs/contracts/write-engine.md) contract
19
+ with **mandatory disclosure footer** appended by this command's output
20
+ template (not by the model, no opt-out).
21
+
22
+ > Writing in your **own** voice? Use [`/post-as:me`](../post-as/me.md)
23
+ > — reads `.agent-user.md`, no disclosure footer.
24
+
25
+ ## Steps
26
+
27
+ ### 1. Select the ghostwriter (style source)
28
+
29
+ Argument shapes:
30
+
31
+ - `/ghostwriter:write` → interactive numbered menu (see below).
32
+ - `/ghostwriter:write --as=<value> [...modifiers]` → non-interactive.
33
+ - `/ghostwriter:write <value> [...modifiers]` → positional shorthand.
34
+
35
+ `<value>` resolves against **slugs** and (when
36
+ `ghostwriter.aliases: true` in `.agent-project-settings.yml` — default
37
+ on) the `aliases:` list of every consumer profile. See
38
+ [`ghostwriter-schema § Aliases`](../../../docs/contracts/ghostwriter-schema.md#aliases).
39
+
40
+ Scan `agents/ghostwriter/*.md`, excluding `README.md` and any file
41
+ with `fictional: true` (fixtures are not consumable from this
42
+ command — they live in the package source as schema examples).
43
+
44
+ Resolution order for `--as=<value>` / positional `<value>`:
45
+
46
+ 1. **Slug match** — case-insensitive equality against filename stem.
47
+ 2. **Alias match** (skip when `ghostwriter.aliases: false`) —
48
+ case-insensitive equality against every profile's `aliases:` entry.
49
+ Conflicts are impossible at runtime — the consumer-side lint
50
+ rejects cross-profile alias collisions at commit time, so an alias
51
+ resolves to exactly one profile or zero.
52
+ 3. **No match** → abort with: *"No profile matches `<value>` (tried
53
+ slug + aliases). Run `/ghostwriter:list` to see available profiles."*
54
+
55
+ | State | Action |
56
+ |---|---|
57
+ | Zero non-fixture profiles | **Abort.** Print: *"No ghostwriter profiles exist. Run `/ghostwriter:fetch <url-or-name>` first."* |
58
+ | One or more profiles, interactive | Numbered menu: `1. <slug> — <identity.name> · <confidence> · <last_updated>` |
59
+ | `--as=<value>` / positional | Resolve via the order above; abort on no match |
60
+
61
+ User picks by number or value. No default — explicit choice required.
62
+
63
+ ### 2. Load the style source
64
+
65
+ Read the selected file's frontmatter. Required keys (per
66
+ [`ghostwriter-schema`](../../../docs/contracts/ghostwriter-schema.md)):
67
+ `identity.name`, `style.fingerprint.*`, `style.free_form_notes`,
68
+ `voice_samples`, `taboos`, `source_provenance.verification`.
69
+
70
+ `verification: user-asserted` → print a one-line warning before
71
+ proceeding: *"⚠️ Profile is user-asserted (not host-fetched).
72
+ Style fidelity may be lower."* Non-blocking.
73
+
74
+ ### 3. Collect topic + modifiers
75
+
76
+ Per [`write-engine § 2`](../../../docs/contracts/write-engine.md).
77
+ Flag form: `--tone=<formal|casual|neutral>`,
78
+ `--length=<words>`, `--channel=<linkedin-post|tweet|blog|freeform>`,
79
+ `--audience=<text>`. Missing flags → interactive prompt, **one
80
+ question per turn**, in the order Topic → Tone → Length → Channel →
81
+ Audience. Tone / length defaults derive from the per-channel table
82
+ and the vocab-register → tone mapping in the engine contract.
83
+
84
+ ### 4. Negative-constraint pass
85
+
86
+ Apply the loaded `taboos` list as exclusions before drafting (per
87
+ [`write-engine § 3`](../../../docs/contracts/write-engine.md)). Print
88
+ a one-line acknowledgement: *"Excluding N taboos from this profile."*
89
+
90
+ ### 5. Draft
91
+
92
+ Generate the body as a single fenced markdown block per
93
+ [`write-engine § 4`](../../../docs/contracts/write-engine.md). Honour
94
+ fingerprint constraints: sentence-length ±25 %, opener / closer
95
+ patterns, hashtag / emoji rules, ±15 % length tolerance.
96
+
97
+ ### 6. Append the disclosure footer (literal, deterministic)
98
+
99
+ After the body, emit a blank line, then the literal string (rendered
100
+ in the user's language; English template below):
101
+
102
+ ```
103
+ *Written in the style of <identity.name>, not by them.*
104
+ ```
105
+
106
+ This footer is appended **by this command's output template** as a
107
+ fixed string. It is not produced by the model. No `--no-disclosure`
108
+ flag, no `--internal` flag, no opt-out. The absence of any such flag
109
+ is the acceptance criterion (locked in
110
+ [`ghostwriter-schema`](../../../docs/contracts/ghostwriter-schema.md)
111
+ § Mandatory disclosure footer).
112
+
113
+ **The footer always uses `identity.name`, never the alias that
114
+ triggered the command.** Invoking `--as=Hawking` against a profile
115
+ with `identity.name: "Stephen Hawking"` produces *"Written in the
116
+ style of Stephen Hawking, not by them."* — never *"…of Hawking…"*.
117
+ Aliases are UX-only; identity attribution stays deterministic.
118
+
119
+ ### 7. Print
120
+
121
+ Print the complete block (body + blank line + footer) inside one
122
+ fenced markdown region. No file writes, no commit, no save. The user
123
+ copies the output manually.
124
+
125
+ ### 8. Stale-warning surface
126
+
127
+ If the selected profile's `source_provenance.last_fetched_at` is
128
+ > 90 days old, print one line **after** the fenced block:
129
+
130
+ ```
131
+ ⚠️ agents/ghostwriter/<slug>.md last fetched YYYY-MM-DD (>90 days). Run /ghostwriter:fetch <slug> --force-refresh.
132
+ ```
133
+
134
+ Non-blocking.
135
+
136
+ ## Rules
137
+
138
+ - **Do NOT commit, push, or open a PR.** The user owns the git surface.
139
+ - **Do NOT omit the disclosure footer.** It is mandatory on every
140
+ invocation. Any flag that would suppress it is forbidden by design
141
+ and rejected by the package skill linter (`scripts/lint_skills.py`).
142
+ - **Do NOT write the draft to disk.** This command prints only.
143
+ - **Do NOT blend multiple ghostwriter voices.** One style source per
144
+ invocation in v1.
145
+ - **Do NOT consume `personas/*.md` or `.agent-user.md`** — those are
146
+ separate primitives. Personas are review lenses; `.agent-user.md`
147
+ is `/post-as:me`.
148
+ - **Do NOT proceed without an explicit `--as=<slug>` or interactive
149
+ selection.** No default ghostwriter.
150
+ - **Do NOT bypass the negative-constraint pass** even when the user
151
+ asks for off-profile content. Surface the taboo and abort.
152
+
153
+ ## See also
154
+
155
+ - [`write-engine`](../../../docs/contracts/write-engine.md) — shared procedural contract.
156
+ - [`ghostwriter-schema`](../../../docs/contracts/ghostwriter-schema.md) — locked v1 frontmatter.
157
+ - [`/ghostwriter`](../ghostwriter.md) — parent cluster.
158
+ - [`/ghostwriter:fetch`](fetch.md) — the producer side.
159
+ - [`/post-as:ghostwriter`](../post-as/ghostwriter.md) — thin alias for this command.
160
+ - [`/post-as:me`](../post-as/me.md) — sibling consumer, user-self voice, no footer.