> ## Documentation Index
> Fetch the complete documentation index at: https://felimet-hub.jmcores.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 02-1 設定的層級模型

> 建立「作用範圍 × 設定種類」兩軸座標系，讓你面對任何 AI 編程工具的設定檔都能立刻判斷它的優先序、合併語意與版控策略。

export const ScopeFilePicker = ({lang = "zh"}) => {
  const t = {
    zh: {
      kindLabel: "設定種類",
      scopeLabel: "作用範圍",
      kinds: ["個人化", "記憶", "規則 / 指令", "隱私", "權限", "自動化"],
      scopes: ["使用者", "專案", "本地"],
      resultTitle: "放哪裡？",
      vcsLabel: "版控",
      commit: "提交（團隊共享）",
      gitignore: "gitignore（個人）",
      hint: "選擇種類與範圍，查看應寫入的檔案",
      examples: {
        "個人化-使用者": {
          file: "~/.claude/CLAUDE.md",
          vcs: "gitignore",
          note: "跨所有專案的語言偏好、語氣、輸出格式。只影響你自己，不污染團隊。"
        },
        "個人化-專案": {
          file: "./CLAUDE.md",
          vcs: "commit",
          note: "通常不建議把純個人偏好放進專案層，除非是全隊共識的格式規範。"
        },
        "個人化-本地": {
          file: "./CLAUDE.local.md",
          vcs: "gitignore",
          note: "個人沙箱 URL、本地路徑、測試資料偏好，只有你看得到。"
        },
        "記憶-使用者": {
          file: "~/.claude/CLAUDE.md",
          vcs: "gitignore",
          note: "跨 session 持久化的個人事實與偏好。"
        },
        "記憶-專案": {
          file: "./CLAUDE.md 或 .claude/rules/",
          vcs: "commit",
          note: "專案共用的背景知識（架構說明、領域詞彙）。"
        },
        "記憶-本地": {
          file: "./CLAUDE.local.md",
          vcs: "gitignore",
          note: "個人本地記憶覆寫，不進版控。"
        },
        "規則 / 指令-使用者": {
          file: "~/.claude/CLAUDE.md",
          vcs: "gitignore",
          note: "跨所有專案生效的個人慣例，例如：永遠用台灣繁中回覆。"
        },
        "規則 / 指令-專案": {
          file: "./CLAUDE.md 或 .claude/rules/*.md",
          vcs: "commit",
          note: "團隊共用的程式碼風格規約、專案約束。全隊共享，放這裡。"
        },
        "規則 / 指令-本地": {
          file: "./CLAUDE.local.md",
          vcs: "gitignore",
          note: "個人覆寫規則，例如本地測試用的特殊約束。"
        },
        "隱私-使用者": {
          file: "~/.claude/settings.json",
          vcs: "gitignore",
          note: "訓練退出、資料保留期限等隱私設定。個人層，不進版控。"
        },
        "隱私-專案": {
          file: ".claude/settings.json",
          vcs: "commit",
          note: "少見：若整個專案有統一的資料處理政策，可放這裡，但通常是個人設定。"
        },
        "隱私-本地": {
          file: ".claude/settings.local.json",
          vcs: "gitignore",
          note: "本地個人隱私設定覆寫。"
        },
        "權限-使用者": {
          file: "~/.claude/settings.json",
          vcs: "gitignore",
          note: "你個人跨所有專案的 allow / ask / deny 規則基線。"
        },
        "權限-專案": {
          file: ".claude/settings.json",
          vcs: "commit",
          note: "這個專案全隊共用的權限規則，例如：deny 讀取 .env、ask git push。"
        },
        "權限-本地": {
          file: ".claude/settings.local.json",
          vcs: "gitignore",
          note: "個人本地權限覆寫，高於專案層、低於 CLI 參數。密鑰相關設定放這裡。"
        },
        "自動化-使用者": {
          file: "~/.claude/settings.json (hooks/skills)",
          vcs: "gitignore",
          note: "跨所有專案生效的個人 hook 或 skill，例如全域 PostToolUse 日誌 hook。"
        },
        "自動化-專案": {
          file: ".claude/settings.json + .claude/skills/",
          vcs: "commit",
          note: "這個專案專屬的 hook 與 skill，全隊共享，版本化管理。"
        },
        "自動化-本地": {
          file: ".claude/settings.local.json",
          vcs: "gitignore",
          note: "個人本地的 hook 覆寫，例如本機除錯用的額外日誌。"
        }
      }
    },
    en: {
      kindLabel: "Setting type",
      scopeLabel: "Scope",
      kinds: ["Personalization", "Memory", "Rules / Instructions", "Privacy", "Permissions", "Automation"],
      scopes: ["User", "Project", "Local"],
      resultTitle: "Where does it go?",
      vcsLabel: "Version control",
      commit: "Commit (shared with team)",
      gitignore: "gitignore (personal only)",
      hint: "Pick a type and scope to see the target file",
      examples: {
        "Personalization-User": {
          file: "~/.claude/CLAUDE.md",
          vcs: "gitignore",
          note: "Language preference, tone, output format for all your projects. Affects only you, does not pollute the team."
        },
        "Personalization-Project": {
          file: "./CLAUDE.md",
          vcs: "commit",
          note: "Generally avoid putting purely personal preferences in the project layer, unless it is a formatting convention the whole team agrees on."
        },
        "Personalization-Local": {
          file: "./CLAUDE.local.md",
          vcs: "gitignore",
          note: "Personal sandbox URLs, local paths, test data preferences visible only to you."
        },
        "Memory-User": {
          file: "~/.claude/CLAUDE.md",
          vcs: "gitignore",
          note: "Personal facts and preferences persisted across sessions."
        },
        "Memory-Project": {
          file: "./CLAUDE.md or .claude/rules/",
          vcs: "commit",
          note: "Shared project background knowledge: architecture notes, domain vocabulary."
        },
        "Memory-Local": {
          file: "./CLAUDE.local.md",
          vcs: "gitignore",
          note: "Personal local memory overrides, not committed."
        },
        "Rules / Instructions-User": {
          file: "~/.claude/CLAUDE.md",
          vcs: "gitignore",
          note: "Personal conventions active across all projects, e.g. always reply in Traditional Chinese."
        },
        "Rules / Instructions-Project": {
          file: "./CLAUDE.md or .claude/rules/*.md",
          vcs: "commit",
          note: "Team-shared coding style conventions and project constraints. This is the right place."
        },
        "Rules / Instructions-Local": {
          file: "./CLAUDE.local.md",
          vcs: "gitignore",
          note: "Personal rule overrides, e.g. special constraints for local testing."
        },
        "Privacy-User": {
          file: "~/.claude/settings.json",
          vcs: "gitignore",
          note: "Training opt-out, data retention period, and other privacy settings. Personal, not committed."
        },
        "Privacy-Project": {
          file: ".claude/settings.json",
          vcs: "commit",
          note: "Rare: use when the whole project has a unified data handling policy; usually a personal setting."
        },
        "Privacy-Local": {
          file: ".claude/settings.local.json",
          vcs: "gitignore",
          note: "Local personal privacy setting overrides."
        },
        "Permissions-User": {
          file: "~/.claude/settings.json",
          vcs: "gitignore",
          note: "Your personal allow / ask / deny baseline across all projects."
        },
        "Permissions-Project": {
          file: ".claude/settings.json",
          vcs: "commit",
          note: "Team-shared permission rules for this project, e.g. deny reading .env, ask before git push."
        },
        "Permissions-Local": {
          file: ".claude/settings.local.json",
          vcs: "gitignore",
          note: "Personal local permission overrides; higher priority than project layer, lower than CLI args. Put secret-related settings here."
        },
        "Automation-User": {
          file: "~/.claude/settings.json (hooks/skills)",
          vcs: "gitignore",
          note: "Personal hooks or skills active across all projects, e.g. a global PostToolUse logging hook."
        },
        "Automation-Project": {
          file: ".claude/settings.json + .claude/skills/",
          vcs: "commit",
          note: "Project-specific hooks and skills shared with the team, version-controlled."
        },
        "Automation-Local": {
          file: ".claude/settings.local.json",
          vcs: "gitignore",
          note: "Personal local hook overrides, e.g. extra debug logging on your machine."
        }
      }
    }
  };
  const ui = t[lang] || t["zh"];
  const [selectedKind, setSelectedKind] = useState(null);
  const [selectedScope, setSelectedScope] = useState(null);
  const resultKey = selectedKind && selectedScope ? `${selectedKind}-${selectedScope}` : null;
  const result = resultKey ? ui.examples[resultKey] : null;
  const isCommit = result && result.vcs === "commit";
  const css = `
    .sfp-root {
      --sfp-accent: #bf7551;
      --sfp-accent-light: #cf8a68;
      --sfp-bg: #faf8f4;
      --sfp-card: #f3efe8;
      --sfp-border: #d9c9b4;
      --sfp-text: #2d2418;
      --sfp-muted: #7a6a57;
      --sfp-commit: #3b6b3b;
      --sfp-commit-bg: #eaf3ea;
      --sfp-gitignore: #5a3f6b;
      --sfp-gitignore-bg: #f0eaf5;
      font-family: inherit;
      border: 1px solid var(--sfp-border);
      border-radius: 10px;
      background: var(--sfp-bg);
      padding: 1.25rem 1.5rem 1.5rem;
      max-width: 640px;
    }
    .dark .sfp-root {
      --sfp-bg: #1e1a16;
      --sfp-card: #2a2420;
      --sfp-border: #4a3e30;
      --sfp-text: #e8ddd0;
      --sfp-muted: #a08870;
      --sfp-commit: #7ec87e;
      --sfp-commit-bg: #1a2e1a;
      --sfp-gitignore: #c8a8e8;
      --sfp-gitignore-bg: #1e1428;
    }
    .sfp-hint {
      font-size: 0.82rem;
      color: var(--sfp-muted);
      margin-bottom: 1rem;
    }
    .sfp-row {
      display: flex;
      gap: 1.25rem;
      flex-wrap: wrap;
      margin-bottom: 1rem;
    }
    .sfp-col {
      flex: 1;
      min-width: 160px;
    }
    .sfp-col-label {
      font-size: 0.75rem;
      font-weight: 600;
      text-transform: uppercase;
      letter-spacing: 0.06em;
      color: var(--sfp-muted);
      margin-bottom: 0.45rem;
    }
    .sfp-chips {
      display: flex;
      flex-direction: column;
      gap: 0.35rem;
    }
    .sfp-chip {
      padding: 0.38rem 0.8rem;
      border-radius: 6px;
      border: 1.5px solid var(--sfp-border);
      background: var(--sfp-card);
      color: var(--sfp-text);
      font-size: 0.83rem;
      cursor: pointer;
      text-align: left;
      transition: border-color 0.15s, background 0.15s;
    }
    .sfp-chip:hover {
      border-color: var(--sfp-accent-light);
    }
    .sfp-chip.active {
      border-color: var(--sfp-accent);
      background: var(--sfp-accent);
      color: #fff;
    }
    .sfp-result {
      margin-top: 0.75rem;
      border: 1.5px solid var(--sfp-border);
      border-radius: 8px;
      background: var(--sfp-card);
      padding: 0.9rem 1.1rem;
      animation: sfp-fadein 0.18s ease;
    }
    @keyframes sfp-fadein { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
    .sfp-result-title {
      font-size: 0.72rem;
      font-weight: 600;
      text-transform: uppercase;
      letter-spacing: 0.07em;
      color: var(--sfp-muted);
      margin-bottom: 0.35rem;
    }
    .sfp-file {
      font-family: monospace;
      font-size: 0.88rem;
      font-weight: 600;
      color: var(--sfp-accent);
      margin-bottom: 0.55rem;
      word-break: break-all;
    }
    .sfp-vcs {
      display: inline-block;
      padding: 0.2rem 0.65rem;
      border-radius: 4px;
      font-size: 0.76rem;
      font-weight: 600;
      margin-bottom: 0.55rem;
    }
    .sfp-vcs.commit {
      background: var(--sfp-commit-bg);
      color: var(--sfp-commit);
    }
    .sfp-vcs.gitignore {
      background: var(--sfp-gitignore-bg);
      color: var(--sfp-gitignore);
    }
    .sfp-note {
      font-size: 0.82rem;
      color: var(--sfp-muted);
      line-height: 1.55;
    }
    .sfp-placeholder {
      color: var(--sfp-muted);
      font-size: 0.84rem;
      padding: 0.5rem 0;
      text-align: center;
    }
    @media (max-width: 480px) {
      .sfp-row { flex-direction: column; gap: 0.85rem; }
    }
  `;
  return <div className="sfp-root">
      <style>{css}</style>
      <div className="sfp-hint">{ui.hint}</div>
      <div className="sfp-row">
        <div className="sfp-col">
          <div className="sfp-col-label">{ui.kindLabel}</div>
          <div className="sfp-chips">
            {ui.kinds.map(k => <button key={k} className={"sfp-chip" + (selectedKind === k ? " active" : "")} onClick={() => setSelectedKind(selectedKind === k ? null : k)}>
                {k}
              </button>)}
          </div>
        </div>
        <div className="sfp-col">
          <div className="sfp-col-label">{ui.scopeLabel}</div>
          <div className="sfp-chips">
            {ui.scopes.map(s => <button key={s} className={"sfp-chip" + (selectedScope === s ? " active" : "")} onClick={() => setSelectedScope(selectedScope === s ? null : s)}>
                {s}
              </button>)}
          </div>
        </div>
      </div>
      <div className="sfp-result">
        {result ? <>
            <div className="sfp-result-title">{ui.resultTitle}</div>
            <div className="sfp-file">{result.file}</div>
            <div className={"sfp-vcs " + result.vcs}>
              {result.vcs === "commit" ? ui.commit : ui.gitignore}
            </div>
            <div className="sfp-note">{result.note}</div>
          </> : <div className="sfp-placeholder">{ui.hint}</div>}
      </div>
    </div>;
};

