Tìm hiểu folder .claude: cấu trúc và cấu hình Claude Code — hoatq.dev

cat blog/.md

Tìm hiểu folder .claude: cấu trúc và cấu hình Claude Code

date: tags: ai, claude-code, developer-tools, configuration, workflow

Lần đầu mở một project có dùng Claude Code, mình nhìn vào folder .claude/ và hoang mang: có agents/, skills/, hooks/, hai file settings.jsonsettings.local.json, một worktrees/ rỗng. Không có tài liệu nào ở chỗ dễ thấy giải thích cái nào nên commit, cái nào nên cho vào .gitignore, cái nào dùng chung, cái nào cá nhân. Sau vài lần tự mày mò và gây phiền cho team (commit nhầm cấu hình cá nhân, ghi đè cấu hình chung của team), mình ngồi xuống đọc kỹ và tự viết ghi chú. Bài này là ghi chú đó, chỉnh lại cho ai cũng dùng được.

Hai vị trí: global và project

Claude Code đọc cấu hình từ hai cấp:

  • Global: ~/.claude/ — thuộc về user, không commit, chứa cấu hình cá nhân và runtime state.
  • Project: {repo}/.claude/ — thuộc về project, commit được, dùng chung với team.

Khi có xung đột, cấu hình ở project sẽ override cấu hình global. Cách hoạt động giống Git config (~/.gitconfig vs {repo}/.git/config), hoặc ESLint (~/.eslintrc vs file trong project).

Nguyên tắc đơn giản mình tự đặt: cái gì team cần cùng tuân theo thì nằm ở project, cái gì của riêng mình thì nằm ở global hoặc file .local.

Folder ~/.claude/ — global

Folder này Claude Code tự tạo ra khi bạn cài CLI. ls qua sẽ thấy nhiều thứ:

~/.claude/
├── settings.json        # config cá nhân (model default, theme...)
├── projects/            # lịch sử conversation theo từng project
├── sessions/            # session đang mở
├── todos/               # todo list của mỗi session
├── plans/               # plan do agent tạo ra
├── skills/              # skill cá nhân (dùng ở mọi project)
├── plugins/             # plugin cài từ marketplace
├── file-history/        # snapshot file Claude đã edit
├── shell-snapshots/     # state shell khi agent chạy Bash
├── telemetry/           # data usage
├── backups/             # backup định kỳ
└── history.jsonl        # history lệnh đã gõ

Đa phần là runtime state — đừng đụng vào. Thứ bạn thực sự nên quan tâm chỉ có ba:

settings.json — cấu hình cá nhân. Ví dụ theme, model mặc định, danh sách công cụ tin cậy riêng (ví dụ bạn muốn cho phép Bash(docker compose:*) ở mọi project mà không cần khai lại từng project một).

skills/ — skill cá nhân dùng được ở mọi project. Mình để đây: /commit, /review-pr, /explain-diff. Cấu trúc đã nói kỹ trong bài cấu trúc SKILL.md.

projects/ — mỗi project bạn từng mở có một folder con chứa lịch sử trò chuyện. Đường dẫn được mã hóa: /Users/kyro/work/my-app-Users-kyro-work-my-app. Biết quy tắc này có ích khi bạn muốn mở lại cuộc trò chuyện cũ.

Phần còn lại (file-history/, shell-snapshots/, telemetry/) là dữ liệu phụ trợ. Không commit, không sửa tay. Muốn dọn bớt dung lượng? Xóa backups/ cũ là đủ.

Folder {project}/.claude/ — project

Đây mới là nơi đáng đầu tư. Cấu trúc đầy đủ mình đang dùng (sau vài lần tổ chức lại):

.claude/
├── README.md              # giải thích tổ chức folder cho team mới (commit)
├── settings.json          # config team dùng chung — permissions + hooks + statusLine (commit)
├── settings.local.json    # override cá nhân (gitignore)
├── statusline.sh          # script render statusline ở đáy terminal (commit)
├── rules/                 # quy ước cross-cutting — single source of truth (commit)
├── skills/                # capability nhỏ, auto-trigger qua description (commit)
├── commands/              # slash command user gõ thẳng — /commit, /pr... (commit)
├── agents/                # subagent persona/utility (commit)
├── agent-memory/          # bộ nhớ persistent của agent — tự build qua sessions (commit)
├── hooks/                 # hook script (commit)
└── worktrees/             # worktree metadata (gitignore)

Hai folder mới nhất mình thêm vào — rules/agent-memory/ — là phần quan trọng nhất sau vài tháng nhưng không có trong setup mặc định.

settings.json. Config team dùng chung. Ví dụ từ project mình:

{
  "permissions": {
    "allow": [
      "Bash(docker compose:*)",
      "Bash(npx nuxi:*)",
      "mcp__playwright__browser_navigate"
    ]
  },
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "bash .claude/hooks/check-claude-md.sh"
          }
        ]
      }
    ]
  },
  "enabledPlugins": {
    "github@claude-plugins-official": true
  }
}

