Open Source Project of the Day (Part 27): Awesome AI Coding – A One-Stop AI Programming Resource Navigator

Introduction

“AI coding tools and resources are scattered everywhere. A topically organized, searchable, contributable list can save enormous amounts of search time.”

This is Part 27 of the “Open Source Project of the Day” series. Today we explore Awesome AI Coding (GitHub).

When doing AI-assisted programming, you’ll face questions like: which editor or terminal tool should I use? For multi-agent frameworks, should I pick MetaGPT or CrewAI? What RAG frameworks and vector databases are available? Where do I find MCP servers? What ready-made templates are there for Claude Code Rules and Skills? Awesome AI Coding is exactly that kind of curated resource navigator: covering 12 major sections including code generation, Agent development, RAG, LLM applications, code review and testing, prompt engineering, MCP, code understanding, Agent Skills, development acceleration tools, learning resources, and ClaudeCode Rules. Each section lists representative projects with brief descriptions, supports both Chinese and English (README_zh.md), table of contents navigation, and in-browser search. This article focuses on the content structure and what each section can help you with, for easy reference or contribution.

What You’ll Learn

  • Awesome AI Coding’s positioning: a one-stop AI programming resource navigator
  • What each of the 12 categories covers, with typical entries
  • How to search quickly (table of contents, Ctrl+F), Chinese/English entries, and contribution methods
  • ClaudeCode Rules section: language/framework/practice rule file structure
  • Complementary relationship with other Awesome-style lists

Prerequisites

  • Basic familiarity with AI-assisted programming, LLMs, Agents, RAG, and MCP is sufficient — the list itself is designed as a “where to go next” entry point after getting the basics

Project Background

Project Introduction

Awesome AI Coding is a curated collection of AI coding resources (Awesome-style), aimed at developers and teams who “use AI to write code, build Agents, do RAG, and build LLM applications.” Content is divided into 12 major categories, each further broken down into subcategories or directly listing projects — each with a brief description and link for quick navigation to editors, frameworks, vector databases, MCP platforms, Skill collections, spec-driven development tools, and more. The repo provides both an English README and a Chinese README_zh.md, and welcomes continuous additions of quality resources via Issues/PRs.

Core problems the project solves:

  • AI coding tools, frameworks, Skills, and rules are scattered across GitHub, websites, and communities — hard to browse systematically
  • Need a “categorized by use case” navigator, not just a generic AI list
  • Want to cover desktop/terminal editors, Agent frameworks, RAG, MCP, and ClaudeCode Rules all in one place for easy end-to-end reference

Target user groups:

  • Developers just starting with AI coding who want a quick ecosystem overview
  • Teams needing to evaluate editors, Agent frameworks, RAG, MCP, and Skills
  • People using Claude Code/Cursor who are looking for Rules and Skills templates
  • Contributors and maintainers of Awesome-style lists

Project Stats (Brief)

  • 📦 Content format: Markdown documents (README.md, README_zh.md) + rules/ directory in the repo (ClaudeCode Rules)
  • 📄 License: MIT
  • 🌐 Entry points: English README, Chinese README_zh.md
  • 📝 Updates: README notes continuous updates, Issues/PRs welcome; footer has Last Updated date (e.g., 2026-01-29)

Main Features: Content Structure Overview

Core Purpose

Awesome AI Coding’s core purpose is to aggregate AI coding resources by topic and provide a searchable, navigable, contributable entry point:

  1. Clear categories: 12 major categories + subcategories, covering the complete pipeline from “editors/IDEs” to “ClaudeCode Rules”
  2. Each entry has a description: Project name + link + one-line description, easy to decide whether to click
  3. Bilingual: Main README in English, README_zh in Chinese, for different reading preferences
  4. Searchable: README suggests using Ctrl+F / Cmd+F to search by keyword
  5. Extensible: Contributing guide explains how to add resources via Fork + PR

12 Major Categories Overview

1. AI Code Editors & IDEs

  • Desktop Editors: Cursor, GitHub Copilot, Replit, Bolt, Devin AI, Trae (ByteDance), Windsurf, CodeBuddy, etc. — covering desktop and online AI coding environments.
  • Terminal Tools: Claude Code, OpenCode, Codex, Gemini CLI, and other CLI/terminal tools.

Ideal for: Quick comparison when choosing an IDE or terminal tool.

2. AI Agent Frameworks

  • Multi-Agent Systems: MetaGPT, CrewAI, AutoGen, JoyAgent-JDGeni, 500 AI Agents, Agent Design Patterns (Chinese), etc.
  • Agent Development Frameworks: LangGraph, AgentEvolv, etc.
  • Coding Agent Tools: Claude Code Plugins, Serena, OpenAutoGLM, SuperClaude Framework, etc.

Ideal for: Framework and tool selection when building multi-agent systems, orchestration, and coding agents.

3. RAG & Knowledge Bases

  • RAG Frameworks: e.g., RAGFlow.
  • Vector Databases: Supabase, Pinecone, Weaviate, etc.
  • Knowledge Graphs: Graphiti (real-time knowledge graph, can be used with code understanding).

Ideal for: Knowledge base Q&A, retrieval augmentation, vector and graph storage selection.

4. LLM Development Frameworks

  • Frameworks & Tools: LangChain, LlamaIndex, Haystack.
  • LLM Application Examples: Awesome LLM Apps, Agents Towards Production, etc.

Ideal for: Framework and example reference when building LLM applications and production-grade Agents.

5. Code Review & Testing

  • Code Review Tools: e.g., CodeRabbit and other AI code review assistants.

Ideal for: Integrating AI code review and quality tools.

6. Prompt Engineering

  • Prompt Tools: System Prompt Leak, System Prompts and Models of AI Tools (30,000+ lines of tool structure and prompts), etc.
  • Prompt Resources: Awesome Prompts, Prompt Engineering Guide, etc.

Ideal for: Learning and collecting system prompts and prompt engineering practices.

7. MCP Protocol & Tools

  • MCP Frameworks: Awesome MCP Servers and similar collections.
  • MCP Server Platforms: MCP.so, MCP.ad (33,000+ servers), Cursor Directory, Pulse MCP, Glama MCP, etc.

Ideal for: Finding MCP servers and integrating them with Cursor/Claude Code.

8. Code Analysis & Understanding

  • Code Understanding Tools: DeepWiki (deep GitHub repo understanding, Devin-powered Q&A), etc.
  • Code Analysis: CodeQL, etc.

Ideal for: Code understanding, static analysis, and security scanning.

9. Agent Skills

  • Official Skills: Superpowers, Anthropic Skills, OpenAI Skills, Trail of Bits Skills, etc.
  • Community Skills: Antigravity Awesome Skills (552+), Vercel/AWS/Obsidian/Context Engineering specialized collections, etc.
  • Resource Collections & Platforms: Claude Code Plugins, SkillsMP, skill0, multiple Awesome Claude Skills collections, NotebookLM Skill, OpenSkills, Skills, etc.

Ideal for: Selecting or referencing Agent Skills, plugins, and marketplaces for Claude Code/Cursor.

10. Development Tools & Acceleration

  • Documentation Tools: MarkItDown (multi-format to Markdown, LLM-compatible), etc.
  • Project Management: Spec-Kit (spec-driven development, Copilot integration), OpenSpec, BMAD-METHOD, etc.

Ideal for: Document conversion, spec-driven development, and requirements-to-code collaboration workflows.

11. Learning Resources

  • Tutorials & Guides: AI Code Guide, Agent Design Patterns CN (with local and Colab), etc.
  • Community Resources: Awesome AI, Awesome LLM Resources, etc.

Ideal for: Entry-level pathways and advanced learning.

12. ClaudeCode Rules

The rules/ directory in the repo provides ready-to-use development rules and specifications:

  • Language-Specific: Python, Go, Rust, Node.js, iOS Swift, Android App, Android System, etc.
  • Framework & Platform: React Frontend, Vue Frontend, Backend, Docker, etc.
  • Development Practices: Agents, Coding Style, Patterns, Performance, Security, Testing, Git Workflow, Hooks, etc.

Ideal for: Configuring project-level/language-level Rules for Claude Code or similar Agents — unifying style and security policies.

Use Cases

  1. Selection phase: Browse and compare by category when choosing IDEs, Agent frameworks, RAG/vector databases, MCP platforms, and Skill collections.
  2. Learning path: Start from Learning Resources and Prompt/LLM application examples, then jump to Agent, RAG, and MCP as needed.
  3. Configure Claude Code/Cursor: Find ready-made Skills and Rules templates in Agent Skills and ClaudeCode Rules — copy or adapt to local use.
  4. Standards and collaboration: Reference Spec-Kit, OpenSpec, and BMAD-METHOD in Development Tools for spec-driven and multi-agent collaboration workflows.
  5. Contribute and maintain: When discovering quality resources, submit PRs per the Contributing guide to keep the list updated.

