<?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>Forem: davidTang</title>
    <description>The latest articles on Forem by davidTang (@weiwei_tang_fc1fdc4e0b3de).</description>
    <link>https://forem.com/weiwei_tang_fc1fdc4e0b3de</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%2F3874281%2Ff3ea3fcb-54a5-4240-bcaa-5e214d9de275.png</url>
      <title>Forem: davidTang</title>
      <link>https://forem.com/weiwei_tang_fc1fdc4e0b3de</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/weiwei_tang_fc1fdc4e0b3de"/>
    <language>en</language>
    <item>
      <title>How I Stopped Cursor AI from Ruining My Code Style (and How You Can Too)</title>
      <dc:creator>davidTang</dc:creator>
      <pubDate>Mon, 13 Apr 2026 08:03:02 +0000</pubDate>
      <link>https://forem.com/weiwei_tang_fc1fdc4e0b3de/how-i-stopped-cursor-ai-from-ruining-my-code-style-and-how-you-can-too-4h42</link>
      <guid>https://forem.com/weiwei_tang_fc1fdc4e0b3de/how-i-stopped-cursor-ai-from-ruining-my-code-style-and-how-you-can-too-4h42</guid>
      <description>&lt;p&gt;I've been using Cursor as my primary editor for about a month now — working full-time on a Next.js 14 project with TypeScript, Tailwind CSS, and a fairly opinionated component architecture.&lt;/p&gt;

&lt;p&gt;The AI capabilities are genuinely impressive. But after the honeymoon phase, I started noticing a pattern that was quietly eating my productivity.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem Nobody Warns You About
&lt;/h2&gt;

&lt;p&gt;The AI doesn't know your coding standards. And it doesn't care.&lt;/p&gt;

&lt;p&gt;My project has clear conventions: functional components, named exports, Tailwind for all styling, strict TypeScript with zero tolerance for &lt;code&gt;any&lt;/code&gt;, and early returns to keep nesting shallow.&lt;/p&gt;

&lt;p&gt;But every time I asked Cursor to generate a component, help me refactor, or scaffold a new page, the output was a coin flip:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sometimes &lt;code&gt;export default function&lt;/code&gt;, sometimes &lt;code&gt;export function&lt;/code&gt; — no consistency&lt;/li&gt;
&lt;li&gt;Inline &lt;code&gt;style={{ color: 'red' }}&lt;/code&gt; showing up in a Tailwind-only codebase&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;any&lt;/code&gt; sprinkled around like confetti&lt;/li&gt;
&lt;li&gt;Pages Router patterns (&lt;code&gt;getServerSideProps&lt;/code&gt;) sneaking into an App Router project&lt;/li&gt;
&lt;li&gt;Class components appearing in 2026&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these are "wrong" in isolation. But in the context of my project, every single one creates friction. I was spending 20-30% of my time just reformatting AI output to match conventions.&lt;/p&gt;

&lt;p&gt;That's not AI-assisted development. That's AI-generated tech debt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Discovering .cursorrules
&lt;/h2&gt;

&lt;p&gt;I stumbled onto the solution while browsing GitHub repos one evening. Several open-source projects had a &lt;code&gt;.cursorrules&lt;/code&gt; file sitting in their root directory — something I'd never noticed before.&lt;/p&gt;

&lt;p&gt;The concept is simple: you create a plain text file called &lt;code&gt;.cursorrules&lt;/code&gt; in your project root, write your coding standards in natural language, and Cursor's AI will respect them across all interactions — completions, chat, Composer, everything.&lt;/p&gt;

&lt;p&gt;Think of it as onboarding documentation, but for your AI pair programmer instead of a new hire.&lt;/p&gt;

&lt;p&gt;Here's a stripped-down example of what mine looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are a senior TypeScript developer working on a production Next.js application.

Tech Stack:
- TypeScript 5 with strict mode enabled
- React 18 with functional components only
- Next.js 14 using the App Router (NOT Pages Router)
- Tailwind CSS for all styling — no exceptions

Code Style Rules:
- Always use named exports. Never use default exports.
- Prefer early returns to reduce nesting. Max nesting depth: 2 levels.
- Never use the `any` type. Use proper interfaces, generics, or `unknown`.
- Use descriptive variable names. No single-letter variables except in short lambdas.
- Prefer `const` over `let`. Never use `var`.
- Always define proper TypeScript interfaces for component props.

File Structure:
- React components → /components
- Utility functions → /lib
- Type definitions → /types
- API routes → /app/api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After dropping this into my project root, the difference was immediate and dramatic. The AI-generated code went from "needs significant cleanup" to "basically ready to commit."&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Writing Good Rules Is Harder Than You Think
&lt;/h2&gt;

