stackademic

The leading education platform for anyone with an interest in software development.

The Missing Manual for AI-Assisted Development with Claude

The Missing Manual for AI-Assisted Development with Claude

TarrantRo

For engineers who want AI to genuinely integrate into their daily development workflow — not just answer questions.

Table of Contents

  1. Why You Need a Configuration System
  2. File Hierarchy Overview
  3. CLAUDE.md: Your Project’s AI Briefing Document
  4. settings.json: Behavior and Permission Control
  5. Hooks: The Key to Automated Workflows
  6. MCP Servers: Extending AI’s Reach
  7. Skills: Encapsulating Reusable AI Workflows
  8. Agent SDK: Building Custom AI Agents
  9. Development Best Practices
  10. Common Anti-Patterns

1. Why You Need a Configuration System

Most developers start with Claude CLI the same way: open a terminal, ask a question, get an answer — then repeat themselves every session explaining the tech stack, coding conventions, and project structure.

The root cause is missing context. A configuration system’s core value is ensuring the AI already understands your project, your preferences, and what it’s allowed to do before a single message is typed.

A well-structured configuration lets you:

  • Give the AI permanent knowledge of your tech stack and conventions, no re-explaining needed
  • Require explicit confirmation before dangerous operations like git push --force
  • Automate repetitive tasks like formatting on file save
  • Share a consistent AI experience across your entire team

2. File Hierarchy Overview

Claude CLI configuration follows a proximity principle: configuration closer to the project takes higher priority. Personal settings never bleed into shared team configuration.

~/.claude/                          # Global user-level config
├── settings.json                   # Global permissions, model, behavior
├── CLAUDE.md                       # Personal global preferences (not committed)
├── keybindings.json                # Custom keyboard shortcuts
└── projects/
    └── <project-hash>/
        └── memory/                 # Auto-generated project memory files
<project-root>/
├── CLAUDE.md                       # Project-level briefing (committed, team-shared)
├── .claude/
│   ├── settings.json               # Project permissions and behavior (committed)
│   ├── settings.local.json         # Local overrides (add to .gitignore)
│   └── skills/                     # Project-specific Skill definitions
│       └── my-skill.md
└── src/
    └── components/
        └── CLAUDE.md               # Subdirectory-level notes (optional)

Configuration Priority (highest to lowest)

Subdirectory CLAUDE.md
  > Project .claude/settings.local.json
    > Project .claude/settings.json
      > Project root CLAUDE.md
        > Global ~/.claude/settings.json
          > Global ~/.claude/CLAUDE.md

Rule of thumb: team conventions go in project-level config, personal preferences go in global config, sensitive local overrides go in settings.local.json (gitignored).

3. CLAUDE.md: Your Project’s AI Briefing Document

CLAUDE.md is automatically loaded by Claude CLI at the start of every conversation. Think of it as an onboarding document the AI reads before touching your codebase.

What a Good CLAUDE.md Contains

# Project Name
## Tech Stack
- Backend: Go 1.22, Chi router
- Frontend: React 18 + TypeScript, Vite
- Database: PostgreSQL 15, sqlc for type-safe queries
- Testing: Go stdlib testing + testify; Vitest for frontend
## Project Structure
- `cmd/` — service entry points
- `internal/` — business logic (no external imports)
- `pkg/` — reusable libraries
- `web/` — frontend source
## Development Commands
- `make dev` — start dev environment (requires Docker)
- `make test` — run all tests
- `make lint` — run golangci-lint + eslint
- `make generate` — regenerate sqlc and protobuf files
## Coding Conventions
- Go: all errors must be handled, no bare `panic`, functions over 80 lines need splitting
- TypeScript: no `any`, functional components, state via Zustand
- Commit messages follow Conventional Commits
- All public APIs require integration test coverage
## Important Constraints
- Database migration files are immutable — only add new ones, never edit existing
- Changes to `internal/auth` require a security review
- Never modify anything under `vendor/`

Subdirectory CLAUDE.md

For complex projects, add scoped instructions closer to specific areas of the codebase:

# web/src/components/CLAUDE.md
## Component Conventions
- All components typed as `React.FC<Props>`
- Props interface must match the component name, e.g. `ButtonProps`
- Use CSS Modules; filename must match component name
- Never call APIs directly inside components — use hooks

⚠️ What Should NOT Be in CLAUDE.md

  • Secrets, tokens, or passwords — even for development environments
  • Large code samples — they consume context; the AI reads source files more accurately anyway
  • Frequently changing information — like current version numbers; stale data misleads the AI

4. settings.json: Behavior and Permission Control

settings.json defines what Claude CLI can and cannot do. This is the core of your security boundary.

The Permission Model

Claude CLI uses an allowlist model: everything requires confirmation by default, and explicitly allowed operations run automatically.

{
  "permissions": {
    "allow": [
      "Bash(npm run *)",
      "Bash(make *)",
      "Bash(git status)",
      "Bash(git diff *)",
      "Bash(git log *)",
      "Bash(git add *)",
      "Bash(git commit *)",
      "Read(**)",
      "Edit(**)",
      "Write(src/**)"
    ],
    "deny": [
      "Bash(git push --force*)",
      "Bash(rm -rf *)",
      "Write(.env*)"
    ]
  }
}

