Build or refresh a public-figure voice profile under agents/reference/ghostwriter/ from a URL or bare name; runs the public-figure attestation gate; delegates web-fetch/web-search to host.
Scanned 6/5/2026
Install via CLI
openskills install event4u-app/agent-config---
model_tier: inherit
name: ghostwriter:fetch
pack: gtm-marketing
tier: 2
cluster: ghostwriter
sub: fetch
description: Build or refresh a public-figure voice profile under agents/reference/ghostwriter/ from a URL or bare name; runs the public-figure attestation gate; delegates web-fetch/web-search to host.
suggestion:
eligible: true
trigger_description: "fetch public figure writing voice, capture LinkedIn / blog / Substack style, build ghostwriter profile from name, refresh stale profile"
trigger_context: "user wants to capture a documented public figure's writing voice from a URL or by name into agents/reference/ghostwriter/<slug>.md"
workspaces:
- agent-config-maintainer
packs:
- meta
---
# /ghostwriter:fetch
Build (or refresh) a ghostwriter profile at
`agents/reference/ghostwriter/<slug>.md` from one of two inputs:
| Input | Mode | Host-agent capability used |
|---|---|---|
| URL (LinkedIn / blog / Substack / personal site) | **URL mode** | web-fetch |
| Bare name (`"Alice Walker"`) | **Name-only mode** | web-search |
Zero network code in the package — the host agent performs the fetch /
search; this command is procedural only. Schema:
[`ghostwriter-schema`](../../../docs/contracts/ghostwriter-schema.md).
## Steps
### 1. Parse input + resolve slug
Argument shape: `/ghostwriter:fetch <input> [--force-refresh]`.
- Looks like a URL (`https?://`) → URL mode. Derive slug from the
page's primary author / persona name (kebab-case).
- Otherwise → name-only mode. Slug = full name kebab-case
(`alice-walker`). If a slug already exists with a different role,
ask the user for a discriminator suffix (`alice-walker-novelist`).
Existing `agents/reference/ghostwriter/<slug>.md`?
| State | Action |
|---|---|
| Missing | Proceed to fresh-fetch flow |
| Exists, no `--force-refresh` | Diff-and-accept flow (Step 6) |
| Exists, `--force-refresh` | Back up to `<slug>.md.bak`, rebuild from scratch |
### 2. Public-figure attestation gate (BLOCKING)
Print verbatim, one question per turn, **all four** required before any
write. Mirrors the deterministic gate in
[`ghostwriter-schema § public-figure gate`](../../../docs/contracts/ghostwriter-schema.md).
1. *"Is the target a documented public figure with a public-facing role
(author / executive / academic / politician / journalist /
public-speaker / public-artist / deceased-historical)? Which category?"*
2. *"Are all sources you intend to use public — not paywalled,
login-walled, leaked, or retracted?"*
3. *"Do you accept the right-of-publicity and defamation surface? The
package documents the gate but the legal call is yours."*
4. *"Do you understand the disclosure footer on every `/ghostwriter:write`
output is non-removable?"*
Any "no" / silence / decline → abort. Do not write the file.
Record the UTC ISO timestamp of the fourth "yes" into
`identity.attestation_recorded_at`.
### 3a. URL mode — host-agent fetch
Instruct the host agent: *"Fetch the URL `<input>` and any linked
author archive / post index. Return public posts (target: last 100;
floor: 3 distinct items). Exclude paywalled / login-walled / private
content."*
| Result | Action |
|---|---|
| Host has web-fetch + ≥ 3 distinct items returned | `source_provenance.verification: fetched`; proceed to Step 4 |
| Host has web-fetch but < 3 items | Abort; report the floor; suggest name-only mode for broader sources |
| Host cannot fetch | Emit paste-prompt (Step 3c) |
### 3b. Name-only mode — host-agent search
Instruct the host agent: *"Search authoritative public sources for
`<name>`: Wikipedia, official site, verified social, archived
interviews, published books (for deceased figures). Return ≥ 3
distinct authoritative items."*
| Result | Action |
|---|---|
| ≥ 3 distinct authoritative items | `verification: fetched`; proceed to Step 4 |
| < 3 items | Abort; report the floor; ask the user to supply URLs |
| Host cannot search | Emit paste-prompt (Step 3c) |
### 3c. Paste-prompt fallback
Print: *"Host agent cannot fetch / search. Paste ≥ 3 public-source
excerpts with their URLs; one excerpt per code block, max ~200 words
each. Type `done` when finished."*
Collected material → `source_provenance.verification: user-asserted`.
`/ghostwriter:show` will surface a `⚠️ user-asserted` warning on this
profile.
### 4. Derive frontmatter
From the gathered material, populate the locked frontmatter per
[`ghostwriter-schema § locked frontmatter (v1)`](../../../docs/contracts/ghostwriter-schema.md):
- `identity.*` — name, role, category (from Step 2), source URLs,
`fetched_at` (today, ISO date), `attestation_recorded_at` (Step 2).
- `style.fingerprint.*` — derive `sentence_length_avg`, `vocab_register`,
opener / closer patterns, hashtag / emoji rules, paragraph cadence
from the gathered excerpts.
- `style.free_form_notes` — short prose summary.
- `voice_samples` — pick up to 3 public excerpts, ≤ 200 words each,
source-attributed.
- `taboos` — what the figure demonstrably never does in public writing.
- `source_provenance.{count, last_fetched_at, types, verification}`.
- `confidence` — derived deterministically:
| Sources × types | Confidence |
|---|---|
| 3 sources, same platform | `low` |
| 3+ sources, 2+ platforms | `med` |
| 5+ sources, 3+ platforms, ≥ 1 canonical | `high` |
- `fictional: false` (always, for consumer-side files).
- `last_updated` — today, ISO date.
Body: a single `# Notes` section, empty for fresh fetches.
**Hard cap: 200 lines total.**
### 5. Propose + confirm (fresh-fetch path)
Print the proposed file content as a fenced markdown block. Ask:
> 1. write — save to `agents/reference/ghostwriter/<slug>.md`
> 2. edit — open in IDE first (per `file-editor` skill), save after
> 3. cancel — discard
Only on choice 1 or 2 (after save) write the file. Print the
post-write summary:
```
✅ agents/reference/ghostwriter/<slug>.md written.
confidence: <low|med|high> · sources: <n> · verification: <fetched|user-asserted>
```
### 6. Diff-and-accept (re-fetch path, no `--force-refresh`)
Re-run Steps 2–4 against the existing file. Show a **field-by-field
diff** (frontmatter keys + voice samples). Ask the user to accept
per-field changes (numbered options). Bump `last_updated` and
`source_provenance.last_fetched_at` on accept. Mirrors
[`/agents:user:accept`](../agents/user/accept.md).
### 7. Stale-warning surface (always)
After any write (or no-op accept), if any other profile under
`agents/reference/ghostwriter/*.md` has `source_provenance.last_fetched_at` >
90 days old, print one line per stale profile:
```
⚠️ ghostwriter/<other-slug>.md last fetched YYYY-MM-DD (>90 days). Run /ghostwriter:fetch <other-slug> --force-refresh.
```
Non-blocking.
## Rules
- **Do NOT commit, push, or open a PR.** The user owns the git surface.
- **Do NOT write the file before the attestation gate completes** with
four explicit "yes" answers.
- **Do NOT bypass the < 3 distinct sources floor** under any flag.
- **Do NOT introduce network code in the package** — the host agent
performs every fetch / search; this command only orchestrates.
- **Do NOT accept private / paywalled / leaked / retracted material**
even when the user pastes it (Step 3c).
## See also
- [`ghostwriter-schema`](../../../docs/contracts/ghostwriter-schema.md) — locked v1 frontmatter, verification levels, confidence derivation.
- [`/ghostwriter`](../ghostwriter.md) — parent cluster.
- [`/ghostwriter:write`](write.md) — consume side; appends the mandatory disclosure footer.
- [`/agents:user:accept`](../agents/user/accept.md) — the diff-and-accept flow this command mirrors on re-fetch.
No comments yet. Be the first to comment!