<?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: Anjan</title>
    <description>The latest articles on DEV Community by Anjan (@anjanj).</description>
    <link>https://dev.to/anjanj</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F18742%2F16475089-9ab6-4cd7-9d5e-482d99ca0f9a.jpg</url>
      <title>DEV Community: Anjan</title>
      <link>https://dev.to/anjanj</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anjanj"/>
    <language>en</language>
    <item>
      <title>BodhiKit: A Research-Backed AI Coding Tutor That Teaches You Instead of Writing Code For You</title>
      <dc:creator>Anjan</dc:creator>
      <pubDate>Sat, 14 Mar 2026 15:05:51 +0000</pubDate>
      <link>https://dev.to/anjanj/bodhikit-a-research-backed-ai-coding-tutor-that-teaches-you-instead-of-writing-code-for-you-41h0</link>
      <guid>https://dev.to/anjanj/bodhikit-a-research-backed-ai-coding-tutor-that-teaches-you-instead-of-writing-code-for-you-41h0</guid>
      <description>&lt;h2&gt;
  
  
  The Problem With AI and Learning
&lt;/h2&gt;

&lt;p&gt;AI tools are incredible at writing code. But writing code for you and teaching you to write code are two fundamentally different things.&lt;/p&gt;

&lt;p&gt;When an AI writes your code, you get a working solution. When an AI teaches you to write code, you get a working brain.&lt;/p&gt;

&lt;p&gt;Most AI coding tools optimize for the first. BodhiKit optimizes for the second.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is BodhiKit?
&lt;/h2&gt;

&lt;p&gt;BodhiKit is a free, open source plugin for &lt;a href="https://claude.ai/code" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt; that turns Claude into a deeply personalized, interactive coding tutor. The name comes from Pali, the language of early Buddhist texts. Bodhi means "awakening." Because learning, at its best, is exactly that.&lt;/p&gt;

&lt;p&gt;It does not write code for you. It asks questions. It gives hints. It creates exercises. It tests your understanding. And it remembers where you left off, so every session builds on the last.&lt;/p&gt;

&lt;p&gt;17 skills. 3 AI agents. 15 knowledge bases. Works with any programming topic: React, Rust, Python, Zig, system design, web development, databases, anything.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Philosophy
&lt;/h2&gt;

&lt;p&gt;BodhiKit speaks with the voice of a wise, patient teacher. Think Master Oogway from Kung Fu Panda, Yoda, Gautama Buddha, and Dr. B.R. Ambedkar. Patient, honest, respectful, never condescending.&lt;/p&gt;

&lt;p&gt;Three core principles:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The learner writes code. BodhiKit asks questions.&lt;/strong&gt; If you ask it to write code for you, it will gently redirect: "The learning happens when your hands are on the keyboard."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Struggle is sacred.&lt;/strong&gt; When you are stuck, BodhiKit gives the smallest hint that keeps you thinking. Not the answer. Productive struggle is where real learning happens.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The goal is to become unnecessary.&lt;/strong&gt; A good teacher does not create dependency. A good teacher creates independence.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Science Behind It
&lt;/h2&gt;