export const ArchFlow = ({nodes = [], lang = "zh"}) => {
  const t = lang === "en" ? {
    flow: "Data flow",
    hint: "Click any stage to see what it does",
    stage: "Stage"
  } : {
    flow: "資料流",
    hint: "點任一階段看它做什麼",
    stage: "階段"
  };
  const safe = Array.isArray(nodes) ? nodes : [];
  const [active, setActive] = useState(0);
  if (safe.length === 0) return null;
  const idx = Math.min(active, safe.length - 1);
  const current = safe[idx];
  const css = `
  .af-root{--af-bg:#FAF8F3;--af-surface:rgba(191,117,81,0.06);--af-surface2:rgba(0,0,0,0.025);--af-border:rgba(0,0,0,0.09);--af-text:#2b2722;--af-dim:#6f6a62;--af-faint:#8a8378;--af-rail:rgba(0,0,0,0.12);--af-accent:#bf7551;border:1px solid var(--af-border);border-radius:14px;background:var(--af-bg);color:var(--af-text);overflow:hidden;}
  .dark .af-root{--af-bg:#1b1a18;--af-surface:rgba(207,138,104,0.09);--af-surface2:rgba(255,255,255,0.03);--af-border:rgba(255,255,255,0.08);--af-text:#e7e3da;--af-dim:#a8a299;--af-faint:#8a8378;--af-rail:rgba(255,255,255,0.13);--af-accent:#cf8a68;}
  .af-head{padding:13px 18px 11px;display:flex;align-items:center;gap:9px;flex-wrap:wrap;border-bottom:1px solid var(--af-border);}
  .af-head-ic{color:var(--af-accent);flex-shrink:0;}
  .af-head-t{font-size:12px;font-weight:700;letter-spacing:.6px;color:var(--af-dim);text-transform:uppercase;}
  .af-head-h{font-size:12px;color:var(--af-faint);}
  .af-grid{display:flex;gap:0;align-items:stretch;}
  .af-list{flex:1 1 0;min-width:0;padding:12px 12px 16px;}
  .af-node{display:flex;align-items:stretch;gap:10px;width:100%;text-align:left;background:transparent;border:none;cursor:pointer;padding:0;color:inherit;font:inherit;-webkit-tap-highlight-color:transparent;}
  .af-railcol{width:22px;flex-shrink:0;display:flex;flex-direction:column;align-items:center;}
  .af-dot{width:9px;height:9px;border-radius:50%;margin-top:14px;background:var(--af-faint);opacity:.5;flex-shrink:0;transition:background .15s,box-shadow .15s,opacity .15s;}
  .af-line{width:2px;flex:1 1 0;background:var(--af-rail);min-height:10px;}
  .af-body{flex:1 1 0;min-width:0;padding:9px 12px;margin:2px 0;border-radius:9px;border:1px solid transparent;transition:background .15s,border-color .15s;}
  .af-node:hover .af-body{background:var(--af-surface2);}
  .af-node-on .af-body{background:var(--af-surface);border-color:rgba(191,117,81,.30);}
  .af-node-on .af-dot{background:var(--af-accent);opacity:1;box-shadow:0 0 0 4px rgba(191,117,81,.15);}
  .af-label{font-size:14.5px;font-weight:550;line-height:1.45;}
  .af-node-on .af-label{color:var(--af-accent);}
  .af-detail{width:300px;flex-shrink:0;border-left:1px solid var(--af-border);padding:16px 18px;background:var(--af-surface2);}
  .af-detail-k{font-size:11px;font-weight:700;letter-spacing:.5px;text-transform:uppercase;color:var(--af-accent);margin-bottom:7px;}
  .af-detail-l{font-size:16px;font-weight:600;margin-bottom:9px;line-height:1.35;}
  .af-detail-d{font-size:13.5px;line-height:1.65;color:var(--af-dim);}
  @media (max-width:640px){.af-grid{flex-direction:column;}.af-detail{width:auto;border-left:none;border-top:1px solid var(--af-border);}}
  `;
  return <div className="af-root">
      <style>{css}</style>
      <div className="af-head">
        <svg className="af-head-ic" xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect width="8" height="8" x="3" y="3" rx="2" /><path d="M7 11v4a2 2 0 0 0 2 2h4" /><rect width="8" height="8" x="13" y="13" rx="2" /></svg>
        <span className="af-head-t">{t.flow}</span>
        <span className="af-head-h">{t.hint}</span>
      </div>
      <div className="af-grid">
        <div className="af-list">
          {safe.map((n, i) => <button key={i} type="button" className={"af-node" + (i === idx ? " af-node-on" : "")} onClick={() => setActive(i)} onMouseEnter={() => setActive(i)}>
              <div className="af-railcol">
                <div className="af-dot" />
                {i < safe.length - 1 && <div className="af-line" />}
              </div>
              <div className="af-body">
                <div className="af-label">{n.label}</div>
              </div>
            </button>)}
        </div>
        <div className="af-detail">
          <div className="af-detail-k">{t.stage} {idx + 1} / {safe.length}</div>
          <div className="af-detail-l">{current.label}</div>
          <div className="af-detail-d">{current.detail}</div>
        </div>
      </div>
    </div>;
};

