If you've ever struggled with anxiety, negative self-talk, or emotional spirals, you've probably heard of Cognitive Behavioral Therapy (CBT). It's one of the most evidence-backed therapeutic approaches for anxiety, depression, and dozens of other conditions.
But here's the thing: the core CBT technique — the thought record — is essentially a structured way to debug your own thinking. And if you're a developer, you already know how to debug.
In this tutorial, I'll show you how to build a CBT Thought Record Journal in Python — a CLI tool that guides you through the 7-column thought record, stores entries as JSON, and lets you review patterns over time.
What Is a Thought Record?
A thought record (also called a "dysfunctional thought record" or "ABCDE worksheet") is a structured table where you:
- Situation — Describe what triggered the emotional response
- Emotions — Rate intensity (0-100)
- Automatic Thoughts — What went through your mind?
- Cognitive Distortion — Which thinking trap did you fall into?
- Evidence For — What supports the thought?
- Evidence Against — What contradicts it?
- Balanced Thought — A fairer, more accurate reframe
This structure comes from Aaron Beck's cognitive therapy model. Research shows that regular practice reduces anxiety and depression symptoms by 40-60% over 12-20 sessions.
The 10 Common Cognitive Distortions
Before we code, here are the distortions our tool will detect:
DISTORTIONS = {
'all_or_nothing': 'All-or-Nothing Thinking (splitting)',
'overgeneralization': 'Overgeneralization',
'mental_filter': 'Mental Filter (focusing only on negatives)',
'disqualifying_positive': 'Disqualifying the Positive',
'mind_reading': 'Jumping to Conclusions (Mind Reading)',
'fortune_telling': 'Jumping to Conclusions (Fortune Telling)',
'magnification': 'Magnification (Catastrophizing) or Minimization',
'emotional_reasoning': 'Emotional Reasoning',
'should_statements': 'Should Statements',
'labeling': 'Labeling and Mislabeling',
'personalization': 'Personalization and Blame',
}
Building the Tool
Step 1: Data Model
from dataclasses import dataclass, field
from datetime import datetime
from typing import List
import json
@dataclass
class ThoughtRecord:
date: str = field(default_factory=lambda: datetime.now().isoformat())
situation: str = ''
emotions: dict = field(default_factory=dict)
automatic_thoughts: str = ''
distortions: List[str] = field(default_factory=list)
evidence_for: str = ''
evidence_against: str = ''
balanced_thought: str = ''
new_emotion_rating: dict = field(default_factory=dict)
def to_dict(self):
return {
'date': self.date,
'situation': self.situation,
'emotions': self.emotions,
'automatic_thoughts': self.automatic_thoughts,
'distortions': self.distortions,
'evidence_for': self.evidence_for,
'evidence_against': self.evidence_against,
'balanced_thought': self.balanced_thought,
'new_emotion_rating': self.new_emotion_rating,
}
Step 2: Distortion Detector
This is where it gets interesting. We can use simple pattern matching to suggest which distortions might be present:
import re
def detect_distortions(thought: str) -> list:
thought_lower = thought.lower()
detected = []
if re.search(r'\b(always|never|completely|totally|ruined|perfect|failure|success)\b', thought_lower):
detected.append('all_or_nothing')
if re.search(r'\b(every time|nothing ever)\b', thought_lower):
detected.append('overgeneralization')
if re.search(r'\b(disaster|end of|over for|can.?t handle|unbearable|worst)\b', thought_lower):
detected.append('magnification')
if re.search(r'\b(should|must|have to|ought to)\b', thought_lower):
detected.append('should_statements')
if re.search(r'\b(i feel|it feels|feels like)\b', thought_lower):
detected.append('emotional_reasoning')
if re.search(r'\b(i am a |i.m a |they are a )\b', thought_lower):
detected.append('labeling')
if re.search(r'\b(they think|they know|everyone thinks|people will)\b', thought_lower):
detected.append('mind_reading')
if re.search(r'\b(will go wrong|going to fail|this will)\b', thought_lower):
detected.append('fortune_telling')
return detected
This isn't therapy — it's a prompting tool. The user confirms which distortions actually apply. But the pattern matching helps you learn to recognize them.
Step 3: Interactive CLI
def run_thought_record():
print('=' * 60)
print(' CBT Thought Record Journal')
print('=' * 60)
record = ThoughtRecord()
record.situation = input('What happened? (Describe the situation):\n> ')
print('\nWhat emotions did you feel? (rate 0-100)')
print("Type emotion + rating, e.g. 'anxiety 80'. Empty line to finish.")
while True:
entry = input('> ')
if not entry.strip():
break
parts = entry.rsplit(' ', 1)
if len(parts) == 2 and parts[1].isdigit():
record.emotions[parts[0]] = int(parts[1])
record.automatic_thoughts = input('\nWhat went through your mind?\n> ')
detected = detect_distortions(record.automatic_thoughts)
if detected:
print('\nPossible cognitive distortions detected:')
for d in detected:
print(f' - {DISTORTIONS[d]}')
confirm = input('\nWhich apply? (comma-separate, or all):\n> ')
record.distortions = detected if confirm.strip() == 'all' else \
[d.strip() for d in confirm.split(',') if d.strip() in DISTORTIONS]
record.evidence_for = input('\nEvidence that supports the thought:\n> ')
record.evidence_against = input('\nEvidence against the thought:\n> ')
record.balanced_thought = input('\nA fairer, more balanced thought:\n> ')
print('\nRe-rate your emotions now (0-100):')
for emotion in record.emotions:
new_rating = input(f' {emotion} (was {record.emotions[emotion]}): ')
if new_rating.isdigit():
record.new_emotion_rating[emotion] = int(new_rating)
return record
Step 4: Storage + Pattern Review
from pathlib import Path
from collections import Counter
class ThoughtRecordJournal:
def __init__(self, filepath='thought_records.json'):
self.filepath = Path(filepath)
self.records = self._load()
def _load(self):
if self.filepath.exists():
with open(self.filepath, 'r') as f:
return json.load(f)
return []
def add(self, record: ThoughtRecord):
self.records.append(record.to_dict())
self._save()
def _save(self):
with open(self.filepath, 'w') as f:
json.dump(self.records, f, indent=2)
def review_patterns(self):
all_distortions = []
for r in self.records:
all_distortions.extend(r.get('distortions', []))
counts = Counter(all_distortions)
print('\n--- Your Most Common Distortions ---')
for dist, count in counts.most_common():
print(f' {count}x {DISTORTIONS.get(dist, dist)}')
print('\n--- Emotion Intensity Trend ---')
for r in self.records[-10:]:
for emo, rating in r.get('emotions', {}).items():
new = r.get('new_emotion_rating', {}).get(emo, '?')
print(f" {r['date'][:10]} {emo}: {rating} -> {new}")
Step 5: Putting It Together
def main():
journal = ThoughtRecordJournal()
print('CBT Thought Record Journal')
print('1. New thought record')
print('2. Review patterns')
print('3. Export to CSV')
choice = input('\nChoice: ')
if choice == '1':
record = run_thought_record()
journal.add(record)
print('\nThought record saved.')
elif choice == '2':
journal.review_patterns()
if __name__ == '__main__':
main()
Why This Matters
I built a full CBT toolkit with 200+ free tools covering specific phobias, chronic illness, burnout, and more. The thought record is the foundation — once you can identify and reframe a cognitive distortion, you have a portable skill that works across every mental health challenge.
The toolkit is free and open source: CBT Toolkit on GitHub
The Science
CBT has one of the strongest evidence bases in mental health:
- Anxiety disorders: 50-60% symptom reduction (Hofmann et al., 2012 meta-analysis of 269 studies)
- Depression: equivalent to SSRI medication in mild-moderate cases (Cuijpers et al., 2013)
- Insomnia: 70-80% improvement (CBT-I specifically)
- PTSD: recommended first-line treatment by APA, NICE, and WHO
The thought record targets cognitive restructuring — the process of identifying, evaluating, and modifying distorted thinking patterns. It's the CBT equivalent of git bisect for your mind: systematically narrowing down where the bug (distortion) is.
Beyond the CLI
From here, you could extend this tool to:
- Web app (Flask/FastAPI) with a nice UI for the 7-column table
- Mobile app (React Native) with push reminders
- NLP-powered distortion detection using a fine-tuned model
- Pattern visualization with matplotlib showing emotion trends
- Export to PDF for sharing with a therapist
The core data model and distortion detector stay the same — only the interface changes.
Takeaway
Building mental health tools is deeply rewarding. You're not just writing code — you're creating something that could help someone understand their own mind a little better. And the thought record is the perfect starting point: it's structured, evidence-based, and translates naturally into a data model.
If you found this helpful, check out the CBT Toolkit — 200+ free CBT tools for specific conditions, all open source.
Disclaimer: This tool is for self-help and education, not a replacement for professional therapy. If you're struggling, please reach out to a licensed therapist or a crisis line (988 in the US).
Top comments (0)