openwriter 0.35.0 → 0.35.2

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 (31) hide show
  1. package/dist/plugins/authors-voice/package.json +24 -23
  2. package/dist/plugins/authors-voice/skill/LICENSE +21 -0
  3. package/dist/plugins/authors-voice/skill/README.md +126 -0
  4. package/dist/plugins/authors-voice/skill/SKILL.md +151 -0
  5. package/dist/plugins/authors-voice/skill/catalog/ai-tells.md +144 -0
  6. package/dist/plugins/authors-voice/skill/catalog/anchor-prompt.md +189 -0
  7. package/dist/plugins/authors-voice/skill/catalog/author-hints.md +119 -0
  8. package/dist/plugins/authors-voice/skill/catalog/fingerprints.md +175 -0
  9. package/dist/plugins/authors-voice/skill/catalog/hurdle.md +76 -0
  10. package/dist/plugins/authors-voice/skill/catalog/post-write-audit.md +105 -0
  11. package/dist/plugins/authors-voice/skill/docs/analysis.md +31 -0
  12. package/dist/plugins/authors-voice/skill/docs/anchor-iteration.md +176 -0
  13. package/dist/plugins/authors-voice/skill/docs/api/import.md +78 -0
  14. package/dist/plugins/authors-voice/skill/docs/api/protocol.md +140 -0
  15. package/dist/plugins/authors-voice/skill/docs/api/setup.md +37 -0
  16. package/dist/plugins/authors-voice/skill/docs/api/tools.md +102 -0
  17. package/dist/plugins/authors-voice/skill/docs/api/troubleshooting.md +7 -0
  18. package/dist/plugins/authors-voice/skill/docs/apply-protocol-deep.md +191 -0
  19. package/dist/plugins/authors-voice/skill/docs/context-hygiene.md +33 -0
  20. package/dist/plugins/authors-voice/skill/docs/setup.md +74 -0
  21. package/dist/plugins/authors-voice/skill/docs/tiers.md +13 -0
  22. package/dist/plugins/authors-voice/skill/package.json +35 -0
  23. package/dist/plugins/authors-voice/skill/prompts/skeleton.md +29 -0
  24. package/dist/plugins/authors-voice/skill/voice/README.md +51 -0
  25. package/dist/plugins/authors-voice/skill/voice/corpus/.gitkeep +0 -0
  26. package/dist/plugins/github/dist/blog-tools.js +2 -2
  27. package/package.json +1 -1
  28. package/skill/SKILL.md +18 -6
  29. package/skill/agents/openwriter-enrichment-minion.md +4 -4
  30. package/skill/agents/openwriter-sort-minion.md +5 -5
  31. package/skill/docs/enrichment.md +3 -3