Tool Permission Syntax

ToolName(argument-match-pattern)
  • Bash(npm *) — allow all npm commands
  • Bash(npm run test) — allow only this exact command
  • Read(**) — allow reading any file (** matches multiple path segments)
  • Write(src/**) — allow writing only inside the src/ directory

Model and Behavior Configuration

{
  "model": "claude-opus-4-7",
  "env": {
    "NODE_ENV": "development",
    "LOG_LEVEL": "debug"
  },
  "hooks": {
    "PreToolUse": [...],
    "PostToolUse": [...],
    "Stop": [...]
  }
}

Team Config vs Personal Config

FileCommit to gitPurpose.claude/settings.jsonYesShared team permission baseline.claude/settings.local.jsonNo (gitignore)Personal local overrides~/.claude/settings.json—Cross-project personal defaults

5. Hooks: The Key to Automated Workflows

Hooks are shell commands configured in settings.json that run automatically when specific events fire. They are the primary mechanism for automating your AI workflow.

Available Hook Events

EventFires WhenCommon UsesPreToolUseBefore the AI calls a toolBlock dangerous operations, audit loggingPostToolUseAfter the AI calls a toolValidate results, trigger follow-up actionsNotificationWhen the AI needs to alert the userDesktop notificationsStopWhen the AI finishes a response turnRun tests, generate summaries

Practical Hook Examples

1. Auto-format after AI edits a file

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "if [[ \"$CLAUDE_TOOL_INPUT\" == *.go ]]; then gofmt -w \"$CLAUDE_TOOL_INPUT\"; fi"
          }
        ]
      }
    ]
  }
}

2. Block writes to production config

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Write|Edit",
        "hooks": [
          {
            "type": "command",
            "command": "echo \"$CLAUDE_TOOL_INPUT\" | grep -q 'config/production' && echo 'Direct modification of production config is not allowed' && exit 2 || exit 0"
          }
        ]
      }
    ]
  }
}

3. Desktop notification when AI finishes

{
  "hooks": {
    "Stop": [
      {
        "type": "command",
        "command": "notify-send 'Claude' 'Task complete'"
      }
    ]
  }
}

Hook Exit Code Convention

Exit CodeMeaning0Proceed normally1Log a warning, proceed anyway2Block the operation; AI receives an error message

6. MCP Servers: Extending AI’s Reach

MCP (Model Context Protocol) is the standard protocol for connecting AI to external systems. Through MCP Servers, the AI can query databases, call internal APIs, and interact with third-party services.

Configuring MCP Servers

Declare them in settings.json:

{
  "mcpServers": {
    "postgres": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-postgres"],
      "env": {
        "POSTGRES_URL": "postgresql://localhost/mydb"
      }
    },
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_TOKEN": "${GITHUB_TOKEN}"
      }
    },
    "internal-api": {
      "command": "python",
      "args": [".claude/mcp/internal-api-server.py"],
      "env": {
        "API_BASE_URL": "http://localhost:8080"
      }
    }
  }
}

Security Principles

  • Reference sensitive tokens via environment variables (${VAR_NAME}), never hardcode them
  • Internal MCP Servers should default to read-only; expose write operations as explicit tools with permission controls
  • Document each MCP Server’s purpose in CLAUDE.md so the AI uses them intentionally

7. Skills: Encapsulating Reusable AI Workflows

Skills are structured instruction sets stored in .md files and triggered via /skill-name commands. They are the primary tool for standardizing AI workflows across a team.

Skill File Structure

# .claude/skills/create-feature.md
---
name: create-feature
description: Scaffold a standard feature module (handler + service + repo + tests)
triggers:
  - /create-feature
---
## Usage
/create-feature <feature-name> [--module <module-name>]
## Steps
1. Under `internal/<module>/`, create these files:
   - `handler.go` — HTTP layer
   - `service.go` — business logic layer
   - `repo.go` — data access layer
   - `*_test.go` — unit tests for each
2. Register routes in the `RegisterRoutes` function in `handler.go`
3. Add dependency injection bindings in `internal/wire.go`
4. Create a database migration file if schema changes are needed
## Output Checklist
List all created files and modified files when done.

Project-Level vs Global Skills

.claude/skills/         # Project-specific; committed to git; team-shared
~/.claude/skills/       # Personal global; reusable across all projects

What’s Worth Turning Into a Skill

  • Code generation with a fixed output structure (CRUD modules, API endpoints)
  • Multi-step coordinated tasks (DB migration + code generation + tests)
  • Tasks where the team has explicit conventions (PR descriptions, review checklists)
  • Recurring analysis tasks (dependency security audits, benchmark comparisons)

8. Agent SDK: Building Custom AI Agents

When the interactive Claude CLI model isn’t enough, the Agent SDK lets you build purpose-built agents — for example, automated code review in CI/CD pipelines, or automated triage of monitoring alerts.

Core Concept: The Agent Loop

import anthropic
client = anthropic.Anthropic()
tools = [
    {
        "name": "read_file",
        "description": "Read the contents of a project file",
        "input_schema": {
            "type": "object",
            "properties": {
                "path": {"type": "string", "description": "File path"}
            },
            "required": ["path"]
        }
    }
]
def run_agent(task: str) -> str:
    messages = [{"role": "user", "content": task}]
    while True:
        response = client.messages.create(
            model="claude-opus-4-7",
            max_tokens=4096,
            tools=tools,
            messages=messages
        )
        if response.stop_reason == "end_turn":
            return extract_text(response)
        if response.stop_reason == "tool_use":
            tool_results = execute_tools(response.content)
            messages.append({"role": "assistant", "content": response.content})
            messages.append({"role": "user", "content": tool_results})

CI/CD Integration Example

# .github/workflows/ai-review.yml
name: AI Code Review
on:
  pull_request:
    types: [opened, synchronize]
jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Run AI Review
        env:
          ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: python .claude/agents/pr-reviewer.py ${{ github.event.pull_request.number }}

Agent Design Principles

  1. Single responsibility: each agent does one thing; split complex tasks across multiple collaborating agents
  2. Idempotent operations: retrying a failed agent run should not produce side effects
  3. Audit logging: record every tool call the agent makes for debugging
  4. Hard limits: set max_tokens and loop iteration caps to prevent runaway agents

9. Development Best Practices

9.1 Front-Load Context Into Configuration

Stop repeating yourself. Put recurring context into CLAUDE.md once.

## Project-Specific Vocabulary
- "DTO" = Data Transfer Object, lives in `internal/dto/`
- "UC" = Use Case, lives in `internal/usecase/`
- "current PR" = changes in `git diff main...HEAD`

Also, use /clear to reset the conversation context when switching to an unrelated task. Long sessions accumulate stale context that degrades output quality.

9.2 Principle of Least Privilege

Resist the temptation to give the AI broad permissions for convenience:

// Bad: dangerously broad
{ "allow": ["Bash(*)", "Write(**)"] }
// Good: precise, intentional grants
{
  "allow": [
    "Bash(npm run *)",
    "Bash(git add src/**)",
    "Write(src/**)",
    "Write(test/**)"
  ],
  "deny": [
    "Bash(git push *)",
    "Write(.env*)",
    "Write(config/production*)"
  ]
}

9.3 Progressive Automation

Start automating low-risk operations and expand trust incrementally:

Phase 1: Read-only automation (file reads, code search, running tests)
Phase 2: Local write automation (file edits, local git operations)
Phase 3: Guarded remote operations (create PR, with confirmation required)
Phase 4: Fully automated CI/CD flows (within clearly scoped task boundaries)

9.4 Write Constrained Prompts

Structure matters more than length. Give the AI constraints, not freedom:

// Vague — produces mediocre results
"Optimize this code"
// Constrained — produces targeted results
"Refactor the validateToken function in src/auth/middleware.go:

* Goal: extract the duplicated error handling logic
* Constraint: do not change the function signature or touch test files
* Verify: run `make test` after refactoring to confirm tests pass"

9.5 Use AI for Structured Code Review

Give the AI an explicit review mandate instead of asking it to “look at the code”:

Review internal/payment/calculator.go for:

1. security — SQL injection, auth bypass, input validation
2. correctness — boundary conditions, concurrency safety, error handling
3. performance — N+1 queries, unnecessary allocations
4. conventions — compliance with project rules in CLAUDE.md
Flag each issue with a severity: critical / warning / suggestion

9.6 Team Collaboration Conventions

## What to Commit
Always commit:

* CLAUDE.md (all levels)
* .claude/settings.json
* .claude/skills/\*.md
  Never commit:
* .claude/settings.local.json
* Any file containing tokens or credentials
* \~/.claude/ (personal global config)

## PR Template Additions

* [ ] Did conventions change? Update CLAUDE.md.
* [ ] Is this task repetitive? Consider creating a Skill.
* [ ] Do new operations need permission entries in settings.json?

10. Common Anti-Patterns

Using AI as a Search Engine

// Anti-pattern: asking for information with a deterministic answer
"How do goroutines work?"
// Better: use AI for project-specific reasoning
"In internal/worker/processor.go, what data race risks should I
watch for when converting the current serial processing to concurrent?"

Blindly Trusting AI Output

AI can produce incorrect code with high confidence. Code generated by AI for critical paths — authentication, payments, data migrations — must be human-reviewed and test-covered before merging. Treat AI output as a draft, not a finished product.

Overloading a Single Session

Doing too much in one session leads to context pollution — early incorrect assumptions contaminate later outputs. Start a new session for each independent task.

Letting AI Guess Intent

// Anti-pattern: open-ended instruction
"Add some tests to this module"
// Better: specify exactly what you expect
"Write unit tests for the Calculate function in internal/payment/calculator.go.
Cover: happy path, zero amount, negative amount, and unsupported currency."

Ignoring the AI’s Uncertainty Signals

When the AI says “I’m not sure” or “you may want to verify this” — don’t skip past it. These signals usually mean it’s working at the boundary of its knowledge or lacks context. Human intervention at these moments is far more efficient than letting the AI guess.

Comments

Loading comments…