Quick Usage

  • Browse: Open README or README_zh.md, navigate to sections via the top table of contents.
  • Search: Use Ctrl+F / Cmd+F on the page to search by keyword (e.g., “RAG”, “MCP”, “Claude”, “Skill”).
  • Reference Rules: Clone or download the repo, then configure the corresponding .md paths from rules/ to Claude Code or your Agent rules directory.
  • Contribute: Fork → new branch → add entry in the corresponding category (format: - **[Name](link)** - Brief description) → submit PR.

Core Features

  1. Comprehensive topic coverage: From editors to Rules, covers the complete AI coding toolchain and learning path.
  2. Consistent structure: Major category → subcategory → list items, each with “name + link + one-liner” — easy to scan.
  3. Bilingual: Main README in English, README_zh in Chinese, accessible to teams and communities.
  4. Includes ClaudeCode Rules: Repo rules can be directly used for project standards and Agent behavior constraints.
  5. Open contribution: Issues/PRs welcome, suitable for community co-maintenance and updates.
  6. Awesome-style: Follows awesome list conventions, easy to use alongside other Awesome lists.

Complementary to Other Resource Lists

Dimension Awesome AI Coding Single-topic Awesome (e.g., awesome-claude-skills) Vendor documentation/navigator
Coverage 12 categories: editors, terminal, Agent, RAG, MCP, Skills, Rules, etc. Usually focused on Skills or one framework Primarily their own products
Language Bilingual (Chinese + English) Project-dependent Vendor-dependent
Rules & standards Includes rules/ directory, directly usable Few ready-made Rules collections Mostly product usage instructions
Positioning Navigation for the complete “AI coding” pipeline Deep focus on one sub-domain Product and ecosystem promotion

Why it’s worth bookmarking:

  • Single entry covering selection, learning, configuration, and standards — reduces repetitive searching.
  • ClaudeCode Rules and Agent Skills categories are especially useful for developers using Claude Code / Cursor.
  • Continuous updates and contribution mechanism keeps up with new tools and projects.

Detailed Project Analysis

Document and Directory Structure

  • README.md: English main document with complete table of contents and 12 major category content.
  • README_zh.md: Chinese version, same structure as English, for Chinese readers.
  • rules/: Multiple Markdown rule files, organized by language (python, go, rust, nodejs, ios-swift, android-app, android-system), framework (react-frontend, vue-frontend, backend, docker), and practice (agents, coding-style, patterns, performance, security, testing, git-workflow, hooks) — can be directly loaded by Claude Code or similar Agents.

Content Organization Principles

  • Categorized by use case: Organized around “what you’re doing” (writing code, building Agents, doing RAG, configuring MCP, finding Skills, configuring Rules) — not by company or tech stack name.
  • Minimal per entry: Only name, link, and one-line description — no long text, easy to quickly scan.
  • Representative first: Each category lists representative or highly-adopted projects, balancing official and community options.

Contribution and Maintenance

  • Contribution workflow: Fork → feature branch → add entry per existing format in the appropriate category → submit PR.
  • README note: Quality resources welcomed via Issue or PR; list will be continuously updated.
  • Suitable for: Discovering uncatalogued quality projects, fixing links or descriptions, syncing Chinese README_zh updates.

Project Resources

Official Resources

Who Should Use This

  • AI coding beginners: Need a topically categorized navigator to quickly understand the editor, framework, RAG, MCP, and Skills ecosystem.
  • Teams in the selection phase: When comparing Agent frameworks, RAG, vector databases, MCP platforms, and spec-driven tools — use this list as a starting point.
  • Claude Code / Cursor users: Find ready-made Agent Skills and Rules templates, configure project standards and security policies.
  • List maintainers and contributors: Want to participate in maintaining or expanding an Awesome list focused on “AI coding.”

Welcome to visit my personal homepage for more useful knowledge and interesting products

Parameter Count Is the Worst Way to Pick a Model on 8GB VRAM

Parameter Count Is the Worst Way to Pick a Model on 8GB VRAM

I’ve been running local LLMs on an RTX 4060 8GB for six months. Qwen2.5-32B, Qwen3.5-9B/27B/35B-A3B, BGE-M3 — all crammed through Q4_K_M quantization. One thing I can say with certainty:

Parameter count is the worst metric for model selection.

Online comparisons rank models by size — “32B gives this quality,” “7B gives that.” Benchmarks like MMLU and HumanEval publish rankings by parameter count. But those assume abundant VRAM. On 8GB, parameter count fails to predict the actual experience.

This article covers three rules I derived from real measurements, plus a decision framework for 8GB VRAM model selection. All data comes from my previous benchmark articles.

Rule 1: Fitting in VRAM ≠ Running Fast

When you hit the 8GB wall, the first instinct is “VRAM usage is X GB, so it fits.” But VRAM usage and speed have no linear relationship.

The Qwen3.5 three-model comparison made this painfully clear:

Model VRAM Speed GPU Utilization
9B 7.1GB 33.0 t/s 91%
27B dense (ngl=24) 7.7GB 3.57 t/s 60%
35B-A3B MoE 7.6GB 8.61 t/s 95%

VRAM usage is nearly identical (7.1–7.7GB). Speed differs by 10x.

The culprit is GPU utilization. The 27B model only loads 24 of 58 layers onto the GPU. The remaining 34 layers run on CPU. The GPU finishes its portion and idles while waiting for CPU. 60% utilization means the GPU wastes 40% of its time.

What actually determines speed on 8GB VRAM:
  1. Can all layers fit on GPU? → Partial offload = massive speed drop
  2. Offload ratio → ngl/total_layers dominates throughput
  3. MoE active parameters → 35B with 3B active fits entirely on GPU

Rules from measurement:

  • ngl < 50% of total layers → unusable for interactive tasks
  • ngl = total layers within 8GB → fast
  • For MoE models, judge by active parameter count. 35B with 3B active fits 8GB easily

Rule 2: Thinking Model Context Length Doesn’t Mean What You Think

Qwen3.5 introduced thinking (consuming tokens for internal reasoning). This creates a new problem under context constraints.

Standard model:
  Prompt → Answer
  ctx consumed = prompt + answer

Thinking model:
  Prompt → Thinking (internal reasoning) → Answer
  ctx consumed = prompt + thinking + answer

Same ctx 8192, but thinking eats into available output tokens. And thinking length varies non-deterministically by task.

Qwen3.5-9B task-level thinking consumption:

Task Thinking lines ctx consumed Result
Code generation Short Plenty Completed
Math Short Plenty Completed
Knowledge summary 242 lines 8095/8192 Barely survived

The 27B and 35B-A3B models exhausted their context on the knowledge summary task and failed completely. Models with more knowledge generate longer thinking chains, consuming more context. The 9B survived precisely because its shallower knowledge cut thinking short.

Rules from measurement:

  • Thinking model × ctx 8192 = effective output budget is drastically task-dependent (97% ctx consumed in one real case)
  • Higher-knowledge models (27B+) face greater ctx exhaustion risk
  • Long-form generation requires either non-thinking models or ctx 32K+

Rule 3: Slow Model Failures Cost You the Square of Latency

When a model fails, the cost is inversely proportional to its speed.

Time to context exhaustion across Qwen3.5 models:

Model Speed Time to failure
9B ~33 t/s ~4 min
35B-A3B 7.63 t/s 20 min
27B dense 3.21 t/s 58 min

All three failed identically. But the 27B made you wait 58 minutes to discover that. The 9B lets you retry in 4 minutes.

Furthermore, as context fills up, attention computation becomes heavier and speed degrades:

  • 35B-A3B: 8.61 t/s at start → 7.63 t/s near exhaustion (−11%)
  • 27B: 3.57 t/s → 3.21 t/s (−10%)

Slow models get penalized twice on context exhaustion. You notice the failure later, and the model runs even slower right before failing.

Rules from measurement:

  • Tasks requiring iteration → prioritize fast models (faster failure recovery)
  • One-shot tasks requiring quality → quality-first is acceptable
  • Inference speed < 5 t/s is impractical for interactive use

Selection Framework: Decision Tree for 8GB VRAM

Combining all three rules:

Q1: Does the task require long output (1000+ tokens)?
├── YES → Q2: Does it need a thinking model?
│   ├── YES → Need ctx 32K+. On 8GB, consider non-thinking alternatives
│   └── NO  → Go to Q3
└── NO  → Go to Q3

Q3: Interactive use (response time matters)?
├── YES → Q4: Domain expertise needed?
│   ├── YES → MoE recommended (35B-A3B: 8.6 t/s + high quality)
│   └── NO  → 9B class recommended (33 t/s, low latency)
└── NO  → Batch processing allows 27B dense (quality > speed)

