> ## 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.

# 04-0 .claude 目錄全覽

> Part IV 的地圖：先看懂 .claude 目錄的完整結構，再進各單元深讀。涵蓋專案層與使用者層每個檔案的用途、載入時機與版控建議，以及 output-styles、keybindings、themes、workflows、agent-memory 五個補充主題。

export const DirExplorer = ({lang = "zh", scopes = []}) => {
  const UI = lang === "en" ? {
    expandAll: "Expand all",
    collapseAll: "Collapse all",
    whenLoads: "WHEN IT LOADS",
    tips: "TIPS",
    copy: "Copy",
    copied: "Copied",
    mapsToLabel: "Maps to Claude",
    badgeLabels: {
      committed: "Committed to version control",
      gitignored: "Git-ignored (local only)",
      local: "Local override",
      autogen: "Auto-generated"
    },
    badgeTexts: {
      committed: "COMMITTED",
      gitignored: "GITIGNORED",
      local: "LOCAL",
      autogen: "AUTOGEN"
    }
  } : {
    expandAll: "全部展開",
    collapseAll: "全部收合",
    whenLoads: "載入時機",
    tips: "提示",
    copy: "複製",
    copied: "已複製",
    mapsToLabel: "對照 Claude",
    badgeLabels: {
      committed: "已提交至版本控制",
      gitignored: "Git 忽略（僅本機）",
      local: "本機覆寫",
      autogen: "自動產生"
    },
    badgeTexts: {
      committed: "COMMITTED",
      gitignored: "GITIGNORED",
      local: "LOCAL",
      autogen: "AUTOGEN"
    }
  };
  const ACCENT_LIGHT = "#bf7551";
  const ACCENT_DARK = "#cf8a68";
  const DIR_COLORS = {
    blue: "#5b6c8f",
    purple: "#8a6f8e",
    yellow: "#c9a35b",
    green: "#8a9a7b",
    teal: "#6f9290",
    rose: "#ab7269",
    amber: "#b9835c",
    gray: "#8a8378",
    default: "#8a8378"
  };
  const BADGE_COLORS = {
    committed: {
      dot: "#6dab7d",
      title: "committed"
    },
    gitignored: {
      dot: "#d4844a",
      title: "gitignored"
    },
    local: {
      dot: "#8a8378",
      title: "local"
    },
    autogen: {
      dot: "#c8a240",
      title: "autogen"
    }
  };
  const safeScopes = Array.isArray(scopes) && scopes.length > 0 ? scopes : [];
  if (safeScopes.length === 0) return null;
  const [activeScopeId, setActiveScopeId] = useState(safeScopes[0].id);
  const [expandedIds, setExpandedIds] = useState({});
  const [selectedNode, setSelectedNode] = useState(null);
  const [copiedFlag, setCopiedFlag] = useState(false);
  const [isDark, setIsDark] = useState(false);
  useEffect(() => {
    const detectDark = () => setIsDark(document.documentElement.classList.contains("dark"));
    detectDark();
    const obs = new MutationObserver(detectDark);
    obs.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class"]
    });
    const firstScope = safeScopes[0];
    if (firstScope && Array.isArray(firstScope.tree)) {
      const initExpanded = {};
      firstScope.tree.forEach((node, i) => {
        if (node.kind === "dir") initExpanded[firstScope.id + ":" + i] = true;
      });
      setExpandedIds(initExpanded);
    }
    return () => obs.disconnect();
  }, []);
  const switchScope = id => {
    setActiveScopeId(id);
    setSelectedNode(null);
    const scope = safeScopes.find(s => s.id === id);
    if (!scope) return;
    const initExpanded = {};
    (scope.tree || []).forEach((node, i) => {
      if (node.kind === "dir") initExpanded[id + ":" + i] = true;
    });
    setExpandedIds(initExpanded);
  };
  const activeScope = safeScopes.find(s => s.id === activeScopeId) || safeScopes[0];
  const tree = Array.isArray(activeScope.tree) ? activeScope.tree : [];
  const collectAllDirKeys = (nodes, scopeId, prefix) => {
    const keys = [];
    (nodes || []).forEach((node, i) => {
      const key = prefix + i;
      if (node.kind === "dir") {
        keys.push(scopeId + ":" + key);
        const childKeys = collectAllDirKeys(node.children, scopeId, key + "-");
        childKeys.forEach(k => keys.push(k));
      }
    });
    return keys;
  };
  const handleExpandAll = () => {
    const keys = collectAllDirKeys(tree, activeScopeId, "");
    const next = {};
    keys.forEach(k => {
      next[k] = true;
    });
    setExpandedIds(next);
  };
  const handleCollapseAll = () => {
    setExpandedIds({});
  };
  const isAllExpanded = () => {
    const keys = collectAllDirKeys(tree, activeScopeId, "");
    return keys.length > 0 && keys.every(k => expandedIds[k]);
  };
  const handleCopy = code => {
    if (!code) return;
    try {
      navigator.clipboard.writeText(code).then(() => {
        setCopiedFlag(true);
        setTimeout(() => setCopiedFlag(false), 1600);
      });
    } catch (_) {
      setCopiedFlag(false);
    }
  };
  const FolderIcon = ({color}) => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke={color || DIR_COLORS.default} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{
    flexShrink: 0
  }}>
      <path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z" />
    </svg>;
  const FileDocIcon = ({color}) => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke={color || DIR_COLORS.default} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{
    flexShrink: 0
  }}>
      <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
      <polyline points="14 2 14 8 20 8" />
      <line x1="16" y1="13" x2="8" y2="13" />
      <line x1="16" y1="17" x2="8" y2="17" />
      <polyline points="10 9 9 9 8 9" />
    </svg>;
  const FileJsonIcon = ({color}) => <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke={color || DIR_COLORS.default} strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{
    flexShrink: 0
  }}>
      <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
      <polyline points="14 2 14 8 20 8" />
      <text x="7" y="19" fontSize="7" fontWeight="700" fill={color || DIR_COLORS.default} stroke="none" fontFamily="monospace">{"{}"}</text>
    </svg>;
  const ChevronRight = () => <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" style={{
    flexShrink: 0,
    transition: "transform 0.15s"
  }}>
      <polyline points="9 18 15 12 9 6" />
    </svg>;
  const getFileIcon = node => {
    const c = DIR_COLORS[node.color] || DIR_COLORS.default;
    if (node.kind === "dir") return <FolderIcon color={c} />;
    if (node.name && (node.name.endsWith(".json") || node.name.endsWith(".jsonc"))) return <FileJsonIcon color={c} />;
    return <FileDocIcon color={c} />;
  };
  const renderNodes = (nodes, scopeId, depth, keyPrefix) => {
    return (nodes || []).map((node, i) => {
      const nodeKey = keyPrefix + i;
      const stateKey = scopeId + ":" + nodeKey;
      const isExpanded = !!expandedIds[stateKey];
      const isSelected = selectedNode && selectedNode._key === stateKey;
      const badge = node.badge ? BADGE_COLORS[node.badge] : null;
      const hasDetail = node.detail && typeof node.detail === "object";
      const isDir = node.kind === "dir";
      const handleClick = () => {
        if (isDir) {
          setExpandedIds(prev => ({
            ...prev,
            [stateKey]: !prev[stateKey]
          }));
        }
        if (hasDetail) {
          setSelectedNode(isSelected ? null : {
            ...node,
            _key: stateKey
          });
        } else if (isDir && !hasDetail) {}
      };
      return <div key={stateKey} className="dx-node-wrap">
          <button type="button" className={"dx-node" + (isSelected ? " dx-node-selected" : "")} style={{
        paddingLeft: depth * 14 + 8 + "px"
      }} onClick={handleClick} aria-pressed={isSelected ? "true" : "false"}>
            {isDir ? <span className="dx-chevron" style={{
        transform: isExpanded ? "rotate(90deg)" : "rotate(0deg)"
      }}>
                <ChevronRight />
              </span> : <span className="dx-chevron-spacer" />}
            {getFileIcon(node)}
            <span className="dx-node-name">{node.name}</span>
            {badge && <span className="dx-badge-dot" style={{
        background: badge.dot
      }} title={UI.badgeLabels[node.badge] || node.badge} />}
          </button>
          {isDir && isExpanded && node.children && node.children.length > 0 && <div className="dx-children">
              {renderNodes(node.children, scopeId, depth + 1, nodeKey + "-")}
            </div>}
        </div>;
    });
  };
  const renderDetail = () => {
    if (!selectedNode || !selectedNode.detail) {
      return <div className="dx-detail-empty">
          <svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" style={{
        opacity: 0.25,
        marginBottom: "10px"
      }}>
            <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
            <polyline points="14 2 14 8 20 8" />
            <line x1="16" y1="13" x2="8" y2="13" />
            <line x1="16" y1="17" x2="8" y2="17" />
          </svg>
          <span>{lang === "en" ? "Select a file or folder" : "點選左側項目查看說明"}</span>
        </div>;
    }
    const d = selectedNode.detail;
    const c = DIR_COLORS[selectedNode.color] || DIR_COLORS.default;
    const badge = selectedNode.badge ? BADGE_COLORS[selectedNode.badge] : null;
    return <div className="dx-detail-inner">
        {d.breadcrumb && <div className="dx-breadcrumb">{d.breadcrumb}</div>}

        <div className="dx-detail-title-row">
          {getFileIcon(selectedNode)}
          <span className="dx-detail-title">{d.title || selectedNode.name}</span>
          {badge && <span className="dx-pill" style={{
      color: badge.dot,
      borderColor: badge.dot + "55",
      background: badge.dot + "18"
    }}>
              {UI.badgeTexts[selectedNode.badge]}
            </span>}
        </div>

        {d.tagline && <div className="dx-tagline">{d.tagline}</div>}

        {d.whenItLoads && <div className="dx-when-card">
            <div className="dx-when-label">{UI.whenLoads}</div>
            <div className="dx-when-body">{d.whenItLoads}</div>
          </div>}

        {d.description && <div className="dx-description">{d.description}</div>}

        {d.tips && d.tips.length > 0 && <div className="dx-tips-card">
            <div className="dx-tips-label">{UI.tips}</div>
            <ul className="dx-tips-list">
              {d.tips.map((tip, i) => <li key={i} className="dx-tips-item">{tip}</li>)}
            </ul>
          </div>}

        {d.example && d.example.code && <div className="dx-code-block">
            <div className="dx-code-header">
              <span className="dx-code-filename">{d.example.filename || ""}</span>
              <button type="button" className="dx-copy-btn" onClick={() => handleCopy(d.example.code)}>
                {copiedFlag ? UI.copied : UI.copy}
              </button>
            </div>
            <pre className="dx-code-pre"><code>{d.example.code}</code></pre>
          </div>}

        {d.mapsTo && <div className="dx-maps-card">
            <div className="dx-maps-label">{UI.mapsToLabel}</div>
            <div className="dx-maps-body">{d.mapsTo}</div>
          </div>}
      </div>;
  };
  const accentColor = isDark ? ACCENT_DARK : ACCENT_LIGHT;
  const css = `
  .dx-root {
    --dx-bg: #FAF8F3;
    --dx-surface: rgba(0,0,0,0.025);
    --dx-border: rgba(0,0,0,0.09);
    --dx-text: #2b2722;
    --dx-dim: #6f6a62;
    --dx-faint: #8a8378;
    --dx-accent: #bf7551;
    --dx-accent-bg: rgba(191,117,81,0.08);
    --dx-accent-border: rgba(191,117,81,0.30);
    --dx-when-bg: rgba(91,108,143,0.07);
    --dx-when-border: rgba(91,108,143,0.35);
    --dx-when-label: #46587a;
    --dx-tips-bg: rgba(191,117,81,0.06);
    --dx-code-bg: #1A1918;
    --dx-code-text: #e2ddd7;
    --dx-code-header: #2a2826;
    --dx-maps-bg: rgba(138,111,142,0.09);
    --dx-maps-border: rgba(138,111,142,0.35);
    --dx-maps-label: #6f5673;
    border: 1px solid var(--dx-border);
    border-radius: 12px;
    background: var(--dx-bg);
    color: var(--dx-text);
    overflow: hidden;
    display: flex;
    min-height: 560px;
  }
  .dark .dx-root {
    --dx-bg: #1b1a18;
    --dx-surface: rgba(255,255,255,0.03);
    --dx-border: rgba(255,255,255,0.08);
    --dx-text: #e7e3da;
    --dx-dim: #a8a299;
    --dx-faint: #8a8378;
    --dx-accent: #cf8a68;
    --dx-accent-bg: rgba(207,138,104,0.09);
    --dx-accent-border: rgba(207,138,104,0.30);
    --dx-when-bg: rgba(91,108,143,0.14);
    --dx-when-border: rgba(91,108,143,0.42);
    --dx-when-label: #9fb0d4;
    --dx-tips-bg: rgba(207,138,104,0.07);
    --dx-code-bg: #121110;
    --dx-code-text: #d8d4ce;
    --dx-code-header: #1e1c1a;
    --dx-maps-bg: rgba(138,111,142,0.14);
    --dx-maps-border: rgba(138,111,142,0.42);
    --dx-maps-label: #c4a8c8;
  }

  /* ── 左面板 ── */
  .dx-left {
    width: min(264px, 38%);
    min-width: 196px;
    flex-shrink: 0;
    border-right: 1px solid var(--dx-border);
    display: flex;
    flex-direction: column;
    overflow: hidden;
  }
  /* scope bar 強制單列：scope 按鈕收縮溢出省略，展開鈕固定不擠掉 */
  .dx-scope-bar {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 7px 8px 6px;
    border-bottom: 1px solid var(--dx-border);
    flex-wrap: nowrap;
  }
  .dx-scope-btn {
    flex: 1 1 0;
    min-width: 0;
    font-size: 11px;
    font-weight: 600;
    padding: 4px 7px;
    border-radius: 6px;
    border: 1px solid transparent;
    background: transparent;
    color: var(--dx-dim);
    cursor: pointer;
    transition: background 0.13s, color 0.13s, border-color 0.13s;
    font: inherit;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .dx-scope-btn:hover {
    background: var(--dx-surface);
    color: var(--dx-text);
  }
  .dx-scope-btn.dx-scope-active {
    background: var(--dx-accent-bg);
    border-color: var(--dx-accent-border);
    color: var(--dx-accent);
  }
  .dx-expand-btn {
    flex-shrink: 0;
    font-size: 10.5px;
    padding: 4px 7px;
    border-radius: 6px;
    border: 1px solid var(--dx-border);
    background: transparent;
    color: var(--dx-faint);
    cursor: pointer;
    transition: color 0.13s, background 0.13s;
    font: inherit;
    white-space: nowrap;
    letter-spacing: 0.01em;
  }
  .dx-expand-btn:hover {
    background: var(--dx-surface);
    color: var(--dx-text);
  }
  .dx-tree {
    flex: 1 1 0;
    overflow-y: auto;
    padding: 6px 0 10px;
  }
  .dx-tree::-webkit-scrollbar { width: 5px; }
  .dx-tree::-webkit-scrollbar-thumb { background: var(--dx-border); border-radius: 4px; }
  .dx-node-wrap { display: flex; flex-direction: column; }
  .dx-node {
    display: flex;
    align-items: center;
    gap: 5px;
    width: 100%;
    text-align: left;
    background: transparent;
    border: none;
    border-left: 2px solid transparent;
    cursor: pointer;
    padding-top: 4px;
    padding-bottom: 4px;
    padding-right: 10px;
    color: var(--dx-text);
    font: inherit;
    font-size: 13px;
    line-height: 1.4;
    transition: background 0.12s, border-color 0.12s;
    -webkit-tap-highlight-color: transparent;
  }
  .dx-node:hover {
    background: var(--dx-surface);
  }
  .dx-node-selected {
    border-left-color: var(--dx-accent);
    background: var(--dx-accent-bg);
    color: var(--dx-text);
  }
  .dx-chevron {
    display: flex;
    align-items: center;
    flex-shrink: 0;
    color: var(--dx-faint);
    width: 13px;
  }
  .dx-chevron-spacer { width: 13px; flex-shrink: 0; }
  .dx-node-name {
    flex: 1 1 0;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  /* 狀態 badge 改小圓角方塊（非外部文件站的圓點），保持自家識別 */
  .dx-badge-dot {
    width: 5.5px;
    height: 5.5px;
    border-radius: 1.5px;
    transform: rotate(45deg);
    flex-shrink: 0;
    margin-left: 2px;
    opacity: 0.85;
  }

  /* ── 右詳情面板 ── */
  .dx-right {
    flex: 1 1 0;
    min-width: 0;
    overflow-y: auto;
    padding: 20px 24px;
    display: flex;
    flex-direction: column;
  }
  .dx-right::-webkit-scrollbar { width: 5px; }
  .dx-right::-webkit-scrollbar-thumb { background: var(--dx-border); border-radius: 4px; }
  .dx-detail-empty {
    flex: 1 1 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    color: var(--dx-faint);
    font-size: 13px;
    gap: 4px;
    text-align: center;
  }
  .dx-detail-inner {
    display: flex;
    flex-direction: column;
    gap: 14px;
  }
  .dx-breadcrumb {
    font-size: 11.5px;
    color: var(--dx-faint);
    font-family: monospace;
    letter-spacing: 0.01em;
  }
  .dx-detail-title-row {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
  }
  .dx-detail-title {
    font-size: 22px;
    font-weight: 700;
    line-height: 1.25;
    color: var(--dx-text);
  }
  .dx-pill {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    padding: 2px 8px;
    border-radius: 20px;
    border: 1px solid;
    flex-shrink: 0;
  }
  .dx-tagline {
    font-size: 13.5px;
    color: var(--dx-dim);
    line-height: 1.5;
    margin-top: -4px;
  }
  /* 載入時機卡走自家樣式：左緣色條 + 暖中性底（非外部文件站的藍框卡） */
  .dx-when-card {
    background: var(--dx-when-bg);
    border: none;
    border-left: 3px solid var(--dx-when-border);
    border-radius: 4px 10px 10px 4px;
    padding: 11px 14px;
  }
  .dx-when-label {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--dx-when-label);
    margin-bottom: 5px;
  }
  .dx-when-body {
    font-size: 13.5px;
    color: var(--dx-text);
    line-height: 1.55;
  }
  .dx-description {
    font-size: 15px;
    line-height: 1.65;
    color: var(--dx-dim);
  }
  .dx-tips-card {
    background: var(--dx-tips-bg);
    border-radius: 8px;
    padding: 11px 14px 12px;
  }
  .dx-tips-label {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--dx-accent);
    margin-bottom: 7px;
  }
  .dx-tips-list {
    margin: 0;
    padding-left: 18px;
    display: flex;
    flex-direction: column;
    gap: 5px;
  }
  .dx-tips-item {
    font-size: 13.5px;
    color: var(--dx-dim);
    line-height: 1.55;
  }
  .dx-code-block {
    border-radius: 9px;
    overflow: hidden;
    border: 1px solid rgba(255,255,255,0.06);
  }
  .dx-code-header {
    background: var(--dx-code-header);
    padding: 7px 12px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
  }
  .dx-code-filename {
    font-size: 11.5px;
    font-family: monospace;
    color: var(--dx-faint);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }
  .dx-copy-btn {
    flex-shrink: 0;
    font-size: 11px;
    font-weight: 600;
    padding: 3px 9px;
    border-radius: 5px;
    border: 1px solid rgba(255,255,255,0.12);
    background: rgba(255,255,255,0.06);
    color: #c0bbb4;
    cursor: pointer;
    transition: background 0.13s, color 0.13s;
    font: inherit;
    font-size: 11px;
    font-weight: 600;
  }
  .dx-copy-btn:hover {
    background: rgba(255,255,255,0.12);
    color: #e2ddd7;
  }
  .dx-code-pre {
    margin: 0;
    background: var(--dx-code-bg);
    padding: 14px 16px;
    overflow-x: auto;
    font-size: 12.5px;
    line-height: 1.6;
    color: var(--dx-code-text);
    font-family: "JetBrains Mono", "Fira Code", "Cascadia Code", monospace;
    tab-size: 2;
  }
  .dx-code-pre::-webkit-scrollbar { height: 5px; }
  .dx-code-pre::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.12); border-radius: 3px; }
  .dx-maps-card {
    background: var(--dx-maps-bg);
    border: 1px solid var(--dx-maps-border);
    border-radius: 8px;
    padding: 11px 14px;
  }
  .dx-maps-label {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--dx-maps-label);
    margin-bottom: 5px;
  }
  .dx-maps-body {
    font-size: 13.5px;
    color: var(--dx-dim);
    line-height: 1.55;
  }

  /* ── 手機堆疊 ── */
  @media (max-width: 700px) {
    .dx-root { flex-direction: column; min-height: unset; }
    .dx-left {
      width: 100%;
      min-width: unset;
      border-right: none;
      border-bottom: 1px solid var(--dx-border);
      max-height: 260px;
    }
    .dx-right { padding: 16px; }
    .dx-detail-title { font-size: 18px; }
  }
  `;
  return <div className="dx-root">
      <style>{css}</style>

      {}
      <div className="dx-left">
        <div className="dx-scope-bar">
          {safeScopes.map(scope => <button key={scope.id} type="button" className={"dx-scope-btn" + (scope.id === activeScopeId ? " dx-scope-active" : "")} onClick={() => switchScope(scope.id)}>
              {scope.label}
            </button>)}
          <button type="button" className="dx-expand-btn" onClick={isAllExpanded() ? handleCollapseAll : handleExpandAll} title={isAllExpanded() ? UI.collapseAll : UI.expandAll}>
            {isAllExpanded() ? "⊟" : "⊞"}
          </button>
        </div>

        <div className="dx-tree" role="tree">
          {renderNodes(tree, activeScopeId, 0, "")}
        </div>
      </div>

      {}
      <div className="dx-right">
        {renderDetail()}
      </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 跟 .mcp.json 不在 .claude/ 裡，放錯位置 Claude 讀不到。",
