Writing Analytics¶
Context: Three scripts track writing progress at different granularities: per-section word counts, chapter-level status dashboards, and daily velocity trends. Combined with Obsidian plugins, they create a full picture of where the book stands at any moment.
Writing a book without progress tracking is like driving without a speedometer. You feel like you're moving, but you have no idea if you'll arrive on time. At 78,000 words target across 12 chapters, "I wrote a lot today" doesn't cut it. You need numbers.
Word Count: The Foundation¶
word_count.py is the most-run script in the entire system. It answers one question: how many words of actual prose exist in the manuscript?
The challenge is defining "actual prose." A raw word count of every .md file in the vault overstates by 15-20%. Here's what gets excluded:
| Excluded Content | Why |
|---|---|
| YAML frontmatter | Metadata, not prose |
| Mermaid diagram syntax | Code, not prose |
References sections (## References onward) |
URLs and citation text |
HTML comments (<!-- ... -->) |
Internal tracking blocks |
Obsidian comments (%% ... %%) |
Author notes |
Footnote markers ([^tag]) |
Syntax, not words |
Wiki-link syntax gets special handling. [[concepts/Data Flywheel|Data Flywheel]] counts as two words ("Data Flywheel"), not the full path. The link destination is metadata; the display text is what the reader sees.
# Full book with per-section breakdown
python scripts/word_count.py --draft "Draft 3" --verbose
# Verbose mode shows exclusion breakdown:
# Frontmatter (YAML): 3,456 words
# Mermaid diagrams: 891 words
# References section: 2,103 words
# Comments (HTML/Obs): 234 words
# Footnote markers: 775 words
# ─────────────────────────────────────
# Total excluded: 7,459 words
# Raw file total: 88,832 words
# Book content: 81,373 words
That 7,400-word gap between raw and counted is real. Without filtering, you'd think you were 10% further ahead than you actually are.
Book Status Dashboard¶
book_status.py is the weekly check-in. It reads the frontmatter status field from every chapter and section file, counts words per chapter, and renders a color-coded progress table.
Each chapter shows: - Status (outline, drafting, revising, editing, done) -- color-coded red through green - Word count vs target - Progress bar -- visual fill based on percentage - Part grouping -- chapters organized under their parts
# Full formatted dashboard
python scripts/book_status.py
# One-line summary for scripts or dashboards
python scripts/book_status.py --brief
# Output: 81,373/78,000 words (104%) | 10/12 done | 2 in progress
# JSON for programmatic consumption
python scripts/book_status.py --json
The --brief mode is designed for embedding. Pipe it into a Slack message, a commit description, or a daily standup note. The --json mode feeds the book intelligence app's dashboard.
Daily Stats: Velocity Tracking¶
daily_stats.py is the accountability tool. It takes daily snapshots of word counts, stores them in .writing_stats.json, and shows you trends.
What it tracks:
| Feature | Command | What You See |
|---|---|---|
| Today's writing | -- (default) |
Words added today, daily goal progress, which chapters changed |
| Record snapshot | --record |
Saves today's count for future comparison |
| History | --history 7 |
Table of last N days with daily changes |
| Contribution graph | --graph |
GitHub-style heatmap of writing activity over 12 weeks |
| Chapter progress | --progress |
Progress bars for every chapter against 6,500-word target |
| Section detail | --sections |
Per-section word changes since last snapshot |
| Writing streak | --streak |
Consecutive days meeting the 500-word daily goal |
| Obsidian sync | --sync |
Writes a Dashboard-Stats.md file into the vault |
The contribution graph is surprisingly motivating. Seeing a row of green squares creates the same "don't break the chain" effect as any habit tracker. Empty squares create guilt. Both work.
# Record today's snapshot and sync to Obsidian
python scripts/daily_stats.py --record --sync
# Show last 14 days of writing history
python scripts/daily_stats.py --history 14
# See which sections changed today
python scripts/daily_stats.py --sections
The script also installs as a git post-commit hook (--install-hook). Every time you commit changes to the book drafts folder, it auto-records a snapshot. No manual --record needed. Writing stats accumulate passively.
Obsidian Integration¶
The scripts complement two Obsidian plugins:
Novel Word Count shows live word counts in the file explorer sidebar. Every section file displays its current word count next to the filename. This is the real-time view -- useful during active writing when you want to see a section grow toward its 1,200-word target without leaving the editor.
Writing Goals sets per-section targets. A progress bar appears at the bottom of each file showing percentage toward goal. When the bar turns green, the section is long enough. This plugin catches under-writing in real time; the scripts catch it in aggregate.
The combination works like this: Obsidian plugins give you the section-level view while you're writing. Scripts give you the chapter and book-level view when you step back to assess.
Metrics That Matter¶
After writing 12 chapters, here are the metrics that actually influenced decisions:
| Metric | Why It Mattered |
|---|---|
| Words per section | Flagged sections that were too thin (under 800 words) or bloated (over 1,800) |
| Daily velocity | Showed that 500 words/day was sustainable; 1,000 led to burnout and quality drops |
| Chapter completion dates | Made deadline estimation possible -- 3 days per chapter in drafting phase |
| Status distribution | Revealed that chapters clustered in "drafting" too long; we needed a push to "revising" |
The metrics you don't need: total time spent (hard to measure with AI assistance), words per hour (meaningless when the AI writes and you edit), revision count (the good chapters needed more revisions, not fewer).
Track output, not effort. The scripts are built around that principle.
Related: Script Ecosystem | Dataview and Dashboards