refactor(linkedin)!: rename plugin linkedin-thought-leadership → linkedin-studio (v3.0.0)

BREAKING CHANGE: the marketplace slug, the agent namespace
(linkedin-studio:<agent>), and the runtime state-file path
(~/.claude/linkedin-studio.local.md) all change. Reinstall required;
existing state migrated in place (post metrics, streak, history preserved).
The /linkedin:* commands are unchanged — the command namespace is set
per-command in frontmatter and was always independent of the plugin slug.
Functionality is byte-identical to v2.4.0; this release is pure identity.

- dir + manifests: plugins/linkedin-studio + plugin.json + root marketplace.json
- agent namespace updated in commands/newsletter.md (only functional invoker)
- state path updated in 4 hook scripts + topic-rotation prompt + state template
- catch-all skill dir renamed skills/linkedin-studio (5 functional skills unchanged)
- docs + version bump to 3.0.0 across README badge, CHANGELOG, root README/CLAUDE.md
- historical records (CHANGELOG past entries, docs/ build artifacts,
  config-audit v5.0.0 snapshots) intentionally retain the old slug

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-05-29 11:32:02 +02:00
commit b6bb61246b
196 changed files with 164 additions and 138 deletions

View file

@ -0,0 +1,30 @@
# LinkedIn Studio — Session State
**Last updated:** [Auto-filled by session-start hook]
## Last Session Summary
<!-- Brief recap of what was done last session -->
## Recent Posts
<!-- Posts created in recent sessions -->
<!-- Format: - [YYYY-MM-DD] "Hook text..." — topic -->
## Active Content Plan
<!-- Current week's plan and upcoming topics -->
## Pending Tasks
<!-- Actionable items for next session -->
- [ ] Posts to publish
- [ ] Analytics to import
- [ ] Engagement tasks (5x5x5)
## Current Strategy
<!-- Phase and focus area -->
**Phase:** [Foundation / Growth / Authority / Scale]
**Focus:** [Current strategic priority]
## Recommendations
<!-- Top 3 actionable suggestions from last session -->
## Notes
<!-- Free-form session notes -->

View file

@ -0,0 +1,18 @@
# Content History Log
Tracks all LinkedIn posts created through the plugin. Append-only — never edit existing entries.
Auto-initialized from `config/content-history.template.md` when the first post is logged.
## Format
| Date | Hook | Topic | Format | Words | Chars | Source |
|------|------|-------|--------|-------|-------|--------|
<!-- Entries are appended below by the Stop hook -->
<!-- Format: | YYYY-MM-DD | "Hook text (60 chars max)..." | topic_area | post/quick/react/video | word_count | char_count | original/url/curated | -->
## Content Log
| Date | Hook | Topic | Format | Words | Chars | Source |
|------|------|-------|--------|-------|-------|--------|

View file

@ -0,0 +1,28 @@
{
"_doc": {
"purpose": "Schema + starter for edition-config.json — the STATIC per-edition delivery metadata that render/build-linkedin.mjs reads (calendar, freshness, cover credit, captions). Complements edition-state.json (machine resumption state) and edition-delingstekst.md (distribution copy).",
"decision": "G — production lives in the series root, NOT in the plugin. Copy this template to <serie>/linkedin/edition-config.json and fill it in. This file is the schema-defining TEMPLATE only.",
"location": "<serie>/linkedin/edition-config.json (read relative to cwd = series root; OUT_ROOT = <cwd>/linkedin)",
"graceful": "render/build-linkedin.mjs loadEditionConfig() falls back to empty defaults if this file is missing or malformed — every field below is optional. Provide it for a complete delivery page (calendar slot, freshness banner, cover credit, alt-text caption).",
"keys": "Article keys are zero-padded strings mirroring edition-state.json + the NN-prefix of each NN-utkast.md draft: \"01\", \"02\", ..., plus \"samle\" for the collected post.",
"fields": {
"calendar[NN]": "{ dag: human date label e.g. \"Mandag 02.06\", klokke: \"HH:MM\" } — the scheduled slot shown on POST.html. Default if absent: { dag: \"—\", klokke: \"08:00\" }.",
"freshness[NN]": "string — a freshness/recency note rendered in the amber banner (e.g. \"Tall fra Q1 2026; sjekk før publisering etter 01.07\"). Omit for no banner.",
"coverCredit": "string — global cover-image credit line (\"Add credit and caption\" field). One value for the whole edition.",
"captions[NN]": "string — per-article cover-image caption / alt text. Default if absent: \"—\".",
"carousel": "list of zero-padded NN strings (e.g. [\"03\",\"06\"]) — the editions that ship an optional carousel/document post. POST.html shows a carousel block only for these NN. Empty/absent → no carousel block. (S14/F6: replaces the old hardcoded Seres set.)"
}
},
"calendar": {
"01": { "dag": "<Ukedag DD.MM>", "klokke": "08:00" },
"samle": { "dag": "<Ukedag DD.MM>", "klokke": "08:00" }
},
"freshness": {
"01": "<optional freshness note shown in the banner — omit the key for no banner>"
},
"coverCredit": "<cover-image credit line, or empty string>",
"captions": {
"01": "<cover-image caption / alt text for article 01>"
},
"carousel": []
}