"settings.local.json 沒加進 .gitignore，個人設定就推給全隊了。",
"rules/ 下的 .md 不會自動載入，沒在 settings.json 的 rules 路徑裡就是死檔。",
"改了 output style 沒 /clear，本 session 永遠用舊的，因為系統提示在起手就鎖定。",
"subagent 沒設 memory: frontmatter，根本就沒有 agent-memory 目錄。",
"三種 memory: 範圍寫進的目錄不一樣，project / local / user 搞混就寫錯地方。",
"跨工具照抄 .claude/ 路徑，Codex 的 skills 在 .agents/ 不是 .codex/，直接踩坑。",
]}
/>

<Info>
  **這頁是 Part IV 的地圖**

  Part IV（04-0 到 04-11）涵蓋 Claude Code 的整個客製化層。這一頁的任務是先給你全局：`.claude` 目錄下每個檔案與資料夾各是什麼、何時載入、要不要提交版控。有了這張地圖，後面 04-1 到 04-11 逐機制深入時才不會迷路。

  **與 02-6 的分界**：本頁是 Claude 自家 `.claude/` 目錄的完整參考；[02-6](/code-agent/configuration/other-tools-comparison) 是跨工具對照（Claude vs Codex vs Antigravity vs Copilot）。想知道「Codex 的同等設定在哪」去 02-6，想知道「這個 `.claude/` 裡的檔案是什麼」查本頁。

  **補充五個無專篇主題**：output-styles、keybindings、themes、workflows、agent-memory 在 Part IV 沒有獨立單元，本頁第 5 節補到可操作。