export const LearnerPrimer = ({items = [], lang = "zh"}) => {
  const t = lang === "en" ? {
    title: "Before this unit, be honest with yourself",
    sub: "If you can't answer these, that gap is exactly what this unit closes."
  } : {
    title: "讀這個單元前，先誠實面對",
    sub: "這幾題答不出來，正是這個單元要替你補的洞。"
  };
  const css = `
  .lp-root{--lp-bg:#FAF7F1;--lp-surface:rgba(191,117,81,0.05);--lp-border:rgba(0,0,0,0.09);--lp-edge:rgba(191,117,81,0.42);--lp-text:#2b2722;--lp-dim:#6f6a62;--lp-accent:#bf7551;border:1px solid var(--lp-border);border-left:3px solid var(--lp-edge);border-radius:13px;background:var(--lp-bg);color:var(--lp-text);overflow:hidden;margin:1.25rem 0;}
  .dark .lp-root{--lp-bg:#1b1a18;--lp-surface:rgba(207,138,104,0.07);--lp-border:rgba(255,255,255,0.08);--lp-edge:rgba(207,138,104,0.5);--lp-text:#e7e3da;--lp-dim:#a8a299;--lp-accent:#cf8a68;}
  .lp-head{display:flex;align-items:center;gap:9px;padding:13px 18px 11px;border-bottom:1px solid var(--lp-border);background:var(--lp-surface);}
  .lp-ic{color:var(--lp-accent);flex-shrink:0;}
  .lp-htx{display:flex;flex-direction:column;gap:1px;min-width:0;}
  .lp-title{font-size:14px;font-weight:650;line-height:1.3;letter-spacing:.01em;}
  .lp-sub{font-size:12px;color:var(--lp-dim);line-height:1.4;}
  .lp-list{list-style:none;margin:0;padding:10px 18px 14px;display:flex;flex-direction:column;gap:0;}
  .lp-item{display:flex;align-items:baseline;gap:11px;padding:7px 0;font-size:14px;line-height:1.6;border-top:1px solid var(--lp-border);}
  .lp-item:first-child{border-top:none;}
  .lp-mark{flex-shrink:0;color:var(--lp-accent);font-size:13px;font-weight:700;line-height:1.55;font-variant-numeric:tabular-nums;opacity:.85;}
  .lp-q{flex:1 1 0;min-width:0;color:var(--lp-text);}
  @media (max-width:620px){.lp-head{padding:12px 14px 10px;}.lp-list{padding:8px 14px 12px;}}
  `;
  return <div className="lp-root">
      <style>{css}</style>
      <div className="lp-head">
        <svg className="lp-ic" xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10" /><circle cx="12" cy="12" r="6" /><circle cx="12" cy="12" r="2" /></svg>
        <span className="lp-htx">
          <span className="lp-title">{t.title}</span>
          <span className="lp-sub">{t.sub}</span>
        </span>
      </div>
      <ul className="lp-list">
        {items.map((q, i) => <li className="lp-item" key={i}>
            <span className="lp-mark">{String(i + 1).padStart(2, "0")}</span>
            <span className="lp-q">{q}</span>
          </li>)}
      </ul>
    </div>;
};

