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

# Hugging Face organization models

> Connect a Hugging Face organization to Endor Labs to scan and score all its AI models.

export const LicenseBadge = ({sku, skus, relation = 'any'}) => {
  const DATA_URL = '/snippets/license-sku-data.json';
  const CACHE_KEY = 'license-sku-data';
  const CACHE_TTL_MS = 60 * 60 * 1000;
  const REGISTRY_KEY = '__licenseSkuRegistry';
  const FALLBACK_LICENSES_URL = '/introduction/licenses';
  const ACCENT = '#26D07C';
  const CONJUNCTION = {
    any: 'or',
    all: 'and'
  };
  const FONT_STACK = '-apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif';
  const [isDark, setIsDark] = useState(false);
  const [data, setData] = useState(null);
  const [hasFetchError, setHasFetchError] = useState(false);
  const skuList = useMemo(() => {
    if (Array.isArray(skus) && skus.length > 0) {
      return skus.filter(code => typeof code === 'string' && code.trim()).map(c => c.trim());
    }
    if (typeof sku === 'string' && sku.trim()) {
      return [sku.trim()];
    }
    return [];
  }, [sku, skus]);
  useEffect(() => {
    const check = () => {
      const root = document.documentElement;
      setIsDark(root.dataset.theme === 'dark' || root.classList.contains('dark'));
    };
    check();
    const observer = new MutationObserver(check);
    observer.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ['data-theme', 'class']
    });
    return () => observer.disconnect();
  }, []);
  useEffect(() => {
    let cancelled = false;
    const readCache = () => {
      try {
        const raw = sessionStorage.getItem(CACHE_KEY);
        if (!raw) return null;
        const parsed = JSON.parse(raw);
        if (Date.now() - parsed.ts > CACHE_TTL_MS) {
          sessionStorage.removeItem(CACHE_KEY);
          return null;
        }
        return parsed.data;
      } catch (e) {
        return null;
      }
    };
    const writeCache = value => {
      try {
        sessionStorage.setItem(CACHE_KEY, JSON.stringify({
          ts: Date.now(),
          data: value
        }));
      } catch (e) {}
    };
    const fetchSkuData = async () => {
      const cached = readCache();
      if (cached) return cached;
      if (!globalThis[REGISTRY_KEY]) {
        globalThis[REGISTRY_KEY] = {};
      }
      const registry = globalThis[REGISTRY_KEY];
      if (registry[CACHE_KEY]) return registry[CACHE_KEY];
      const promise = (async () => {
        const resp = await fetch(DATA_URL);
        if (!resp.ok) throw new Error(`HTTP ${resp.status}`);
        const json = await resp.json();
        writeCache(json);
        return json;
      })();
      registry[CACHE_KEY] = promise;
      promise.finally(() => {
        delete registry[CACHE_KEY];
      });
      return promise;
    };
    fetchSkuData().then(d => {
      if (!cancelled) setData(d);
    }).catch(() => {
      if (!cancelled) setHasFetchError(true);
    });
    return () => {
      cancelled = true;
    };
  }, []);
  const textColor = isDark ? '#e6edf3' : '#1f2937';
  const textMuted = isDark ? 'rgba(230,237,243,0.65)' : 'rgba(31,41,55,0.65)';
  const bannerBackground = isDark ? '#161b22' : '#f6f8fa';
  const borderColor = isDark ? 'rgba(38,208,124,0.35)' : 'rgba(38,208,124,0.45)';
  const linkColor = isDark ? '#4ade80' : '#059669';
  const errorBackground = isDark ? '#3b1111' : '#fef2f2';
  const errorBorder = isDark ? '#7f1d1d' : '#fecaca';
  const errorText = isDark ? '#fecaca' : '#7f1d1d';
  const licensesUrl = data?.licensesPageUrl || FALLBACK_LICENSES_URL;
  const resolveSkuName = code => {
    const entry = data?.skus?.[code];
    if (entry?.name) return entry.name;
    return null;
  };
  const formatSkuLabel = code => {
    const name = resolveSkuName(code);
    if (name) return name;
    return code;
  };
  const joinWithConjunction = (codes, conjunction) => {
    const labels = codes.map(formatSkuLabel);
    if (labels.length === 0) return '';
    if (labels.length === 1) return labels[0];
    if (labels.length === 2) return `${labels[0]} ${conjunction} ${labels[1]}`;
    const head = labels.slice(0, -1).join(', ');
    const tail = labels[labels.length - 1];
    return `${head}, ${conjunction} ${tail}`;
  };
  const buildSkuSentence = codes => {
    const conj = CONJUNCTION[relation] || CONJUNCTION.any;
    const names = joinWithConjunction(codes, conj);
    const noun = codes.length > 1 ? 'licenses' : 'license';
    return `${names} ${noun}`;
  };
  const renderLink = text => <a href={licensesUrl} className="lic-link" style={{
    color: linkColor,
    fontSize: '0.75rem',
    fontWeight: 500,
    textDecoration: 'none',
    whiteSpace: 'nowrap'
  }}>
      {text} →
    </a>;
  const renderBanner = codes => <div className="lic-banner not-prose" style={{
    margin: '1rem 0',
    padding: '0.5rem 0.85rem',
    background: bannerBackground,
    border: `1px solid ${borderColor}`,
    borderLeft: `3px solid ${ACCENT}`,
    borderRadius: '6px',
    color: textColor,
    fontSize: '0.75rem',
    display: 'flex',
    alignItems: 'center',
    gap: '0.5rem',
    flexWrap: 'wrap',
    fontFamily: FONT_STACK,
    lineHeight: 1.5
  }}>
      <span style={{
    flex: 1,
    minWidth: 0
  }}>
        <span style={{
    color: textMuted,
    marginRight: '0.3rem'
  }}>Requires</span>
        <span style={{
    fontWeight: 600
  }}>{buildSkuSentence(codes)}</span>
      </span>
      {renderLink('Licenses')}
    </div>;
  const renderLoading = () => <div className="not-prose" style={{
    margin: '1rem 0',
    padding: '0.6rem 0.9rem',
    background: bannerBackground,
    border: `1px dashed ${borderColor}`,
    borderRadius: '6px',
    color: textMuted,
    fontSize: '0.85rem',
    fontStyle: 'italic',
    fontFamily: FONT_STACK
  }} role="status" aria-live="polite">
      Loading license info…
    </div>;
  const renderInputError = message => <div className="not-prose" style={{
    margin: '1rem 0',
    padding: '0.6rem 0.9rem',
    background: errorBackground,
    border: `1px solid ${errorBorder}`,
    borderRadius: '6px',
    color: errorText,
    fontSize: '0.85rem',
    fontFamily: FONT_STACK
  }} role="alert">
      {message}
    </div>;
  if (typeof sku === 'string' && Array.isArray(skus)) {
    return renderInputError('LicenseBadge: pass either `sku` or `skus`, not both.');
  }
  if (skuList.length === 0) {
    return renderInputError('LicenseBadge: `sku` or `skus` is required.');
  }
  if (hasFetchError) return renderBanner(skuList);
  if (!data) return renderLoading();
  return renderBanner(skuList);
};

