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:

  1. Situation — Describe what triggered the emotional response
  2. Emotions — Rate intensity (0-100)
  3. Automatic Thoughts — What went through your mind?
  4. Cognitive Distortion — Which thinking trap did you fall into?
  5. Evidence For — What supports the thought?
  6. Evidence Against — What contradicts it?
  7. 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).