> ## 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-11 Agent Teams 與 Sub Agent：差異、啟用、協作與獨立作業

> Sub Agent 一次性執行後消滅，Agent Teams 可定址、持續存活、可彼此傳訊。本單元釐清兩者的生命週期差異、啟用方式，並列舉三種協作模式，讓你在設計自動化流程時選對工具、不過度工程化。

export const ToolCompare = ({lang = "zh", tools = [], dimensions = [], defaultSelected, notes = []}) => {
  const UI = lang === "en" ? {
    allTools: "All",
    recommend: "Recommended",
    noSupport: "N/A",
    minOneToolW: "Select at least one tool",
    mobileLabel: "Tool",
    dimensionLbl: "Dimension",
    notes: "Notes"
  } : {
    allTools: "全選",
    recommend: "推薦",
    noSupport: "無對應",
    minOneToolW: "至少選一個工具",
    mobileLabel: "工具",
    dimensionLbl: "維度",
    notes: "注意事項"
  };
  const ACCENT_L = "#bf7551";
  const ACCENT_D = "#cf8a68";
  const REC_BDR_L = "rgba(191,117,81,0.45)";
  const REC_BG_L = "rgba(191,117,81,0.06)";
  const REC_BDR_D = "rgba(207,138,104,0.45)";
  const REC_BG_D = "rgba(207,138,104,0.08)";
  const looksLikePath = val => typeof val === "string" && (/[/\\.*:]/).test(val);
  const safeTools = Array.isArray(tools) ? tools : [];
  const safeDimensions = Array.isArray(dimensions) ? dimensions : [];
  if (safeTools.length === 0 || safeDimensions.length === 0) return null;
  const allIds = safeTools.map(t => t.id);
  const initSelected = Array.isArray(defaultSelected) && defaultSelected.length > 0 ? defaultSelected.filter(id => allIds.includes(id)) : allIds;
  const [selectedIds, setSelectedIds] = useState(initSelected.length > 0 ? initSelected : allIds);
  const [expandedCell, setExpandedCell] = useState(null);
  const [mobileTool, setMobileTool] = useState(initSelected[0] || allIds[0]);
  const [isDark, setIsDark] = useState(false);
  useEffect(() => {
    const detect = () => setIsDark(document.documentElement.classList.contains("dark"));
    detect();
    const obs = new MutationObserver(detect);
    obs.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["class"]
    });
    return () => obs.disconnect();
  }, []);
  const toggleTool = id => {
    setSelectedIds(prev => {
      const next = prev.includes(id) ? prev.filter(x => x !== id) : [...prev, id];
      if (next.length === 0) return prev;
      if (expandedCell) {
        const [, cellToolId] = expandedCell.split(":");
        if (!next.includes(cellToolId)) setExpandedCell(null);
      }
      return next;
    });
  };
  const isAllSelected = selectedIds.length === allIds.length;
  const toggleAll = () => {
    if (isAllSelected) {
      setSelectedIds([allIds[0]]);
    } else {
      setSelectedIds(allIds);
    }
    setExpandedCell(null);
  };
  const visibleTools = safeTools.filter(t => selectedIds.includes(t.id));
  const cellKey = (dimId, toolId) => dimId + ":" + toolId;
  const toggleExpand = (dimId, toolId) => {
    const key = cellKey(dimId, toolId);
    setExpandedCell(prev => prev === key ? null : key);
  };
  const renderValue = cell => {
    if (cell.na) {
      return <span className="tc-na">{UI.noSupport}</span>;
    }
    const useMono = cell.mono === true || cell.mono !== false && looksLikePath(cell.value);
    return useMono ? <code className="tc-code">{cell.value}</code> : <span>{cell.value}</span>;
  };
  const css = `
  /* ── 根容器 ── */
  .tc-root {
    --tc-bg:           #FAF8F3;
    --tc-surface:      rgba(0,0,0,0.022);
    --tc-stripe:       rgba(0,0,0,0.028);
    --tc-border:       rgba(0,0,0,0.09);
    --tc-text:         #2b2722;
    --tc-dim:          #6f6a62;
    --tc-faint:        #8a8378;
    --tc-accent:       ${ACCENT_L};
    --tc-accent-bg:    ${REC_BG_L};
    --tc-accent-bdr:   ${REC_BDR_L};
    --tc-expand-bg:    rgba(0,0,0,0.016);
    --tc-code-bg:      rgba(0,0,0,0.055);
    --tc-na-color:     #9a9490;
    --tc-pill-on-bg:   rgba(191,117,81,0.10);
    --tc-pill-on-bdr:  rgba(191,117,81,0.35);
    --tc-pill-on-txt:  #a05c38;
    border: 1px solid var(--tc-border);
    border-radius: 14px;
    background: var(--tc-bg);
    color: var(--tc-text);
    overflow: hidden;
    font-size: 14px;
  }
  .dark .tc-root {
    --tc-bg:           #1b1a18;
    --tc-surface:      rgba(255,255,255,0.03);
    --tc-stripe:       rgba(255,255,255,0.025);
    --tc-border:       rgba(255,255,255,0.08);
    --tc-text:         #e7e3da;
    --tc-dim:          #a8a299;
    --tc-faint:        #706b64;
    --tc-accent:       ${ACCENT_D};
    --tc-accent-bg:    ${REC_BG_D};
    --tc-accent-bdr:   ${REC_BDR_D};
    --tc-expand-bg:    rgba(255,255,255,0.022);
    --tc-code-bg:      rgba(255,255,255,0.08);
    --tc-na-color:     #6e6b65;
    --tc-pill-on-bg:   rgba(207,138,104,0.12);
    --tc-pill-on-bdr:  rgba(207,138,104,0.35);
    --tc-pill-on-txt:  ${ACCENT_D};
  }

  /* ── 精簡篩選列 ── */
  .tc-filter-bar {
    display: flex;
    align-items: center;
    gap: 0;
    padding: 0 14px;
    border-bottom: 1px solid var(--tc-border);
    background: var(--tc-surface);
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    /* 單行、不折行，高度由內容決定（約 36px） */
    flex-wrap: nowrap;
    white-space: nowrap;
    min-height: 36px;
  }
  .tc-filter-bar::-webkit-scrollbar { display: none; }

  /* 分隔竿（All 後面） */
  .tc-filter-sep {
    flex-shrink: 0;
    width: 1px;
    height: 14px;
    background: var(--tc-border);
    margin: 0 10px 0 6px;
    align-self: center;
  }

  /* pill 基底 — 極輕量文字標籤 */
  .tc-pill {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 5px 9px;
    border-radius: 5px;
    border: 1px solid transparent;
    background: transparent;
    color: var(--tc-faint);
    font: inherit;
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0.01em;
    cursor: pointer;
    transition: color 0.12s, background 0.12s, border-color 0.12s;
    flex-shrink: 0;
    white-space: nowrap;
    /* 行高對齊 filter-bar */
    margin: 5px 1px;
  }
  .tc-pill:hover {
    color: var(--tc-text);
    background: rgba(0,0,0,0.04);
  }
  .dark .tc-pill:hover {
    background: rgba(255,255,255,0.05);
  }
  /* 選中態：細框 + 淡底 + 文字加深（非按鈕感，保持輕量） */
  .tc-pill-on {
    color: var(--tc-pill-on-txt);
    background: var(--tc-pill-on-bg);
    border-color: var(--tc-pill-on-bdr);
    font-weight: 600;
  }
  /* 全選 pill — 略小一點字型 */
  .tc-pill-all {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    padding: 4px 8px;
    color: var(--tc-dim);
  }
  .tc-pill-all.tc-pill-on {
    color: var(--tc-pill-on-txt);
  }
  /* 選中小圓點 */
  .tc-pill-dot {
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--tc-accent);
    flex-shrink: 0;
  }

  /* ── 桌面表格 ── */
  .tc-table-wrap {
    overflow: hidden;
  }
  /* Mintlify 的 MDX 渲染器會自動把 <table> 包進 data-table-wrapper：
   * 加 -mx-[var(--page-padding)] 負邊距 + w-[calc(100%+padding*2)] 全寬 + py-[1em]，
   * 讓表格往外溢出，撐破 tc-root 的圓角容器（2026-06-12 線上實證跑版）。
   * 中和它：邊距歸零、寬度收回 100%、把橫向捲動容器設在這層（sticky 左欄靠它）。 */
  .tc-root [data-table-wrapper] {
    margin: 0 !important;
    width: 100% !important;
    max-width: 100% !important;
    padding: 0 !important;
    overflow-x: auto;
    contain: none !important;
  }
  .tc-root [data-table-wrapper] > div {
    padding: 0 !important;
    margin: 0 !important;
  }
  .tc-root [data-table-wrapper]::-webkit-scrollbar { height: 4px; }
  .tc-root [data-table-wrapper]::-webkit-scrollbar-thumb { background: var(--tc-border); border-radius: 2px; }
  .tc-table {
    width: 100%;
    border-collapse: collapse;
    margin: 0 !important;
  }

  /* 表頭 */
  .tc-thead th {
    padding: 9px 15px;
    text-align: left;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--tc-faint);
    border-bottom: 2px solid var(--tc-border);
    background: var(--tc-surface);
    white-space: nowrap;
  }
  /* 維度欄（sticky 左欄） */
  .tc-thead th:first-child,
  .tc-td-dim {
    position: sticky;
    left: 0;
    z-index: 1;
  }
  .tc-thead th:first-child {
    width: 160px;
    min-width: 130px;
    background: var(--tc-surface);
    border-right: 1px solid var(--tc-border);
    z-index: 2;
  }

  /* 維度標籤欄 */
  .tc-td-dim {
    padding: 13px 15px;
    font-size: 12.5px;
    font-weight: 700;
    color: var(--tc-dim);
    vertical-align: middle;
    white-space: nowrap;
    border-bottom: 1px solid var(--tc-border);
    border-right: 1px solid var(--tc-border);
    background: var(--tc-surface);
  }

  /* 斑馬紋：奇數維度列 */
  .tc-row-even .tc-td-dim,
  .tc-row-even .tc-td {
    background-color: var(--tc-stripe);
  }
  .tc-row-even .tc-td-dim {
    background: color-mix(in srgb, var(--tc-surface) 70%, var(--tc-stripe) 30%);
  }

  /* 資料儲存格 */
  .tc-td {
    padding: 0;
    border-bottom: 1px solid var(--tc-border);
    border-left: 1px solid var(--tc-border);
    vertical-align: top;
    min-width: 150px;
  }
  .tc-td-inner {
    display: flex;
    flex-direction: column;
  }

  /* 主值行（可點擊） */
  .tc-cell-btn {
    display: flex;
    align-items: flex-start;
    gap: 6px;
    width: 100%;
    text-align: left;
    background: transparent;
    border: none;
    padding: 13px 15px;
    color: inherit;
    font: inherit;
    font-size: 13px;
    line-height: 1.5;
    cursor: pointer;
    transition: background 0.11s;
    -webkit-tap-highlight-color: transparent;
  }
  .tc-cell-btn:hover {
    background: rgba(0,0,0,0.03);
  }
  .dark .tc-cell-btn:hover {
    background: rgba(255,255,255,0.03);
  }
  .tc-cell-btn-on {
    background: var(--tc-expand-bg);
  }

  /* 推薦標記：左 3px accent 邊框 + 淡底 */
  .tc-td-recommend {
    border-left: 3px solid var(--tc-accent-bdr);
    background: var(--tc-accent-bg);
  }
  .tc-td-recommend .tc-cell-btn:hover {
    background: rgba(191,117,81,0.05);
  }

  /* recommend 角標：超小 badge */
  .tc-rec-badge {
    flex-shrink: 0;
    margin-top: 1px;
    font-size: 9px;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--tc-accent);
    border: 1px solid var(--tc-accent-bdr);
    border-radius: 3px;
    padding: 1px 4px;
    white-space: nowrap;
    opacity: 0.85;
  }

  /* na 樣式 */
  .tc-na {
    font-style: italic;
    color: var(--tc-na-color);
    font-size: 12.5px;
    opacity: 0.7;
  }

  /* 等寬值 */
  .tc-code {
    font-family: "JetBrains Mono", "Fira Code", "Cascadia Code", monospace;
    font-size: 12px;
    background: var(--tc-code-bg);
    border-radius: 3px;
    padding: 1px 4px;
    word-break: break-all;
  }

  /* 展開詳情列 */
  .tc-detail-row td {
    padding: 0;
    border-bottom: 1px solid var(--tc-border);
  }
  .tc-detail-cell {
    padding: 10px 15px 12px;
    font-size: 12.5px;
    line-height: 1.65;
    color: var(--tc-dim);
    background: var(--tc-expand-bg);
    border-top: 1px dashed var(--tc-border);
    border-left: 1px solid var(--tc-border);
  }
  .tc-detail-cell:first-child {
    border-left: none;
    font-weight: 700;
    color: var(--tc-faint);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    vertical-align: top;
    padding-top: 12px;
    background: var(--tc-surface);
    white-space: nowrap;
    width: 160px;
  }
  .tc-detail-recommend {
    border-left: 3px solid var(--tc-accent-bdr) !important;
    background: var(--tc-accent-bg) !important;
  }

  /* 展開箭頭 */
  .tc-chevron {
    flex-shrink: 0;
    margin-top: 3px;
    opacity: 0.35;
    transition: transform 0.14s, opacity 0.14s;
  }
  .tc-chevron-open {
    transform: rotate(90deg);
    opacity: 0.65;
  }

  /* ── 注腳 ── */
  .tc-notes {
    border-top: 1px solid var(--tc-border);
    padding: 10px 16px 12px;
    display: flex;
    flex-direction: column;
    gap: 4px;
  }
  .tc-notes-label {
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--tc-faint);
    margin-bottom: 3px;
  }
  .tc-note-item {
    font-size: 12.5px;
    color: var(--tc-dim);
    line-height: 1.55;
    padding-left: 14px;
    position: relative;
  }
  .tc-note-item::before {
    content: "*";
    position: absolute;
    left: 2px;
    color: var(--tc-faint);
  }

  /* ── 手機模式 ─────────────────────────────────────────── */
  .tc-mobile { display: none; }
  @media (max-width: 700px) {
    .tc-filter-bar { display: none; }
    .tc-table-wrap  { display: none; }
    .tc-mobile      { display: block; }

    .tc-mob-tabs {
      display: flex;
      overflow-x: auto;
      border-bottom: 1px solid var(--tc-border);
      -webkit-overflow-scrolling: touch;
      scrollbar-width: none;
    }
    .tc-mob-tabs::-webkit-scrollbar { display: none; }
    .tc-mob-tab {
      flex: 1 0 auto;
      padding: 10px 16px;
      background: transparent;
      border: none;
      border-bottom: 2px solid transparent;
      color: var(--tc-dim);
      font: inherit;
      font-size: 13px;
      font-weight: 500;
      cursor: pointer;
      white-space: nowrap;
      transition: color 0.12s, border-color 0.12s;
    }
    .tc-mob-tab-on {
      color: var(--tc-accent);
      border-bottom-color: var(--tc-accent);
      font-weight: 700;
    }
    .tc-mob-cards {
      padding: 12px 0 4px;
    }
    .tc-mob-card {
      border-bottom: 1px solid var(--tc-border);
      padding: 12px 16px;
    }
    .tc-mob-card:last-child { border-bottom: none; }
    .tc-mob-dim {
      font-size: 11px;
      font-weight: 700;
      letter-spacing: 0.05em;
      text-transform: uppercase;
      color: var(--tc-faint);
      margin-bottom: 6px;
    }
    .tc-mob-val {
      font-size: 13.5px;
      line-height: 1.55;
    }
    .tc-mob-rec {
      display: inline-block;
      margin-top: 6px;
      font-size: 9.5px;
      font-weight: 700;
      letter-spacing: 0.05em;
      text-transform: uppercase;
      color: var(--tc-accent);
      border: 1px solid var(--tc-accent-bdr);
      border-radius: 3px;
      padding: 1px 5px;
    }
    .tc-mob-detail {
      margin-top: 7px;
      font-size: 12.5px;
      line-height: 1.65;
      color: var(--tc-dim);
    }
    .tc-notes { padding: 11px 16px 13px; }
  }
  `;
  const renderDesktopTable = () => <div className="tc-table-wrap">
      <table className="tc-table">
        <thead className="tc-thead">
          <tr>
            <th>{UI.dimensionLbl}</th>
            {visibleTools.map(tool => <th key={tool.id}>{tool.label}</th>)}
          </tr>
        </thead>
        <tbody>
          {}
          {safeDimensions.flatMap((dim, dimIdx) => {
    const isAnyExpanded = visibleTools.some(t => expandedCell === cellKey(dim.id, t.id));
    const stripeClass = dimIdx % 2 === 1 ? " tc-row-even" : "";
    const rows = [];
    rows.push(<tr key={dim.id} className={"tc-row" + stripeClass}>
                <td className="tc-td-dim">{dim.label}</td>
                {visibleTools.map(tool => {
      const cell = (dim.cells || ({}))[tool.id] || ({});
      const key = cellKey(dim.id, tool.id);
      const isOpen = expandedCell === key;
      const hasDetail = !!cell.detail;
      const isRec = !!cell.recommend;
      return <td key={tool.id} className={"tc-td" + (isRec ? " tc-td-recommend" : "")}>
                      <div className="tc-td-inner">
                        <button type="button" className={"tc-cell-btn" + (isOpen ? " tc-cell-btn-on" : "")} onClick={hasDetail ? () => toggleExpand(dim.id, tool.id) : undefined} style={hasDetail ? {} : {
        cursor: "default"
      }} aria-expanded={hasDetail ? String(isOpen) : undefined}>
                          <span style={{
        flex: "1 1 0",
        minWidth: 0
      }}>
                            {renderValue(cell)}
                          </span>
                          {isRec && <span className="tc-rec-badge">{UI.recommend}</span>}
                          {hasDetail && <svg className={"tc-chevron" + (isOpen ? " tc-chevron-open" : "")} width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round">
                              <polyline points="9 18 15 12 9 6" />
                            </svg>}
                        </button>
                      </div>
                    </td>;
    })}
              </tr>);
    if (isAnyExpanded) {
      const openToolId = visibleTools.find(t => expandedCell === cellKey(dim.id, t.id))?.id;
      const openCell = openToolId ? (dim.cells || ({}))[openToolId] || ({}) : {};
      if (openCell.detail) {
        const openTool = safeTools.find(t => t.id === openToolId);
        const isRec = !!openCell.recommend;
        rows.push(<tr key={dim.id + "-detail"} className="tc-detail-row">
                    <td className="tc-detail-cell">
                      {openTool ? openTool.label : ""}
                    </td>
                    <td colSpan={visibleTools.length} className={"tc-detail-cell" + (isRec ? " tc-detail-recommend" : "")}>
                      {openCell.detail}
                    </td>
                  </tr>);
      }
    }
    return rows;
  })}
        </tbody>
      </table>
    </div>;
  const renderMobile = () => {
    const activeTool = safeTools.find(t => t.id === mobileTool) || safeTools[0];
    return <div className="tc-mobile">
        <div className="tc-mob-tabs" role="tablist">
          {safeTools.map(tool => <button key={tool.id} type="button" role="tab" aria-selected={tool.id === mobileTool ? "true" : "false"} className={"tc-mob-tab" + (tool.id === mobileTool ? " tc-mob-tab-on" : "")} onClick={() => setMobileTool(tool.id)}>
              {tool.label}
            </button>)}
        </div>

        <div className="tc-mob-cards">
          {safeDimensions.map(dim => {
      const cell = (dim.cells || ({}))[activeTool.id] || ({});
      const isRec = !!cell.recommend;
      return <div key={dim.id} className="tc-mob-card">
                <div className="tc-mob-dim">{dim.label}</div>
                <div className="tc-mob-val">{renderValue(cell)}</div>
                {isRec && <div className="tc-mob-rec">{UI.recommend}</div>}
                {cell.detail && <div className="tc-mob-detail">{cell.detail}</div>}
              </div>;
    })}
        </div>
      </div>;
  };
  return <div className="tc-root">
      <style>{css}</style>

      {}
      <div className="tc-filter-bar">
        <button type="button" className={"tc-pill tc-pill-all" + (isAllSelected ? " tc-pill-on" : "")} onClick={toggleAll} aria-pressed={String(isAllSelected)}>
          {UI.allTools}
        </button>

        {}
        <span className="tc-filter-sep" aria-hidden="true" />

        {safeTools.map(tool => {
    const isOn = selectedIds.includes(tool.id);
    return <button key={tool.id} type="button" className={"tc-pill" + (isOn ? " tc-pill-on" : "")} onClick={() => toggleTool(tool.id)} aria-pressed={String(isOn)}>
              {isOn && <span className="tc-pill-dot" aria-hidden="true" />}
              {tool.label}
            </button>;
  })}
      </div>

      {}
      {visibleTools.length > 0 && renderDesktopTable()}

      {}
      {renderMobile()}

      {}
      {notes.length > 0 && <div className="tc-notes">
          <div className="tc-notes-label">{UI.notes}</div>
          {notes.map((note, i) => <div key={i} className="tc-note-item">{note}</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={[
"Sub Agent 一次性消滅，Agent Teams 持續存活",
"5 worker 平行 = 5× context",
"Worker 用 Haiku，Lead 才用 Sonnet",
"3 個 teammate 起步是過度工程化",
"子任務有依賴關係，平行反而比線性慢",
"訊息往返沒設終止條件，team 靜默卡死",
"teammate 不繼承 SOUL.md，主人格別期待",
]}
/>

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

  Sub Agent 是一次性子任務的執行者：spawn 後處理完返回結論，脈絡不延續。Agent Teams 是可定址、可持續對話、可協作的常駐代理：建立後保有身份，可收訊息、可與其他 Agent 互傳狀態、可搶任務。本單元釐清兩者的生命週期差異、各自的啟用方式，並列舉主從編排、平行獨立分工、Agent 間訊息往返三種協作模式，讓你在設計自動化流程時選對工具、不過度工程化。
</Info>

## 學習目標

讀完本單元，你應該能夠：

* [ ] 分清 Sub Agent（一次性 spawn、結論回傳主線、脈絡不延續）與 Agent Teams（可定址、持續存活、可協作）的本質差異。
* [ ] 說出 Sub Agent 與 Agent Teams 各自的啟用方式及限制（截至 2026-06，Agent Teams 為實驗性功能）。
* [ ] 列舉三種協作模式（主從編排、平行獨立分工、Agent 間訊息往返），並判斷各適用場景。
* [ ] 判斷一個任務該用 Sub Agent、Agent Teams，還是根本不需要多代理。

***

## 1. 兩者定義與核心差異

Anthropic 在 Claude Code v2.1.32 起引入 **Agent Teams** \[1]。它是相對於 [04-5 Subagent](/code-agent/customization/subagents) 的另一層多代理機制：不是「一次 spawn 跑完就消失」，而是「多個 Claude Code 實例以 team 形式組成、共享 task list、互相傳訊、可被使用者與 lead 直接定址」。

<Note>
  **命名澄清**

  本單元以 **Sub Agent** 指 [04-5](/code-agent/customization/subagents) 的 Subagent（一次性、隔離 context、回傳結論）；以 **Agent Teams** 指 Anthropic 文件中的 "agent teams" / teammate（持續、可定址、可協作）。**Subagent 與 Agent Teams 是兩個獨立機制，可以並存**：一個 session 內可以同時有 Subagent 與 Agent Teams，各自扮演不同角色。
</Note>

核心差異（截至 2026-06 依官方 agent teams 章節 \[1]）：

| 維度       | Sub Agent                | Agent Teams                                    |
| -------- | ------------------------ | ---------------------------------------------- |
| 生命週期     | 任務結束即消滅                  | 持續存活直到 lead 拆解 team                            |
| 可定址性     | 不可定址（主動 spawn）           | 可定址（lead / 隊友 / 使用者皆可指名）                       |
| 上下文      | 每次 spawn 全新              | 跨輪次延續（teammate 持續累積自己的脈絡）                      |
| 通訊方式     | 只回傳結論給 caller            | 透過 mailbox 雙向傳訊、共享 task list、idle notification |
| 數量限制     | 同一 session 內可多次 spawn    | 一個 lead 同時只管一個 team \[1]                       |
| 巢狀       | 不能 spawn Subagent        | teammate 不能 spawn team 或其他 teammate \[1]       |
| Token 成本 | 較低（結論摘要回 caller）         | 較高（每個 teammate 一個完整 context window）            |
| 適用場景     | 一次性子任務、唯讀查詢、平行分工（結果不需互動） | 持續協作、需多輪反饋、需共享狀態、需被使用者直接介入                     |

<Tip>
  **與 [01-4 上下文工程](/code-agent/foundations/context-engineering)的銜接**

  Sub Agent 是「把大任務關到 swap partition」、主 RAM 只看到結論。Agent Teams 是「開了 N 個獨立 RAM、可彼此交換訊息」。前者省 context、後者買協作能力。**選錯的代價是 token 燒完卻沒拿到結果，或為了省 token 把多輪對話硬塞進單一 context 使模型輸出品質下降**。
</Tip>

## 2. 啟用方式

### 2.1 Sub Agent（[04-5](/code-agent/customization/subagents) 已展開）

從主 session 或 Skill 用 `Agent(<name>)` 顯式叫用，或讓 Claude 依 `description` 自動委派。Subagent 定義在 `.claude/agents/`、使用者層 `~/.claude/agents/`、plugin `agents/`、managed 設定或 `--agents` CLI flag。生命週期就是「spawn → 跑任務 → 回傳結論 → 結束」。

### 2.2 Agent Teams

**截至 2026-06，Agent Teams 為實驗性功能，預設關閉** \[1]。啟用方式：

```json theme={null}
// .claude/settings.json 或 ~/.claude/settings.json
{
  "env": {
    "CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
  }
}
```

或在 shell 啟動時設環境變數：

```bash theme={null}
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 claude
```

啟用後，在對話中以自然語言請 Claude 建立 team：

```text theme={null}
我要設計一套 CLI 工具追蹤 codebase 裡的 TODO 註解。
建一個 agent team，從三個角度探索：UX、技術架構、唱反調。
```

Claude 會建立 team、spawn teammates、各自探索、合成結論 \[1]。

<Warning>
  **Agent Teams 的當前限制**

  * 預設關閉，需 `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` 啟用。
  * in-process 模式下 `/resume` 與 `/rewind` 不還原 teammates；resume 後 lead 可能嘗試聯絡不存在的 teammate \[1]。
  * task 狀態有時 lag（teammate 沒 mark completed 會卡住 dependent task）\[1]。
  * 同一 lead 同時只管一個 team；要建新 team 先清掉舊的。
  * teammate 不能 spawn 自己的 team 或其他 teammate。
  * lead 是固定的，session 啟動後不能改。
  * 所有 teammate 啟動時繼承 lead 的權限模式；不能個別設。
  * split-pane 模式需要 tmux 或 iTerm2（VS Code integrated terminal、Windows Terminal、Ghostty 不支援）\[1]。
</Warning>

### 2.3 顯示模式

Agent Teams 支援兩種顯示模式 \[1]：

| 模式                      | 設定                           | 行為                                                              |
| ----------------------- | ---------------------------- | --------------------------------------------------------------- |
| in-process（預設 fallback） | `teammateMode: "in-process"` | 所有 teammate 跑在主 terminal 內。`Shift+Down` 循環切換；可對任一 teammate 直接傳訊 |
| split-pane              | `teammateMode: "tmux"`       | 每個 teammate 一個 pane。需 tmux 或 iTerm2 + `it2` CLI                 |

預設 `auto`：在 tmux session 內啟動就用 split-pane，否則 in-process。要強制：

```bash theme={null}
claude --teammate-mode in-process
```

<Note>
  **Windows 上要 split-pane：psmux 或 WSL 的 tmux**

  tmux 與 iTerm2 都不是 Windows native，Windows 使用者預設只會落到 in-process。要在 Windows 用 split-pane，兩條路：

  * **psmux**：Rust 寫的 Windows 原生終端多工器，相容既有 `.tmux.conf`，不需 WSL 或 Cygwin；在 psmux session 內啟動 Claude Code，teammate 會自動進獨立 pane。截至 2026-06 仍屬新專案（版本 0.1.x），導入前自評維護狀態 \[4]。
  * **WSL 內的 tmux**：在 WSL 裝 tmux、於 WSL 終端跑 Claude Code，split-pane 與原生 tmux 行為一致；前提是你的專案與工具鏈在 WSL 側可用。
</Note>

### 2.4 模型選擇

Teammate 預設不繼承 lead 的 `/model` 選擇。要設預設 teammate model：在 Claude Code 內跑 `/config`，選 **Default teammate model**。可選「Default（leader's model）」讓 teammate 跟 lead 用同模型 \[1]。

## 3. 協作模式

### 3.1 主從編排（Orchestrator-Worker）

一個主 agent 拆解任務後依序或並行 spawn 多個 Sub Agent，收集結論後整合。**Sub Agent 互不知曉彼此存在**。

```text theme={null}
Lead: 把這個 PR 拆三塊分析
  ├─ spawn Subagent A (security)
  ├─ spawn Subagent B (performance)
  └─ spawn Subagent C (style)
  收集三份結論，整合成單一回應
```

對應 Sub Agent 機制，Agent Teams 也支援此模式但更貴。**什麼時候用 Sub Agent 即可**：每個 worker 是獨立、唯讀、結論能合併的；worker 之間不需對話。

### 3.2 平行獨立分工

多個 Sub Agent 同時處理不重疊的子任務（各自操作不同檔案或模組），主線最後 merge 結論。**最常見的多代理模式，實作最簡單**。

對應 Sub Agent 機制。Agent Teams 也支援，但同樣是不必要的複雜度。**判斷：worker 之間不需對話、結論可合併 → Sub Agent 就夠**。

### 3.3 Agent 間訊息往返（Peer Messaging）

Agent Teams 之間透過 mailbox 傳遞訊息、協商狀態。**適合流程需要多輪反饋的場景**：

* reviewer 把意見傳回 writer，writer 修改後再傳回 reviewer。
* 多個 investigator 各自提出假說，互相挑戰，達成共識。
* 平行探索的多個角度，最後由 lead 整合成單一結論。

<Note>
  **三種模式的選擇範例**

  **情境 1：code review**
  三個 reviewer（security / performance / test coverage）各自看同一 PR，回傳結論。→ **Sub Agent 就夠**（結論合併、不需對話）。

  **情境 2：研究某個開源專案是否值得採用**
  一個研究 owner agent 派三個 Sub Agent 分頭看「程式碼品質」「社群活躍度」「授權與維護狀況」。三份結論合併出單一建議。→ **Sub Agent 就夠**。

  **情境 3：bug 調查，root cause 不明**
  spawn 5 個 teammate 各自提出一個假說、互相挑戰、留下任何撐過挑戰的證據。→ **Agent Teams 才有價值**（需要訊息往返、辯論結構）。

  **情境 4：writer + reviewer 持續迭代文件草稿**
  writer 起草、reviewer 給意見、writer 修、reviewer 再看，來回多輪直到收斂。→ **Agent Teams**（Sub Agent 一次就消滅，無法多輪對話）。
</Note>

## 4. 相互獨立作業

### 4.1 何時讓 agent 互不干擾

子任務之間**沒有共享可變狀態**（各自讀不同資料、寫不同檔案）→ 平行獨立最省事，無需同步機制。

對應實作：每個 Sub Agent / Teammate 工作在不同 worktree。Git worktree 是物理隔離手段（見 [04-5](/code-agent/customization/subagents)）：

```bash theme={null}
# 為每個 worker 建獨立 worktree
git worktree add ../agent-A -b agent-A-branch
git worktree add ../agent-B -b agent-B-branch
```

### 4.2 何時需要共享狀態

任務 B 的輸入依賴任務 A 的輸出 → 改用**順序編排**（A 跑完才 B 跑）或 **Agent Teams 訊息往返**，不要用平行。

平行分工對**依賴關係**特別脆弱：A 與 B 都被派去「讀同一個檔、修改不同段落」，最後合併時衝突。**事先盤點依賴**：若兩任務共享可變狀態，要嘛順序跑、要嘛 Agent Teams 互相協調。

### 4.3 用 TeammateIdle / TaskCreated / TaskCompleted hooks 強化流程

Agent Teams 提供三個專屬 hook 事件點 \[1, 見 [04-6 Hooks](/code-agent/customization/hooks)]：

* `TeammateIdle`：teammate 即將進入 idle。`exit 2` 給回饋讓它繼續工作。
* `TaskCreated`：task 正在被建立。`exit 2` 阻擋建立。
* `TaskCompleted`：task 正在被標記完成。`exit 2` 阻擋完成並給回饋。

這三個事件是「teammate 協作品質閘門」的位置：teammate 寫完程式碼、沒跑測試就 idle？用 `TeammateIdle` hook 擋下。teammate 標記一個 task 為完成、但 commit message 沒遵守團隊慣例？用 `TaskCompleted` hook 退件。

```json theme={null}
{
  "hooks": {
    "TeammateIdle": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "${CLAUDE_PROJECT_DIR}/.claude/hooks/require-tests.sh"
          }
        ]
      }
    ]
  }
}
```

## 5. 成本與複雜度

### 5.1 不為平行而平行的判準

平行新增額外 context 成本與協調複雜度。**若子任務彼此依賴、或整合結論的複雜度超過拆解的收益，不如線性跑**。

成本評估三題：

1. **子任務間是否真正正交？** 共用輸入、互相讀寫、共享狀態 → 不正交，平行反而慢。
2. **整合結論的難度是否可控？** 若三份結論互相矛盾、需大量二次協調 → 拆解的收益不見了。
3. **平行帶來的加速是否抵消額外 token 費用？** 5 個 Haiku worker vs 1 個 Sonnet 跑完：5 個 worker 燒 5× context，加速 5× 是上限。**真實加速往往只有 2-3×**（受通訊、同步、idle 時間影響）。

### 5.2 模型選型

Worker Agent 盡量用較便宜的模型（Haiku）；只有主 Orchestrator / Lead 需要推理能力時才用 Sonnet / Opus（參見 [04-5](/code-agent/customization/subagents)）。

Agent Teams 預設不繼承 lead 模型（\[1] 第 2.4 節）；明確指定才能省成本：

```text theme={null}
Create a team with 4 teammates to refactor these modules in parallel.
Use Sonnet for each teammate.
```

或用 `/config` 設 default teammate model 為 Haiku 系列。

### 5.3 已知限制

Agent Teams 為實驗性功能，官方明示的限制 \[1]：

* in-process 模式下 resume 不還原 teammates。
* task 狀態可能 lag。
* shutdown 可能慢（teammate 跑完當前 tool call 才停）。
* 一個 lead 只能管一個 team。
* 無巢狀。
* lead 固定、不能轉移。
* 權限模式在 spawn 時決定，啟動後才能改。
* split-pane 模式需 tmux / iTerm2。

<Tip>
  **`CLAUDE.md` 對 teammate 同樣生效**

  官方明示 teammates 會讀 `CLAUDE.md`，作為專案級指引傳遞給所有 teammate \[1]。這是規範 teammate 行為最直接的方式。把跨 teammate 通用的規範寫進 `CLAUDE.md`，不要依賴 lead 每次都交代。
</Tip>

## 6. 工具對照

<ToolCompare
  lang="zh"
  tools={[
{ id: "claude",  label: "Claude Code" },
{ id: "codex",   label: "OpenAI Codex" },
{ id: "gemini",  label: "Google Gemini CLI" },
{ id: "copilot", label: "GitHub Copilot" },
{ id: "cursor",  label: "Cursor" },
]}
  dimensions={[
{
  id: "one-shot",
  label: "一次性子代理",
  cells: {
    claude:  { value: "Sub Agent（`Agent(<name>)` 工具）[2]", recommend: true, detail: "spawn 後執行任務、回傳結論、context 不延續。定義在 .claude/agents/ 或 ~/.claude/agents/，支援 isolation: worktree 物理隔離。" },
    codex:   { value: "無對等原生機制", detail: "OpenAI Codex CLI 為單一 agent 設計，無 spawn 子代理的原生機制；多工作流需手動分拆或透過 API 層級的 Assistants 實現（截至 2026-06，依官方文件 [5]）。" },
    gemini:  { value: "無對等原生機制", detail: "Gemini CLI 為單一 agent 設計，無 spawn 子代理的原生機制；多代理需透過 API 或 LangChain/LangGraph 等框架實現（截至 2026-06，依官方文件 [6]）。" },
    copilot: { value: "無對等原生機制", detail: "GitHub Copilot CLI 以 suggest/explain 模式為主，無 spawn 子代理的原生機制（截至 2026-06，依官方文件 [7]）。" },
    cursor:  { value: "無對等原生機制", detail: "Cursor 以 IDE 整合 agent 為主，無 spawn 子代理的原生機制；多代理需透過 API 層級實現（截至 2026-06，依官方文件 [8]）。" },
  },
},
{
  id: "persistent",
  label: "持續 / 可定址代理",
  cells: {
    claude:  { value: "Agent Teams（v2.1.32+，實驗性）[1]", recommend: true, detail: "多個 Claude Code 實例以 team 形式組成、共享 task list、互相傳訊、可被使用者與 lead 直接定址。以 CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 啟用。" },
    codex:   { value: "OpenAI Assistants API（非 CLI 層）", detail: "OpenAI 提供 Assistants API（含 Threads、Runs、persistent memory），可實現持續可定址代理，但這是 API 層級功能，非 Codex CLI 原生支援（截至 2026-06，依官方 Assistants API 文件 [5]）。" },
    gemini:  { value: "無 CLI 層原生持續代理機制", detail: "Google Gemini CLI 本身無持續可定址代理機制；持續代理需透過 Vertex AI Agent Builder 或 API 層級實現（截至 2026-06，依官方文件 [6]）。" },
    copilot: { value: "無原生持續代理機制", detail: "GitHub Copilot CLI 無持續可定址代理機制；GitHub Copilot 的 Extensions 機制可提供更豐富的工具整合，但不等同於多代理架構（截至 2026-06，依官方文件 [7]）。" },
    cursor:  { value: "無原生持續代理機制", detail: "Cursor 無持續可定址代理機制；Cursor 的 Background Agent 功能為後台執行單一任務，非多代理協作架構（截至 2026-06，依官方文件 [8]）。" },
  },
},
{
  id: "shared-tasks",
  label: "共享 task list",
  cells: {
    claude:  { value: "是（`~/.claude/tasks/<team>/`）[1]", recommend: true },
    codex:   { na: true },
    gemini:  { na: true },
    copilot: { na: true },
    cursor:  { na: true },
  },
},
{
  id: "inter-agent-msg",
  label: "Agent 間訊息",
  cells: {
    claude:  { value: "是（mailbox + `SendMessage`）[1]", recommend: true },
    codex:   { na: true },
    gemini:  { na: true },
    copilot: { na: true },
    cursor:  { na: true },
  },
},
{
  id: "hook-events",
  label: "Teammate hook 事件",
  cells: {
    claude:  { value: "TeammateIdle、TaskCreated、TaskCompleted [1, 3]", recommend: true, detail: "exit 2 可攔截並給回饋；TeammateIdle 用於強制要求 teammate 繼續工作，TaskCompleted 用於品質閘門。" },
    codex:   { na: true },
    gemini:  { na: true },
    copilot: { na: true },
    cursor:  { na: true },
  },
},
{
  id: "display-modes",
  label: "顯示模式",
  cells: {
    claude:  { value: "in-process / split-pane（tmux / iTerm2）[1]", recommend: true, detail: "auto 模式：tmux session 內啟動就用 split-pane，否則 in-process。Windows 用 psmux 或 WSL tmux 取得 split-pane。" },
    codex:   { value: "單一終端機輸出", detail: "Codex CLI 以單一終端機互動或非互動模式呈現輸出，無多 pane 多代理顯示模式（截至 2026-06）。" },
    gemini:  { value: "單一終端機輸出", detail: "Gemini CLI 以單一終端機互動或 --prompt 非互動模式呈現輸出，無多 pane 多代理顯示模式（截至 2026-06）。" },
    copilot: { value: "單一終端機輸出", detail: "GitHub Copilot CLI 以 gh copilot suggest/explain 單一輸出呈現，無多 pane 顯示模式（截至 2026-06）。" },
    cursor:  { value: "IDE 多 pane 整合", detail: "Cursor 以 IDE pane 系統呈現 agent 輸出，非針對多代理協作設計（截至 2026-06）。" },
  },
},
{
  id: "isolation",
  label: "物理隔離手段",
  cells: {
    claude:  { value: "`isolation: worktree`（[2]）", recommend: true, detail: "Subagent frontmatter 設 isolation: worktree，自動建立獨立 git worktree，避免多代理同時操作同一工作目錄的衝突。" },
    codex:   { value: "Docker / 沙箱環境", detail: "Codex CLI 支援 --sandbox 模式，以 Docker 容器隔離執行環境（截至 2026-06，依官方文件 [5]）。" },
    gemini:  { value: "Docker / 沙箱環境", detail: "Gemini CLI 支援 --sandbox 模式，以 Docker 容器隔離執行環境（截至 2026-06，依官方文件 [6]）。" },
    copilot: { value: "本機環境執行", detail: "GitHub Copilot CLI 指令在本機環境執行，無內建容器隔離機制（截至 2026-06，依官方文件 [7]）。" },
    cursor:  { value: "IDE 沙箱 / 遠端環境", detail: "Cursor 的 Background Agent 支援在遠端沙箱環境執行，減少本機環境影響（截至 2026-06，依官方文件 [8]）。" },
  },
},
]}
  notes={[
"Agent Teams（v2.1.32+）為實驗性功能，預設關閉；以 CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1 啟用 [1]。",
"OpenAI Assistants API 提供持續代理概念，但屬 API 層級功能，非 Codex CLI 原生多代理機制。",
"Cursor 為第三方 IDE（Anysphere），本 Playbook 僅短提一欄。",
]}
/>

<Note>
  **命名與邊界**

  * **Agent Teams（v2.1.32+）** 為實驗性功能，預設關閉；以 `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1` 啟用 \[1]。
  * **OpenAI、Google、GitHub Copilot、Cursor** 對多代理的具體機制以各家當前官方文件為準；各欄內容依官方文件截至 2026-06 之公開資訊填入。
  * **Cursor 為第三方 IDE**（Anysphere），本 Playbook 僅短提一欄。
</Note>

## 動手做

<Steps>
  <Step title="三種模式各跑一次（20 分鐘）">
    **主從編排（Sub Agent）**：在當前專案下用三個 Sub Agent 平行做 security / performance / test coverage 三個角度的 review，觀察主線整合結論的成本。

    **平行獨立分工（Sub Agent）**：讓三個 Sub Agent 各自重構三個不同模組，觀察 worktree 隔離是否需要。

    **訊息往返（Agent Teams，需先啟用 `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`）**：建一個 3 個 teammate 的 team 對某個不熟悉的 bug 提出假說、互相挑戰。**觀察 token 成本是否明顯高於 Sub Agent 模式**。
  </Step>

  <Step title="加 hook 強化流程（10 分鐘）">
    在 `.claude/settings.json` 加 `TeammateIdle` hook，跑 `/teammateMode` 切到 `tmux` 模式（或維持 in-process），觀察 hook 是否觸發。
  </Step>
</Steps>

## 常見誤區

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

  * **把有依賴關係的子任務設計成平行分工**：整合時需要大量二次協調，反而比線性慢。先用 [01-5 Workflow Engineering](/code-agent/foundations/workflow-engineering) 釐清誰依賴誰。
  * **Agent Teams 的訊息格式沒有定義終止條件**：造成無窮訊息往返或靜默卡死。**每個訊息交換都有明確 exit condition**（accept / reject / escalate）。
  * **所有 Agent 都用最強模型**：忽略 worker 任務用 Haiku 即可的事實，成本失控。**Worker 用 Haiku、Lead 用 Sonnet/Opus**。
  * **把 Agent Teams 當 Thread 來用**：Agent Teams 是完整 Claude Code 實例，**有完整 context、完整工具、完整權限**，不是「便宜的 Sub Agent」。**預期它吃 token 的量級與一個獨立 session 相同**。
  * **忘了 `CLAUDE.md` 對 teammate 生效**：teammate 不繼承 lead 的對話歷史，但會讀專案的 `CLAUDE.md` \[1]。**把跨 teammate 通用的規範寫進 `CLAUDE.md`，不要依賴 lead 每次都交代**。
  * **用 Agent Teams 跑小任務**：一個 5 行的 grep 用 Sub Agent 即可，team 是為需要協作的多輪工作設計的。**3 個 teammate 起步是過度工程化** \[1]。
</Warning>

## 自我檢核

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

  1. 你能用一張表說出 Sub Agent 與 Agent Teams 在生命週期、可定址性、通訊方式、Token 成本四個維度的差異嗎？
  2. 你能判斷下面三個任務各該用哪一個嗎？
     * 重構三個不同模組（互不依賴）
     * 對某個 bug 提出多個互相挑戰的假說
     * 跨 5 個檔案的功能新增（5 個小任務、每個都自己完整）
  3. 你最近一個多代理設計，子任務之間是真正正交的嗎？還是只是「感覺應該平行」？
  4. 你的 `CLAUDE.md` 有沒有寫明「哪些任務走 Sub Agent、哪些走 Agent Teams」的判準？
</Check>

## 來源與延伸閱讀

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

<div className="references">
  * \[1] Anthropic, "Orchestrate teams of Claude Code sessions," code.claude.com, 2026. \[Online]. Available: [https://code.claude.com/docs/en/agent-teams](https://code.claude.com/docs/en/agent-teams) （截至 2026-06；v2.1.32+ 啟用、`CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1`、mailbox、shared task list、teammate hook 事件、display modes、已知限制）

  * \[2] Anthropic, "Create custom subagents," code.claude.com, 2026. \[Online]. Available: [https://code.claude.com/docs/en/sub-agents](https://code.claude.com/docs/en/sub-agents) （截至 2026-06；Subagent 完整 frontmatter、`isolation: worktree`、`skills` 預載、`Task` → `Agent` 改命名 v2.1.63）

  * \[3] Anthropic, "Hooks," code.claude.com, 2026. \[Online]. Available: [https://code.claude.com/docs/en/hooks](https://code.claude.com/docs/en/hooks) （截至 2026-06；TeammateIdle、TaskCreated、TaskCompleted 事件、`exit 2` 攔截語義）

  * \[4] psmux, "psmux: native terminal multiplexer for Windows," GitHub, 2026. \[Online]. Available: [https://github.com/psmux/psmux](https://github.com/psmux/psmux) （截至 2026-06；Rust 單一二進位、相容 `.tmux.conf`、Windows native 不需 WSL/Cygwin；在 psmux session 內啟動 Claude Code 時 teammate 自動進 pane；版本 0.1.x，屬新專案）

  * \[5] OpenAI, "Codex CLI," developers.openai.com, 2026. \[Online]. Available: [https://developers.openai.com/codex](https://developers.openai.com/codex) （截至 2026-06；Codex CLI 設計為單一 agent，多代理需透過 Assistants API 或 API 層級實現；--sandbox Docker 隔離）

  * \[6] Google, "Gemini CLI," google-gemini.github.io, 2026. \[Online]. Available: [https://google-gemini.github.io/gemini-cli/](https://google-gemini.github.io/gemini-cli/) （截至 2026-06；Gemini CLI 為單一 agent 設計；--sandbox 模式；多代理需透過 Vertex AI Agent Builder 或外部框架實現）

  * \[7] GitHub Docs, "GitHub Copilot CLI," docs.github.com, 2026. \[Online]. Available: [https://docs.github.com/en/copilot/how-tos/copilot-cli](https://docs.github.com/en/copilot/how-tos/copilot-cli) （截至 2026-06；gh copilot suggest/explain 模式；無原生子代理或持續代理機制；Extensions 提供工具整合）

  * \[8] Cursor, "Background Agent," cursor.com, 2026. \[Online]. Available: [https://cursor.com/docs/background-agent](https://cursor.com/docs/background-agent) （截至 2026-06；Background Agent 為後台執行單一任務，非多代理協作；遠端沙箱環境執行）
</div>

* Sub Agent 設計與 `isolation: worktree` 見 [04-5 Subagent](/code-agent/customization/subagents)。
* Skill + Sub Agent 配合見 [04-4 Skills](/code-agent/customization/skills)。
* 跨 agent 整合介面見 [04-9 MCP 整合](/code-agent/customization/mcp-integration)。
* 強制執行見 [04-6 Hooks](/code-agent/customization/hooks)。
* 上下文隔離概念見 [01-4 上下文工程](/code-agent/foundations/context-engineering)。
* 多步任務編排見 [01-5 Workflow Engineering](/code-agent/foundations/workflow-engineering)。