@@ -0,0 +1,102 @@
1
+ # API Reference
2
+
3
+ ## REST Endpoints (recommended)
4
+
5
+ All endpoints require `Authorization: Bearer $AV_API_KEY`. Base URL: `https://api.authors-voice.com`
6
+
7
+ ### Core Skill Endpoints
8
+
9
+ **Get voice profile** — full linguistic fingerprint (6 categories + sentence distribution):
10
+ ```bash
11
+ curl -s https://api.authors-voice.com/api/voice/profiles/default \
12
+ -H "Authorization: Bearer $AV_API_KEY"
13
+ # Optional: ?format=detailed for profile ID + summary
14
+ ```
15
+
16
+ **Apply voice** — rewrite content in the author's voice:
17
+ ```bash
18
+ curl -s -X POST https://api.authors-voice.com/api/voice/apply \
19
+ -H "Authorization: Bearer $AV_API_KEY" \
20
+ -H "Content-Type: application/json" \
21
+ -d '{"content": "text to rewrite", "mode": "rewrite", "inputType": "ai", "category": "x"}'
22
+ ```
23
+
24
+ ### Additional REST Endpoints
25
+
26
+ | Endpoint | Method | Purpose |
27
+ |----------|--------|---------|
28
+ | `/api/voice/profiles` | GET | List profiles with counts |
29
+ | `/api/voice/profiles/:profileId` | GET | Full voice profile (use `default` for default) |
30
+ | `/api/voice/apply` | POST | Rewrite content in author's voice |
31
+ | `/api/voice/setup` | POST | Analyze samples and build voice profile |
32
+ | `/api/voice/content` | GET | List writing samples (query: profileId, category) |
33
+ | `/api/voice/content` | POST | Upload content chunks |
34
+ | `/api/voice/content/bulk` | POST | Bulk upload documents |
35
+ | `/api/voice/content/:docId` | PATCH | Update doc metadata |
36
+ | `/api/voice/content/:docId` | DELETE | Delete document |
37
+ | `/api/voice/anchor/derive` | POST | Derive a voice anchor from pasted prose |
38
+ | `/api/voice/anchor` | GET/PUT/DELETE | Read / persist / clear the voice anchor |
39
+ | `/api/voice/usage` | GET | Usage stats |
40
+
41
+ ---
42
+
43
+ ## MCP Protocol (alternative)
44
+
45
+ For MCP-compatible clients, all tools are also available via JSON-RPC POST:
46
+
47
+ ```bash
48
+ curl -s -X POST "https://api.authors-voice.com/api/voice/mcp" \
49
+ -H "Authorization: Bearer $AV_API_KEY" \
50
+ -H "Content-Type: application/json" \
51
+ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"TOOL_NAME","arguments":{...}}}'
52
+ ```
53
+
54
+ ---
55
+
56
+ ## Available Tools (12)
57
+
58
+ ### Content Import (3 tools)
59
+
60
+ | Tool | Description |
61
+ |------|-------------|
62
+ | `import_from_url` | Import from any public URL (Medium, Substack, WordPress, .md/.txt). Args: `url`, `categories[]`, `authenticity`. |
63
+ | `bulk_import` | Import multiple docs (max 50). Each item: `{url}` or `{content, docId}` + `categories[]`. Global `authenticity`. |
64
+ | `upload_content` | Upload raw markdown. **One-click ergonomics**: `profileId` is optional — omit it and the server auto-creates/resolves a default profile. `content` can be raw text (server chunks on blank lines) instead of pre-split `chunks[]`, so the minimal payload is `{docId, content}`. Re-uploading the same `docId` replaces (idempotent). This is the contract the OpenWriter filetree right-click ingestion posts against. |
65
+
66
+ ### Voice Profiles (3 tools)
67
+
68
+ | Tool | Description |
69
+ |------|-------------|
70
+ | `list_profiles` | List voice profiles, categories, and document counts. Each profile also carries `hasAnchor` (bool) and `anchorAuthors` (the reference authors behind the anchor), so callers can tell which profiles carry an anchor without a per-profile GET. No args. |
71
+ | `get_voice_profile` | Get full voice guidelines — 6 linguistic categories + sentence stats. Use before writing to understand the author's patterns. Optional `profileId`. |
72
+ | `setup_voice` | Analyze samples → create/update voice profile. Args: `profileName`, optional `forceReanalyze`. Call after importing content. |
73
+
74
+ ### Voice Anchor (1 tool)
75
+
76
+ | Tool | Description |
77
+ |------|-------------|
78
+ | `set_voice_anchor` | Derive and persist a voice anchor from pasted reference prose. The anchor is V1's lead voice signal — injected ahead of sample retrieval in `rewrite`/`generate` and the OpenWriter editor path. REST equivalents: `POST /api/voice/anchor/derive`, `GET/PUT/DELETE /api/voice/anchor`. |
79
+
80
+ ### Voice Application (2 tools)
81
+
82
+ | Tool | Description |
83
+ |------|-------------|
84
+ | `rewrite` | Rewrite existing content in the author's voice. Modes: `rewrite`, `shrink`, `expand`, `custom`. Supports `contextBefore`/`contextAfter`, `inputType`, `category`. |
85
+ | `generate` | Generate NEW content in author's voice. Args: `instruction`, optional `query` (topic for retrieval), `contextBefore`/`contextAfter`, `category`, `targetWords`. |
86
+
87
+ **rewrite parameters**: `content`, `mode`, `contextBefore`, `contextAfter`, `category`, `inputType` (human/ai/ai-assisted), `targetWords` (max 2000), `format` (markdown/plaintext).
88
+
89
+ **inputType** controls how aggressively the rewrite treats the input:
90
+ - `human` — Author's own writing. Preserve word choices and quirks, only polish flow/grammar.
91
+ - `ai` — Generic AI content. Discard phrasing entirely, rewrite from scratch using voice samples.
92
+ - `ai-assisted` (default) — Mixed authorship. Preserve passages matching the author's voice, rewrite generic/formulaic parts.
93
+
94
+ **generate note**: `query` is optional — describes what content is ABOUT for better voice retrieval. When omitted, context + instruction are used for retrieval.
95
+
96
+ ### Content Management (3 tools)
97
+
98
+ | Tool | Description |
99
+ |------|-------------|
100
+ | `list_content` | List writing samples with chunk counts. Optional `category` filter. |
101
+ | `update_content` | Retag a doc. Args: `docId`, `categories[]`, `authenticity`. |
102
+ | `delete_content` | Permanently delete a doc and its chunks. Args: `docId`. |
@@ -0,0 +1,7 @@
1
+ # Troubleshooting
2
+
3
+ **"Unauthorized"** — Check `AV_API_KEY` is set and starts with `av_live_`.
4
+
5
+ **"profileId query parameter is required"** — Some REST endpoints need profileId. For MCP tools, omit profileId to use the default profile.
6
+
7
+ **Empty document list** — Connection is active but no documents match. Try without a query filter.
@@ -0,0 +1,191 @@
1
+ # Apply Protocol — Deep Reference
2
+
3
+ Loaded when scoping a brief (Apply step 4) or running cross-section coherence review (Apply step 8). Not in context for routing or other turns.
4
+
5
+ ## Step 4 — Writing the TASK brief
6
+
7
+ Promoted to `SKILL.md` Apply Protocol step 4. The load-bearing rules (commitments-only default, never meta-references, COMMITMENTS as quasi-verbatim, read-prior-integrated-sections, preservation scope, cadence prescription) live there. This doc holds the edge-case templates and minion taxonomy below.
8
+
9
+ ## Writing minion taxonomy
10
+
11
+ | Minion | Scope | Input | Output | When fires |
12
+ |---|---|---|---|---|
13
+ | **Apply** | Generative writing | Commitments + voice + context SUMMARIES (no source prose) | Fresh prose | Initial drafts. Also small reframes when audit prescribes a structural fix (audit's prescription becomes the commitment). |
14
+ | **Rewrite** | Generative writing against updated commitments WITH context awareness | Updated commitments + voice + context layers (summary of preceding + key-term glossary + adjacent seam paragraphs as orientation-only) + cadence prescription. NO source prose for content being written. | Fresh prose | Beat Map commitments changed; surrounding prose is acceptable and should be preserved. Apply brief + context awareness layers. |
15
+
16
+ Plus **Blinder Audit** (Step 8b — paragraph-level substance duplication, critic only) and **Anchor Iteration** (Step 10 — final polish, channels voice anchors as panel, iterates to 90/100; see `anchor-iteration.md`).
17
+
18
+ ### Editor's classification job after Audit fires
19
+
20
+ Each finding routes to one of three paths:
21
+ - **Editor direct (no minion)** — cuts, swaps, reorders, sentence-level surgical patches. Per FIRM RULE 1 carve-out.
22
+ - **Rewrite Minion** — paragraph's SUBSTANCE needs to change (structurally redundant with another, or mission needs to shift). Compression alone produces thin output.
23
+ - **Apply Minion (small)** — audit prescribes a specific reframe of a small span and new prose is needed (e.g., "reframe opening sentence to acknowledge pivot from X to Y"). Audit's prescription becomes the commitment.
24
+
25
+ Classification rule: **before flagging anything for a minion, ask "is this a SHAPE problem or a SUBSTANCE problem?"** Different work needed → Rewrite or Cut. New prose into a small span → small Apply. Surgical word/sentence work on existing prose → editor direct.
26
+
27
+ ## Rewrite Minion
28
+
29
+ The Rewrite Minion IS the Apply Minion fired with context awareness. The brief shape preserves Apply's no-source-prose-ceiling property (minion brings its own moves) while adding context layers needed to flow into surrounding prose.
30
+
31
+ ### Validated brief shape
32
+
33
+ ```
34
+ [Voice profile: anchor, NEVER rules, fingerprints, stats, coined terms, examples]
35
+
36
+ ---
37
+
38
+ TASK:
39
+
40
+ PROJECT: [1-paragraph context — what the doc is, what the section does]
41
+
42
+ CONTEXT — what's already established in the surrounding prose:
43
+ - [Summary of preceding section as bullets — what was named, what was claimed, what threads are live. NOT raw prose. 5-10 bullets.]
44
+
45
+ KEY TERMS already named (available for callback if useful):
46
+ [Glossary list — coined terms, named concepts, distinctive phrasings the prose has established]
47
+
48
+ IMMEDIATELY PRECEDING PARAGRAPH (for seam continuity ONLY; do NOT mirror its cadence):
49
+ [Full paragraph verbatim — 1 only]
50
+
51
+ IMMEDIATELY FOLLOWING PARAGRAPH (for seam continuity ONLY; do NOT mirror its cadence):
52
+ [Full paragraph verbatim — 1 only]
53
+
54
+ COMMITMENT(S) — what your new content must land in the reader:
55
+ [Outcome statement(s) per beat]
56
+
57
+ CADENCE PRESCRIPTION (per paragraph):
58
+ [Explicit rhythm direction — open with X, build with Y, close with Z. Mandatory.]
59
+
60
+ LENGTH: [target word count]
61
+
62
+ Return prose only. No commentary. No headers. No beat labels.
63
+ ```
64
+
65
+ The two seam paragraphs are full prose (minion needs flow continuity at the join), flagged explicitly as orientation-only. This avoids the source-prose ceiling because the task is "write fresh content that flows from / into these" rather than "match this cadence." **Framing matters more than presence.**
66
+
67
+ ### Why these elements
68
+
69
+ - FULL adjacent seam paragraphs flagged "orientation only — do NOT mirror cadence" — flow continuity without ceiling
70
+ - SUMMARIES of preceding section (bullets, not raw prose) + key-term glossary — document-scale awareness
71
+ - OMITTING source prose for content being written — preserves no-ceiling property
72
+ - INCLUDING explicit cadence prescription per paragraph — mandatory; short calls need cadence MORE, not less
73
+
74
+ ### Scope
75
+
76
+ Works at any scope: paragraph-level (1 new paragraph), section-level (3-5 paragraphs), beat-level (full beat regeneration). Pick by what changed in commitments — one beat's outcome → regenerate one paragraph; chapter-arc beat's whole outcome shape → regenerate the whole beat; multiple beats → batch per chapter-arc beat.
77
+
78
+ ### Preserving specific lines from existing prose
79
+
80
+ List them as MUST-APPEAR-VERBATIM in commitments (Apply's "selective lifts" mode). Rare — usually the writer's training data brings stronger lines than the existing prose anyway.
81
+
82
+ ### Audit follow-up MANDATORY
83
+
84
+ Rewrite outputs are subject to the same minion-blinder problem as first-pass Apply. The minion only sees its slice — seam paragraphs + summary bullets, not every paragraph in adjacent sections. It can introduce repetitions with paragraphs it didn't see.
85
+
86
+ **After any Rewrite Minion call, fire the Audit Minion (Step 8b) on the integrated document.** No exceptions. Empirical case: first Rewrite test (B1 close + B2 opening) produced strong individual prose AND 8 audit findings — most notably a visual-roster repetition across 4 paragraphs the rewriter never saw.
87
+
88
+ ### Don't conflate rewrites with violation patches
89
+
90
+ Violation patches (FIRM RULE 1 carve-out) are 1-3 sentence local fixes to NEVER violations or brief errors WITHIN otherwise-acceptable prose. Editor work, small scope, surgical. Rewrites here mean re-running the minion against UPDATED commitments — different scenario, different scope decision.
91
+
92
+ ## Step 8 — Cross-section coherence review
93
+
94
+ After integrating multiple minion outputs, scan for what individual runs cannot see:
95
+
96
+ - **Cadence repetition** across sections (same opens, same closes, same paragraph counts)
97
+ - **Recurring metaphors / phrases** across sections
98
+ - **Structural sameness** (every section ends with 4-layer enumeration, every section opens with 3 shorts)
99
+ - **Coined term overuse** — coined terms get injected into every minion call as MUST-PRESERVE, producing document-scale repetition (e.g., "territory" every 3 paragraphs). Track heavy-use terms; for subsequent minions, omit heavy-use terms from coined-terms injection OR add "use sparingly" instruction
100
+
101
+ Fix options: re-spawn with varied prescription, surgical post-edit (combine/split/swap), vary commitments + coined-terms per section at brief-assembly time, or accept for low-stakes drafts. The editor owns document-scale coherence; minions are responsible only for section-scale quality.
102
+
103
+ ## Step 8b — Blinder Audit Minion (mandatory post-integration)
104
+
105
+ ### Purpose
106
+
107
+ Minions write with SURGICAL context — just their slice of the doc — to avoid source-prose ceiling and context pollution. The trade-off: minion A doesn't know what minion B wrote. They can independently produce paragraphs whose ENTIRE SUBSTANCE mirrors another paragraph's entire substance. The **blinder problem**.
108
+
109
+ The Blinder Audit Minion has ONE job: find pairs of paragraphs whose whole substance closely mirrors each other.
110
+
111
+ ### Operational test
112
+
113
+ The audit must reduce to an OBJECTIVE pattern-match — not a subjective claim about reader experience. The working question:
114
+
115
+ **"Summarize each paragraph in one sentence. Are two paragraphs' summaries effectively the same?"**
116
+
117
+ Or sharper: **"Could I cut this paragraph entirely and lose only redundancy?"** Answerable by reading; neither requires reader-experience judgment.
118
+
119
+ Empirically validated: the visual-roster case (4 paragraphs each enumerating the same 5 species in different framings) was a real blinder hit. Every other category tested at sentence-level, transition-level, or image-anchor level was a false positive — either intentional craft (image-anchoring, scaffolding, callbacks) or AI baseline patterns the reader doesn't notice.
120
+
121
+ ### When to fire (mandatory)
122
+
123
+ - After integrating ≥2 minion outputs into one document
124
+ - After any rewrite cycle touching multiple sections
125
+ - Before showing the integrated document to the user
126
+
127
+ Skip when: single-minion / single-section work; surgical violation patches only.
128
+
129
+ ### What to scan for (ONE category)
130
+
131
+ **PARAGRAPH-LEVEL SUBSTANCE DUPLICATION** — two paragraphs whose entire substance closely mirrors each other.
132
+
133
+ Diagnostic for any candidate pair:
134
+ 1. Summarize paragraph A in one sentence. ("This paragraph does X.")
135
+ 2. Summarize paragraph B in one sentence. ("This paragraph does Y.")
136
+ 3. If X and Y are effectively the same job done with different words — finding.
137
+ 4. If X and Y are different work — even if paragraphs share images, lexical phrases, or thematic threads — NOT a finding.
138
+
139
+ Cut test: could you delete one paragraph and lose only redundancy (no unique substance, no unique image-anchor, no unique scaffolding move)? Yes → real blinder. Cutting would lose something distinct → NOT a blinder regardless of surface similarity.
140
+
141
+ ### What NOT to scan for (explicit exclusions — these produce false positives)
142
+
143
+ The audit must NOT flag any of these, even when surface similarity exists:
144
+
145
+ - **Sentence-level overlap across paragraph boundaries** (P4's closing shares thematic thread with P5's opening). Bridge/transition work. Cutting disconnects.
146
+ - **Image-anchoring across paragraphs** (the same image used in 2-3 paragraphs to thread a concept). Craft. The savanna/lion appearing in opener + body + closing is intentional thread.
147
+ - **Callbacks** (an image returning later as frame device or recognition moment). Craft.
148
+ - **Scaffolding repeats** (a paragraph opening with brief re-statement of previous paragraph's premise to set up its own new move). Premise-restatement is structure-promise, not duplication.
149
+ - **Sentence-level lexical/thematic overlap of any kind** unless part of WHOLE-PARAGRAPH substance duplication. Sharing the word "engine" or "same biology" is sentence-level — not a finding.
150
+ - **Structural sameness** (parallel cadence, repeated openers, declarative thesis + builds + aphorism). Readers don't notice; AI baseline behavior addressed by /anti-ai.
151
+ - **Cadence repetition** (parallel rhythm runs in adjacent paragraphs). Same reason.
152
+ - **Coined-term recurrence**. Coined terms are SUPPOSED to recur as identity markers.
153
+ - **Single-paragraph internal repetition** (triple anaphora within ONE paragraph). Craft, and the audit scans across paragraphs not within.
154
+
155
+ ### Expected hit rate
156
+
157
+ Paragraph-level substance duplication is rare in semi-competent writing. On well-written beats the audit should typically return **NO BLINDER ERRORS FOUND** — the correct output, not a list of stretched findings to justify the call.
158
+
159
+ The audit fires as backstop on every integration. It catches gross duplications (visual-roster case, two paragraphs accidentally doing the same teaching beat). Most of the time it correctly returns zero.
160
+
161
+ ### Report format
162
+
163
+ ```
164
+ Finding #N
165
+ - LOCATION: paragraph references (e.g., "B2 P4 + B2 P5")
166
+ - SUMMARY A: one sentence describing what paragraph A does
167
+ - SUMMARY B: one sentence describing what paragraph B does
168
+ - WHY THE SUMMARIES MATCH: one sentence showing the substance duplication
169
+ - CUT TEST: could one paragraph be deleted entirely with only redundancy lost? (If no, the finding is invalid; do not include.)
170
+ - SEVERITY: moderate / major (paragraph-level duplication does not produce "minor" findings)
171
+ - SUGGESTED FIX: cut paragraph A / cut paragraph B / merge to single paragraph
172
+ ```
173
+
174
+ If nothing meets the bar, return exactly: **"NO BLINDER ERRORS FOUND"** — that string, nothing else. Do NOT pad with sentence-level observations, structural notes, or polishing suggestions.
175
+
176
+ ### Editor's response
177
+
178
+ For each finding:
179
+ - Apply the cut test independently. Does deleting one paragraph lose only redundancy?
180
+ - Yes → **cut** (editor territory, FIRM RULE 1 carve-out). Delete weaker paragraph via write_to_pad. If both are strong but redundant, merge unique fragments via Rewrite Minion.
181
+ - No → audit got it wrong. Defer.
182
+
183
+ Audit minion does NOT patch. Only reports.
184
+
185
+ Classification failure modes:
186
+ 1. Trusting a finding without applying the cut test. If both paragraphs carry distinct substance, the audit was matching surface features. Defer.
187
+ 2. Routing a paragraph-level cut to a Rewrite Minion when it should just be a cut. If two paragraphs do the same work, deleting one is the cleanest move.
188
+
189
+ ### Brief shape (template)
190
+
191
+ Index every paragraph in the doc (e.g., "B1 P1: ...", "B2 P7: ...") so the audit can reference cleanly. Pass the full indexed document + the ONE category + the explicit exclusions + the output format. No voice profile needed (this isn't writing prose). Use opus.
@@ -0,0 +1,33 @@
1
+ # Context Hygiene
2
+
3
+ Reset context before applying voice to fresh writing — voice profiles fight against active conversation context and lose. Anchor blends, NEVER rules, and first-token cadence all get out-pulled by whatever prose dominates the live session.
4
+
5
+ ## Two situations
6
+
7
+ | Situation | Practice |
8
+ | --- | --- |
9
+ | First piece of fresh writing in this session | **Reset.** Start a fresh session. Apply Protocol loads voice files cold. |
10
+ | Iteration on already-voice-applied writing (review → revise → review) | **Stay.** The context IS the voice you locked in. |
11
+
12
+ ## When to surface the prompt
13
+
14
+ Surface only when ALL THREE hit:
15
+
16
+ 1. Voice profile is set up at Tier 1+
17
+ 2. Request is fresh writing, not iteration
18
+ 3. Session has substantial prior context unrelated to the writing task
19
+
20
+ Skip for brand-new sessions or when prior context IS the writing-task setup.
21
+
22
+ ## Prompt to surface
23
+
24
+ > Voice profile is set up at **Tier N**. Context here is polluted with **<one-line summary>**, which will pull output toward that register instead of the locked voice.
25
+ >
26
+ > For best output, start a fresh session and run:
27
+ >
28
+ > ```
29
+ > /writers-voice
30
+ > <then ask for your writing task>
31
+ > ```
32
+ >
33
+ > Or tell me **"write here anyway"** and I'll proceed with the active context.
@@ -0,0 +1,74 @@
1
+ # Setup, Anchor Protocol, Multi-Register
2
+
3
+ Loaded on first run, when generating a new anchor, or when splitting a corpus by register. Not in context during normal writing sessions.
4
+
5
+ ## Setup Flow
6
+
7
+ If `voice/anchor.md` doesn't exist or is empty, walk the user through setup:
8
+
9
+ 1. **Get the anchor.** Derivation is **fully local** — your own agent analyzes the writing, nothing leaves the machine, no service cost. Run the **Anchor Protocol** below to generate `voice/anchor.md` directly from the corpus on disk. Launch it as a sub-agent (see "Launching the anchor as a sub-agent") so the full stylometry rubric never pollutes the main session. Works offline. If the user has no corpus yet, ask them to seed 2-5 paragraphs (step 2) first — there is no hosted alternative.
10
+
11
+ 2. **Seed the corpus** — ask for 2-5 paragraphs, write each to `voice/corpus/sample-NNN.md` with `added: YYYY-MM-DD` frontmatter.
12
+ 3. **Run Analysis Protocol** (see `docs/analysis.md`) — populates `stats.md`, `never-rules.md`, `fingerprints.md`, `status.md`.
13
+ 4. **Optional: curate examples** — ask the user for 3-5 most-representative paragraphs, write to `voice/examples.md`.
14
+ 5. **Optional: populate coined terms** — ask the user for any coined terms / proper-noun concepts they want preserved verbatim, write to `voice/coined-terms.md` as a bare bullet list.
15
+ 6. **Report status** — read `voice/status.md` and tell the user their tier + what unlocks next.
16
+
17
+ ## Anchor Protocol (fully in-agent)
18
+
19
+ Generates `voice/anchor.md` (lean) and `voice/anchor-analysis.md` (rich).
20
+
21
+ 1. Confirm corpus has ≥300 words. Below 300, ask the user to add a few more samples before anchoring.
22
+ 2. Read `voice/stats.md`. If missing, run **Analysis Protocol** first.
23
+ 3. Read `catalog/anchor-prompt.md` (full stylometry rubric) and `catalog/author-hints.md` (curated training-data authors with prose features).
24
+ 4. **Set aside conversational context.** Score the corpus on prose mechanics only — never on themes/topics.
25
+ 5. **Per-sample register analysis.** For each sample, record word count, address mode, register, signature moves. Flag samples >25% volume. Cluster by register; if 2+ distinct registers appear, flag as multi-register corpus.
26
+ 6. **Score with register-aware feature validation.** Apply the 8 dimensions from `catalog/anchor-prompt.md`. Match against author hints. Assign weights summing to 100. For each cited feature, verify ≥40% sample appearance OR ≥40% volume (if neither, drop the feature; if it was the strongest evidence, drop the author).
27
+ 7. **Self-criticism pass.** Strip any thematic reasoning. Set `confidence` and `any_thematic_reasoning` flags.
28
+ 8. **Write `voice/anchor.md`** — JUST the lean `- N% Author` lines. No headers, no sub-bullets.
29
+ 9. **Write `voice/anchor-analysis.md`** — per-author features, per-sample table, register diversity, self-check, refresh notes. Human-facing only.
30
+ 10. **If multi-register corpus detected**, recommend a Multi-Register Split (see below).
31
+ 11. Report blend + confidence + caveats to user.
32
+
33
+ ## Launching the anchor as a sub-agent
34
+
35
+ The Anchor Protocol loads a large stylometry rubric (`catalog/anchor-prompt.md`),
36
+ the author-hints catalog, and the full corpus. Running it inline floods the main
37
+ session with analysis context the user never needs to see. **Launch it as a
38
+ sub-agent instead** — the sub-agent does the heavy reading and writes the files;
39
+ the main session gets back only a short summary.
40
+
41
+ Use the Agent/Task tool (general-purpose) with a self-contained prompt. The
42
+ sub-agent has no memory of this conversation, so the prompt must name every file
43
+ by absolute path:
44
+
45
+ > Generate a writer's-voice anchor, entirely locally. Do NOT call any network
46
+ > service or API — analyze with your own reasoning only.
47
+ > 1. Read the stylometry rubric at `<skill>/catalog/anchor-prompt.md` and the
48
+ > author hints at `<skill>/catalog/author-hints.md`.
49
+ > 2. Read every sample in `<skill>/voice/corpus/` (strip YAML frontmatter; keep
50
+ > samples separate) and the deterministic stats at `<skill>/voice/stats.md`
51
+ > (run the Analysis Protocol first if it's missing).
52
+ > 3. Follow the rubric exactly: per-sample register analysis → register-aware
53
+ > feature validation → score 8 dimensions → self-criticism pass.
54
+ > 4. Write `<skill>/voice/anchor.md` (lean blend lines only) and
55
+ > `<skill>/voice/anchor-analysis.md` (rich, human-facing).
56
+ > 5. Return ONLY: the blend lines, confidence, and any multi-register warning.
57
+
58
+ Replace `<skill>` with the skill's absolute path. After it returns, read
59
+ `voice/anchor.md`, report the blend + confidence to the user, and offer a
60
+ multi-register split if the sub-agent flagged one.
61
+
62
+ ## Multi-Register Anchors
63
+
64
+ If the corpus spans multiple registers (e.g., third-person expository AND direct-you instructional), maintain a separate anchor per register: `voice/anchor-<context>.md` (e.g., `anchor-book.md`, `anchor-essay.md`, `anchor-tweets.md`). Same lean format. Each gets a paired `voice/anchor-<context>-analysis.md`.
65
+
66
+ **Multi-Register Split procedure:**
67
+
68
+ 1. Identify registers from the per-sample analysis.
69
+ 2. For each register, ask the user for a slug + one-line description.
70
+ 3. Filter corpus to samples in that register.
71
+ 4. Run the matcher on the subset (same `catalog/anchor-prompt.md` rubric, same variance checks).
72
+ 5. Write `voice/anchor-<slug>.md` (lean) + `voice/anchor-<slug>-analysis.md` (rich).
73
+
74
+ **Apply-time anchor selection:** at write time, if multiple anchor files exist, pick by user's request context (explicit naming wins; project the user is working on wins next; ask if ambiguous; fallback to `voice/anchor.md`).
@@ -0,0 +1,13 @@
1
+ # Tier Reference
2
+
3
+ Determined by total word count in `voice/corpus/`. Each tier unlocks additional voice-profile features. Computed during Analysis Protocol.
4
+
5
+ | Tier | Words | Name | Unlocked | Locked |
6
+ | --- | --- | --- | --- | --- |
7
+ | 0 | <300 | Empty | (none) | anchor blend, basic stats, NEVER rules, fingerprints |
8
+ | 1 | 300-999 | Anchor | anchor blend, basic stats | preliminary NEVER rules, fingerprints |
9
+ | 2 | 1000-4999 | Preliminary | anchor blend, basic stats, preliminary NEVER rules, top fingerprints | full NEVER coverage, all fingerprints |
10
+ | 3 | 5000-19999 | Full Coverage | anchor blend, stats, full NEVER rules, full fingerprints | high-confidence em-dash hurdle |
11
+ | 4 | ≥20000 | AV-Grade | anchor blend, stats, full NEVER rules, full fingerprints, em-dash hurdle cleared | (none) |
12
+
13
+ The tier is reported to the user after every Analysis Protocol run, with a "what unlocks next" pointer.
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "authors-voice",
3
+ "version": "0.19.1",
4
+ "description": "Author's Voice — constructed-voice skill for AI agents. Anchors writing to a training-data author blend, progressively layers NEVER rules, presentation fingerprints, sentence stats, coined terms, and curated examples from a growing local corpus. Local-first markdown skill; optional paid API for plugin/programmatic flows. Replaces writers-voice + the legacy voice-* skill family.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "travsteward",
8
+ "homepage": "https://openwriter.io/authors-voice",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/travsteward/authors-voice"
12
+ },
13
+ "keywords": [
14
+ "claude",
15
+ "claude-code",
16
+ "skill",
17
+ "voice",
18
+ "writing",
19
+ "ai",
20
+ "openwriter",
21
+ "authors-voice",
22
+ "writers-voice",
23
+ "anti-ai"
24
+ ],
25
+ "files": [
26
+ "SKILL.md",
27
+ "catalog/",
28
+ "docs/",
29
+ "prompts/",
30
+ "voice/README.md",
31
+ "voice/corpus/.gitkeep",
32
+ "LICENSE",
33
+ "README.md"
34
+ ]
35
+ }
@@ -0,0 +1,29 @@
1
+ You write at this exact training-data blend:
2
+
3
+ {INCLUDE: voice/anchor.md}
4
+
5
+ Maintain these proportions across the output. The blend IS the voice. Do not soften toward generic literary register. Do not default to your own RLHF-trained voice.
6
+
7
+ STYLE REPAIRS — apply these as hard constraints:
8
+
9
+ {INCLUDE: voice/never-rules.md}
10
+
11
+ {INCLUDE: voice/fingerprints.md}
12
+
13
+ {INCLUDE: voice/stats.md}
14
+
15
+ CONTENT — preserve these coined terms verbatim:
16
+
17
+ {INCLUDE: voice/coined-terms.md}
18
+
19
+ REFERENCE EXAMPLES OF AUTHOR'S WRITING (use if helpful — content and style):
20
+
21
+ {INCLUDE: voice/examples.md}
22
+
23
+ ---
24
+
25
+ TASK:
26
+
27
+ {TASK}
28
+
29
+ Return prose only. No commentary. No diff. No explanation. No headers. No markdown wrapping.
@@ -0,0 +1,51 @@
1
+ # Voice Profile
2
+
3
+ This directory is your **voice profile**. Files in here are read by the agent at write time and applied as style constraints. The skill builds these up progressively over time.
4
+
5
+ ## What goes here
6
+
7
+ | File | Purpose | Source |
8
+ |------|---------|--------|
9
+ | `anchor.md` | Anchor blend (3-5 training-data authors with weights) | Pasted from openwriter.io/writers-voice OR generated in-agent by the skill |
10
+ | `anchor-<context>.md` | OPTIONAL per-register anchors (e.g., `anchor-book.md`, `anchor-tweets.md`) — when your corpus spans multiple registers | Generated in-agent via the Multi-Register Split procedure |
11
+ | `stats.md` | Sentence distribution + punctuation density | Agent best-effort from corpus |
12
+ | `never-rules.md` | NEVER rules (kill-list) | Agent + manual additions |
13
+ | `fingerprints.md` | Exact presentation choices (Oxford comma, etc.) | Agent + manual overrides |
14
+ | `examples.md` | Curated reference paragraphs | Manually picked by the user |
15
+ | `status.md` | Current tier + what's locked | Agent-generated |
16
+ | `corpus/` | Raw samples accumulating over time | Manually added (drop files here) |
17
+
18
+ ## Multi-Register Anchors
19
+
20
+ If your corpus contains writing in multiple registers — third-person expository AND second-person instructional, or analytical essays AND aphoristic tweets — a single blended anchor will pull toward whichever register has the most volume in your corpus, leaving the others under-weighted.
21
+
22
+ The skill detects this automatically during the Anchor Protocol and offers a multi-register split: one anchor file per register (`anchor-book.md`, `anchor-tweets.md`, etc.). At write-time, the agent picks the right anchor based on what you're writing.
23
+
24
+ NEVER rules and fingerprints stay corpus-wide — only the AUTHOR BLEND varies per register.
25
+
26
+ To generate per-register anchors, ask: *"Split my anchor by register."* See the **Multi-Register Anchors** section in `SKILL.md` for the full procedure.
27
+
28
+ ## How it grows
29
+
30
+ The more samples you accumulate in `corpus/`, the richer the analysis. Tiers:
31
+
32
+ - **300-1k words**: anchor blend + basic stats
33
+ - **1k-5k words**: + preliminary NEVER rules + top fingerprints
34
+ - **5k-20k words**: + full NEVER coverage + all fingerprints
35
+ - **20k+ words**: AV-grade (high-confidence profile)
36
+
37
+ ## Re-running analysis
38
+
39
+ After adding samples to `corpus/`, tell the agent:
40
+
41
+ > "Re-analyze my voice profile."
42
+
43
+ The agent reads `catalog/*.md` and the corpus, then regenerates `stats.md`, `never-rules.md`, `fingerprints.md`, and `status.md`. No Node script — pure markdown skill, the agent is the extractor.
44
+
45
+ ## Manual edits
46
+
47
+ `never-rules.md` and `fingerprints.md` have a `## Manual Additions` / `## Manual Overrides` section at the bottom. The agent preserves anything you put there across regenerations.
48
+
49
+ ## Privacy
50
+
51
+ This is your voice profile. The files live on your disk. The skill never uploads anything — analysis is local (agent reasoning over local files). The only thing that leaves your machine is if you use the web tool at openwriter.io/writers-voice for the anchor step (300-800 words pasted in, used once, cached 24h, never trained on). If you use skill mode instead, even the anchor is generated locally.
@@ -437,7 +437,7 @@ function defaultDirsForFramework(fw, detectedContentDir) {
437
437
  // ---- post_to_blog helpers ----
438
438
  /**
439
439
  * Strict double-quoted YAML emission for scalars — matches the style of
440
- * caloriebot's existing posts. Arrays are inline-square-bracket JSON for
440
+ * a typical Astro blog's existing posts. Arrays are inline-square-bracket JSON for
441
441
  * compactness. Booleans + numbers emit bare.
442
442
  */
443
443
  function yamlValue(v) {
@@ -564,7 +564,7 @@ export function buildFrontmatter(title, blogCtx, site, coverImagePath) {
564
564
  }
565
565
  // Date fields emit as UNQUOTED yaml scalars (pubDate: 2026-05-31), never
566
566
  // quoted strings. Astro's z.date() rejects a quoted value — js-yaml parses it
567
- // as a String, not a Date — which froze a live Netlify build (paybotapp.com,
567
+ // as a String, not a Date — which froze a live Netlify build (a production Astro blog,
568
568
  // 2026-06-01). The unquoted form is ALSO accepted by z.coerce.date() and by
569
569
  // Jekyll/Hugo/Next (gray-matter), so it is the universally-correct emit.
570
570
  // adr: adr/blog-image-contract.md
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openwriter",
3
- "version": "0.35.0",
3
+ "version": "0.35.2",
4
4
  "description": "The open-source writing surface for AI agents. Markdown-native editor with pending change review — your agent writes, you accept or reject.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/skill/SKILL.md CHANGED
@@ -16,7 +16,7 @@ description: |
16
16
  Requires: OpenWriter MCP server configured. Browser UI at localhost:5050.
17
17
  metadata:
18
18
  author: travsteward
19
- version: "0.17.0"
19
+ version: "0.18.0"
20
20
  repository: https://github.com/travsteward/openwriter
21
21
  license: MIT
22
22
  ---
@@ -56,7 +56,7 @@ You are a writing collaborator. You read documents and make edits **exclusively
56
56
 
57
57
  **Why a minion, not inline.** Earlier this was "handle it inline, no minion — sorting is a judgment call." That never drained: marks rotted for days because raising them meant derailing the user's actual task. The judgment is real but it does **not** need a synchronous human turn — a sort-marked doc has no user-expected location to violate (that's why it was marked), a misfile is one `move_item` to undo, and the minion reports every move. Reversible + visible replaces the gate. This is the same autonomous-drain rail enrichment rides (firm rule 5).
58
58
 
59
- **Surfacing to the user:** treat sorting like enrichment and the inbox — a maintenance reflex, not a feature they ask for. Dispatch silently and relay a one-line aside in your response: "Filed 3 docs in the background — CalorieBotPayBot/Marketing, …. Now, …". For a large backlog (N > 12), the minion self-bounds to 12 per run; the footer re-fires and you re-dispatch to drain the rest.
59
+ **Surfacing to the user:** treat sorting like enrichment and the inbox — a maintenance reflex, not a feature they ask for. Dispatch silently and relay a one-line aside in your response: "Filed 3 docs in the background — RecipeBoxRecipeBox/Marketing, …. Now, …". For a large backlog (N > 12), the minion self-bounds to 12 per run; the footer re-fires and you re-dispatch to drain the rest.
60
60
 
61
61
  **Manual path still exists.** Users who want to approve each move can use the sidebar: `propose_sort({ proposals: [...] })` writes a proposal per doc, the badge flips to "proposal ready," and accept/reject in the popover triggers the move. The minion doesn't use this — it's for when the user explicitly wants a gate. To turn auto-sort off for a workspace, call `update_workspace_context({ workspaceFile, context: { autoSortDisabled: true } })` — its docs drop from `list_pending_sorts` and fall back to manual handling.
62
62
 
@@ -397,11 +397,23 @@ npx skills add https://github.com/travsteward/openwriter --skill x-writer
397
397
  # Book-scale long-form — chapter architecture, beats, workspace management
398
398
  npx skills add https://github.com/travsteward/openwriter --skill book-writer
399
399
 
400
- # Author's Voicevoice matching, minion dispatch, anti-AI (required by both above)
401
- claude install github:travsteward/authors-voice
400
+ # Channel-agnostic draftingbeats-first uncommitted drafts
401
+ npx skills add https://github.com/travsteward/openwriter --skill beat-writer
402
+
403
+ # Long-form blog posts — beats, titling, voice anchor, publish via github plugin
404
+ npx skills add https://github.com/travsteward/openwriter --skill blog-writer
405
+
406
+ # Weekly email newsletter pipeline
407
+ npx skills add https://github.com/travsteward/openwriter --skill newsletter-writer
408
+
409
+ # Copy polish to 90/100 + AI-fingerprint scrub
410
+ npx skills add https://github.com/travsteward/openwriter --skill polish
411
+ npx skills add https://github.com/travsteward/openwriter --skill anti-ai
402
412
  ```
403
413
 
404
- For voice-matched drafting without a custom voice profile, install **voice-presets** 5 pre-built frames (authority, provocateur, logical, storyteller, business). For an AI-detection pass without full authors-voice setup, install **anti-ai**. Both are optional.
414
+ Author's Voice (voice matching, minion dispatch required by the writers above) now ships INSIDE the authors-voice plugin: enabling the plugin delivers both the MCP tools and the skill at `plugins/authors-voice/skill/SKILL.md`. Standalone install also works: `claude install github:travsteward/authors-voice`.
415
+
416
+ For an AI-detection pass without full authors-voice setup, the bundled **anti-ai** skill stands alone.
405
417
 
406
418
  ## Workflow
407
419
 
@@ -632,7 +644,7 @@ Requires authentication via `request_login_code` + `verify_login`. All publish t
632
644
 
633
645
  ## Author's Voice Plugin
634
646
 
635
- When the user enables the Author's Voice plugin in Settings, install the skill see [authors-voice.com](https://www.authors-voice.com) for install methods. The skill handles API key setup and everything else.
647
+ The plugin ships with the Author's Voice skill built in (`plugins/authors-voice/skill/SKILL.md`) — enabling the plugin in Settings delivers both the MCP tools and the agent instructions. No separate install needed; see [authors-voice.com](https://www.authors-voice.com) for the standalone copy and docs.
636
648
 
637
649
  ## Updating
638
650