Write sh*t down, so you don't forget it.
Back to blog

How Are You Using AI to Improve Your Workflow?

I’ll be honest, for the longest time I was using AI the same way everyone else was. Open a chat, paste some code, ask a question, copy the answer, move on. It worked, but it wasn’t exactly life-changing. I was basically using a Ferrari to go grocery shopping. 🙃

Then I discovered Claude Code and everything changed. Not overnight though, it took me months of trial and error, breaking things, getting frustrated, and slowly figuring out how to make it actually work the way I needed it to. What I ended up with is a setup that honestly feels less like a tool and more like having a team of developers sitting next to me. Let me walk you through how I got here.

It all started with a CLAUDE.md file

Every Claude Code project starts with a CLAUDE.md file at the root of your repo. Think of it as the instruction manual you hand to a new developer on their first day. It’s the first thing Claude reads when it enters your project, and it sets the tone for everything.

My first CLAUDE.md had a decent amount of content but it wasn’t structured properly. It was a wall of text with no clear sections, no golden rules, and no specific instructions for how I wanted Claude to behave. Predictably, Claude kept doing stuff I didn’t want, using the wrong patterns, ignoring our conventions, and generating code that looked nothing like the rest of the codebase. 😑

After a few weeks of correcting the same mistakes over and over, I started adding more detail. Now my CLAUDE.md includes:

  • Project overview - What the app is, the tech stack, how things are wired together
  • Quick commands - Build, test, lint, the stuff you run 50 times a day
  • Behavior guidelines - Things like “always write tests before implementation” and “never skip linting”
  • Code quality standards - Naming conventions, file structure, architectural decisions
  • Golden rules - Non-negotiable stuff that Claude must follow no matter what

The key lesson I learned: be ridiculously specific. Don’t say “follow best practices.” Tell it which best practices. If your project uses a specific component pattern, spell it out. The more context you give Claude, the less time you spend fixing its output.

# Project Name

## Overview
Full-stack application with Next.js frontend and .NET API backend.

## Quick Commands
- `npm run dev` - Start development server
- `npm run test` - Run unit tests
- `npm run lint` - Run linter

## Golden Rules
1. Never skip tests
2. Always use TypeScript strict mode
3. Follow the established component patterns
4. Check for accessibility compliance

Agents: because one Claude isn’t enough

This is where things started getting really fun. Claude Code supports agent definitions that live in .claude/agents/. Each agent is a markdown file that defines a specialized role with its own instructions and knowledge.

At first I had one agent. Then two. Then I couldn’t stop making them because they were so damn useful. I now run 9 agents in my setup: 😬

AgentRole
frontendReact/Next.js components, state management, UI patterns
backend.NET Core API development, server-side logic
sqlSQL Server queries, database operations
playwrightEnd-to-end testing with video recording
dockerContainer management, infrastructure, networking
qaCode review, accessibility audits, performance checks
securityOWASP Top 10 audits, SOC2 Type II compliance, threat modeling, formal security reports
githubBranch management, PR creation, test video uploads
build-error-resolverMinimal-diff fixes for TypeScript, Biome, and .NET build errors

Each agent has domain-specific instructions. My frontend agent knows our component patterns, which state management library we use, and how forms are structured. My sql agent knows our database schema and query conventions. It’s like having specialists on call instead of one generalist who kinda knows everything but not really.

Here’s a simplified example:

# Frontend Agent

You are a frontend developer specializing in React and Next.js.

## Patterns
- Use the App Router (page.tsx for server components, PageUI.tsx for client components)
- State management via TanStack Query for server state, URL params for UI state
- All forms use our form library with schema-based validation

## Rules
- Always check accessibility (WCAG 2.1 AA)
- Never use inline styles, use the design system
- Prefer server components unless client interactivity is required

