Resource Guide

The Claude Code Folder Setup

Every company repo I open now is set up like this: three root files, and this .claude folder. One config, whole team, same Claude.

The Structure

Three root files. One .claude folder.

your-project/
CLAUDE.md team instructions
CLAUDE.local.md personal notes
.mcp.json MCP connections
.claude/
settings.json permissions
settings.local.json private
rules/ coding-style.md, testing.md ...
commands/ deploy.md, code-review.md ...
skills/ investigate-errors/, code-review/ ...
hooks/ run-tests.sh, check-env.sh ...
Committed Gitignored

The Part People Mix Up

Commands vs Skills

commands/

You Call Them

Saved prompts you trigger with a slash command. You type /deploy staging and Claude runs that prompt.

  • Filename = command name
  • $ARGUMENTS captures your input
  • Claude never runs these on its own
skills/

They Call Themselves

Each skill has a description. Claude reads it, decides when to use it. Sees an error? Picks up investigate-errors on its own.

  • Own folder with SKILL.md + supporting files
  • YAML frontmatter: description, when_to_use
  • Claude activates them autonomously
01 Root Level · Committed to Git

CLAUDE.md

The main file your whole team shares

This is the first thing Claude reads when it opens your repo. Architecture, conventions, build commands, gotchas. Everything Claude needs to act on your codebase. Committed to git so the entire team shares one source of truth.

  • Project architecture and structure overview
  • Build, test, and deploy commands
  • Code conventions and style rules
  • Environment variable requirements
  • What Claude should and should NOT do
CLAUDE.md
# PaperCurator: RAG-Powered Research Assistant

## Quick Start
```bash
pip install -r requirements.txt
python -m uvicorn app.main:app --reload  # :8000
pytest                                    # run tests
```

## Stack
- **Runtime:** Python 3.11+
- **Framework:** FastAPI with Pydantic validation
- **Database:** PostgreSQL 16 via SQLAlchemy
- **Vector Store:** OpenSearch (BM25 + dense)
- **LLM:** Ollama (local) / OpenAI (cloud)

## Code Conventions
- 4-space indentation, type hints everywhere
- All route handlers delegate to a service
- Use Pydantic models for all request validation

## What Claude Should NOT Do
- Never modify applied Alembic migrations
- Never hardcode secrets or connection strings
- Never use `Any` type, use proper generics
02 Root Level · Gitignored

CLAUDE.local.md

Your personal notes, only you see this

Same format as CLAUDE.md, but gitignored. Local paths, personal preferences, machine-specific config, notes you don't want to share with the team.

  • Local database ports and Docker commands
  • Personal testing preferences
  • Current focus areas and in-progress work
  • Machine-specific setup quirks
CLAUDE.local.md
## My Local Setup
- PostgreSQL runs on port 5433
  (not default 5432, another project uses that)
- Redis on Docker: `docker start rag-redis`
- Ollama running locally on :11434

## My Preferences
- I use pytest with verbose output: `pytest -v`
- Don't auto-format on save, I run black manually

## Current Focus
- Working on the chunking pipeline (issue #47)
- The `services/embedder.py` is half-done
03 Root Level · Committed to Git

.mcp.json

MCP connections: GitHub, databases, monitoring

MCP (Model Context Protocol) lets Claude talk directly to external services. Define your connections here: GitHub for PRs, a database for queries, Datadog for monitoring. The whole team shares the same integrations.

  • stdio: runs a local process (npx, python)
  • http: connects to a remote HTTP server
  • Use ${VAR} for environment variable references
  • Use ${VAR:-default} for fallback values
.mcp.json
{
  "mcpServers": {
    "github": {
      "type": "http",
      "url": "https://api.githubcopilot.com/mcp/",
      "headers": {
        "Authorization": "Bearer ${GITHUB_TOKEN}"
      }
    },
    "postgres": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@bytebase/dbhub", "--transport", "stdio"],
      "env": {
        "DB_URL": "${DATABASE_URL}"
      }
    },
    "datadog": {
      "type": "http",
      "url": "https://mcp.datadoghq.com/sse",
      "headers": {
        "DD-API-KEY": "${DD_API_KEY}",
        "DD-APP-KEY": "${DD_APP_KEY}"
      }
    }
  }
}
04 .claude/ · Committed to Git

settings.json

Permissions: what Claude can and can't do

Controls what Claude is allowed to do without asking. 'allow' means Claude runs it silently. 'deny' means Claude is blocked, period. Anything not listed, Claude asks you each time. Team shares the same guardrails.

  • allow: Claude can do this silently
  • deny: Claude is blocked from this, period
  • Pattern syntax: ToolName(glob pattern)
  • settings.local.json for your personal overrides (gitignored)
settings.json
{
  "permissions": {
    "allow": [
      "Bash(pytest *)",
      "Bash(ruff check *)",
      "Bash(pip install *)",
      "Bash(git status)",
      "Bash(git diff *)",
      "Bash(git log *)",
      "Read(.claude/**)"
    ],
    "deny": [
      "Write(.env)",
      "Write(.env.*)",
      "Bash(rm -rf *)",
      "Bash(git push --force *)"
    ]
  }
}
05 .claude/ · Committed to Git

rules/

When CLAUDE.md gets too big, split it

Each rule file is a focused set of instructions on one topic. Rules without a paths: frontmatter load every session. Rules with paths: only load when Claude opens matching files, so testing rules don't clutter sessions about UI.

  • coding-style.md: loads every session (no path filter)
  • testing.md: loads only when editing test files
  • api-conventions.md: loads only for route files
  • Path-scoped via YAML frontmatter at the top
