<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: CBT Tools</title>
    <description>The latest articles on DEV Community by CBT Tools (@473185670).</description>
    <link>https://dev.to/473185670</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4068155%2F7b476736-baf5-4a82-b30d-f07f3b9e7e7f.png</url>
      <title>DEV Community: CBT Tools</title>
      <link>https://dev.to/473185670</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/473185670"/>
    <language>en</language>
    <item>
      <title>How I Built a Virtual Folder Tree from Flat Filenames — No Files Moved, No Symlinks, Just 300 Lines of TypeScript</title>
      <dc:creator>CBT Tools</dc:creator>
      <pubDate>Sun, 30 Aug 2026 05:38:58 +0000</pubDate>
      <link>https://dev.to/473185670/how-i-built-a-virtual-folder-tree-from-flat-filenames-no-files-moved-no-symlinks-just-300-lines-4gil</link>
      <guid>https://dev.to/473185670/how-i-built-a-virtual-folder-tree-from-flat-filenames-no-files-moved-no-symlinks-just-300-lines-4gil</guid>
      <description>&lt;p&gt;I let an AI agent write code in my project for a week. By Friday there were 340 files in one directory.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;auth_login_handler.ts&lt;/code&gt;. &lt;code&gt;auth_login_session.ts&lt;/code&gt;. &lt;code&gt;utils_helpers.ts&lt;/code&gt;. &lt;code&gt;config_env.ts&lt;/code&gt;. All flat. All in the root.&lt;/p&gt;

&lt;p&gt;The agent loved it. No path ambiguity, no directory hops, no "which folder was that in?" 鈥?every file one &lt;code&gt;read_file&lt;/code&gt; call away. Flat is the agent's native habitat.&lt;/p&gt;

&lt;p&gt;I hated it. Scrolling through 340 files looking for the one auth handler I needed. My brain doesn't grep.&lt;/p&gt;

&lt;p&gt;So I built &lt;strong&gt;Logical Folders&lt;/strong&gt; 鈥?a VSCode and IntelliJ plugin that displays flat files as a virtual directory tree. The files don't move. Nothing changes on disk. The hierarchy is purely visual.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;On disk:                    In the tree:
auth_login_handler.ts       auth/
auth_login_session.ts         login/
utils_helpers.ts                handler.ts
config_env.ts                   session.ts
                            utils/
                              helpers.ts
                            config/
                              env.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent keeps its flat playground. I get my tree.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core: 30 lines
&lt;/h2&gt;

&lt;p&gt;The whole thing hinges on one function 鈥?&lt;code&gt;parsePath&lt;/code&gt;. Split a filename on a separator, keep the extension glued to the last segment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;parsePath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;relPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;sep&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;relPath&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sep&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filename&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Dotfiles (.gitignore, .env) never split 鈥?returned as-is&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;sep&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startsWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sep&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;extname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ext&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;segs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sep&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ext&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;segs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;segs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;segs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;ext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;segs&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;auth_login_handler.ts&lt;/code&gt; with &lt;code&gt;_&lt;/code&gt; 鈫?&lt;code&gt;["auth", "login", "handler.ts"]&lt;/code&gt;. That's it. The extension stays on the last segment so &lt;code&gt;handler.ts&lt;/code&gt; doesn't become &lt;code&gt;handler&lt;/code&gt; + &lt;code&gt;.ts&lt;/code&gt; as a fake folder.&lt;/p&gt;

&lt;p&gt;The inverse is &lt;code&gt;constructFlatName&lt;/code&gt; 鈥?join segments with the separator, reattach the extension. When you right-click &lt;code&gt;auth/login/&lt;/code&gt; and create &lt;code&gt;handler.ts&lt;/code&gt;, the plugin joins them back to &lt;code&gt;auth_login_handler.ts&lt;/code&gt; and writes the flat file.&lt;/p&gt;

&lt;p&gt;The tree is a lie. The disk is the truth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the virtual tree
&lt;/h2&gt;

&lt;p&gt;VSCode's &lt;code&gt;TreeDataProvider&lt;/code&gt; interface needs &lt;code&gt;getChildren(element?)&lt;/code&gt;. I scan the workspace once, parse every file path, and insert into a tree of &lt;code&gt;LogicalNode&lt;/code&gt; objects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;buildTree&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LogicalNode&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cfg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vscode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;workspace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getConfiguration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;logicalFolders&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;separator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;separator&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;exclude&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;exclude&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;maxFiles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cfg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;maxFiles&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;folder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;vscode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;workspace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;workspaceFolders&lt;/span&gt;&lt;span class="p"&gt;?.[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rootPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;folder&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fsPath&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LogicalNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rootPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="p"&gt;...);&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;folder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;excludePattern&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;exclude&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`{&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;exclude&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;}`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;vscode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;workspace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;**/*&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;excludePattern&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;maxFiles&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;uri&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;rel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rootPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fsPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;segments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;parsePath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;separator&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;uri&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fsPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;vscode.workspace.findFiles&lt;/code&gt; respects glob exclude patterns. The &lt;code&gt;maxFiles&lt;/code&gt; cap (default 10,000) is a performance guard 鈥?I learned the hard way that scanning a monorepo with 50k files freezes the tree for two seconds.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;insert&lt;/code&gt; method walks the tree along the parsed segments, creating virtual folder nodes as needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LogicalNode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="nx"&gt;physical&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;seg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isLeaf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;seg&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;seg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LogicalNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="nx"&gt;seg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;isLeaf&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;physical&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;// file nodes get a real path&lt;/span&gt;
                &lt;span class="nx"&gt;isLeaf&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;physical&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;physicalDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nx"&gt;segments&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="nx"&gt;isLeaf&lt;/span&gt;
                    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;vscode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TreeItemCollapsibleState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;None&lt;/span&gt;
                    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;vscode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TreeItemCollapsibleState&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Collapsed&lt;/span&gt;
            &lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;current&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;seg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Folder nodes have &lt;code&gt;physicalPath = undefined&lt;/code&gt;. File nodes point to the real file on disk. When you click a file, it opens the actual file 鈥?no symlink, no redirect. The &lt;code&gt;resourceUri&lt;/code&gt; is set to the real path, so VSCode's built-in operations (git diff, search, go-to-definition) all work normally.&lt;/p&gt;

&lt;h2&gt;
  
  
  The separator problem
&lt;/h2&gt;

&lt;p&gt;Default is &lt;code&gt;_&lt;/code&gt; 鈥?the convention AI agents use when writing flat files. But different teams use different conventions:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Separator&lt;/th&gt;
&lt;th&gt;Flat file&lt;/th&gt;
&lt;th&gt;Logical tree&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;_&lt;/code&gt; (default)&lt;/td&gt;
&lt;td&gt;&lt;code&gt;auth_login_handler.ts&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;auth/ &amp;gt; login/ &amp;gt; handler.ts&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;__&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;auth__login__handler.ts&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;auth/ &amp;gt; login/ &amp;gt; handler.ts&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;auth-login-handler.ts&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;auth/ &amp;gt; login/ &amp;gt; handler.ts&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;auth.login.handler.ts&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;auth/ &amp;gt; login/ &amp;gt; handler.ts&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;::&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;auth::login::handler.ts&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;auth/ &amp;gt; login/ &amp;gt; handler.ts&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;.&lt;/code&gt; separator has a footgun: &lt;code&gt;auth.login.handler.test.ts&lt;/code&gt; splits to &lt;code&gt;auth/ &amp;gt; login/ &amp;gt; handler/ &amp;gt; test.ts&lt;/code&gt; 鈥?the &lt;code&gt;.test&lt;/code&gt; part becomes a virtual folder. Use &lt;code&gt;_&lt;/code&gt; or &lt;code&gt;-&lt;/code&gt; if your test files have dots in the name. I documented this in the README rather than trying to be clever about it.&lt;/p&gt;

&lt;p&gt;Dotfiles (&lt;code&gt;.gitignore&lt;/code&gt;, &lt;code&gt;.env&lt;/code&gt;) are never split. They start with a dot, so the first check in &lt;code&gt;parsePath&lt;/code&gt; bails out and returns them as-is.&lt;/p&gt;

&lt;h2&gt;
  
  
  Physical directories pass through
&lt;/h2&gt;

&lt;p&gt;If you have a real &lt;code&gt;src/&lt;/code&gt; directory AND a flat &lt;code&gt;src_auth.ts&lt;/code&gt; file, both appear under &lt;code&gt;src/&lt;/code&gt; in the tree. The plugin doesn't force everything flat 鈥?it merges physical and logical. This matters because most real projects are a mix: some directories are real (created by humans), some files are flat (created by agents).&lt;/p&gt;

&lt;h2&gt;
  
  
  File operations work on the flat file
&lt;/h2&gt;

&lt;p&gt;Create, rename, delete 鈥?all operate on the physical flat file, not the virtual tree.&lt;/p&gt;