Endor Labs provides a Hugging Face integration that continuously scans all models in your Hugging Face organization and scores them for security, activity, popularity, and quality. You can use the integration to gain visibility into both public and private models, identify risks, and govern AI model usage across your organization.

The scans discover models across the organization and surface them in your inventory along with their Endor scores. Providing a Hugging Face access token extends coverage to private and gated models in addition to public ones. Discovered models are also correlated with models referenced in your project source code, enabling previously undiscoverable private models to be identified and included in your inventory.

<LicenseBadge skus={["EL-OSS-CORE", "EL-OSS-PRO"]} relation="any" />

<Note>
  Only users with the admin authorization role can create and manage installations.
</Note>

## Configure the Hugging Face integration

To connect a Hugging Face organization and scan its models:

1. Select **Projects** from the left sidebar.

2. Click **Add Project**.

3. Under **Namespace**, select the Endor Labs namespace for this installation.

   <Note>
     We recommend you use a [child namespace](/platform-administration/namespaces) for better organization of your projects.
   </Note>

4. Select **Hugging Face**.

   <img src="https://mintcdn.com/endorlabs-b4795f4f/_0Dor7cg7Ah00DxC/images/secure-ai-coding/hf-org-scan/add-hf-org.webp?fit=max&auto=format&n=_0Dor7cg7Ah00DxC&q=85&s=83fa29934c0d40736f6b623b2fe71b73" alt="Add Hugging Face organization" style={{width: '60%'}} width="1008" height="1394" data-path="images/secure-ai-coding/hf-org-scan/add-hf-org.webp" />

5. Enter the host URL of your Hugging Face organization in the format `https://huggingface.co/<organization-name>`, for example `https://huggingface.co/meta-llama`.

6. Optionally, enter your Hugging Face access token.

   <Note>A token with read-only access is required to scan private models.</Note>

7. Click **Create**.

Endor Labs scans all models in the organization and reports findings.

## Scan with endorctl

You can scan a Hugging Face organization from the command line using the following command:

```bash theme={null}
endorctl sync-org --namespace <namespace> --platform-source=huggingface --name=<organization-name>
```

Replace `<organization-name>` with the organization name as it appears in Hugging Face, for example `meta-llama` or `google`.

Alternatively, you can provide the installation UUID instead of the organization name:

```bash theme={null}
endorctl sync-org --namespace <namespace> --platform-source=huggingface --uuid=<installation-uuid>
```