<LearnerPrimer
  lang="zh"
  items={[
"設定有三種語意：覆寫、串接、合併，別當成同一回事。",
"你以為使用者層的 CLAUDE.md 會被專案層蓋掉？兩份都讀。",
"個人語言偏好寫進 ./CLAUDE.md，全隊被你污染。",
"API key 進 settings.json 跟貼上 GitHub 是同一件事。",
"deny 規則被低層 allow 解開？做不到。",
"「我明明設了怎麼沒用」十之八九是被近一層蓋掉。",
"範圍軸選錯，下次 commit 就是密鑰外洩。",
]}
/>

<Info>
  **這個單元解決什麼問題**

  在學任何一家工具的設定細節之前，先建立一個通用座標系。掌握「作用範圍」與「設定種類」這兩個軸，之後看到任何工具的設定檔，你都能立刻判斷它屬於哪一格、會不會被別的設定覆寫、該不該提交到版控。
</Info>

## 學習目標

* [ ] 能用「作用範圍」軸（受管理 → 使用者 → 專案 → 本地）描述任一設定的生效範圍。
* [ ] 能用「設定種類」軸（個人化 / 記憶 / 規則 / 隱私 / 權限 / 自動化）分類任一設定項。
* [ ] 能說明覆寫優先序，並分辨「覆寫」「串接」「合併」三種不同的層級語意。
* [ ] 能正確區分「該提交到版控（團隊共享）」與「該 gitignore（個人）」的設定檔。