The build-error-resolver agent deserves a special shout-out. This thing is a lifesaver. It makes the smallest possible diff to fix build errors, nothing more. It never refactors, never changes architecture, and never “improves” surrounding code. When you have a TypeScript or Biome error, this agent fixes it surgically and moves on. No more Claude deciding that fixing a type error is a good time to refactor your entire component. 🙌

Contexts: different vibes for different tasks

I learned this one the hard way. I was using Claude the same way for everything, writing code, reviewing PRs, investigating bugs, and the results were inconsistent. Sometimes Claude would be too chatty when I just wanted code. Other times it wouldn’t dig deep enough when I needed research.

Contexts live in .claude/contexts/ and let you switch Claude’s behavior depending on what you’re doing. I use three:

Development Mode (dev.md)

“Write code first, explain after.” This makes Claude action-oriented. It minimizes questions, focuses on implementation, and only explains when asked. Perfect for when you know what you want and just need it built.

Review Mode (review.md)

Thoroughness is the priority here. Claude organizes feedback by severity, checks security first, and doesn’t let anything slide. This is the mode I use for PR reviews and code audits.

Research Mode (research.md)

“Read widely before concluding.” Claude explores the codebase, reads documentation, and presents findings before making any recommendations. Great for investigating bugs or evaluating architectural decisions.

Switching contexts is free and the quality difference is night and day. Trust me on this one.

Skills: teaching Claude new tricks

Skills are basically knowledge packs that live in .claude/skills/. They can be installed at the project level (inside your repo’s .claude/skills/) or globally at the user level (~/.claude/skills/). Agents reference them when they need deep expertise on a specific topic.

You can find skills on marketplaces like skills.sh and skillsmp.com, or on GitHub repos. Installing them is as simple as running npx skills add with the repo URL. Here’s what I have installed:

Claudeception - skills.sh | GitHub

Ok this one is my absolute favorite and I’m a little obsessed with it. It’s a continuous learning system that extracts reusable knowledge from your work sessions. After each session, it evaluates whether something worth remembering was discovered and creates a new skill if so. Basically Claude is building its own playbook over time. The more you use it, the smarter it gets. Over time, Claudeception has generated dozens of skills for me automatically from real debugging sessions and implementation tasks. They live in my global ~/.claude/skills/ directory so they’re available across all my projects. 🧠

npx skills add https://github.com/blader/claudeception --skill claudeception

Security Compliance - skills.sh | GitHub

By davila7. A comprehensive security knowledge base covering SOC2 Trust Service Criteria, OWASP Top 10 mitigations, threat modeling frameworks (STRIDE, PASTA), and risk scoring. My security agent references this constantly. If you’re building anything that needs to pass a compliance audit, install this immediately.

npx skills add https://github.com/davila7/claude-code-templates --skill security-compliance

Vercel React Best Practices - skills.sh | GitHub

Straight from Vercel Engineering. A collection of 57 rules across 8 categories covering performance, bundle size, server-side rendering, re-renders, animations, and CSS patterns. Each rule includes correct and incorrect examples so Claude doesn’t have to guess. If you’re building with React or Next.js, this is a must-have.

npx skills add https://github.com/vercel-labs/agent-skills --skill vercel-react-best-practices

Web Design Guidelines - skills.sh | GitHub

Also from Vercel. Reviews your UI code against web interface best practices and accessibility standards. I use it for design audits and UX reviews. It catches things I would have missed.

npx skills add https://github.com/vercel-labs/agent-skills --skill web-design-guidelines

Custom Selectors - Project-specific UI selector patterns for E2E testing. Covers modals, form components, date pickers, and other custom widgets. You won’t find this one on any marketplace because I built it specifically for my app’s UI components. This is a good example of a skill that’s tailored to your project rather than being generic.

The beauty of skills is that they’re composable. An agent can reference multiple skills, and skills can be shared across projects.

Be intentional about what you install