&lt;p&gt;So I had the concept down. But getting the rules right? That took way more iteration than I expected.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem 1: Too vague = useless&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;My first attempt included gems like "write clean, maintainable code" and "follow best practices." The AI nodded politely and continued doing whatever it wanted. These instructions are the equivalent of telling a new developer to "just write good code" — technically correct, practically worthless.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem 2: Too verbose = also useless&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;My second attempt was a 150-line manifesto covering every edge case I could think of. The AI started ignoring chunks of it because there was too much to process. Rules files have an effective attention window, and flooding it with noise drowns out the signal.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem 3: Stack-specific nuances are tricky&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The difference between "use React" and "use React 18 with functional components, hooks, and the App Router pattern" is enormous. The AI treats vague stack references as permission to use any version's patterns. I was getting &lt;code&gt;componentDidMount&lt;/code&gt; mixed with &lt;code&gt;useEffect&lt;/code&gt; in the same conversation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem 4: Phrasing matters more than you'd think&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;"Don't use any" is weaker than "Never use the &lt;code&gt;any&lt;/code&gt; type. For unknown types, use &lt;code&gt;unknown&lt;/code&gt; and narrow with type guards." The more explicit and actionable the instruction, the better the compliance.&lt;/p&gt;

&lt;p&gt;I spent probably 4-5 hours across two weeks refining my rules file. Effective? Yes. Fun? Not remotely.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Faster Path
&lt;/h2&gt;

&lt;p&gt;Around iteration six of my hand-crafted rules file, a colleague pointed me to an online generator that takes a completely different approach: instead of writing rules in prose, you select your tech stack and preferences from a visual interface, and it outputs an optimized rules file.&lt;/p&gt;

&lt;p&gt;The tool is at &lt;strong&gt;ittoolshq.com/en/cursorrules-generator&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;What made it click for me:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Granular style controls.&lt;/strong&gt; It's not just "React yes/no." You can specify individual code style preferences — functional components, named exports, early returns, strict TypeScript — at a very fine-grained level. These are exactly the kinds of rules that make the biggest practical difference.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Multi-editor support.&lt;/strong&gt; I use Cursor primarily, but I've been experimenting with Windsurf on a side project. This tool generates the right format for each:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cursor → &lt;code&gt;.cursorrules&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Windsurf → &lt;code&gt;.windsurfrules&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Cline → &lt;code&gt;.clinerules&lt;/code&gt; or &lt;code&gt;AGENTS.md&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Sensible defaults.&lt;/strong&gt; The generated output isn't just a list of "do this, don't do that." It structures the rules in a way that models respond well to — role framing, grouped directives, clear prohibitions.&lt;/p&gt;

&lt;p&gt;The workflow is: open the page → check the boxes that match your stack → copy the output → paste into your project root → done. Took me about 2 minutes versus the hours I spent writing mine manually.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Before and After
&lt;/h2&gt;

&lt;p&gt;Let me show you the actual difference in AI output quality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before .cursorrules — asking Cursor to create a user profile card:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserProfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUserData&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setUserData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nf"&gt;setLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;loading&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;textAlign&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;center&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;20px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1px solid #ccc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;8px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;16px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;avatar&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;64px&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;borderRadius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;50%&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;8px 0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#666&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Issues: default export, &lt;code&gt;any&lt;/code&gt; props, inline styles everywhere, no TypeScript types, no error handling, no loading skeleton, untyped state.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After .cursorrules — the exact same prompt:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;UserProfileProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;UserData&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;avatar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
  &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserProfile&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;UserProfileProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;UserData&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchUser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to fetch user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;UserData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;setUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;setError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Unknown error&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;fetchUser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-center p-5 text-red-500"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;UserProfileSkeleton&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"border border-gray-200 rounded-lg p-4"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt;
        &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;avatar&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'s avatar`&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"w-16 h-16 rounded-full"&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"mt-2 text-lg font-semibold"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text-gray-500"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same AI. Same prompt. Same model. The only difference is a config file in the project root.&lt;/p&gt;

&lt;p&gt;Named export. Proper interfaces. Tailwind classes. Early returns. Error handling. Typed state. Destructured props. No &lt;code&gt;any&lt;/code&gt; in sight.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 5 Rules That Made the Biggest Impact
&lt;/h2&gt;

&lt;p&gt;After weeks of experimentation, these are the specific rules that produced the most noticeable improvement in output quality:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. "Never use &lt;code&gt;any&lt;/code&gt;. Use &lt;code&gt;unknown&lt;/code&gt; for truly unknown types and create proper interfaces for everything else."
&lt;/h3&gt;