***

## 1. 第一軸：作用範圍（scope）

同一個設定可以出現在不同範圍，誰生效取決於優先序。以 Claude Code 為主範本，由高到低五層（截至 2026-05 官方文件 \[1]）：

<ArchFlow
  lang="zh"
  nodes={[
{
  label: "受管理政策（managed）",
  detail: "企業以 MDM / Group Policy 部署，不可被任何下層覆寫。macOS：/Library/Application Support/ClaudeCode/managed-settings.json；Linux/WSL：/etc/claude-code/managed-settings.json；Windows：C:\\Program Files\\ClaudeCode\\managed-settings.json。",
},
{
  label: "命令列參數 / 工作階段",
  detail: "當次執行的臨時覆寫，高於所有持久化設定。session 結束即失效。",
},
{
  label: "本地個人（local）",
  detail: ".claude/settings.local.json、./CLAUDE.local.md。已 gitignore，只有你看得到，不分享給任何人。",
},
{
  label: "專案（project）",
  detail: ".claude/settings.json、./CLAUDE.md（或 ./.claude/CLAUDE.md）。提交版控、全隊共享。這是團隊慣例與約束的落點。",
},
{
  label: "使用者（user）",
  detail: "~/.claude/settings.json、~/.claude/CLAUDE.md。套用到你機器上所有專案的個人偏好基線。",
},
]}
/>