I’m very security conscious, so I don’t just install every skill I come across. Skills are code that runs in your project context, so you should treat them the same way you’d treat any dependency: read it first, understand what it does, and make sure it’s actually useful before adding it.

What I do when I find a skill or repo that looks interesting is point Claude at it and say “read through this and tell me which parts would actually benefit our codebase.” Claude analyzes the skill’s rules and patterns against my existing code and tells me what’s relevant and what’s not. Sometimes a skill has 57 rules but only 8 of them apply to my project. Why would I load all 57 into context every time?

From there I either:

  • Install the full skill if most of it is relevant and I’ve reviewed what it does (like Claudeception or the security compliance skill, those are universally useful)
  • Cherry-pick the useful parts and add them to my own .claude/docs/ files, tailored to my project’s patterns and conventions
  • Skip it entirely if Claude’s analysis shows it doesn’t add much value

This approach has two benefits. First, security: you know exactly what’s in your setup because you’ve vetted everything. Second, efficiency: every skill adds to Claude’s context, and context isn’t free. Remember the whole modular docs lesson from earlier? Same thing applies here. Only load what’s relevant to your codebase. It’s the difference between giving a new developer a 500-page company wiki versus a curated onboarding doc with just the stuff they need to know.

Hooks: the thing that saved my sanity

Let me tell you about the first time Claude pushed code with console.log statements scattered everywhere to a PR. That was a fun conversation with the team. 😬

Hooks are now the backbone of my setup. They run automatically before or after Claude uses certain tools, catching problems before they snowball. They’re configured in .claude/settings.json.

Pre-Tool Hooks (Before Claude Acts)

Block long-lived servers outside tmux - If Claude tries to run npm run dev or docker compose up without being in a tmux session, it gets blocked. I learned this one after Claude locked up my terminal for the third time running a dev server in a non-multiplexed session. 🙃

Git push reminder - Before any git push, Claude is reminded to review changes one more time. A small speed bump that has prevented more than a few premature pushes.

Block random file creation - Claude loves creating random markdown and text files everywhere if you let it. This hook blocks file creation outside of designated directories. No more documentation sprawl.

Compact suggestion - After approximately 50 tool calls, Claude gets reminded to run /compact to manage context window size. Long sessions degrade in quality if the context gets too bloated. I had to learn this the hard way after a 2-hour session where Claude started forgetting things I told it 30 minutes earlier.

Post-Tool Hooks (After Claude Acts)

Type checking after edits - Every time Claude edits or writes a .ts or .tsx file, tsc --noEmit and the linter run automatically. If there are type errors, Claude sees them immediately and fixes them before moving on. This hook alone has probably saved me hours.

Console.log audit - After editing TypeScript files, a script scans for console.log statements. Never again will debug logs make it into production. Never. Again.

Here’s what the hook config looks like in settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hook": "if echo \"$INPUT\" | grep -q 'npm run dev'; then echo 'BLOCK: Use tmux for long-running processes'; fi"
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hook": ".claude/hooks/typecheck-after-edit.sh"
      }
    ]
  }
}

MCP Servers: giving Claude superpowers

Model Context Protocol (MCP) servers give Claude access to external tools and services. You can learn more about configuring them in the MCP documentation. They’re configured in .mcp.json at the project root. I use three:

Docker MCP

Docker Docs | GitHub

If you’ve read my previous articles you know I spend a lot of time in Docker. This MCP gives Claude the ability to manage containers directly, start, stop, inspect, debug, check logs, all without switching to a terminal. When paired with my docker agent, Claude can troubleshoot container issues autonomously. It’s like having a DevOps engineer on speed dial. Docker also has a guide for using it with Claude Code if you want to set it up.

Chrome DevTools MCP

GitHub | npm

This one connects Claude to a running browser through Chrome DevTools Protocol. Claude can take snapshots of pages, inspect elements, check console errors, monitor network requests, and run performance traces. It closes the feedback loop between writing code and seeing what actually happens in the browser. You can also check out the Claude Code docs on using it with Chrome for setup instructions.