Q5: Running RAG/Embedding simultaneously?
├── YES → Calculate total VRAM: inference model + embedding
│         BGE-M3: ~1.5GB, inference: fits in remaining 6.5GB?
│         → 9B (7.1GB) can't co-exist. Need 5B or smaller, or MoE
└── NO  → Apply Q3-Q4 results

Recommendation Matrix

Use Case Recommended Model Reason
Code completion / chat 9B 33 t/s, low latency, 4min recovery
Specialized tasks (no RAG) 35B-A3B MoE 8.6 t/s, high quality, 95% GPU
RAG + inference together 5B or smaller, or API split VRAM sharing limit
Long-form translation/summary Non-thinking model Avoid ctx exhaustion
Batch processing (quality-first) 27B dense Speed doesn’t matter
Absolutely avoid 27B dense × interactive 3.5 t/s + ctx exhaustion = worst UX

Quantization: Is There a Reason to Choose Anything Other Than Q4_K_M?

All testing used Q4_K_M. Here’s a brief comparison with alternatives:

# llama.cpp quantization formats (positioned for 8GB VRAM)
quant_options = {
    "Q2_K":   {"bits": 2.6, "quality": "Low", "size_ratio": 0.33,
               "use_case": "Only when you absolutely must run a larger model"},
    "Q4_K_M": {"bits": 4.8, "quality": "Practical", "size_ratio": 0.55,
               "use_case": "Default choice. Best quality-speed balance"},
    "Q5_K_M": {"bits": 5.5, "quality": "High", "size_ratio": 0.63,
               "use_case": "When VRAM allows. 9B at Q5 ~7.5GB"},
    "Q6_K":   {"bits": 6.6, "quality": "Highest", "size_ratio": 0.75,
               "use_case": "Only 7B class on 8GB. For fixed quality tasks"},
    "Q8_0":   {"bits": 8.5, "quality": "FP16-equivalent", "size_ratio": 1.0,
               "use_case": "Only 3B or smaller on 8GB. Good for embedding models"}
}

When to change from Q4_K_M:

  • 9B → Q5_K_M: VRAM 7.1→~7.5GB. Fits. Quality improvement is marginal but free
  • 9B → Q6_K: VRAM ~8.0GB. Tight. Risk of VRAM contention with other processes
  • 35B-A3B → Q2_K: Large quality degradation. MoE has fewer active parameters, so quantization degradation hits harder per-parameter

Conclusion: Q4_K_M is the sweet spot for 8GB. Quality degradation is negligible, and VRAM usage at ~50% of capacity keeps larger models in play.

What Six Months on 8GB Taught Me

The 8GB constraint is simultaneously a limitation and a filter.

On an A100 80GB, everything runs. No selection pressure means architectural differences don’t surface as experience differences. 8GB forces you to find the exact optimal combination of model, task, and config.

Choosing by parameter count is like choosing a car by displacement alone. A 2.0L turbo four can beat a 3.5L NA V6. MoE 35B-A3B can beat dense 27B. Change the constraints, change the ranking.

The three rules again:

  1. Fitting in VRAM ≠ running fast — Judge by GPU utilization and ngl ratio
  2. Thinking model context is not face value — Budget ctx per task
  3. Slow model failure cost scales with the square of latency — Iterate fast with fast models

Spec sheets don’t lie, but they only tell half the truth. The other half only shows up when you run it on your own GPU.

Test Environment & Related Articles

GPU:    NVIDIA GeForce RTX 4060 Laptop GPU 8GB
CPU:    AMD Ryzen 7
RAM:    32GB DDR5
Engine: llama.cpp (GGUF)
OS:     Windows 11

What RAG Is: The Pattern That Grounds AI in Reality

Same Question, Different Answer — left panel (coral border): Question → Model (frozen knowledge) →

Part 2 of 8 — RAG Article Series

Previous: Why AI Gets Things Wrong (Part 1)

TechNova is a fictional company used as a running example throughout this series.

Same Question, Different Answer

Same customer. Same question. The WH-1000 headphones were bought last month, and they want to know about returns.

This time, the AI assistant does not answer from what it learned during training. Before generating a response, it retrieves TechNova’s current return policy — the document in the CMS, updated last quarter, version 4.1. The policy says fifteen days. The assistant reads it, and responds: fifteen days, and the window has closed.

The customer is disappointed, but they get the right answer. No escalation. No support agent cleaning up after the model. No confident wrong answer delivered with the authority of a system that cannot tell old facts from current ones.

The model did not get smarter. It did not retrain. It did not receive a fine-tuning update with the latest policy documents. The only thing that changed is where the answer came from.

What Just Changed

In Part 1, the model answered from its internal state — a compressed snapshot of everything it learned during training. That snapshot included a return policy that was accurate six months ago and wrong today. The model had no way to know the difference.

In the scenario above, the policy fact comes from retrieved context, not from what the model remembered. The system retrieved the current document from TechNova’s knowledge base, placed it in the model’s context, and asked it to generate. The model’s answer reflected what the document actually says — right now, not six months ago.

RAG changes the model’s source of truth at answer time. The model’s reasoning capability is unchanged. Instead of relying on frozen parameters, it relies on retrieved context — context that can be updated, versioned, and kept current without touching the model itself.

The full name is Retrieval-Augmented Generation. Retrieve first, then generate. The retrieval step is what makes the difference between the wrong answer in Part 1 and the right answer above.

Same Question, Different Answer — left panel (coral border): Question → Model (frozen knowledge) →

RAG Is a Pattern, Not a Product

RAG is not a tool you buy. It is a way of structuring the system.

This matters because it is easy to confuse the pattern with the tools used to build it. A vector database is one way to store knowledge the system can search. An embedding model is one way to help the system find documents by meaning, not just exact words. A prompt template is one way to format the retrieved text and question into a single prompt for the model. None of them are RAG. RAG is the system structure: retrieve relevant knowledge first, then generate from it.

Six Components in One Sentence Each

Every RAG system, regardless of implementation, has six components. They run in order, each feeding the next.

Query. The question or request that arrives from the user — in TechNova’s case, “What is the return policy for the WH-1000?”

Retriever. The component that takes the query and finds relevant content from the knowledge base.

Knowledge base. The external store of documents, records, or data that the retriever searches — TechNova’s policy documents, troubleshooting guides, and product specs.

Retrieved context. The specific content the retriever returns — the chunks of text that will be placed in front of the model.

Prompt assembly. The step that combines the retrieved context with the original query into a single input for the model.

Generation. The model reads the assembled prompt and produces an answer grounded in the retrieved context, not its training data.

Those six components run in sequence. The query enters, context is retrieved, the model generates. Everything in between is a design decision. Parts 3 and 4 examine those decisions and the ways they fail.

The RAG Pattern — six-component linear flow left to right: Query (blue) → Retriever (blue) → Knowledge Base (teal) → Retrieved Context (teal) → Prompt Assembly (purple) → Generation (purple). Each box has a one-line subtitle.

Knowledge vs Reasoning — The Line That Matters

People often get confused about what RAG actually improves. It does not make the model smarter. It does not improve its ability to reason, combine information, or draw conclusions. A model that struggles with multi-step logic will still struggle with multi-step logic after you add retrieval. RAG changes what the model knows at the moment it answers, not how well it thinks.

This distinction matters because it shows which problems RAG solves and which it does not. If TechNova’s AI assistant gives the wrong return policy because the model never saw the updated document, that is a knowledge problem. RAG fixes it. If the assistant sees the correct document but misinterprets a conditional clause — “fifteen days from date of delivery, not date of purchase” — that is a reasoning problem. RAG does not fix it. The retriever did its job. The model did not.

When something goes wrong in a RAG system, the first question is always: did the retriever return the right content? If yes, the problem is generation. If no, the problem is retrieval. Learning to separate retrieval problems from generation problems is the most useful thing you can take from this series.

RAG matters because it changes the model’s source of truth at answer time, not because it adds more boxes to the architecture.

Three Takeaways

1. RAG is a pattern: retrieve relevant context, then generate an answer grounded in that context.

No vendor, no framework, no specific stack defines RAG. The pattern is simple: retrieve first, then generate using external knowledge.

2. Retrieval quality sets the ceiling for the answer.

If the retriever returns the wrong content, the model will produce a well-reasoned wrong answer. The model still matters — but it cannot rescue bad retrieval.

3. RAG addresses knowledge currency. The model still handles reasoning.

RAG changes where knowledge comes from. It does not change how well the model reasons over that knowledge.

Part 3 breaks the pattern into two operational shifts — one that prepares knowledge before any question is asked, and one that answers the question at runtime — and shows where each shift fails.

Next: How RAG Works: The Complete Pipeline (Part 3 of 8)

BDD Test Cases from User Stories: 5 Steps and 12 Scenarios

User stories set the destination. Test cases map every path, including the wrong ones.

