@hanna84/mcp-writing 3.23.1 → 3.23.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.
package/CHANGELOG.md CHANGED
@@ -4,9 +4,16 @@ All notable changes to this project will be documented in this file. Dates are d
4
4
 
5
5
  Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
6
6
 
7
+ #### [v3.23.2](https://github.com/hannasdev/mcp-writing/compare/v3.23.1...v3.23.2)
8
+
9
+ - docs: clarify relationship workflow guidance [`#232`](https://github.com/hannasdev/mcp-writing/pull/232)
10
+
7
11
  #### [v3.23.1](https://github.com/hannasdev/mcp-writing/compare/v3.23.0...v3.23.1)
8
12
 
13
+ > 30 May 2026
14
+
9
15
  - fix: align relationship compatibility sync and audit [`#231`](https://github.com/hannasdev/mcp-writing/pull/231)
16
+ - Release 3.23.1 [`f0b643b`](https://github.com/hannasdev/mcp-writing/commit/f0b643bcb7b09adf066380d37718b09001dd3020)
10
17
 
11
18
  #### [v3.23.0](https://github.com/hannasdev/mcp-writing/compare/v3.22.5...v3.23.0)
12
19
 
package/README.md CHANGED
@@ -30,7 +30,7 @@ Instead of feeding an entire manuscript to an AI and hoping it fits in the conte
30
30
  - **Core platform complete:** Metadata-first analysis, SQLite-canonical structural and relationship metadata, compatibility sidecar maintenance, AI-assisted prose editing with confirmation + git history, review bundles, and Scrivener Direct extraction are all implemented.
31
31
  - **Recently completed:** Database Backup and Recovery added project backup export, freshness diagnostics, advisory operation history, automatic backup refresh after sanctioned project-scoped canonical mutations, dry-run restore planning, transactional restore application, and backup/restore operations guidance.
32
32
  - **Previous milestone:** Docker, CI, and Deployment Workflow made Docker a supported way to build, run, smoke-test, and deploy Writing MCP.
33
- - **Active development:** Architecture Alignment Follow-up M5, documenting sidecar compatibility, migration, and deprecation expectations.
33
+ - **Active development:** Relationship Metadata Boundary M3, aligning workflow and generated documentation around SQLite-canonical relationship authority.
34
34
  - **Deferred backlog:** OpenClaw integration, client-agnostic setup, divisions, and embeddings search.
35
35
  - **Ideas and open questions:** tracked separately so future exploration does not distort the active roadmap.
36
36
 
@@ -153,7 +153,7 @@ Outcome: subplot structure stays visible and auditable, which reduces dropped th
153
153
  Goal: keep indexes accurate without manually re-tagging everything.
154
154
 
155
155
  1. After rewriting scenes, call `enrich_scene` to re-derive lightweight metadata from current prose.
156
- 2. Use `update_scene_metadata` for intentional editorial fields (for example, beat, POV, status, and tags); use `list_chapters` plus `assign_scene_to_chapter` or `move_scene` for chapter placement and ordering. Numeric chapter filters are compatibility aliases for read scopes, not mutation targets.
156
+ 2. Use `update_scene_metadata` for intentional editorial fields (for example, beat, POV, status, and tags). It rejects scene `characters` and `places`; use `connect_character_place_evidence` when a scene proves paired sheet-backed character/place evidence, and keep one-sided scene links for a deliberately named relationship workflow. Use `audit_relationship_metadata` for retained sidecar/frontmatter relationship fields. Use `list_chapters` plus `assign_scene_to_chapter` or `move_scene` for chapter placement and ordering.
157
157
  3. Use `search_metadata` and `find_scenes` to verify scenes are discoverable under the expected filters.
158
158
 
159
159
  Outcome: your AI assistant can reliably find the right scenes without drifting from the manuscript.
@@ -179,7 +179,7 @@ Goal: rebuild scene-to-character links in a controlled way after imported prose
179
179
  4. Re-run `enrich_scene_characters_batch` with `dry_run=false` once the preview looks correct.
180
180
  5. If you want a destructive overwrite instead of additive merge behavior, use `replace_mode=replace` with `confirm_replace=true` deliberately.
181
181
 
182
- Outcome: character-link maintenance becomes a preview-first batch operation instead of a one-off regex script or manual sidecar cleanup.
182
+ Outcome: character-link maintenance becomes a preview-first relationship repair operation instead of a one-off regex script or manual sidecar cleanup.
183
183
 
184
184
  ### 6) Post-upgrade recovery after legacy migration warnings
185
185
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanna84/mcp-writing",
3
- "version": "3.23.1",
3
+ "version": "3.23.2",
4
4
  "description": "MCP service for AI-assisted reasoning and editing on long-form fiction projects",
5
5
  "homepage": "https://hannasdev.github.io/mcp-writing/",
6
6
  "type": "module",
@@ -121,7 +121,7 @@ function buildRelationshipMetadataBoundaryDetails({ projectId, sceneId, blockedF
121
121
  boundary: "scene_relationship_metadata",
122
122
  relationship_tools: ["connect_character_place_evidence", "audit_relationship_metadata"],
123
123
  discovery_workflows: ["describe_workflows", "find_scenes", "list_characters", "list_places"],
124
- next_step: "Use find_scenes, list_characters, and list_places to identify stable IDs. Use connect_character_place_evidence only when the scene proves paired sheet-backed character/place evidence; use audit_relationship_metadata to review legacy sidecar/frontmatter relationship fields. Character-only or place-only scene evidence is not changed through update_scene_metadata.",
124
+ next_step: "Use find_scenes, list_characters, and list_places to identify stable IDs. Use connect_character_place_evidence when the scene proves paired sheet-backed character/place evidence; use audit_relationship_metadata to review legacy sidecar/frontmatter relationship fields. Independent character-only or place-only scene links remain valid, but are not changed through update_scene_metadata.",
125
125
  };
126
126
  }
127
127
 
@@ -1120,7 +1120,7 @@ export function registerMetadataTools(s, {
1120
1120
  project_id: scene.project_id,
1121
1121
  compatibility: compatibilityRelationships,
1122
1122
  canonical: canonicalRelationships,
1123
- next_step: "Treat SQLite relationship rows as canonical. Use find_scenes, list_characters, and list_places to inspect stable IDs; use connect_character_place_evidence for paired sheet-backed evidence or leave character-only/place-only repairs to a deliberately named future workflow.",
1123
+ next_step: "Treat SQLite relationship rows as canonical. Use find_scenes, list_characters, and list_places to inspect stable IDs; use connect_character_place_evidence when evidence is paired, and leave independent character-only/place-only repairs to a deliberately named future workflow.",
1124
1124
  });
1125
1125
  }
1126
1126
  }
@@ -1213,7 +1213,7 @@ export function registerMetadataTools(s, {
1213
1213
  compatibility_note_count: diagnostics.filter(diagnostic => diagnostic.severity === "info").length,
1214
1214
  },
1215
1215
  next_steps: [
1216
- "Use connect_character_place_evidence for scene-backed character/place relationships.",
1216
+ "Use connect_character_place_evidence when scene-backed character/place evidence is paired; independent one-sided links remain valid but need a deliberately named workflow.",
1217
1217
  "Use record_character_relationship_beat for relationship arcs between characters.",
1218
1218
  "Use link_reference_evidence for explicit reference evidence.",
1219
1219
  "Use export_project_backup when a fresh recovery snapshot is needed.",
@@ -1440,7 +1440,7 @@ export function registerMetadataTools(s, {
1440
1440
  // ---- connect_character_place_evidence ------------------------------------
1441
1441
  s.tool(
1442
1442
  "connect_character_place_evidence",
1443
- "Connect a character and place as scene-backed story evidence. This is the outcome-level workflow for character/place association: SQLite scene relationship indexes commit first, project backups refresh after commit, and scene sidecar characters/places are refreshed only as generated compatibility output.",
1443
+ "Connect a character and place as paired scene-backed story evidence. This outcome-level workflow covers sheet-backed character/place associations: SQLite scene relationship indexes commit first, project backups refresh after commit, and scene sidecar characters/places are refreshed only as generated compatibility output. Independent character-only or place-only scene links remain valid, but are not handled by update_scene_metadata and need a deliberately named workflow if promoted later.",
1444
1444
  {
1445
1445
  project_id: z.string().describe("Project the scene belongs to (e.g. 'the-lamb')."),
1446
1446
  scene_id: z.string().describe("Scene that provides the evidence for this character/place association."),
@@ -1470,7 +1470,7 @@ export function registerMetadataTools(s, {
1470
1470
  // ---- audit_relationship_metadata -----------------------------------------
1471
1471
  s.tool(
1472
1472
  "audit_relationship_metadata",
1473
- "Review relationship metadata authority, stale indexes, and retained compatibility notes without mutating SQLite or files. Use this before repair work when character/place associations, sidecar tags, scene threads, or recovery readiness look stale or ambiguous.",
1473
+ "Review relationship metadata authority, stale indexes, retained compatibility notes, and scene character/place sidecar drift without mutating SQLite or files. Use this before repair work when character/place associations, sidecar tags, scene threads, or recovery readiness look stale or ambiguous.",
1474
1474
  {
1475
1475
  project_id: z.string().optional().describe("Optional project scope for the audit."),
1476
1476
  },
@@ -2344,7 +2344,7 @@ export function registerMetadataTools(s, {
2344
2344
  // ---- update_scene_metadata -----------------------------------------------
2345
2345
  s.tool(
2346
2346
  "update_scene_metadata",
2347
- "Update one or more non-structural, non-relationship metadata fields for a scene. Writes only supplied allowed fields to the .meta.yaml sidecar and preserves existing structural compatibility fields; it never modifies prose, mirrors path-derived structure, or changes scene character/place relationship authority. Structural fields (part, chapter, chapter_id, chapter_title, timeline_position) are rejected here; use list_chapters plus assign_scene_to_chapter, move_scene, rename_chapter, or reorder_chapter for structure changes. Relationship fields (characters, places) are rejected here; use discovery workflows plus connect_character_place_evidence for paired sheet-backed character/place evidence, and audit_relationship_metadata for legacy sidecar/frontmatter relationship review. Allowed changes are immediately reflected in the index. Only available when the sync dir is writable.",
2347
+ "Update one or more non-structural, non-relationship metadata fields for a scene. Writes only supplied allowed fields to the .meta.yaml sidecar and preserves existing structural compatibility fields; it never modifies prose, mirrors path-derived structure, or changes scene character/place relationship authority. Structural fields (part, chapter, chapter_id, chapter_title, timeline_position) are rejected here; use list_chapters plus assign_scene_to_chapter, move_scene, rename_chapter, or reorder_chapter for structure changes. Relationship fields (characters, places) are rejected here; use discovery workflows plus connect_character_place_evidence when evidence is paired, and audit_relationship_metadata for legacy sidecar/frontmatter relationship review. Independent character-only or place-only scene links remain valid, but are intentionally not changed through this generic metadata tool. Allowed changes are immediately reflected in the index. Only available when the sync dir is writable.",
2348
2348
  {
2349
2349
  scene_id: z.string().describe("The scene_id to update (e.g. 'sc-011-sebastian')."),
2350
2350
  project_id: z.string().describe("Project the scene belongs to (e.g. 'the-lamb')."),
@@ -2361,8 +2361,8 @@ export function registerMetadataTools(s, {
2361
2361
  timeline_position: z.number().int().optional().describe("Rejected by update_scene_metadata. Use move_scene for ordering changes."),
2362
2362
  story_time: z.string().optional(),
2363
2363
  tags: z.array(z.string()).optional(),
2364
- characters: z.array(z.string()).optional().describe("Rejected by update_scene_metadata. Use find_scenes, list_characters, list_places, connect_character_place_evidence for paired sheet-backed evidence, and audit_relationship_metadata for compatibility review."),
2365
- places: z.array(z.string()).optional().describe("Rejected by update_scene_metadata. Use find_scenes, list_characters, list_places, connect_character_place_evidence for paired sheet-backed evidence, and audit_relationship_metadata for compatibility review."),
2364
+ characters: z.array(z.string()).optional().describe("Rejected by update_scene_metadata. Use find_scenes, list_characters, list_places, connect_character_place_evidence when evidence is paired, and audit_relationship_metadata for compatibility review; independent character-only evidence remains valid but needs a deliberately named workflow."),
2365
+ places: z.array(z.string()).optional().describe("Rejected by update_scene_metadata. Use find_scenes, list_characters, list_places, connect_character_place_evidence when evidence is paired, and audit_relationship_metadata for compatibility review; independent place-only evidence remains valid but needs a deliberately named workflow."),
2366
2366
  }).describe("Fields to update. Only supplied keys are changed."),
2367
2367
  },
2368
2368
  async ({ scene_id, project_id, fields }) => {
@@ -2607,7 +2607,7 @@ export function registerMetadataTools(s, {
2607
2607
  // ---- update_place_sheet --------------------------------------------------
2608
2608
  s.tool(
2609
2609
  "update_place_sheet",
2610
- "Update canonical place profile fields and retained compatibility notes. The place name commits to SQLite first and refreshes project backups; associated_characters and tags are compatibility/review metadata only. For current character/place relationship authority, use connect_character_place_evidence.",
2610
+ "Update canonical place profile fields and retained compatibility notes. The place name commits to SQLite first and refreshes project backups; associated_characters and tags are compatibility/review metadata only. Use connect_character_place_evidence when scene-backed character/place evidence is paired; independent place-only links remain valid but need a deliberately named workflow.",
2611
2611
  {
2612
2612
  place_id: z.string().describe("The place_id to update (e.g. 'place-harbor-district'). Use list_places to find valid IDs."),
2613
2613
  fields: z.object({
@@ -2716,7 +2716,7 @@ export function registerMetadataTools(s, {
2716
2716
  }),
2717
2717
  non_canonical_fields: ["associated_characters", "tags"].filter(field => Object.hasOwn(fields, field)),
2718
2718
  next_step: Object.hasOwn(fields, "associated_characters")
2719
- ? "Use connect_character_place_evidence to make scene-backed character/place associations authoritative."
2719
+ ? "Use connect_character_place_evidence when paired scene-backed character/place evidence should become authoritative; independent one-sided links remain valid but need a deliberately named workflow."
2720
2720
  : undefined,
2721
2721
  ...backupMutationFields(backupResult),
2722
2722
  });
@@ -609,7 +609,7 @@ export function registerSearchTools(s, {
609
609
  // ---- get_place_sheet -----------------------------------------------------
610
610
  s.tool(
611
611
  "get_place_sheet",
612
- "Get full place details, including canonical sheet content plus retained sidecar associated_characters and tags as compatibility/review notes. Use connect_character_place_evidence for current scene-backed character/place authority. Response shape note: returns a structured envelope (`results`, `total_count`) with one result row.",
612
+ "Get full place details, including canonical sheet content plus retained sidecar associated_characters and tags as compatibility/review notes. Use connect_character_place_evidence when scene-backed character/place evidence is paired; independent place-only links remain valid and need an explicit relationship workflow rather than a place-sheet read. Response shape note: returns a structured envelope (`results`, `total_count`) with one result row.",
613
613
  {
614
614
  place_id: z.string().describe("The place_id to look up (e.g. 'place-harbor-district'). Use list_places to find valid IDs."),
615
615
  },
@@ -68,12 +68,12 @@ export const WORKFLOW_CATALOGUE = [
68
68
  label: "Track and repair story relationships",
69
69
  use_when: "Use when the user wants to track an arc, link evidence, review stale relationships, repair metadata parity, or prepare generated recovery material for relationship metadata.",
70
70
  steps: [
71
- { tool: "find_scenes", note: "Identify scene_id and project_id from story context before recording relationships." },
71
+ { tool: "find_scenes", note: "Identify scene_id and project_id from story context before recording relationships; use list_characters and list_places when stable entity IDs need disambiguation." },
72
72
  { tool: "track_thread_arc", note: "Use when a scene should carry a storyline, subplot, setup, escalation, reveal, reversal, payoff, or other thread beat." },
73
- { tool: "connect_character_place_evidence", note: "Use when a scene proves a character/place association; SQLite scene relationship indexes commit first and sidecar characters/places remain generated compatibility output." },
73
+ { tool: "connect_character_place_evidence", note: "Use when a scene proves paired sheet-backed character/place evidence; SQLite scene relationship indexes commit first and sidecar characters/places remain generated compatibility output. Independent character-only or place-only scene links remain valid, but need a deliberately named future workflow for daily repair." },
74
74
  { tool: "record_character_relationship_beat", note: "Use when a scene proves a relationship beat between two characters without exposing the character_relationships table." },
75
75
  { tool: "link_reference_evidence", note: "Use when scene, character, place, or reference evidence should point to a reference document; SQLite commits first and compatibility output is generated transparency." },
76
- { tool: "audit_relationship_metadata", note: "Use before repair work to review stale relationship indexes and sidecar-only compatibility notes without mutating canonical state." },
76
+ { tool: "audit_relationship_metadata", note: "Use before repair work to review stale relationship indexes, retained sidecar/frontmatter characters or places, and compatibility drift without mutating canonical state." },
77
77
  { tool: "suggest_scene_references", note: "Use preview first to review candidate scene-reference links from character/place evidence; use apply only after the relationship outcome is intended." },
78
78
  { tool: "enrich_scene_characters_batch", note: "Use dry_run first when prose-derived character relationship parity needs repair across multiple scenes; apply mode syncs SQLite after compatibility output and refreshes backups for changed scenes." },
79
79
  { tool: "diagnose_project_backups", note: "Relationship mutation tools refresh project backups after canonical commits; run this if backup_warnings were returned or recovery readiness matters." },
@@ -101,9 +101,9 @@ export const WORKFLOW_CATALOGUE = [
101
101
  steps: [
102
102
  { tool: "sync", note: "Refresh SQLite indexes from current compatibility inputs, then review warnings instead of patching sidecars as the first repair step." },
103
103
  { tool: "diagnose_structure", note: "Use when sidecar, frontmatter, folder, chapter, epigraph, or generated-export structure appears to disagree with SQLite canonical state." },
104
- { tool: "audit_relationship_metadata", note: "Use when sidecar threads, tags, flags, associated_characters, characters, places, or reference aliases need authority classification before repair." },
104
+ { tool: "audit_relationship_metadata", note: "Use when sidecar threads, tags, flags, associated_characters, characters, places, or reference aliases need authority classification before repair; relationship fields are compatibility input/review evidence, not generic metadata writes." },
105
105
  { tool: "track_thread_arc", note: "Use for current thread authority instead of editing sidecar threads." },
106
- { tool: "connect_character_place_evidence", note: "Use for current scene-backed character/place authority instead of editing sidecar relationship lists." },
106
+ { tool: "connect_character_place_evidence", note: "Use for paired scene-backed character/place evidence instead of editing sidecar relationship lists or sending characters/places through update_scene_metadata; independent one-sided links remain valid but are outside this generic metadata path." },
107
107
  { tool: "link_reference_evidence", note: "Use for current reference-link authority instead of editing sidecar/frontmatter aliases." },
108
108
  { tool: "export_project_backup", note: "Generate a recovery snapshot from SQLite canonical state after meaningful canonical migration or repair work; editing backup artifacts does not mutate current state." },
109
109
  ],