Context7 Documentation MCP

GitHub | Upstash Blog

Ok let’s be real, one of the most annoying things about AI coding assistants is when they give you outdated code because their training data is from 6 months ago. Context7 fixes this by fetching the latest documentation for your dependencies on demand. I have it configured with library IDs for my entire stack:

  • Frontend: Next.js, React, TypeScript, TailwindCSS, shadcn/ui, TanStack Query/Table
  • Backend: ASP.NET Core, Entity Framework Core, AutoMapper
  • Database & Auth: SQL Server, Keycloak
  • Testing: Playwright, Vitest, Storybook
  • Tooling: Biome (linting/formatting)

When Claude needs to look up an API or check how something works in the latest version, it queries Context7 instead of guessing. The difference in accuracy is massive. This alone has drastically reduced the number of times I have to say “that API doesn’t exist anymore.”

{
  "mcpServers": {
    "docker": {
      "command": "docker",
      "args": ["mcp", "gateway", "run"]
    },
    "chrome-devtools": {
      "command": "npx",
      "args": ["chrome-devtools-mcp@latest"]
    },
    "context7": {
      "command": "npx",
      "args": ["@upstash/context7-mcp@latest"]
    }
  }
}

Custom slash commands

Custom commands live in .claude/commands/ and give you shortcuts for complex operations. I have two that I use all the time:

/verify - The quality gate

A comprehensive quality check that runs in different modes:

  • quick - Just type checking and linting
  • full - Everything: types, lint, tests, backend build, secret scanning
  • pre-commit - Checks relevant to what you’re about to commit
  • pre-pr - The full gauntlet before opening a pull request

/stream - Implementation pattern

A reference command that outputs the correct pattern for implementing streaming AI responses in our app. Instead of me trying to remember the boilerplate every time, I just run the command and get the exact server and client code I need.

Commands are just markdown files with instructions for Claude. Dead simple to create, easy to maintain.

Documentation: the .claude/docs directory

After a while, my CLAUDE.md was getting massive. Like, embarrassingly large. Every time Claude did something wrong, I’d add another rule to CLAUDE.md. It was turning into a novel and I knew this was going to be a problem, which brings me to something important.

I now maintain a structured documentation directory at .claude/docs/ organized by topic:

.claude/docs/
  ├── architecture/    # App Router, component patterns
  ├── data/            # Data fetching, state management
  ├── forms/           # Form library patterns, validation
  ├── tables/          # DataTable component, pagination
  ├── testing/         # Test patterns, coverage targets
  ├── quality/         # TypeScript strictness, performance
  ├── ui/              # Error handling, loading states, a11y
  └── i18n/            # Internationalization setup

Each file documents a specific pattern with examples. When an agent needs to implement something, it references the relevant doc instead of guessing. Bonus: these docs are useful for onboarding new team members too. Double duty. 👌

Why not just put everything in CLAUDE.md?

This is something I wish someone had told me earlier because it directly impacts your wallet and your productivity.

Everything in CLAUDE.md gets loaded into context on every single conversation. If your CLAUDE.md is 5,000 lines covering every pattern, convention, and edge case, Claude is eating all those tokens before you even ask your first question. That burns through your weekly limits fast.

With modular docs, CLAUDE.md stays lean with just the essentials (project overview, key commands, golden rules). The detailed stuff lives in separate files that agents and skills pull in only when they need them. A frontend task loads the component patterns doc. A testing task loads the test conventions doc. Nothing else gets touched.

Think of it like lazy loading for AI context. You wouldn’t load every JavaScript module on page load, so why load every piece of documentation on every conversation?