&lt;p&gt;This single rule eliminated roughly 90% of my type-safety fixes. Before this rule, the AI would default to &lt;code&gt;any&lt;/code&gt; whenever the type wasn't immediately obvious. After — it actually takes the time to define interfaces.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. "Use Next.js 14 App Router exclusively. Never use &lt;code&gt;getServerSideProps&lt;/code&gt;, &lt;code&gt;getStaticProps&lt;/code&gt;, or any Pages Router API."
&lt;/h3&gt;

&lt;p&gt;Next.js has been around long enough that most training data includes Pages Router patterns. Without this explicit prohibition, the AI would regularly mix paradigms, which is especially confusing for newer developers on the team who might not recognize the mismatch.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. "All styling must use Tailwind CSS utility classes. Never use inline styles, CSS modules, or styled-components."
&lt;/h3&gt;

&lt;p&gt;This eliminated the most common source of inconsistency in generated code. The AI has strong tendencies toward inline styles (probably because they're self-contained and don't require imports), so you need to be very explicit about prohibiting them.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. "Prefer early returns to reduce nesting. Maximum nesting depth is 2 levels."
&lt;/h3&gt;

&lt;p&gt;This one surprised me with how well it works. The AI actually counts nesting levels and restructures logic with guard clauses. Code readability improved significantly.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. "When creating new files, follow this directory structure: components in /components, utilities in /lib, type definitions in /types."
&lt;/h3&gt;

&lt;p&gt;Subtle but powerful. When you ask the AI to create a new utility function, it'll suggest putting it in &lt;code&gt;/lib&lt;/code&gt; instead of dropping it in a random location. Small thing, but it keeps the project organized as it grows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Tips for Your Own Setup
&lt;/h2&gt;

&lt;p&gt;A few things I've learned that might save you some trial and error:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Start minimal.&lt;/strong&gt; Begin with 5-10 core rules that address your biggest pain points. You can always add more later. A focused rules file outperforms a comprehensive one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Be explicit about what NOT to do.&lt;/strong&gt; "Use Tailwind" is good. "Use Tailwind. Never use inline styles or CSS-in-JS" is better. The model responds more reliably to clear prohibitions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Include framework version numbers.&lt;/strong&gt; "React 18" and "Next.js 14 App Router" give the model much better context than just "React" and "Next.js."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update your rules as your project evolves.&lt;/strong&gt; I revisit mine roughly every two weeks. As new patterns emerge in the codebase, I add rules to codify them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Test with edge cases.&lt;/strong&gt; After updating your rules, ask the AI to generate something that would typically violate your conventions. If it still misbehaves, the rule needs to be rephrased or made more prominent.&lt;/p&gt;

&lt;h2&gt;
  
  
  The ROI Calculation
&lt;/h2&gt;

&lt;p&gt;Here's the math that convinced my team to adopt this across all our projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Time to set up .cursorrules: &lt;strong&gt;5 minutes&lt;/strong&gt; (with a generator) to &lt;strong&gt;2 hours&lt;/strong&gt; (from scratch)&lt;/li&gt;
&lt;li&gt;Time saved per day on code reformatting: &lt;strong&gt;15-30 minutes&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Break-even point: &lt;strong&gt;Day 1&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Over a month, that's roughly &lt;strong&gt;8-10 hours&lt;/strong&gt; of developer time saved per person. For a team of four, that's a full work week recovered every month.&lt;/p&gt;

&lt;p&gt;And the quality improvement is arguably even more valuable than the time savings. Fewer style inconsistencies means fewer code review comments, fewer merge conflicts from reformatting, and a more consistent codebase overall.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;If you want to try this yourself:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option A: Write your own.&lt;/strong&gt; Create a &lt;code&gt;.cursorrules&lt;/code&gt; file in your project root. Start with your 5 most important conventions. Test, iterate, refine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Option B: Generate one.&lt;/strong&gt; Go to &lt;strong&gt;ittoolshq.com/en/cursorrules-generator&lt;/strong&gt;, select your stack and preferences, copy the output. Customize from there.&lt;/p&gt;

&lt;p&gt;Either way, the important thing is to have one. An imperfect &lt;code&gt;.cursorrules&lt;/code&gt; file is infinitely better than no &lt;code&gt;.cursorrules&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;If you're using Windsurf, the same concept applies — just name the file &lt;code&gt;.windsurfrules&lt;/code&gt;. For Cline users, it's &lt;code&gt;.clinerules&lt;/code&gt; or &lt;code&gt;AGENTS.md&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;What rules have you found most effective in your own setup? I'm always looking to refine mine — drop your best tips in the comments.&lt;/p&gt;