View file

@ -0,0 +1,55 @@
<!--
TEMPLATE — edition-delingstekst.md (distribution copy for a newsletter edition)
Purpose : the per-edition LinkedIn distribution text that render/build-linkedin.mjs
folds into each POST.html "all-in-one-place" deliverable. This is the
feed copy the reader sees BEFORE "…see more" — the hook that earns the
click (gated in /linkedin:newsletter Step 9).
Decision: G — production lives in the series root, NOT the plugin. Copy this to
<serie>/linkedin/edition-delingstekst.md and fill it in.
Location: <serie>/linkedin/edition-delingstekst.md (cwd = series root).
Graceful: render/build-linkedin.mjs degrades if this file is missing (no
distribution copy is folded in; the article POST.html still builds).
Provide it for a complete delivery.
GRAMMAR (exactly what parseDelingstekst() recognizes — do not improvise):
- A section starts with a heading: "## Del N — <title>" (N = article number,
mapped to zero-padded key "0N") OR "## Samle <…>" (the collected post,
key "samle").
- "## SYSTEM …" headings are ignored.
- Inside a section, until the next "## " heading or a "---" line:
* "**Første kommentar:** <text>" → first-comment text (one line).
* a line beginning with "#" + non-space (e.g. "#KI #offentligsektor")
→ the hashtag line.
* a "> …" blockquote line → ignored (use it for NB/notes to yourself).
* every other line → part of the share text (the hook + body shown in feed).
Keys MUST match the NN-prefix of the draft (NN-utkast.md) and edition-config.json.
-->
## Del 1 — <edition title>
<First line = the krok/hook: the single line that must stop the scroll. Keep the
strongest claim or tension here; this is what shows before "…see more".>
<Then 24 short lines that pay off the hook and point at the article. Tighten,
never pad — this is feed copy, not the article.>
**Første kommentar:** <the first-comment text — e.g. a link, a question to seed
discussion, or the "full edition here" pointer. LinkedIn suppresses links in the
body, so the link belongs here.>
#hashtag1 #hashtag2 #hashtag3
> NB to self (ignored by the renderer): note any freshness caveat or A/B variant
> you want to remember for this edition.
---
## Samle <collected-post title, if shipping a roundup of the series>
<Hook for the collected/summary post. Same grammar. Omit this whole section if the
edition has no samle post.>
**Første kommentar:** <first comment for the samle post>
#hashtag1 #hashtag2

View file