<Tip>
  **通用心法**

  「越靠近當前任務的設定，優先序越高」。受管理政策是唯一從上而下、不可違逆的例外，那是給 IT 管控用的。其餘四層都遵守「近者為大」。
</Tip>

### 三種層級語意：覆寫 vs 串接 vs 合併

這是多數人對「層級」最大的誤解：**不是所有設定都用「高層覆寫低層」**。Claude Code 裡至少有三種不同的合併行為，混用這兩種心智模型會讓你在 debug 時耗費大量時間（\[1]\[2]）：

| 語意                  | 適用對象                                  | 行為                                                                                     |
| ------------------- | ------------------------------------- | -------------------------------------------------------------------------------------- |
| **覆寫（override）**    | `settings.json` 的同一個鍵                 | 高優先序層的值蓋掉低層，只有一個值生效                                                                    |
| **串接（concatenate）** | `CLAUDE.md` / memory 規則檔              | 各層**全部載入**、不互相覆寫，依「root → 當前目錄」順序拼接進上下文                                                |
| **合併（merge）**       | `permissions` 的 allow / ask / deny 規則 | 跨層的規則陣列**串接 + 去重**成一份；評估依 `deny → ask → allow` 順序，首個命中者勝；**`deny` 不可被任何層的 `allow` 解開** |

換句話說：你的 `~/.claude/CLAUDE.md` 與專案 `./CLAUDE.md` **不會互相覆寫**，兩份都會被讀進去（使用者層在前、專案層在後）。但 `~/.claude/settings.json` 與 `.claude/settings.json` 裡同一個鍵，高層的會贏。把這兩件事當成同一回事，是「我明明在使用者層設了，怎麼專案裡行為不一樣」這類困惑的根源。

## 2. 第二軸：設定種類