</description>
      <category>cursor</category>
      <category>ai</category>
      <category>typescript</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Stop Writing JSON Schemas by Hand: A Better Way to Build Claude Agent Tools</title>
      <dc:creator>davidTang</dc:creator>
      <pubDate>Sun, 12 Apr 2026 02:02:05 +0000</pubDate>
      <link>https://forem.com/weiwei_tang_fc1fdc4e0b3de/stop-writing-json-schemas-by-hand-a-better-way-to-build-claude-agent-tools-2on3</link>
      <guid>https://forem.com/weiwei_tang_fc1fdc4e0b3de/stop-writing-json-schemas-by-hand-a-better-way-to-build-claude-agent-tools-2on3</guid>
      <description>&lt;h1&gt;
  
  
  Stop Writing JSON Schemas by Hand: A Better Way to Build Claude Agent Tools
&lt;/h1&gt;

&lt;p&gt;If you’ve been building AI Agents or working with Anthropic's Claude to implement Function Calling (Tool Use), you probably know the pain. &lt;/p&gt;

&lt;p&gt;Defining a new tool isn't just about writing the underlying business logic. It requires formatting exact JSON Schemas that strictly adhere to Anthropic’s nested specifications. A missing bracket, an incorrect type definition, or a formatting typo means your entire API call crashes. Frankly, writing and debugging these schemas manually is a massive time-sink.&lt;/p&gt;

&lt;p&gt;To solve my own headache, I found/built a straightforward solution: the &lt;strong&gt;&lt;a href="https://ittoolshq.com/openclaw-tool-generator" rel="noopener noreferrer"&gt;OpenClaw Tool Generator&lt;/a&gt;&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;It’s a zero-setup, local-first web utility designed specifically to generate Anthropic-compliant Tool Use schemas and wrapper codes in seconds.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why You Should Give It a Try
&lt;/h2&gt;

&lt;p&gt;Here are the core reasons why this might save you hours of debugging:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Natural Language to Schema
&lt;/h3&gt;

&lt;p&gt;You don't need to manually define properties one by one. You can simply describe what your tool does in plain English. For example: &lt;em&gt;"I need a tool that queries weather data. It should take a city string (required) and an optional boolean parameter for Celsius."&lt;/em&gt; &lt;br&gt;
Hit generate, and it instantly visualizes the exact, Anthropic-ready JSON Schema.&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%2F1u5co7zodd7hws9h4usn.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%2F1u5co7zodd7hws9h4usn.png" alt=" " width="800" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Strict Anthropic Specification Alignment
&lt;/h3&gt;

&lt;p&gt;Generic JSON schema generators often fall short because LLM tool calling requires specific constraints. OpenClaw naturally aligns with Claude's strict Tool Use API format. The generated JSON block can be copied and pasted directly into your API payload without any secondary formatting.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Real-time Syntax Validation &amp;amp; Claude Preview
&lt;/h3&gt;

&lt;p&gt;The built-in editor right next to the form provides real-time JSON syntax highlighting and continuous error-checking. More importantly, it offers a "Claude Perspective Preview"—letting you intuitively see exactly how the language model will perceive your tool definition before you even make the API call.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Boilerplate Generation (Python &amp;amp; Node.js)
&lt;/h3&gt;

&lt;p&gt;Having the schema is only half the battle. OpenClaw takes it a step further by generating the code scaffolding for your tool in Python or JavaScript (Node.js). It sets up the function definition and schema injection automatically. You just copy the boilerplate, drop in your actual business logic (like fetching queries or scraping data), and your plugin is ready.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. 100% Privacy Friendly (Local Browser Execution)
&lt;/h3&gt;

&lt;p&gt;When we write internal tools, exposing our database schemas or sensitive API signatures to third-party servers is a massive red flag. OpenClaw runs &lt;strong&gt;100% locally in your browser&lt;/strong&gt;. No data is ever sent back to a remote server. You can safely define tools for your company's proprietary services without privacy anxiety.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;If you are spending your weekends wiring LangChain setups, tinkering with LlamaIndex, or building raw API integration for Claude Agents, this tool will act as a significant productivity booster. &lt;/p&gt;

&lt;p&gt;It’s completely free and requires no login. You can try it out directly right here:&lt;br&gt;
👉 &lt;strong&gt;&lt;a href="https://ittoolshq.com/openclaw-tool-generator" rel="noopener noreferrer"&gt;OpenClaw Tool Generator&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I'd love to hear your feedback or feature requests. Let me know in the comments how you handle your tool-calling workflows!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>claude</category>
      <category>langchain</category>
      <category>json</category>
    </item>
  </channel>
</rss>
