Skip to main content

Story Design Coherence — manage dependency graphs between story design documents

Project description

sdcoh — Story Design Coherence

PyPI Python License Stars

日本語版 README

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. Declare dependencies in sdcoh.yml

Starting with v0.2, dependencies are declared centrally in sdcoh.yml using patterns. No frontmatter needed in your Markdown files.

rules:
  - name: "design informs episodes"
    from: "design/*.md"
    to: "drafts/ep*.md"
    relation: informs

  - name: "brief feeds episode"
    from: "briefs/{ep}-brief.md"
    to: "drafts/{ep}.md"
    relation: feeds

Edge semantic: from → to means "when from changes, to becomes stale."

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, each with a node type
scan:
  - { path: "design/",  type: "design" }
  - { path: "drafts/",  type: "episode" }
  - { path: "briefs/",  type: "brief" }
  - { path: "reviews/", type: "review" }

# 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

# Dependency rules: when `from` changes, `to` is stale
rules:
  - name: "design informs episodes"
    from: "design/*.md"
    to: "drafts/ep*.md"
    relation: informs
  - name: "brief feeds episode"
    from: "briefs/{ep}-brief.md"
    to: "drafts/{ep}.md"
    relation: feeds

# Optional: OpenViking semantic search integration
openviking:
  enabled: false
  endpoint: "http://localhost:1933"
  auto_register: true

Node IDs are auto-generated as {type}:{basename} (e.g. design/characters.mddesign:characters).

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

Rule Syntax

Pattern tokens

Token Meaning
* Any string (no /)
? Single char (no /)
{name} Named capture (non-greedy, no /) — bind once in from, substitute in to
literal Matches exactly (regex metacharacters are escaped)

Examples

Fan-out — one file to many:

- name: "design informs all episodes"
  from: "design/*.md"
  to: "drafts/ep*.md"
  relation: informs

1-to-1 pairing — match by shared capture:

- name: "brief feeds episode"
  from: "briefs/{ep}-brief.md"
  to: "drafts/{ep}.md"
  relation: feeds
# briefs/ep01-brief.md → drafts/ep01.md

Multiple variants — any suffix after captured prefix:

- name: "any brief revision feeds episode"
  from: "briefs/{ep}-*.md"
  to: "drafts/{ep}.md"
  relation: feeds
# briefs/ep01-kubota-brief.md → drafts/ep01.md
# briefs/ep01-revision2-brief.md → drafts/ep01.md

Reverse flow — episodes update review logs:

- name: "episode updates expression log"
  from: "drafts/ep*.md"
  to: "design/expression-log.md"
  relation: extracts_from

Validation

sdcoh catches common mistakes at scan time:

  • Node ID collision — two files producing the same {type}:{basename} (e.g. from nested subdirectories)
  • Undefined placeholderto: "drafts/{missing}.md" when from has no {missing} capture
  • Relation conflict — two rules producing the same edge with different relations
  • Self-loop — a file matching both sides is silently excluded
  • Zero matches — a rule that produces no edges warns during sdcoh scan

CLI Reference

Command Description
sdcoh init Initialize project (sdcoh.yml + .sdcoh/)
sdcoh scan Apply rules, 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 rules that produced no edges
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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sdcoh-0.2.0.tar.gz (34.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sdcoh-0.2.0-py3-none-any.whl (15.6 kB view details)

Uploaded Python 3

File details

Details for the file sdcoh-0.2.0.tar.gz.

File metadata

  • Download URL: sdcoh-0.2.0.tar.gz
  • Upload date:
  • Size: 34.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.7

File hashes

Hashes for sdcoh-0.2.0.tar.gz
Algorithm Hash digest
SHA256 9d0c4e2aceec24f4e02f940ae741824e776f9de0482195313c4af244a43d518a
MD5 36824cf2bec37e9d090a1208af6ad722
BLAKE2b-256 95d85183e0e7538a72638b37e46eaa5407481b1f4208e9ad92f0bf7e873f156a

See more details on using hashes here.

File details

Details for the file sdcoh-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: sdcoh-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 15.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.7

File hashes

Hashes for sdcoh-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6632f1219956f18e63f8a0f67cf11f8d3350d931f14f33d4d00e4832854989f4
MD5 88ce5862df597e2247ef4022f303ce2a
BLAKE2b-256 2849d6d542fdfe376633929fa54739162e12b8ea777bb128e2677f4f17adb01d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page