@ -0,0 +1,65 @@
{
"_doc": {
"purpose": "Schema for edition-state.json — deterministic resumption state for a newsletter edition in production. Holds the current phase + per-article status so /linkedin:newsletter (Step 0) can resume exactly where a prior session stopped.",
"decision": "G — production state lives in the serie-mappe (e.g. /Users/ktg/repos/maskinrommet/serier/<slug>/linkedin/edition-state.json), NOT in the plugin. This file is the schema-defining TEMPLATE only; copy + fill it in the serie-mappe when producing an edition.",
"complements": "edition-config.json (static: calendar, freshness, captions) and <serie>/STATE.md (human-readable narrative state, overwritten each phase per the ONE-system continuity rule — there is no edition-HANDOVER.md). edition-state.json is the machine-readable companion: deterministic resumption + the durable fact-check log, immutable rules, and persona verdicts that the old HANDOVER §4/§5 used to carry.",
"lifecycle": "/linkedin:newsletter reads this in Step 0 and rewrites it at every phase transition. Article keys mirror edition-config.json (zero-padded strings: \"01\", \"02\", ..., or \"samle\").",
"phases": [
"load-context — read <serie>/STATE.md, voice profile, persona library, series brief (Step 0)",
"brief-calibration — angle, voice, audience personas, key points, leader-takeaway (Step 1)",
"research — parallel scoped mandates → verified notes, triangulation (Step 2)",
"skeleton-pitch — five-line skeleton (premise/problem/recommendation/payoff/forward) + section pitches, operator gate + persona-skjelett-sweep BEFORE prose (Step 2.5)",
"spine-prose — one paragraph per section against the gated skeleton, operator gate BEFORE full expansion (Step 3a)",
"draft — full prose expansion against the gated spine; may span sessions (Step 3b)",
"consistency-quality — threads, premise→conclusion arc, AI-slop removal, formatting dose (Step 4)",
"factcheck-sweep — risk-sorted, guilty-until-disproven, verification log (Step 5)",
"editorial-review — editor's craft gate: prose-craft (em-dash density, verbatim repetition, postulated numbers, contradictions, versal-tic) + narrative-architecture (concrete instantiation, theory-anchored hypotheses, series-title symmetry, equal action per addressee, un-overloaded conclusion), ≤10 flags BLOCK/REWORK/NICE, operator-gated via SendUserFile BEFORE the persona sweep (Step 5.5)",
"persona-sweep-prelock — reader jury, primary wins, convergence to clean YES (Step 6)",
"annotation — optional annotatable review HTML for a manual pass (Step 7)",
"visual-assets — cover (+ optional inline figures) or carousel deck: brief → generate → operator-gate → approve, BEFORE lock so build-linkedin.mjs picks them up (Step 7.5)",
"lock-delivery — LOCK → POST.html all-in-one-place deliverable (Step 8)",
"hook-conversion-gate — persona gate on distribution text post-lock: would YOU click? (Step 9)",
"scheduling — register edition in plugin queue/state for native LinkedIn scheduling (Step 10)"
],
"articleStatusValues": ["pending", "in-progress", "locked", "scheduled"],
"editorialReview": "Per-article editorial-review record written by Step 5.5 (editorial-review phase). Runs AFTER fact-check (Step 5) and BEFORE the persona sweep (Step 6): the editorial-reviewer agent judges CRAFT (prose-craft + narrative-architecture), not reader-response, mirroring the Maskinrommet skrivekontrakt §C2. The report (≤10 flags, each with kategori P1P5/A1A5, quote/line-ref, direction, severity BLOCK/REWORK/NICE) is surfaced to the operator via SendUserFile; the operator decides which flags fold in. Shape: { reportPath, flagCount, byAxis: { prosa, arkitektur }, bySeverity: { block, rework, nice }, foldedIn, waived, status }. status ladder: pending → reviewed → folded. null until Step 5.5 runs. This is the craft companion to factcheckLog (truth) and personaSweep (response).",
"visualAssets": "Per-article visual-asset record written by Step 7.5 (visual-assets phase). Runs BEFORE lock because render/build-linkedin.mjs picks up linkedin/NN/cover.png + the edition-config credit/caption when it builds POST.html — generating images after lock would force a re-render. Shape: { format: \"standard\" | \"carousel\"; cover: { brief, route, candidates[], approved, status }; figures: [ { id, brief, placement, status } ]; carousel: null | { source, pdf, status } }. format \"standard\" = cover + optional inline figures (cover.png is mandatory per the KTG cover-directive); format \"carousel\" = typografisk deck via render/build-carousel.mjs instead of cover+inline (cover/figures stay empty). route: \"mcp-image\" (default, via mcp__mcp-image__generate_image) | \"external\" (DALL·E / Midjourney / photographer → linkedin/NN/cover-raw.png). status ladder: pending → briefed → generated → approved. candidates[] holds the cover-v<N>-kandidat.png attempts; approved is the fixed approved name (\"cover.png\") once the operator-gate passes. figures[].id = \"fig1\"..; placement = section reference in NN-utkast.md (figures are referenced in the draft via ![alt](linkedin/NN/figN.png) and uploaded manually in the LinkedIn editor — build-linkedin.mjs does NOT embed them). Naming convention: cover.png (approved, fixed — what build-linkedin.mjs reads) | cover-v<N>-kandidat.png (attempts) | cover-raw.png (optional external pre-edit source) | fig<N>.png (inline). credit + caption are recorded in <serie>/linkedin/image-credit-caption.md and flow into edition-config.json coverCredit + captions[NN]."
},
"schemaVersion": 1,
"series": {
"slug": "<series-slug>",
"title": "<Series title>"
},
"currentArticle": "01",
"currentPhase": "load-context",
"updatedAt": "<ISO-8601 timestamp>",
"articles": {
"01": {
"title": "<Article 1 title>",
"phase": "load-context",
"status": "pending",
"immutableRules": null,
"factcheckLog": null,
"editorialReview": null,
"personaSweep": {
"skeleton": null,
"resonance": null,
"conversion": null
},
"visualAssets": {
"format": "standard",
"cover": {
"brief": null,
"route": null,
"candidates": [],
"approved": null,
"status": "pending"
},
"figures": [],
"carousel": null
},
"locked": false,
"scheduled": null
}
}
}