範圍決定「在哪生效」，種類決定「管什麼」。六類：

* **個人化**：角色、語言、語氣、輸出格式。
* **記憶**：跨 session 持久化的事實與偏好（[01-4](/code-agent/foundations/context-engineering) 談過短期 vs 長期）。
* **規則 / 指令**：專案慣例、約束（`CLAUDE.md`、`AGENTS.md`、`.claude/rules/`）。
* **隱私**：訓練退出、保留期限、暫時對話。
* **權限**：工具可否執行、可讀寫哪些路徑（allow / ask / deny）。
* **自動化**：Skill、Hook、工作流。

兩軸一交叉，任何一個設定項都能被你定位到「哪一格」：一條規則是「規則種類 × 某個範圍」，一個權限是「權限種類 × 某個範圍」。

## 3. 兩軸交叉：決策工具

把「種類 × 範圍」當成一張矩陣，每次要放一個設定，先選這兩個軸，答案就決定了它該進哪個檔、要不要提交版控。

<ScopeFilePicker lang="zh" />

<Note>
  **三個設定，三個位置**

  1. **團隊共用的程式碼風格規約**：規則種類 × 專案範圍 → 寫進 `./CLAUDE.md`，**提交版控**，全隊共享。
  2. **你個人的測試沙箱 URL 與偏好測試資料**：個人化 / 規則種類 × 本地範圍 → 寫進 `./CLAUDE.local.md`，**加進 `.gitignore`**，只有你看得到、不污染團隊。
  3. **你跨所有專案的語言偏好（一律用台灣繁中回覆）**：個人化種類 × 使用者範圍 → 寫進 `~/.claude/CLAUDE.md`，套用到你機器上每個專案。

  三個都是「規則 / 個人化」種類，差別只在範圍，而範圍直接決定了「提交還是 gitignore、誰看得到」。這就是兩軸座標系的用法：先定種類，再定範圍，檔案位置與版控策略就自動掉出來了。
</Note>

<Warning>
  **同一個鍵設在多層時，先想清楚是覆寫還是串接**

  若你在 `~/.claude/settings.json` 設了 `model`，又在 `.claude/settings.json` 設了不同的 `model`，**專案層贏**（覆寫，近者為大）。但若你在 `~/.claude/CLAUDE.md` 與 `./CLAUDE.md` 各寫了風格規則，**兩份都生效**（串接），衝突時 Claude 可能任選一條，所以別讓兩層的規則互相矛盾。
</Warning>

## 4. 提交 vs gitignore（關鍵實務）

範圍軸最直接的版控後果，就是這條二分：

* **提交（版控、團隊共享）**：團隊應一致遵守的規則與設定。`./CLAUDE.md`、`.claude/settings.json`、`.claude/rules/`、`AGENTS.md`。
* **gitignore（個人、不分享）**：個人覆寫、密鑰、本地路徑。`./CLAUDE.local.md`、`.claude/settings.local.json`、任何含 token 的檔。

這跟 `.env` / `.env.example` 是同一套思維：可分享的模板進版控，含密鑰的實體留本地。判準很簡單：**這個設定換一個隊友套用，是幫到他還是洩漏你？** 幫到他就提交，洩漏你就 gitignore。

<Warning>
  **密鑰永遠不進會被提交的檔**

  最常見也最貴的錯誤：把 API key、token 寫進 `.claude/settings.json`（會提交）而非 `settings.local.json`（gitignore）。一旦推上遠端，等於公開。密鑰、本地絕對路徑、個人沙箱位址，一律走 local 層。
</Warning>

## 5. 把任何新工具對位到此模型

這個座標系的價值，在於它跨工具通用。拿到一個陌生工具，依序問五個問題，你就摸清了它的設定面，不用讀完整份文件：

<Steps>
  <Step title="使用者級設定在哪？">
    套用所有專案的個人偏好放哪個檔或目錄？
  </Step>

  <Step title="專案級規則檔是哪個？">
    哪個檔案進版控、對全隊生效？
  </Step>

  <Step title="有沒有本地覆寫層？">
    有沒有已 gitignore 的個人設定入口？
  </Step>

  <Step title="隱私 / 訓練退出開關在哪？">
    如何退出資料訓練或設定資料保留期？
  </Step>

  <Step title="權限怎麼控制？">
    能不能限制它讀寫、執行的範圍？deny / ask / allow 在哪設？
  </Step>
</Steps>

五題答得出來，你就能安全地開始用它，而不是踩到「設了沒用」或「不小心提交了密鑰」才回頭補課。