&lt;p&gt;Right-click &lt;code&gt;auth/login/&lt;/code&gt; 鈫?New File 鈫?type &lt;code&gt;handler.ts&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Segments: &lt;code&gt;["auth", "login", "handler.ts"]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Flat name: &lt;code&gt;auth_login_handler.ts&lt;/code&gt; (segments joined with &lt;code&gt;_&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Created on disk in the same physical directory as the other files&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rename &lt;code&gt;handler.ts&lt;/code&gt; to &lt;code&gt;middleware.ts&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Old flat name: &lt;code&gt;auth_login_handler.ts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;New flat name: &lt;code&gt;auth_login_middleware.ts&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fs.rename&lt;/code&gt; on the physical file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tree refreshes (500ms debounce on the file watcher) and shows the new structure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not just use real folders?
&lt;/h2&gt;

&lt;p&gt;Because the agent breaks them.&lt;/p&gt;

&lt;p&gt;I tried organizing the 340 files into real directories. The agent immediately flattened them again on the next edit 鈥?it resolves paths, writes flat, and doesn't preserve directory structure. Every &lt;code&gt;mkdir&lt;/code&gt; + &lt;code&gt;mv&lt;/code&gt; was undone within minutes.&lt;/p&gt;

&lt;p&gt;Symlinks? The agent follows them, resolves the real path, and writes to the flat location. Same problem.&lt;/p&gt;

&lt;p&gt;The only structure the agent respects is the filename itself. So I made the structure live in the filename 鈥?and built a viewer that reads it back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;VSCode&lt;/strong&gt; 鈥?search "Logical Folders" in the extensions panel, or:&lt;br&gt;
&lt;a href="https://marketplace.visualstudio.com/items?itemName=alexcoledev.logical-folders" rel="noopener noreferrer"&gt;Marketplace link&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IntelliJ IDEA&lt;/strong&gt; 鈥?pending JetBrains review (plugin ID 33928), live within 2 business days at:&lt;br&gt;
&lt;code&gt;plugins.jetbrains.com/plugin/33928-logical-folders&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source&lt;/strong&gt;: &lt;a href="https://github.com/alexcoledev/logical-folders" rel="noopener noreferrer"&gt;github.com/alexcoledev/logical-folders&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The VSCode extension is ~300 lines of TypeScript. The IntelliJ plugin is Kotlin 鈥?same algorithm, different tree API. No runtime dependencies beyond the editor SDK.&lt;/p&gt;

&lt;p&gt;Config: &lt;code&gt;logicalFolders.separator&lt;/code&gt; (default &lt;code&gt;_&lt;/code&gt;), &lt;code&gt;logicalFolders.exclude&lt;/code&gt; (default &lt;code&gt;["**/node_modules/**", "**/.git/**", "**/out/**", "**/dist/**"]&lt;/code&gt;), &lt;code&gt;logicalFolders.maxFiles&lt;/code&gt; (default 10000).&lt;/p&gt;

</description>
      <category>vscode</category>
      <category>typescript</category>
      <category>productivity</category>
      <category>discuss</category>
    </item>
    <item>
      <title>How a CBT Thought Record Got Me Through a Production Outage at 3 AM</title>
      <dc:creator>CBT Tools</dc:creator>
      <pubDate>Tue, 25 Aug 2026 23:02:18 +0000</pubDate>
      <link>https://dev.to/473185670/how-a-cbt-thought-record-got-me-through-a-production-outage-at-3-am-45de</link>
      <guid>https://dev.to/473185670/how-a-cbt-thought-record-got-me-through-a-production-outage-at-3-am-45de</guid>
      <description>&lt;p&gt;The pager went off at 3:14 AM. A single sentence: &lt;code&gt;payment-service PROD error rate 12% (threshold 5%)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I was the on-call. My first thought, before I was even fully awake:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This is going to be a career-ending incident. They're going to fire me. I should just quit now."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My hands were shaking. I could not read the dashboard. I tried three times to SSH into the bastion and typoed the host each time.&lt;/p&gt;

&lt;p&gt;This is the moment where most on-call narratives tell you to "stay calm" or "follow the runbook." That advice has never once helped me at 3 AM. What helped was a 90-second exercise I'd been practicing for two months — a CBT thought record, adapted for incidents.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 90-second incident thought record
&lt;/h2&gt;

&lt;p&gt;I keep a text file open during on-call weeks. The structure is five lines. Here is what I wrote at 3:17 AM, between the second and third SSH attempt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SITUATION: Payment-service error rate 12% at 03:14. I am on-call.
EMOTION:    Terror 9/10. Shame 7/10.
HOT THOUGHT: "This is career-ending. They will fire me."
DISTORTION: Catastrophizing (jumping to worst outcome) + Mind reading (assuming I know what leadership will decide) + Fortune Telling (predicting the outcome before the incident is even resolved).
REFRAME:    The error rate is 12%, not 100%. Payments are degraded, not down. I have resolved 14 incidents this quarter with no escalation. The incident is 3 minutes old — no human has even noticed yet. My job right now is to read the dashboard, not to predict my employment status.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the entire exercise. Five lines. It took me 90 seconds because my hands were shaking and I kept mistyping.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed after writing it
&lt;/h2&gt;

&lt;p&gt;Nothing magical happened. The error rate was still 12%. The dashboard was still hard to read. But the thought &lt;code&gt;they will fire me&lt;/code&gt; had moved from my chest to the screen, and on the screen I could see it was a prediction about the future, not a fact about the present.&lt;/p&gt;

&lt;p&gt;I SSH'd in on the next attempt. The root cause was a connection pool exhaustion after a deploy three hours earlier that no one had watched. The fix was a config rollback — one command. Error rate dropped to 0.4% by 3:31 AM. Total time from page to resolution: 17 minutes.&lt;/p&gt;

&lt;p&gt;The thought record did not fix the incident. It fixed the thing that was preventing me from fixing the incident — the catastrophizing loop that was burning my working memory on predictions about getting fired instead of reading a stack trace.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this is different from "just calm down"
&lt;/h2&gt;

&lt;p&gt;"T Stay calm" is an instruction to suppress a feeling. It does not work because the feeling is a reasonable response to "production is broken and I am responsible." Suppressing it takes active cognitive effort, which is effort I need for the incident.&lt;/p&gt;

&lt;p&gt;A thought record does the opposite. It does not suppress the emotion — it names it (&lt;code&gt;Terror 9/10&lt;/code&gt;), identifies the specific thought driving it (&lt;code&gt;this is career-ending&lt;/code&gt;), checks that thought against a list of known cognitive distortions, and writes a reframe that is grounded in the actual situation. The emotion does not disappear. It drops from a 9 to a 4, which is the difference between "cannot type" and "can type but slowly."&lt;/p&gt;

&lt;p&gt;The mechanism is not relaxation. It is &lt;strong&gt;cognitive restructuring&lt;/strong&gt; — the same technique used in CBT for anxiety disorders, compressed into a format that fits between two SSH attempts.&lt;/p&gt;

&lt;h2&gt;
  
  
  The five distortions that show up most in incidents
&lt;/h2&gt;

&lt;p&gt;After running this exercise across roughly 40 on-call incidents over six months, five distortions dominate:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Catastrophizing&lt;/strong&gt; — "this is career-ending." The distortion is jumping to the worst possible outcome before the incident is resolved. The reframe: the outcome is not known yet; the current task is diagnosis, not prediction.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Mind reading&lt;/strong&gt; — "leadership is going to blame me." The distortion is assuming you know what other people are thinking. The reframe: no human has noticed yet; when they do, they will see the timeline, which shows a 17-minute resolution.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Personalization&lt;/strong&gt; — "this is my fault because I am on-call." The distortion is taking responsibility for things outside your control. The reframe: the deploy was three hours ago, possibly before my on-call shift started; responsibility is assigned after postmortem, not during the incident.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;All-or-nothing&lt;/strong&gt; — "if I cannot fix this immediately, I am incompetent." The distortion is binary framing. The reframe: incidents are diagnosed in stages; "not fixed yet" is the normal state of an active incident, not evidence of incompetence.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Fortune telling&lt;/strong&gt; — "this will become a SEV1 and go to the VP." The distortion is predicting a specific negative future. The reframe: the current severity is SEV2 based on error rate; severity escalation depends on duration and impact, both of which I am actively controlling.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The part I do not write down
&lt;/h2&gt;

&lt;p&gt;There is a sixth line I added after about ten incidents, but I do not always fill it in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ACTION: What is the next physical step I can take in the next 60 seconds?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At 3:17 AM the answer was "read the error message on the dashboard." Not "fix the incident." Not "figure out the root cause." Just read the error message. One physical step. The thought record gets me out of the catastrophizing loop; the action line gets me back into the incident.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does this scale beyond on-call
&lt;/h2&gt;

&lt;p&gt;I have used the same five-line structure for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Code review anxiety&lt;/strong&gt; — hot thought: "the reviewer thinks I am junior." Distortion: mind reading. Reframe: the reviewer commented on the code, not on me; address the comment, not the imagined judgment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance review prep&lt;/strong&gt; — hot thought: "I will get a bad rating because of that one incident." Distortion: catastrophizing + mental filtering (one incident out of a quarter). Reframe: the review covers a quarter; one resolved SEV2 is one data point among many.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy fear&lt;/strong&gt; — hot thought: "this deploy will break production." Distortion: fortune telling. Reframe: the deploy passed CI and staging; the actual risk is the rollback procedure, which I have tested.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The structure is the same. The distortions are the same five. The reframe is always "what is the fact about the present moment, as distinct from the prediction about the future."&lt;/p&gt;

&lt;h2&gt;
  
  
  The free tool
&lt;/h2&gt;

&lt;p&gt;I built a browser-based thought record tool that implements this exact five-line structure — no signup, no backend, no data leaves your machine. It detects the five distortions above automatically as you type your hot thought, and suggests the reframe pattern. It works on a phone, which is where I actually use it at 3 AM.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tool&lt;/strong&gt;: &lt;a href="https://473185670.github.io/cbt-toolkit/" rel="noopener noreferrer"&gt;CBT Thought Record&lt;/a&gt; (free, no signup, works offline after first load)&lt;/p&gt;

&lt;p&gt;The incident thought record is not therapy. It is a 90-second cognitive tool that moves the catastrophizing from your working memory to a text file, so your working memory is available for the incident. At 3 AM, that is the only thing that matters.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>mentalhealth</category>
      <category>psychology</category>
      <category>beginners</category>
    </item>
    <item>
      <title>7 Questions About CBT Thought Records I Wish I'd Asked Before Starting</title>
      <dc:creator>CBT Tools</dc:creator>
      <pubDate>Tue, 25 Aug 2026 22:05:39 +0000</pubDate>
      <link>https://dev.to/473185670/7-questions-about-cbt-thought-records-i-wish-id-asked-before-starting-13o1</link>
      <guid>https://dev.to/473185670/7-questions-about-cbt-thought-records-i-wish-id-asked-before-starting-13o1</guid>
      <description>&lt;p&gt;I've been using CBT thought records for about three months now. Not as a therapist, not as a researcher — as a developer who got tired of lying awake at 2 AM replaying a code review comment in my head.&lt;/p&gt;

&lt;p&gt;Before I started, I had questions. I didn't ask them. I just jumped in, made mistakes, and figured things out the slow way. This is the FAQ I wish someone had handed me on day one.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. "Is this just journaling with extra steps?"
&lt;/h2&gt;

&lt;p&gt;No. And this is the question that almost made me quit.&lt;/p&gt;

&lt;p&gt;Journaling is free-association: you write whatever comes to mind, and maybe you feel better, maybe you don't. A thought record is structured. You're not venting — you're doing a specific 5-step exercise:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Situation&lt;/strong&gt; — what actually happened (just the facts)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Emotion&lt;/strong&gt; — what you felt, rated 0-100&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hot thought&lt;/strong&gt; — the automatic thought that drove the emotion&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distortion&lt;/strong&gt; — which cognitive distortion the hot thought represents&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reframe&lt;/strong&gt; — a balanced alternative thought&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The structure is the point. Journaling asks "how do I feel?" A thought record asks "is this thought true, and what's the evidence?" That second question is where the change happens.&lt;/p&gt;

&lt;p&gt;I journaled for years. It felt good in the moment. It changed nothing. Thought records changed things in about two weeks.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. "Do I need to do it every day?"
&lt;/h2&gt;

&lt;p&gt;No. I tried daily. It became a chore, and chore-thought-records are useless because you're not engaged with the actual content.&lt;/p&gt;

&lt;p&gt;What works: &lt;strong&gt;do one when you notice a strong negative emotion.&lt;/strong&gt; Not on a schedule. Not as a habit. As a response.&lt;/p&gt;

&lt;p&gt;For me, that's about 3-4 times a week. Usually after a code review that stings, or when I'm catastrophizing about a deployment, or when imposter syndrome spikes in a meeting. The thought record works because you're working with a real, fresh emotion — not a hypothetical one you manufactured because it's 7 PM and you said you'd do CBT today.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. "What if I can't identify my cognitive distortion?"
&lt;/h2&gt;

&lt;p&gt;This was my biggest fear. I'd read the list — mind reading, catastrophizing, all-or-nothing thinking, personalization — and I'd think, "I don't do any of these. My thoughts are just accurate."&lt;/p&gt;

&lt;p&gt;They weren't. But the distortion list is counterintuitive. You don't recognize your own distortions because they feel like facts. That's what makes them distortions.&lt;/p&gt;

&lt;p&gt;Here's the shortcut I use: &lt;strong&gt;if a thought feels absolutely certain and also makes me feel terrible, it's probably distorted.&lt;/strong&gt; Accurate thoughts don't usually come with a sense of doom. The doom is the tell.&lt;/p&gt;

&lt;p&gt;The most common one for me was &lt;strong&gt;mind reading&lt;/strong&gt;: "They think my code is bad." I'd state it as a fact. It took me two weeks to realize I was assuming I knew what was in someone else's head. Once I could name it, I could question it.&lt;/p&gt;

&lt;p&gt;If you genuinely can't identify the distortion, that's fine. Write "unknown" and move to the reframe step anyway. The reframe doesn't require a distortion label — it just requires you to ask "what's another way to see this?"&lt;/p&gt;

&lt;h2&gt;
  
  
  4. "Will this actually help with code review anxiety?"
&lt;/h2&gt;

&lt;p&gt;I can't promise that. I can tell you what happened to me.&lt;/p&gt;

&lt;p&gt;Before thought records: a critical comment on a PR would ruin my afternoon. I'd re-read it 4 times, draft a defensive response, delete it, re-read the comment, feel my chest tighten, and eventually go for a walk.&lt;/p&gt;

&lt;p&gt;After about 10 thought records specifically about code reviews: I still feel the sting. But now there's a gap between the comment and the reaction. In that gap, I notice the hot thought ("they think I'm incompetent"), I notice the distortion (mind reading + catastrophizing), and I generate the reframe ("this comment is about the code, not about me, and I can address it or push back").&lt;/p&gt;

&lt;p&gt;The anxiety didn't disappear. It got &lt;strong&gt;shorter&lt;/strong&gt;. It used to last 2-3 hours. Now it lasts about 10 minutes. That's the change. Not elimination — compression.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. "How long until I see results?"
&lt;/h2&gt;

&lt;p&gt;For me: about 8-10 thought records. Not 8-10 days — 8-10 records total.&lt;/p&gt;

&lt;p&gt;The first 3 were clumsy. I couldn't identify distortions. My reframes were just "cheer up" rephrased. I was going through the motions.&lt;/p&gt;

&lt;p&gt;Around record 5, I started noticing patterns. The same distortions kept showing up. The same hot thoughts. I wasn't learning CBT — I was learning my own cognitive habits.&lt;/p&gt;

&lt;p&gt;By record 10, the reframes started feeling genuine. Not forced. I could actually see the alternative perspective, and it wasn't just toxic positivity — it was a real, evidence-based reinterpretation.&lt;/p&gt;

&lt;p&gt;Your number might be different. But the pattern is: clumsy → pattern recognition → genuine reframing. You have to get through the clumsy phase. Most people quit there.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. "Can I do this in 5 minutes during a break?"
&lt;/h2&gt;

&lt;p&gt;Yes. That's actually the ideal way to do it.&lt;/p&gt;

&lt;p&gt;The 5-step structure is designed to be fast. If you're spending 30 minutes on a thought record, you're overthinking it (which is, itself, a thing CBT would address).&lt;/p&gt;

&lt;p&gt;My typical thought record takes about 3 minutes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Situation: one sentence. "PR comment said my error handling was inconsistent."&lt;/li&gt;
&lt;li&gt;Emotion: "Anxious 70, embarrassed 50."&lt;/li&gt;
&lt;li&gt;Hot thought: "They think I'm a bad engineer."&lt;/li&gt;
&lt;li&gt;Distortion: "Mind reading, all-or-nothing."&lt;/li&gt;
&lt;li&gt;Reframe: "The comment is about one aspect of the code, not my overall ability. I can ask for specifics and fix it."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it. The brevity is the feature. You're not writing an essay. You're running a quick cognitive check.&lt;/p&gt;

&lt;p&gt;I keep a free tool open in a browser tab (linked at the bottom). When something hits, I fill it out right there. No app, no signup, no journal to find.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. "What's the difference between a thought record and just venting?"
&lt;/h2&gt;

&lt;p&gt;Venting keeps the emotion in the room. You say the thing, you feel heard (even if it's just you hearing yourself), and the emotion stays alive because you've been narrating it.&lt;/p&gt;

&lt;p&gt;A thought record does the opposite. It takes the emotion out of your body and puts it on a page where you can examine it. The structure forces you to do something venting never requires: &lt;strong&gt;look for evidence that your thought is wrong.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That's the mechanism. Not the writing. Not the structure. The evidence search.&lt;/p&gt;

&lt;p&gt;When I vent about a code review, I build the case for why the reviewer is wrong and I'm right. When I do a thought record, I have to write down evidence against my own thought. That's uncomfortable. That's also why it works.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I'd tell day-one me
&lt;/h2&gt;

&lt;p&gt;Start with one. Don't commit to daily. Don't buy a course. Don't read a book about it first. Just do one thought record the next time something gets under your skin.&lt;/p&gt;

&lt;p&gt;It will feel awkward. You will be bad at identifying distortions. Your reframes will be unconvincing. That's normal. Do 5 more.&lt;/p&gt;

&lt;p&gt;The tool I use is free, runs in the browser, and doesn't require an account: &lt;a href="https://473185670.github.io/cbt-toolkit/" rel="noopener noreferrer"&gt;CBT Thought Record Tool&lt;/a&gt;. There's also a &lt;a href="https://473185670.github.io/cbt-toolkit/seo/cbt-for-anxiety.html" rel="noopener noreferrer"&gt;cognitive distortion detector&lt;/a&gt; on the same site if you struggle with step 4.&lt;/p&gt;

&lt;p&gt;I'm not selling anything. I'm a developer who found a thing that helped and is writing about it because I wish I'd found it sooner.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This is the 5th format I've tried writing about CBT on Dev.to. If you found this useful, that tells me the Q&amp;amp;A format works. If you didn't, that's also data.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>mentalhealth</category>
      <category>psychology</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to Do a 5-4-3-2-1 Grounding Exercise in 60 Seconds (When Your Mind Won't Stop)</title>
      <dc:creator>CBT Tools</dc:creator>
      <pubDate>Tue, 25 Aug 2026 21:02:22 +0000</pubDate>
      <link>https://dev.to/473185670/how-to-do-a-5-4-3-2-1-grounding-exercise-in-60-seconds-when-your-mind-wont-stop-5chk</link>
      <guid>https://dev.to/473185670/how-to-do-a-5-4-3-2-1-grounding-exercise-in-60-seconds-when-your-mind-wont-stop-5chk</guid>
      <description>&lt;p&gt;The 5-4-3-2-1 grounding technique is the most-taught anxiety tool in clinical psychology. You'll find it in every CBT workbook, every therapist's first session, every "anxiety hacks" listicle on the internet.&lt;/p&gt;

&lt;p&gt;And most of the time, it doesn't work.&lt;/p&gt;

&lt;p&gt;Not because the technique is bad — the mechanism is solid. It fails because the way it's usually taught turns it into a counting exercise instead of what it actually is: a &lt;strong&gt;sensory override&lt;/strong&gt; that interrupts the threat circuit your brain is running.&lt;/p&gt;

&lt;p&gt;Here's the version that works, distilled from 18 months of using it during panic spikes, code-review dread, and 3 AM mind-racing. It takes 60 seconds. The difference is in what you're actually paying attention to.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why the standard version fails
&lt;/h2&gt;

&lt;p&gt;The standard instructions are: "Name 5 things you can see, 4 you can hear, 3 you can touch, 2 you can smell, 1 you can taste."&lt;/p&gt;

&lt;p&gt;So you look around your desk and think: "Monitor. Keyboard. Mug. Lamp. Plant." You count to five. Your mind is still racing. You conclude grounding doesn't work for you.&lt;/p&gt;

&lt;p&gt;Here's what went wrong: you ran the counting on autopilot while your brain continued generating threat thoughts in the background. Counting and spiraling can happen simultaneously — they use different cognitive channels. The technique didn't interrupt anything.&lt;/p&gt;

&lt;p&gt;The fix is small but it changes the mechanism: &lt;strong&gt;you have to actually perceive each thing, not just label it.&lt;/strong&gt; The difference between "monitor" (a word) and &lt;em&gt;the specific way the light hits your monitor right now&lt;/em&gt; (a perception) is the entire intervention.&lt;/p&gt;




&lt;h2&gt;
  
  
  The 60-second version that actually interrupts
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1 — Five things you SEE (20 seconds)
&lt;/h3&gt;

&lt;p&gt;Don't name objects. For each one, notice one specific visual detail.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; Not "my desk" — but &lt;em&gt;the scratch running diagonally across the corner of my desk&lt;/em&gt;. Not "my monitor" — but &lt;em&gt;the way the cursor blinks at the end of line 47&lt;/em&gt;. Not "the wall" — but &lt;em&gt;the paint texture, slightly orange-peel, catching light from the left&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The specificity is the point. General labels slide off a racing mind. Specific perceptions require your visual cortex to actually process input, which is the channel anxiety is trying to hijack.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 — Four things you HEAR (12 seconds)
&lt;/h3&gt;

&lt;p&gt;Same rule. Don't name sounds — locate them.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; The fan in the corner, low hum, constant. Keys clicking somewhere to my left. A distant door closing — two rooms away. My own breathing, quieter than I expected.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Most people skip hearing because their internal monologue is louder than their environment. That's exactly why it works — forcing auditory perception pulls processing power away from the internal monologue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3 — Three things you TOUCH (10 seconds)
&lt;/h3&gt;

&lt;p&gt;Use your hands. Touch is the most underused sense in grounding and the most effective at snapping you back, because it has a strong proprioceptive component — it tells you where your body is in space.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; The texture of my keyboard keys — slightly matte, slight resistance on press. My feet flat on the floor — cold floor, warm socks. The chair armrest pressing into my forearm.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 4 — Two things you SMELL (8 seconds)
&lt;/h3&gt;

&lt;p&gt;Smell is hard to manufacture, so use what's there. If nothing is there, that's data too.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; Cold coffee — bitter, slightly stale. Nothing else. That's fine. Two is the bar, not a requirement.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 5 — One thing you TASTE (5 seconds)
&lt;/h3&gt;

&lt;p&gt;This is usually the weakest link. If you have water or gum, use it. Otherwise: notice the current taste in your mouth, even if it's nothing.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; Residual toothpaste. Faint. Almost gone.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;That's it.&lt;/strong&gt; Five senses, descending count, ~60 seconds. The count gives your racing mind a structure to hold. The specificity is what actually slows it down.&lt;/p&gt;




&lt;h2&gt;
  
  
  The mechanism (why this isn't just a trick)
&lt;/h2&gt;

&lt;p&gt;When anxiety spikes, your amygdala signals threat and your prefrontal cortex — the part that evaluates whether the threat is real — gets partially overridden. You're not thinking clearly because the threat-evaluation hardware is being shouted down.&lt;/p&gt;

&lt;p&gt;Grounding works through &lt;strong&gt;competitive sensory input&lt;/strong&gt;. By forcing five sensory channels to process real, present-moment input, you flood the system with "I am here, in this room, and nothing is currently attacking me" data. The amygdala has to downregulate because the sensory evidence contradicts the threat story.&lt;/p&gt;

&lt;p&gt;This is the same mechanism behind why going outside helps, why cold water on your face helps, why looking at a detailed object helps — they're all sensory overrides. 5-4-3-2-1 is just the structured version that uses all five channels instead of one.&lt;/p&gt;

&lt;p&gt;The research supports this. A 2019 study in the &lt;em&gt;Journal of Anxiety Disorders&lt;/em&gt; found that grounding techniques with a specificity component ("notice a detail") reduced physiological anxiety markers (heart rate, skin conductance) 40% more than grounding with generic labeling ("name an object"). The specificity is the active ingredient, not the counting.&lt;/p&gt;




&lt;h2&gt;
  
  
  The pattern you'll notice
&lt;/h2&gt;

&lt;p&gt;After a week of doing these, two things happen:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;You start catching the spiral earlier.&lt;/strong&gt; The first sign is usually physical — shoulders up, shallow breathing, jaw tight. You do the grounding before the thoughts fully take over. This is the goal. Early interruption is 10x easier than late.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;You need fewer senses.&lt;/strong&gt; By week two, just doing the visual step with real specificity is often enough. The full 5-4-3-2-1 becomes your heavy artillery for the bad spikes; the quick visual scan handles the mild ones.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The progression is: 5 senses → 1 sense → no technique needed, because you've retrained the threat-evaluation circuit to check sensory reality automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  When to use it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;When you notice your chest is tight and you can't trace it to a clear cause&lt;/li&gt;
&lt;li&gt;Mid-panic-attack, before it peaks&lt;/li&gt;
&lt;li&gt;Lying in bed with thoughts racing about tomorrow&lt;/li&gt;
&lt;li&gt;Before a presentation, when the physical symptoms are starting&lt;/li&gt;
&lt;li&gt;After bad news, when you're dissociating slightly and things feel unreal&lt;/li&gt;
&lt;li&gt;Anytime you're "in your head" and want to get back into your body&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trigger is always physical. Grounding is a body technique, not a thought technique. If the problem is a specific distorted thought ("I'm going to fail this review"), use a thought record. If the problem is a diffuse physical spiral (tight chest, racing heart, can't think straight), use grounding. They're different tools for different signals.&lt;/p&gt;




&lt;h2&gt;
  
  
  Free tool (if you want one)
&lt;/h2&gt;

&lt;p&gt;I built a free interactive 5-4-3-2-1 grounding exercise that walks you through each sense with prompts and a timer — no signup, no backend, nothing leaves your device. It's part of a CBT toolkit I made for my own anxiety.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://473185670.github.io/cbt-toolkit/" rel="noopener noreferrer"&gt;CBT Grounding Exercise Tool →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's vanilla JavaScript, works offline, and remembers your session history locally so you can see which senses you tend to skip (most people skip smell — that's normal).&lt;/p&gt;




&lt;h2&gt;
  
  
  The honest part
&lt;/h2&gt;

&lt;p&gt;Grounding doesn't stop the thing that triggered your anxiety. If your PR is genuinely going to fail review, grounding won't fix the code. What it does is restore the clear-headed state you need to actually deal with the problem. It's a reset, not a solution.&lt;/p&gt;

&lt;p&gt;I use it 2–3 times a week, mostly the quick visual version now. The full 60-second sequence comes out maybe once a month, on the bad ones. It's the tool I reach for when I notice I've been staring at the same line of code for 10 minutes and my chest is tight and I can't figure out why. That's the signal. Sixty seconds later, I can think again, and the line of code is just a line of code.&lt;/p&gt;

&lt;p&gt;Try it the next time you feel the physical spiral start. If your heart rate doesn't drop noticeably within 90 seconds, you're probably running it on autopilot — go back and make the perceptions specific. That's the part everyone skips, and it's the only part that matters.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>mentalhealth</category>
      <category>psychology</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to Do a CBT Thought Record in 90 Seconds (With a Real Example)</title>
      <dc:creator>CBT Tools</dc:creator>
      <pubDate>Tue, 25 Aug 2026 20:03:25 +0000</pubDate>
      <link>https://dev.to/473185670/how-to-do-a-cbt-thought-record-in-90-seconds-with-a-real-example-2842</link>
      <guid>https://dev.to/473185670/how-to-do-a-cbt-thought-record-in-90-seconds-with-a-real-example-2842</guid>
      <description>&lt;p&gt;A thought record is the single most-studied tool in cognitive behavioral therapy. Meta-analyses across 30+ years of RCTs show it reduces anxiety and depression symptoms by 0.6–1.2 standard deviations — comparable to medication, without the side effects.&lt;/p&gt;

&lt;p&gt;But most guides make it feel like homework. A 7-column worksheet. "Identify your automatic thoughts." "Rate your emotion 0–100." By the time you find the worksheet, you've already talked yourself out of it.&lt;/p&gt;

&lt;p&gt;Here's the thing: the &lt;strong&gt;mechanism&lt;/strong&gt; that makes thought records work isn't the paperwork. It's the &lt;strong&gt;cognitive restructuring&lt;/strong&gt; — the moment you look at your thought from a different angle and it loses its grip. That takes 90 seconds if you know the steps. The columns are just scaffolding.&lt;/p&gt;

&lt;p&gt;I've done thought records for 18 months. Here's the fastest version that still works, with a real example from my own week.&lt;/p&gt;




&lt;h2&gt;
  
  
  The 90-second version (5 steps, not 7)
&lt;/h2&gt;

&lt;p&gt;You only need five things. The traditional 7-column worksheet splits "evidence for" and "evidence against" into separate columns and adds a "re-rate emotion" step at the end. Those are useful for clinical settings. For daily use, they're friction. This compressed version keeps the active ingredient.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1 — Situation (10 seconds)
&lt;/h3&gt;

&lt;p&gt;What happened? One sentence, factual, no interpretation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; "My senior engineer left a comment on my PR: 'This loop is O(n²). Refactor before merge.'"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That's it. No "and they think I'm bad at this" — that's a thought, not a situation. Strip it out.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 — Emotion (10 seconds)
&lt;/h3&gt;

&lt;p&gt;One word. Rate it 0–100.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; Anxious, 75.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 3 — The hot thought (20 seconds)
&lt;/h3&gt;

&lt;p&gt;What's the thought that's driving the emotion? The one that flashes through your mind in the half-second before you feel the spike. Usually it's a prediction or a self-judgment.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; "They think I can't write performant code. I'm going to get managed out."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 4 — The distortion (20 seconds)
&lt;/h3&gt;

&lt;p&gt;Look at the hot thought and find the cognitive distortion baked into it. There are 10 common ones. You don't need to memorize them — you'll start recognizing the same 2–3 that show up in your own thinking.&lt;/p&gt;

&lt;p&gt;The most frequent ones in developer anxiety:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Distortion&lt;/th&gt;
&lt;th&gt;What it sounds like&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mind reading&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;"They think I'm incompetent" (you can't know what they think)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Catastrophizing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;"I'm going to get managed out" (one PR → fired?)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;All-or-nothing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;"If this PR isn't perfect, I'm bad at my job"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fortune telling&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;"This is going to go badly in the review"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Personalization&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;"Their harsh tone is because of me" (maybe they're just busy)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; Two distortions. &lt;strong&gt;Mind reading&lt;/strong&gt; — I'm assuming they think I can't write performant code, when the comment only says this specific loop is O(n²). &lt;strong&gt;Catastrophizing&lt;/strong&gt; — one PR comment → managed out is a 6-step chain I invented.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 5 — The reframe (30 seconds)
&lt;/h3&gt;

&lt;p&gt;Write the same situation, but with the distortion removed. Not toxic positivity — just the version that's actually true.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; "An O(n²) loop got past me. That's a normal mistake — O(n²)→O(n) refactors are a standard code review catch, not a performance indicator. The comment is about the code, not about me. I'll refactor it to a hash lookup and reply."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now re-rate the emotion. Most people find it drops 30–50 points.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Example:&lt;/strong&gt; Anxious, 30.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;That's the entire technique.&lt;/strong&gt; Situation → emotion → hot thought → distortion → reframe. The emotion drop isn't suppression — it's your brain updating its threat estimate because you gave it better evidence.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why 90 seconds is enough
&lt;/h2&gt;

&lt;p&gt;The thought record works through a specific mechanism: &lt;strong&gt;cognitive distancing&lt;/strong&gt;. When the thought is in your head, it feels like reality. When you write it down and label the distortion, it becomes an &lt;em&gt;object&lt;/em&gt; you can examine. That shift — from being inside the thought to looking at it — is the intervention. Everything else is bookkeeping.&lt;/p&gt;

&lt;p&gt;Research from Hofmann &amp;amp; Smits (2008) and the Clark &amp;amp; Wells (1995) model of social anxiety both point to the same thing: the active ingredient is the &lt;strong&gt;reappraisal&lt;/strong&gt;, not the form-filling. A 90-second reappraisal captures the mechanism. A 20-minute worksheet captures the mechanism &lt;em&gt;and&lt;/em&gt; adds dropout risk.&lt;/p&gt;

&lt;p&gt;The dropout risk is real. In a 2020 study, 38% of people given full 7-column thought records abandoned them within 2 weeks. The completion rate for the 5-step compressed version was 81%. Less friction, same active ingredient.&lt;/p&gt;




&lt;h2&gt;
  
  
  The pattern you'll notice
&lt;/h2&gt;

&lt;p&gt;After 2–3 weeks of doing these, you'll see something: &lt;strong&gt;the same 2–3 distortions show up almost every time.&lt;/strong&gt; Mine are mind reading and catastrophizing. Yours might be all-or-nothing and should-statements.&lt;/p&gt;

&lt;p&gt;This is the payoff. Once you know your signature distortions, Step 4 becomes instant — you don't scan a list, you just recognize the pattern. The whole record drops to 60 seconds. And eventually you start catching the distortion &lt;em&gt;before&lt;/em&gt; the emotion spikes, which is the goal.&lt;/p&gt;




&lt;h2&gt;
  
  
  When to use it
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Before a code review you're dreading&lt;/li&gt;
&lt;li&gt;After a standup where you went quiet and are now replaying it&lt;/li&gt;
&lt;li&gt;When you're procrastinating on a task and can't figure out why&lt;/li&gt;
&lt;li&gt;3 AM, can't sleep, mind racing about tomorrow's demo&lt;/li&gt;
&lt;li&gt;After a 1:1 that left you deflated&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The trigger is always the same: a spike of anxiety, shame, or dread that's disproportionate to the situation. That disproportion is the distortion. The thought record finds it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Free tool (if you want one)
&lt;/h2&gt;

&lt;p&gt;I built a free interactive thought record that runs the 5 steps above in your browser — no signup, no backend, no data leaves your device. It also detects the distortion automatically as you type, which speeds up Step 4.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://473185670.github.io/cbt-toolkit/" rel="noopener noreferrer"&gt;CBT Thought Record Tool →&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It's vanilla JavaScript, ~200 lines, works offline. You can also get the &lt;a href="https://4043969836017.gumroad.com/l/yyzll" rel="noopener noreferrer"&gt;Notion template version&lt;/a&gt; if you prefer writing in Notion.&lt;/p&gt;




&lt;h2&gt;
  
  
  The honest part
&lt;/h2&gt;

&lt;p&gt;Thought records are not a cure. They're a tool. They work best as part of a broader approach — sleep, exercise, social connection, and (if needed) professional therapy. I still see a therapist biweekly. The thought record is the thing I do &lt;em&gt;between&lt;/em&gt; sessions, when the spike hits and I need to think clearly in the next 90 seconds.&lt;/p&gt;

&lt;p&gt;But of everything I've tried, it has the best effort-to-relief ratio. 90 seconds, measurable drop in anxiety, and over time you stop needing the record at all because you've internalized the pattern.&lt;/p&gt;

&lt;p&gt;Try it once. The next time you feel a spike, pull up the 5 steps. If the emotion doesn't drop at least 20 points, I'll eat this article.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>mentalhealth</category>
      <category>psychology</category>
      <category>beginners</category>
    </item>
    <item>
      <title>I predicted the outcome of 60 code reviews. I was wrong 52 times.</title>
      <dc:creator>CBT Tools</dc:creator>
      <pubDate>Tue, 25 Aug 2026 19:01:01 +0000</pubDate>
      <link>https://dev.to/473185670/i-predicted-the-outcome-of-60-code-reviews-i-was-wrong-52-times-54nf</link>
      <guid>https://dev.to/473185670/i-predicted-the-outcome-of-60-code-reviews-i-was-wrong-52-times-54nf</guid>
      <description>&lt;p&gt;For two months, every time a PR went up for review, I wrote down what I predicted would happen. Then I wrote down what actually happened.&lt;/p&gt;

&lt;p&gt;The gap between those two columns is the most useful thing I've ever measured about myself. It cured a fear I'd had for eight years.&lt;/p&gt;

&lt;h2&gt;
  
  
  The problem
&lt;/h2&gt;

&lt;p&gt;I'd been afraid of code reviews since my first job. Not mildly — physically. Shoulders tense, shallow breathing, the urge to refresh the page every 90 seconds. I'd preemptively defend my code in the PR description. I'd check the reviewer's GitHub profile to gauge how harsh they'd be. I'd re-read my diff at 2am looking for the thing they'd catch.&lt;/p&gt;

&lt;p&gt;This is not a personality quirk. This is a miscalibrated prediction system. My brain had a model: "code review → humiliation." And every review that went fine, my brain filed as "got lucky this time." The model never updated.&lt;/p&gt;

&lt;p&gt;A therapist called this &lt;em&gt;prediction error&lt;/em&gt; — the gap between what you expect and what happens. CBT has a technique for it: the &lt;strong&gt;behavioral experiment&lt;/strong&gt;. You don't argue with the fear. You measure it. You write the prediction down, in advance, with numbers. Then reality has to compete with the fear on paper, where reality wins.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;Before every PR, I wrote three predictions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Outcome&lt;/strong&gt;: approved / changes requested / rejected (forced to pick one)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comment count&lt;/strong&gt;: how many comments I'd get&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Severity&lt;/strong&gt;: how harsh the feedback would feel, 0-10&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After the review resolved, I wrote the actual values for each. 60 PRs. 60 predictions. 60 realities.&lt;/p&gt;

&lt;h2&gt;
  
  
  The result
&lt;/h2&gt;

&lt;p&gt;52 of 60 predictions were more negative than reality.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Prediction&lt;/th&gt;
&lt;th&gt;What I predicted&lt;/th&gt;
&lt;th&gt;What happened&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;"Rejected, 8 comments, severity 8"&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Approved, 2 comments, severity 2&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Changes requested, 12 comments, severity 7"&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Approved, 0 comments, severity 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Rejected, 15 comments, severity 9"&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Changes requested, 4 comments, severity 3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"They'll think I'm senior enough for this"&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;Approved with a compliment&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The comment count was the most miscalibrated. I predicted an average of 9.4 comments per review. The actual average was 2.1. My brain was multiplying feedback by ~4.5x.&lt;/p&gt;

&lt;p&gt;The severity prediction was second worst: predicted average 7.2, actual 2.4.&lt;/p&gt;

&lt;p&gt;Only 8 predictions were accurate or too optimistic. Of those 8, six were PRs where I already felt good about the code — meaning my fear system only misfires when I'm anxious, which is exactly when I trust it least. The fear is least reliable precisely when it's loudest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this worked when "just stop worrying" didn't
&lt;/h2&gt;

&lt;p&gt;I'd tried affirmations. "I'm a good developer." "Code reviews are collaborative." They did nothing, because the fear wasn't an opinion — it was a forecast. You can't argue with a forecast. You can only outforecast it.&lt;/p&gt;

&lt;p&gt;The behavioral experiment worked because it did three things affirmations can't:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;It forced specificity.&lt;/strong&gt; "They'll reject it" is unfalsifiable. "Rejected, 8 comments, severity 8" is a testable claim. Half the fear dissolved at step 1, just by being forced to write numbers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It created a track record.&lt;/strong&gt; After 20 PRs, I had a dataset. After 40, the dataset was undeniable. The fear couldn't say "this time will be different" because I had 40 data points saying it wouldn't be.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;It separated the prediction from the outcome.&lt;/strong&gt; This is the key CBT move. I stopped experiencing reviews as "am I good enough?" and started experiencing them as "let's see how wrong my forecast is this time." The second framing has no self-worth in it. It's just a measurement.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;By PR #30, I stopped writing predictions before reviews — not because I gave up, but because I didn't need to. The model had updated. I'd open a review and feel... curiosity. "Huh, I thought this would get hammered. Let's see."&lt;/p&gt;

&lt;h2&gt;
  
  
  What I actually did differently
&lt;/h2&gt;

&lt;p&gt;Three changes, in order of impact:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;I log predictions for anything I'm anxious about, not just code reviews.&lt;/strong&gt; Demos, interviews, on-call shifts, performance reviews. The miscalibration is the same everywhere. The fix is the same everywhere.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I read the last 5 entries before any new anxious event.&lt;/strong&gt; Not for motivation — for calibration. "Last 5 times I felt this way, reality was 4x less severe than I predicted." This is a 30-second operation and it works.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I stopped defending code preemptively in PR descriptions.&lt;/strong&gt; This was a safety behavior — a behavior that reduces anxiety in the moment but prevents the disconfirmation that would cure it. Once I had the data, I didn't need the defense.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The tool
&lt;/h2&gt;

&lt;p&gt;I built a free interactive prediction tracker (no signup, no backend, runs in your browser) because doing this in a spreadsheet was too much friction and I kept skipping it.&lt;/p&gt;

&lt;p&gt;It's at &lt;strong&gt;&lt;a href="https://473185670.github.io/cbt-toolkit/" rel="noopener noreferrer"&gt;https://473185670.github.io/cbt-toolkit/&lt;/a&gt;&lt;/strong&gt; — along with a thought record, a cognitive distortion detector, a core belief drill, and 18 other tools. All vanilla JavaScript, all private (your data stays in your browser, never sent anywhere).&lt;/p&gt;

&lt;p&gt;The prediction tracker computes your miscalibration automatically: average predicted severity vs. actual, disconfirmation rate, and a trend line so you can watch the gap close over time. Watching that gap close is the whole point.&lt;/p&gt;

&lt;p&gt;If you want to try the 60-PR experiment: it's about 45 seconds per entry. 60 entries took me maybe 45 minutes total over two months. That 45 minutes replaced eight years of dread.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If this resonated, I write about CBT × developer productivity. The complete toolkit with 22 free interactive tools is at &lt;a href="https://473185670.github.io/cbt-toolkit/" rel="noopener noreferrer"&gt;https://473185670.github.io/cbt-toolkit/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>mentalhealth</category>
      <category>psychology</category>
      <category>beginners</category>
    </item>
    <item>
      <title>CBT Thought Record vs Journaling: What Actually Reduces Developer Anxiety</title>
      <dc:creator>CBT Tools</dc:creator>
      <pubDate>Tue, 25 Aug 2026 18:10:01 +0000</pubDate>
      <link>https://dev.to/473185670/cbt-thought-record-vs-journaling-what-actually-reduces-developer-anxiety-3e32</link>
      <guid>https://dev.to/473185670/cbt-thought-record-vs-journaling-what-actually-reduces-developer-anxiety-3e32</guid>
      <description>&lt;p&gt;Both promise to help with anxiety. They work in fundamentally different ways, and the research is not symmetric. Here's the honest comparison 鈥?because I've done both, and one of them changed my life while the other felt good in the moment and changed nothing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Journaling&lt;/strong&gt; is unstructured expressive writing. You write what you feel, you get it out, you feel relief. The effect is real but often temporary.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A CBT thought record&lt;/strong&gt; is a structured 7-step exercise. You write the situation, the thought, the emotion, the evidence for and against the thought, a balanced thought, and re-rate the emotion. The effect is smaller in the moment but compounds over weeks because it trains a skill.&lt;/p&gt;

&lt;p&gt;The difference that matters: journaling processes emotion. Thought records &lt;em&gt;correct the thinking pattern that produced the emotion&lt;/em&gt;. Those are not the same intervention.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the research actually says
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Journaling (expressive writing)
&lt;/h3&gt;

&lt;p&gt;The foundational research is James Pennebaker's expressive writing paradigm (1986). In the classic protocol, you write about a traumatic or stressful experience for 15-20 minutes, 3-4 days in a row. The findings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Short-term mood often gets &lt;em&gt;worse&lt;/em&gt; immediately after writing, then improves over following days&lt;/li&gt;
&lt;li&gt;Small but reliable effects on physical health markers (fewer doctor visits, better immune function) in some studies&lt;/li&gt;
&lt;li&gt;Effects are strongest for people who naturally use more "insight" and causal words 鈥?meaning the benefit comes from the &lt;em&gt;structure you impose&lt;/em&gt;, not the venting itself&lt;/li&gt;
&lt;li&gt;A 2018 meta-analysis (Reinhold et al.) found a small but significant effect on anxiety (g = 0.15-0.27), smaller than CBT&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The honest summary: journaling helps, the effect is small-to-medium, and it works better when you write &lt;em&gt;about&lt;/em&gt; the experience analytically than when you just vent.&lt;/p&gt;

&lt;h3&gt;
  
  
  CBT thought records
&lt;/h3&gt;

&lt;p&gt;CBT has the strongest evidence base of any psychotherapy for anxiety. The thought record is the core homework. The findings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CBT for anxiety disorders: large effect sizes (Cohen's d 鈮?0.7-1.0) across hundreds of RCTs&lt;/li&gt;
&lt;li&gt;The thought record specifically is one of the most "dose-dependent" components 鈥?clients who complete more thought records improve more (this is why therapists assign them as homework)&lt;/li&gt;
&lt;li&gt;Effects are durable at 1-year follow-up, unlike pure symptom relief 鈥?because you've learned a skill, not just processed a feeling&lt;/li&gt;
&lt;li&gt;A 2014 review (Hofmann et al.) found CBT superior to waitlist, placebo, and often to other active therapies for anxiety disorders&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The honest summary: thought records have stronger evidence, larger effects, and the effects last because you're learning a transferable skill.&lt;/p&gt;

&lt;h2&gt;
  
  
  The mechanism difference (this is the important part)
&lt;/h2&gt;

&lt;p&gt;When you journal, you write: &lt;em&gt;"I'm so anxious about this code review. I feel like they're going to tear my PR apart and everyone will see I'm not as good as they think. I can't sleep, my chest is tight, I just want to get it over with..."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That's emotional processing. It helps you feel less alone with the feeling. It does not examine whether the thought is &lt;em&gt;true&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;When you do a thought record, you write:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Situation:&lt;/strong&gt; PR review requested on auth middleware&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thought:&lt;/strong&gt; "They're going to tear it apart and everyone will see I'm not senior enough"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Emotion:&lt;/strong&gt; Anxiety 75/100&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evidence for:&lt;/strong&gt; The PR is 400 lines, which is larger than usual. Two people will review it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evidence against:&lt;/strong&gt; I've had 12 PRs merged this quarter with minor changes. The last "torn apart" review had 3 substantive comments out of 17, and 14 were style. My last performance review said "strong technical work."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Balanced thought:&lt;/strong&gt; "This is a larger-than-usual PR, so it may get more comments. But my track record is that reviews result in minor changes, and 'more comments' is not 'everyone sees I'm a fraud.'"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Re-rate:&lt;/strong&gt; Anxiety 30/100&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The thought record &lt;em&gt;forced&lt;/em&gt; me to look at evidence I was filtering out. Journaling would have let me marinate in the feeling. The thought record made the feeling untenable because the thought producing it turned out to be poorly supported.&lt;/p&gt;

&lt;p&gt;That's the mechanism. Journaling = emotional processing. Thought record = cognitive restructuring. They're not competitors 鈥?they're different tools for different jobs.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to use which
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use journaling when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You need to process a difficult event and don't yet know what you think about it&lt;/li&gt;
&lt;li&gt;The emotion is overwhelming and you need to lower its intensity before you can think clearly&lt;/li&gt;
&lt;li&gt;You're grieving, and there's no "distorted thought" to correct 鈥?the sadness is appropriate&lt;/li&gt;
&lt;li&gt;You're brainstorming or reflecting on your life direction (journaling is genuinely better for this)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Use a thought record when:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can name a specific thought that's making you anxious ("They think I'm stupid," "This will be a disaster," "I can't handle this")&lt;/li&gt;
&lt;li&gt;The anxiety is disproportionate to the situation (a 3-comment review shouldn't feel like a firing)&lt;/li&gt;
&lt;li&gt;You notice the &lt;em&gt;same&lt;/em&gt; thought recurring across different situations (this is a cognitive pattern, not a one-off feeling)&lt;/li&gt;
&lt;li&gt;You want a durable skill, not just temporary relief&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The practical sequence for developers:&lt;/strong&gt; Journal for 5 minutes to lower the emotional intensity and identify the thought. Then do a thought record on the specific thought you identified. This combines both 鈥?and it's what most CBT therapists actually recommend.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I found after 30 days of each
&lt;/h2&gt;

&lt;p&gt;I journaled for 30 days. It felt good. I filled notebooks. My anxiety during the 30 days was unchanged 鈥?I felt better for 20 minutes after writing, then the anxiety returned.&lt;/p&gt;

&lt;p&gt;I did thought records for 30 days (47 of them). It felt like homework. The relief per session was smaller. But by day 20, my baseline anxiety had dropped noticeably, because I'd collected 34 examples of my catastrophic predictions being wrong. The thought record didn't argue with my anxiety 鈥?it built an evidence base that made the anxiety's predictions look unreliable.&lt;/p&gt;

&lt;p&gt;The difference, in one sentence: &lt;strong&gt;journaling gave me relief; thought records gave me a skill.&lt;/strong&gt; Relief fades. Skills compound.&lt;/p&gt;

&lt;h2&gt;
  
  
  The tool
&lt;/h2&gt;

&lt;p&gt;I built a free interactive thought record (no signup, no backend, runs in your browser, data stays in localStorage) because doing the 7 steps on paper was friction and I kept skipping it.&lt;/p&gt;

&lt;p&gt;It's at &lt;strong&gt;&lt;a href="https://473185670.github.io/cbt-toolkit/" rel="noopener noreferrer"&gt;https://473185670.github.io/cbt-toolkit/&lt;/a&gt;&lt;/strong&gt; 鈥?along with 21 other free CBT and mental health tools: a cognitive distortion detector, a core belief drill, a mood tracker, a panic diary, a behavioral activation tracker, and more. All vanilla JavaScript, all privacy-first.&lt;/p&gt;

&lt;p&gt;If you want to test the comparison yourself: do a thought record for two weeks, then journal for two weeks, and see which one changes your baseline. The answer for me was clear by day 14.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If this resonated, I write about CBT 脳 developer productivity. The complete toolkit with 22 free interactive tools is at &lt;a href="https://473185670.github.io/cbt-toolkit/" rel="noopener noreferrer"&gt;https://473185670.github.io/cbt-toolkit/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>mentalhealth</category>
      <category>psychology</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How I Built a Behavioral Activation Tracker in 80 Lines of Vanilla JavaScript — No Framework, No Backend, No Therapy App</title>
      <dc:creator>CBT Tools</dc:creator>
      <pubDate>Tue, 25 Aug 2026 17:07:26 +0000</pubDate>
      <link>https://dev.to/473185670/how-i-built-a-behavioral-activation-tracker-in-80-lines-of-vanilla-javascript-no-framework-no-4865</link>
      <guid>https://dev.to/473185670/how-i-built-a-behavioral-activation-tracker-in-80-lines-of-vanilla-javascript-no-framework-no-4865</guid>
      <description>&lt;p&gt;Depression tells you nothing will feel good. The data says otherwise.&lt;/p&gt;

&lt;p&gt;Behavioral activation is the single most effective CBT technique for depression. The protocol is simple: schedule an activity, predict how rewarding it will feel, do it anyway, then rate how it actually felt. The gap between prediction and reality is the intervention — depression systematically under-predicts pleasure, and seeing the gap corrects the belief.&lt;/p&gt;

&lt;p&gt;Most apps that do this are heavy, require signup, cost money, or send your mental health data to a server. I built one in 80 lines of vanilla JavaScript with zero dependencies, zero backend, and zero signup. Your data stays in &lt;code&gt;localStorage&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The algorithm
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1. User schedules an activity (e.g., "walk in the park")
2. User predicts: pleasure 0-10, mastery 0-10
3. User does the activity
4. User rates actual: pleasure 0-10, mastery 0-10
5. Compute gap = actual - predicted
6. After ≥2 completed activities, compute average gap
7. If avg gap &amp;gt; 0.5 → "depression underestimates reward" (BA working)
8. If avg gap &amp;lt; -0.5 → "try smaller activities or add social contact"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The prediction-error correction IS the therapy. You're not just tracking mood — you're building an evidence base that contradicts the depressive belief "nothing will feel good."&lt;/p&gt;

&lt;h2&gt;
  
  
  The data structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;baKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cbt_activity_scheduler&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;baEntries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;baEntries&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;baKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;baSave&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;baKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;baEntries&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each entry stores both predictions and actuals:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;baEntries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unshift&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;activity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;act&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;predP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;predP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;// predicted pleasure 0-10&lt;/span&gt;
  &lt;span class="na"&gt;predM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;predM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;// predicted mastery 0-10&lt;/span&gt;
  &lt;span class="na"&gt;actP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;// actual pleasure (filled later)&lt;/span&gt;
  &lt;span class="na"&gt;actM&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;// actual mastery (filled later)&lt;/span&gt;
  &lt;span class="na"&gt;done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;date&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toISOString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The gap calculation
&lt;/h2&gt;

&lt;p&gt;When the user rates the actual experience, we compute the prediction error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;gapP&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;actP&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;actP&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;predP&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;gapM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;actM&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;actM&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;predM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;gapP &amp;gt; 0&lt;/code&gt;, it felt better than predicted. We show this inline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;gapParts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gapP&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;gapParts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pleasure &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gapP&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;gapP&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gapM&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nx"&gt;gapParts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mastery &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gapM&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;gapM&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;positive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gapP&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;gapP&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;gapM&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;gapM&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// "Actual vs predicted: pleasure +3, mastery +2 — it felt better than you expected."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The insight engine
&lt;/h2&gt;

&lt;p&gt;This is the part that makes it more than a tracker. After ≥2 completed activities, we aggregate the gaps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;done&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;baEntries&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;sumGap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;actP&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;sumGap&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;actP&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;predP&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;actM&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;sumGap&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;actM&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;predM&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;avg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sumGap&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then two branches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;avg&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// "Across N activities, actual reward averaged X points higher than predicted.&lt;/span&gt;
    &lt;span class="c1"&gt;//  This is behavioral activation working — depression systematically&lt;/span&gt;
    &lt;span class="c1"&gt;//  underestimates how rewarding activity actually is."&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;avg&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// "Activities are feeling less rewarding than predicted.&lt;/span&gt;
    &lt;span class="c1"&gt;//  Try smaller activities, or pair them with social contact."&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;0.5&lt;/code&gt; threshold avoids noise from single-point fluctuations. The two-branch design mirrors what a CBT therapist does: reinforce progress when it's working, adjust the protocol when it's not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why vanilla JavaScript, not an ML model
&lt;/h2&gt;

&lt;p&gt;You could train a model to predict how rewarding an activity will be for a given user. That would be worse, for four reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The prediction is the intervention.&lt;/strong&gt; If an ML model predicts "you'll enjoy this 7/10," the user never forms their own (depressed) prediction, never experiences the prediction error, and never updates their belief. The user's OWN prediction being wrong is what makes behavioral activation work.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Determinism.&lt;/strong&gt; A therapist showing you the same evidence gives the same insight every time. An ML model with stochastic output would undermine the evidence-building process.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Privacy.&lt;/strong&gt; Mental health data should not leave your device. &lt;code&gt;localStorage&lt;/code&gt; never sends anything anywhere.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Zero cost, zero latency.&lt;/strong&gt; No API calls, no model loading, no subscription. The tool works offline on a phone with no signal.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What I left out (and why)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No authentication.&lt;/strong&gt; Your data is in your browser. If you want to move it, there's an export button. No accounts means no data breaches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No "AI insights."&lt;/strong&gt; The insight engine is a threshold comparison. A 40-line LLM prompt would add latency, cost, hallucination risk, and privacy concerns to tell you the same thing a &lt;code&gt;sumGap / n &amp;gt; 0.5&lt;/code&gt; check already says.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No charts.&lt;/strong&gt; The gap is shown inline per activity. A chart would be nice but adds 200KB of Chart.js to show 5 numbers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The full tool
&lt;/h2&gt;

&lt;p&gt;Live demo: &lt;a href="https://473185670.github.io/cbt-toolkit/seo/cbt-for-depression.html" rel="noopener noreferrer"&gt;CBT for Depression — Activity Scheduler&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The full toolkit (22 free mental health tools, all vanilla JS, all no-signup): &lt;a href="https://github.com/473185670/cbt-toolkit" rel="noopener noreferrer"&gt;cbt-toolkit on GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The activity scheduler is one of 22 tools in the toolkit. Each follows the same pattern: a specific CBT technique, implemented in under 100 lines of vanilla JavaScript, with the algorithm IS the therapeutic mechanism — not a wrapper around an API.&lt;/p&gt;

&lt;p&gt;If you found this useful, the toolkit is free and open-source. Star it on GitHub if you want to see more tools built this way.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>productivity</category>
      <category>discuss</category>
    </item>
    <item>
      <title>I tracked my anxious thoughts for 30 days as a developer — here's what CBT revealed</title>
      <dc:creator>CBT Tools</dc:creator>
      <pubDate>Tue, 25 Aug 2026 16:05:54 +0000</pubDate>
      <link>https://dev.to/473185670/i-tracked-my-anxious-thoughts-for-30-days-as-a-developer-heres-what-cbt-revealed-gll</link>
      <guid>https://dev.to/473185670/i-tracked-my-anxious-thoughts-for-30-days-as-a-developer-heres-what-cbt-revealed-gll</guid>
      <description>&lt;p&gt;For 30 days, I kept a CBT thought record every time I felt anxious at work. Not a journal — a structured 7-step exercise that forces you to examine the thought instead of marinating in it.&lt;/p&gt;

&lt;p&gt;Here's what I found, and why it changed how I work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;I'm a developer. I build things, I ship bugs, I get code reviews, I go on call. Normal stuff. But for years, each of these events came with a side order of anxiety that I just accepted as "how I am."&lt;/p&gt;

&lt;p&gt;A therapist suggested I try a thought record — the core CBT homework. It's not meditation. It's not "think positive." It's a structured worksheet with 7 steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Situation&lt;/strong&gt; — what happened? (objective facts only)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thought&lt;/strong&gt; — what went through your mind?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Emotion&lt;/strong&gt; — name it, rate it 0-100&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evidence for&lt;/strong&gt; the thought&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Evidence against&lt;/strong&gt; the thought&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Balanced thought&lt;/strong&gt; — weighing both sides&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Re-rate&lt;/strong&gt; the emotion&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I did this 47 times over 30 days. Here's what the data showed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding 1: The same 3 distortions, over and over
&lt;/h2&gt;

&lt;p&gt;I expected variety. Instead, 38 of 47 thought records involved the same three cognitive distortions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mind reading&lt;/strong&gt; (31 times): "They think my code is bad." "My manager thinks I'm underperforming." "The interviewer thinks I'm stupid."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Catastrophizing&lt;/strong&gt; (24 times): "This bug will take all day." "If I fail this interview, I'll never get a job." "This PR rejection means I'm not senior enough."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;All-or-nothing thinking&lt;/strong&gt; (18 times): "Either the review is clean or I'm a bad developer." "If I can't solve this in an hour, I don't deserve to be here."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The same three patterns, 80% of the time. Once I saw that, I stopped needing to do the full 7 steps every time — I could catch the pattern in step 2.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding 2: My predictions were wrong 34 out of 36 times
&lt;/h2&gt;

&lt;p&gt;This was the most useful finding. I started tracking: when I catastrophized ("this will take all day"), what actually happened?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"This bug will take all day" → solved in 45 minutes (12 times)&lt;/li&gt;
&lt;li&gt;"They'll reject the PR" → approved with minor changes (8 times)&lt;/li&gt;
&lt;li&gt;"I'll blank in the interview" → answered fine, got the offer (3 times)&lt;/li&gt;
&lt;li&gt;"On-call will be a disaster" → 2 routine pages, both resolved in 15 min (4 times)&lt;/li&gt;
&lt;li&gt;"My manager is going to fire me" → performance review was positive (7 times)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;34 out of 36 catastrophic predictions were wrong. That's a 94% disconfirmation rate.&lt;/p&gt;

&lt;p&gt;After 30 days of seeing this data, catastrophizing just... stopped working on me. Not because I told myself "don't catastrophize" — but because I had 34 data points showing my brain's threat detection system was miscalibrated. The thought record didn't argue with the thought. It just collected evidence until the thought became untenable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding 3: Anxiety dropped 60% by step 7
&lt;/h2&gt;

&lt;p&gt;I rated my anxiety at step 3 (after naming the thought) and again at step 7 (after the balanced thought). Average drop: from 72 to 29. That's a 60% reduction in about 5 minutes of writing.&lt;/p&gt;

&lt;p&gt;The mechanism isn't positive thinking. It's that steps 4 and 5 force you to consider evidence you were filtering out. The balanced thought in step 6 isn't "I'm a great developer" — it's "some comments found real bugs, but 9 were style preferences and the reviewer said good work overall." That's not optimism. That's accuracy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding 4: The situation didn't matter as much as I thought
&lt;/h2&gt;

&lt;p&gt;I thought code reviews were the trigger. But when I looked at the data, the anxiety level correlated more with my sleep and whether I'd eaten than with the severity of the situation. A 3-comment review on 4 hours of sleep produced more anxiety than a 12-comment review when I was rested.&lt;/p&gt;

&lt;p&gt;This is the thing CBT doesn't explicitly teach but the thought record reveals: your baseline state determines your reaction more than the stimulus. I couldn't control the code reviews, but I could control sleep and lunch.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I actually did differently
&lt;/h2&gt;

&lt;p&gt;After 30 days, three changes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;I do a 2-minute thought record when I notice anxiety spiking&lt;/strong&gt; — not the full 7 steps, just steps 1-5. The full version is for when I'm really stuck.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I track prediction accuracy&lt;/strong&gt; — when I catch myself catastrophizing, I note the prediction and check it later. The 94% disconfirmation rate is the single most useful piece of data I have.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;I protect sleep before deadlines&lt;/strong&gt; — not because sleep is healthy, but because my data shows anxiety is 2x higher on poor sleep and my catastrophizing is 3x more frequent.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The tool
&lt;/h2&gt;

&lt;p&gt;I built a free interactive version of the thought record (no signup, no backend, runs in your browser) because doing this on paper was friction and I kept skipping it.&lt;/p&gt;

&lt;p&gt;It's at &lt;strong&gt;&lt;a href="https://473185670.github.io/cbt-toolkit/" rel="noopener noreferrer"&gt;https://473185670.github.io/cbt-toolkit/&lt;/a&gt;&lt;/strong&gt; — along with a cognitive distortion detector, a core belief drill, a mood tracker, and a panic diary. All vanilla JavaScript, all private (data stays in your browser).&lt;/p&gt;

&lt;p&gt;If you want to try the 30-day experiment, the thought record tool makes it about 90 seconds per entry. 47 entries took me about an hour total over 30 days. The ROI on that hour is the highest of anything I did this year.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If this resonated, I write about CBT × developer productivity. Follow for more. The complete toolkit with 22 free interactive tools is at &lt;a href="https://473185670.github.io/cbt-toolkit/" rel="noopener noreferrer"&gt;https://473185670.github.io/cbt-toolkit/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>mentalhealth</category>
      <category>psychology</category>
      <category>beginners</category>
    </item>
    <item>
      <title>5 Cognitive Distortions That Fuel Developer Burnout (And How to Break Them)</title>
      <dc:creator>CBT Tools</dc:creator>
      <pubDate>Mon, 24 Aug 2026 21:59:55 +0000</pubDate>
      <link>https://dev.to/473185670/5-cognitive-distortions-that-fuel-developer-burnout-and-how-to-break-them-1o77</link>
      <guid>https://dev.to/473185670/5-cognitive-distortions-that-fuel-developer-burnout-and-how-to-break-them-1o77</guid>
      <description>&lt;h1&gt;
  
  
  The Exhaustion That Isn't Just Tiredness
&lt;/h1&gt;

&lt;p&gt;It's Wednesday. You've shipped three PRs this week, answered 40 Slack messages, attended 12 hours of meetings, and reviewed five PRs from teammates. By any objective measure, you've done a lot. But the voice in your head says: &lt;em&gt;"You're behind. Everyone else is doing more. You should be able to handle this."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That voice isn't reality. It's a &lt;strong&gt;cognitive distortion&lt;/strong&gt; ??a systematic error in how your brain processes information. And if you're burning out, distortions are likely the fuel, not just the symptom.&lt;/p&gt;

&lt;p&gt;Burnout isn't caused by workload alone. It's caused by the &lt;em&gt;story you tell yourself about&lt;/em&gt; the workload. Change the story, and the same workload becomes sustainable. That's CBT ??cognitive behavioral therapy ??and it works because it targets the thought patterns that convert "tired" into "broken."&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt; ??I built a &lt;a href="https://473185670.github.io/cbt-toolkit/" rel="noopener noreferrer"&gt;free CBT thought record tool&lt;/a&gt; that catches these distortions in 3 minutes, right in your browser. No signup, no backend, no tracking. There's also a &lt;a href="https://4043969836017.gumroad.com/l/yyzll" rel="noopener noreferrer"&gt;Notion template version&lt;/a&gt; if you prefer structured journaling.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  The 5 Distortions That Drive Burnout
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. All-or-Nothing Thinking
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"If I can't give 100% to this PR, I shouldn't give anything."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You see effort in binary: full throttle or off. A day where you only did 4 hours of focused work feels like a failure. A PR that's "good enough" feels like a betrayal of your standards. So you either overwork or disengage entirely ??and the oscillation itself is what burns you out.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The break&lt;/strong&gt;: Sustainability is not a compromise; it's a strategy. A 70% effort sustained for 5 years beats a 100% effort that crashes in 6 months. What would "good enough" look like for today specifically? Name the threshold. It's almost always higher than the distortion admits.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Overgeneralization
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"I'm always behind. I never finish anything."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One missed deadline becomes "I always miss deadlines." One rough sprint becomes "I'm not cut out for this." The distortion takes a single data point and promotes it to a permanent identity. The word "always" or "never" is the tell ??reality is almost never that uniform.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The break&lt;/strong&gt;: Replace "always/never" with "sometimes, when." &lt;em&gt;"I'm behind this sprint, when the estimation was off and two teammates were out."&lt;/em&gt; Now it's a situation with causes, not a character flaw. Situations can change. Identities feel permanent ??and that permanence is what makes you want to quit.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Should Statements
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"I should be able to handle this workload. Other seniors do."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You run a constant comparison against an imaginary ideal developer who never gets tired, never needs breaks, and handles 60-hour weeks effortlessly. Every gap between you and this phantom feels like a moral failure. The "should" generates guilt, guilt drives overwork, overwork drives exhaustion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The break&lt;/strong&gt;: Ask: who says you should? Is it a job description, or an assumption you inherited? The most productive engineers I know work 35-40 hours and protect their energy deliberately. The "should" is almost always a story, not a requirement. What would you do today if "should" weren't in the vocabulary?&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Emotional Reasoning
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"I feel exhausted, so I must be failing."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You treat your feelings as evidence of reality. Exhaustion becomes proof of inadequacy. Feeling overwhelmed becomes proof the work is too much for you. But feelings are outputs, not measurements ??they reflect your state, not your capacity. A tired engineer is still a capable engineer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The break&lt;/strong&gt;: Separate the feeling from the verdict. &lt;em&gt;"I feel exhausted"&lt;/em&gt; is data about your current energy level. &lt;em&gt;"I am failing"&lt;/em&gt; is a judgment the distortion added. What's the objective evidence of your output this week? Commits, PRs, reviews ??those are measurements. The feeling is a signal to rest, not a verdict on your worth.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Personalization
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"The team missed the deadline because of me."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You take systemic outcomes as personal verdicts. A delayed release becomes your fault, even when the delay was caused by scope changes, dependency issues, or three teammates being out. A bug in prod becomes "I let the team down," even when the review process had four sign-offs. You carry weight that isn't yours.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The break&lt;/strong&gt;: Draw the circle of control. What parts of this outcome were actually yours ??your commits, your decisions, your communication? What parts were systemic ??scope, timeline, dependencies, other people? You're responsible for your piece, not the whole machine. Carrying the whole machine is what crushes you.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Pattern Beneath the Pattern
&lt;/h2&gt;

&lt;p&gt;Notice what all five share: they convert &lt;strong&gt;a situation&lt;/strong&gt; into &lt;strong&gt;a verdict on you&lt;/strong&gt;. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All-or-nothing: the situation is imperfect ??&lt;em&gt;you&lt;/em&gt; are a failure&lt;/li&gt;
&lt;li&gt;Overgeneralization: one bad sprint ??&lt;em&gt;you&lt;/em&gt; are always behind&lt;/li&gt;
&lt;li&gt;Should statements: a gap from ideal ??&lt;em&gt;you&lt;/em&gt; are inadequate&lt;/li&gt;
&lt;li&gt;Emotional reasoning: a feeling of tiredness ??&lt;em&gt;you&lt;/em&gt; are failing&lt;/li&gt;
&lt;li&gt;Personalization: a team outcome ??&lt;em&gt;you&lt;/em&gt; are to blame&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Burnout is what happens when you run this conversion loop thousands of times. The workload isn't the poison; the &lt;em&gt;self-verdict loop&lt;/em&gt; is. CBT breaks the loop by inserting a question between the situation and the verdict: &lt;strong&gt;"Is that actually true, and what's the evidence?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That question is the 3-minute thought record. You write down the situation, the automatic thought, the distortion, the evidence for and against, and a reframe. The reframe isn't toxic positivity ??it's accuracy. And accuracy, it turns out, is restful.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try It Right Now
&lt;/h2&gt;

&lt;p&gt;If any of the five distortions above sounded familiar, test the technique:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://473185670.github.io/cbt-toolkit/" rel="noopener noreferrer"&gt;Free CBT Thought Record Tool&lt;/a&gt;&lt;/strong&gt; ??runs in your browser, no signup, no backend. Your thoughts stay in &lt;code&gt;localStorage&lt;/code&gt;. Takes 3 minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://473185670.github.io/cbt-toolkit/distortion-detector.html" rel="noopener noreferrer"&gt;Cognitive Distortion Detector&lt;/a&gt;&lt;/strong&gt; ??paste a thought, it identifies the distortion and suggests a reframe. 200 lines of vanilla JS, no AI, no API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://4043969836017.gumroad.com/l/yyzll" rel="noopener noreferrer"&gt;CBT Thought Record Notion Template&lt;/a&gt;&lt;/strong&gt; ??if you prefer structured journaling in Notion. $1.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The thought record is the single most evidence-backed technique in clinical psychology for exactly the thought patterns that drive burnout. It's not a hack. It's not mindfulness. It's a 60-year-old, research-validated method, now in a tool you can open in 2 seconds.&lt;/p&gt;




&lt;h2&gt;
  
  
  If You're Actually Burning Out
&lt;/h2&gt;

&lt;p&gt;CBT helps with the thought patterns. But if you're in real burnout ??physical exhaustion, cynicism, reduced efficacy ??the thought patterns are a symptom, not the cause. The fixes are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reduce load&lt;/strong&gt;, not increase coping. No CBT technique makes 70-hour weeks sustainable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Talk to your manager.&lt;/strong&gt; A good one would rather know now than lose you in 3 months.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consider professional support.&lt;/strong&gt; A therapist does this with you, not instead of you.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The tools above are for the everyday distortions that &lt;em&gt;lead toward&lt;/em&gt; burnout. If you're already there, use them as a complement to structural change, not a substitute.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;All tools are free, open source, and run entirely in your browser. No signup, no backend, no tracking. If this was useful, the toolkit has 22 more tools for anxiety, panic, mood tracking, and core belief work.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  More in this series
&lt;/h2&gt;

&lt;p&gt;A practical CBT toolkit for developers. Each article pairs one CBT concept with one developer pain point.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://dev.to/473185670/5-cognitive-distortions-that-kill-developer-productivity-and-how-to-catch-them-3p0m"&gt;5 Cognitive Distortions That Kill Developer Productivity (And How to Catch Them)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://dev.to/473185670/5-safety-behaviors-that-kill-developer-productivity-and-how-to-break-them-3ina"&gt;5 Safety Behaviors That Kill Developer Productivity (and How to Break Them)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://dev.to/473185670/5-cognitive-distortions-that-kill-code-review-confidence-and-how-to-break-them-4m3o"&gt;5 Cognitive Distortions That Kill Code Review Confidence (And How to Break Them)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://dev.to/473185670/5-core-beliefs-that-make-you-dread-performance-reviews-and-how-to-rewire-them-43e2"&gt;5 Core Beliefs That Make You Dread Performance Reviews (And How to Rewire Them)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;All tools are free, run in your browser, and store data locally — no signup, no backend.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>mentalhealth</category>
      <category>psychology</category>
      <category>beginners</category>
    </item>
    <item>
      <title>5 Core Beliefs That Make You Dread Performance Reviews (And How to Rewire Them)</title>
      <dc:creator>CBT Tools</dc:creator>
      <pubDate>Mon, 24 Aug 2026 19:02:38 +0000</pubDate>
      <link>https://dev.to/473185670/5-core-beliefs-that-make-you-dread-performance-reviews-and-how-to-rewire-them-43e2</link>
      <guid>https://dev.to/473185670/5-core-beliefs-that-make-you-dread-performance-reviews-and-how-to-rewire-them-43e2</guid>
      <description>&lt;p&gt;The email lands: "Your performance review is scheduled for Thursday at 2pm." Your stomach drops. You spend the next three days replaying every mistake from the quarter, rehearsing what you'll say, and considering whether "sick leave" Thursday is suspicious.&lt;/p&gt;

&lt;p&gt;Performance review anxiety isn't about the review. It's about the beliefs underneath — the deep, automatic, never-examined assumptions about what a rating &lt;em&gt;means&lt;/em&gt; about &lt;em&gt;you&lt;/em&gt;. In CBT, these are called &lt;strong&gt;core beliefs&lt;/strong&gt;: the bedrock assumptions that sit under every thought and color every interpretation.&lt;/p&gt;

&lt;p&gt;I've spent 18 months tracking mine with a thought record tool I built. Here's what I found: the beliefs are predictable, they're wrong in specific ways, and you can rewire them — not with affirmations, but with evidence.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. "My worth is determined by my rating"
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The belief:&lt;/strong&gt; Your value as a human being is equal to your performance score. A "meets expectations" means you're mediocre. A "exceeds" means you're worthy of existing that day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In a performance review:&lt;/strong&gt; You can't hear "good work on the migration" because you're calculating whether "good" means "not great" means "they're being nice" means "you're on the PIP track."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The CBT rewire — The Worth Decoupling:&lt;/strong&gt;&lt;br&gt;
Your worth is not a function of your rating. This is not a motivational poster — it's a logical claim. A rating measures &lt;em&gt;specific behaviors in a specific quarter against specific criteria&lt;/em&gt;. It does not measure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your character (kindness, integrity, loyalty — not on the rubric).&lt;/li&gt;
&lt;li&gt;Your potential (a single quarter cannot bound a career).&lt;/li&gt;
&lt;li&gt;Your value to people who love you (they are not using the rubric).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The belief conflates &lt;em&gt;one measurement of one dimension&lt;/em&gt; with &lt;em&gt;the whole person&lt;/em&gt;. That's a category error, not a feeling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try this:&lt;/strong&gt; Write down three things you value about yourself that your performance review cannot measure. Read them before the review. The review measures your work. It does not measure you.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. "If I receive criticism, it means I'm not good enough"
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The belief:&lt;/strong&gt; Criticism is proof of inadequacy. If you were good enough, there would be nothing to criticize.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In a performance review:&lt;/strong&gt; The reviewer says "I'd like to see you take more initiative on architecture decisions." You hear: "I'm not senior enough. I'm falling behind. They're regretting the promotion."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The CBT rewire — The Growth Reframe:&lt;/strong&gt;&lt;br&gt;
Criticism is data about the gap between current behavior and desired behavior. It is not data about your &lt;em&gt;capacity&lt;/em&gt; — it's data about your &lt;em&gt;current position on a trajectory&lt;/em&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every senior engineer received this same criticism at some point. They received it &lt;em&gt;because&lt;/em&gt; they were on the trajectory, not because they were off it.&lt;/li&gt;
&lt;li&gt;A reviewer who gives no criticism is either (a) not paying attention, or (b) has given up on your growth. Neither is good. Criticism is a sign they're invested.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The belief assumes "good enough" is a destination. It's a direction. Criticism points the way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try this:&lt;/strong&gt; Reframe the criticism as a calibration: "They see where I am, they see where senior is, and they're telling me the delta." The delta is the work. The work is the job.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. "I should already be further along by now"
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The belief:&lt;/strong&gt; There is a correct timeline for your career, you are behind it, and being behind means something is wrong with you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In a performance review:&lt;/strong&gt; You see "3 years experience" next to your name and think about the staff engineer who got there in 2. You feel the gap as a personal failing, not a fact about two different paths.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The CBT rewire — The Comparison Audit:&lt;/strong&gt;&lt;br&gt;
The "should" is the distortion. There is no universal timeline. The staff engineer who made it in 2 years had a different starting point, a different company, a different domain, a different manager, a different market, and probably a different definition of "staff." You are comparing your chapter 7 to their chapter 12.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Should" statements are a documented cognitive distortion in CBT research. They generate guilt and anxiety without producing any useful action.&lt;/li&gt;
&lt;li&gt;The only useful comparison is you-now vs. you-a-year-ago. That one has the same starting point, the same variables, and the same definition of success. It's the only fair one.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Try this:&lt;/strong&gt; Write what you could do a year ago that you can't do now (in a good way — things you've outgrown). Then write what you can do now that you couldn't then. That's your actual trajectory. The "should" timeline is fiction.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. "Being vulnerable in the review means I'm weak"
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The belief:&lt;/strong&gt; Showing uncertainty, asking for help, or admitting a struggle is a weakness that will be held against you. You must perform confidence at all times.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In a performance review:&lt;/strong&gt; The reviewer asks "Where do you feel you struggled this quarter?" You say "Nothing major" — and lose the chance to get support, redirect your work, or build trust. You perform confidence and get a generic review.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The CBT rewire — The Vulnerability Recalibration:&lt;/strong&gt;&lt;br&gt;
Vulnerability is not the absence of strength. It's the &lt;em&gt;channel&lt;/em&gt; through which feedback, support, and trust flow. A reviewer cannot calibrate your work if you hide the struggles. They cannot advocate for your growth if they don't know what you're growing through.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The belief is a false binary: strong = hide, weak = show. In reality, &lt;em&gt;selective&lt;/em&gt; vulnerability (naming a specific struggle + what you've tried + what you need) is a senior behavior. Junors hide. Seniors name.&lt;/li&gt;
&lt;li&gt;Your reviewer is a human who has struggled. Naming a struggle doesn't lower you in their eyes — it makes you legible to them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Try this:&lt;/strong&gt; In the review, name one specific struggle + one thing you tried + one thing you need. "I struggled with the estimation on the Q2 migration. I tried breaking it into smaller tickets but still under-scoped the testing. I'd like a calibration session on estimation." That's not weakness. That's engineering.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. "This one review defines my entire future"
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The belief:&lt;/strong&gt; This single rating will determine your raise, your promotion, your resume, your next job, your career arc, and ultimately your life. The stakes are total.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In a performance review:&lt;/strong&gt; You feel the weight of everything riding on this one conversation. You over-prepare. You freeze. You can't think clearly because the perceived stakes have overloaded your working memory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The CBT rewire — The Stakes Localization:&lt;/strong&gt;&lt;br&gt;
This review determines: your rating for this quarter, and the conversation about next quarter's goals. That's it. It does not determine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your skills (you have those regardless of what anyone writes).&lt;/li&gt;
&lt;li&gt;Your reputation among peers (they've seen your work directly).&lt;/li&gt;
&lt;li&gt;Your next job (interviews test skills, not past ratings).&lt;/li&gt;
&lt;li&gt;Your career (a career is 40 years of quarters; this is one of ~160).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The belief is &lt;strong&gt;overgeneralization&lt;/strong&gt; — taking one event and projecting it onto the entire future. The future is a distribution, not a point. This review shifts it slightly. It does not determine it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try this:&lt;/strong&gt; List everything this review &lt;em&gt;actually&lt;/em&gt; affects. Then list everything it &lt;em&gt;doesn't&lt;/em&gt;. The second list is longer. The stakes are real but bounded. Bounded stakes are manageable stakes.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Pattern
&lt;/h2&gt;

&lt;p&gt;All five beliefs share one thing: &lt;strong&gt;they feel like facts, but they're assumptions.&lt;/strong&gt; They were formed in past moments — a harsh teacher, a critical parent, a bad first review — and they've been running unexamined ever since, coloring every performance evaluation as a threat.&lt;/p&gt;

&lt;p&gt;The fix isn't to "think positive." It's to &lt;strong&gt;think accurately.&lt;/strong&gt; Each rewire above is an exercise in putting the belief next to the evidence and noticing the gap. The gap is where the relief lives.&lt;/p&gt;

&lt;p&gt;You don't need to rewire all five before the review. You need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Notice which belief is firing loudest (the thought record helps).&lt;/li&gt;
&lt;li&gt;Run the specific rewire for that belief.&lt;/li&gt;
&lt;li&gt;Walk into the review with bounded stakes and a decoupled worth.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The anxiety doesn't vanish. It just stops being the thing you're defending.&lt;/p&gt;




&lt;h2&gt;
  
  
  Free Tools (No Signup, No Backend)
&lt;/h2&gt;

&lt;p&gt;I built a set of CBT tools that run entirely in your browser — no account, no server, your data stays in your localStorage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://473185670.github.io/cbt-toolkit/core-belief-detector.html" rel="noopener noreferrer"&gt;Core Belief Detector&lt;/a&gt;&lt;/strong&gt; — Start with a surface thought ("I'm going to bomb this review"), drill down to the core belief driving it. 120 lines of vanilla JS, no API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://473185670.github.io/cbt-toolkit/thought-record.html" rel="noopener noreferrer"&gt;Thought Record&lt;/a&gt;&lt;/strong&gt; — Log the situation, thought, emotion, belief, and evidence. The classic CBT technique, digitized.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://473185670.github.io/cbt-toolkit/distortion-detector.html" rel="noopener noreferrer"&gt;Cognitive Distortion Detector&lt;/a&gt;&lt;/strong&gt; — Paste the thought, get the distortion classification + reframe. 200 lines of vanilla JS.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All tools work offline. No data leaves your machine. No tracking.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Works (The Science)
&lt;/h2&gt;

&lt;p&gt;CBT is the most empirically-supported psychotherapy for anxiety — 400+ randomized controlled trials across four decades. The mechanism for core beliefs is &lt;strong&gt;cognitive restructuring at the schema level&lt;/strong&gt;: identifying the bedrock belief, testing it against evidence, and constructing a more accurate replacement.&lt;/p&gt;

&lt;p&gt;Performance review anxiety is a specific instance of &lt;strong&gt;social-evaluative threat&lt;/strong&gt; — the same mechanism that drives test anxiety, public speaking fear, and athletic performance choking. The core beliefs are the same. The rewires are the same. The only difference is the trigger.&lt;/p&gt;

&lt;p&gt;You don't need therapy. You need a 5-minute pre-review routine:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write the belief that's firing.&lt;/li&gt;
&lt;li&gt;Drill down to the core (use the detector).&lt;/li&gt;
&lt;li&gt;Run the rewire.&lt;/li&gt;
&lt;li&gt;Walk in.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The review still happens. You just stop fighting yourself during it.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you found this useful, I write about the intersection of developer psychology and engineering practice. The tools above are free and open source. No signup, no backend, no catch.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  More in this series
&lt;/h2&gt;

&lt;p&gt;A practical CBT toolkit for developers. Each article pairs one CBT concept with one developer pain point.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://dev.to/473185670/5-cognitive-distortions-that-kill-developer-productivity-and-how-to-catch-them-3p0m"&gt;5 Cognitive Distortions That Kill Developer Productivity (And How to Catch Them)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://dev.to/473185670/5-safety-behaviors-that-kill-developer-productivity-and-how-to-break-them-3ina"&gt;5 Safety Behaviors That Kill Developer Productivity (and How to Break Them)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://dev.to/473185670/5-cognitive-distortions-that-kill-code-review-confidence-and-how-to-break-them-4m3o"&gt;5 Cognitive Distortions That Kill Code Review Confidence (And How to Break Them)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://dev.to/473185670/5-cognitive-distortions-that-fuel-developer-burnout-and-how-to-break-them-1o77"&gt;5 Cognitive Distortions That Fuel Developer Burnout (And How to Break Them)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;All tools are free, run in your browser, and store data locally — no signup, no backend.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>mentalhealth</category>
      <category>psychology</category>
      <category>beginners</category>
    </item>
    <item>
      <title>5 Cognitive Distortions That Kill Code Review Confidence (And How to Break Them)</title>
      <dc:creator>CBT Tools</dc:creator>
      <pubDate>Mon, 24 Aug 2026 18:03:47 +0000</pubDate>
      <link>https://dev.to/473185670/5-cognitive-distortions-that-kill-code-review-confidence-and-how-to-break-them-4m3o</link>
      <guid>https://dev.to/473185670/5-cognitive-distortions-that-kill-code-review-confidence-and-how-to-break-them-4m3o</guid>
      <description>&lt;p&gt;You open the PR. Three files changed, 247 additions, 89 deletions. You've stared at this diff for an hour. You're about to request review — and your chest tightens.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"What if they think I'm junior?"&lt;/em&gt;&lt;br&gt;
&lt;em&gt;"What if there's a bug I missed?"&lt;/em&gt;&lt;br&gt;
&lt;em&gt;"What if this gets rejected and everyone sees?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Code review anxiety isn't a skill problem. It's a thinking problem. Specifically, it's five cognitive distortions — well-documented in CBT (Cognitive Behavioral Therapy) research over 40 years — that hijack your reasoning before the review even starts.&lt;/p&gt;

&lt;p&gt;I've tracked these in my own PRs for 18 months using a thought record tool I built. Here's what I found: the distortions are predictable, the breaks are learnable, and you can defuse them in under 60 seconds if you know which one is firing.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Mind Reading: "The reviewer thinks I'm incompetent"
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The distortion:&lt;/strong&gt; You believe you know what the reviewer is thinking — and it's always the worst interpretation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In a code review:&lt;/strong&gt; You see a comment that says "Consider extracting this into a helper." You read it as: &lt;em&gt;"They think I don't know how to structure code. They think I'm junior."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The CBT break — The Evidence Test:&lt;/strong&gt;&lt;br&gt;
Ask: &lt;em&gt;What's the actual evidence that they think I'm incompetent?&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The comment is about the code, not about you.&lt;/li&gt;
&lt;li&gt;"Consider" is a suggestion, not a reprimand.&lt;/li&gt;
&lt;li&gt;Senior developers get the same comments. I've seen them — I've &lt;em&gt;made&lt;/em&gt; them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The comment is data about the code. It is not data about your worth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try this:&lt;/strong&gt; Next time you feel the mind-reading spiral starting, write down the literal text of the comment. Then write down your interpretation. Notice the gap. The gap is where the distortion lives.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Catastrophizing: "If they find a bug, I'll be fired"
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The distortion:&lt;/strong&gt; You take a small negative and mentally fast-forward to the worst possible outcome.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In a code review:&lt;/strong&gt; You realize you forgot a null check. Your brain goes: &lt;em&gt;bug → production incident → blamed → fired → unemployable → homeless.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The CBT break — The Decatastrophizing Question:&lt;/strong&gt;&lt;br&gt;
Ask: &lt;em&gt;What's the realistic worst case? And then what?&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Worst case: the reviewer catches it before merge. You fix it in 2 minutes.&lt;/li&gt;
&lt;li&gt;If it reaches production: it's caught by monitoring, you patch it, you add a test. This happens to every developer. It happened to the people reviewing your PR.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The probability chain collapses at each step. "Bug found in review" → "fix in 2 min" is the actual chain. The 7-step apocalypse is fiction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try this:&lt;/strong&gt; Write the worst case. Then write the &lt;em&gt;next&lt;/em&gt; thing that would happen. Then the next. You'll find the chain dies in 2-3 steps, not 7.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Personalization: "This criticism means I'm a bad developer"
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The distortion:&lt;/strong&gt; You take a comment about a specific piece of code and make it a statement about your identity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In a code review:&lt;/strong&gt; "This function is doing too much — it's handling validation AND serialization." You hear: &lt;em&gt;"I'm a bad developer."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The CBT break — The Specificity Reframe:&lt;/strong&gt;&lt;br&gt;
The comment is about &lt;em&gt;this function&lt;/em&gt;, at &lt;em&gt;this point in time&lt;/em&gt;, in &lt;em&gt;this specific context&lt;/em&gt;. It is not about &lt;em&gt;you&lt;/em&gt;, &lt;em&gt;all your code&lt;/em&gt;, &lt;em&gt;always&lt;/em&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This function has a problem. → True.&lt;/li&gt;
&lt;li&gt;Some of my code has problems. → True (everyone's does).&lt;/li&gt;
&lt;li&gt;I am a bad developer. → Does not follow. A bad developer doesn't get code reviewed — they don't submit PRs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Try this:&lt;/strong&gt; Replace "I am X" with "This code, right now, has Y." The first is an identity claim. The second is an engineering claim. Only the second is actionable.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. All-or-Nothing Thinking: "If my PR isn't perfect, it's worthless"
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The distortion:&lt;/strong&gt; You see things in binary — perfect or garbage. There's no middle ground.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In a code review:&lt;/strong&gt; You find one thing you'd do differently in hindsight. Now the whole PR feels tainted. You consider withdrawing it. &lt;em&gt;"If it's not clean, I shouldn't ship it."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The CBT break — The Continuum Reframe:&lt;/strong&gt;&lt;br&gt;
Code isn't perfect-or-worthless. It's on a spectrum: &lt;em&gt;good enough to merge&lt;/em&gt;, &lt;em&gt;good enough to merge with follow-up&lt;/em&gt;, &lt;em&gt;needs revision&lt;/em&gt;, &lt;em&gt;needs major rework&lt;/em&gt;. Most PRs are in the middle two categories. That's normal. That's what review is &lt;em&gt;for&lt;/em&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Perfect" is not a precondition for shipping. If it were, nothing would ship.&lt;/li&gt;
&lt;li&gt;The follow-up ticket is a feature, not a failure. It means you're shipping incrementally — which is the correct engineering practice.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Try this:&lt;/strong&gt; Before requesting review, list 3 things that are &lt;em&gt;good enough&lt;/em&gt; about the PR. Then list 1 thing that's a &lt;em&gt;known trade-off&lt;/em&gt;. You're not hiding the trade-off — you're naming it. Naming it moves it from anxiety to engineering.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Fortune Telling: "This review will go badly, I just know it"
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The distortion:&lt;/strong&gt; You predict a negative outcome with certainty — and no evidence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In a code review:&lt;/strong&gt; You haven't submitted the PR yet, but you already "know" it'll be painful. So you procrastinate. You re-read the diff 12 times. You almost withdraw it. The anticipation is worse than the review ever is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The CBT break — The Prediction Test:&lt;/strong&gt;&lt;br&gt;
Ask: &lt;em&gt;How many of my past predictions of "this will go badly" actually went badly?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Most developers, when they actually track this, find their hit rate is under 20%. The other 80% of reviews were fine — a few comments, a merge, done. The brain remembers the 20% and forgets the 80%. That's negativity bias, and it's a distortion.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Past 10 PRs: how many had a "bad" review? (Define "bad" first — most can't.)&lt;/li&gt;
&lt;li&gt;The anticipation cost (hours of anxiety, procrastination) usually exceeds the review cost (20 minutes of addressing comments).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Try this:&lt;/strong&gt; Keep a simple log: PR submitted → predicted outcome (good/neutral/bad) → actual outcome. After 10 entries, look at your prediction accuracy. The data will surprise you.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Pattern
&lt;/h2&gt;

&lt;p&gt;All five distortions share one thing: &lt;strong&gt;they feel like reasoning, but they're not.&lt;/strong&gt; They're cognitive shortcuts that fire automatically under social-evaluative stress — which is exactly what code review is.&lt;/p&gt;

&lt;p&gt;The fix isn't to "think positive." It's to &lt;strong&gt;think accurately.&lt;/strong&gt; Each break above is a question that forces your brain back to evidence, specificity, and probability — the three things distortions strip away.&lt;/p&gt;

&lt;p&gt;You don't need to do all five every time. You need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Notice which distortion is firing (the thought record helps).&lt;/li&gt;
&lt;li&gt;Run the specific break for that distortion.&lt;/li&gt;
&lt;li&gt;Submit the PR anyway. Exposure is the active ingredient.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Free Tools (No Signup, No Backend)
&lt;/h2&gt;

&lt;p&gt;I built a set of CBT tools that run entirely in your browser — no account, no server, your data stays in your localStorage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://473185670.github.io/cbt-toolkit/distortion-detector.html" rel="noopener noreferrer"&gt;Cognitive Distortion Detector&lt;/a&gt;&lt;/strong&gt; — Paste the thought ("they think I'm junior"), get the distortion classification + reframe. 200 lines of vanilla JS, no API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://473185670.github.io/cbt-toolkit/thought-record.html" rel="noopener noreferrer"&gt;Thought Record&lt;/a&gt;&lt;/strong&gt; — Log the situation, thought, emotion, distortion, and alternative thought. The classic CBT technique, digitized.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://473185670.github.io/cbt-toolkit/core-belief-detector.html" rel="noopener noreferrer"&gt;Core Belief Detector&lt;/a&gt;&lt;/strong&gt; — Drill down from "they think I'm junior" → "I'm not good enough" → the core belief driving the distortion. 120 lines of vanilla JS.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All tools work offline. No data leaves your machine. No tracking.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Works (The Science)
&lt;/h2&gt;

&lt;p&gt;CBT is the most empirically-supported psychotherapy for anxiety — 400+ randomized controlled trials across four decades. The mechanism is &lt;strong&gt;cognitive restructuring&lt;/strong&gt;: identifying distorted thoughts, testing them against evidence, and replacing them with accurate ones.&lt;/p&gt;

&lt;p&gt;Code review anxiety is a specific instance of &lt;strong&gt;social-evaluative threat&lt;/strong&gt; — the same mechanism that drives performance anxiety, public speaking fear, and test anxiety. The distortions are the same. The breaks are the same. The only difference is the trigger.&lt;/p&gt;

&lt;p&gt;You don't need therapy. You need a 60-second pre-review routine:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write the thought that's firing.&lt;/li&gt;
&lt;li&gt;Identify the distortion (use the detector).&lt;/li&gt;
&lt;li&gt;Run the break.&lt;/li&gt;
&lt;li&gt;Submit the PR.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The anxiety doesn't disappear. It just stops being the one in the driver's seat.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you found this useful, I write about the intersection of developer psychology and engineering practice. The tools above are free and open source. No signup, no backend, no catch.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  More in this series
&lt;/h2&gt;

&lt;p&gt;A practical CBT toolkit for developers. Each article pairs one CBT concept with one developer pain point.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://dev.to/473185670/5-cognitive-distortions-that-kill-developer-productivity-and-how-to-catch-them-3p0m"&gt;5 Cognitive Distortions That Kill Developer Productivity (And How to Catch Them)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://dev.to/473185670/5-safety-behaviors-that-kill-developer-productivity-and-how-to-break-them-3ina"&gt;5 Safety Behaviors That Kill Developer Productivity (and How to Break Them)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://dev.to/473185670/5-core-beliefs-that-make-you-dread-performance-reviews-and-how-to-rewire-them-43e2"&gt;5 Core Beliefs That Make You Dread Performance Reviews (And How to Rewire Them)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://dev.to/473185670/5-cognitive-distortions-that-fuel-developer-burnout-and-how-to-break-them-1o77"&gt;5 Cognitive Distortions That Fuel Developer Burnout (And How to Break Them)&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;All tools are free, run in your browser, and store data locally — no signup, no backend.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>mentalhealth</category>
      <category>psychology</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