The other benefits:

  • Context window preservation - Every token spent on irrelevant docs is a token that can’t be used for your actual code. A bloated CLAUDE.md means Claude hits context limits sooner and starts forgetting things.
  • Cost savings - Tokens cost money whether you’re on a subscription or paying per API call. Only loading what’s relevant saves a surprising amount.
  • Faster startup - Smaller CLAUDE.md means Claude processes your project context faster. When you’re running dozens of sessions a day, those seconds add up.

The workflow: it all starts with a PRD

This is probably the most important part of my setup and the thing that made the biggest difference in output quality.

It starts with me telling Claude what I want to build. Could be a feature, a fix, whatever. I don’t need to have it all figured out, I just need the idea. From there, Claude flips into interview mode. It starts asking me clarifying questions, what’s the expected behavior, what are the edge cases, what do I not want, who’s the user, what does “done” look like. It’s like pair programming with a product manager who actually listens. 😏

Once Claude has enough context from the interview, it takes all of that and generates a structured PRD (Product Requirements Document) with user stories, acceptance criteria, and dependencies. From the PRD, it breaks everything down into individual tasks with clear descriptions. Only then does it start writing code.

I can’t overstate how much this changed things. Before this, I’d just tell Claude “build me a thing” and it would start coding based on whatever vague instruction I gave it. I’d end up with something that was technically functional but missed the point entirely. Now, by the time Claude starts implementing, we’ve already had a conversation about what we’re building and why. No more “that’s not what I meant” moments. Well, fewer of them at least. 🙃

The full pipeline looks like this: IDEA > INTERVIEW > PRD > TASKS > PLAN > CODE > TEST > BUILD > VERIFY > PR

Every PR ships with a video

This is something I’m really proud of. Every PR that Claude creates includes a short video showing exactly what was built or changed. Not a 20-minute recording of the entire E2E test suite, just the tests that are specific to that PR. If the PR adds a new form, the video shows the form being filled out, submitted, and validated. If it fixes a bug, the video shows the bug being reproduced and then working correctly after the fix.

This does a few things. First, it makes code review way faster because the reviewer can watch a 30-second video and immediately understand what the PR does without having to pull the branch and test it locally. Second, it gives QA a clear reference for what to test and how to replicate it. Third, it creates a living history of what was built and when, which is surprisingly useful when you need to go back and understand why something was changed.

My playwright agent handles the test recording and my github agent handles uploading the videos and attaching them to the PR. It’s fully automated, I don’t have to think about it. Claude runs the relevant tests with video recording enabled, captures the output, and includes it in the PR description.

The .claude/WORKFLOW.md file documents all of this. It’s a quick reference that maps:

  • The idea > interview > PRD > tasks flow
  • Which context to use for which task
  • Which agent handles what
  • Available commands and when to use them
  • The development feedback loop (Edit > Rebuild > Inspect > Fix > Repeat)
  • Hook behavior and how to interpret warnings

Without this file, I had a bunch of configs sitting in a directory. With it, I have a system.

Permissions: because Claude will do dumb stuff if you let it

The .claude/settings.local.json file controls what Claude is allowed to do. I maintain an explicit whitelist of allowed bash commands (docker, npm, git, curl, etc.) and enabled skills. This prevents Claude from running arbitrary commands while still giving it enough freedom to be useful.

I also configure which MCP servers are active and what library documentation Context7 should have access to. The principle is simple: give Claude exactly what it needs, nothing more. Trust me, you do not want Claude running random commands on your machine without guardrails. 💀

What I learned building all this

Here’s the stuff I wish I knew when I started:

1. Start small and iterate. Don’t try to build this entire setup in a weekend. Start with CLAUDE.md and your golden rules. Add agents and hooks as you identify patterns over time.

2. Make your agents specific. A “general coding” agent is useless. An agent that knows your exact component patterns, testing conventions, and state management approach is invaluable. The more specific, the better.

3. Use hooks aggressively. Every time you catch yourself manually running a check after Claude edits something, that’s a hook waiting to be written. The type checking hook alone changed my life.