Ba thứ chính:

  • permissions.allow: cấp phép trước một số công cụ cho project này. Ai trong team cũng dùng Docker, nên cho phép sẵn Bash(docker compose:*) để đỡ phải xác nhận mỗi lần.
  • hooks: script chạy tự động theo sự kiện. Ở đây mình có PostToolUse — sau mỗi lần agent Edit/Write file, hệ thống sẽ chạy check-claude-md.sh để nhắc cập nhật file CLAUDE.md tương ứng.
  • enabledPlugins: plugin bật cho project này.

settings.local.json. Cấu hình cá nhân override lên cấu hình chung, bắt buộc cho vào .gitignore. Đây là nơi bạn thêm quyền tạm thời, cho phép công cụ riêng, đặt khác đồng đội mà không phiền ai. Định dạng giống settings.json, các giá trị trùng sẽ override.

.gitignore tối thiểu:

.claude/settings.local.json
.claude/worktrees/
.claude/.DS_Store

rules/ (lớp single source of truth). Đây là folder mình thêm vào sau khi nhận ra skills/agents đang lặp nội dung của nhau. rules/ chứa quy ước cross-cutting: branch strategy, commit convention, PR template, security baseline, coding guide, language conventions. Skills và agents reference file trong rules/ thay vì copy-paste. Đổi rule một chỗ, mọi nơi tự cập nhật. Ví dụ rules/contributing.md, rules/coding-guide.md, rules/security-baseline.md.

skills/ (lớp capability). Procedure atomic — auto-trigger khi description match với task. Project mình có: requirements-analysis, task-planner, backend-coder, unit-testing, security-audit, code-review. Mỗi skill ~150-280 dòng, làm một việc cụ thể. Cấu trúc đã nói kỹ trong bài SKILL.md.

commands/ (lớp user entry point). Slash command user gõ thẳng — /commit, /pr, /branch, /dev-flow. Khác skill ở chỗ: command luôn user-triggered (không auto-trigger), thường là thin shim spawn agent hoặc chứa procedure ngắn. Mình tách commands khỏi skills sau khi nhận ra hai khái niệm bị trộn lẫn — slash command đơn giản dạng /commit thuộc về commands/, capability dạng unit-testing (Claude tự pick khi viết test) thuộc về skills/.

agents/ (lớp role/persona). Subagent có context riêng, tools/permissions thu hẹp. Project mình tách hai loại:

  • Personas (workflow dài): ba (Business Analyst), tl (Tech Lead, model Opus), dev, qa, cr (Code Reviewer, model Opus).
  • Utility (context protection): explore (model Haiku) — quét codebase rộng và trả về tóm tắt, tránh ngập context của persona.

Cách thiết kế AGENT.md, chọn model, và spawn subagent từ subagent qua Task tool — mình mổ xẻ trong bài subagent Claude Code.

agent-memory/ (lớp persistent memory). Đây là feature mình suýt bỏ qua nhưng giá trị nhất. Mỗi agent khai báo memory: project trong YAML frontmatter → Claude Code tự load 200 dòng / 25KB đầu của .claude/agent-memory/<agent-name>/MEMORY.md vào system prompt mỗi lần spawn agent. Agent có Read/Write/Edit để tự curate file này.

Ý nghĩa: agent không phải re-scan codebase mỗi lần. explore/MEMORY.md mình seed sẵn architecture summary của các service trong monorepo → first run trả lời ngay từ memory thay vì quét hàng chục file. dev/MEMORY.md chứa các gotchas đặc thù project (vd quy ước về soft-delete, datetime timezone, exception hierarchy). Sau vài session, agent tự thêm pattern mới.

hooks/. Shell script chạy theo sự kiện. Mình có 4 hook đang chạy: block-secrets.sh (chặn đọc .env/secrets), format-on-edit.sh (auto Prettier/Ruff sau Edit/Write), inject-context.sh (đưa branch + uncommitted state vào đầu mỗi prompt), stop-summary.sh (tóm tắt trạng thái khi Claude xong turn). Các sự kiện chính, định dạng JSON đầu vào, và sample script mình đã đi kỹ ở bài hooks trong Claude Code.

statusline.sh. Script render dòng status cố định ở đáy terminal — Claude Code refresh mỗi vài giây. Ví dụ output: 📍 fe:release±2 | be:#1234±3 | mig:feature/xyz±2 | core:main±44. Mình hiển thị git state per service (multi-repo project), tô màu branch theo loại (red cho main, blue cho release, yellow cho dirty). Wire trong settings.json qua "statusLine": { "type": "command", "command": "..." }.

worktrees/. Metadata của Git worktree do Claude Code tạo khi dùng chế độ isolation: worktree. Runtime state, cho vào .gitignore.

File CLAUDE.md — nơi ghi kiến thức về codebase

Không nằm trong folder .claude/ nhưng thuộc cùng hệ sinh thái này. CLAUDE.md là file Markdown đặt ở thư mục gốc của repo (và có thể đặt thêm ở subfolder), tự động được nạp vào ngữ cảnh mỗi khi Claude Code làm việc với file trong thư mục đó.