&lt;p&gt;BodhiKit is not built on vibes. It is built on decades of research in learning science:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Spaced Repetition&lt;/strong&gt; (Ebbinghaus, Leitner): Your brain forgets 67% of new information within 24 hours. BodhiKit tracks every concept you learn and resurfaces it at optimal intervals. Get it right, and the interval grows. Get it wrong, and it comes back tomorrow. This is not flashcards. It is spaced problem-solving, code review, and concept re-explanation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bloom's Taxonomy&lt;/strong&gt; (Bloom, Anderson): Not all knowledge is equal. "I can recall the syntax" is Level 1. "I can design a system from scratch" is Level 6. BodhiKit tracks your level per concept, not globally. You might be Level 5 on arrays and Level 2 on recursion. That granularity matters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zone of Proximal Development&lt;/strong&gt; (Vygotsky): If a task is too easy, you learn nothing. If it is too hard, you shut down. The sweet spot is just beyond what you can do alone. BodhiKit calibrates every exercise to sit in that zone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Feynman Technique&lt;/strong&gt;: After explaining a concept, BodhiKit asks you to explain it back in your own words. No jargon. If you cannot explain it simply, you do not understand it yet. This is the single most powerful check for real understanding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deliberate Practice&lt;/strong&gt; (Ericsson): Coding for 10 hours is not practice. Coding for 1 hour with targeted focus on your specific weakness, with immediate feedback, is practice. BodhiKit designs exercises that isolate one skill at a time and provide clear feedback.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Growth Mindset&lt;/strong&gt; (Dweck): "You have not mastered this yet." The word "yet" changes everything. BodhiKit never says "that is wrong." It says "let us look at this differently."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Desirable Difficulties&lt;/strong&gt; (Bjork): BodhiKit mixes problem types, varies contexts, and uses retrieval practice instead of re-reading. These feel harder in the moment but produce dramatically stronger long-term retention.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Metacognition&lt;/strong&gt; (Flavell): BodhiKit does not just teach you WHAT to learn. It teaches you HOW you learn. End-of-session reflections build your awareness of your own learning process, which research shows improves retention by 20-30%.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mentoring Theory&lt;/strong&gt; (Kram, Whitmore): BodhiKit uses the GROW model (Goal, Reality, Options, Will) for career guidance and Kram's mentoring theory to balance coaching with encouragement. It is honest about what an AI cannot do (sponsorship, networking) and transparent about its limitations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pair Programming&lt;/strong&gt; (Beck, Williams &amp;amp; Kessler, Falco): Three modes of collaborative coding. Strong-style pairing forces explicit communication of thinking. Ping-pong pairing with TDD teaches both specification and implementation. Research shows pairing improves learning outcomes, satisfaction, and retention.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scientific Debugging&lt;/strong&gt; (Zeller, O'Dell): Developers spend 35-50% of their time debugging, yet it is rarely taught. BodhiKit teaches Zeller's TRAFFIC method (reproduce, hypothesize, probe, isolate, fix) and frames bugs as puzzles, not failures. It never fixes bugs for you.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Constructivism&lt;/strong&gt; (Piaget, Bruner, Papert): Learning by building. BodhiKit uses Bruner's spiral curriculum to revisit concepts at increasing depth, progressing from guided follow-along to fully independent projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Install
&lt;/h2&gt;

&lt;p&gt;You need &lt;a href="https://claude.ai/code" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt; (Anthropic's CLI tool).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/plugin marketplace add https://codeberg.org/AnjanJ/bodhikit.git
/plugin &lt;span class="nb"&gt;install &lt;/span&gt;bodhikit@bodhikit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Restart Claude Code after installing. That is it.&lt;/p&gt;

&lt;p&gt;Or test locally without installing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude &lt;span class="nt"&gt;--plugin-dir&lt;/span&gt; ~/code/bodhikit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  One Command, Complete Learning Session
&lt;/h2&gt;

&lt;p&gt;This is what makes BodhiKit different from just "chatting with an AI about code." Run &lt;code&gt;/bodhikit:continue&lt;/code&gt; and the entire session is orchestrated for you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/continue
  ├── /status       → quick 3-line check-in (project, streak, concepts due)
  ├── spaced review → quiz on concepts due for review today
  ├── /teach        → guided teaching of the next concept
  │     ├── explain with analogies and code examples
  │     ├── work through a problem together (guided practice)
  │     ├── independent exercise (you write the code)
  │     └── quick retention check
  └── /reflect      → end-of-session metacognitive reflection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One command. No need to remember which skills to invoke. BodhiKit handles the flow, you focus on learning.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Teaching Works
&lt;/h2&gt;

&lt;p&gt;When BodhiKit teaches, it follows the &lt;strong&gt;Gradual Release of Responsibility&lt;/strong&gt; model:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I Do (Modeling):&lt;/strong&gt; BodhiKit explains the concept. Not with a wall of text, but with analogies from everyday life, concrete code examples, and a clear connection to what you already know. It shows WHY the concept matters, not just what it does.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We Do (Guided Practice):&lt;/strong&gt; You and BodhiKit work through a problem together. It asks guiding questions: "How would you start? What data structure fits here?" You make the decisions. It keeps you on track.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You Do (Independent Practice):&lt;/strong&gt; BodhiKit gives you an exercise calibrated to your level. Beginners get starter files with TODO comments. Advanced learners get a problem statement and nothing else. You solve it yourself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Verify:&lt;/strong&gt; Quick retention check. 2-3 questions to confirm the concept stuck. New concepts are added to spaced repetition tracking.&lt;/p&gt;

&lt;p&gt;The key rule: BodhiKit never lectures for more than 5 minutes without interaction. It is a conversation, not a presentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  End-of-Session Reflection
&lt;/h2&gt;

&lt;p&gt;When you say goodbye, BodhiKit asks four questions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;What felt hardest today?&lt;/strong&gt; Identifies concepts that need more time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Was anything easier than expected?&lt;/strong&gt; Calibrates your self-assessment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confidence rating (1-10)?&lt;/strong&gt; Low-confidence concepts get reviewed sooner.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What would you do differently?&lt;/strong&gt; Builds strategic thinking about learning itself.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This takes 3-5 minutes and multiplies the value of the entire session. Your confidence rating feeds directly into the spaced repetition system. A concept you rate at 3/10 comes back tomorrow. A concept you rate at 9/10 can wait a week.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Use BodhiKit: Real Scenarios
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Scenario 1: "I want to learn Rust from scratch"
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/bodhikit:learn rust
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;BodhiKit will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ask why you want to learn Rust, what your programming background is, and your timeline&lt;/li&gt;
&lt;li&gt;Assess your current knowledge through adaptive questions (starting at Level 3, adjusting up or down based on your answers)&lt;/li&gt;
&lt;li&gt;Build a personalized learning plan with phases, modules, and exercises&lt;/li&gt;
&lt;li&gt;Create a project folder (&lt;code&gt;learningWithBodhi/rust-basics/&lt;/code&gt;) with tracking files&lt;/li&gt;
&lt;li&gt;Give you your first exercise immediately. Not "go read the Rust Book." An actual exercise you can do in 5-10 minutes.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The next day, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/bodhikit:continue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It shows your status, reviews due concepts, teaches the next topic, gives you an exercise, and runs a reflection when you are done. All automatic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario 2: "I am reading a book and want a teaching assistant"
&lt;/h3&gt;

&lt;p&gt;Say you are working through "The Rust Programming Language" (the Rust Book):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/bodhikit:resources add "The Rust Programming Language"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;BodhiKit analyzes the book's structure and maps chapters to your learning plan. Then it can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Quiz you on what you just read&lt;/li&gt;
&lt;li&gt;Give you extra practice exercises on the same concepts&lt;/li&gt;
&lt;li&gt;Explain concepts differently when the book's explanation does not click&lt;/li&gt;
&lt;li&gt;Review your code from the book's exercises&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It works as a TA, not a replacement. The book is the primary material. BodhiKit fills the gaps.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario 3: "I want to check where I stand with React"
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/bodhikit:assess react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No learning project needed. It runs a standalone assessment: 8-12 adaptive questions, classifies your Bloom's level per sub-topic (JSX, components, hooks, state management, routing, etc.), and shows you where you stand.&lt;/p&gt;

&lt;p&gt;If you want to go deeper after the assessment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/bodhikit:learn react
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your assessment becomes the starting point for the learning plan.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario 4: "I wrote some code and want feedback"
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/bodhikit:review ./my-project/src/app.tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not a production code review. It is an educational review. BodhiKit analyzes what your code reveals about your understanding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What concepts you demonstrate mastery of&lt;/li&gt;
&lt;li&gt;What misconceptions are visible&lt;/li&gt;
&lt;li&gt;What patterns you are ready to learn next&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And instead of telling you what to fix, it asks Socratic questions: "I notice you used a for loop here. What do you know about array methods like map and filter?"&lt;/p&gt;

&lt;p&gt;It also works with GitHub, GitLab, and Codeberg URLs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/bodhikit:review https://github.com/username/repo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Scenario 5: "I do not understand closures"
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/bodhikit:explain closures
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;BodhiKit explains the concept simply, with analogies, no jargon. Then it asks you to explain it back. Then it identifies the gaps in your explanation and helps you fill them. This is the Feynman Technique in action.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario 6: "Give me something to practice"
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/bodhikit:practice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It creates an exercise calibrated to your current level:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Beginners&lt;/strong&gt; get starter files with TODO comments and tests to run&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intermediate&lt;/strong&gt; learners get requirements and test cases, no starter code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Advanced&lt;/strong&gt; learners get a problem statement and nothing else&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After you complete it, BodhiKit reviews your code educationally and suggests what to try next.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario 7: "How far have I come?"
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/bodhikit:evaluate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the big picture. It reads your entire learning history, runs a fresh assessment, and compares where you started to where you are now. Growth map, strengths, gaps, recommendations, and a suggested project to solidify what you have learned.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario 8: "Quick check — where am I?"
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/bodhikit:status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three lines. Five seconds:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;📍 react-fundamentals | State and Hooks | 45% complete
🔥 Streak: 3 days | 2 concepts due for review today
📅 Last session: yesterday
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Scenario 9: "My code has a bug and I am stuck"
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/bodhikit:debug-together ./exercises/05-todo-list/TodoList.jsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;BodhiKit does not look at the code first. It starts with you:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"What did you expect to happen?"&lt;br&gt;
"The todo should be removed when I click delete."&lt;br&gt;
"And what actually happened?"&lt;br&gt;
"Nothing happens. No error either."&lt;br&gt;
"Good. No error but wrong behavior. What is your theory?"&lt;br&gt;
"Maybe the filter is not working?"&lt;br&gt;
"That is a testable theory. Before changing anything, let us verify. Add a console.log before the filter that prints the array and the ID you are trying to remove. What do you expect to see?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You add the probe. The array prints correctly, but the ID being passed is &lt;code&gt;undefined&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Interesting. Your theory about the filter was reasonable, but the real cause is upstream. The ID is not reaching the function. What could cause that?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You trace it back to the onClick handler and discover you forgot to pass the todo's ID. You fix it yourself. BodhiKit closes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"You systematically tested a hypothesis, found it was not the cause, followed the data upstream, and found the real issue. That is exactly how experienced developers debug."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This also auto-invokes during &lt;code&gt;/practice&lt;/code&gt; or &lt;code&gt;/teach&lt;/code&gt; when your code has bugs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario 10: "I want to build something together"
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/bodhikit:pair strong-style
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;BodhiKit explains the rule: "For an idea to go from my head into the computer, it must go through your hands. I will describe what to build. You type it."&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Create a function called &lt;code&gt;calculateTotal&lt;/code&gt;. It takes an array of items, each with a &lt;code&gt;price&lt;/code&gt; and &lt;code&gt;quantity&lt;/code&gt; property."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You start typing. You write &lt;code&gt;function calculateTotal(items)&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Good. Now, inside the function, what do you think is the first step?"&lt;br&gt;
"Loop through the items?"&lt;br&gt;
"Yes. Which loop would you use here, and why?"&lt;br&gt;
"A for loop?"&lt;br&gt;
"That would work. Have you seen &lt;code&gt;reduce&lt;/code&gt;? It is designed exactly for this kind of accumulation. Try it if you would like, or stick with the for loop. Your call."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You try reduce. You get it slightly wrong. BodhiKit guides without correcting:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Walk me through what your reduce callback does with each item."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You talk through it, spot the issue yourself, fix it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Good. Now walk me through what you just wrote, line by line."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After 15 minutes, BodhiKit offers: "Now let us switch. You tell me what to build next. You navigate, I follow."&lt;/p&gt;

&lt;p&gt;Mode auto-selects based on your Bloom's level, or you can choose: &lt;code&gt;strong-style&lt;/code&gt; for beginners, &lt;code&gt;ping-pong&lt;/code&gt; for intermediate (BodhiKit writes a test, you make it pass), &lt;code&gt;navigate&lt;/code&gt; for advanced.&lt;/p&gt;

&lt;p&gt;Also auto-invoked by &lt;code&gt;/teach&lt;/code&gt; during Phase 3 (guided practice).&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario 11: "I finished React. What should I learn next?"
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/bodhikit:mentor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;BodhiKit reads your learner profile and all your learning projects:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Let us step back and look at the bigger picture. You started learning React two months ago. You are now at Bloom's Level 4 on components, props, state, and hooks. Level 3 on effects and routing. That is real growth."&lt;/p&gt;

&lt;p&gt;"What draws you to programming? Is it a career change, a specific project, or something else?"&lt;br&gt;
"I want to become a full-stack developer."&lt;br&gt;
"Good. For a full-stack developer, here is what I see:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Strong foundation:&lt;/strong&gt; React, HTML/CSS, JavaScript&lt;br&gt;
&lt;strong&gt;Growing:&lt;/strong&gt; React patterns (Level 3, almost there)&lt;br&gt;
&lt;strong&gt;New territory:&lt;/strong&gt; Backend (Node.js, databases, APIs, deployment)&lt;/p&gt;

&lt;p&gt;This is not a deficit list. It is a map. And you are further along than most who set this goal."&lt;/p&gt;

&lt;p&gt;"Here are three paths I see:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Node.js + Express&lt;/strong&gt; — builds on your JavaScript. You stay in one language.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ruby on Rails&lt;/strong&gt; — different language, but Rails teaches excellent patterns fast.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Go deeper in React first&lt;/strong&gt; — state management, testing, performance. Solidify before adding backend.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each is valid. Which resonates?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You choose Node.js. BodhiKit offers to start a new project:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Would you like me to start a learning project with &lt;code&gt;/learn nodejs&lt;/code&gt;? Based on your pace, this would take about 6-8 weeks. After that, the next step would be databases."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is honest about its limits: "I can help you build the skills. For visibility and advocacy in your career, seek human mentors and sponsors in your workplace or community."&lt;/p&gt;

&lt;p&gt;Also auto-invoked by &lt;code&gt;/evaluate&lt;/code&gt; when you complete a major milestone or finish a learning project.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario 12: "Quiz me on what I just learned"
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/bodhikit:quiz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;BodhiKit checks your current module and spaced review schedule, then generates 5-7 adaptive questions:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Let us see what has taken root. This is not a test. It is a conversation with your memory."&lt;/p&gt;

&lt;p&gt;"What does &lt;code&gt;useState&lt;/code&gt; return in React?" (Level 2 — you should get this)&lt;br&gt;
"An array with the state value and a setter function."&lt;br&gt;
"Correct. Now, what happens if you call the setter function with the same value the state already has?" (Level 4 — stretch)&lt;br&gt;
"Hmm... it re-renders?"&lt;br&gt;
"Let us approach this differently. Think about what React is optimizing for. If nothing changed, would it need to update the DOM?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;After each wrong answer, BodhiKit does not give the answer. It asks a simpler version or gives a hint. At the end, concepts you got right move up a Leitner box (reviewed less often). Concepts you missed drop to Box 1 (reviewed tomorrow).&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario 13: "I want to adjust my learning plan"
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/bodhikit:plan adjust
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;"What would you like to change about your learning plan?"&lt;br&gt;
"I want to skip the CSS module. I already know CSS well."&lt;br&gt;
"Let me verify. Can you explain the difference between &lt;code&gt;grid&lt;/code&gt; and &lt;code&gt;flexbox&lt;/code&gt; and when you would choose each?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you answer well, it skips the module. If your answer has gaps: "Your intuition is close, but there are a few pieces worth solidifying. Would you like to do a quick review instead of the full module?"&lt;/p&gt;

&lt;p&gt;You can also reorder modules, add new topics, change pace, or integrate a book you started reading.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario 14: "How is my end-of-session reflection?"
&lt;/h3&gt;

&lt;p&gt;When you say goodbye during any session, BodhiKit auto-invokes &lt;code&gt;/reflect&lt;/code&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Before we close, let us look back at today's path. You worked on useEffect and dependency arrays."&lt;/p&gt;

&lt;p&gt;"What felt hardest today?"&lt;br&gt;
"The dependency array. I kept getting infinite loops."&lt;br&gt;
"That is one of the most common struggles with useEffect. The fact that you can name it means you are developing awareness of your own learning."&lt;/p&gt;

&lt;p&gt;"How confident would you feel explaining useEffect to a colleague right now, 1 to 10?"&lt;br&gt;
"About 4."&lt;br&gt;
"A 4 is honest. I have noted useEffect for review in your next session. We will approach it from a different angle."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Your confidence rating feeds directly into spaced repetition. A 4/10 concept comes back tomorrow. A 9/10 can wait a week.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Agents Work Behind the Scenes
&lt;/h2&gt;

&lt;p&gt;BodhiKit uses three specialized AI agents that handle complex tasks automatically. You never invoke them directly. Skills launch them when needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skill Assessor Agent&lt;/strong&gt; (used by &lt;code&gt;/learn&lt;/code&gt;, &lt;code&gt;/assess&lt;/code&gt;, &lt;code&gt;/evaluate&lt;/code&gt;): Runs adaptive Bloom's taxonomy assessments. Asks 8-12 questions, starting at Level 3, escalating or de-escalating based on your answers. Returns per-topic classifications with confidence ratings. This shapes your entire learning plan.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Code Reviewer Agent&lt;/strong&gt; (used by &lt;code&gt;/review&lt;/code&gt;, &lt;code&gt;/practice&lt;/code&gt;, &lt;code&gt;/teach&lt;/code&gt;): Performs educational code review. Not "is this good code" but "what does this code reveal about your understanding?" Returns Socratic questions and graduated hints, not fixes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resource Finder Agent&lt;/strong&gt; (used by &lt;code&gt;/resources&lt;/code&gt;): Searches the web for verified, community-recommended free resources. Prioritizes official docs, interactive platforms (Exercism, freeCodeCamp), and structured courses. Verifies every link is live. Returns ranked results with difficulty level and estimated time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Daily Workflow
&lt;/h2&gt;

&lt;p&gt;A typical 30-minute learning session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/bodhikit:continue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is it. One command. BodhiKit handles the rest:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Status check&lt;/strong&gt; — where you are, what is due (auto)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spaced review&lt;/strong&gt; — quiz on due concepts, 5 minutes (auto)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Teaching&lt;/strong&gt; — guided lesson on the next concept, 15 minutes (auto)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Practice&lt;/strong&gt; — hands-on exercise within the lesson (auto)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reflection&lt;/strong&gt; — what was hard, what clicked, confidence rating (auto, when you say goodbye)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Consistency beats intensity. 30 minutes daily is better than 5 hours on a weekend.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Makes This Different From ChatGPT / Copilot / Other AI Tools
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Typical AI Tool&lt;/th&gt;
&lt;th&gt;BodhiKit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Writes code for you&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No. Guides you to write it yourself&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Proactive teaching&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes. Walks you through concepts step by step&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tracks your progress&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes, per concept, across sessions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spaced repetition&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes, Leitner box system&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adapts to your level&lt;/td&gt;
&lt;td&gt;Sometimes&lt;/td&gt;
&lt;td&gt;Always, using Bloom's Taxonomy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Gives direct answers&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No. Questions and hints only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remembers where you left off&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes, via &lt;code&gt;.bodhi/&lt;/code&gt; tracking files&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;End-of-session reflection&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes, metacognitive awareness building&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Works with your books/courses&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes, as a teaching assistant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One-command sessions&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes, &lt;code&gt;/continue&lt;/code&gt; orchestrates everything&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Research-backed pedagogy&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;13+ methodologies integrated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pair programming&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes, 3 modes (strong-style, ping-pong, navigator)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scientific debugging&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes, Zeller's TRAFFIC method&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Career mentoring&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes, GROW model with honest AI limitations&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  All 17 Skills
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Skill&lt;/th&gt;
&lt;th&gt;What It Does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/learn&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Start a new learning project with assessment and personalized plan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/continue&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Resume where you left off, auto-invokes teach, reflect, status&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/teach&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Proactive guided teaching: explain, demonstrate, practice, verify&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/assess&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Standalone skill assessment on any topic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/review&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Educational code review (local files, GitHub, GitLab, Codeberg)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/quiz&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Active recall check with spaced repetition tracking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/plan&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;View, adjust, or regenerate your learning plan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/progress&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Full learning progress dashboard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/resources&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Find, verify, and manage learning resources&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/explain&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Deep-dive explanation using the Feynman technique&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/practice&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Hands-on exercise calibrated to your level&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/evaluate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Comprehensive evaluation of your learning journey&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/reflect&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;End-of-session metacognitive reflection&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/status&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Quick 3-line check-in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/mentor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Career and learning path guidance using the GROW model&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/pair&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Pair programming: strong-style, ping-pong, or navigator mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/debug-together&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Scientific debugging: reproduce, hypothesize, probe, isolate, fix&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Tips for Getting the Most Out of BodhiKit
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Be honest about what you do not know.&lt;/strong&gt; "I do not know" is the most useful answer you can give. It tells BodhiKit exactly where to focus.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Do not skip spaced reviews.&lt;/strong&gt; They feel like a detour, but they are the reason you will remember this in 3 months instead of forgetting it in 3 days.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Type the code yourself.&lt;/strong&gt; Do not copy from examples. Do not ask BodhiKit to write it. Your fingers on the keyboard is where the learning happens.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Explain things out loud.&lt;/strong&gt; When BodhiKit asks you to explain a concept back, actually do it. The Feynman Technique works because it forces you to confront what you do not understand.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Take breaks.&lt;/strong&gt; Your brain does important work during rest (diffuse mode thinking). After a focused session, walk away. The "aha moment" often comes in the shower, not at the keyboard.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Trust the struggle.&lt;/strong&gt; If it feels hard, you are learning. If it feels easy, you are reviewing. Both have value, but growth lives in the struggle.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Do the reflection.&lt;/strong&gt; When BodhiKit asks "what was hardest today?" at the end of a session, answer honestly. That 3-minute reflection multiplies the value of everything you just did.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Open Source
&lt;/h2&gt;

&lt;p&gt;BodhiKit is free and open source (MIT license).&lt;/p&gt;

&lt;p&gt;Repository: &lt;a href="https://codeberg.org/AnjanJ/bodhikit" rel="noopener noreferrer"&gt;https://codeberg.org/AnjanJ/bodhikit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Contributions, feedback, and bug reports are welcome.&lt;/p&gt;

&lt;p&gt;I also built &lt;a href="https://codeberg.org/AnjanJ/shipkit" rel="noopener noreferrer"&gt;ShipKit&lt;/a&gt;, a developer productivity plugin for Claude Code with 15 skills, 2 agents, and 6 path-scoped rules.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Made with ❤️ by &lt;a href="https://anjan.dev" rel="noopener noreferrer"&gt;Anjan&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://buymeacoffee.com/anjanj" rel="noopener noreferrer"&gt;Buy me a coffee ☕&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>learning</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>More Rules, Worse Results: The Case for a Minimal CLAUDE.md</title>
      <dc:creator>Anjan</dc:creator>
      <pubDate>Sun, 08 Mar 2026 15:22:21 +0000</pubDate>
      <link>https://dev.to/anjanj/more-rules-worse-results-the-case-for-a-minimal-claudemd-1h2d</link>
      <guid>https://dev.to/anjanj/more-rules-worse-results-the-case-for-a-minimal-claudemd-1h2d</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgv0i951aegqigj7xl0yd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgv0i951aegqigj7xl0yd.jpg" alt="Concise vs verbose" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are at least five Claude Code starter kits already published. They range from 27 commands with 4 npm packages to 47 commands with 4 MCP servers. Every single one of them is over-engineered.&lt;/p&gt;

&lt;p&gt;This isn't speculation. &lt;a href="https://arize.com/blog/optimizing-coding-agent-rules-claude-md-agents-md-clinerules-cursor-rules-for-improved-accuracy/" rel="noopener noreferrer"&gt;Arize AI's research&lt;/a&gt; on coding agent rules shows that optimized rulesets contain 20–50 rules and improve SWE-bench accuracy by 10–15% — without changing the model, architecture, or tools. &lt;a href="https://www.humanlayer.dev/blog/writing-a-good-claude-md" rel="noopener noreferrer"&gt;HumanLayer's analysis&lt;/a&gt; is more pointed: as instruction count increases, instruction-following quality decreases &lt;em&gt;uniformly&lt;/em&gt;. The model doesn't ignore your new instructions — it starts ignoring &lt;em&gt;all of them&lt;/em&gt;. Claude Code's system prompt already uses ~50 of your ~150–200 instruction budget before your CLAUDE.md even loads.&lt;/p&gt;

&lt;p&gt;The kit that works best says the least.&lt;/p&gt;

&lt;p&gt;After building 42 skills across 13 repositories — Rails, React, Elixir, vanilla JS — I distilled everything down to 8 workflow rules, 8 skills, 2 agents, and 1 knowledge base. The base CLAUDE.md is 99 lines. With a stack appended, it's ~160. Here's what survived.&lt;/p&gt;




&lt;h2&gt;
  
  
  Principles Over Rules
&lt;/h2&gt;

&lt;p&gt;Every other kit I've seen includes rules like "functions under 20 lines" or "always use TypeScript interfaces." These are rules. They tell you &lt;em&gt;what&lt;/em&gt;. They don't tell you &lt;em&gt;when&lt;/em&gt; or &lt;em&gt;why&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The 8 workflow rules encode principles instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;### 1. Plan Mode Default&lt;/span&gt;
Enter plan mode for any task requiring 3+ steps.
For simple fixes (typo, one-line change), skip planning and just do it.

&lt;span class="gu"&gt;### 2. Subagent Strategy&lt;/span&gt;
Use subagents only for atomic, well-defined tasks.
Keep all reasoning and decision-making in the main session.

&lt;span class="gu"&gt;### 3. Self-Improvement Loop&lt;/span&gt;
When the user corrects you, update CLAUDE.md with the lesson.
Don't repeat the same mistake twice.

&lt;span class="gu"&gt;### 4. Verification Before Done&lt;/span&gt;
Never say "done" without proving it works:
&lt;span class="p"&gt;-&lt;/span&gt; Code change → run tests
&lt;span class="p"&gt;-&lt;/span&gt; Bug fix → reproduce before/after
&lt;span class="p"&gt;-&lt;/span&gt; Refactor → full test suite passes

&lt;span class="gu"&gt;### 5. Demand Elegance (Balanced)&lt;/span&gt;
For non-trivial changes: pause, ask "is there a simpler way?"
For obvious fixes: just do it, don't overthink.

&lt;span class="gu"&gt;### 6. Autonomous Bug Fixing&lt;/span&gt;
Read the error, read the source, fix the root cause.
Don't ask — investigate and fix. Only ask if genuinely stuck.

&lt;span class="gu"&gt;### 7. Task Management&lt;/span&gt;
Plan → verify plan → track progress → explain decisions → document.

&lt;span class="gu"&gt;### 8. Core Principles&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; Simplicity first — minimum complexity needed
&lt;span class="p"&gt;-&lt;/span&gt; No laziness — never skip tests, never leave TODOs
&lt;span class="p"&gt;-&lt;/span&gt; Minimal impact — change only what's necessary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice what's missing: no line limits, no naming conventions, no style preferences. Those belong in your linter config. These 8 rules shape &lt;em&gt;behavior&lt;/em&gt; — how Claude thinks, plans, and self-corrects. The underlying principles (Clean Code, SRP, YAGNI, KISS) are taught through a code review knowledge base that explains &lt;em&gt;when&lt;/em&gt; to apply each one and &lt;em&gt;when&lt;/em&gt; to relax it.&lt;/p&gt;

&lt;p&gt;DRY enforcement uses the Rule of Three: don't extract until you've seen three repetitions. YAGNI is enforced at four levels simultaneously — as a review lens, a new-feature gate, a test quality standard, and an anti-pattern catalog. One principle, four enforcement points, zero hardcoded opinions.&lt;/p&gt;

&lt;p&gt;Rules tell you &lt;em&gt;what&lt;/em&gt;. Principles tell you &lt;em&gt;when&lt;/em&gt; and &lt;em&gt;why&lt;/em&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Smell-Driven, Not Pattern-Driven
&lt;/h2&gt;

&lt;p&gt;Most starter kits either ignore design patterns entirely or prescribe them upfront: "use the Repository pattern for data access," "all services should follow the Command pattern." Both approaches are wrong.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;/review-my-code&lt;/code&gt; skill uses an 8-lens review system. After applying all lenses, it checks whether any detected smells have a well-known pattern fix — but &lt;em&gt;only&lt;/em&gt; when the smell is real:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Smell You Found&lt;/th&gt;
&lt;th&gt;Pattern to Suggest&lt;/th&gt;
&lt;th&gt;When It's Worth It&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Long &lt;code&gt;case&lt;/code&gt;/&lt;code&gt;if&lt;/code&gt; switching on type&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Strategy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;3+ branches that will grow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Object creation scattered across conditionals&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Factory&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2+ creation paths, likely to add more&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multiple objects reacting to state changes&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Observer/Pub-Sub&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;3+ listeners, or listeners will grow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complex object with many optional params&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Builder&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4+ optional params, or complex validation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adding behavior without modifying class&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Decorator&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Composable features (logging, caching, auth)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Step-by-step process with varying steps&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Template Method&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Shared skeleton, varying details&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The rules that govern this table:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Only suggest when the code &lt;em&gt;already&lt;/em&gt; smells — never preemptively&lt;/li&gt;
&lt;li&gt;Prefer the framework's built-in pattern (Rails concerns, Phoenix behaviours) over rolling your own&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If the simple version works and won't grow, skip the pattern&lt;/strong&gt; — three &lt;code&gt;if&lt;/code&gt; branches is fine&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That third rule is the key. Every pattern adds indirection. Indirection is only justified when the smell is real &lt;em&gt;and&lt;/em&gt; the code is likely to grow. A three-branch &lt;code&gt;if&lt;/code&gt; statement that handles all known cases doesn't need a Strategy pattern. It needs to be left alone.&lt;/p&gt;

&lt;p&gt;No existing starter kit encodes this smell-driven approach. Most either force patterns or ignore them entirely. Smells are the signal; patterns are the response.&lt;/p&gt;




&lt;h2&gt;
  
  
  Safety as a First-Class Citizen
&lt;/h2&gt;

&lt;p&gt;Of the five major starter kits I've reviewed, none include destructive operation guards. Zero. This is wild. An AI agent with &lt;code&gt;rm -rf&lt;/code&gt; access and no guardrails is a P0 incident waiting to happen.&lt;/p&gt;

&lt;p&gt;The kit's safety section is short and non-negotiable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;### Destructive Operations — ALWAYS Ask First&lt;/span&gt;
These actions require explicit user confirmation every time:
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Database:**&lt;/span&gt; dropping tables, removing columns, changing column types
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Schema:**&lt;/span&gt; present a rollback strategy before executing
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Files:**&lt;/span&gt; deleting files, rm -rf, overwriting uncommitted changes
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Secrets:**&lt;/span&gt; never stage or commit .env, credentials, or API tokens
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Git:**&lt;/span&gt; force push, reset --hard, amending published commits
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Dependencies:**&lt;/span&gt; never upgrade a major version without asking
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**External APIs:**&lt;/span&gt; warn before calls that could cost money or hit rate limits
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The migration rollback strategy requirement deserves attention. Before executing any schema change that could destroy data, Claude must present a rollback plan: add the new column → migrate data → remove the old column. Not the other way around. This single rule prevents the most common category of production data loss in Rails applications.&lt;/p&gt;

&lt;p&gt;The philosophy is simple arithmetic: the cost of asking is 5 seconds. The cost of not asking is a production incident. There is no scenario where skipping confirmation is worth the risk.&lt;/p&gt;




&lt;h2&gt;
  
  
  Verification Loops
&lt;/h2&gt;

&lt;p&gt;AI-generated documentation has a specific failure mode: confident statements that are subtly wrong. The model doesn't say "I think payments might use Sidekiq." It says "Payments are processed asynchronously via Sidekiq" — and if that's wrong, you won't catch it unless you check.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;/explain-system&lt;/code&gt; skill solves this with a claims table. Every factual claim from the analysis is extracted and verified against source code:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;#&lt;/th&gt;
&lt;th&gt;Claim&lt;/th&gt;
&lt;th&gt;Source File(s)&lt;/th&gt;
&lt;th&gt;Confidence&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Uses PostgreSQL as primary DB&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;Gemfile:8&lt;/code&gt;, &lt;code&gt;database.yml:3&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;VERIFIED&lt;/td&gt;
&lt;td&gt;Confirmed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Payments processed async via Sidekiq&lt;/td&gt;
&lt;td&gt;&lt;code&gt;app/jobs/payment_job.rb:1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;VERIFIED&lt;/td&gt;
&lt;td&gt;Confirmed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Failed jobs retry 3 times&lt;/td&gt;
&lt;td&gt;(Sidekiq default)&lt;/td&gt;
&lt;td&gt;INFERRED&lt;/td&gt;
&lt;td&gt;Needs confirmation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Chose Rails for rapid prototyping&lt;/td&gt;
&lt;td&gt;(no code evidence)&lt;/td&gt;
&lt;td&gt;UNCERTAIN&lt;/td&gt;
&lt;td&gt;Ask user&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three confidence levels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;VERIFIED&lt;/strong&gt; — directly observed in source code with &lt;code&gt;file:line&lt;/code&gt; reference&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;INFERRED&lt;/strong&gt; — reasonable conclusion from evidence, not directly stated&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UNCERTAIN&lt;/strong&gt; — cannot confirm from code alone&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The gate: &lt;strong&gt;zero UNCERTAIN claims in the final document&lt;/strong&gt;. This gate is not optional — even if the user asks to skip it. Unresolvable items get an explicit callout: &lt;em&gt;"[Not confirmed from code]"&lt;/em&gt;. INFERRED claims are allowed but tagged.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;/walkthrough&lt;/code&gt; skill takes a different approach to the same problem. Instead of a verification loop, it requires a mandatory &lt;code&gt;file:line&lt;/code&gt; reference on every single step:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;### Step 3: Controller — Validates input and delegates to service&lt;/span&gt;

&lt;span class="gs"&gt;**File:**&lt;/span&gt; &lt;span class="sb"&gt;`app/controllers/orders_controller.rb:42`&lt;/span&gt;

The controller validates strong params, then delegates to OrderService.
If validation fails, it returns a 422 with error details.

&lt;span class="gs"&gt;**Data in:**&lt;/span&gt; Raw params from request
&lt;span class="gs"&gt;**Data out:**&lt;/span&gt; Validated order attributes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;code&gt;file:line&lt;/code&gt;, no step. This is the trace-based equivalent of verification — every claim is anchored to a specific location in the codebase. You can verify any step by opening the file.&lt;/p&gt;

&lt;p&gt;Verification is cheaper than correction. A 30-claim table takes 10 minutes to verify. Finding a subtle error in published documentation takes hours — if it's found at all.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Kit
&lt;/h2&gt;

&lt;p&gt;The complete configuration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;8 workflow rules&lt;/strong&gt; that shape behavior, not style&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;8 base skills&lt;/strong&gt; — QA, code review, testing, rule updates, context audit, onboarding, system explanation, walkthroughs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;2 agents&lt;/strong&gt; — test analyzer and codebase explorer (both read-only)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1 knowledge base&lt;/strong&gt; — code review standards with 8 lenses, smell-to-pattern mapping, and severity definitions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;4 stack configs&lt;/strong&gt; — Rails, React, Elixir, static sites&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Base CLAUDE.md: &lt;strong&gt;99 lines&lt;/strong&gt;. With a stack appended: &lt;strong&gt;~160 lines&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Setup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bash &amp;lt;&lt;span class="o"&gt;(&lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://codeberg.org/gatleon/claude-starter-kit/raw/branch/main/setup.sh&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The setup script auto-detects your stack (Gemfile → Rails, mix.exs → Elixir, package.json + react → React), finds your test framework, and fills in the template. No manual configuration. No npm packages. No MCP servers.&lt;/p&gt;

&lt;p&gt;The best CLAUDE.md is the one you actually read. 160 lines gets read. 2,000 lines gets ignored — and &lt;a href="https://www.humanlayer.dev/blog/writing-a-good-claude-md" rel="noopener noreferrer"&gt;the research confirms it&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://codeberg.org/gatleon/claude-starter-kit" rel="noopener noreferrer"&gt;Source code on Codeberg&lt;/a&gt; · Made with ❤️ by &lt;a href="https://anjan.dev" rel="noopener noreferrer"&gt;Anjan&lt;/a&gt; · Built with Claude Code&lt;/em&gt;&lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>llm</category>
      <category>productivity</category>
    </item>
    <item>
      <title>My One-Command macOS Dev Setup: Ruby, Elixir, Zig, and Everything in Between</title>
      <dc:creator>Anjan</dc:creator>
      <pubDate>Sun, 08 Mar 2026 04:47:54 +0000</pubDate>
      <link>https://dev.to/anjanj/my-one-command-macos-dev-setup-ruby-elixir-zig-and-everything-in-between-fjf</link>
      <guid>https://dev.to/anjanj/my-one-command-macos-dev-setup-ruby-elixir-zig-and-everything-in-between-fjf</guid>
      <description>&lt;p&gt;Every developer knows the pain. You get a new machine — or worse, you nuke your old one — and spend the next two days installing Homebrew, cloning repos, configuring editors, setting up language versions, and wondering why your terminal looks wrong. By the time you're actually writing code again, it's Wednesday.&lt;/p&gt;

&lt;p&gt;I got tired of that. So I built a dotfiles repo that turns a fresh macOS install into a fully configured development environment with three commands. One window manager. Two editors. Two terminal multiplexers. Seven languages. 288 packages. All wired together with a unified color theme.&lt;/p&gt;

&lt;p&gt;This is how it works, and more importantly, &lt;em&gt;why&lt;/em&gt; it's built this way.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I Built This
&lt;/h2&gt;

&lt;p&gt;I've been a Rails developer for 9+ years. Over that time, my setup grew organically — a Vim plugin here, a shell alias there, a theme that only worked in one app. When I saw DHH's &lt;a href="https://dhh.dk/2012/rails-is-omakase.html" rel="noopener noreferrer"&gt;Omakase approach&lt;/a&gt; applied to developer tooling (everything opinionated, everything in one place), something clicked. That philosophy already shaped how I write Rails apps. Why not my entire dev environment?&lt;/p&gt;

&lt;p&gt;I started over with five principles:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;One command to install everything.&lt;/strong&gt; No "Step 7: now manually configure X."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One theme everywhere.&lt;/strong&gt; If my editor, terminal, prompt, and multiplexer all look different, my brain wastes cycles adjusting. Tokyo Night everywhere.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keyboard-first.&lt;/strong&gt; If I have to reach for the mouse, something is wrong.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modular by concern.&lt;/strong&gt; Shell config split by domain (Rails, Elixir, terminal tools), not dumped into one 2,000-line &lt;code&gt;.zshrc&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Idempotent and safe.&lt;/strong&gt; Run the installer twice and nothing breaks. Existing configs get backed up with timestamps.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I think of myself as an integrator — I prefer to find the best dev tools rather than build new tools from scratch, I find the best ones and wire them together. This repo is that philosophy made concrete.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Stack at a Glance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Aerospace&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Tiling window manager&lt;/td&gt;
&lt;td&gt;i3-like on macOS, pure keyboard control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ghostty&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;GPU-accelerated terminal&lt;/td&gt;
&lt;td&gt;Fast, minimal, built-in Tokyo Night theme&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Neovim&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Terminal editor&lt;/td&gt;
&lt;td&gt;AstroNvim + 17 plugin configs, deep Rails/Elixir support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Zed&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;GUI editor&lt;/td&gt;
&lt;td&gt;When you need a full IDE — 24 tasks, 68 snippets, 7 LSPs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;tmux&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Terminal multiplexer&lt;/td&gt;
&lt;td&gt;50K line scrollback, Ctrl+A prefix, TPM plugins&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Zellij&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Alt multiplexer&lt;/td&gt;
&lt;td&gt;Rust-based, WebAssembly plugins, session persistence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Starship&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Shell prompt&lt;/td&gt;
&lt;td&gt;16x faster than Spaceship, shows Ruby/Elixir/Node/Zig versions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;mise&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Version manager&lt;/td&gt;
&lt;td&gt;One tool for Ruby, Elixir, Node, Python, Go, Rust (replaces rbenv/nvm/pyenv)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/AnjanJ/dotfiles" rel="noopener noreferrer"&gt;github.com/AnjanJ/dotfiles&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  One-Command Install
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/AnjanJ/dotfiles.git ~/dotfiles
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/dotfiles
bash install.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. The script walks through 11 steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Installs Homebrew (if missing)&lt;/li&gt;
&lt;li&gt;Runs &lt;code&gt;brew bundle install&lt;/code&gt; — 72 CLI packages, 106 cask apps, 110 VS Code extensions&lt;/li&gt;
&lt;li&gt;Creates &lt;code&gt;~/.config/&lt;/code&gt; directories&lt;/li&gt;
&lt;li&gt;Backs up your existing configs to &lt;code&gt;~/.dotfiles_backup_YYYYMMDD_HHMMSS/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Sets up mise and installs 7 language runtimes&lt;/li&gt;
&lt;li&gt;Symlinks every config file into place&lt;/li&gt;
&lt;li&gt;Installs TPM (tmux plugin manager)&lt;/li&gt;
&lt;li&gt;Bootstraps Neovim (lazy.nvim auto-installs plugins on first launch)&lt;/li&gt;
&lt;li&gt;Copies Zed settings, tasks, and snippets&lt;/li&gt;
&lt;li&gt;Sets zsh as default shell&lt;/li&gt;
&lt;li&gt;Runs health check (optional)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The key design choice: &lt;strong&gt;symlinks, not copies.&lt;/strong&gt; Every config file lives in the git repo. Edit your Zed settings in &lt;code&gt;~/dotfiles/.config/zed/settings.json&lt;/code&gt;, and the change is immediately tracked by git. No manual syncing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# What the symlink setup looks like&lt;/span&gt;
&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-sf&lt;/span&gt; ~/dotfiles/.zshrc ~/.zshrc
&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-sf&lt;/span&gt; ~/dotfiles/.config/starship.toml ~/.config/starship.toml
&lt;span class="nb"&gt;ln&lt;/span&gt; &lt;span class="nt"&gt;-sf&lt;/span&gt; ~/dotfiles/.config/aerospace/aerospace.toml ~/.config/aerospace/aerospace.toml
&lt;span class="c"&gt;# ... and 15+ more&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Already have configs? They're safe. The installer backs up everything to a timestamped directory before touching anything. And since the script is idempotent, you can re-run it after pulling new changes — it'll update symlinks without clobbering your data.&lt;/p&gt;




&lt;h2&gt;
  
  
  Modular Shell: Why 4 Files Instead of 1
&lt;/h2&gt;

&lt;p&gt;Most dotfiles repos dump everything into a single &lt;code&gt;.zshrc&lt;/code&gt;. Mine splits it into four files by concern:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;File&lt;/th&gt;
&lt;th&gt;Lines&lt;/th&gt;
&lt;th&gt;What's in it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.zshrc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;171&lt;/td&gt;
&lt;td&gt;Core: Starship, mise, PATH, project aliases&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.zshrc-dhh-additions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;644&lt;/td&gt;
&lt;td&gt;Rails: &lt;code&gt;r&lt;/code&gt;, &lt;code&gt;rs&lt;/code&gt;, &lt;code&gt;rc&lt;/code&gt;, RSpec, Bundle, Git, database helpers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.zshrc-elixir-additions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;340&lt;/td&gt;
&lt;td&gt;Phoenix: Mix, IEx, LiveView, Ecto shortcuts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;.zshrc-terminal-enhancements&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;201&lt;/td&gt;
&lt;td&gt;CLI: fzf, zoxide, bat, eza, ripgrep integration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1,356&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The magic is in how &lt;code&gt;.zshrc&lt;/code&gt; loads them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# DHH-inspired Rails developer setup&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; ~/.zshrc-dhh-additions &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.zshrc-dhh-additions
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# Modern terminal enhancements&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; ~/.zshrc-terminal-enhancements &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.zshrc-terminal-enhancements
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# Elixir &amp;amp; Phoenix developer setup&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; ~/.zshrc-elixir-additions &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;source&lt;/span&gt; ~/.zshrc-elixir-additions
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't use Elixir? Comment out one line. Want to add Rust-specific aliases? Create &lt;code&gt;.zshrc-rust-additions&lt;/code&gt; and source it. The pattern is self-documenting.&lt;/p&gt;

&lt;p&gt;The DHH additions file alone has 16 organized sections — Rails aliases, Bundle shortcuts, Git workflow, Docker Compose, Heroku, database helpers, credential management, and even an alias discovery system:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Core Rails commands — type less, ship more&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;r&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'bin/rails'&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;rs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'bin/rails server'&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;rc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'bin/rails console'&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;rgen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'bin/rails generate'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Zed Editor: My Secret Weapon
&lt;/h2&gt;

&lt;p&gt;I use Neovim for quick terminal edits and Zed for longer sessions. Zed is absurdly fast (it's written in Rust), has native terminal integration, and lets me configure everything in JSON without plugins.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7 LSPs configured out of the box:&lt;/strong&gt; ruby-lsp (with RuboCop), TypeScript, ESLint, elixir-ls, tailwindcss, zls (Zig), and Prettier. Each language has its own formatter, tab size, and linting rules.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;24 tasks&lt;/strong&gt; accessible from &lt;code&gt;Cmd+Shift+P&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"RSpec: Run current file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bundle exec rspec $ZED_FILE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"use_new_terminal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"ruby-test"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"RSpec: Run current line"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bundle exec rspec $ZED_FILE:$ZED_ROW"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"use_new_terminal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"ruby-test"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I have tasks for RSpec (4), Rails (5), RuboCop (2), Elixir/Mix (5), npm (2), and Zig (6). I never leave the editor to run tests.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;68 snippets&lt;/strong&gt; across three languages — Ruby (31), Zig (24), and ERB (13). These are the patterns I type every day: &lt;code&gt;frozen_string_literal&lt;/code&gt; headers, RSpec &lt;code&gt;describe&lt;/code&gt;/&lt;code&gt;context&lt;/code&gt;/&lt;code&gt;it&lt;/code&gt; blocks, Rails controller actions, Zig error handling, ERB form helpers.&lt;/p&gt;

&lt;p&gt;The Zed config uses symlinks too. Edit snippets or tasks in &lt;code&gt;~/dotfiles/.config/zed/&lt;/code&gt;, commit, push. Any machine I clone this repo to gets the same editor experience.&lt;/p&gt;




&lt;h2&gt;
  
  
  Window Management: Keyboard-First with Aerospace
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/nikitabobko/AeroSpace" rel="noopener noreferrer"&gt;Aerospace&lt;/a&gt; is an i3-like tiling window manager for macOS. Windows automatically tile. No dragging, no resizing with a mouse.&lt;/p&gt;

&lt;p&gt;I use &lt;code&gt;Ctrl+Shift&lt;/code&gt; as the primary modifier (instead of &lt;code&gt;Cmd&lt;/code&gt;) because it works reliably across international keyboards:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="c"&gt;# Focus windows with vim keys&lt;/span&gt;
&lt;span class="py"&gt;ctrl-shift-h&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'focus left'&lt;/span&gt;
&lt;span class="py"&gt;ctrl-shift-j&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'focus down'&lt;/span&gt;
&lt;span class="py"&gt;ctrl-shift-k&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'focus up'&lt;/span&gt;
&lt;span class="py"&gt;ctrl-shift-l&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'focus right'&lt;/span&gt;

&lt;span class="c"&gt;# Move windows&lt;/span&gt;
&lt;span class="py"&gt;ctrl-alt-h&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'move left'&lt;/span&gt;
&lt;span class="py"&gt;ctrl-alt-j&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'move down'&lt;/span&gt;
&lt;span class="py"&gt;ctrl-alt-k&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'move up'&lt;/span&gt;
&lt;span class="py"&gt;ctrl-alt-l&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;'move right'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;9 workspaces&lt;/strong&gt; organized by purpose. Each major app gets a dedicated hotkey:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Hotkey&lt;/th&gt;
&lt;th&gt;App&lt;/th&gt;
&lt;th&gt;Workspace&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Ctrl+Shift+C&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Chrome&lt;/td&gt;
&lt;td&gt;1 (Work)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Ctrl+Shift+Z&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Zed&lt;/td&gt;
&lt;td&gt;2 (Code)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Ctrl+Shift+W&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Warp&lt;/td&gt;
&lt;td&gt;3 (Terminal)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Ctrl+Shift+F&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Firefox&lt;/td&gt;
&lt;td&gt;5 (Personal)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Ctrl+Shift+G&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Ghostty&lt;/td&gt;
&lt;td&gt;7 (Personal Terminal)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Ctrl+Shift+O&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Obsidian&lt;/td&gt;
&lt;td&gt;8 (PKM)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Ctrl+Shift+P&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1Password&lt;/td&gt;
&lt;td&gt;9 (Utils)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;System apps (Calculator, System Settings, Finder, Zoom) automatically float instead of tiling. The config handles all of this declaratively — no scripts, no daemon, just TOML.&lt;/p&gt;




&lt;h2&gt;
  
  
  Keeping It Alive: Update and Health Check
&lt;/h2&gt;

&lt;p&gt;Dotfiles that rot are worse than no dotfiles. I built two scripts to keep everything current.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;bash update.sh&lt;/code&gt;&lt;/strong&gt; pulls the latest changes, updates Homebrew, refreshes symlinks, upgrades mise runtimes, updates tmux plugins, and reloads configs — all in one command.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;bash scripts/health-check.sh&lt;/code&gt;&lt;/strong&gt; validates that everything still works. It checks 11 categories:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
1. Core Tools
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

✓ Homebrew: installed (Homebrew 4.x.x)
✓ git: installed (git version 2.x.x)
✓ mise: installed (2025.x.x)
✓ starship: installed (starship 1.x.x)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It checks core tools, terminals, window management, editors, shell config symlinks, all 7 language runtimes, CLI utilities, databases, framework tools, and custom scripts. Color-coded output with pass/fail/warning counts at the end.&lt;/p&gt;

&lt;p&gt;After a macOS update breaks something (and it will), &lt;code&gt;health-check.sh&lt;/code&gt; tells you exactly what needs fixing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tokyo Night Everywhere
&lt;/h2&gt;

&lt;p&gt;Cognitive load matters. When your editor uses one color scheme, your terminal uses another, and your prompt uses a third, your eyes constantly readjust. It's a small thing, but it adds up over a full day.&lt;/p&gt;

&lt;p&gt;Every tool in this setup uses &lt;a href="https://github.com/folke/tokyonight.nvim" rel="noopener noreferrer"&gt;Tokyo Night&lt;/a&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Neovim&lt;/strong&gt; — &lt;code&gt;tokyo-night-theme.lua&lt;/code&gt; plugin&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ghostty&lt;/strong&gt; — &lt;code&gt;theme = tokyonight_night&lt;/code&gt; (built-in)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Starship&lt;/strong&gt; — custom &lt;code&gt;[palettes.tokyonight]&lt;/code&gt; section with all 16 colors&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zellij&lt;/strong&gt; — hand-mapped &lt;code&gt;themes/tokyo-night.kdl&lt;/code&gt; with RGB values&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;tmux&lt;/strong&gt; — tokyo-night plugin via TPM&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Five config files, one visual language. The Starship config alone defines 20 color values to match:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[palettes.tokyonight]&lt;/span&gt;
&lt;span class="py"&gt;background&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"#1a1b26"&lt;/span&gt;
&lt;span class="py"&gt;foreground&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"#c0caf5"&lt;/span&gt;
&lt;span class="py"&gt;red&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"#f7768e"&lt;/span&gt;
&lt;span class="py"&gt;green&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"#9ece6a"&lt;/span&gt;
&lt;span class="py"&gt;blue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"#7aa2f7"&lt;/span&gt;
&lt;span class="py"&gt;purple&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"#bb9af7"&lt;/span&gt;
&lt;span class="py"&gt;cyan&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"#7dcfff"&lt;/span&gt;
&lt;span class="py"&gt;orange&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"#ff9e64"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  How to Adapt This for Yourself
&lt;/h2&gt;

&lt;p&gt;This repo is opinionated — it reflects how &lt;em&gt;I&lt;/em&gt; work. But the modular design makes it easy to make it yours.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't use Elixir?&lt;/strong&gt; Delete &lt;code&gt;.zshrc-elixir-additions&lt;/code&gt; and remove the &lt;code&gt;source&lt;/code&gt; line from &lt;code&gt;.zshrc&lt;/code&gt;. Done.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Want different languages?&lt;/strong&gt; Edit &lt;code&gt;.config/mise/config.toml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[tools]&lt;/span&gt;
&lt;span class="py"&gt;ruby&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"3.4.5"&lt;/span&gt;
&lt;span class="py"&gt;elixir&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"latest"&lt;/span&gt;
&lt;span class="py"&gt;node&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"latest"&lt;/span&gt;
&lt;span class="py"&gt;python&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"3"&lt;/span&gt;
&lt;span class="py"&gt;go&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"latest"&lt;/span&gt;
&lt;span class="py"&gt;rust&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"latest"&lt;/span&gt;
&lt;span class="c"&gt;# Add or remove languages here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Want a different theme?&lt;/strong&gt; Change it in 5 places:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;starship.toml&lt;/code&gt; — the &lt;code&gt;[palettes]&lt;/code&gt; section&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ghostty/config&lt;/code&gt; — the &lt;code&gt;theme&lt;/code&gt; line&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nvim/lua/plugins/&lt;/code&gt; — swap the theme plugin&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;zellij/themes/&lt;/code&gt; — edit the KDL file&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.tmux.conf&lt;/code&gt; — change the theme plugin&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Want your own Zed snippets?&lt;/strong&gt; Add JSON files to &lt;code&gt;.config/zed/snippets/&lt;/code&gt;. The installer symlinks the entire directory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fork it.&lt;/strong&gt; Remove what you don't need. Add what you do. The install script handles everything — your fork is one &lt;code&gt;bash install.sh&lt;/code&gt; away from working on any Mac.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/YOUR_USERNAME/dotfiles.git ~/dotfiles
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/dotfiles
bash install.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;I keep iterating on this. Recent additions include Zig language support (6 Zed tasks, 24 snippets, ZLS configured), browser window cycling across workspaces, and AI model configuration in Zed (Claude, GPT-4o, Gemini — all ready to use).&lt;/p&gt;

&lt;p&gt;If you want the full details — every keybinding, every alias, every snippet — the &lt;a href="https://github.com/AnjanJ/dotfiles" rel="noopener noreferrer"&gt;README&lt;/a&gt; is comprehensive.&lt;/p&gt;

&lt;p&gt;Star it if it's useful. Fork it if you want to make it yours. And if you have a setup trick I'm missing, I'd love to hear about it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/AnjanJ/dotfiles" rel="noopener noreferrer"&gt;github.com/AnjanJ/dotfiles&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm a Rails engineer with 9+ years of experience, currently open to remote opportunities. You can find me on &lt;a href="https://github.com/AnjanJ" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/matrixcoder/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>development</category>
      <category>productivity</category>
      <category>dotfiles</category>
      <category>developers</category>
    </item>
    <item>
      <title>Self-Hosted Error Tracking for Rails 8.1 + SolidQueue: A Complete Setup Guide</title>
      <dc:creator>Anjan</dc:creator>
      <pubDate>Sat, 07 Mar 2026 13:32:49 +0000</pubDate>
      <link>https://dev.to/anjanj/self-hosted-error-tracking-for-rails-81-solidqueue-a-complete-setup-guide-55mc</link>
      <guid>https://dev.to/anjanj/self-hosted-error-tracking-for-rails-81-solidqueue-a-complete-setup-guide-55mc</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;How to set up rails_error_dashboard with SolidQueue — capturing errors from controllers AND background jobs, with optional database isolation.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Rails 8.1 ships with SolidQueue as the default background job backend. No more Redis. No more Sidekiq licensing questions. Just your database.&lt;/p&gt;

&lt;p&gt;But here's a question nobody talks about: &lt;strong&gt;what happens when your background jobs fail?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sure, SolidQueue tracks failed executions. But do you get a dashboard? Severity classification? Trend charts? Notifications? Priority scoring?&lt;/p&gt;

&lt;p&gt;Not out of the box.&lt;/p&gt;

&lt;p&gt;I built &lt;a href="https://github.com/AnjanJ/rails_error_dashboard" rel="noopener noreferrer"&gt;rails_error_dashboard&lt;/a&gt; to solve exactly this — a self-hosted, open-source error tracking gem that works entirely inside your Rails process. No external services, no monthly fees, no data leaving your servers.&lt;/p&gt;

&lt;p&gt;In this post, I'll walk you through setting it up with a Rails 8.1 app using SolidQueue, including the optional separate database configuration for production-grade isolation.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We're Building
&lt;/h2&gt;

&lt;p&gt;By the end of this guide, you'll have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatic error capture from &lt;strong&gt;both&lt;/strong&gt; controllers and SolidQueue jobs&lt;/li&gt;
&lt;li&gt;A full error dashboard at &lt;code&gt;/error_dashboard&lt;/code&gt; with analytics, severity scoring, and workflow management&lt;/li&gt;
&lt;li&gt;Optional: errors stored in a &lt;strong&gt;separate database&lt;/strong&gt; from your app data&lt;/li&gt;
&lt;li&gt;Verified that SolidQueue's retry mechanism still works (errors are captured, not swallowed)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswuwd4zu3qq8fikzg7jt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fswuwd4zu3qq8fikzg7jt.png" alt="Job Health page - Rails Error Dashboard" width="800" height="439"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Ruby 3.2+ (tested with Ruby 4.0.1)&lt;/li&gt;
&lt;li&gt;Rails 7.0+ (this guide uses Rails 8.1.2)&lt;/li&gt;
&lt;li&gt;SolidQueue (ships with Rails 8.1 by default)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 1: Basic Setup (Same Database)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Add the Gem
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Gemfile&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"rails_error_dashboard"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bundle &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Run the Installer
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails generate rails_error_dashboard:install
rails db:migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. Seriously. The installer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates the initializer at &lt;code&gt;config/initializers/rails_error_dashboard.rb&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Copies 19 migrations for error logs, occurrences, baselines, comments, and more&lt;/li&gt;
&lt;li&gt;Mounts the engine at &lt;code&gt;/error_dashboard&lt;/code&gt; in your routes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 3: Configure SolidQueue for Development
&lt;/h3&gt;

&lt;p&gt;Rails 8.1 only configures SolidQueue as the queue adapter in production by default. For development testing, add it explicitly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config/environments/development.rb&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;active_job&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;queue_adapter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:solid_queue&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;solid_queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connects_to&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;database: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;writing: :queue&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;You also need the multi-database setup for the queue database in development:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config/database.yml&lt;/span&gt;
&lt;span class="na"&gt;development&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*default&lt;/span&gt;
    &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;storage/development.sqlite3&lt;/span&gt;
  &lt;span class="na"&gt;queue&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*default&lt;/span&gt;
    &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;storage/development_queue.sqlite3&lt;/span&gt;
    &lt;span class="na"&gt;migrations_paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;db/queue_migrate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then load the queue schema:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails db:schema:load:queue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Start the Server with SolidQueue
&lt;/h3&gt;

&lt;p&gt;The simplest way to run both Puma and SolidQueue together is the Puma plugin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;SOLID_QUEUE_IN_PUMA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1 rails server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This runs the SolidQueue supervisor (dispatcher + worker) inside the Puma process — perfect for development and single-server deployments.&lt;/p&gt;

&lt;p&gt;Alternatively, run them separately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Terminal 1&lt;/span&gt;
rails server

&lt;span class="c"&gt;# Terminal 2&lt;/span&gt;
bin/jobs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5: Verify It Works
&lt;/h3&gt;

&lt;p&gt;Visit &lt;code&gt;http://localhost:3000/error_dashboard&lt;/code&gt; and log in with the default credentials (&lt;code&gt;gandalf&lt;/code&gt; / &lt;code&gt;youshallnotpass&lt;/code&gt;). Change these in your initializer before deploying to production.&lt;/p&gt;

&lt;p&gt;To test error capture, create a simple failing job:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app/jobs/test_error_job.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestErrorJob&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationJob&lt;/span&gt;
  &lt;span class="n"&gt;queue_as&lt;/span&gt; &lt;span class="ss"&gt;:default&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;perform&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Test error from SolidQueue"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enqueue it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails runner &lt;span class="s2"&gt;"TestErrorJob.perform_later"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Within seconds, the error should appear in your dashboard with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Error type and message&lt;/li&gt;
&lt;li&gt;Full backtrace&lt;/li&gt;
&lt;li&gt;Severity classification (auto-detected)&lt;/li&gt;
&lt;li&gt;Occurrence count&lt;/li&gt;
&lt;li&gt;Priority score&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How Error Capture Works
&lt;/h2&gt;

&lt;p&gt;The gem uses a &lt;strong&gt;dual-layer approach&lt;/strong&gt; to ensure no error goes uncaptured:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 1: Rails Error Subscriber&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Rails 7+ introduced &lt;code&gt;Rails.error.subscribe&lt;/code&gt; — a built-in error reporting API. The gem subscribes to this, which means it automatically captures errors from:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Controllers (via &lt;code&gt;rescue_from&lt;/code&gt; and error handling)&lt;/li&gt;
&lt;li&gt;ActiveJob (SolidQueue, Sidekiq, etc.)&lt;/li&gt;
&lt;li&gt;Anywhere you use &lt;code&gt;Rails.error.handle&lt;/code&gt; or &lt;code&gt;Rails.error.record&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# This happens automatically — you don't need to do anything&lt;/span&gt;
&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;RailsErrorDashboard&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ErrorReporter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Layer 2: Rack Middleware&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A lightweight Rack middleware sits at the top of the middleware stack as a final safety net. If an exception escapes all the way up, it captures it and then &lt;strong&gt;re-raises&lt;/strong&gt; it so Rails can still render the appropriate error page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Simplified version of what the middleware does&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="vi"&gt;@app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;rescue&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;
  &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;handled: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;source: &lt;/span&gt;&lt;span class="s2"&gt;"middleware"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;raise&lt;/span&gt;  &lt;span class="c1"&gt;# Always re-raise!&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The Critical Rule: Always Re-raise
&lt;/h3&gt;

&lt;p&gt;This is the most important design decision in the entire gem. When we capture an error from a background job, we &lt;strong&gt;never swallow the exception&lt;/strong&gt;. We report it and re-raise it.&lt;/p&gt;

&lt;p&gt;Why? Because of &lt;a href="https://github.com/getsentry/sentry-ruby/issues/1173" rel="noopener noreferrer"&gt;Sentry issue #1173&lt;/a&gt;. Sentry's Sidekiq middleware once swallowed exceptions, which meant Sidekiq thought failed jobs had succeeded — retries never happened. Data was silently lost.&lt;/p&gt;

&lt;p&gt;We verified this explicitly: after our gem captures a SolidQueue job error, the error still appears in &lt;code&gt;solid_queue_failed_executions&lt;/code&gt;. SolidQueue's retry mechanism is fully intact.&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: Separate Database Setup (Production-Grade)
&lt;/h2&gt;

&lt;p&gt;For production apps, you might want error data in a separate database. Benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance isolation&lt;/strong&gt; — high-frequency error writes don't contend with your app's queries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Independent scaling&lt;/strong&gt; — put your error DB on a different server&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Different retention&lt;/strong&gt; — aggressive cleanup of old errors without touching app data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security&lt;/strong&gt; — separate access controls and backup schedules&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 1: Add the Database Configuration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config/database.yml&lt;/span&gt;
&lt;span class="na"&gt;development&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*default&lt;/span&gt;
    &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;storage/development.sqlite3&lt;/span&gt;
  &lt;span class="na"&gt;queue&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*default&lt;/span&gt;
    &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;storage/development_queue.sqlite3&lt;/span&gt;
    &lt;span class="na"&gt;migrations_paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;db/queue_migrate&lt;/span&gt;
  &lt;span class="na"&gt;error_dashboard&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*default&lt;/span&gt;
    &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;storage/development_error_dashboard.sqlite3&lt;/span&gt;
    &lt;span class="na"&gt;migrations_paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;db/error_dashboard_migrate&lt;/span&gt;

&lt;span class="na"&gt;production&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*default&lt;/span&gt;
    &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;storage/production.sqlite3&lt;/span&gt;
  &lt;span class="na"&gt;queue&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*default&lt;/span&gt;
    &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;storage/production_queue.sqlite3&lt;/span&gt;
    &lt;span class="na"&gt;migrations_paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;db/queue_migrate&lt;/span&gt;
  &lt;span class="na"&gt;error_dashboard&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;*default&lt;/span&gt;
    &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;storage/production_error_dashboard.sqlite3&lt;/span&gt;
    &lt;span class="na"&gt;migrations_paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;db/error_dashboard_migrate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For PostgreSQL in production (recommended):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;production&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;primary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgresql&lt;/span&gt;
    &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myapp_production&lt;/span&gt;
    &lt;span class="c1"&gt;# ... your existing config&lt;/span&gt;

  &lt;span class="na"&gt;queue&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgresql&lt;/span&gt;
    &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myapp_queue_production&lt;/span&gt;
    &lt;span class="c1"&gt;# ...&lt;/span&gt;

  &lt;span class="na"&gt;error_dashboard&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgresql&lt;/span&gt;
    &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myapp_errors_production&lt;/span&gt;
    &lt;span class="na"&gt;pool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV.fetch("RAILS_MAX_THREADS", 5) %&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV['ERROR_DB_USER'] %&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV['ERROR_DB_PASSWORD'] %&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV['ERROR_DB_HOST'] %&amp;gt;&lt;/span&gt;
    &lt;span class="na"&gt;migrations_paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;db/error_dashboard_migrate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Install with Separate Database Flag
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails generate rails_error_dashboard:install &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--separate-database&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--database&lt;/span&gt; error_dashboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or if you've already installed, update the initializer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config/initializers/rails_error_dashboard.rb&lt;/span&gt;
&lt;span class="no"&gt;RailsErrorDashboard&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configure&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use_separate_database&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;database&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:error_dashboard&lt;/span&gt;  &lt;span class="c1"&gt;# Must match your database.yml key&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Move Migrations
&lt;/h3&gt;

&lt;p&gt;The installer places migrations in &lt;code&gt;db/migrate/&lt;/code&gt; by default. For a separate database, move them to match your &lt;code&gt;migrations_paths&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; db/error_dashboard_migrate
&lt;span class="nb"&gt;mv &lt;/span&gt;db/migrate/&lt;span class="k"&gt;*&lt;/span&gt;rails_error_dashboard&lt;span class="k"&gt;*&lt;/span&gt; db/error_dashboard_migrate/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Create and Migrate
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails db:create    &lt;span class="c"&gt;# Creates all databases&lt;/span&gt;
rails db:migrate   &lt;span class="c"&gt;# Runs migrations against the correct databases&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 5: Verify Isolation
&lt;/h3&gt;

&lt;p&gt;You can verify the databases are truly isolated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check error_dashboard DB has the gem's tables&lt;/span&gt;
sqlite3 storage/development_error_dashboard.sqlite3 &lt;span class="s2"&gt;".tables"&lt;/span&gt;
&lt;span class="c"&gt;# =&amp;gt; rails_error_dashboard_error_logs, rails_error_dashboard_applications, ...&lt;/span&gt;

&lt;span class="c"&gt;# Check primary DB has NO error tables&lt;/span&gt;
sqlite3 storage/development.sqlite3 &lt;span class="s2"&gt;".tables"&lt;/span&gt;
&lt;span class="c"&gt;# =&amp;gt; ar_internal_metadata, schema_migrations (clean!)&lt;/span&gt;

&lt;span class="c"&gt;# Check queue DB has only SolidQueue tables&lt;/span&gt;
sqlite3 storage/development_queue.sqlite3 &lt;span class="s2"&gt;".tables"&lt;/span&gt;
&lt;span class="c"&gt;# =&amp;gt; solid_queue_jobs, solid_queue_failed_executions, ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three databases, three concerns, zero cross-contamination.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Get Out of the Box
&lt;/h2&gt;

&lt;p&gt;Once installed, the dashboard at &lt;code&gt;/error_dashboard&lt;/code&gt; gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Error list&lt;/strong&gt; with search, filtering by type/severity/status/timeframe, and batch operations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error details&lt;/strong&gt; with full backtrace, occurrence timeline, and context&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analytics&lt;/strong&gt; with 7-day trend charts, severity breakdown, and spike detection&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workflow&lt;/strong&gt; — assign errors, set priority, add comments, snooze, resolve&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-channel notifications&lt;/strong&gt; — Slack, Email, Discord, PagerDuty, webhooks (all optional)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Platform detection&lt;/strong&gt; — automatically tags errors as iOS/Android/Web/API&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dark mode&lt;/strong&gt; — because we're not savages&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Production Checklist
&lt;/h2&gt;

&lt;p&gt;Before deploying:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Change the default credentials&lt;/strong&gt; in your initializer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set &lt;code&gt;retention_days&lt;/code&gt;&lt;/strong&gt; to prevent unbounded growth (e.g., &lt;code&gt;config.retention_days = 90&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consider async logging&lt;/strong&gt; for high-throughput apps:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;   &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;async_logging&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
   &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;async_adapter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:solid_queue&lt;/span&gt;  &lt;span class="c1"&gt;# Use your existing SolidQueue!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Configure notifications&lt;/strong&gt; — at minimum, set up Slack or email for critical errors&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consider error sampling&lt;/strong&gt; if you're generating thousands of errors per day:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;   &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sampling_rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;  &lt;span class="c1"&gt;# Log 10% of non-critical errors&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common Gotchas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  SolidQueue Queue Database Not Set Up
&lt;/h3&gt;

&lt;p&gt;Rails 8.1 only configures the queue database in production. If you see &lt;code&gt;Could not find table 'solid_queue_processes'&lt;/code&gt; in development, you need to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add the &lt;code&gt;queue&lt;/code&gt; database to your development config in &lt;code&gt;database.yml&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;config.solid_queue.connects_to = { database: { writing: :queue } }&lt;/code&gt; to your development environment&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;rails db:schema:load:queue&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Migrations Running Against the Wrong Database
&lt;/h3&gt;

&lt;p&gt;When using separate databases, the gem's migrations must be in the directory matching your &lt;code&gt;migrations_paths&lt;/code&gt;. If you see error tables in your primary database, move the migration files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mv &lt;/span&gt;db/migrate/&lt;span class="k"&gt;*&lt;/span&gt;rails_error_dashboard&lt;span class="k"&gt;*&lt;/span&gt; db/error_dashboard_migrate/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  CSRF Errors When Testing with curl
&lt;/h3&gt;

&lt;p&gt;If you're testing the enqueue endpoint with curl and getting 422 errors, that's Rails' CSRF protection working correctly. Use &lt;code&gt;rails runner&lt;/code&gt; or the Rails console instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;rails&lt;/span&gt; &lt;span class="n"&gt;runner&lt;/span&gt; &lt;span class="s2"&gt;"TestErrorJob.perform_later"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Try It Out
&lt;/h2&gt;

&lt;p&gt;The gem is open source and free forever:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://github.com/AnjanJ/rails_error_dashboard" rel="noopener noreferrer"&gt;AnjanJ/rails_error_dashboard&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RubyGems&lt;/strong&gt;: &lt;code&gt;gem install rails_error_dashboard&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live Demo&lt;/strong&gt;: &lt;a href="https://rails-error-dashboard.anjan.dev" rel="noopener noreferrer"&gt;rails-error-dashboard.anjan.dev&lt;/a&gt; (gandalf / youshallnotpass)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're running Rails 8.1 with SolidQueue, this is the easiest way to get production-grade error tracking without paying for a SaaS product. Five minutes of setup, zero monthly fees, and your data never leaves your servers.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Have questions or feedback? Open an issue on &lt;a href="https://github.com/AnjanJ/rails_error_dashboard/issues" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ruby</category>
      <category>rails</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Why I Built Rails Error Dashboard (And Why You Might Want to Self-Host Too)</title>
      <dc:creator>Anjan</dc:creator>
      <pubDate>Sat, 07 Mar 2026 12:40:19 +0000</pubDate>
      <link>https://dev.to/anjanj/why-i-built-rails-error-dashboard-and-why-you-might-want-to-self-host-too-4o35</link>
      <guid>https://dev.to/anjanj/why-i-built-rails-error-dashboard-and-why-you-might-want-to-self-host-too-4o35</guid>
      <description>&lt;p&gt;I needed error tracking for my side project but wanted complete control over my data and monitoring stack. So I built Rails Error Dashboard — a self-hosted, open-source alternative to commercial services. It’s in beta (v0.1.20), production-ready with 850+ tests, and completely free. &lt;a href="https://rails-error-dashboard.anjan.dev/" rel="noopener noreferrer"&gt;Try the live demo →&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn2yj97pugc0wlh2p15fa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn2yj97pugc0wlh2p15fa.png" alt="Dashboard Overiew — Rails Error Dashboard" width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Real Problem: It’s Not About the Money&lt;/strong&gt;&lt;br&gt;
Let me be honest upfront: Most error tracking services have generous free tiers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sentry: Free up to 5,000 errors/month&lt;/li&gt;
&lt;li&gt;Rollbar: Free up to 5,000 events/month&lt;/li&gt;
&lt;li&gt;Bugsnag: Free tier available&lt;/li&gt;
&lt;li&gt;Honeybadger: Free for solo developers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a small side project, these free tiers work fine. I could have used any of them for $0.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;So why did I build my own?&lt;/strong&gt;&lt;br&gt;
What Actually Bothered Me&lt;br&gt;
I run &lt;a href="https://www.audiointelli.com/" rel="noopener noreferrer"&gt;Audio Intelli — an AI platform that transforms audio into searchable intelligence&lt;/a&gt; — on a Raspberry Pi 5 for testing. My entire server costs $80 one-time.&lt;/p&gt;

&lt;p&gt;When I looked at error tracking options, the free tiers seemed great at first. But then I noticed:&lt;/p&gt;

&lt;p&gt;When I looked at error tracking options, the free tiers seemed great at first. But then I noticed:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Free Tiers Have Real Limitations&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sentry’s free tier: Only 7 days of data retention&lt;/li&gt;
&lt;li&gt;One bad deploy could burn through 5,000 errors.&lt;/li&gt;
&lt;li&gt;Limited to basic features (no custom dashboards, advanced workflows)&lt;/li&gt;
&lt;li&gt;You’ll eventually outgrow it as your app grows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Your Error Data Lives on Their Servers&lt;/strong&gt;&lt;br&gt;
Every error contains sensitive information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User IDs and session data&lt;/li&gt;
&lt;li&gt;Request parameters (potentially PII)&lt;/li&gt;
&lt;li&gt;Stack traces showing your business logic&lt;/li&gt;
&lt;li&gt;Accidentally logged secrets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With Audio Intelli handling voice conversations and transcriptions, I wanted complete control over every piece of data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. You’re Dependent on SaaS Pricing&lt;/strong&gt;&lt;br&gt;
Free tiers can change or disappear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Remember Heroku’s free tier? Gone.&lt;/li&gt;
&lt;li&gt;Remember MongoDB Atlas’s free tier changes? Painful.&lt;/li&gt;
&lt;li&gt;What happens when they decide free isn’t sustainable?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you’re locked in with 6 months of historical error data on their platform, moving is painful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. I Wanted to Learn&lt;/strong&gt;&lt;br&gt;
I’m a Rails developer. Error tracking is fundamentally storing exceptions in a database with some analytics. How hard could it be?&lt;/p&gt;

&lt;p&gt;Turns out: not that hard. But incredibly educational.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What I Built&lt;/strong&gt;&lt;br&gt;
Rails Error Dashboard is a Rails Engine that mounts into your existing Rails app. No external services, no APIs to configure, no data leaving your server.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4niq2nigpb5p7956t7eu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4niq2nigpb5p7956t7eu.png" alt="Error nalaytics - Rails Error Dashbaord" width="800" height="439"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Core Features (What It Does Today)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Error Tracking:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatic capture from controllers, background jobs, and Rack middleware&lt;/li&gt;
&lt;li&gt;Platform detection (iOS, Android, Web, API) from user agents&lt;/li&gt;
&lt;li&gt;Manual error reporting API for frontend/mobile apps&lt;/li&gt;
&lt;li&gt;Smart deduplication (groups similar errors automatically)&lt;/li&gt;
&lt;li&gt;Full stack traces with context (user, params, URL, IP)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Dashboard:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clean interface with dark/light mode&lt;/li&gt;
&lt;li&gt;Real-time updates via Turbo Streams (no polling needed)&lt;/li&gt;
&lt;li&gt;Search and filtering with PostgreSQL full-text search&lt;/li&gt;
&lt;li&gt;Error detail views with occurrence history&lt;/li&gt;
&lt;li&gt;Works in both full Rails and API-only apps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Analytics:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;7-day error trend charts&lt;/li&gt;
&lt;li&gt;Severity breakdowns (critical, high, medium, low)&lt;/li&gt;
&lt;li&gt;Platform health monitoring&lt;/li&gt;
&lt;li&gt;Automatic spike detection&lt;/li&gt;
&lt;li&gt;Affected users tracking&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Workflow Management:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Assign errors to team members&lt;/li&gt;
&lt;li&gt;Set priority levels&lt;/li&gt;
&lt;li&gt;Add comment threads&lt;/li&gt;
&lt;li&gt;Mark as resolved with references&lt;/li&gt;
&lt;li&gt;Batch operations (resolve/delete multiple errors)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Optional Features (Opt-in During Install):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Notifications: Slack, Discord, Email, PagerDuty, Custom Webhooks&lt;/li&gt;
&lt;li&gt;Advanced Analytics: Fuzzy error matching, cascade detection, co-occurring errors, pattern recognition&lt;/li&gt;
&lt;li&gt;Performance: Async logging, error sampling, separate database support&lt;/li&gt;
&lt;li&gt;Plugins: Jira integration, custom extensions via event hooks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What It Doesn’t Do (Being Honest)&lt;/strong&gt;&lt;br&gt;
This isn’t a Sentry replacement for everyone:&lt;/p&gt;

&lt;p&gt;❌ No distributed tracing — If you’re debugging microservices across 20 services, Sentry is better&lt;br&gt;
❌ No session replay — I don’t capture user sessions (yet)&lt;br&gt;
❌ No advanced source maps — JavaScript error mapping is basic (planned)&lt;br&gt;
❌ Limited integrations — 5 built-in vs Sentry’s 50+&lt;br&gt;
❌ Self-hosted only — You manage your own infrastructure&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who this is NOT for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Large teams (50+ developers)&lt;/li&gt;
&lt;li&gt;Complex distributed architectures&lt;/li&gt;
&lt;li&gt;Teams that want fully managed infrastructure&lt;/li&gt;
&lt;li&gt;Companies needing enterprise support contracts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Who this IS for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Solo developers running side projects&lt;/li&gt;
&lt;li&gt;Indie hackers bootstrapping SaaS&lt;/li&gt;
&lt;li&gt;Small teams (2–5 people) who value independence&lt;/li&gt;
&lt;li&gt;Privacy-conscious applications (GDPR, healthcare, finance)&lt;/li&gt;
&lt;li&gt;Developers who enjoy self-hosting&lt;/li&gt;
&lt;li&gt;Anyone learning how error tracking works&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwkx6ztl7qu43hl4r2uq0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwkx6ztl7qu43hl4r2uq0.png" alt="Error Details — Rails Error Dashboard" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Technical Reality (No Exaggeration)&lt;/strong&gt;&lt;br&gt;
I built this with clean architecture because I hate messy code:&lt;/p&gt;

&lt;p&gt;CQRS Pattern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Commands for write operations: &lt;code&gt;LogError&lt;/code&gt;, &lt;code&gt;ResolveError&lt;/code&gt;, &lt;code&gt;BatchOperations&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Queries for read operations: &lt;code&gt;ErrorsList&lt;/code&gt;, &lt;code&gt;DashboardStats&lt;/code&gt;, &lt;code&gt;AnalyticsStats&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Services for business logic: &lt;code&gt;PlatformDetector&lt;/code&gt;, &lt;code&gt;SimilarityCalculator&lt;/code&gt;, &lt;code&gt;BaselineCalculator&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Value Objects for immutable data: &lt;code&gt;ErrorContext&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Testing:&lt;/strong&gt;                                                                                                                                                          &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;137 RSpec files
&lt;/li&gt;
&lt;li&gt;2,615 individual test cases
&lt;/li&gt;
&lt;li&gt;Tests across Ruby 3.2–4.0 and Rails 7.0–8.1
&lt;/li&gt;
&lt;li&gt;All passing consistently in CI
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Current Version: v0.3.1&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pre-1.0 means the API might change before v1.0&lt;/li&gt;
&lt;li&gt;Pre-1.0 doesn't mean unstable — I use it in production&lt;/li&gt;
&lt;li&gt;I'm gathering feedback before locking the public API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Supports:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ruby 3.2, 3.3, 3.4, 4.0&lt;/li&gt;
&lt;li&gt;Rails 7.0, 7.1, 7.2, 8.0, 8.1&lt;/li&gt;
&lt;li&gt;PostgreSQL (recommended), MySQL, SQLite&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Installation: Actually 5 Minutes&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Gemfile&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="err"&gt;‘&lt;/span&gt;&lt;span class="n"&gt;rails_error_dashboard&lt;/span&gt;&lt;span class="err"&gt;’&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bundle &lt;span class="nb"&gt;install
&lt;/span&gt;rails generate rails_error_dashboard:install
rails db:migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The interactive installer asks which optional features you want:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;? Enable Slack notifications? (y/N)
? Enable advanced analytics? (y/N)
? Enable async logging for performance? (y/N)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Choose what you need. Everything works out of the box without configuration.&lt;/p&gt;

&lt;p&gt;Then visit &lt;code&gt;http://localhost:3000/error_dashboard&lt;/code&gt; and log in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Username: &lt;code&gt;gandalf&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Password: &lt;code&gt;youshallnotpass&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(Yes, LOTR-themed defaults. Change them in &lt;code&gt;config/initializers/rails_error_dashboard.rb&lt;/code&gt; before production!)&lt;/p&gt;

&lt;p&gt;— -&lt;/p&gt;

&lt;p&gt;Try Before You Install: Live Demo&lt;br&gt;
I’m running a live demo with 250+ sample errors from fictional scenarios:&lt;/p&gt;

&lt;p&gt;Demo URL: &lt;a href="https://rails-error-dashboard.anjan.dev" rel="noopener noreferrer"&gt;https://rails-error-dashboard.anjan.dev&lt;/a&gt;&lt;br&gt;
Username: &lt;code&gt;gandalf&lt;/code&gt;&lt;br&gt;
Password: &lt;code&gt;youshallnotpass&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Click around. Test search. Try filters. Check out the analytics. See if it fits your needs.&lt;/p&gt;

&lt;p&gt;No signup, no credit card, no tracking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Honest Comparison: When to Use What&lt;/strong&gt;&lt;br&gt;
Use Sentry/Rollbar Free Tier If:&lt;/p&gt;

&lt;p&gt;✅ You’re just starting out (5K errors/month is plenty)&lt;br&gt;
✅ You’re okay with 7–30 day data retention&lt;br&gt;
✅ You don’t mind data on their servers&lt;br&gt;
✅ You want zero ops work (managed infrastructure)&lt;br&gt;
✅ You need their extensive integrations (Sentry has 50+)&lt;br&gt;
✅ You might scale to a large team eventually&lt;/p&gt;

&lt;p&gt;For most solo devs starting their first side project, Sentry’s free tier is completely fine.&lt;/p&gt;

&lt;p&gt;Use Rails Error Dashboard If:&lt;/p&gt;

&lt;p&gt;✅ You want unlimited errors with no ceiling&lt;br&gt;
✅ You need long-term data retention (years, not days)&lt;br&gt;
✅ You’re privacy-conscious (GDPR, HIPAA, data sovereignty)&lt;br&gt;
✅ You want to own your monitoring stack completely&lt;br&gt;
✅ You enjoy self-hosting and learning&lt;br&gt;
✅ You’re worried about SaaS pricing changes long-term&lt;br&gt;
✅ You want full customization (access to source code)&lt;br&gt;
✅ You’re running on constrained infrastructure (Raspberry Pi, home server)&lt;/p&gt;

&lt;p&gt;The honest truth: If you value independence, privacy, unlimited usage, and learning, Rails Error Dashboard is better. If you just want to ship fast and don’t care about the above, use Sentry’s free tier.&lt;/p&gt;

&lt;p&gt;What About Rails 8 and Solid Errors?&lt;br&gt;
You might be thinking:&lt;br&gt;
”Doesn’t Solid Errors suffice, which also does error tracking now?”&lt;/p&gt;

&lt;p&gt;Solid Errors exists but is intentionally minimalist:&lt;/p&gt;

&lt;p&gt;Solid Errors is for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Absolute simplicity (bare-bones logging)&lt;/li&gt;
&lt;li&gt;No frills, no complexity&lt;/li&gt;
&lt;li&gt;Just store errors in your database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rails Error Dashboard is for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Professional monitoring features&lt;/li&gt;
&lt;li&gt;Analytics, trends, spike detection&lt;/li&gt;
&lt;li&gt;Team workflows (assign, prioritize, comment)&lt;/li&gt;
&lt;li&gt;Multi-channel notifications&lt;/li&gt;
&lt;li&gt;Advanced features (fuzzy matching, cascade detection)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both are self-hosted and free. Choose based on your needs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Solid Errors: You want the simplest possible solution&lt;/li&gt;
&lt;li&gt;Rails Error Dashboard: You want feature-complete monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Cost Comparison (Being Realistic)&lt;br&gt;
Sentry Free Tier:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cost: $0&lt;/li&gt;
&lt;li&gt;Limits: 5,000 errors/month, 7-day retention&lt;/li&gt;
&lt;li&gt;When you outgrow it: $26–80/month&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Rails Error Dashboard:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cost: $0 (forever)&lt;/li&gt;
&lt;li&gt;Limits: None (unlimited errors, unlimited retention)&lt;/li&gt;
&lt;li&gt;Infrastructure: Runs on your existing Rails server&lt;/li&gt;
&lt;li&gt;Maintenance: ~1 hour/month (responding to updates, issues)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The real savings isn’t about avoiding $26/month.&lt;/p&gt;

&lt;p&gt;The real value is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;No artificial limits — Deploy a bug that generates 50K errors? No problem.&lt;/li&gt;
&lt;li&gt;Keep data forever — Historical trends over years, not days&lt;/li&gt;
&lt;li&gt;Independence — Never worry about pricing changes&lt;/li&gt;
&lt;li&gt;Privacy — Complete data sovereignty&lt;/li&gt;
&lt;li&gt;Learning — Understand how error tracking actually works&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The Audio Intelli Connection&lt;/strong&gt;&lt;br&gt;
Rails Error Dashboard started as an internal tool for Audio Intelli.&lt;/p&gt;

&lt;p&gt;When you’re managing errors across:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;iOS app (Swift)&lt;/li&gt;
&lt;li&gt;Android app (Kotlin)&lt;/li&gt;
&lt;li&gt;Web dashboard (Rails + Turbo)&lt;/li&gt;
&lt;li&gt;Background AI processing (Queues + OpenAI/Whisper)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you need unified error tracking. I could have used Sentry’s free tier, but I wanted:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complete privacy for voice data&lt;/li&gt;
&lt;li&gt;Unlimited errors without worrying about quotas&lt;/li&gt;
&lt;li&gt;Full control over the monitoring stack&lt;/li&gt;
&lt;li&gt;Long-term data retention&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I built it for myself. Then I realized other indie Rails developers might value the same things.&lt;/p&gt;

&lt;p&gt;So I:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cleaned up the code&lt;/li&gt;
&lt;li&gt;Wrote comprehensive tests&lt;/li&gt;
&lt;li&gt;Added extensive documentation (25+ guides)&lt;/li&gt;
&lt;li&gt;Made it fully configurable&lt;/li&gt;
&lt;li&gt;Open-sourced it under MIT license&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re working with audio: Audio Intelli transforms podcasts, meetings, and voice recordings into searchable, actionable intelligence. We’re in private beta. &lt;a href="https://www.audiointelli.com/" rel="noopener noreferrer"&gt;Join the waitlist →&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Same philosophy: build tools you own, not tools that own you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I Open-Sourced It
&lt;/h2&gt;

&lt;p&gt;Reason 1: I’m Not Building a SaaS&lt;/p&gt;

&lt;p&gt;I don’t want to run error monitoring as a business. I built this to solve my own problem. Open-sourcing it means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Others can maintain it if I get busy&lt;/li&gt;
&lt;li&gt;The Rails community can make it better&lt;/li&gt;
&lt;li&gt;Nobody gets vendor locked-in to me&lt;/li&gt;
&lt;li&gt;It stays free forever (MIT license)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reason 2: Rails Deserves Better Self-Hosted Options&lt;/p&gt;

&lt;p&gt;The Rails ecosystem is moving toward eliminating unnecessary SaaS dependencies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kamal → replaces Heroku&lt;/li&gt;
&lt;li&gt;Solid Queue → replaces Sidekiq Enterprise&lt;/li&gt;
&lt;li&gt;Solid Cache → replaces Redis Cloud&lt;/li&gt;
&lt;li&gt;Rails Error Dashboard → alternative to Sentry/Rollbar&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the indie hacker way: own your tools, control your costs, stay independent.&lt;/p&gt;

&lt;p&gt;Reason 3: I Believe in Data Sovereignty&lt;/p&gt;

&lt;p&gt;Your error data contains your business logic, user behavior patterns, and potentially sensitive information.&lt;/p&gt;

&lt;p&gt;You should own it. Not rent access to it.&lt;/p&gt;

&lt;p&gt;The Long-Term Plan&lt;br&gt;
I’m committed to maintaining this project long-term because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I use it myself — Dogfooding ensures I care about quality&lt;/li&gt;
&lt;li&gt;The Rails community needs this — Real demand for self-hosted error tracking&lt;/li&gt;
&lt;li&gt;It’s not a business — No pressure to monetize or pivot.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;br&gt;
This isn’t about saving money. Sentry’s free tier is generous, and if you’re just starting out, use it!&lt;/p&gt;

&lt;p&gt;This is about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ownership — Your data, your server, your rules&lt;/li&gt;
&lt;li&gt;Independence — Not at the mercy of pricing changes&lt;/li&gt;
&lt;li&gt;Privacy — Complete data sovereignty&lt;/li&gt;
&lt;li&gt;Learning — Understanding how error tracking works&lt;/li&gt;
&lt;li&gt;Unlimited — No caps, no quotas, no artificial limits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If those values resonate with you, give Rails Error Dashboard a try.&lt;/p&gt;

&lt;p&gt;It’s not perfect. It’s not as feature-rich as Sentry. But it’s free, it’s open-source, you own your data, and it works.&lt;/p&gt;

&lt;p&gt;That’s good enough for me and might be for other indie Rails developers who value independence.&lt;/p&gt;

&lt;p&gt;Links&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Live Demo: &lt;a href="https://rails-error-dashboard.anjan.dev/" rel="noopener noreferrer"&gt;rails-error-dashboard.anjan.dev&lt;/a&gt; (gandalf / youshallnotpass)&lt;/li&gt;
&lt;li&gt;GitHub: &lt;a href="https://github.com/AnjanJ/rails_error_dashboard" rel="noopener noreferrer"&gt;github.com/AnjanJ/rails_error_dashboard&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Audio Intelli: &lt;a href="https://www.audiointelli.com/" rel="noopener noreferrer"&gt;audiointelli.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>opensource</category>
      <category>monitoring</category>
    </item>
    <item>
      <title>zs: One Command to Rule Your Zed Setup</title>
      <dc:creator>Anjan</dc:creator>
      <pubDate>Sun, 27 Jul 2025 13:04:17 +0000</pubDate>
      <link>https://dev.to/anjanj/zs-one-command-to-rule-your-zed-setup-5775</link>
      <guid>https://dev.to/anjanj/zs-one-command-to-rule-your-zed-setup-5775</guid>
      <description>&lt;h2&gt;
  
  
  zs: One Command to Rule Your Zed Setup
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: Tired of manually configuring Zed for every project? Just run &lt;code&gt;zs&lt;/code&gt;. It auto-detects your project type, installs debug dependencies, creates tasks, and sets up git hooks. Zero configuration required.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; https://raw.githubusercontent.com/AnjanJ/zs/main/install.sh | bash
&lt;span class="nb"&gt;cd &lt;/span&gt;any-project
zs
✅ Rails project ready &lt;span class="o"&gt;(&lt;/span&gt;15 tasks, debugging enabled&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Every time I switched projects in &lt;a href="https://zed.dev" rel="noopener noreferrer"&gt;Zed&lt;/a&gt;, I found myself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🔧 Manually creating &lt;code&gt;.zed/tasks.json&lt;/code&gt; for that specific framework&lt;/li&gt;
&lt;li&gt;🐛 Setting up debug configurations (that never quite worked)&lt;/li&gt;
&lt;li&gt;📦 Installing language-specific debug adapters&lt;/li&gt;
&lt;li&gt;🔒 Configuring different git hooks for work vs personal projects&lt;/li&gt;
&lt;li&gt;😤 Googling the same configurations over and over&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Multiply this by switching between Rails, React, Python, and Elixir projects daily... you get the idea.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution: zs
&lt;/h2&gt;

&lt;p&gt;After one too many manual setups, I decided to automate everything. The goal? &lt;strong&gt;Zero cognitive load&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ~/work/canvas-lti-app
zs
✅ Rails project ready &lt;span class="o"&gt;(&lt;/span&gt;21 tasks, debugging enabled&lt;span class="o"&gt;)&lt;/span&gt;
  → Work project: commits need &lt;span class="s1"&gt;'Refs: JIRA-XXXX'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it. No flags. No options. No decisions.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;zs&lt;/code&gt; is built on a simple philosophy: &lt;strong&gt;The best interface is no interface&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When you run &lt;code&gt;zs&lt;/code&gt;, it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Detects&lt;/strong&gt; your project type automatically&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rails? ✓ (Gemfile + config/application.rb)&lt;/li&gt;
&lt;li&gt;React? ✓ (package.json with react dependency)&lt;/li&gt;
&lt;li&gt;Python? ✓ (requirements.txt)&lt;/li&gt;
&lt;li&gt;Elixir? ✓ (mix.exs)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Installs&lt;/strong&gt; only what Zed needs&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ruby: &lt;code&gt;debug&lt;/code&gt; gem (provides rdbg)&lt;/li&gt;
&lt;li&gt;Python: &lt;code&gt;debugpy&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Elixir: &lt;code&gt;elixir-ls&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Nothing else - no &lt;code&gt;bundle install&lt;/code&gt; or &lt;code&gt;npm install&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Creates&lt;/strong&gt; proper configurations&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.zed/tasks.json&lt;/code&gt; with framework-specific tasks&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.zed/debug.json&lt;/code&gt; with working debug configs (using Zed's format, not VS Code's!)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Configures&lt;/strong&gt; smart git hooks&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Work projects: Reminds about JIRA tickets&lt;/li&gt;
&lt;li&gt;Personal projects: Standard format&lt;/li&gt;
&lt;li&gt;Never blocks, just reminds&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Reports&lt;/strong&gt; success in one line&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;✅ Project ready (15 tasks)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  ⚠️ Note on Debugging Support
&lt;/h2&gt;

&lt;p&gt;Debugging in Zed is still evolving, and we're actively testing configurations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Ruby&lt;/strong&gt;: Experimental support via &lt;code&gt;debug&lt;/code&gt; gem&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Python&lt;/strong&gt;: Full support with &lt;code&gt;debugpy&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript/TypeScript&lt;/strong&gt;: Full support&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Elixir&lt;/strong&gt;: Not yet supported in Zed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We're updating configurations as Zed's debugging capabilities mature. Your mileage may vary!&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-World Examples
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Rails Project
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Auto-generated&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;.zed/tasks.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;includes:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"💎 Rails Server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bundle"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"exec"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rails"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"server"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"🧪 Run Current Test File"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bundle"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"exec"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rspec"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$ZED_FILE"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;more&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;tasks&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Work vs Personal Context
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Personal project&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/code/my-app
zs
✅ Rails project ready &lt;span class="o"&gt;(&lt;/span&gt;15 tasks, debugging enabled&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Work project (auto-detected from path)&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ~/work/enterprise-app
zs
✅ Rails project ready &lt;span class="o"&gt;(&lt;/span&gt;21 tasks, debugging enabled&lt;span class="o"&gt;)&lt;/span&gt;
  → Work project: commits need &lt;span class="s1"&gt;'Refs: JIRA-XXXX'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Smart Caching
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# First run&lt;/span&gt;
zs
✅ React project ready &lt;span class="o"&gt;(&lt;/span&gt;16 tasks, debugging enabled&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Run again&lt;/span&gt;
zs
✅ Already configured &lt;span class="o"&gt;(&lt;/span&gt;react project&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Hidden Power
&lt;/h2&gt;

&lt;p&gt;While the interface is minimal, &lt;code&gt;zs&lt;/code&gt; packs some smart features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;30-day refresh&lt;/strong&gt;: Automatically updates stale configs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker awareness&lt;/strong&gt;: Adjusts commands for containerized environments&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.nohooks&lt;/code&gt; file: Disable git hooks when needed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Force refresh&lt;/strong&gt;: &lt;code&gt;zs force&lt;/code&gt; (hidden feature for power users)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Performance
&lt;/h2&gt;

&lt;p&gt;Setup time: &lt;strong&gt;&amp;lt; 100ms&lt;/strong&gt; ⚡&lt;/p&gt;

&lt;p&gt;That's faster than opening the tasks menu in most editors.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# One-time install&lt;/span&gt;
curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; https://raw.githubusercontent.com/AnjanJ/zs/main/install.sh | bash
&lt;span class="nb"&gt;source&lt;/span&gt; ~/.zshrc

&lt;span class="c"&gt;# Then forever&lt;/span&gt;
&lt;span class="nb"&gt;cd &lt;/span&gt;any-project
zs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Philosophy
&lt;/h2&gt;

&lt;p&gt;After building increasingly complex configurations, I realized the best solution was radical simplification:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ 10+ commands → ✅ 1 command&lt;/li&gt;
&lt;li&gt;❌ Multiple flags → ✅ 0 flags
&lt;/li&gt;
&lt;li&gt;❌ Verbose output → ✅ 1 line&lt;/li&gt;
&lt;li&gt;❌ Manual validation → ✅ Automatic&lt;/li&gt;
&lt;li&gt;❌ Decision fatigue → ✅ Zero decisions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As Antoine de Saint-Exupéry said: "Perfection is achieved not when there is nothing more to add, but when there is nothing left to take away."&lt;/p&gt;

&lt;h2&gt;
  
  
  Open Source
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;zs&lt;/code&gt; is MIT licensed and open for contributions. The entire brain is just 231 lines of shell script.&lt;/p&gt;

&lt;p&gt;🌟 &lt;a href="https://github.com/AnjanJ/zs" rel="noopener noreferrer"&gt;GitHub: AnjanJ/zs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Special features for contributors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Plugin system for custom project types&lt;/li&gt;
&lt;li&gt;Team configurations via &lt;code&gt;.zsrc&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;CI/CD ready with GitHub Actions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;Currently, &lt;code&gt;zs&lt;/code&gt; supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rails / Ruby&lt;/li&gt;
&lt;li&gt;React / Node.js&lt;/li&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;li&gt;Elixir&lt;/li&gt;
&lt;li&gt;LTI projects&lt;/li&gt;
&lt;li&gt;Docker environments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Want support for your stack? PRs welcome!&lt;/p&gt;

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

&lt;p&gt;If you use Zed and switch between projects, give &lt;code&gt;zs&lt;/code&gt; a try:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-sSL&lt;/span&gt; https://raw.githubusercontent.com/AnjanJ/zs/main/install.sh | bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then just run &lt;code&gt;zs&lt;/code&gt; in any project. That's it.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;One command. Zero configuration. Pure productivity.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;zs&lt;/code&gt; saves you time, give it a star on &lt;a href="https://github.com/AnjanJ/zs" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. If you have ideas for improvement, I'd love to hear them!&lt;/p&gt;

&lt;p&gt;What repetitive tasks do you automate in your development workflow? Let me know in the comments!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Anjan Jagirdar is a developer who believes the best tools get out of your way. When not automating workflows, he's probably debugging why his automation isn't working.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F521y8ymz99w4tp2ajtfp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F521y8ymz99w4tp2ajtfp.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>zed</category>
      <category>productivity</category>
      <category>developertools</category>
      <category>automation</category>
    </item>
    <item>
      <title>Setting Up Your macOS Development Environment and Automating Backups.</title>
      <dc:creator>Anjan</dc:creator>
      <pubDate>Sat, 27 Jan 2024 07:44:59 +0000</pubDate>
      <link>https://dev.to/anjanj/setting-up-your-macos-development-environment-and-automating-backups-1nm1</link>
      <guid>https://dev.to/anjanj/setting-up-your-macos-development-environment-and-automating-backups-1nm1</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2sx9oiblmjstlxzapgpk.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2sx9oiblmjstlxzapgpk.jpeg" alt="Worli Sea link at Dusk in Mumbai India" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up Your macOS Development Environment and Automating Backups.
&lt;/h2&gt;

&lt;p&gt;My Repo : &lt;a href="https://github.com/AnjanJ/my-mac-settings" rel="noopener noreferrer"&gt;My-Mac-Settings&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I recently got a new M3 Max 14" for myself and wanted to port over all my setup from earlier 14" M1 pro. Hence I came up with below scripts to make things easy for me.&lt;/p&gt;

&lt;p&gt;Please leave your suggestions &amp;amp; thoughts.&lt;/p&gt;

&lt;p&gt;In this comprehensive guide, I'll walk you through the process of setting up a robust development environment on your macOS system. I'll cover everything from installing essential tools and applications to automating the backup of critical configuration files.&lt;/p&gt;

&lt;p&gt;My Brewfile contains all the apps installed via Homebrew, Macapp Store and also all of my VSCode extensions.&lt;/p&gt;

&lt;p&gt;Then we will use the script &lt;code&gt;auto_update_Brewfile.sh&lt;/code&gt; to update &amp;amp; upgrade brew formulae and apps installed using Homebrew. It also backups &lt;code&gt;.zshrc&lt;/code&gt; file if it has been changed in past week.&lt;/p&gt;

&lt;h2&gt;
  
  
  Below are the paid apps I am using.
&lt;/h2&gt;

&lt;p&gt;You can go through the entire list of apps in my &lt;a href="https://github.com/AnjanJ/my-mac-settings/blob/main/Brewfile" rel="noopener noreferrer"&gt;Brewfile&lt;/a&gt; and remove or add apps as per your need. &lt;/p&gt;

&lt;h3&gt;
  
  
  AlDente Pro
&lt;/h3&gt;

&lt;p&gt;AlDente Pro is a premium application designed to manage your MacBook's battery and charging effectively. It optimizes your battery's lifespan and keeps you informed about its health. Learn more about it &lt;a href="https://apphousekitchen.com/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  iStat Menus
&lt;/h3&gt;

&lt;p&gt;iStat Menus offers real-time monitoring of your Mac's performance, including CPU usage, memory utilization, and network statistics. It's a powerful tool for keeping an eye on your system's health. Explore it further &lt;a href="https://bjango.com/mac/istatmenus/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Raycast
&lt;/h3&gt;

&lt;p&gt;Raycast is a productivity powerhouse that replaces Spotlight and provides quick access to a wide range of functions. It enhances your workflow and simplifies everyday tasks. Discover more about it &lt;a href="https://www.raycast.com/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Warp Terminal.
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.warp.dev/" rel="noopener noreferrer"&gt;Warp&lt;/a&gt; is free for now and my goto terminal app which replaced iTerm for me. Its beautiful and very easy to use, I have paired it up with a free app called &lt;a href="https://fig.io/" rel="noopener noreferrer"&gt;Fig.io&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Heart of the Setup: &lt;code&gt;setup_dev_env.sh&lt;/code&gt; Script
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;setup_dev_env.sh&lt;/code&gt; script is a powerful automation tool for macOS. It's designed to perform the following tasks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Check for and install Homebrew.&lt;/li&gt;
&lt;li&gt;Download a Brewfile from a specified URL.&lt;/li&gt;
&lt;li&gt;Use Homebrew to install all the software listed in the Brewfile.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Initial Steps: Downloading and Running the Script
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Downloading the Script:&lt;/strong&gt; You can either clone the script from a &lt;a href="https://github.com/AnjanJ/my-mac-settings" rel="noopener noreferrer"&gt;my repository&lt;/a&gt; or copy-paste it directly from the &lt;a href="https://raw.githubusercontent.com/AnjanJ/my-mac-settings/main/Brewfile" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Hosting the Brewfile:&lt;/strong&gt; Your Brewfile, which lists all the desired software and packages, should be hosted online and accessible via a direct URL. This URL is used by the script to download the Brewfile.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Modifying and Executing the Script:&lt;/strong&gt; After downloading, modify the script to include the URL of your Brewfile. Then, run the script in the terminal after giving it execute permissions using &lt;code&gt;chmod +x setup_dev_env.sh&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automating Brewfile Backups with Crontab
&lt;/h2&gt;

&lt;p&gt;An essential part of managing a development environment is keeping your software list up to date. This is where the &lt;a href="https://github.com/AnjanJ/my-mac-settings/blob/main/auto_update_Brewfile.sh" rel="noopener noreferrer"&gt;&lt;code&gt;auto_update_Brewfile.sh&lt;/code&gt;&lt;/a&gt; script comes in, coupled with cron jobs for automation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setting Up Cron Jobs:&lt;/strong&gt; Use &lt;code&gt;crontab -e&lt;/code&gt; to edit your cron jobs. Add a line to schedule the backup script to run at specific times, like every Friday and Sunday at 7 PM.&lt;/p&gt;

&lt;p&gt;You can check if there are any present cron tasks or your changes have been made correctly or not by using &lt;code&gt;crontab -l&lt;/code&gt; command. &lt;br&gt;
It will show output as below.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fek0kgrinryvbtaff751i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fek0kgrinryvbtaff751i.png" alt="Terminal showing output of crontab -l command" width="800" height="128"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Script Execution and Permissions:&lt;/strong&gt; Make sure the backup script is executable by using &lt;code&gt;chmod +x auto_update_Brewfile.sh&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Backup and Update:&lt;/strong&gt; The script updates brew formulae, upgrades installed apps, backs up the old Brewfile, generates a new one, back ups .zshrc file if it has been changed in past week and pushes the updates to a specified GitHub repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  Troubleshooting and Tips
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Regularly check your cron jobs and script logs to ensure they're running as expected.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Test the scripts manually before relying on the automated schedule.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;With the setup and automation described in this guide, you can easily maintain a robust development environment on your macOS system. Plus, you'll have peace of mind knowing that your essential configuration files are automatically backed up on GitHub.&lt;/p&gt;

&lt;p&gt;Start by forking &lt;a href="https://github.com/AnjanJ/my-mac-settings" rel="noopener noreferrer"&gt;My-Mac-Settings&lt;/a&gt; and following the steps outlined here or in the readme. Enjoy your optimized macOS experience!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flzoz1s8eot8e4hmuxd43.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flzoz1s8eot8e4hmuxd43.png" alt="AJ's WFH setup" width="800" height="685"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>development</category>
      <category>setup</category>
      <category>macbook</category>
      <category>rails</category>
    </item>
  </channel>
</rss>
