Story Design Coherence — manage dependency graphs between story design documents
Project description
sdcoh — Story Design Coherence
Manage dependency graphs between story design documents. Detect change impact and stale downstream files.
When writing novels with AI, you end up with dozens of interconnected design documents: character sheets, beat sheets, foreshadowing ledgers, style guides, briefs, and episode drafts. Change one, and you need to update five others. Forget one, and your story has inconsistencies.
sdcoh makes these dependencies explicit and trackable.
The Problem
You update the character sheet...
→ but forget to update the beat sheet
→ which means the brief is based on stale info
→ which means the AI writes the episode with wrong details
→ which means you spend an hour finding why the draft feels off
The Solution
$ sdcoh status
⚠️ Updates needed (3):
design:continuity last updated 3/15 ← episode:ep07 updated 3/28
design:expression-log last updated 3/10 ← episode:ep05 updated 3/27
brief:ep08 last updated 3/13 ← design:beat-sheet updated 3/25
✅ In sync (12)
Install
pip install sdcoh
Optional OpenViking integration:
pip install sdcoh[openviking]
Quick Start
1. Initialize your project
cd your-novel-project/
sdcoh init --name "My Novel" --alias my-novel
This creates sdcoh.yml and .sdcoh/ directory.
2. Add frontmatter to your documents
Add YAML frontmatter to each Markdown file declaring its dependencies:
---
sdcoh:
id: "design:beat-sheet"
depends_on:
- id: "design:characters"
relation: derives_from
---
# Beat Sheet
...
3. Scan and check
sdcoh scan # Build the dependency graph
sdcoh graph # Visualize it
sdcoh validate # Check for broken references
sdcoh status # Find stale documents
4. Check impact before editing
$ sdcoh impact design/characters.md
Affected (4):
🟡 design:beat-sheet ← derives_from
🟡 design:foreshadowing ← references
🟡 brief:ep02 ← references
🟡 episode:ep01 ← implements
Project Config (sdcoh.yml)
project:
name: "My Novel"
alias: "my-novel"
# Directories to scan for Markdown files
scan:
- design/
- drafts/
- briefs/
- reviews/
- research/
- docs/
# Node types with layer hierarchy (lower = upstream)
node_types:
research: { layer: -1 } # Most upstream
design: { layer: 0 }
brief: { layer: 1 }
episode: { layer: 2 }
review: { layer: 3 } # Most downstream
# Optional: OpenViking semantic search integration
openviking:
enabled: false
endpoint: "http://localhost:1933"
auto_register: true
Default Directory Structure
novel-project/
├── sdcoh.yml # Project config
├── design/ # Character sheets, beat sheets, style guides, etc.
├── drafts/ # Episode manuscripts
├── briefs/ # Writing briefs for AI agents
├── reviews/ # Review results
├── research/ # Research materials
└── docs/ # Workflow documentation
Frontmatter Spec
Fields
| Field | Required | Description |
|---|---|---|
id |
Yes | Node ID in {type}:{name} format |
depends_on |
No | Upstream dependencies (if they change, I'm affected) |
updates |
No | Downstream targets (if I change, they need updating) |
Relation Types
| Relation | Meaning | Example |
|---|---|---|
derives_from |
Derived from this document | beat sheet ← characters |
implements |
Implements this design | episode ← beat sheet |
constrained_by |
Must follow these rules | episode ← style guide |
references |
References this document | brief ← foreshadowing ledger |
extracts_from |
Extracted from this source | expression log ← episode |
triggers_update |
Change triggers update | continuity ← episode |
Glob Patterns
Use fnmatch-style glob patterns to declare dependencies on multiple nodes at once:
# design/characters.md — updates all episodes and briefs when changed
sdcoh:
id: "design:characters"
updates:
- id: "episode:*"
relation: triggers_update
- id: "brief:*"
relation: triggers_update
- id: "design:voice-*"
relation: triggers_update
Patterns are expanded at scan time — graph.json contains only concrete edges. Supported glob syntax: * (any string), ? (single char), [seq] (character set).
This lets you declare dependencies from the design doc side, keeping episode/brief frontmatter minimal:
# drafts/ep05.md — only exception-specific dependencies needed
sdcoh:
id: "episode:ep05"
depends_on:
- id: "design:foreshadow-ledger"
relation: references
A glob pattern that matches zero nodes produces a warning during sdcoh scan.
Bidirectional Dependencies
Some relationships go both ways. Use depends_on for upstream and updates for downstream:
# episode extracts expressions into the log
# drafts/ep01.md
sdcoh:
id: "episode:ep01"
updates:
- id: "design:expression-log"
relation: extracts_from
# the log is referenced by briefs to avoid repetition
# design/expression-log.md
sdcoh:
id: "design:expression-log"
depends_on:
- id: "episode:ep01"
relation: extracts_from
CLI Reference
| Command | Description |
|---|---|
sdcoh init |
Initialize project (sdcoh.yml + .sdcoh/) |
sdcoh scan |
Parse frontmatter, build dependency graph |
sdcoh impact <path> |
Show what's affected by changing a file |
sdcoh graph |
Display dependency tree |
sdcoh validate |
Check for broken refs, cycles, orphans |
sdcoh status |
Find stale downstream documents |
Options
sdcoh scan --quiet # Minimal output (for hooks)
sdcoh scan --warn # List files without frontmatter
sdcoh impact <path> --depth N # Limit traversal depth
sdcoh status --warn-only # Only output if warnings exist
sdcoh status --json # JSON output
Claude Code Integration
Install as Plugin
/plugin marketplace add ysttsu/sdcoh
/plugin install sdcoh@sdcoh
Skills
| Skill | Trigger | Action |
|---|---|---|
/sdcoh-scan |
"scan", "graph update" | sdcoh scan + sdcoh validate |
/sdcoh-impact |
"what's affected?" | sdcoh impact on recent file |
/sdcoh-status |
"stale check" | sdcoh status |
PostToolUse Hook (auto-scan on edit)
Add to .claude/settings.json:
{
"hooks": {
"PostToolUse": [{
"matcher": "Write|Edit",
"if": "Write(*/design/*)|Edit(*/design/*)",
"hooks": [{
"type": "command",
"command": "sdcoh scan --quiet && sdcoh status --warn-only",
"timeout": 10
}]
}]
}
}
Background: Why This Exists
This tool was inspired by CoDD (Coherence-Driven Development), which manages coherence between software design documents. sdcoh adapts the same principle for fiction writing workflows, where AI-assisted novel projects can accumulate 20-30+ interconnected design documents.
Built as part of an AI-assisted novel writing workflow where the author acts as "director" and AI agents handle drafting. The dependency graph ensures that when a design decision changes, all downstream documents are flagged for review — preventing the subtle inconsistencies that plague long-form fiction.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sdcoh-0.1.1.tar.gz.
File metadata
- Download URL: sdcoh-0.1.1.tar.gz
- Upload date:
- Size: 24.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8d7c7a93132905547d2f44468b8bdc6a91fa8bc7899987f0ef75229908f0e35b
|
|
| MD5 |
f30d5f58ea05af6c5925b8a3583e3022
|
|
| BLAKE2b-256 |
e807fae9527a6aec3dd529acd6f14c1e982cf870c2c2b092de4e2c61e8086735
|
File details
Details for the file sdcoh-0.1.1-py3-none-any.whl.
File metadata
- Download URL: sdcoh-0.1.1-py3-none-any.whl
- Upload date:
- Size: 14.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
29e25733edab9f45b602501b60d7f3ffa3b141181daf93fc4531167139ff3d6f
|
|
| MD5 |
1403d5ede4adb287c6680001b8d6adf9
|
|
| BLAKE2b-256 |
a8a68cacecaf7e878590916bbf153508741349320568a980bb440d43b3025aba
|