In this post we walk through a 5-step BDD decomposition framework for turning a single user story into concrete Given/When/Then scenarios, with a complete worked coupon example. BDD (Behavior-Driven Development) structures tests as Given/When/Then scenarios that both stakeholders and tools like Cucumber or SpecFlow can understand.

Most teams write user stories in a format like:

As a checkout user,
I want to apply a discount coupon,
So that I pay less for my order.

Then they try to extract test cases directly from that sentence. The result is a handful of happy path scenarios and a nagging sense that something important was missed.

That instinct is right. This post explains why, and what to do about it.

Why User Stories Fail as Test Case Sources

User stories describe intent, not behavior. They answer why a feature exists, not what the system should do in every situation.

The coupon story above doesn’t say:

  • What happens if the coupon is expired
  • What if the cart is below the minimum order value
  • Whether a coupon can be applied more than once
  • What if the coupon code is valid but belongs to a different user
  • What if the user removes an item after applying the coupon
  • What happens if the coupon service is temporarily unavailable

None of these are edge cases you invent. They’re real scenarios that happen in production. They’re just not in the user story because user stories aren’t meant to capture them.

The gap between “the story” and “what needs testing” is where bugs live.

The 5-Step BDD Decomposition Framework

Don’t try to extract test cases from the user story text directly. Use the story as a starting point for structured decomposition.

The framework in summary:

  1. Identify the main scenario (the happy path)
  2. Map every input and its valid boundaries
  3. Add negative scenarios for each invalid input
  4. Add boundary-condition scenarios at and around each threshold
  5. Add error-handling and state-transition scenarios

Each step below.

Step 1: Identify the Main Scenario

What does the system do in the ideal case? This is your happy path, the scenario where everything works as intended.

Scenario: Valid coupon applies correct discount
  Given I have a cart with items totaling $50
  And I have a valid coupon "SAVE20" for 20% off
  When I apply the coupon
  Then the cart total should be $40
  And I should see "20% off applied"

This is what your product owner has in mind when they write the story. Necessary, but not close to enough.

Step 2: Map Every Input and Its Boundaries

Every input the user provides or the system receives has a valid range. List them explicitly.

Input Valid Range Boundary Cases
Coupon code Alphanumeric, 4-20 chars Empty, too short, too long, special chars
Expiry date Today or future Yesterday, today, tomorrow
Minimum cart value Above minimum threshold (e.g., $30) $29.99, $30.00, $30.01
Usage limit 0 – N uses per user 0, 1, max, max+1
User ownership Owned by this user or global Own coupon, other user’s coupon, global

Each boundary is a potential test case. The edge of the valid range is where errors happen.

Step 3: Add Negative Scenarios

For each input, ask: what should the system do when this input is invalid, expired, or out of range? Each answer is a test case.

Scenario: Expired coupon is rejected with clear message
  Given I have a cart with items totaling $50
  And I have an expired coupon "OLD20"
  When I apply the coupon
  Then I should see the error "This coupon has expired"
  And the cart total should remain $50
  And no discount should be applied

Step 4: Add Boundary Conditions

Boundary conditions are the exact limits of valid input: the values right at, just below, and just above each threshold.

A coupon with a $30 minimum order value needs three scenarios:

  • Cart at $29.99 → coupon rejected
  • Cart at $30.00 → coupon accepted
  • Cart at $30.01 → coupon accepted
Scenario: Coupon rejected when cart is one cent below minimum
  Given I have a cart with items totaling $29.99
  And I have a valid coupon "SAVE20" with a $30 minimum
  When I apply the coupon
  Then I should see "Minimum order of $30 required"
  And the cart total should remain $29.99

Boundary conditions expose off-by-one errors, rounding bugs, and comparison operator mistakes (< vs <=). I’ve seen teams spend weeks debugging production issues that a single boundary test would have caught. The return on time invested is unusually high.

Step 5: Add Error Handling and State Scenarios

What happens if the coupon service is down? What if the user applies a coupon, then removes an item that drops the cart below the minimum?

State transitions (when valid inputs become invalid mid-session) are consistently under-tested. In most codebases I’ve worked on, they’re not tested at all.

Scenario: Coupon auto-removed when cart drops below minimum
  Given I have a cart with items totaling $50
  And I have successfully applied coupon "SAVE20" with a $30 minimum
  When I remove items bringing the cart total to $25
  Then the coupon should be automatically removed
  And I should see "Coupon removed: cart below $30 minimum"
  And the cart total should be $25 with no discount

The Three Coverage Levels

Not every story needs exhaustive coverage immediately. A pragmatic approach uses three levels, chosen based on the risk profile of the feature.

Coverage Level Scenarios Focus Use When
Quick 3 total Happy path + obvious failures Low-risk features, rapid prototyping, legacy system initial coverage
Standard 8 total Adds boundaries & realistic edge cases Most production features
Exhaustive 12 total Adds security, concurrency, state transitions Payment flows, authentication, data integrity, anything hard to roll back

Choosing the right level is a judgment call about risk, not a technical decision. Features that touch money, health data, or user permissions need Exhaustive. A blog post draft autosave feature probably needs Quick.

Worked Example: Coupon Application

User story: As a checkout user, I want to apply a discount coupon, so that I pay less for my order.

Quick Coverage (3 scenarios)

# Scenario Tests
1 Valid coupon applied Correct discount shown, cart total updated
2 Invalid coupon code Clear error message, cart unchanged
3 Expired coupon Expiry-specific error message
Scenario: Valid coupon applies correct discount
  Given I have a cart with items totaling $50
  And I have a valid coupon "SAVE20" for 20% off
  When I apply the coupon
  Then the cart total should be $40
  And I should see "20% off applied"

Scenario: Invalid coupon code is rejected
  Given I have a cart with items totaling $50
  When I apply coupon "NOTREAL"
  Then I should see "Coupon not found"
  And the cart total should remain $50

Scenario: Expired coupon is rejected
  Given I have a cart with items totaling $50
  And I have an expired coupon "OLD20"
  When I apply the coupon
  Then I should see "This coupon has expired"
  And the cart total should remain $50

Standard Coverage Adds (5 more scenarios, 8 total)

# Scenario Tests
4 Cart below minimum order value Minimum order error with threshold displayed
5 Single-use coupon applied twice “Coupon already used” error
6 Coupon applied, then item removed below minimum Coupon auto-removed, user notified
7 Cart at exactly minimum value Coupon applies successfully
8 Cart $0.01 below minimum Coupon not applicable
Scenario: Coupon rejected when cart is one cent below minimum
  Given I have a cart with items totaling $29.99
  And I have a valid coupon "SAVE20" with a $30 minimum order
  When I apply the coupon
  Then I should see "Minimum order of $30 required"
  And the cart total should remain $29.99

Scenarios 7-8 are the boundary pair for the minimum threshold. Testing both sides of the boundary catches < vs <= bugs that unit tests often miss.

Exhaustive Coverage Adds (4 more scenarios, 12 total)

# Scenario Tests
9 Coupon belonging to another user “Coupon not found” (not “belongs to someone else”)
10 Two simultaneous coupon applications Only one applied, no double discount
11 Coupon code with SQL injection attempt Sanitized and treated as invalid
12 Coupon applied, page refreshed State persisted correctly

These deserve additional commentary.

Scenario 9: User Enumeration Prevention

At first glance, you might write the expected behavior as: “When I apply a coupon that belongs to another user, I see ‘This coupon belongs to a different account.'”

That sounds helpful, but it leaks information. It confirms the coupon exists and is assigned to someone. An attacker can use this to enumerate valid coupon codes or confirm which users have coupons.

The correct behavior returns a generic “Coupon not found” message, identical to what you’d see for a coupon that doesn’t exist at all.

Scenario: Coupon belonging to another user returns generic not-found
  Given I have a cart with items totaling $50
  And a coupon "PRIVATE10" exists but belongs to another user
  When I apply coupon "PRIVATE10"
  Then I should see "Coupon not found"
  And the cart total should remain $50

Scenario 10: Race Condition / Double Discount

If a user opens two tabs and clicks “Apply Coupon” simultaneously, what happens? Without explicit concurrency handling, you can end up with double discounts or corrupted cart state. I’ve seen promotions lose thousands of dollars to this exact bug during flash sales.

Scenario 11: Input Sanitization

The coupon code field accepts user input. That input will hit your database. Malicious input should be sanitized and rejected as “invalid code,” not cause errors or, worse, execute.

Scenario 12: State Persistence

If a user applies a coupon then refreshes the page, is the coupon still applied? This tests session or database persistence. It sounds obvious, but I’ve seen carts silently drop discounts on refresh because the coupon was stored client-side only.

Common Mistakes

Four mistakes I see repeatedly in BDD scenarios.

Mistake 1: Testing the Implementation, Not the Behavior

BDD scenarios should describe what the system does from a user’s perspective, not how it does it internally.

Bad:

Scenario: Click apply button sends API request
  Given I am on the cart page
  When I click the "Apply Coupon" button
  Then a POST request is sent to /api/v1/coupons/apply

Good:

Scenario: Valid coupon applies correct discount
  Given I have a cart with items totaling $50
  When I apply coupon "SAVE20"
  Then my cart total should be $40

The bad version tests implementation details. The good version tests behavior. Only the second survives a refactor.

Mistake 2: Skipping Boundary Conditions

Teams often test “valid” and “invalid” but miss the exact threshold. If the minimum order is $30, test $29.99, $30.00, and $30.01 — not just “$20” and “$50.”

Mistake 3: Coupling to UI Elements

Scenarios that say “When the user clicks the Apply Coupon button” couple your test cases to your UI. Describe actions at the domain level: “When the user applies coupon SAVE20.”

Mistake 4: One Huge Scenario Instead of Multiple Focused Ones

A scenario with twelve steps and three outcomes is testing three things at once. When it fails, you don’t know which of the three things broke. One behavior per scenario.

Where AI Fits: Honestly

AI test case generation is useful but uneven. Worth being specific about where it helps and where it doesn’t.

AI handles well:

  • Volume. Given a well-structured user story, AI can generate a complete scenario set in seconds rather than the hour it might take manually.
  • Consistency. AI doesn’t forget null inputs or boundary values — the inputs you’d normally catch on the thirtieth scenario of the day when you’re no longer paying attention.
  • Format compliance. Gherkin syntax is strict, and AI follows it reliably.
  • Coverage breadth. AI applies the decomposition systematically across every input. It won’t skip Step 4 because it’s Friday afternoon.

AI handles poorly:

  • Domain-specific rules. Your business has constraints that aren’t in the user story: user enumeration risks, regional compliance requirements, product-specific logic. AI doesn’t know these unless you tell it explicitly.
  • Organizational context. Which test cases already exist? Which are covered by integration tests at a lower level? AI doesn’t have this information and will generate duplication.
  • Coverage level judgment. Deciding whether a feature needs Quick, Standard, or Exhaustive coverage is a risk assessment about your system, your users, and your rollback capability. That’s a human call.

What actually works: let AI handle Steps 2-5 at the coverage level you choose, then review and add the domain constraints it can’t know. You get AI’s consistency with your context.

Summary

The gap between user stories and test cases is where bugs live. A structured decomposition approach closes that gap:

  1. Identify the main scenario — the happy path
  2. Map every input and its boundaries — the raw material for edge cases
  3. Add negative scenarios — what happens when inputs are invalid
  4. Add boundary conditions — the exact thresholds where errors hide
  5. Add error handling and state transitions — the scenarios that survive production

Choose your coverage level based on risk: Quick for low-stakes features, Standard for most production work, Exhaustive for anything involving money, security, or data integrity.

This is part of the Practical Test Design series. I’m building KRINO Dokim, a tool that applies this 5-step framework automatically — you choose the coverage level, it generates the scenarios, and you review with full visibility into why each scenario was created. If you work with user stories and BDD, I’d genuinely appreciate your feedback on the approach.

What coverage level does your team default to? Have you run into the user enumeration trap (Scenario 9)? I’d love to hear in the comments.

Claude Code CLAUDE.md vs settings.json: which one controls what (and why it matters)

Claude Code CLAUDE.md vs settings.json: which one controls what (and why it matters)

If you’ve been using Claude Code for more than a week, you’ve probably edited both CLAUDE.md and .claude/settings.json — and at some point wondered: which file should this go in?

They look similar. They both configure Claude’s behavior. But they control completely different things, and mixing them up leads to frustrating results.

Here’s the complete breakdown.

The mental model

CLAUDE.md = Claude’s brain

settings.json = Claude’s permissions

CLAUDE.md is natural language. You write instructions, context, constraints, and preferences. Claude reads it like a colleague reads a briefing doc.

settings.json is machine config. It controls what tools Claude is allowed to use, what commands it can run, what it’s blocked from doing.

What CLAUDE.md controls

# Project context
This is a Next.js 14 app using Prisma + PostgreSQL.

# Architecture decisions
- All API routes live in /app/api/
- Database models are in /prisma/schema.prisma
- Never create new /pages/ routes — we're on App Router

# Code style
- TypeScript strict mode always on
- Prefer async/await over .then() chains
- Use Zod for all input validation

# Response format
- Give me code first, explanation after
- Skip obvious comments — I can read the code
- When suggesting a fix, show the before AND after

Things that belong in CLAUDE.md:

  • Tech stack and architecture
  • Coding conventions and style preferences
  • Business domain context (what the app does, who uses it)
  • Response format preferences
  • Things to always/never do
  • Commands to run for common tasks

What settings.json controls

{
  "permissions": {
    "allow": [
      "Bash(npm run *)",
      "Bash(git add:*)",
      "Bash(git commit:*)",
      "Bash(cat:*)",
      "Bash(grep:*)",
      "Bash(find:*)"
    ],
    "deny": [
      "Bash(rm -rf *)",
      "Bash(git push:*)",
      "Bash(curl:*)",
      "WebFetch"
    ]
  }
}

Things that belong in settings.json:

  • Which bash commands Claude can run without asking
  • Which tools are blocked entirely
  • Auto-approve settings for trusted operations
  • Model preferences (if you’re on Pro)

The key difference: CLAUDE.md is read, settings.json is enforced

Claude can choose to ignore something in CLAUDE.md if it thinks it knows better. (It shouldn’t, but it can.) Settings.json is a hard fence — Claude literally cannot execute a command that’s in the deny list.

This is why:

  • Style preferences go in CLAUDE.md — you want Claude to understand and apply them, not be mechanically blocked
  • Safety constraints go in settings.json — you want actual enforcement, not suggestions

Real-world example: preventing accidental deploys

Wrong approach — putting it in CLAUDE.md:

# IMPORTANT
Never run `git push` or deployment commands without asking me first.

Claude will try to follow this. But if it’s confident a push is needed, it might do it anyway.

Right approach — settings.json:

{
  "permissions": {
    "deny": [
      "Bash(git push:*)",
      "Bash(npm run deploy:*)",
      "Bash(vercel:*)"
    ]
  }
}

Now it’s impossible, not just discouraged.

Real-world example: project conventions

Wrong approach — trying to encode this in settings.json: You can’t. Settings.json doesn’t support natural language rules.

Right approach — CLAUDE.md:

# Database conventions
- All new tables need a `created_at` and `updated_at` column
- Foreign key names: {table}_{column}_fkey
- Always use UUIDs for primary keys, never auto-increment integers
- Migrations live in /prisma/migrations/ �� never edit them by hand

Claude reads this, understands it, and applies it when writing schema changes.

The inheritance question

Both files support inheritance — but differently.

CLAUDE.md inheritance (directory-based):

~/.claude/CLAUDE.md          # global rules for all projects
/project/CLAUDE.md           # project rules
/project/src/api/CLAUDE.md   # subdirectory rules

All three are read and merged, with deeper files taking precedence.

settings.json inheritance (also directory-based):

~/.claude/settings.json      # global permissions
/project/.claude/settings.json  # project permissions

Permissions merge — if global denies git push but project allows it, the project setting wins.

My combined setup

Here’s what my two files look like on a typical project:

CLAUDE.md:

# Stack
Node.js 20, Express 5, PostgreSQL 16, Redis

# Rules
- Tests live in /test/ mirroring /src/ structure
- All routes must have input validation (Zod)
- Log with winston, never console.log in production code
- Environment variables always via process.env, never hardcoded

# Workflow  
- After any schema change, remind me to run migrations
- When creating a new API endpoint, scaffold test file too
- Prefer small focused functions over large ones

# Response style
- Code first, then brief explanation
- If you see a related issue while fixing something, mention it but don't fix it unless I ask

.claude/settings.json:

{
  "permissions": {
    "allow": [
      "Bash(npm run test:*)",
      "Bash(npm run lint:*)",
      "Bash(npm install:*)",
      "Bash(git status:)",
      "Bash(git diff:*)",
      "Bash(cat:*)",
      "Bash(ls:*)",
      "Bash(grep:*)"
    ],
    "deny": [
      "Bash(git push:*)",
      "Bash(rm -rf:*)",
      "Bash(DROP TABLE:*)"
    ]
  }
}

Quick reference

What you want File
Coding style rules CLAUDE.md
Architecture context CLAUDE.md
Domain knowledge CLAUDE.md
Response format preferences CLAUDE.md
Block dangerous commands settings.json
Auto-approve safe commands settings.json
Prevent git push settings.json
Project tech stack info CLAUDE.md
Tool restrictions settings.json

One more thing: the API alternative

If you’re using Claude Code heavily, you’ve probably noticed the rate limits. One thing that helps: routing Claude Code through a direct API endpoint instead of Anthropic’s consumer tier.