## 工具對照

各家的設定層級對應（截至 2026-05，精確檔名與機制以官方文件為準，逐項細節見 [02-2](/code-agent/configuration/anthropic-claude-setup) 與 [02-6](/code-agent/configuration/other-tools-comparison)）：

| 範圍   | Anthropic Claude（主範本）                     | OpenAI Codex                                  | Google Antigravity                    | GitHub Copilot CLI                                                         | Cursor                |
| ---- | ----------------------------------------- | --------------------------------------------- | ------------------------------------- | -------------------------------------------------------------------------- | --------------------- |
| 使用者級 | `~/.claude/`（`settings.json`、`CLAUDE.md`） | `~/.codex/config.toml`                        | `~/.gemini/`（`GEMINI.md`、`AGENTS.md`） | `~/.copilot/copilot-instructions.md`（單檔）                                   | User Rules (GUI)      |
| 專案級  | `.claude/`、`./CLAUDE.md`                  | `AGENTS.md`、`.codex/config.toml`（trusted 才載入） | `.agent/rules/`（單數）、`GEMINI.md`       | `.github/copilot-instructions.md`、`.github/instructions/*.instructions.md` | `.cursor/rules/*.mdc` |
| 本地覆寫 | `settings.local.json`、`CLAUDE.local.md`   | CLI flags                                     | （無明確獨立本地層，以工作區為準）                     | `~/.copilot/copilot-instructions.md`（CLI 本身即支援本機層，與 `AGENTS.md` 併用）        | （無對等獨立本地層，詳見 02-6）    |

<Note>
  **對照表給座標，不給細則**

  這張表讓你知道「同一層在你的工具叫什麼」。各 cell 的精確語意（誰覆寫誰、哪些進版控）屬快變動事實，統一在 02-2（Claude）與 02-6（其餘）查證並標日期。值得記住的是：幾乎每家都有「使用者 / 專案 / 本地」這條範圍軸，差別只在檔名與本地層完整度。
</Note>

## 常見誤區

<Warning>
  **反模式清單**

  * **以為所有層都是「高層覆寫低層」**：`settings.json` 是覆寫，但 `CLAUDE.md` 是串接、`permissions` 是合併。用錯心智模型會有 debug 成本（第 1 節）。
  * **把個人偏好寫進團隊共享的專案規則檔**：你的語言偏好、沙箱 URL 進了 `./CLAUDE.md`，全隊都被你的偏好污染。那是 `CLAUDE.local.md` 或使用者層的事。
  * **把密鑰寫進會被提交的設定檔**：`settings.json` 會進版控，密鑰要走 `settings.local.json`（第 4 節）。
  * **不知道某設定被更高優先序的層覆寫**：「我明明設了怎麼沒用」十之八九是被近一層的設定蓋掉，或被受管理政策鎖死。先確認生效的是哪一層。
</Warning>

## 自我檢核

<Check>
  **通過本單元的標準**

  1. 你能說出你主力工具的「使用者級」與「專案級」設定各放哪、哪些已進版控嗎？
  2. 給你一個 API key、一條團隊風格規則、一個個人語言偏好，你能各自說出「放哪一格、提交還是 gitignore」嗎？
  3. 你能解釋為什麼 `~/.claude/CLAUDE.md` 與 `./CLAUDE.md` 不會互相覆寫，但兩份 `settings.json` 的同一個鍵會嗎？
</Check>

## 來源與延伸閱讀

事實主張依官方文件，快變動項標註截至 2026-05。

<div className="references">
  * \[1] Anthropic, "Claude Code settings"（設定優先序：managed → CLI → local → project → user；檔案位置；permissions 為跨層合併），Claude Code Docs. [https://code.claude.com/docs/en/settings](https://code.claude.com/docs/en/settings) （截至 2026-05）

  * \[2] Anthropic, "How Claude remembers your project"（`CLAUDE.md` 階層與串接載入、`CLAUDE.local.md`、`@path` 匯入語法、`.claude/rules/`、Claude Code 讀 `CLAUDE.md` 而非 `AGENTS.md`），Claude Code Docs. [https://code.claude.com/docs/en/memory](https://code.claude.com/docs/en/memory) （截至 2026-05）
</div>

* 銜接：[02-2](/code-agent/configuration/anthropic-claude-setup) Claude 設定逐項、[02-6](/code-agent/configuration/other-tools-comparison) 其他工具設定對照、[04-1](/code-agent/customization/claude-md-memory) CLAUDE.md 與記憶檔、[04-2](/code-agent/customization/rules) rules 規則檔。
