Word count goals get a lot of criticism, and some of it is fair. A thousand bad words aren't better than two hundred good ones. But on days when I'm drafting, a simple number tells me something useful: did I actually write today, or did I just rearrange commas?
Most editors show the word count of the current file. That's not what I want. I want to know how many words I added today across everything I work on. So I wrote a small script for it. It takes a snapshot of my writing folder once a day and compares it with yesterday.
The idea
- Count the words in every Markdown file in a folder.
- Save the total, with today's date, to a small CSV file.
- Show the difference from the previous entry.
That's all. No database, no app, no account.
The script
I wrote it in Python because it ships with most systems and handles text well. Save this as wordlog.py:
#!/usr/bin/env python3
"""Log the total word count of a writing folder once per day."""
import csv
import re
import sys
from datetime import date
from pathlib import Path
FOLDER = Path(sys.argv[1] if len(sys.argv) > 1 else "~/writing").expanduser()
LOG = FOLDER / ".wordlog.csv"
FRONTMATTER = re.compile(r"\A---\n.*?\n---\n", re.DOTALL)
CODE_BLOCK = re.compile(r"```
.*?
```", re.DOTALL)
def count_words(text: str) -> int:
text = FRONTMATTER.sub("", text)
text = CODE_BLOCK.sub("", text)
return len(re.findall(r"\b[\w'-]+\b", text))
def total_words() -> int:
return sum(
count_words(p.read_text(encoding="utf-8", errors="ignore"))
for p in FOLDER.rglob("*.md")
)
def read_log() -> list[list[str]]:
if not LOG.exists():
return []
with LOG.open(newline="") as f:
return list(csv.reader(f))
def main() -> None:
today = date.today().isoformat()
total = total_words()
rows = [r for r in read_log() if r and r[0] != today]
previous = int(rows[-1][1]) if rows else total
rows.append([today, str(total)])
with LOG.open("w", newline="") as f:
csv.writer(f).writerows(rows)
print(f"{today}: {total} words total, {total - previous:+d} since last entry")
if __name__ == "__main__":
main()
A few choices worth explaining:
- Frontmatter and code blocks are skipped. I don't want a YAML header or a pasted config file to count as writing.
- Running it twice on the same day is safe. The script replaces today's row instead of adding a second one.
- The log lives inside the folder as a hidden file, so it travels with the writing.
Running it
chmod +x wordlog.py
./wordlog.py ~/writing
Output looks like this:
2026-10-21: 48210 words total, +734 since last entry
Making it automatic
I don't want to remember to run it. On Linux or macOS, a cron job at the end of the day takes care of that. Open your crontab with crontab -e and add:
55 23 * * * /usr/bin/python3 /home/you/bin/wordlog.py /home/you/writing
Adjust the paths for your system. If your machine is usually off at midnight, pick a time when it's on, or just run the script by hand when you finish for the day.
Reading the log
Because it's a plain CSV, you can open it in any spreadsheet and make a chart. For a quick look in the terminal, this prints the daily difference:
awk -F, 'NR>1 {print $1, $2-prev} {prev=$2}' ~/writing/.wordlog.csv
The catch
This counts net words. On an editing day, when I cut a weak section, the number goes negative. At first that bothered me. Now I like it. A negative day usually means the piece got better, and seeing it written down reminds me that deleting is part of the work too.
If you want gross words written instead, you'd need to track changes per file, for example with git diff --word-diff and counting the added words. That's a nice next step, but the simple version has been enough for me.
Do you track your writing output at all, or does a number like this just add pressure?
Top comments (0)