4. Set up Context7 early. Outdated documentation is one of the biggest sources of AI hallucinations. Pre-configuring your library IDs means Claude always has access to current docs.

5. Document your patterns. Every time you explain a pattern to Claude more than twice, write it down in .claude/docs/. It pays dividends.

6. Let Claude learn from itself. That’s what Claudeception does. When Claude solves a tricky bug or discovers a non-obvious pattern, it captures that knowledge as a skill for future sessions.

7. Use Cortex to get back up to speed. When you come back to a project after a few days or weeks and can’t remember where you left off, Cortex is a lifesaver. You can search through it to see what was last worked on, what problems were solved, and what patterns were established. It’s like having a dev journal that writes itself and makes context-switching between projects way less painful.

8. Don’t blindly install skills. When you find a skill that looks useful, point Claude at the repo and ask it to analyze which parts actually benefit your codebase. Install the full thing only if most of it applies. Otherwise, cherry-pick the relevant parts into your own docs. Every skill adds context, and unnecessary context costs you tokens and degrades quality.

9. Tell Claude what you want, then let it interview you. Don’t jump straight into coding. Tell Claude the idea, let it ask you questions, and let it generate a PRD and tasks from your answers. The 5 minutes you spend in that interview saves hours of rework. Using the /verify command at each stage prevents Claude from shipping half-baked work.

10. Contexts are free, use them. Development, review, and research require fundamentally different approaches. The quality difference between using the right context and not using one is significant.

11. Keep your hooks fast. Hooks run on every relevant tool call. If your type checking script takes 30 seconds, it’ll slow everything down. Keep them lightweight and focused.

12. Prune regularly. Your setup should evolve with your project. Remove agents you’re not using, update docs that are stale, and tone down hooks that are too noisy.

The complete directory structure

For reference, here’s what my fully configured Claude Code project looks like:

your-project/
├── CLAUDE.md                           # Project constitution
├── .mcp.json                           # MCP server configuration
└── .claude/
    ├── WORKFLOW.md                     # Quick reference guide
    ├── settings.json                   # Hooks and plugin configuration
    ├── settings.local.json             # Permissions and MCP config
    ├── agents/                         # Specialized agent definitions
    │   ├── frontend.md
    │   ├── backend.md
    │   ├── sql.md
    │   ├── playwright.md
    │   ├── docker.md
    │   ├── qa.md
    │   ├── security.md
    │   ├── github.md
    │   └── build-error-resolver.md
    ├── contexts/                       # Behavioral modes
    │   ├── dev.md
    │   ├── review.md
    │   └── research.md
    ├── commands/                       # Custom slash commands
    │   └── verify.md
    ├── hooks/                          # Hook scripts
    │   ├── typecheck-after-edit.sh
    │   └── check-console-log.sh
    ├── docs/                           # Project documentation
    │   ├── architecture/
    │   ├── data/
    │   ├── testing/
    │   └── ui/
    └── skills/                         # Installed knowledge packs
        ├── claudeception/
        ├── security-compliance/
        ├── vercel-react-best-practices/
        └── web-design-guidelines/

Wrapping up

Look, I’m not going to sit here and tell you this setup is perfect or that it’ll work for everyone. What I will tell you is that the difference between using AI as a chatbot and using it as an actual development partner comes down to how much time you’re willing to invest in configuring it.

It took me months of tweaking, breaking things, and getting annoyed at Claude before I landed on something that actually works. But it’s been worth it. My setup catches mistakes before they become problems, enforces standards without me having to think about it, and honestly makes me a faster developer.

Take what works from my setup, ignore what doesn’t, and build your own. The best configuration is the one that fits your workflow, not mine.

And yes, I used AI to help me write this article. 🤪

Thanks for reading. 🙌


Hire me

Do you have a project you need help with? Would you like to improve your processes to work faster and more efficiently? Contact me for a free consult to see if I can help, let's get you and your team being productive and shipping products.

Let's chat