</Info>

## 學習目標

* [ ] 能說出 `.claude/` 目錄下每個檔案與資料夾的用途、載入時機，以及該提交還是該 gitignore。
* [ ] 能分辨哪些檔案在專案根（`CLAUDE.md`、`.mcp.json`、`.worktreeinclude`）而非 `.claude/` 內。
* [ ] 能設定 output-styles、keybindings、themes 這三個個人化面，並說出 workflows 與 agent-memory 的存放位置。
* [ ] 能把任一檔案對應到它的深讀單元，知道要查細節時去哪一篇。

<Warning>
  **時效聲明**

  目錄結構與檔名查證截至 2026-06，來源為官方互動式目錄頁 `code.claude.com/docs/zh-TW/claude-directory` \[1] 與各對應主題頁。Claude Code 改版頻繁，動手前以官方當前頁為準。
</Warning>

***

## 互動式目錄全覽

點選左側任一項目，右側顯示該檔案的用途、載入時機與操作提示。切換上方的 **Project** 與 **Global** 標籤分別查看專案層與使用者層。

<DirExplorer
  lang="zh"
  scopes={[
{
  id: "project",
  label: "Project",
  tree: [
    {
      name: "CLAUDE.md",
      kind: "file",
      color: "blue",
      badge: "committed",
      detail: {
        breadcrumb: "（repo 根目錄）/ CLAUDE.md",
        title: "CLAUDE.md",
        tagline: "每 session 起手全量載入的專案指令主檔",
        whenItLoads: "每次 session 啟動時全量讀入，與 ~/.claude/CLAUDE.md 並存載入；衝突時專案層優先。",
        description: "放專案慣例、常用指令、架構脈絡、維護鐵則。也可放在 .claude/CLAUDE.md（兩個位置等效，官方建議根目錄）。不是 settings.json，這裡是 context，不是 enforced 設定。",
        tips: [
          "放在 repo 根目錄（不是 .claude/ 裡），放錯 Claude 讀不到。",
          "長度超出 context window 會被截斷：關鍵鐵則放前面，細節抽到 rules/ 用 paths: 按需載入。",
          "可用 @filename 語法 import 其他 .md，把大型 CLAUDE.md 拆成多檔管理。"
        ],
        example: {
          filename: "CLAUDE.md",
          code: `# My Project

## 常用指令
- 安裝：\`npm install\`
- 測試：\`npm test\`
- 建置：\`npm run build\`

## 架構脈絡
src/api/ 為 REST endpoints，src/domain/ 為純業務邏輯，
兩者不可互相 import。

@.claude/rules/security.md`
        },
        mapsTo: "~/.claude/CLAUDE.md（個人跨專案指令）"
      }
    },
    {
      name: "CLAUDE.local.md",
      kind: "file",
      color: "default",
      badge: "gitignored",
      detail: {
        breadcrumb: "（repo 根目錄）/ CLAUDE.local.md",
        title: "CLAUDE.local.md",
        tagline: "本機私有設定，gitignored",
        whenItLoads: "每 session 起手載入，與 CLAUDE.md 合併，不提交版控。",
        description: "放只有你自己機器需要的設定：沙盒 URL、本機測試帳號、本地路徑。這些不應推給團隊，所以 gitignored。",
        tips: [
          "確認 .gitignore 有 CLAUDE.local.md 這一行，否則個人設定會推給全隊。",
          "與 CLAUDE.md 合併載入，不是取代，兩者同時生效。"
        ]
      }
    },
    {
      name: ".mcp.json",
      kind: "file",
      color: "purple",
      badge: "committed",
      detail: {
        breadcrumb: "（repo 根目錄）/ .mcp.json",
        title: ".mcp.json",
        tagline: "專案級 MCP 伺服器設定，團隊共享",
        whenItLoads: "session 啟動時建立連線；工具 schema 預設延遲載入（lazy-load）。",
        description: "定義這個專案用到的 MCP 伺服器。提交後整個團隊共用同一份設定。個人專屬的 MCP（只有你要用的）放 ~/.claude.json 而非此處。",
        tips: [
          "放在 repo 根目錄，不是 .claude/ 裡。",
          "個人 MCP 伺服器放 ~/.claude.json 的 mcpServers 欄位，不要推進專案。"
        ],
        example: {
          filename: ".mcp.json",
          code: `{
"mcpServers": {
"filesystem": {
  "command": "npx",
  "args": ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"]
}
}
}`
        },
        mapsTo: "~/.claude.json 的 mcpServers（個人 MCP）"
      }
    },
    {
      name: ".worktreeinclude",
      kind: "file",
      color: "default",
      badge: "committed",
      detail: {
        breadcrumb: "（repo 根目錄）/ .worktreeinclude",
        title: ".worktreeinclude",
        tagline: "建立 git worktree 時要複製的 gitignored 檔清單",
        whenItLoads: "建立 git worktree 時讀取。",
        description: "用 .gitignore 語法列出在建立新 worktree 時要從主 repo 複製過去的 gitignored 檔（例如 .env）。這樣每個 worktree 都能有自己的環境變數副本，而不用手動複製。",
        tips: [
          "只影響 git worktree 建立流程，平時 session 不讀。",
          "常見用途：.env 檔在 .gitignore 裡但 worktree 需要，列在這裡就自動複製。"
        ]
      }
    },
    {
      name: ".claude",
      kind: "dir",
      color: "blue",
      children: [
        {
          name: "settings.json",
          kind: "file",
          color: "gray",
          badge: "committed",
          detail: {
            breadcrumb: ".claude/ settings.json",
            title: "settings.json",
            tagline: "專案共享的 enforced 設定（不是 context，是執行規則）",
            whenItLoads: "每 session 起手讀入，與 ~/.claude/settings.json 合併；陣列跨層合併，純量取最近層。",
            description: "控制權限（allow / deny list）、hooks（PreToolUse / PostToolUse / Stop）、預設 model、環境變數、statusLine、outputStyle 等。與 CLAUDE.md 最大的差別：這裡的設定是被 enforced 的，Claude 不能無視；CLAUDE.md 只是 context，Claude 可以選擇不遵循（雖然通常會）。",
            tips: [
              "hooks 寫在這裡：PostToolUse 做自動格式化、PreToolUse 做安全檢查、Stop 做 session 結束驗證。",
              "deny list 格式：{ \"permissions\": { \"deny\": [\"Bash(rm -rf *)\", \"Read(**/.env*)\"] } }",
              "settings.local.json 可以個人覆寫這裡的設定，且不進版控。"
            ],
            example: {
              filename: ".claude/settings.json",
              code: `{
"permissions": {
"allow": ["Bash(npm run *)", "Bash(git *)"],
"deny": ["Bash(rm -rf *)", "Read(**/.env*)"]
},
"hooks": {
"PostToolUse": [{
  "matcher": "Write|Edit",
  "hooks": [{ "type": "command", "command": "npx prettier --write $CLAUDE_TOOL_INPUT_FILE_PATH" }]
}]
},
"model": "claude-sonnet-4-5"
}`
            },
            mapsTo: "~/.claude/settings.json（全域預設，被專案層覆寫）"
          }
        },
        {
          name: "settings.local.json",
          kind: "file",
          color: "gray",
          badge: "gitignored",
          detail: {
            breadcrumb: ".claude/ settings.local.json",
            title: "settings.local.json",
            tagline: "個人覆寫 settings.json，gitignored",
            whenItLoads: "與 settings.json 同時讀入，純量取本層（最近層優先），陣列跨層合併。",
            description: "與 settings.json 完全相同的 schema，但 gitignored。用來放你個人在這個專案的設定覆寫：session 期間核准的額外權限就存這裡，不是 settings.json。",
            tips: [
              "必須在 .gitignore 裡：沒有就會把個人核准的 permission 推給全隊。",
              "session 期間你手動核准的工具權限會自動存入這個檔，不用手寫。"
            ]
          }
        },
        {
          name: "rules",
          kind: "dir",
          color: "purple",
          children: [
            {
              name: "security.md",
              kind: "file",
              color: "purple",
              badge: "committed",
              detail: {
                breadcrumb: ".claude/rules/ security.md（範例）",
                title: "rules/<name>.md",
                tagline: "主題範圍的規則檔，按需或全量載入",
                whenItLoads: "無 paths: frontmatter：等同 CLAUDE.md 每 session 起手載入。有 paths: frontmatter：只在 Claude 讀到符合 glob 的檔案時才載入。",
                description: "把 CLAUDE.md 拆出來的主題規則：安全邊界、coding style、測試要求、commit 格式等。按主題分檔後，有 paths: 限定時只在相關場景載入，降低 context 消耗。",
                tips: [
                  "paths: frontmatter 範例：paths: ['src/api/**'] — 只在 Claude 讀到 src/api/ 底下的檔案時才載入這份規則。",
                  "無 paths: 的規則等同 CLAUDE.md 起手全量載入，不要把太長的說明文字放這裡。",
                  "規則是 context，不是 enforced 設定。若要 enforce 行為（如 deny list）用 settings.json。"
                ],
                example: {
                  filename: ".claude/rules/security.md",
                  code: `---
description: 安全規則：不讀 .env，不寫 credentials
paths: ["src/auth/**", "src/api/**"]
---

# 安全規則

- 禁止讀取 .env 或任何含有 secrets 的檔案。
- 任何包含 API key 或 token 的字串不得寫入原始碼。
- 新增 API endpoint 必須加認證 middleware。`
                }
              }
            },
            {
              name: "<name>.md",
              kind: "file",
              color: "purple",
              detail: {
                breadcrumb: ".claude/rules/ <name>.md",
                title: "rules/*.md（命名規則）",
                tagline: "一個主題一個檔，用語意化檔名",
                description: "建議命名：house-style.md（排版）、coding-standards.md（程式碼）、testing.md（測試）、security.md（安全）、git-workflow.md（版控）。沒有限制，但語意化命名讓維護者一眼看出作用範圍。",
                tips: [
                  "rules/ 沒有子目錄限制，可以 rules/frontend/react.md 這樣分組。",
                  "Global 層（~/.claude/rules/）與專案層（.claude/rules/）同時生效，不互斥。"
                ]
              }
            }
          ]
        },
        {
          name: "skills",
          kind: "dir",
          color: "yellow",
          children: [
            {
              name: "security-review",
              kind: "dir",
              color: "yellow",
              children: [
                {
                  name: "SKILL.md",
                  kind: "file",
                  color: "yellow",
                  badge: "committed",
                  detail: {
                    breadcrumb: ".claude/skills/security-review/ SKILL.md",
                    title: "SKILL.md（完整範例：security-review）",
                    tagline: "可由 /security-review 或 Claude 自動叫用的 skill",
                    whenItLoads: "你輸入 /security-review，或 Claude 依 description 判斷應呼叫時載入。",
                    description: "每個 skill 是一個子目錄，SKILL.md 是入口。frontmatter 的 description 決定 Claude 何時自動叫用；directory 可附帶 references/（參考資料）與 scripts/（輔助腳本）。",
                    tips: [
                      "description 要明確：Claude 靠這段文字決定自動叫用時機，太模糊就不會觸發。",
                      "references/ 放 Claude 執行 skill 時需要查閱的輔助文件（checklist、範本）。",
                      "scripts/ 放 skill 需要呼叫的輔助腳本（shell、Python），skill 可以用 Bash 工具執行它們。"
                    ],
                    example: {
                      filename: ".claude/skills/security-review/SKILL.md",
                      code: `---
name: security-review
description: >
Triggered automatically when modifying authentication, authorization,
user input handling, database queries, or cryptographic operations.
Run /security-review explicitly for a full audit of the current diff.
---

# Security Review Skill

## 執行步驟

1. 掃描 diff 中所有涉及 auth / input / DB / crypto 的異動。
2. 對照 references/owasp-top10.md 的清單逐項檢查。
3. 回報：CRITICAL（必修）/ HIGH（建議修）/ INFO（注意）三個等級。
4. CRITICAL 發現時停止並請使用者確認再繼續。`
                    }
                  }
                },
                {
                  name: "references",
                  kind: "dir",
                  color: "yellow",
                  detail: {
                    breadcrumb: ".claude/skills/security-review/ references/",
                    title: "references/（選用）",
                    tagline: "skill 執行時查閱的輔助資料",
                    description: "放 checklist、範本、標準文件。Claude 在執行 skill 時可以 Read 這些檔案。references/ 與 scripts/ 都是選用，不需要就不建立。"
                  }
                },
                {
                  name: "scripts",
                  kind: "dir",
                  color: "yellow",
                  detail: {
                    breadcrumb: ".claude/skills/security-review/ scripts/",
                    title: "scripts/（選用）",
                    tagline: "skill 可呼叫的輔助腳本",
                    description: "放 shell script、Python script 等。SKILL.md 可以指示 Claude 用 Bash 工具執行這裡的腳本，讓 skill 可以做自動化操作（跑 linter、產報告等）。"
                  }
                }
              ]
            },
            {
              name: "<skill-name>",
              kind: "dir",
              color: "yellow",
              detail: {
                breadcrumb: ".claude/skills/ <skill-name>/",
                title: "skills/<name>/（命名規則）",
                tagline: "一個 skill 一個子目錄，目錄名即命令名",
                description: "目錄名決定斜線命令名稱：skills/add-content/ 就是 /add-content。同名時 skills/ 優先於 commands/ 的舊式單檔命令。跨專案個人 skill 放 ~/.claude/skills/。"
              }
            }
          ]
        },
        {
          name: "commands",
          kind: "dir",
          color: "green",
          children: [
            {
              name: "<name>.md",
              kind: "file",
              color: "green",
              badge: "committed",
              detail: {
                breadcrumb: ".claude/commands/ <name>.md",
                title: "commands/<name>.md",
                tagline: "舊式單檔斜線命令，新工作流建議改用 skills/",
                whenItLoads: "你輸入 /<name> 時載入。",
                description: "commands/ 與 skills/ 現在是同一機制，差別只在目錄結構：commands/ 是單一 .md 檔，skills/ 是子目錄（可含 references/ / scripts/）。同名時 skills/ 優先。新工作流建議直接用 skills/，commands/ 留給已有的舊式命令。",
                tips: [
                  "若命令不需要附帶輔助資料或腳本，用 commands/ 的單檔形式就夠了。",
                  "同名時 skills/ 優先：有 skills/foo/ 就不會執行 commands/foo.md。"
                ]
              }
            }
          ]
        },
        {
          name: "output-styles",
          kind: "dir",
          color: "teal",
          children: [
            {
              name: "<name>.md",
              kind: "file",
              color: "teal",
              badge: "committed",
              detail: {
                breadcrumb: ".claude/output-styles/ <name>.md",
                title: "output-styles/<name>.md",
                tagline: "替換或附加系統提示，調整 Claude 的工作模式",
                whenItLoads: "session 起手讀入系統提示時（起手後不重載，改完要 /clear）。",
                description: "output style 是附加到系統提示的一段文字，預設會替換掉 Claude Code 的內建軟體工程任務指令。用來把 Claude Code 調成寫程式以外的用途（教學、審查模式）。個人風格放 ~/.claude/output-styles/，專案共享放這裡。",
                tips: [
                  "frontmatter keep-coding-instructions: true 可同時保留內建任務指令，適合「在原有基礎上加規則」。",
                  "改了 output style 要 /clear 或開新 session 才生效：系統提示在 session 起手就鎖定。",
                  "用 /config 選擇，或在 settings.json 設 outputStyle key。"
                ],
                example: {
                  filename: ".claude/output-styles/review-mode.md",
                  code: `---
name: 審查模式
description: 每完成一個任務後解釋設計決策，小改動留給使用者自己實作
keep-coding-instructions: true
---

每完成一個任務，補一段「為什麼這樣設計」說明關鍵取捨。
改動少於 10 行時，用 TODO(human) 標記留給使用者實作，不自己寫。`
                }
              }
            }
          ]
        },
        {
          name: "agents",
          kind: "dir",
          color: "rose",
          children: [
            {
              name: "*.md",
              kind: "file",
              color: "rose",
              badge: "committed",
              detail: {
                breadcrumb: ".claude/agents/ *.md",
                title: "agents/*.md",
                tagline: "subagent 定義：獨立 context、工具集、可指定 model",
                whenItLoads: "Task 工具被呼叫時，或你在對話中明確叫用 subagent 名稱時。",
                description: "每個 .md 定義一個 subagent。subagent 在獨立的 context window 中運行，有自己的工具集，可以指定不同的 model（如用 haiku 跑輕量任務）。主 session 可以同時啟動多個 subagent 平行處理。",
                tips: [
                  "frontmatter 可設 model: claude-haiku-4-5 讓輕量 subagent 省 token。",
                  "tools: 欄位限定這個 subagent 能用哪些工具，是安全邊界的一部分。",
                  "memory: project / local / user 決定 subagent 的記憶範圍（見第 5.5 節）。"
                ],
                example: {
                  filename: ".claude/agents/code-reviewer.md",
                  code: `---
name: code-reviewer
description: >
Run after writing or modifying any code. Reviews for correctness,
security issues, and code quality. Invoked automatically after edits.
model: claude-sonnet-4-5
tools: [Read, Grep, Glob]
---

# Code Reviewer

審查最近的程式碼異動，回報 CRITICAL / HIGH / MEDIUM 三個等級的問題。
不主動修改程式碼，只提供具體可行的改善建議。`
                }
              }
            }
          ]
        },
        {
          name: "workflows",
          kind: "dir",
          color: "rose",
          children: [
            {
              name: "*.js",
              kind: "file",
              color: "rose",
              badge: "committed",
              detail: {
                breadcrumb: ".claude/workflows/ *.js",
                title: "workflows/*.js",
                tagline: "動態 multi-agent 協調腳本，需 v2.1.154+",
                whenItLoads: "你輸入 /<name>（檔名即命令名）時在背景執行。",
                description: "runtime 在背景執行的 JavaScript 腳本，用來動態生成並協調數十到數百個 subagent。不是手寫的：跑 /workflows 按 s 存檔產生。每個 .js 成為一個 /<name> 命令。專案層同名覆寫個人層（~/.claude/workflows/）。",
                tips: [
                  "需要 Claude Code v2.1.154+，舊版沒有這個功能。",
                  "關閉方式：/config 切 Dynamic workflows，或 settings.json 設 disableWorkflows: true，或環境變數 CLAUDE_CODE_DISABLE_WORKFLOWS=1。",
                  "內建的 /deep-research 就是一個 workflow，可以參考它的結構。"
                ]
              }
            }
          ]
        },
        {
          name: "agent-memory",
          kind: "dir",
          color: "rose",
          children: [
            {
              name: "<agent-name>",
              kind: "dir",
              color: "rose",
              children: [
                {
                  name: "MEMORY.md",
                  kind: "file",
                  color: "rose",
                  badge: "committed",
                  detail: {
                    breadcrumb: ".claude/agent-memory/<agent>/ MEMORY.md",
                    title: "agent-memory/<agent>/MEMORY.md",
                    tagline: "subagent 的專案層持久記憶（memory: project）",
                    whenItLoads: "subagent 啟動時讀入前 200 行（上限 25 KB）。",
                    description: "subagent 在 frontmatter 設 memory: project 時自動建立並維護。存放 subagent 跨 session 需要記住的資訊。與主 session 的自動記憶（~/.claude/projects/<repo>/memory/MEMORY.md）完全分開，不要混淆。",
                    tips: [
                      "你不手寫這個檔案，subagent 自己維護它。",
                      "memory: local 寫到 agent-memory-local/（gitignored）；memory: user 寫到 ~/.claude/agent-memory/（跨專案）。",
                      "subagent 沒設 memory: frontmatter 就完全沒有記憶目錄，不會自動建立。"
                    ]
                  }
                }
              ]
            }
          ]
        }
      ]
    }
  ]
},
{
  id: "global",
  label: "Global ~/.claude",
  tree: [
    {
      name: ".claude.json",
      kind: "file",
      color: "gray",
      detail: {
        breadcrumb: "~/ .claude.json",
        title: ".claude.json",
        tagline: "app 狀態、UI 偏好、OAuth、個人 MCP（用 /config 管，不手編）",
        whenItLoads: "Claude Code 啟動時讀入，由工具管理，不手工編輯。",
        description: "存 app 狀態、UI 偏好（主題、語言）、OAuth session、per-project 信任決策、個人 MCP 伺服器。大多數欄位由 /config 和 Claude Code 自動管理。IDE 切換旗標（autoConnectIde 等）在這裡；session 期間手動核准的 permission 則存在 .claude/settings.local.json。",
        tips: [
          "個人 MCP 伺服器（只有你要用的）放這裡的 mcpServers 欄位，不要推進專案的 .mcp.json。",
          "用 /config 管理，避免手動修改出現格式錯誤導致 Claude Code 無法啟動。"
        ],
        mapsTo: "（無對等的專案層檔案，這是全域 app 狀態）"
      }
    },
    {
      name: ".claude",
      kind: "dir",
      color: "default",
      children: [
        {
          name: "CLAUDE.md",
          kind: "file",
          color: "blue",
          detail: {
            breadcrumb: "~/.claude/ CLAUDE.md",
            title: "~/.claude/CLAUDE.md",
            tagline: "個人跨專案指令，每 session 與專案 CLAUDE.md 並存載入",
            whenItLoads: "每次 session 起手，與專案層 CLAUDE.md 並存載入；衝突時專案層優先。",
            description: "放你個人在所有專案都適用的偏好和規則：慣用語言、輸出格式要求、思維原則等。專案層 CLAUDE.md 更具體、優先級更高。",
            tips: [
              "不要把機密或機器本地路徑放這裡：這個檔在你的 home 目錄，但若你備份 dotfiles 就可能外流。",
              "與專案 CLAUDE.md 並存，兩者都會載入；衝突時專案層優先。"
            ]
          }
        },
        {
          name: "settings.json",
          kind: "file",
          color: "gray",
          detail: {
            breadcrumb: "~/.claude/ settings.json",
            title: "~/.claude/settings.json",
            tagline: "套用所有專案的全域預設設定",
            whenItLoads: "每 session 起手，被專案層 .claude/settings.json 的同名 key 覆寫。",
            description: "全域預設值：deny list、hooks、預設 model 等。專案層的設定更具體並優先。適合放「所有專案都要遵守」的安全邊界（如全域 deny .env 讀寫）。",
            tips: [
              "陣列類設定（如 hooks）跨層合併：全域 hooks + 專案 hooks 都會生效。",
              "純量（如 model）取最近層：專案設定了就用專案的，沒設才用這裡的全域值。"
            ],
            mapsTo: ".claude/settings.json（專案層，優先級更高）"
          }
        },
        {
          name: "keybindings.json",
          kind: "file",
          color: "gray",
          detail: {
            breadcrumb: "~/.claude/ keybindings.json",
            title: "keybindings.json",
            tagline: "自訂互動式 CLI 快捷鍵，需 v2.1.18+",
            whenItLoads: "CLI 啟動時讀入，支援熱重載（改動立即生效，不需重啟）。",
            description: "重綁互動式 CLI 的鍵盤快捷鍵。支援多種 context（Chat、Autocomplete、Settings 等）分別設定。設為 null 解除綁定；支援 chord（空格分隔的連按）。",
            tips: [
              "用 /keybindings 建立或開啟這個檔（附 JSON schema），比手寫更安全。",
              "/doctor 會報告綁定衝突警告。",
              "保留鍵不可重綁：Ctrl+C、Ctrl+D、Ctrl+M、Caps Lock。"
            ],
            example: {
              filename: "~/.claude/keybindings.json",
              code: `{
"bindings": [
{
  "context": "Chat",
  "bindings": {
    "ctrl+e": "chat:externalEditor",
    "ctrl+u": null
  }
}
]
}`
            }
          }
        },
        {
          name: "themes",
          kind: "dir",
          color: "teal",
          children: [
            {
              name: "<name>.json",
              kind: "file",
              color: "teal",
              detail: {
                breadcrumb: "~/.claude/themes/ <name>.json",
                title: "themes/<name>.json",
                tagline: "自訂 CLI 配色主題：base preset + overrides 色票",
                whenItLoads: "session 起手讀入，支援熱重載。",
                description: "定義自訂主題：選一個內建 base（light / dark）加上 overrides 色票。用 /theme 互動建立，或手寫 JSON。選了自訂主題後偏好存成 custom:<slug>。",
                tips: [
                  "用 /theme 互動建立比手寫 JSON 更不易出錯。",
                  "支援熱重載：改動後不需重啟 CLI 就生效。"
                ],
                example: {
                  filename: "~/.claude/themes/dracula.json",
                  code: `{
"name": "Dracula",
"base": "dark",
"overrides": {
"claude": "#bd93f9",
"error": "#ff5555",
"success": "#50fa7b"
}
}`
                }
              }
            }
          ]
        },
        {
          name: "rules",
          kind: "dir",
          color: "purple",
          children: [
            {
              name: "*.md",
              kind: "file",
              color: "purple",
              detail: {
                breadcrumb: "~/.claude/rules/ *.md",
                title: "~/.claude/rules/*.md",
                tagline: "跨專案個人規則，與專案層同時生效",
                description: "與 .claude/rules/ 完全相同的機制，作用於你的所有專案。適合放跨專案都適用的個人規範（寫作風格、安全邊界、輸出偏好等）。"
              }
            }
          ]
        },
        {
          name: "skills",
          kind: "dir",
          color: "yellow",
          children: [
            {
              name: "<name>/SKILL.md",
              kind: "file",
              color: "yellow",
              detail: {
                breadcrumb: "~/.claude/skills/ <name>/SKILL.md",
                title: "~/.claude/skills/<name>/SKILL.md",
                tagline: "跨專案個人 skill",
                description: "與 .claude/skills/ 完全相同的機制，但跨所有專案生效。適合放個人常用的工作流（code-review、research、debug 等）。"
              }
            }
          ]
        },
        {
          name: "agents",
          kind: "dir",
          color: "rose",
          children: [
            {
              name: "*.md",
              kind: "file",
              color: "rose",
              detail: {
                breadcrumb: "~/.claude/agents/ *.md",
                title: "~/.claude/agents/*.md",
                tagline: "跨專案個人 subagent",
                description: "與 .claude/agents/ 完全相同的機制，跨所有專案生效。適合放個人常用的 subagent 定義（如各種 reviewer、researcher）。"
              }
            }
          ]
        },
        {
          name: "projects",
          kind: "dir",
          color: "amber",
          children: [
            {
              name: "<repo-path>",
              kind: "dir",
              color: "amber",
              children: [
                {
                  name: "memory",
                  kind: "dir",
                  color: "amber",
                  children: [
                    {
                      name: "MEMORY.md",
                      kind: "file",
                      color: "amber",
                      badge: "autogen",
                      detail: {
                        breadcrumb: "~/.claude/projects/<repo>/memory/ MEMORY.md",
                        title: "~/.claude/projects/<repo>/memory/MEMORY.md",
                        tagline: "主 session 自動記憶（v2.1.59+，前 200 行或 25 KB）",
                        whenItLoads: "每 session 起手載入前 200 行（上限 25KB），v2.1.59+ 功能。",
                        description: "這是你的主 session 的跨 session 自動記憶，不是 subagent 記憶。Claude Code 自己維護這個檔案，紀錄跨 session 值得記住的資訊。你可以直接讀這個檔，但不要手動大幅改寫（Claude 的增量更新邏輯會出錯）。",
                        tips: [
                          "這個檔的路徑是 ~/.claude/projects/<hash-of-repo-path>/memory/MEMORY.md，不是你的 repo 裡面的檔案。",
                          "與 .claude/agent-memory/ 完全分開：這是主 session 的記憶，不是 subagent 的記憶。",
                          "可以讀，但不要大幅手改：Claude 用增量方式更新，手寫可能讓格式亂掉。"
                        ]
                      }
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    }
  ]
}
]}
/>

***

## 1. 先分清三個位置家族

`.claude` 相關的檔案散在三個地方，先釘住這個分界，後面逐項才不會錯位：

| 家族            | 位置                                                               | 提交版控                       | 誰看得到       |
| ------------- | ---------------------------------------------------------------- | -------------------------- | ---------- |
| 專案根           | repo 根目錄（`CLAUDE.md`、`.mcp.json`、`.worktreeinclude`）             | 多數提交                       | 團隊         |
| 專案 `.claude/` | repo 內 `.claude/` 目錄                                             | 多數提交，`*.local.*` gitignore | 團隊（個人覆寫除外） |
| 使用者層          | `~/.claude/`（Windows：`%USERPROFILE%\.claude\`）與 `~/.claude.json` | 不提交（機器本地）                  | 只有你        |

最常踩的錯是把 `CLAUDE.md`、`.mcp.json` 當成 `.claude/` 裡的檔案。它們在**專案根**，不在 `.claude/` 內 \[1]。

## 2. 五個目前沒有專門單元的主題

Part IV 的 04-1 到 04-11 各有深寫單元，以下五個例外，這裡補到可操作。

### 2.1 output-styles：改寫系統提示的工作模式

output style 是附加到系統提示的一段文字，預設**會替換掉內建的軟體工程任務指令**，用來把 Claude Code 調成寫程式以外的用途（教學、審查模式）\[2]。

* 內建四種：`Default`、`Proactive`、`Explanatory`、`Learning`。
* 自訂：放 `~/.claude/output-styles/<name>.md`（個人）或 `.claude/output-styles/`（專案共享）。frontmatter 欄位：`name`、`description`、`keep-coding-instructions`（預設 `false`；設 `true` 保留內建任務指令）、`force-for-plugin`（plugin 專用）。
* 選用：`/config` 選 Output style，或在 `settings.json` 設 `outputStyle` key。系統提示在 session 起始固定（為了快取），**改後要 `/clear` 或開新 session 才生效**。

### 2.2 keybindings：自訂快捷鍵

`~/.claude/keybindings.json` 重綁互動式 CLI 的鍵（需 v2.1.18+）\[3]。

* 格式：`{ "bindings": [{ "context": "Chat", "bindings": { "ctrl+e": "chat:externalEditor", "ctrl+u": null } }] }`。設 `null` 解除綁定，支援 chord（空格分隔的連按）。
* context 分多種（`Global`、`Chat`、`Autocomplete`、`Settings` 等），綁定限定在特定介面區域。
* 保留鍵不可重綁：`Ctrl+C`、`Ctrl+D`、`Ctrl+M`、`Caps Lock`。
* 用 `/keybindings` 建立或開檔（附 schema），`/doctor` 會顯示綁定衝突警告。改動自動偵測、熱重載。

### 2.3 themes：自訂配色

`~/.claude/themes/<name>.json` 定義主題，內容是一個內建 `base` preset 加一組 `overrides` 色票 \[1]。用 `/theme` 互動建立或手寫 JSON；選了自訂主題後偏好存成 `custom:<slug>`。讀取於 session 起始並熱重載。

```json theme={null}
{
  "name": "Dracula",
  "base": "dark",
  "overrides": { "claude": "#bd93f9", "error": "#ff5555", "success": "#50fa7b" }
}
```

### 2.4 workflows：動態多代理腳本

`.claude/workflows/<name>.js`（專案）或 `~/.claude/workflows/`（個人）是 runtime 在背景執行的 JavaScript 腳本，用來生成並協調數十到數百個 subagent，需 Claude Code v2.1.154+ \[1, 4]。不是手寫的，而是從 `/workflows` 跑一輪後按 `s` 存檔產生。每個 `.js` 成為一個 `/<name>` 命令；專案層同名覆寫個人層。要關閉：`/config` 切 Dynamic workflows、`settings.json` 設 `disableWorkflows: true`、或環境變數 `CLAUDE_CODE_DISABLE_WORKFLOWS=1` \[4]。

### 2.5 agent-memory：subagent 的持久記憶

subagent 在 frontmatter 設 `memory:` 才會有專屬記憶目錄，存放位置依範圍而定 \[1]：

| frontmatter       | 寫入位置                                     | 提交         | 範圍    |
| ----------------- | ---------------------------------------- | ---------- | ----- |
| `memory: project` | `.claude/agent-memory/<agent>/MEMORY.md` | committed  | 團隊共享  |
| `memory: local`   | `.claude/agent-memory-local/`            | gitignored | 本機本專案 |
| `memory: user`    | `~/.claude/agent-memory/`                | 本機         | 跨專案   |

運作方式同主 session 自動記憶：subagent 自己讀寫，起手載入前 200 行（上限 25 KB），你不手寫。

## 3. 動手做：盤點你的 `.claude/`

<Steps>
  <Step title="列出現有項目">
    在你常用專案跑 `ls -la .claude/` 與 `ls -la ~/.claude/`，對照上方互動式目錄，列出你已有與還沒用到的項目。
  </Step>

  <Step title="檢查 gitignore">
    對每個已有檔案問一句：它該不該提交？`settings.local.json`、`CLAUDE.local.md`、`agent-memory-local/` 必須在 `.gitignore`；漏掉就會把個人設定推給團隊。
  </Step>

  <Step title="試裝一個個人化面">
    挑一個還沒用的個人化面試裝：用 `/theme` 建一個主題，或 `/keybindings` 綁一個常用鍵，確認熱重載生效。
  </Step>

  <Step title="檢查 output style 現值">
    跑 `/config` 看 output style 現值，若你常做非寫程式的任務（審查、教學），試切一個內建 style。
  </Step>
</Steps>

## 4. 常見誤區

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

  * **把 `CLAUDE.md` / `.mcp.json` 當成 `.claude/` 內的檔案**：它們在專案根。放錯位置 Claude 讀不到。
  * **漏 gitignore 個人層**：`settings.local.json`、`CLAUDE.local.md`、`.claude/agent-memory-local/` 一旦提交，就把你的個人覆寫與本機記憶推給全隊。
  * **以為改 output style / 主題立刻生效**：output style 與系統提示在 session 起始固定，改完要 `/clear` 或開新 session。
  * **把 subagent 記憶與主 session 記憶混為一談**：兩者目錄不同、範圍不同，`memory:` frontmatter 沒設就根本沒有 subagent 記憶。
  * **跨工具照抄路徑**：`.claude/` 的結構不會原樣搬到 Codex / Antigravity，逐格對位見 [02-6](/code-agent/configuration/other-tools-comparison)。
</Warning>

## 自我檢核

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

  1. 給你 `.claude/` 下任一檔名，你能說出它的用途、何時載入、該不該提交，以及去哪一篇查細節嗎？
  2. 你能說出哪三個檔在專案根而非 `.claude/` 內嗎？
  3. 你知道 output style、keybindings、themes 各自的設定檔位置與生效時機嗎？
  4. subagent 的三種 `memory:` 範圍分別寫到哪裡、哪個會進版控？
</Check>

## 來源與延伸閱讀

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

<div className="references">
  * \[1] Anthropic, "探索 .claude 目錄"（互動式檔案參考，逐檔列出位置、載入時機、提交與否與範例），Claude Code Docs. Accessed: 2026-06. \[Online]. Available: [https://code.claude.com/docs/zh-TW/claude-directory](https://code.claude.com/docs/zh-TW/claude-directory) （截至 2026-06）

  * \[2] Anthropic, "Output styles"（內建四種、自訂 frontmatter、`outputStyle` 設定與生效時機），Claude Code Docs. Accessed: 2026-06. \[Online]. Available: [https://code.claude.com/docs/en/output-styles](https://code.claude.com/docs/en/output-styles) （截至 2026-06）

  * \[3] Anthropic, "Keybindings"（`~/.claude/keybindings.json`、context 與 action、chord、保留鍵），Claude Code Docs. Accessed: 2026-06. \[Online]. Available: [https://code.claude.com/docs/en/keybindings](https://code.claude.com/docs/en/keybindings) （截至 2026-06）

  * \[4] Anthropic, "Orchestrate subagents at scale with dynamic workflows"（`.claude/workflows/*.js` runtime 背景執行、生成並協調數十至數百個 subagent，從 `/workflows` 按 `s` 存檔、每檔成 `/<name>`、專案覆寫個人、需 v2.1.154+、`disableWorkflows` 或 `CLAUDE_CODE_DISABLE_WORKFLOWS=1` 關閉），Claude Code Docs. Accessed: 2026-06. \[Online]. Available: [https://code.claude.com/docs/en/workflows](https://code.claude.com/docs/en/workflows) （截至 2026-06）
</div>

* 各檔深讀單元：[02-3 settings.json](/code-agent/configuration/settings-json)、[02-4 claude.json](/code-agent/configuration/claude-json)、[04-1 CLAUDE.md 與記憶](/code-agent/customization/claude-md-memory)、[04-2 rules](/code-agent/customization/rules)、[04-3 commands](/code-agent/customization/commands)、[04-4 skills](/code-agent/customization/skills)、[04-5 subagents](/code-agent/customization/subagents)、[04-6 hooks](/code-agent/customization/hooks)、[04-9 MCP](/code-agent/customization/mcp-integration)。
* 其他工具目錄對等：[02-6 其他工具設定對照](/code-agent/configuration/other-tools-comparison)。