The ANTHROPIC_BASE_URL environment variable lets you point Claude Code at any compatible endpoint:

export ANTHROPIC_BASE_URL=https://simplylouie.com/api

SimplyLouie runs a flat-rate Claude API proxy at $2/month — same claude-3-5-sonnet-20241022 model, no per-token billing, no rate limit anxiety. If you’re doing serious Claude Code work, the math tends to favor flat-rate.

The CLAUDE.md vs settings.json confusion trips up a lot of Claude Code users. Once you have the mental model — brain vs fence — the right file for each thing becomes obvious.

What’s in your CLAUDE.md that probably shouldn’t be? Drop it in the comments.

Del aprendizaje a la práctica: Por qué decidí dejar de estudiar en privado y empezar a compartir 🚀

¡Hola a todos! 👋

Llevo mucho tiempo sumergido en cursos, laboratorios y documentación. Durante meses (o incluso años), mi enfoque ha sido absorber todo lo posible sobre Cloud Engineering, Data Analysis entre otros temas. Sin embargo, hoy he tomado una decisión importante: dejar de guardar mis proyectos en carpetas locales y empezar a compartirlos con la comunidad.

He decidido que la mejor forma de crecer no es solo estudiando, sino exponiendo mi trabajo al criterio de otros profesionales para recibir feedback, mejorar y, con suerte, ayudar a alguien que esté en un camino similar.

🛠️ Mi primer aporte: Procesamiento de Datos
Hoy les presento un repositorio en el que he estado trabajando. Es una herramienta diseñada para estandarizar y agilizar el procesamiento de datos en Python, algo fundamental cuando buscas eficiencia en entornos Cloud.

🌟 ¿Por qué decidí publicarlo hoy?
Validación: Quiero saber si las soluciones que diseño siguen las mejores prácticas de la industria.

Comunidad: Creo firmemente que el ecosistema developer crece cuando compartimos lo que aprendemos.

Transparencia: Este es el inicio de mi portafolio público, mostrando mi evolución real en tecnologías como AWS y GCP.

💻 Explora el repositorio
Te invito a revisar el código, clonarlo o incluso criticarlo (constructivamente, ¡claro!). Cualquier sugerencia sobre cómo optimizarlo será más que bienvenida.

👉 URL del Proyecto: https://github.com/luiszuniga1990/data-processing.git

Plausible Code Is the New Technical Debt

I have a take that is going to annoy two groups of people at the same time:

  • The “real engineers don’t use AI” crowd
  • The “AI wrote my whole app” crowd

Here it is:

If AI is in your workflow, your codebase is now a human factors problem.

Not a model problem.

Not a prompt problem.

A human problem.

Because the hardest part is no longer generating code.

The hardest part is knowing what to trust, what to delete, what to keep, and what you are willing to be responsible for at 2:00 AM when prod is on fire and the person who “helped” is a chat bubble with no pager.

The new sin is not bad code. It’s unowned code.

AI makes it easy to produce code that looks plausible.

That’s the trap.

Plausible is not correct. Plausible is not maintainable. Plausible is not secure. Plausible is not even consistent with your repo.

Plausible just means your brain gets a quick dopamine hit and says: “ship it.”

So here’s the controversial thing I think we should start saying out loud:

If you did not read it, you did not write it.

If you did not write it, you do not own it.

If you do not own it, it does not belong in main.

That’s not anti-AI. That’s pro-software.

“But I can read it later”

No you won’t.

You will merge it while it’s fresh. Then a week later you will forget you even asked for it. Then three months later it will fail in a weird edge case and you will be in a code archaeology session, scrolling through a file full of polite variable names and zero intent.

AI code has a smell.

Not because it is always bad.

Because it often has no story.

Human-written code usually has fingerprints:

  • slightly annoying but consistent naming
  • weird shortcuts taken for a specific reason
  • comments that reflect real pain
  • a mental model that shows up across files

AI code often looks clean but detached, like it was written by someone who will never have to maintain it.

Which is true.

The real cost is not bugs. It’s ambiguity.

Bugs are normal. We have tests. We have monitoring. We have rollbacks.

Ambiguity is poison.

Ambiguity is when you can’t tell:

  • what the function is supposed to guarantee
  • what failure looks like
  • what the invariants are
  • why a decision was made
  • what tradeoff was chosen

AI generates code faster than it generates intent.

So if you are using AI and you are not also increasing clarity, you are building a repo that will eventually punish you.

The “AI pair programmer” fantasy is incomplete

Most devs use AI like a hyperactive junior.

“Write me a thing.”

It writes a thing.

You merge the thing.

That is not pairing.

Pairing is: reasoning out loud, constraints, tradeoffs, and a shared model of the system.

So the only way AI becomes a legitimate pair is if you force it to act like one.

Which means you need to change what you ask for.

Instead of: “write the code”

Ask:

  • “Before you write anything, tell me what you think I’m trying to do.”
  • “List assumptions you are making about the system.”
  • “Propose 2 approaches and argue for one.”
  • “Tell me how this fails.”
  • “Write tests first.”
  • “Show me the minimal diff that gets us there.”

If the tool cannot explain itself, it is not helping. It is performing.

A rule that saved me from shipping garbage

I started doing something that feels almost too simple:

Every AI-generated change must come with a receipt.

Not a comment block of fluff.

A receipt like:

  • What problem is this solving, in one sentence?
  • What are the inputs and outputs, explicitly?
  • What are the invariants?
  • What are the failure modes?
  • What tests prove it?
  • What did we choose not to do, and why?

If I cannot answer those, I do not merge.

Because I know what happens otherwise.

I get fast today and slow forever.

“This is just good engineering, nothing new”

Exactly.

That’s the point.

AI did not change what good engineering is.

It changed how easy it is to accidentally do bad engineering.

It lowered the effort required to create complexity.

So we need friction in the right places.

Not bureaucracy.

Friction that forces ownership.

Practical patterns (non-hype, actually usable)

Here are a few patterns that make AI helpful without letting it rot your repo:

Use it for diffs, not features

Ask for the smallest change that moves you forward, then iterate.

Make it write tests and edge cases

Not because it’s perfect, but because it will often suggest failure modes you forgot to consider.

Make it explain the code to you like you are tired

If it can’t do that, it’s too complex or too hand-wavy to merge.

Keep a “kill switch” mindset

Prefer designs you can remove in one commit if it turns out to be wrong.

Treat generated code as untrusted input

Same posture as copy-pasting from Stack Overflow, but faster and more frequent.

The part people avoid: responsibility

This is the emotional part for me.

A lot of us got into software because it felt like a clean meritocracy: you ship, it works, you win.

AI blurs the line between “I built this” and “I assembled this.”

That can mess with your identity.

So some devs swing into denial: “I don’t use it, I’m pure.”

Other devs swing into cosplay: “AI built everything, I’m 10x.”

Both are insecurity.

The mature posture is boring:

Use it. Verify it. Own it.

Your future self will thank you.

A question I want to ask the Dev.to crowd

What is your “AI code ownership” rule right now?

Do you have a hard line like “no generated code without tests” or “no generated code without a design note”?

Or are you just vibing and hoping future you figures it out?

The Hallucination Problem of AI Programming Assistants: How to Implement Specification-Driven Development with OpenSpec

The Hallucination Problem of AI Programming Assistants: How to Implement Specification-Driven Development with OpenSpec

AI programming assistants are powerful, but they often generate code that doesn’t meet actual requirements or violates project specifications. This article shares how the HagiCode project implements “specification-driven development” through the OpenSpec process, significantly reducing AI hallucination risks with a structured proposal mechanism.

Background

Anyone who has used GitHub Copilot or ChatGPT to write code has likely experienced this: the AI-generated code looks beautiful, but it’s full of problems when actually used. It might use a component from the project incorrectly, ignore the team’s coding standards, or write large chunks of logic based on non-existent assumptions.

This is the so-called “AI hallucination” problem—in the programming domain, it manifests as generating code that appears reasonable but doesn’t align with the actual situation of the project.

Actually, this situation is quite frustrating. As AI programming assistants become more widespread, this problem becomes increasingly serious. After all, AI lacks understanding of project history, architectural decisions, and coding standards, while excessive freedom easily leads it to “creatively” generate code that doesn’t match reality. This is quite similar to writing articles—without proper structure, it’s easy to write something unfocused, when that’s not actually the case.

To address these pain points, we made a bold decision: instead of trying to make AI smarter, we put it in a “specification” cage. The changes brought by this decision may be greater than you imagine—I’ll elaborate shortly.

About HagiCode

The solution shared in this article comes from our practical experience in the HagiCode project. HagiCode is an open-source AI code assistant project dedicated to solving real-world problems in AI programming through structured engineering practices.

The Root Causes of AI Hallucination

