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.
The Part People Mix Up
Commands vs Skills
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
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
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
# 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 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
## 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 .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
{
"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}"
}
}
}
} 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)
{
"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 *)"
]
}
} 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/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 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/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. 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/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 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
# 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.
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
AI Agents: Production-Grade Systems
Planning, reasoning, multi-step execution, tool use, memory systems, and multi-agent coordination.
NLP: Zero to Fine-tuning
From TF-IDF to fine-tuning transformers. Learn when traditional NLP beats LLMs and save 100x on cost.
Recommendation Systems
Multi-stage RecSys: candidate generation, ranking, re-ranking, serving millions of users.
MLOps
Feature stores, model registries, CI/CD for ML, monitoring, observability, and deployment at scale.