View file

@ -0,0 +1,63 @@
# Bilde-credit + caption — cover per edition
> **TEMPLATE.** Copy this to `<serie>/linkedin/image-credit-caption.md` and fill it
> in per series. `/linkedin:newsletter` Step 7.5 (visual-assets phase) reads it and
> updates the row for the edition in production; the values flow into
> `<serie>/linkedin/edition-config.json``coverCredit` + `captions[NN]`, which
> `render/build-linkedin.mjs` reads when it builds `POST.html` (Step 8). This file
> is the human-readable source of truth for *motif + credit + caption*; the JSON is
> the machine copy the renderer consumes.
LinkedIn-editoren har et **«Add credit and caption»**-felt under hvert bilde. Fyll
inn per cover. Caption = én kort linje som koder artikkelens signal (det leseren
skal sitte igjen med), ikke en bildebeskrivelse.
> Format i editoren: ofte ett felt. Lim «Caption — Credit» eller bruk feltene hver
> for seg om de finnes.
## Verifiseringsplikt — credit skal være ærlig
Er coveret **KI-generert** (Nano Banana Pro / Gemini / DALL·E / Midjourney) →
credit MÅ si det. Aldri la et AI-bilde framstå som foto eller egenprodusert
illustrasjon. Eksempel-credit for AI-cover:
**Felles credit (alle editions):** `Illustrasjon generert med <verktøy>` — f.eks.
`Illustrasjon generert med Google Gemini (Nano Banana Pro)`.
Er coveret et ekte foto eller en håndlaget figur → bytt til den ærlige creditten
(`Foto: <fotograf>`, `Egenprodusert figur`). Avvik fra felles-creditten føres under.
**Per-edition credit-avvik:** _(list any edition whose credit differs from the
felles-credit, with the reason — e.g. «Del 3: Egenprodusert figur (kodet SVG)».
None by default.)_
## Motiv + caption per edition
| Del | Cover (motiv) | Caption |
|-----|---------------|---------|
| 01 | _<one-line motif — what the cover depicts>_ | _<one-line caption — the article's signal>_ |
| 02 | __ | __ |
| samle | _<optional samle-post badge/motif>_ | _<optional>_ |
## Naming-konvensjon (cover-filer)
- `cover.png`**godkjent, fast navn**. Det eneste filnavnet `build-linkedin.mjs`
leser. Operator-gaten i Step 7.5 kopierer den godkjente kandidaten hit.
- `cover-v<N>-kandidat.png` — genererings-forsøk (mcp-image eller etterbehandlet).
Flere kan ligge side om side uten å overskrive den godkjente.
- `cover-raw.png` — valgfri ekstern pre-edit-kilde (DALL·E / Midjourney / fotograf).
- `fig<N>.png` — inline-figur (`fig1.png`, `fig2.png`, …), referert fra utkast-markdown
med `![alt](linkedin/NN/figN.png)` og **lastet opp manuelt** i editoren
(`build-linkedin.mjs` embedder ikke figurer).
## Carousel-utgaver
Carousel-editions (typografisk deck via `render/build-carousel.mjs`) har som regel
**ingen foto-cover** → ingen bilde-credit nødvendig. Slide-kilden er
`linkedin/NN/carousel.md`, rendret til `linkedin/NN/carousel.pdf`. En carousel-edition
som *også* legger en feed-cover trenger likevel en rad over.
## Samle-post
Ev. Maskinrommet-/serie-badge (egen asset) → ingen credit. Lenken til serien ligger i
første kommentar, ikke i bildet.