Before diving into the solution, let’s first look at where the problem actually lies. After all, know yourself and know your enemy, and you can fight a hundred battles with no danger of defeat—though applying this saying to AI is also somewhat interesting.

Missing Context

AI models are trained on public codebases, but your project has its own history, conventions, and architectural decisions. This “tacit knowledge” cannot be directly accessed by AI, so the generated code often disconnects from the actual project situation.

This can’t be entirely blamed on AI—after all, it hasn’t worked on your project, so how would it know your unwritten rules? It’s like a new intern who doesn’t understand the rules—that’s normal, but the cost might be somewhat high.

Excessive Freedom

When you ask AI to “help me implement a user authentication feature,” it might generate code in any form. Without clear constraints, AI will implement according to what it “thinks” is reasonable, rather than according to your project’s requirements.

This is like letting someone who has never learned your project specifications freely express themselves—can problems be avoided? Actually, it’s not that it’s irresponsible, it just doesn’t know what responsibility is.

Lack of Verification

After AI generates code, if there’s no structured review process, code based on wrong assumptions will directly enter the codebase. By the time problems are discovered in testing or even production environments, the cost is too high.

This is no different from locking the barn after the horse is stolen—except the horse has already run away, so what’s the use of locking the barn? Everyone understands this principle, but actually doing it always feels troublesome. After all, before things go bad, who wants to spend extra time?

OpenSpec: The Answer to Specification-Driven Development

HagiCode chose OpenSpec as the solution, with the core idea being: all code changes must go through a structured proposal process, transforming abstract ideas into executable implementation plans.

This sounds quite grand, but it essentially means having AI write the requirements document before writing the code. After all, preparedness ensures success, unpreparedness spells failure—the ancients didn’t deceive us.

What is OpenSpec

OpenSpec is an npm-based command-line tool (@fission-ai/openspec) that defines a standard proposal file structure and validation mechanism. Simply put, it requires AI to “write the requirements document first” before writing code.

Three-Step Process to Prevent Hallucination

OpenSpec ensures proposal quality through a three-step process:

Step 1: Initialize proposal – Set session state to Openspecing
Step 2: Intermediate processing – Maintain Openspecing state, gradually refine artifacts
Step 3: Complete proposal – Transition to Reviewing state

This design has a clever detail: the first step uses the ProposalGenerationStart type, and completion doesn’t trigger a state transition. This ensures the entire multi-step process won’t prematurely enter the review phase before completion.

Actually, this detail is quite interesting—it’s like cooking. If you lift the lid before the cooking time is reached, you definitely won’t produce a good dish. Only by being patient, taking it step by step, can you finally create a good dish.

// Implementation in the HagiCode project
public enum MessageAssociationType
{
    ProposalGeneration = 2,
    ProposalExecution = 3,

    /// <summary>
    /// Marks the start of the three-step proposal generation process
    /// Does not transition to Reviewing state upon completion
    /// </summary>
    ProposalGenerationStart = 5
}

Standardized File Structure

Every OpenSpec proposal follows the same directory structure:

openspec/
├── changes/                    # Active and archived changes
│   ├── {change-name}/
│   │   ├── proposal.md        # Proposal description
│   │   ├── design.md          # Design document
│   │   ├── specs/             # Technical specifications
│   │   └── tasks.md           # Executable task list
│   └── archive/               # Archived changes
└── specs/                     # Independent specification library

According to statistics from the HagiCode project, there are currently 4000+ archived changes and 150,000+ lines of specification files. This historical accumulation not only gives AI rules to follow but also provides a valuable knowledge base for the team.

This is like the classics left by ancients—read more and you’ll naturally gain some insight. It’s just that these classics aren’t written on bamboo slips, but stored in files.

Multi-Layer Validation Mechanism

The system implements multi-layer validation to ensure proposal quality:

// Validate required files exist
ValidateProposalFiles()

// Validate execution prerequisites
ValidateExecuteAsync()

// Validate startup conditions
ValidateStartAsync()

// Validate archive conditions
ValidateArchiveAsync()

// Proposal name format validation (kebab-case)
ValidateNameFormat()

These validations are like gatekeepers with layers of checks—only truly qualified proposals can pass. Although it seems cumbersome, it’s better than letting terrible code enter the codebase, right?

Prompt Template Constraints

AI execution in HagiCode uses predefined Handlebars templates that include clear step-by-step guidance and safeguards. For example:

  • Prohibit continuing without understanding user intent
  • Prohibit generating unverified code
  • Require re-providing when names are invalid
  • If a change already exists, recommend using the continue command rather than recreating

This approach of “dancing with shackles” actually makes AI more focused on understanding requirements and generating code that complies with specifications. Actually, constraints aren’t necessarily a bad thing—after all, excessive freedom easily leads to chaos.

Practice: How to Use OpenSpec in Projects

Installation and Initialization

npm install -g @fission-ai/openspec@1
openspec --version  # Verify installation

The openspec/ folder structure will be automatically created in the project root directory.

This step doesn’t need much explanation—installing tools, everyone understands. Just remember to use the @fission-ai/openspec@1 version, as new versions might have pitfalls—after all, stability comes first.

Creating Proposals

In HagiCode’s conversation interface, use the shortcut command:

/opsx:new

Or specify the change name and target repository:

/opsx:new "add-user-auth" --repos "repos/web"

Creating proposals is like outlining an article—once you have an outline, the rest is easier to write. It’s just that many people like to start writing directly, only to realize halfway through that their thinking doesn’t flow—that’s truly a headache.

Generating Artifacts

Use /opsx:continue to gradually generate the required artifacts:

proposal.md – Describes the purpose and scope of the change

# Proposal: Add User Authentication

## Why
The current system lacks user authentication functionality and cannot protect sensitive APIs.

## What Changes
- Add JWT authentication middleware
- Implement login/registration API
- Update frontend integration

design.md – Detailed technical design

# Design: Add User Authentication

## Context
Currently using public APIs accessible to anyone...

## Decisions
1. Choose JWT over Session...
2. Use HS256 algorithm...

## Risks
- Token leakage risk...
- Mitigation measures...

specs/ – Technical specifications and test scenarios

# user-auth Specification

## Requirements

### Requirement: JWT Token Generation
The system SHALL use the HS256 algorithm to generate JWT tokens.

#### Scenario: Valid login
- WHEN user provides valid credentials
- THEN the system SHALL return a valid JWT token

tasks.md – Executable task list

# Tasks: Add User Authentication

## 1. Backend Changes
- [ ] 1.1 Create AuthController
- [ ] 1.2 Implement JWT middleware
- [ ] 1.3 Add unit tests

These artifacts are actually like drafts for writing an article—once the draft is written, the main text naturally flows smoothly. It’s just that many people don’t like writing drafts, thinking it wastes time, but actually drafts are where you can best clarify your thinking.

Review and Application

After completing all artifacts:

/opsx:apply

AI will read all context files and execute tasks step by step according to the checklist in tasks.md. At this point, because there are clear specifications, the quality of generated code will be much higher.

Actually, by this step, things are already halfway done. With a clear task list, the rest is just methodical execution. It’s just that many people skip the previous steps and come directly here, so quality naturally can’t be guaranteed.

Archiving

After the change is complete:

/opsx:archive

Move completed changes to the archive/ directory for future reference and reuse.

Archiving is quite important—like properly storing a finished article. When you encounter similar problems in the future, flipping through previous records might give you answers. It’s just that many people are too lazy to do it, thinking it’s troublesome, but actually these accumulations are the most precious wealth.

Notes and Best Practices

Proposal Naming Convention

Use kebab-case format, starting with a letter, containing only lowercase letters, numbers, and hyphens:

  • ✅ add-user-auth
  • ❌ AddUserAuth
  • ❌ add--user-auth

Naming conventions aren’t a big deal, but being unified is generally good. After all, in code, consistency is important—it’s just that many people don’t pay attention to it.

Avoiding Common Errors

  1. Using the wrong type in step 1 of the three-step process – Will transition state prematurely
  2. Forgetting to trigger state transition in the final step – Will get stuck in Openspecing state
  3. Skipping review to execute directly – Should first verify all artifacts are complete

These errors are easily made by beginners—experienced people naturally know how to avoid them. It’s just that beginners will eventually become experienced, and taking some detours is fine, I just hope they don’t take too many.

Managing Multiple Changes

OpenSpec supports managing multiple proposals simultaneously, which is particularly useful when handling large features:

# View all active changes
openspec list

# Switch to a specific change
openspec apply "add-user-auth"

# View change status
openspec status --change "add-user-auth"

Managing multiple changes is like writing several articles simultaneously—it requires some skill and patience. But you’ll get used to it—after all, people can always adapt.

Understanding the Session State Machine

Understanding state transitions helps troubleshoot problems:

Init → Drafting → Openspecing → Reviewing → Executing → ExecutionCompleted → Completed → Archived
  • Openspecing: Planning in progress
  • Reviewing: Under review (can repeatedly modify artifacts)
  • Executing: Executing (applying tasks.md)