rules/
# rules/testing.md (only loads for test files)

---
paths:
  - "tests/**/*.ts"
  - "src/**/*.test.ts"
  - "src/**/*.spec.ts"
---

# Testing Conventions

- Use pytest with fixtures and parametrize
- Group tests by endpoint in test classes
- Each test should be independent
- Always test: happy path, one edge case, one error
- Mock external services, use real test database
- Never use `Any` type in tests
06 .claude/ · Committed to Git

commands/

Saved prompts you trigger yourself

Commands are prompts saved as .md files. The filename becomes the slash command: deploy.md becomes /deploy. You type /deploy staging, Claude runs that prompt with $ARGUMENTS = "staging". You call them. That's the key point.

  • deploy.md → you type /deploy
  • code-review.md → you type /code-review
  • $ARGUMENTS captures what you type after the command
  • You call them. Claude doesn't pick these up on its own
commands/
# commands/deploy.md -> /deploy staging

Run the deployment checklist for **$ARGUMENTS**:

1. Run `pytest` and confirm all pass
2. Run `ruff check .` and confirm no errors
3. Check for uncommitted changes
4. Verify the current branch is `main`
5. Show the last 5 commits

Do NOT run the deploy command.
Just show it and wait for my confirmation.
07 .claude/ · Committed to Git

skills/

Prompts that call themselves

This is where people get confused. Skills are NOT commands. Each skill has a description, like "investigates error traces." Claude reads those descriptions on its own. Sees an error, picks up the investigate-errors skill, runs it. You didn't type anything. Commands, you call them. Skills call themselves.

  • Each skill gets its own folder: skills/investigate-errors/SKILL.md
  • YAML frontmatter with name, description, when_to_use
  • allowed-tools grants permissions while the skill runs
  • Can include supporting files: templates, examples, patterns
  • user-invocable: false hides from menu (Claude-only)
skills/
# skills/investigate-errors/SKILL.md

---
name: investigate-errors
description: "Investigates error traces, stack
  traces, and runtime failures. Reads logs,
  identifies root cause, suggests targeted fixes."
when_to_use: "Activate when the user shares an
  error message, stack trace, or test failure."
allowed-tools: Bash(pytest *) Read(**)
---

# Error Investigation

When you encounter an error trace:

## Step 1: Understand the error
- Read the full stack trace
- Identify exact file and line number
- Note the error type

## Step 2: Trace the cause
- Read the file where the error occurs
- Follow the call chain
- Check recent changes with git log

## Step 3: Suggest the fix
- Smallest change that fixes root cause
- Explain WHY it happened, not just HOW
08 .claude/ · Defined in settings.json

hooks/

Scripts that run on events

Hooks are shell scripts triggered by Claude Code events. Run the test suite every time code changes. Validate your .env on session start. Block a dangerous command before it executes. Defined in settings.json, scripts live in hooks/.

  • SessionStart: when Claude starts a new session
  • PreToolUse: before Claude runs a tool (can block it)
  • PostToolUse: after a tool completes
  • Exit 0 = pass, Exit 1 = block, Exit 2 = warn
hooks/
# In settings.json:
"hooks": {
  "PostToolUse": [{
    "matcher": "Edit|Write",
    "hooks": [{
      "type": "command",
      "command": ".claude/hooks/run-tests.sh",
      "statusMessage": "Running tests..."
    }]
  }]
}

# hooks/run-tests.sh:
#!/bin/bash
cd "$CLAUDE_PROJECT_DIR" || exit 1
pytest --quiet 2>&1
if [ $? -ne 0 ]; then
  echo "FAIL: Tests broken." >&2
  exit 1  # blocks the action
fi
exit 0    # all clear

Quick Reference

What Goes Where

File Location Committed? Purpose
CLAUDE.md Root Yes Team instructions for Claude
CLAUDE.local.md Root No Your personal notes
.mcp.json Root Yes MCP server connections
settings.json .claude/ Yes Permissions & hooks config
settings.local.json .claude/ No Your private permissions
rules/ .claude/ Yes Topic-specific instructions
commands/ .claude/ Yes Slash commands you trigger
skills/ .claude/ Yes AI-triggered prompts
hooks/ .claude/ Yes Event-triggered scripts

Don't Forget

Add These to Your .gitignore

# Personal Claude files
CLAUDE.local.md
.claude/settings.local.json

Your personal notes and local permissions stay on your machine.

Learn More With Us

Our Courses

Real-world AI/ML education. No toy demos. Production code, real architecture, systems you can actually ship.

LIVE
Featured Course

Agentic RAG System

Build a Production-Ready RAG System from Scratch

12 hours of hands-on content. Build an arxiv paper curator with hybrid retrieval, LLM generation via Ollama, agentic workflows, full observability, and streaming APIs. 23+ tools, real architecture.

  • Vector databases & embedding models
  • Hybrid search with BM25 + RRF
  • Monitoring, caching & evaluation
  • Agentic RAG with LangGraph
$99 Self-paced · 12 hours · 7 weeks
Explore the Course
Coming Soon

AI Agents: Production-Grade Systems

Planning, reasoning, multi-step execution, tool use, memory systems, and multi-agent coordination.

Coming Soon

NLP: Zero to Fine-tuning

From TF-IDF to fine-tuning transformers. Learn when traditional NLP beats LLMs and save 100x on cost.

Coming Soon

Recommendation Systems

Multi-stage RecSys: candidate generation, ranking, re-ranking, serving millions of users.

Coming Soon

MLOps

Feature stores, model registries, CI/CD for ML, monitoring, observability, and deployment at scale.