Nội dung nên có:

  • Công nghệ và quy ước đang dùng (Python 3.12, kiến trúc layered của FastAPI…)
  • Cấu trúc thư mục và trách nhiệm từng module
  • Những pattern quan trọng (đặt tên, xử lý lỗi, ghi log)
  • Lệnh dev thường dùng (docker compose up, chạy test, migrate)
  • Những thứ đã thống nhất nhưng không tự suy ra được từ code (chế độ của PgBouncer, vị trí định nghĩa event schema…)

Monorepo thì mỗi service/app có CLAUDE.md riêng, cộng thêm CLAUDE.md chung ở thư mục gốc. Claude Code tự merge theo scope — bạn đang làm file trong backend/identity/ thì cả CLAUDE.md gốc lẫn backend/identity/CLAUDE.md đều được nạp vào.

Mẹo cá nhân: viết CLAUDE.md như viết tài liệu hướng dẫn cho thành viên mới. Viết xong tự đọc lại, hỏi “nếu quên sạch project này thì đọc doc này có đủ để làm được task đầu tiên không?”.

Cái gì commit, cái gì không

Checklist mình dùng:

Commit:

  • .claude/settings.json
  • .claude/README.md
  • .claude/rules/, .claude/skills/, .claude/commands/, .claude/agents/, .claude/hooks/
  • .claude/agent-memory/ — bộ nhớ persistent, share qua git để team cùng lợi
  • .claude/statusline.sh
  • Mọi CLAUDE.md ở root và subfolder

Gitignore:

  • .claude/settings.local.json
  • .claude/agent-memory-local/ — bộ nhớ scope local chỉ riêng máy bạn
  • .claude/worktrees/
  • .claude/.DS_Store
  • Không bao giờ commit cái gì từ ~/.claude/

Bẫy dễ dính:

  • Commit settings.local.json chứa quyền quá rộng → đồng đội bỗng dưng được cấp sẵn những quyền mà bạn tự duyệt cho riêng mình.
  • Viết hook gọi công cụ chỉ cài trên máy bạn (brew install xxx) → máy đồng đội chạy hook lỗi.
  • Nhét secret vào CLAUDE.md — nhớ file này được Claude Code đọc mỗi session, và cũng được commit lên repo. Secret lộ như thường.

Tổ chức cho team — 4 lớp khái niệm rõ ràng

Sau vài tháng, mình tổ chức theo 4 lớp khái niệm — mỗi lớp có vai trò không giao nhau:

LớpVai tròKhi nào loadĐối tượng
rules/Single source of truth — quy ước, conventionsReference từ skills/agents/commandsToàn project
skills/Atomic capability — HOW làm 1 procedure cụ thể (~150-280 dòng)Auto-load khi description matchMain agent + persona có Skill tool
agents/Role/persona — WHO làm việc, isolated context, long workflow (~80 dòng)Spawn qua Task toolSubagent độc lập
commands/User entry point — slash command bạn gõLoad vào main context khi gõ /<name>User-triggered

Nguyên tắc tách lớp:

  • Rules không copy nội dung vào skills/agents — link bằng path
  • Skills không chứa persona — chỉ procedure
  • Agents không chứa procedure dài — link skills + giữ persona/gates/completion criteria
  • Commands không chứa persona — thin shim spawn agent (cho persona) hoặc procedure ngắn (cho action)

Bố cục hợp lý mình đang dùng:

  1. CLAUDE.md ở thư mục gốc mô tả tổng quan, link sang tài liệu chi tiết.
  2. Mỗi service/app có CLAUDE.md riêng kèm architecture index (file/module quan trọng, pattern).
  3. .claude/README.md giải thích tổ chức folder cho người mới.
  4. .claude/rules/ chứa quy ước cross-cutting: branch, commit, PR, security baseline, coding guide.
  5. .claude/settings.json quy định permissions, hooks, statusLine cho cả team.
  6. .claude/skills/ chứa capability: requirements-analysis, task-planner, backend-coder, unit-testing
  7. .claude/commands/ chứa slash command: /commit, /pr, /branch, /dev-flow.
  8. .claude/agents/ chứa persona (ba, tl, dev, qa, cr) + utility (explore).
  9. .claude/agent-memory/<name>/MEMORY.md — bộ nhớ persistent, seed sẵn cho explore/ba/tl/dev, để qa/cr auto-build.
  10. .claude/hooks/ — 4 hook (block-secrets, format-on-edit, inject-context, stop-summary) wire trong settings.json.
  11. .claude/statusline.sh — render git state per service ở đáy terminal.

Setup này ngốn khoảng 1-2 ngày ban đầu, nhiều hơn lần đầu mình viết bài này. Lý do tăng: mình tách thêm rules/agent-memory/. Đổi lại, mỗi dev mới clone về là agent đã “hiểu” project — không phải giải thích lại từ đầu mỗi session, không phải copy-paste quy ước từ Notion. Quan trọng hơn: agent không phải re-scan codebase mỗi session vì memory đã có sẵn architecture cache. Thời gian onboarding thành viên mới từ 2 tuần xuống còn 3-4 ngày. Đó vẫn là khoản đầu tư có lợi nhất mình thấy từ việc dùng công cụ AI năm nay.

// reactions


cat comments.log


hoatq@dev : ~/blog $