State machines are essentially a set of rules. Rules can be annoying sometimes, but more often they’re useful. After all, nothing can be accomplished without norms—as the ancients said long ago.

Summary

Through the OpenSpec process, the HagiCode project has achieved significant results in addressing AI hallucination:

  1. Reduce hallucinations – AI must follow structured specifications and cannot generate code arbitrarily
  2. Improve quality – Multi-layer validation ensures changes meet project standards
  3. Accelerate collaboration – Archived changes provide reference for future development
  4. Traceability – Each change has complete proposal, design, specification, and task records

This solution doesn’t make AI smarter, but puts it in a “specification” cage. Practice has shown that dancing with shackles actually produces better dance.

Actually, this principle is simple—constraints aren’t necessarily a bad thing. It’s like writing articles—with format constraints, it’s actually easier to write good things. It’s just that many people don’t like constraints, thinking they limit their creativity, but actually creativity also needs soil to bloom and bear fruit.

If you’re also using AI programming assistants and have encountered similar problems, why not try OpenSpec? Specification-driven development may seem to add some steps, but this upfront investment will pay back many times over in code quality and maintenance efficiency.

After all, sometimes being slower is actually being faster. It’s just that many people don’t understand this principle…

References

If this article helps you, feel free to give a Star on GitHub. HagiCode public beta has begun—install now to participate in the experience.

This article is pretty much done. There’s nothing particularly profound, just a summary of some practical experience. Hope it’s useful to everyone—after all, with sharing, you learn and let others learn too—it’s a win-win, so why not?

But articles are just articles—what’s truly useful is practice. After all, what you get from paper is shallow—you must personally practice to truly understand, as the ancients said…

Original Article & License

Thanks for reading. If this article helped, consider liking, bookmarking, or sharing it.
This article was created with AI assistance and reviewed by the author before publication.

Build Your Own AI-Powered Wearable with Claude and ESP32

Build Your Own AI-Powered Wearable with Claude and ESP32

Imagine glancing at your wrist and having an AI assistant ready to translate foreign languages, analyze your health data, or answer complex questions—all without pulling out your phone. This isn’t a far‑off sci‑fi fantasy; it’s a project you can build for under $15 using off‑the‑shelf components and the power of Claude, Anthropic’s state‑of‑the‑art language model.

In this article, I’ll walk you through why putting Claude on a wearable makes sense, what hardware you need, and how the software pipeline works. Whether you’re a curious hobbyist or a developer looking to explore edge AI, you’ll finish with a clear roadmap to create your own AI-powered wrist device.

Why Claude on Your Wrist?

Most smartwatches lock you into a vendor’s ecosystem. You get Siri or Google Assistant, but you can’t tweak their behavior, plug in custom sensors, or see how the AI works under the hood. By contrast, a DIY Claude wearable gives you three key advantages:

  1. Full Control Over AI Behavior

    You can craft custom system prompts that shape Claude’s responses—make it speak in a certain tone, limit reply length, or focus on specific domains like language translation or fitness coaching. No more settling for a one‑size‑fits‑all assistant.

  2. Open Sensor Integration

    The ESP32 microcontroller can interface with dozens of sensors: heart‑rate monitors, environmental sensors, GPS modules, even soil moisture probes for your plants. Feed that data straight to Claude for contextual insights.

  3. Learning by Building

    Assembling this wearable teaches you about APIs, wireless communication, sensor interfacing, and embedded programming—skills that are increasingly valuable in an AI‑driven world.

The Hardware: Minimalist and Affordable

You don’t need a lab of equipment. The core build consists of five inexpensive parts:

Component Approx. Cost Role
ESP32‑S3 Dev Board $4 The brain; handles Wi‑Fi, Bluetooth, and processing
0.96‑inch OLED Screen $2 Displays Claude’s responses
I2S Microphone $2 Captures voice input for hands‑free queries
Lithium Battery + Charger $3 Enables portable, untethered use
Jumper Wires $1 Connects everything on a breadboard

Total cost hovers around $10‑15, and no soldering is required—everything plugs into a breadboard with jumper wires.

How the Software Pipeline Works

The magic happens in a simple loop:

  1. Input Capture

    Press a button (or use wake‑word detection) to start recording audio via the I2S microphone.

  2. Speech‑to‑Text

    The ESP32 streams the audio to a lightweight speech recognition service (or runs an offline model like Vosk) to convert speech into text.

  3. API Call to Claude

    The text is packaged into an HTTP request and sent over Wi‑Fi to Anthropic’s Claude API. You’ll need a free API key, which includes generous monthly credits for experimentation.

  4. Response Handling

    Claude returns a generated answer. The ESP32 receives the JSON payload, extracts the text, and pushes it to the OLED screen.

  5. Optional Output

    For added convenience, you can route the response through a small speaker or haptic motor for audio or vibration feedback.

End‑to‑end latency typically falls between 2‑5 seconds—fast enough for natural conversation.

Step‑by‑Step Roadmap

If you’re eager to start, here’s how the build unfolds:

  • Week 1: Get the Basics Running

    Set up the Arduino IDE, install the ESP32 board definitions, and blink an LED to confirm the board works.

  • Week 2: Add the Display

    Wire the OLED screen using I²C and get text showing up. Test different fonts and sizes for readability on a tiny screen.

  • Week 3: Integrate the Microphone

    Hook up the I2S microphone, run a simple audio‑level test, and experiment with capturing voice.

  • Week 4: First Claude Interaction

    Obtain a Claude API key, hard‑code a test question, and watch the answer appear on your wrist display.

  • Week 5: Voice‑Enabled Loop

    Combine speech‑to‑text with the API call so you can speak a question and see the reply.

  • Week 6: Sensor Experiments

    Attach a heart‑rate or temperature sensor, feed live data to Claude, and ask for insights like “Should I rest based on my current heart rate?”

  • Week 7: Polish and Enclose

    Optimize power usage, design a simple 3D‑printed or laser‑cut case, and refine your custom system prompts for specific use cases.

Real‑World Use Cases

Once you have the wearable functioning, the possibilities expand quickly:

  • Travel Companion

    Speak a phrase in your language; get instant translation shown on your wrist—no phone needed.

  • Fitness Coach

    Ask Claude to analyze your workout data and suggest adjustments in real time.

  • Learning Aid

    Point the wearable at a foreign menu, hear the translation, and learn vocabulary on the go.

  • Accessibility Tool

    For users with visual impairments, audio output can read back Claude’s responses.

Tips for Success

  • Start Small

    Get each subsystem working individually before combining them. Isolating problems saves hours of frustration.

  • Manage Power

    The ESP32 can draw significant current when transmitting. Use deep‑sleep modes between interactions to extend battery life.

  • Prompt Engineering Matters

    Spend time refining the system prompt you send with each API call. A well‑crafted prompt dramatically improves relevance and consistency.

  • Leverage Open Source

    Projects like ESP32_AI_Connect and Arduino‑Claude‑Bridge already solve many of the networking and JSON‑parsing hurdles—build on their work.

Limitations to Keep in Mind

  • Dependence on Internet

    Since Claude runs in the cloud, you need a Wi‑Fi connection. Off‑line fallbacks (smaller local models) are possible but sacrifice capability.

  • Screen Size Constraints

    The OLED is tiny; prioritize concise responses or use scrolling text for longer answers.

  • Latency Variability

    Network jitter can affect response time. For time‑critical interactions, consider hybrid approaches that handle simple commands locally.

Next Steps

If this sparks your interest, the full guide dives deeper into each hardware selection, provides exact wiring diagrams, shares ready‑to‑flash Arduino sketches, and walks through advanced features like over‑the‑air updates and custom wake‑word detection.

Free download: https://jacksonfire526.gumroad.com/l/cdliu?utm_source=devto&utm_medium=article&utm_campaign=2026-03-31-claude-code-on-wearables

Complete version: https://jacksonfire526.gumroad.com?utm_source=devto&utm_medium=article&utm_campaign=2026-03-31-claude-code-on-wearables

Start building, and let your wrist become the gateway to a personal AI assistant that’s truly yours.

Day 1 – Restart Coding | Built a REST API Project using Spring Boot Fundamentals

For months, my coding routine looked like this:

Learn → Lose consistency → Stop → Restart again.

So today I decided to restart properly — and document everything I build in public.

This is Day 1.

Progress

I built a simple REST API using Spring Boot to refresh my backend fundamentals.

Instead of jumping into complex projects, I wanted to rebuild the basics properly.

Concepts

  • @RestController
  • @RequestMapping
  • Dependency Injection
  • Basic service layer structure
  • MVC architecture

Lesson

Trying to learn too many things at once is the fastest way to burn out.

Mindset

Not Trying to become an expert – Just Improving 1% Everyday