# Data-Path Convention How command, agent, skill, and hook-prompt prose should refer to **user data** vs **plugin-shipped assets** after the M0 migration. One token, resolved inline, so the prose Claude reads is directly actionable — no indirection, no stale in-plugin paths. ## The two roots | Root | Token in prose | Holds | Moves on migration? | |------|----------------|-------|---------------------| | **Data root** | `${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}` | the user's real data (voice profile, analytics, drafts, plans, …) | yes — auto-migrated out of the plugin on session-start | | **Plugin root** | `${CLAUDE_PLUGIN_ROOT}` | read-only ships (templates, checklists, references, fonts, framework scaffolds) | no — these stay in the plugin | The data root **mirrors** the state file (`~/.claude/linkedin-studio.local.md`). The default is overridable by the single env var `LINKEDIN_STUDIO_DATA`; the deprecated aliases `ANALYTICS_ROOT` / `STATE_FILE` / `PLUGIN_ROOT` are honored for one minor version. This generalizes the proven newsletter pattern `${LTL_SERIES_ROOT:-$HOME/linkedin-series}` (`commands/newsletter.md`) to all data. ## Data-root layout (mirrors brief §7.1) ``` ${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/ voice-samples/ authentic-voice-samples.md chronicle-voice-drift-log.md analytics/ exports/ posts/ weekly-reports/ monthly-reports/ ab-tests/ content-history.md drafts/ queue.json week-*/ carousel/ multiplatform/ repurposed/ profile/ user-profile.md frameworks/ .md audience-insights/ demographics.md engagement-patterns.md examples/ high-engagement-posts.md templates/ my-post-templates.md plans/ -plan-*.md ``` ## The prose rule 1. **A path to user data → the data-root token.** Write the full inline form `${LINKEDIN_STUDIO_DATA:-$HOME/.claude/linkedin-studio}/` — never a bare `assets//` and never `${CLAUDE_PLUGIN_ROOT}/assets//` for data. The inline `:-default` expansion means the prose is self-resolving; do **not** write "the data dir's ``" and force a lookup into this doc. 2. **A path to a plugin-shipped read-only asset → keep `${CLAUDE_PLUGIN_ROOT}`.** Templates (`config/*.template.*`), checklists, `references/`, fonts, and framework scaffolds ship with the plugin and stay there. 3. **Preserve existing graceful-degradation guards.** "if it exists", placeholder / sentinel checks, and `<5`-sample silent-skips stay as written — only the path token changes. ## Scaffold fallback (the COPY classes + the voice placeholder) Four data files ship a **seed/scaffold in-plugin** and a **canonical instance external**: `examples/high-engagement-posts.md`, `audience-insights/{demographics,engagement-patterns}.md`, `templates/my-post-templates.md`. The voice profile is similar — the plugin ships a placeholder at `assets/voice-samples/authentic-voice-samples.md`; the user's real profile lives external. **Readers prefer the external instance and fall back to the in-plugin seed when external is absent** (the code does this in `personalization-score.mjs`; prose keeps its "if it exists" guard). The external instance is canonical — migration never clobbers it. ## Why inline, not indirection (the Step-14 GATE finding) The prototype on the voice-readers family (19 files, 38 refs) measured the open question from brief D3: *can a convention reduce edits, or do commands need literal paths for Claude to act on?* Outcome: command prose that tells Claude to **read** a file needs a resolvable path on the line. A "the data dir's `voice-samples/` (see this doc)" reference adds a lookup hop and is not directly actionable. The inline `${LINKEDIN_STUDIO_DATA:-…}/…` token is both self-resolving **and** points here. So the convention does **not** cut the edit count below ~1 per reference — it makes every edit a **uniform, mechanical** token swap instead of a bespoke per-line decision, with this doc as the single source of truth. Step 15 applies the same uniform token to the remaining families (D3 realized as one token — not a re-decision).