View file

@ -0,0 +1,134 @@
# Reader Persona Library
Reusable reader profiles for the long-form pipeline (`/linkedin:newsletter`).
A reader persona is **not** a target-audience demographic — it is a named
reader who reads a finished draft *read-only* and judges whether it **lands**
(not whether it is "correct"). Personas give direction; the editor holds the
pen. Personas never write text.
Copy this file to `personas.local.md` and adjust the active set per project:
```bash
cp config/personas.template.md config/personas.local.md
```
`personas.local.md` is gitignored (via `*.local.md`) so your active overrides
stay local. The template ships the three Seres seed personas below; clone,
trim, or extend them per series.
---
## How the library is used
- **Per-project selection.** `/linkedin:newsletter` (Step 1) picks the relevant
personas from this library and marks the primary in the edition brief.
- **«primær trumfer».** Exactly one persona is the **primær** reader. On
conflict between personas, the primær weighs highest. A *secondary* NO caused
by role mismatch or an expertise ceiling («this I already know cold») is a
SIGNAL that the gate works — accept it, do not distort the text to chase it.
A *primær* NO is **not** accepted: the text is revised until the primær
reaches a clean YES.
- **Two sweep modes** (same `persona-reviewer` agent): resonance mode (Step 6,
BEFORE lock — «does the point land for this reader?») and conversion mode
(Step 9, after lock — binary «would YOU click?» on the hook only).
### The click-gate is blocking (bar = primær ekte JA)
The persona sweep is not advisory — it returns a **blocking verdict**
(PASS / REWORK / BLOCK), and the bar is the **primær reader's genuine, unqualified
JA**. The three Seres seed personas are the canonical set: **A = IT-divisjonsdirektør**
(sekundær), **B = KI-seksjonsleder** (sekundær), **C = Linjeleder** (PRIMÆR — trumfer).
- **Bar = C ekte JA.** A clean, unqualified yes from the primær. **«JA med store
forbehold» = NEI.**
- ⛔ **Hard fail (= omskriv, ikke annotér):** the verdict is BLOCK, regardless of
the other axes, when the primær —
- «mistet meg» (disengaged before the takeaway), or
- does not own the action (the takeaway is someone else's job), or
- hits a **sjargong-mur** (a wall of technical vocabulary their `sjargong`
rejects), or
- hits a **modell-/navne-katalog** (product/model/benchmark names listed for
completeness).
- These are **rewrite triggers**, not annotations the editor can wave through. A
*sekundær* NO from a role/expertise ceiling stays a SIGNAL the gate works —
never distort the text to chase it.
Each persona documents five fields. Keep the lowercase field keys exactly — the
pipeline and the structural check key off them:
- **rolle** — who they are and what they own.
- **avkobler** — what disconnects them / makes them stop reading.
- **overbeviser** — what convinces them / earns their trust.
- **ekspertise** — expertise level, including any ceiling that makes basics fall flat.
- **sjargong** — jargon tolerance (which vocabulary lands, which repels).
---
## Seed personas (Seres series, public-sector AI adoption)
### Persona 1 — IT-divisjonsdirektør (sekundær)
- **rolle** — Leder IT-divisjonen i en stor offentlig virksomhet; eier drift,
sikkerhet, arkitektur og leverandørforhold med budsjett- og risikoansvar.
- **avkobler** — Hype uten driftskonsekvenser; «AI løser alt»; manglende kobling
til sikkerhet, forvaltningskrav og totalkostnad; abstrakt strategiprat uten et
klart hvem-eier-hva.
- **overbeviser** — Konkret arkitektur og driftsmodell, etterlevelse/sikkerhet,
realistisk totalkostnad, referanser fra sammenlignbar virksomhet, og en tydelig
ansvarsdeling.
- **ekspertise** — Høy teknisk og organisatorisk. Ekspertise-tak på grunnleggende
IT-forklaringer: en post som forklarer systemintegrasjon fra bunnen lander ikke
(sekundær-NEI her er et signal, ikke en svikt).
- **sjargong** — Høy toleranse for IT-/arkitektur-sjargong; lav for AI-buzzwords
og konsulentspråk.
### Persona 2 — KI-seksjonsleder (sekundær)
- **rolle** — Leder en KI-seksjon; bygger AI-kapabilitet, rådgir ledelsen og
balanserer eksperimentering mot forvaltningskrav.
- **avkobler** — Overforenkling av hva AI er; ignorering av governance, EU AI Act
og personvern; «bare kjør i gang»-holdning; manglende erkjennelse av at
dømmekraften ikke kan settes ut.
- **overbeviser** — Nyansert forståelse av hva AI kan og ikke kan, konkret kobling
til forvaltningsverdier, erfaringsbasert framfor teoretisk, og ærlighet om
begrensninger.
- **ekspertise** — Høy i AI-domenet. Ekspertise-tak: kjenner modellene og
teknikkene, så en «hva er en LLM»-post faller flatt. Verdien ligger i syntese
og dømmekraft, ikke grunnkurs.
- **sjargong** — Høy toleranse for AI-/ML-sjargong; lav for vagt lederspråk og
overdreven popularisering.
### Persona 3 — Linjeleder (primær)
> **Dette er primær-personaen.** Ved konflikt mellom personaer vekter denne
> høyest. En primær-NEI godtas ikke — teksten revideres til ren primær-JA.
- **rolle** — Mellomleder med fag- og personalansvar i offentlig virksomhet; skal
beslutte om og hvordan AI tas i bruk i egen enhet, uten dyp teknisk bakgrunn.
- **avkobler** — Teknisk dypdykk uten «hva betyr dette for meg og mine»;
frykt-retorikk; abstrakt policy; språk som forutsetter at hen kan koden.
- **overbeviser** — Konkrete eksempler fra arbeidshverdagen, et klart ansvars- og
dømmekraftsbilde, trygghet på at hen kan ta gode beslutninger uten å være
tekniker, og en leder-takeaway hen kan handle på allerede i morgen.
- **ekspertise** — Lav-til-middels teknisk; høy på ledelse og forvaltning. Trenger
oversettelse, ikke nedlatenhet.
- **sjargong** — Lav toleranse for teknisk sjargong; setter pris på presise,
hverdagsnære formuleringer.
---
## Adding a persona
Copy the block below into `personas.local.md` and fill every field. Mark at most
one persona as `primær` per project; if you add a new primary, demote the old one
to sekundær.
```markdown
### Persona N — [Title] ([primær | sekundær])
- **rolle** — [Who they are and what they own.]
- **avkobler** — [What makes them stop reading.]
- **overbeviser** — [What earns their trust.]
- **ekspertise** — [Expertise level + any ceiling that makes basics fall flat.]
- **sjargong** — [Which vocabulary lands, which repels.]
```

View file

@ -0,0 +1,61 @@
---
# LinkedIn Studio State
# Auto-managed by the linkedin-studio plugin
# Copy to ~/.claude/linkedin-studio.local.md
# Posting metrics
last_post_date: null
first_post_date: null # YYYY-MM-DD, set once on first post, never changed
last_post_topic: "" # Should match an expertise_areas value for pillar tracking
posts_this_week: 0
weekly_goal: 3
current_streak: 0
longest_streak: 0
# Week tracking (ISO week)
current_week: ""
# Analytics tracking
last_import_date: null
last_import_week: ""
# Milestone tracking
follower_count: 0
follower_target: 10000
target_date: "2026-12-31"
monthly_growth: []
projected_10k_date: ""
growth_rate_needed: 0
# Planning
next_planned_topic: ""
pending_5x5x5: false
content_series_active: ""
# Profile
expertise_areas:
- "general"
- ""
- ""
- ""
- ""
---
# LinkedIn Session State
## Recent Posts
<!-- Updated automatically by Stop hook -->
<!-- Format: [YYYY-MM-DD] "Hook text..." (chars) - topic_area -->
## Session Notes
<!-- Free-form notes from sessions -->
## Planned Content
<!-- Upcoming posts and topics -->
## Milestone Log
<!-- Updated when follower_count changes. Format: [YYYY-MM] count (+delta) -->

View file

@ -0,0 +1,126 @@
# User Profile Configuration
Copy this file to `user-profile.local.md` and customize for your needs.
```bash
cp config/user-profile.template.md config/user-profile.local.md
```
---
## PERSONALIZATION SETTINGS
### User Profile Context
**Name:** [Your Name]
**Current Role:** [Your Role] (posting as private individual, not representing employer)
**Organization:** [Not disclosed / Your Company]
**Industry/Domain:** [Your Industry]
**Important Disclaimer:** All articles and posts are written as a private individual. Views expressed are personal and do not represent any employer.
**Core Expertise Areas (5 topics):**
1. [Topic 1]
2. [Topic 2]
3. [Topic 3]
4. [Topic 4]
5. [Topic 5]
**Target Audience:**
- **Primary:** [Who are you primarily writing for?]
- **Secondary:** [Secondary audience]
- **Geographic focus:** [Region/Country]
**LinkedIn Goals (ranked by priority):**
1. [ ] Build thought leadership & authority
2. [ ] Attract speaking opportunities
3. [ ] Network with peers/influencers
4. [ ] Generate qualified leads
5. [ ] Monetization (consulting/courses)
6. [ ] Recruit talent
---
### Voice & Style Profile
**Tone Preferences (select what applies):**
- [ ] Professional & authoritative
- [ ] Conversational & approachable
- [ ] Storytelling-focused
- [ ] Data-driven & analytical
- [ ] Empathetic & supportive
- [ ] Provocative & contrarian
**Content Style Mix:**
- Story-based posts
- Framework/how-to posts
- Data/research posts
- Opinion/commentary posts
- Case study posts
- Personal reflection posts
**Signature Elements:**
- **Key frameworks you've developed:** [Your frameworks, or "None yet"]
- **Recurring themes/angles:** [Your themes]
- **Phrases you commonly use:** [Your phrases]
- **Topics to AVOID:** [Topics you never discuss]
**Writing Quirks & Preferences:**
- **Preferred post length:** [Short 150-500 / Medium 1,200-1,800 / Long 2,000+]
- **Emoji usage:** [None / Minimal 1-2 / Moderate 3-5]
- **Question style CTAs:** [Always / Sometimes / Never]
- **Use of personal anecdotes:** [Always / Sometimes / Rarely]
- **Technical depth:** [Beginner / Intermediate / Advanced / Adaptive]
---
### Voice Profile Summary
**[Your Name] writes with:**
1. **[Quality 1]:** [Description]
2. **[Quality 2]:** [Description]
3. **[Quality 3]:** [Description]
4. **[Quality 4]:** [Description]
5. **[Quality 5]:** [Description]
**DO:**
- [What you always do in your writing]
- [Another thing you do]
**DON'T:**
- [What you never do]
- [Another thing to avoid]
**Universal anti-patterns (keep these — they hold for every author):**
- **Modell-/navne-katalog.** Do not reel off product names, model names, or
benchmarks for completeness. Pick ONE concrete, verifiable (preferably local)
case over a list — a name-dump is a jargon wall to a non-technical reader.
- **Fullstendighet over leser-handling.** Serve what the primary reader can DO
from their chair, not everything the author knows. Completeness is not a virtue.
- **Selvrefererende overhead-åpning.** No meta-commentary about what the text will
or will not do, no warm-ups. Start on the reader's problem.
- **«ikke bare X, men Y», reflex rule-of-three, tacked-on summaries, hedging.**
**Language:** [English / Norwegian / Other]
---
### Strategic Context
**Current LinkedIn Status:**
- **Follower count:** [Your current count]
- **90-day growth goal:** [Your goal]
- **Posting frequency:** [Daily / 3x week / 2x week]
- **Optimal posting times:** [Your best times, or "To be determined"]
---
### Asset Utilization Preferences
**When creating content, Claude should:**
- [ ] Check `/assets/examples/` for past post patterns
- [ ] Reference frameworks from `/assets/frameworks/`
- [ ] Pull case studies from `/assets/case-studies/`
- [ ] Incorporate voice samples from `/assets/voice-samples/`
- [ ] Use research/data from `/assets/research/`