← back to Linkedin Voice Agent
SKILL.md
87 lines
---
name: linkedin-voice-agent
description: 'Persona-voice LinkedIn content engine — the local, build-it-don''t-buy-it answer to Okara''s "LinkedIn Agent v2". Analyzes your OWN past LinkedIn posts to learn your core themes/topics + voice, style, and tone into a reusable profile, then writes new LinkedIn post drafts in that voice — daily or on demand, about your themes, a topic, or a news item — scoring each draft''s hook strength so the strongest float to the top. Runs on LOCAL Ollama by default (zero cost). DRAFT-ONLY — never auto-posts; publishing an approved draft is handed to the linkedin-api skill and stays Steve-gated. Use when Steve says "linkedin voice agent", "/linkedin-voice-agent", "write LinkedIn posts in my voice", "learn my LinkedIn voice", "daily LinkedIn posts like Okara", "build a LinkedIn voice profile", "draft LinkedIn posts about X", or wants Okara-style LinkedIn ghostwriting run locally instead of paying for it.'
---
# linkedin-voice-agent
Local clone of the capability Okara (@askOkara) sells as **LinkedIn Agent v2**:
*"analyzes your past posts to learn your themes + voice/style/tone, then writes
new LinkedIn posts for you every day."* Steve's directive was **"Do not buy.
Build."** — so this runs entirely on local Ollama at **$0**, with no okara.ai
subscription and no data leaving the Mac.
Sibling to the `kartiseira` skill (same draft-only + voice-profile-JSON + local-
Ollama architecture, but for **X/Twitter**). This one is **LinkedIn-native**:
long-form professional register, and it hands publishing to the real
`linkedin-api` skill.
## Hard rail — DRAFT ONLY
This skill NEVER posts to LinkedIn. Automated third-party posting violates
LinkedIn's TOS, and outward publishing is a Steve-gated action regardless. It
writes drafts to a local review queue. To publish an approved draft, hand its
text to the **`linkedin-api`** skill (`scripts/post.py`) — Steve's go.
## When to use
- "linkedin voice agent" / "/linkedin-voice-agent"
- "learn my LinkedIn voice" / "build a LinkedIn voice profile"
- "write LinkedIn posts in my voice" / "daily LinkedIn posts like Okara"
- "draft LinkedIn posts about <topic>" / "react to <news> on LinkedIn in my voice"
Do NOT use for: actually posting (draft-only → `linkedin-api`), X/Twitter content
(use `kartiseira`), Instagram/TikTok (use the DW marketing agents), or DW commerce
copy (use `dw-marketing-copy`).
## Workflow — two stages
### Stage 1 — Learn the voice (once per person)
Build a reusable JSON voice profile from real past posts.
**Getting your past posts (the honest, TOS-clean, $0 path):** LinkedIn has no
free API to read your own feed, so use LinkedIn's official **Download your data**
export: linkedin.com → Settings → *Data privacy* → **Get a copy of your data** →
tick **Posts** → wait for the email → unzip → `Shares.csv`.
```bash
python3 scripts/build_profile.py --export ~/Downloads/Shares.csv --name steve
# or paste-in fallback: a .txt with posts split by a blank line or a --- line
python3 scripts/build_profile.py --posts ~/Desktop/my_posts.txt --name steve
```
Writes `data/profiles/<name>.json` with: measured style **stats** (computed
deterministically — length, line count, emoji/hashtag/question rates), plus
Ollama-synthesised `core_themes`, `voice_summary`, `signature_moves`, `avoid`,
and `sample_hooks`. Skim `voice_summary` and `signature_moves` — hand-refining
them a little gives the sharpest generations. Falls back to a stats-only profile
if Ollama is unreachable (records which in `_voice_source`).
### Stage 2 — Generate drafts (daily or on demand)
```bash
python3 scripts/generate.py --profile steve --count 3 # about their own themes
python3 scripts/generate.py --profile steve --topic "AI in interior design"
python3 scripts/generate.py --profile steve --news "<headline or paragraph to react to>"
```
Generates N distinct posts in the captured voice, scores each draft's **hook
strength 0-100** (deterministic first-line heuristic — free, reproducible),
sorts strongest-first, and writes:
- `data/drafts/<name>-<stamp>.md` — human review (hook score + angle + full text)
- `data/drafts/<name>-<stamp>.jsonl` — machine-readable
Review the `.md`, pick a winner, and publish via `linkedin-api` (Steve-gated).
## Daily automation (the "every day" part) — Steve-gated
Okara posts daily; the equivalent here is a launchd job that runs Stage 2 each
morning and drops fresh drafts in the queue (still draft-only — a human still
approves + publishes). Installing a scheduled job is a gated action, so the
plist + install command are staged in `references/daily-cadence.md` for Steve to
run, not auto-installed.
## Config
- `LVA_MODEL` (default `qwen3:14b`), `OLLAMA_URL` (default `http://localhost:11434`).
- Fallbacks: qwen3 → hermes3 → gemma3 → qwen2.5 → llama3. All local, $0.
## Cost
Profile build + generation are **$0 (local Ollama)**. The only paid/gated step is
publishing, which this skill never does — that's `linkedin-api` on Steve's go.