CINXE.COM

Repository - AT Protocol

<!DOCTYPE html><html lang="en" class="h-full"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/css/786ca9324488b5df.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-496a37b6c26ccd6a.js"/><script src="/_next/static/chunks/fd9d1056-ae1d3d1d803e2e5a.js" async=""></script><script src="/_next/static/chunks/117-545f1187d7f142b2.js" async=""></script><script src="/_next/static/chunks/main-app-3122dc718821276f.js" async=""></script><script src="/_next/static/chunks/972-f3553dcbba031b91.js" async=""></script><script src="/_next/static/chunks/135-8f28b0a70a96c388.js" async=""></script><script src="/_next/static/chunks/212-67e821188dcd5fb8.js" async=""></script><script src="/_next/static/chunks/app/%5Blocale%5D/specs/repository/page-45ed8c439a324609.js" async=""></script><script src="/_next/static/chunks/28-313384c6289a00c0.js" async=""></script><script src="/_next/static/chunks/369-a583bbb81b96a7d8.js" async=""></script><script src="/_next/static/chunks/60-3e1824554a9cf3f8.js" async=""></script><script src="/_next/static/chunks/app/%5Blocale%5D/layout-8706067c5d993875.js" async=""></script><title>Repository - AT Protocol</title><meta name="description" content="Self-authenticating storage for public account content"/><meta property="og:title" content="Repository - AT Protocol"/><meta property="og:description" content="Self-authenticating storage for public account content"/><meta property="og:url" content="https://atproto.com/"/><meta property="og:site_name" content="AT Protocol"/><meta property="og:image" content="https://atproto.com/default-social-card.png"/><meta property="og:image:secure_url" content="https://atproto.com/default-social-card.png"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:type" content="website"/><meta name="twitter:card" content="summary_large_image"/><meta name="twitter:title" content="Repository - AT Protocol"/><meta name="twitter:description" content="Self-authenticating storage for public account content"/><meta name="twitter:image" content="https://atproto.com/default-social-card.png"/><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body class="flex min-h-full bg-white antialiased dark:bg-zinc-900"><script>!function(){try{var d=document.documentElement,c=d.classList;c.remove('light','dark');var e=localStorage.getItem('theme');if('system'===e||(!e&&true)){var t='(prefers-color-scheme: dark)',m=window.matchMedia(t);if(m.media!==t||m.matches){d.style.colorScheme = 'dark';c.add('dark')}else{d.style.colorScheme = 'light';c.add('light')}}else if(e){c.add(e|| '')}if(e==='light'||e==='dark')d.style.colorScheme=e}catch(e){}}()</script><div class="w-full"><div class="h-full lg:ml-72 xl:ml-80"><header class="contents lg:pointer-events-none lg:fixed lg:inset-0 lg:z-40 lg:flex"><div class="contents lg:pointer-events-auto lg:block lg:w-72 lg:overflow-y-auto lg:border-r lg:border-zinc-900/10 lg:px-6 lg:pb-8 lg:pt-4 xl:w-80 lg:dark:border-white/10"><div class="hidden lg:flex"><a aria-label="Home" href="/"><svg viewBox="0 0 162 28" aria-hidden="true" class="h-6"><path class="fill-blue-500" d="M14.362 27.78c-1.956 0-3.756-.324-5.4-.972-1.644-.648-3.072-1.566-4.284-2.754a12.247 12.247 0 0 1-2.808-4.158c-.66-1.596-.99-3.33-.99-5.202 0-2.232.342-4.212 1.026-5.94.696-1.728 1.656-3.18 2.88-4.356a12.48 12.48 0 0 1 4.284-2.7c1.632-.612 3.378-.918 5.238-.918 2.28 0 4.278.354 5.994 1.062 1.716.708 3.144 1.668 4.284 2.88a11.706 11.706 0 0 1 2.538 4.158c.552 1.548.804 3.168.756 4.86-.06 2.328-.546 4.116-1.458 5.364-.912 1.236-2.328 1.854-4.248 1.854a5.839 5.839 0 0 1-2.826-.702 3.703 3.703 0 0 1-1.764-2.07l1.044.054c-.492.924-1.164 1.572-2.016 1.944a6.464 6.464 0 0 1-2.61.558c-1.212 0-2.28-.258-3.204-.774a5.682 5.682 0 0 1-2.178-2.214c-.528-.948-.792-2.046-.792-3.294 0-1.284.276-2.394.828-3.33a5.77 5.77 0 0 1 2.232-2.196c.936-.516 1.992-.774 3.168-.774.78 0 1.59.162 2.43.486.852.324 1.512.78 1.98 1.368l-.738.936V8.664h2.412l-.054 6.462c0 .924.18 1.62.54 2.088.36.468.894.702 1.602.702.624 0 1.104-.174 1.44-.522.348-.36.588-.846.72-1.458a10.66 10.66 0 0 0 .252-2.106c.036-1.86-.24-3.426-.828-4.698-.588-1.272-1.386-2.298-2.394-3.078a9.499 9.499 0 0 0-3.294-1.71c-1.2-.36-2.394-.54-3.582-.54-1.68 0-3.174.27-4.482.81-1.308.528-2.412 1.278-3.312 2.25-.888.96-1.56 2.1-2.016 3.42-.444 1.308-.654 2.748-.63 4.32.048 1.56.33 2.964.846 4.212a9.324 9.324 0 0 0 2.16 3.204 9.38 9.38 0 0 0 3.276 2.034c1.26.468 2.64.702 4.14.702.84 0 1.674-.096 2.502-.288.84-.18 1.608-.438 2.304-.774l1.026 2.808c-.924.432-1.896.75-2.916.954a14.649 14.649 0 0 1-3.078.324Zm-.144-10.098c.852 0 1.566-.246 2.142-.738.576-.492.864-1.326.864-2.502 0-1.068-.258-1.872-.774-2.412-.504-.552-1.218-.828-2.142-.828-1.092 0-1.908.288-2.448.864-.54.576-.81 1.368-.81 2.376 0 1.032.276 1.83.828 2.394.564.564 1.344.846 2.34.846Z"></path><path class="fill-blue-600 dark:fill-blue-500" d="M51.799 7.813V5.545h13.509v2.268H59.86V23h-2.624V7.812h-5.438ZM39.392 23h-2.795l6.28-17.455h3.043L52.203 23h-2.796L44.472 8.716h-.137L39.392 23Zm.469-6.835h9.068v2.216h-9.068v-2.216Z"></path><path class="fill-zinc-700 dark:fill-zinc-400" d="M161.144 5.545V23h-2.548V5.545h2.548ZM149.649 23.264c-1.227 0-2.298-.281-3.213-.843-.915-.563-1.625-1.35-2.131-2.361-.505-1.012-.758-2.194-.758-3.546 0-1.358.253-2.545.758-3.562.506-1.017 1.216-1.807 2.131-2.37.915-.562 1.986-.843 3.213-.843s2.298.28 3.213.843 1.625 1.353 2.131 2.37c.506 1.017.758 2.204.758 3.562 0 1.352-.252 2.534-.758 3.546-.506 1.011-1.216 1.798-2.131 2.36-.915.563-1.986.844-3.213.844Zm.009-2.139c.795 0 1.454-.21 1.977-.63.523-.421.909-.98 1.159-1.68.256-.699.384-1.468.384-2.31 0-.834-.128-1.602-.384-2.3-.25-.705-.636-1.27-1.159-1.697-.523-.426-1.182-.639-1.977-.639-.801 0-1.466.213-1.995.64-.522.426-.912.991-1.167 1.695a6.789 6.789 0 0 0-.375 2.302c0 .84.125 1.61.375 2.31.255.698.645 1.258 1.167 1.678.529.42 1.194.631 1.995.631ZM136.032 23.264c-1.267 0-2.358-.287-3.273-.86-.909-.58-1.608-1.378-2.096-2.395-.489-1.018-.733-2.182-.733-3.495 0-1.33.25-2.503.75-3.52.5-1.022 1.204-1.82 2.113-2.395.909-.573 1.98-.86 3.213-.86.995 0 1.881.184 2.659.554a4.764 4.764 0 0 1 1.884 1.534c.483.659.77 1.429.861 2.31h-2.48a2.974 2.974 0 0 0-.938-1.586c-.483-.443-1.13-.665-1.943-.665-.71 0-1.332.188-1.866.563-.529.37-.941.898-1.236 1.585-.296.682-.443 1.489-.443 2.42 0 .955.144 1.779.434 2.472.29.693.699 1.23 1.227 1.61.535.382 1.162.572 1.884.572.483 0 .92-.088 1.313-.264.397-.182.73-.44.997-.776.272-.335.463-.739.571-1.21h2.48a4.823 4.823 0 0 1-.827 2.267 4.76 4.76 0 0 1-1.849 1.568c-.767.38-1.668.571-2.702.571ZM121.571 23.264c-1.227 0-2.298-.281-3.213-.843-.915-.563-1.625-1.35-2.131-2.361-.505-1.012-.758-2.194-.758-3.546 0-1.358.253-2.545.758-3.562.506-1.017 1.216-1.807 2.131-2.37.915-.562 1.986-.843 3.213-.843s2.298.28 3.213.843 1.625 1.353 2.131 2.37c.505 1.017.758 2.204.758 3.562 0 1.352-.253 2.534-.758 3.546-.506 1.011-1.216 1.798-2.131 2.36-.915.563-1.986.844-3.213.844Zm.009-2.139c.795 0 1.454-.21 1.977-.63.523-.421.909-.98 1.159-1.68.256-.699.383-1.468.383-2.31 0-.834-.127-1.602-.383-2.3-.25-.705-.636-1.27-1.159-1.697-.523-.426-1.182-.639-1.977-.639-.802 0-1.466.213-1.995.64-.522.426-.912.991-1.167 1.695a6.789 6.789 0 0 0-.375 2.302c0 .84.125 1.61.375 2.31.255.698.645 1.258 1.167 1.678.529.42 1.193.631 1.995.631ZM113.379 9.91v2.044h-7.151V9.91h7.151Zm-5.233-3.137h2.548v12.383c0 .495.074.867.221 1.117.148.244.339.412.572.503.238.085.497.127.775.127.205 0 .384-.014.537-.042l.358-.068.46 2.105a4.307 4.307 0 0 1-.63.17 4.992 4.992 0 0 1-1.023.102 4.483 4.483 0 0 1-1.875-.358 3.208 3.208 0 0 1-1.406-1.159c-.358-.522-.537-1.179-.537-1.968V6.773ZM98.321 23.264c-1.227 0-2.298-.281-3.213-.843-.915-.563-1.625-1.35-2.13-2.361-.506-1.012-.76-2.194-.76-3.546 0-1.358.254-2.545.76-3.562.505-1.017 1.215-1.807 2.13-2.37.915-.562 1.986-.843 3.213-.843s2.298.28 3.213.843 1.625 1.353 2.131 2.37c.505 1.017.758 2.204.758 3.562 0 1.352-.253 2.534-.758 3.546-.506 1.011-1.216 1.798-2.131 2.36-.915.563-1.986.844-3.213.844Zm.008-2.139c.796 0 1.455-.21 1.978-.63.523-.421.909-.98 1.159-1.68.256-.699.383-1.468.383-2.31 0-.834-.127-1.602-.383-2.3-.25-.705-.636-1.27-1.159-1.697-.523-.426-1.182-.639-1.978-.639-.8 0-1.465.213-1.994.64-.522.426-.912.991-1.167 1.695a6.789 6.789 0 0 0-.375 2.302c0 .84.125 1.61.375 2.31.255.698.644 1.258 1.167 1.678.529.42 1.193.631 1.995.631ZM84.065 23V9.91h2.463v2.079h.136a3.164 3.164 0 0 1 1.261-1.662 3.61 3.61 0 0 1 2.063-.614 10.896 10.896 0 0 1 1.082.06v2.437a4.577 4.577 0 0 0-.545-.094 5.202 5.202 0 0 0-.784-.06c-.603 0-1.14.129-1.611.384a2.85 2.85 0 0 0-1.517 2.566V23h-2.548ZM68.918 23V5.545h6.221c1.358 0 2.483.248 3.375.742.892.494 1.56 1.17 2.003 2.028.443.853.665 1.813.665 2.881 0 1.074-.225 2.04-.674 2.898-.443.852-1.113 1.528-2.01 2.028-.893.494-2.015.742-3.367.742h-4.279V14.63h4.04c.858 0 1.554-.148 2.088-.444.534-.3.926-.71 1.176-1.227.25-.517.375-1.105.375-1.764 0-.66-.125-1.244-.375-1.756-.25-.511-.645-.912-1.184-1.201-.534-.29-1.239-.435-2.114-.435h-3.307V23h-2.633Z"></path></svg></a></div><div class="fixed inset-x-0 top-0 z-50 flex h-14 items-center justify-between gap-12 px-4 transition sm:px-6 lg:left-72 lg:z-30 lg:px-8 xl:left-80 backdrop-blur-sm lg:left-72 xl:left-80 dark:backdrop-blur bg-white/[var(--bg-opacity-light)] dark:bg-zinc-900/[var(--bg-opacity-dark)]" style="--bg-opacity-light:0.5;--bg-opacity-dark:0.2"><div class="absolute inset-x-0 top-full h-px transition bg-zinc-900/7.5 dark:bg-white/7.5"></div><div class="hidden lg:block lg:max-w-md lg:flex-auto"><button type="button" class="hidden h-8 w-full items-center gap-2 rounded-full bg-white pl-2 pr-3 text-sm text-zinc-500 ring-1 ring-zinc-900/10 transition hover:ring-zinc-900/20 ui-not-focus-visible:outline-none lg:flex dark:bg-white/5 dark:text-zinc-400 dark:ring-inset dark:ring-white/10 dark:hover:ring-white/20"><svg viewBox="0 0 20 20" fill="none" aria-hidden="true" class="h-5 w-5 stroke-current"><path stroke-linecap="round" stroke-linejoin="round" d="M12.01 12a4.25 4.25 0 1 0-6.02-6 4.25 4.25 0 0 0 6.02 6Zm0 0 3.24 3.25"></path></svg>Find something...<kbd class="ml-auto text-2xs text-zinc-400 dark:text-zinc-500"><kbd class="font-sans"></kbd><kbd class="font-sans">K</kbd></kbd></button><!--$--><span hidden="" style="position:fixed;top:1px;left:1px;width:1px;height:0;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0;display:none"></span><!--/$--></div><div class="flex items-center gap-5 lg:hidden"><button type="button" class="flex h-6 w-6 items-center justify-center rounded-md transition hover:bg-zinc-900/5 dark:hover:bg-white/5" aria-label="Toggle navigation"><svg viewBox="0 0 10 9" fill="none" stroke-linecap="round" aria-hidden="true" class="w-2.5 stroke-zinc-900 dark:stroke-white"><path d="M.5 1h9M.5 8h9M.5 4.5h9"></path></svg></button><!--$--><span hidden="" style="position:fixed;top:1px;left:1px;width:1px;height:0;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0;display:none"></span><!--/$--><a aria-label="Home" href="/"><svg viewBox="0 0 162 28" aria-hidden="true" class="h-6"><path class="fill-blue-500" d="M14.362 27.78c-1.956 0-3.756-.324-5.4-.972-1.644-.648-3.072-1.566-4.284-2.754a12.247 12.247 0 0 1-2.808-4.158c-.66-1.596-.99-3.33-.99-5.202 0-2.232.342-4.212 1.026-5.94.696-1.728 1.656-3.18 2.88-4.356a12.48 12.48 0 0 1 4.284-2.7c1.632-.612 3.378-.918 5.238-.918 2.28 0 4.278.354 5.994 1.062 1.716.708 3.144 1.668 4.284 2.88a11.706 11.706 0 0 1 2.538 4.158c.552 1.548.804 3.168.756 4.86-.06 2.328-.546 4.116-1.458 5.364-.912 1.236-2.328 1.854-4.248 1.854a5.839 5.839 0 0 1-2.826-.702 3.703 3.703 0 0 1-1.764-2.07l1.044.054c-.492.924-1.164 1.572-2.016 1.944a6.464 6.464 0 0 1-2.61.558c-1.212 0-2.28-.258-3.204-.774a5.682 5.682 0 0 1-2.178-2.214c-.528-.948-.792-2.046-.792-3.294 0-1.284.276-2.394.828-3.33a5.77 5.77 0 0 1 2.232-2.196c.936-.516 1.992-.774 3.168-.774.78 0 1.59.162 2.43.486.852.324 1.512.78 1.98 1.368l-.738.936V8.664h2.412l-.054 6.462c0 .924.18 1.62.54 2.088.36.468.894.702 1.602.702.624 0 1.104-.174 1.44-.522.348-.36.588-.846.72-1.458a10.66 10.66 0 0 0 .252-2.106c.036-1.86-.24-3.426-.828-4.698-.588-1.272-1.386-2.298-2.394-3.078a9.499 9.499 0 0 0-3.294-1.71c-1.2-.36-2.394-.54-3.582-.54-1.68 0-3.174.27-4.482.81-1.308.528-2.412 1.278-3.312 2.25-.888.96-1.56 2.1-2.016 3.42-.444 1.308-.654 2.748-.63 4.32.048 1.56.33 2.964.846 4.212a9.324 9.324 0 0 0 2.16 3.204 9.38 9.38 0 0 0 3.276 2.034c1.26.468 2.64.702 4.14.702.84 0 1.674-.096 2.502-.288.84-.18 1.608-.438 2.304-.774l1.026 2.808c-.924.432-1.896.75-2.916.954a14.649 14.649 0 0 1-3.078.324Zm-.144-10.098c.852 0 1.566-.246 2.142-.738.576-.492.864-1.326.864-2.502 0-1.068-.258-1.872-.774-2.412-.504-.552-1.218-.828-2.142-.828-1.092 0-1.908.288-2.448.864-.54.576-.81 1.368-.81 2.376 0 1.032.276 1.83.828 2.394.564.564 1.344.846 2.34.846Z"></path><path class="fill-blue-600 dark:fill-blue-500" d="M51.799 7.813V5.545h13.509v2.268H59.86V23h-2.624V7.812h-5.438ZM39.392 23h-2.795l6.28-17.455h3.043L52.203 23h-2.796L44.472 8.716h-.137L39.392 23Zm.469-6.835h9.068v2.216h-9.068v-2.216Z"></path><path class="fill-zinc-700 dark:fill-zinc-400" d="M161.144 5.545V23h-2.548V5.545h2.548ZM149.649 23.264c-1.227 0-2.298-.281-3.213-.843-.915-.563-1.625-1.35-2.131-2.361-.505-1.012-.758-2.194-.758-3.546 0-1.358.253-2.545.758-3.562.506-1.017 1.216-1.807 2.131-2.37.915-.562 1.986-.843 3.213-.843s2.298.28 3.213.843 1.625 1.353 2.131 2.37c.506 1.017.758 2.204.758 3.562 0 1.352-.252 2.534-.758 3.546-.506 1.011-1.216 1.798-2.131 2.36-.915.563-1.986.844-3.213.844Zm.009-2.139c.795 0 1.454-.21 1.977-.63.523-.421.909-.98 1.159-1.68.256-.699.384-1.468.384-2.31 0-.834-.128-1.602-.384-2.3-.25-.705-.636-1.27-1.159-1.697-.523-.426-1.182-.639-1.977-.639-.801 0-1.466.213-1.995.64-.522.426-.912.991-1.167 1.695a6.789 6.789 0 0 0-.375 2.302c0 .84.125 1.61.375 2.31.255.698.645 1.258 1.167 1.678.529.42 1.194.631 1.995.631ZM136.032 23.264c-1.267 0-2.358-.287-3.273-.86-.909-.58-1.608-1.378-2.096-2.395-.489-1.018-.733-2.182-.733-3.495 0-1.33.25-2.503.75-3.52.5-1.022 1.204-1.82 2.113-2.395.909-.573 1.98-.86 3.213-.86.995 0 1.881.184 2.659.554a4.764 4.764 0 0 1 1.884 1.534c.483.659.77 1.429.861 2.31h-2.48a2.974 2.974 0 0 0-.938-1.586c-.483-.443-1.13-.665-1.943-.665-.71 0-1.332.188-1.866.563-.529.37-.941.898-1.236 1.585-.296.682-.443 1.489-.443 2.42 0 .955.144 1.779.434 2.472.29.693.699 1.23 1.227 1.61.535.382 1.162.572 1.884.572.483 0 .92-.088 1.313-.264.397-.182.73-.44.997-.776.272-.335.463-.739.571-1.21h2.48a4.823 4.823 0 0 1-.827 2.267 4.76 4.76 0 0 1-1.849 1.568c-.767.38-1.668.571-2.702.571ZM121.571 23.264c-1.227 0-2.298-.281-3.213-.843-.915-.563-1.625-1.35-2.131-2.361-.505-1.012-.758-2.194-.758-3.546 0-1.358.253-2.545.758-3.562.506-1.017 1.216-1.807 2.131-2.37.915-.562 1.986-.843 3.213-.843s2.298.28 3.213.843 1.625 1.353 2.131 2.37c.505 1.017.758 2.204.758 3.562 0 1.352-.253 2.534-.758 3.546-.506 1.011-1.216 1.798-2.131 2.36-.915.563-1.986.844-3.213.844Zm.009-2.139c.795 0 1.454-.21 1.977-.63.523-.421.909-.98 1.159-1.68.256-.699.383-1.468.383-2.31 0-.834-.127-1.602-.383-2.3-.25-.705-.636-1.27-1.159-1.697-.523-.426-1.182-.639-1.977-.639-.802 0-1.466.213-1.995.64-.522.426-.912.991-1.167 1.695a6.789 6.789 0 0 0-.375 2.302c0 .84.125 1.61.375 2.31.255.698.645 1.258 1.167 1.678.529.42 1.193.631 1.995.631ZM113.379 9.91v2.044h-7.151V9.91h7.151Zm-5.233-3.137h2.548v12.383c0 .495.074.867.221 1.117.148.244.339.412.572.503.238.085.497.127.775.127.205 0 .384-.014.537-.042l.358-.068.46 2.105a4.307 4.307 0 0 1-.63.17 4.992 4.992 0 0 1-1.023.102 4.483 4.483 0 0 1-1.875-.358 3.208 3.208 0 0 1-1.406-1.159c-.358-.522-.537-1.179-.537-1.968V6.773ZM98.321 23.264c-1.227 0-2.298-.281-3.213-.843-.915-.563-1.625-1.35-2.13-2.361-.506-1.012-.76-2.194-.76-3.546 0-1.358.254-2.545.76-3.562.505-1.017 1.215-1.807 2.13-2.37.915-.562 1.986-.843 3.213-.843s2.298.28 3.213.843 1.625 1.353 2.131 2.37c.505 1.017.758 2.204.758 3.562 0 1.352-.253 2.534-.758 3.546-.506 1.011-1.216 1.798-2.131 2.36-.915.563-1.986.844-3.213.844Zm.008-2.139c.796 0 1.455-.21 1.978-.63.523-.421.909-.98 1.159-1.68.256-.699.383-1.468.383-2.31 0-.834-.127-1.602-.383-2.3-.25-.705-.636-1.27-1.159-1.697-.523-.426-1.182-.639-1.978-.639-.8 0-1.465.213-1.994.64-.522.426-.912.991-1.167 1.695a6.789 6.789 0 0 0-.375 2.302c0 .84.125 1.61.375 2.31.255.698.644 1.258 1.167 1.678.529.42 1.193.631 1.995.631ZM84.065 23V9.91h2.463v2.079h.136a3.164 3.164 0 0 1 1.261-1.662 3.61 3.61 0 0 1 2.063-.614 10.896 10.896 0 0 1 1.082.06v2.437a4.577 4.577 0 0 0-.545-.094 5.202 5.202 0 0 0-.784-.06c-.603 0-1.14.129-1.611.384a2.85 2.85 0 0 0-1.517 2.566V23h-2.548ZM68.918 23V5.545h6.221c1.358 0 2.483.248 3.375.742.892.494 1.56 1.17 2.003 2.028.443.853.665 1.813.665 2.881 0 1.074-.225 2.04-.674 2.898-.443.852-1.113 1.528-2.01 2.028-.893.494-2.015.742-3.367.742h-4.279V14.63h4.04c.858 0 1.554-.148 2.088-.444.534-.3.926-.71 1.176-1.227.25-.517.375-1.105.375-1.764 0-.66-.125-1.244-.375-1.756-.25-.511-.645-.912-1.184-1.201-.534-.29-1.239-.435-2.114-.435h-3.307V23h-2.633Z"></path></svg></a></div><div class="flex items-center gap-5"><nav class="hidden md:block"><ul role="list" class="flex items-center gap-8"><li><a class="text-sm leading-5 text-zinc-600 transition hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/sdks">SDKs</a></li><li><a class="text-sm leading-5 text-zinc-600 transition hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="https://docs.bsky.app/blog">Blog</a></li><li><a class="text-sm leading-5 text-zinc-600 transition hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="https://github.com/bluesky-social/atproto">GitHub</a></li><select class="block w-full appearance-none rounded-md border-0 py-1.5 pl-3 pr-3 text-gray-900 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-indigo-600 sm:text-sm sm:leading-6 dark:bg-gray-800 dark:text-gray-100 dark:ring-gray-700"><option value="en" selected="">English</option><option value="pt">Português</option><option value="ja">日本語</option></select></ul></nav><div class="hidden md:block md:h-5 md:w-px md:bg-zinc-900/10 md:dark:bg-white/15"></div><div class="flex gap-4"><div class="contents lg:hidden"><button type="button" class="flex h-6 w-6 items-center justify-center rounded-md transition hover:bg-zinc-900/5 ui-not-focus-visible:outline-none lg:hidden dark:hover:bg-white/5" aria-label="Find something..."><svg viewBox="0 0 20 20" fill="none" aria-hidden="true" class="h-5 w-5 stroke-zinc-900 dark:stroke-white"><path stroke-linecap="round" stroke-linejoin="round" d="M12.01 12a4.25 4.25 0 1 0-6.02-6 4.25 4.25 0 0 0 6.02 6Zm0 0 3.24 3.25"></path></svg></button><!--$--><span hidden="" style="position:fixed;top:1px;left:1px;width:1px;height:0;padding:0;margin:-1px;overflow:hidden;clip:rect(0, 0, 0, 0);white-space:nowrap;border-width:0;display:none"></span><!--/$--></div><button type="button" class="flex h-6 w-6 items-center justify-center rounded-md transition hover:bg-zinc-900/5 dark:hover:bg-white/5" aria-label="Toggle theme"><svg viewBox="0 0 20 20" fill="none" aria-hidden="true" class="h-5 w-5 stroke-zinc-900 dark:hidden"><path d="M12.5 10a2.5 2.5 0 1 1-5 0 2.5 2.5 0 0 1 5 0Z"></path><path stroke-linecap="round" d="M10 5.5v-1M13.182 6.818l.707-.707M14.5 10h1M13.182 13.182l.707.707M10 15.5v-1M6.11 13.889l.708-.707M4.5 10h1M6.11 6.111l.708.707"></path></svg><svg viewBox="0 0 20 20" fill="none" aria-hidden="true" class="hidden h-5 w-5 stroke-white dark:block"><path d="M15.224 11.724a5.5 5.5 0 0 1-6.949-6.949 5.5 5.5 0 1 0 6.949 6.949Z"></path></svg></button></div></div></div><nav class="hidden lg:mt-10 lg:block"><ul role="list"><li class="md:hidden"><a class="block py-1 text-sm text-zinc-600 transition hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/">API</a></li><li class="md:hidden"><a class="block py-1 text-sm text-zinc-600 transition hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="#">Documentation</a></li><li class="md:hidden"><a class="block py-1 text-sm text-zinc-600 transition hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="#">Support</a></li><li class="relative mt-6 md:mt-0"><h2 class="text-xs font-semibold text-zinc-900 dark:text-white">Home</h2><div class="relative mt-3 pl-2"><div class="absolute inset-y-0 left-2 w-px bg-zinc-900/10 dark:bg-white/5"></div><ul role="list" class="border-l border-transparent"><li class="relative"><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/"><span class="truncate">Introduction</span></a></li><li class="relative"><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/sdks"><span class="truncate">SDKs</span></a></li><li class="relative"><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/guides/glossary"><span class="truncate">Glossary</span></a></li><li class="relative"><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/guides/faq"><span class="truncate">FAQ</span></a></li></ul></div></li><li class="relative mt-6"><h2 class="text-xs font-semibold text-zinc-900 dark:text-white">Building apps</h2><div class="relative mt-3 pl-2"><div class="absolute inset-y-0 left-2 w-px bg-zinc-900/10 dark:bg-white/5"></div><ul role="list" class="border-l border-transparent"><li class="relative"><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/guides/applications"><span class="truncate">Quick start</span></a></li></ul></div></li><li class="relative mt-6"><h2 class="text-xs font-semibold text-zinc-900 dark:text-white">Guides</h2><div class="relative mt-3 pl-2"><div class="absolute inset-y-0 left-2 w-px bg-zinc-900/10 dark:bg-white/5"></div><ul role="list" class="border-l border-transparent"><li class="relative"><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/guides/overview"><span class="truncate">Overview</span></a></li><li class="relative"><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/guides/self-hosting"><span class="truncate">Self-hosting</span></a></li><li class="relative"><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/guides/identity"><span class="truncate">Identity</span></a></li><li class="relative"><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/guides/data-repos"><span class="truncate">Data repos</span></a></li><li class="relative"><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/guides/lexicon"><span class="truncate">Schemas &amp; Lexicon</span></a></li></ul></div></li><li class="relative mt-6"><h2 class="text-xs font-semibold text-zinc-900 dark:text-white">Specs</h2><div class="relative mt-3 pl-2"><div class="absolute inset-x-0 top-0 bg-zinc-800/2.5 will-change-transform dark:bg-white/2.5" style="border-radius:8px;height:32px;top:128px;opacity:0"></div><div class="absolute inset-y-0 left-2 w-px bg-zinc-900/10 dark:bg-white/5"></div><div class="absolute left-2 h-6 w-px bg-blue-500" style="top:132px;opacity:1"></div><ul role="list" class="border-l border-transparent"><li class="relative"><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/specs/atp"><span class="truncate">AT Protocol</span></a></li><li class="relative"><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/specs/data-model"><span class="truncate">Data Model</span></a></li><li class="relative"><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/specs/lexicon"><span class="truncate">Lexicon</span></a></li><li class="relative"><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/specs/cryptography"><span class="truncate">Cryptography</span></a></li><li class="relative"><a aria-current="page" class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-900 dark:text-white" href="/specs/repository"><span class="truncate">Repository</span></a><ul role="list" style="opacity:1"><li><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-7 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/specs/repository#repo-data-structure-v3"><span class="truncate">Repo Data Structure (v3)</span></a></li><li><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-7 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/specs/repository#car-file-serialization"><span class="truncate">CAR File Serialization</span></a></li><li><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-7 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/specs/repository#repository-diffs"><span class="truncate">Repository Diffs</span></a></li><li><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-7 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/specs/repository#security-considerations"><span class="truncate">Security Considerations</span></a></li><li><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-7 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/specs/repository#possible-future-changes"><span class="truncate">Possible Future Changes</span></a></li></ul></li><li class="relative"><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/specs/blob"><span class="truncate">Blobs</span></a></li><li class="relative"><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/specs/label"><span class="truncate">Labels</span></a></li><li class="relative"><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/specs/xrpc"><span class="truncate">HTTP API (XRPC)</span></a></li><li class="relative"><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/specs/oauth"><span class="truncate">OAuth</span></a></li><li class="relative"><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/specs/event-stream"><span class="truncate">Event Stream</span></a></li><li class="relative"><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/specs/did"><span class="truncate">DID</span></a></li><li class="relative"><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/specs/handle"><span class="truncate">Handle</span></a></li><li class="relative"><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/specs/nsid"><span class="truncate">NSID</span></a></li><li class="relative"><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/specs/record-key"><span class="truncate">Record Key</span></a></li><li class="relative"><a class="flex justify-between gap-2 py-1 pr-3 text-sm transition pl-4 text-zinc-600 hover:text-zinc-900 dark:text-zinc-400 dark:hover:text-white" href="/specs/at-uri-scheme"><span class="truncate">URI Scheme</span></a></li></ul></div></li></ul></nav></div></header><div class="relative flex h-full flex-col px-4 pt-14 sm:px-6 lg:px-8"><main class="flex-auto"><article class="flex h-full flex-col pb-24 pt-16"><div class="flex-auto prose dark:prose-invert [html_:where(&amp;&gt;*)]:mx-auto [html_:where(&amp;&gt;*)]:max-w-2xl [html_:where(&amp;&gt;*)]:lg:mx-[calc(50%-min(50%,theme(maxWidth.lg)))] [html_:where(&amp;&gt;*)]:lg:max-w-3xl"><h1>Repository</h1> <p><em>See the <a href="../guides/data-repos">Data Repositories Guide</a> for a higher-level introduction.</em></p> <p class="lead">Public atproto content (<strong>records</strong>) is stored in per-account repositories (frequently shortened to <strong>repo</strong>). All currently active records are stored in the repository, and current repository contents are publicly available, but both content deletions and account deletions are fully supported.</p> <p class="lead">The repository data structure is content-addressed (a <a href="https://en.wikipedia.org/wiki/Merkle_tree">Merkle-tree</a>), and every mutation of repository contents (eg, addition, removal, and updates to records) results in a new commit <code>data</code> hash value (CID). Commits are cryptographically signed, with rotatable signing keys, which allows recursive validation of content as a whole or in part.</p> <p class="lead">Repositories and their contents are canonically stored in binary <a href="https://ipld.io/docs/codecs/known/dag-cbor/">DAG-CBOR</a> format, as a graph of data objects referencing each other by content hash (CID Links). Large binary blobs are not stored directly in repositories, though they are referenced by hash (<a href="https://github.com/multiformats/cid">CID</a>). This includes images and other media objects. Repositories can be exported as <a href="https://ipld.io/specs/transport/car/carv1/">CAR</a> files for offline backup, account migration, or other purposes.</p> <p class="lead">In the atproto federation architecture, the authoritative location of an account&#x27;s repository is the associated Personal Data Server (PDS). An account&#x27;s current PDS location is authoritatively indicated in the DID Document.</p> <p class="lead">In real-world use, it is expected that individual repositories will contain anywhere from dozens to millions of records.</p> <h2 class="scroll-mt-24" id="repo-data-structure-v3"><a class="group text-inherit no-underline hover:text-inherit" href="#repo-data-structure-v3">Repo Data Structure (v3)</a></h2> <p>This describes version <code>3</code> of the repository binary format.</p> <p>Version <code>2</code> had a slightly different commit object schema, but is mostly compatible with <code>3</code>.</p> <p>Version <code>1</code> had a different MST fanout configuration, and an incompatible schema for commits and repository metadata. Version <code>1</code> is deprecated, no repositories in this format exist in the network, and implementations do not need to support it.</p> <p>At a high level, a repository is a key/value mapping where the keys are path names (as strings) and the values are records (DAG-CBOR objects).</p> <p>A <strong>Merkle Search Tree</strong> (MST) is used to store this mapping. This content-addressed deterministic data structure stores data in key-sorted order. It is reasonably efficient for key lookups, key range scans, and appends (assuming sorted record paths). The properties of MSTs in general are described in this academic publication:</p> <blockquote> <p>Alex Auvolat, François Taïani. Merkle Search Trees: Efficient State-Based CRDTs in Open Networks. SRDS 2019 - 38th IEEE International Symposium on Reliable Distributed Systems, Oct 2019, Lyon, France. pp.1-10, ff10.1109/SRDS.2019.00032 (<a href="https://inria.hal.science/hal-02303490/document">pdf</a>)</p> </blockquote> <p>The specific details of the MST as used in atproto repositories are described below.</p> <p>Repo paths are strings, while MST keys are byte arrays. Neither may be empty (zero-length). While repo path strings are currently limited to a subset of ASCII (making encoding a no-op), the encoding is specified as UTF-8.</p> <p>Repo paths currently have a fixed structure of <code>&lt;collection&gt;/&lt;record-key&gt;</code>. This means a valid, normalized <a href="./nsid">NSID</a>, followed by a <code>/</code>, followed by a valid <a href="./record-key">Record Key</a>. The path should not start with a leading <code>/</code>, and should always have exactly two path segments. The ASCII characters allowed in the entire path string are currently: letters (<code>A-Za-z</code>), digits (<code>0-9</code>), slash (<code>/</code>), period (<code>.</code>), hyphen (<code>-</code>), underscore (<code>_</code>), and tilde (<code>~</code>). The specific path segments <code>.</code> and <code>..</code> are not valid NSIDs or Record Keys, and will always be disallowed in repo paths.</p> <p>Note that repo paths for all records in the same collection are sorted together in the MST, making enumeration (via key scan) and export efficient. Additionally, the TID Record Key scheme was intentionally selected to provide chronological sorting of MST keys within the scope of a collection. Appends are more efficient than random insertions/mutations within the tree, and when enumerating records within a collection they will be in chronological order (assuming that TID generation was done correctly, which cannot be relied on in general).</p> <h3>Commit Objects</h3> <p>The top-level data object in a repository is a signed commit. The data fields are:</p> <ul> <li><code>did</code> (string, required): the account DID associated with the repo, in strictly normalized form (eg, lowercase as appropriate)</li> <li><code>version</code> (integer, required): fixed value of <code>3</code> for this repo format version</li> <li><code>data</code> (CID link, required): pointer to the top of the repo contents tree structure (MST)</li> <li><code>rev</code> (string, TID format, required): revision of the repo, used as a logical clock. Must increase monotonically. Recommend using current timestamp as TID; <code>rev</code> values in the &quot;future&quot; (beyond a fudge factor) should be ignored and not processed.</li> <li><code>prev</code> (CID link, nullable): pointer (by hash) to a previous commit object for this repository. Could be used to create a chain of history, but largely unused (included for v2 backwards compatibility). In version <code>3</code> repos, this field must exist in the CBOR object, but is virtually always <code>null</code>. NOTE: previously specified as nullable and optional, but this caused interoperability issues.</li> <li><code>sig</code> (byte array, required): cryptographic signature of this commit, as raw bytes</li> </ul> <p>An UnsignedCommit data object has all the same fields except for <code>sig</code>. The process for signing a commit is to populate all the data fields, and then serialize the UnsignedCommit with DAG-CBOR. The output bytes are then hashed with SHA-256, and the binary hash output (without hex encoding) is then signed using the current &quot;signing key&quot; for the account. The signature is then stored as raw bytes in a commit object, along with all the other data fields.</p> <p>The CID for a commit overall is generated by serializing a <em>signed</em> commit object as DAG-CBOR. See notes on the &quot;blessed&quot; CID format below, and in particular be sure to use the <code>dag-cbor</code> multicodec for CIDs linking to commit objects.</p> <p>Note that neither the signature itself nor the signed commit indicate either the type of key used (curve type), or the specific public key used. That information must be fetched from the account&#x27;s DID document. With key rotation, verification of older commit signatures can become ambiguous. The most recent commit should always be verifiable using the current DID document. This implies that a new repository commit should be created every time the signing key is rotated. Such a commit does not need to update the <code>data</code> CID link.</p> <h3>MST Structure</h3> <p>At a high level, the repository MST is a key/value mapping where the keys are non-empty byte arrays, and the values are CID links to records. The MST data structure should be fully reproducible from such a mapping of bytestrings-to-CIDs, with exactly reproducible root CID hash (aka, the <code>data</code> field in commit object).</p> <p>Every node in the tree structure contains a set of key/CID mappings, as well as links to other sub-tree nodes. The entries and links are in key-sorted order, with all of the keys of a linked sub-tree (recursively) falling in the range corresponding to the link location. The sort order is from <strong>left</strong> (lexically first) to <strong>right</strong> (lexically latter). Each key has a <strong>depth</strong> derived from the key itself, which determines which sub-tree it ends up in. The top node in the tree contains all of the keys with the highest depth value (which for a small tree may be all depth zero, so a single node). Links to the left or right of the entire node, or between any two keys in the node, point to a sub-tree node containing keys that fall in the corresponding key range.</p> <p>An empty repository with no records is represented as a single MST node with an empty array of entries. This is the only situation in which a tree may contain an empty leaf node which does not either contain keys (&quot;entries&quot;) or point to a sub-tree containing entries. The top of the tree must not be a an empty node which only points to a sub-tree. Empty intermediate nodes are allowed, as long as they point to a sub-tree which does contain entries. In other words, empty nodes must be pruned from the top and bottom of the tree, but empty intermediate nodes must be kept, such that sub-tree links do not skip a level of depth. The overall structure and shape of the MST is deterministic based on the current key/value content, regardless of the history of insertions and deletions that lead to the current contents.</p> <p>For the atproto MST implementation, the hash algorithm used is SHA-256 (binary output), counting &quot;prefix zeros&quot; in 2-bit chunks, giving a fanout of 4. To compute the depth of a key:</p> <ul> <li>hash the key (a byte array) with SHA-256, with binary output</li> <li>count the number of leading binary zeros in the hash, and divide by two, rounding down</li> <li>the resulting positive integer is the depth of the key</li> </ul> <p>Some examples, with the given ASCII strings mapping to byte arrays:</p> <ul> <li><code>2653ae71</code>: depth &quot;0&quot;</li> <li><code>blue</code>: depth &quot;1&quot;</li> <li><code>app.bsky.feed.post/454397e440ec</code>: depth &quot;4&quot;</li> <li><code>app.bsky.feed.post/9adeb165882c</code>: depth &quot;8&quot;</li> </ul> <p>There are many MST nodes in repositories, so it is important that they have a compact binary representation, for storage efficiency. Within every node, keys (byte arrays) are compressed by eliding common prefixes, with each entry indicating how many bytes it shares with the previous key in the array. The first entry in the array for a given node must contain the full key, and a common prefix length of 0. This key compaction is internal to nodes, it does not extend across multiple nodes in the tree. The compaction scheme is mandatory, to ensure that the MST structure is deterministic across implementations.</p> <p>The node data schema fields are:</p> <ul> <li><code>l</code> (&quot;left&quot;, CID link, nullable): link to sub-tree Node on a lower level and with all keys sorting before keys at this node</li> <li><code>e</code> (&quot;entries&quot;, array of objects, required): ordered list of TreeEntry objects<!-- --> <ul> <li><code>p</code> (&quot;prefixlen&quot;, integer, required): count of bytes shared with previous TreeEntry in this Node (if any)</li> <li><code>k</code> (&quot;keysuffix&quot;, byte array, required): remainder of key for this TreeEntry, after &quot;prefixlen&quot; have been removed</li> <li><code>v</code> (&quot;value&quot;, CID Link, required): link to the record data (CBOR) for this entry</li> <li><code>t</code> (&quot;tree&quot;, CID Link, nullable): link to a sub-tree Node at a lower level which has keys sorting after this TreeEntry&#x27;s key (to the &quot;right&quot;), but before the next TreeEntry&#x27;s key in this Node (if any)</li> </ul> </li> </ul> <p>When parsing MST data structures, the depth and sort order of keys should be verified. This is particularly true for untrusted inputs, but is simplest to just verify every time. Additional checks on node size and other parameters of the tree structure also need to be limited; see the &quot;Security Considerations&quot; section of this document.</p> <h3>CID Formats</h3> <p>The IPFS CID specification is very flexible, and supports a wide variety of hash types, a field indicating the type of content being linked to, and various string encoding options. These features are valuable to allow evolution of the repo format over time, but to maximize interoperability among implementations, only a specific &quot;blessed&quot; set of CID types are allowed.</p> <p>The blessed format for commit objects and MST node objects, when linking to commit objects, MST nodes (aka, <code>data</code>, or MST internal links), or records (aka, MST leaf nodes to records), is:</p> <ul> <li>CIDv1</li> <li>Multibase: binary serialization within DAG-CBOR (or <code>base32</code> for JSON mappings)</li> <li>Multicodec: <code>dag-cbor</code> (0x71)</li> <li>Multihash: <code>sha-256</code> with 256 bits (0x12)</li> </ul> <p>In the context of repositories, it is also desirable for the overall data structure to be reproducible given the contents, so the allowed CID types are strictly constrained and enforced. Commit objects with non-compliant <code>prev</code> or <code>data</code> links are considered invalid. MST Node objects with non-compliant links to other MST Node objects are considered invalid, and the entire MST data structure invalid.</p> <p>More flexibility is allowed in processing the &quot;leaf&quot; links from MST to records, and implementations should retain the exact CID links used for these mappings, instead of normalizing. Implementations should strictly follow the CID blessed format when generating new CID Links to records.</p> <h2 class="scroll-mt-24" id="car-file-serialization"><a class="group text-inherit no-underline hover:text-inherit" href="#car-file-serialization">CAR File Serialization</a></h2> <p>The standard file format for storing data objects is Content Addressable aRchives (CAR). The standard repository export format for atproto repositories is <a href="https://ipld.io/specs/transport/car/carv1/">CAR v1</a>, which have file suffix <code>.car</code> and mimetype <code>application/vnd.ipld.car</code>.</p> <p>The CARv1 format is very simple. It contains a small metadata header (which can indicate one or more &quot;root&quot; CID links), and then a series of binary &quot;blocks&quot;, each of which is a data object. In the context of atproto repositories:</p> <ul> <li>The first element of the CAR <code>roots</code> metadata array must be the CID of the most relevant Commit object. for a generic export, this is the current (most recent) commit. additional CIDs may also be present in the <code>roots</code> array, with (for now) undefined meaning or order</li> <li>For full exports, the full repo structure must be included for the indicated commit, which includes all records and all MST nodes</li> <li>The order of blocks within the CAR file is not currently defined or restricted. implementations may have a &quot;preferred&quot; ordering, but should be tolerant of unexpected ordering</li> <li>Additional blocks, including records, may or may not be included in the CAR file</li> </ul> <p>When importing CAR files, note that there may existing dangling CID references. For example, repositories may contain CID Links to blobs or records in other repositories, and the blocks corresponding to those blobs or references would likely not be included in the CAR file.</p> <p>The CARv1 specification is agnostic about the same block appearing multiple times in the same file (&quot;Duplicate Blocks)&quot;. Implementations should be robust to both duplication and de-duplication of blocks, and should also ignore any unnecessary or unlinked blocks.</p> <h2 class="scroll-mt-24" id="repository-diffs"><a class="group text-inherit no-underline hover:text-inherit" href="#repository-diffs">Repository Diffs</a></h2> <p>A concept which supports efficient synchronization of data between independent services is &quot;diffs&quot; of repository trees between different revisions. The basic principle is that a repository diff contains all the data (commit object, MST nodes, and records) that have changed between an older revision and the current revision of a repo. The diff can be &quot;applied&quot; to the older mirror of the repository, and the result will be the complete MST tree at the current (newer) commit revision.</p> <p>Repo diffs can be serialized as CAR files, sometimes referred to as &quot;CAR slices&quot;. Some details about diff CAR slices:</p> <ul> <li>same format, version, and atproto-specific constraints as full repo export CAR files<!-- --> <ul> <li>blocks &quot;should&quot; be de-duplicated by CID (only one copy included), though receiving implementations must be resilient to duplication</li> </ul> </li> <li>the root CID indicated in the CAR header (the first element of <code>roots</code>) should point to the commit block (which must be included)</li> <li>any required blocks must be included even if they have appeared in the history of the repository previously. eg, if a record is created in rev C, deleted in rev F, and re-created in rev N, the diff &quot;since F&quot; must include the record block</li> <li>all &quot;created&quot; records must be included</li> <li>any records which have been &quot;deleted&quot; and do not exist in the current repo should not be included</li> <li>any records which have been &quot;updated&quot; should include the final version, and should not include the previous version</li> <li>all MST nodes in the current repo which didn&#x27;t exist in the previous repo version must be included</li> <li>with the exception of removed record data, the diff may include additional blocks, which receivers should ignore.<!-- --> <ul> <li>however, diffs which intentionally contain a large amount of irrelevant block data to consume network or compute resources are considered a form of network abuse.</li> </ul> </li> </ul> <p>The diff is a partial Merkle tree, including a signed commit, and can be partially verified. This means that an observer which has successfully resolved the identity of the relevant account (including cryptographic public keys) can verify certain aspects of the data. The diff is a reliable &quot;proof chain&quot; for creation and updates of records: an observer can verify that the new or updated records have the specific record values in the overall repo as of the commit revision. If the observer knows of specific records (by repo path, or by full AT-URI) that have been deleted, they can verify that those records no longer exist in the repo as of the final commit revision.</p> <p>However, an observer which does not know the full state of the repository at the &quot;older&quot; revision <em>can not</em> reliably enumerate all of the records that have been removed from the repository. Such an observer also can not see the previous values of deleted or updated records, either as full values or by CID. Note that the later is an intentional design goal for the diff concept: it is desired that content deletion happen rapidly and not &quot;draw attention&quot; to the content which has been deleted. It is technically possible for &quot;archival&quot; observers to track deletion events and lookup the previous content value, but this requires additional resources and effort.</p> <p>Sometimes repo diffs are generated automatically. For example, every commit to a repo can result in a diff against the immediately preceding commit. In other contexts, diffs are generated on demand: a diff can be requested &quot;since&quot; an arbitrary previous revision. It is not expected that repo hosts support generating diffs between two arbitrary revisions, only &quot;from&quot; an arbitrary older revision and the current revision. Repo hosts are not required to maintain a complete history of prior commits/revisions, and in some cases (such as account migration) may never have had prior repo history. Some details about how to interpret and service requests for diffs &quot;since&quot; a prior revision:</p> <ul> <li>it is helpful to track internally the commit revision when a block (record or MST node) was created or re-created. This enables querying blocks &quot;since&quot; a point in time</li> <li>&quot;since&quot; revisions are not expected to be an exact match<!-- --> <ul> <li>for example, if a repo had a sequence of commits &quot;333&quot;, &quot;666&quot;, &quot;999&quot;, and a &quot;since&quot; value of &quot;444&quot; was requested, the changes in &quot;666&quot; and &quot;999&quot; should be included, as if the &quot;since&quot; parameter was &quot;666&quot;..</li> </ul> </li> <li>a host is allowed to include additional history, but is encouraged to return the minimal or most granular requested data<!-- --> <ul> <li>for example, a host may have &quot;compacted&quot; repo rev history to a smaller number of commits. If a repo had commit history &quot;288&quot;, &quot;300&quot;, &quot;320&quot;, &quot;340&quot;, &quot;400&quot;, and got a request &quot;since&quot; 340, it might return all changes since 300. Hosts are encouraged to return the smallest diff when possible (eg, “since” 340), but clients should be resilient.</li> </ul> </li> <li>if a host receives a “since” request earlier than the oldest available revision for a repository, it should return the full repository. This may happen if the host does not have the complete history of the repository.<!-- --> <ul> <li>for example, if a repository had revisions &quot;140&quot;, &quot;150&quot;, and &quot;160&quot;, then migrated to a new PDS and revisions continued &quot;161&quot; and &quot;170&quot;, if the new PDS is asked for a diff &quot;since&quot; 150, the new PDS would probably need to return the full repository, because the earliest revision it would be aware of was &quot;160&quot; or &quot;161&quot; (depending on how migration was implemented).</li> </ul> </li> </ul> <p>In the specific case of chained commit-to-commit diffs which appear on the firehose, diffs should be &quot;minimal&quot;: they should not contain additional records or additional history.</p> <h2 class="scroll-mt-24" id="security-considerations"><a class="group text-inherit no-underline hover:text-inherit" href="#security-considerations">Security Considerations</a></h2> <p>Repositories are untrusted input: accounts have full control over repository contents, and PDS instances have full control over binary encoding. It is important to handle possible denial of service vectors from both hostile actors or accidental situations (eg, corrupted data or buggy implementations).</p> <p>Generic precautions should be followed with CBOR decoding: a maximum serialized object size, a maximum recursion depth for nested fields, maximum memory budget for deserialized data, etc. Some CBOR libraries include these precautions by default, but others do not.</p> <p>The efficiency of the MST data structure depends on key hashes being relatively randomly dispersed. Because accounts have control over Record Keys, they can mine for sets of record keys with particular depths and sorting order, which result in inefficient tree shapes, which can cause both large storage overhead, and network amplification in the context of federation streams. To protect against these attacks, implementations should limit the number of TreeEntries per Node to a statistically unlikely maximum length. It may also be necessary to limit the overall depth of the repo, or other parameters, to prevent more sophisticated key mining attacks.</p> <p>When importing CAR files, the completeness of the repository structure should be verified. Additional unrelated blocks might be included in the CAR structure; care should be taken when injecting CAR contents directly in to backend block storage, to ensure resources are not wasted on un-referenced blocks. There may also be issues with cross-account contamination from CAR imports, for example previously-deleted records re-appearing via CAR import from an unrelated account.</p> <h2 class="scroll-mt-24" id="possible-future-changes"><a class="group text-inherit no-underline hover:text-inherit" href="#possible-future-changes">Possible Future Changes</a></h2> <p>An optional in-repo mechanism for storing multiple versions of the same record (by path) may be implemented. Eg, adding additional path field to indicate the version by CID, timestamp, or monotonically increasing version integer.</p> <p>Mechanisms for storing metadata associated with each record are being considered, for example, generic label, re-use rights, or hashtag metadata. This would allow mutating the metadata without mutating the record itself, and make some metadata generic across lexicons.</p> <p>Repo path restrictions may be relaxed in other ways, including fewer or additional path segments, more allowed characters (including non-ASCII), etc. Paths will always be valid Unicode strings, mapped to MST keys (byte arrays) by UTF-8 encoding.</p> <p>At the overall atproto specification level, additional &quot;blessed&quot; cryptographic algorithms may be added over time. Likewise, additional CID formats to reference records and blobs may be added. Internal CID format changes would require a repo format version bump.</p> <p>Repository CAR exports may include linked &quot;blobs&quot; (larger binary files). This might become the default, or a configurable option, or some another mechanism for blob export might be chosen (eg, <code>.tar</code> or <code>.zip</code> export).</p> <p>Record content could conceivably be something other than DAG-CBOR some day. This would probably be a repo format version bump. Note that it is possible to efficiently wrap other data formats in a DAG-CBOR wrapper (via a byte array field), or to have a small DAG-CBOR record type that links to a blob in arbitrary format.</p> <p>Repository CAR exports may end up with a preferred block ordering scheme specified.</p> <p>The CARv2 file format, which includes optimizations for some use cases, may be adopted in some form.</p> <p>Adding optional fields to commit and MST node objects may or may not result in a repo format version change. Changing the MST fanout, or any changes to the current MST fields, would be a full repo version change.</p></div></article></main><footer class="mx-auto w-full max-w-2xl space-y-10 pb-16 lg:max-w-5xl"><div class="flex"><div class="flex flex-col items-start gap-3"><a class="inline-flex gap-0.5 justify-center overflow-hidden text-sm font-medium transition rounded-full bg-zinc-100 py-1 px-3 text-zinc-900 hover:bg-zinc-200 dark:bg-zinc-800/40 dark:text-zinc-400 dark:ring-1 dark:ring-inset dark:ring-zinc-800 dark:hover:bg-zinc-800 dark:hover:text-zinc-300" aria-label="Previous: Cryptography" href="/specs/cryptography"><svg viewBox="0 0 20 20" fill="none" aria-hidden="true" class="mt-0.5 h-5 w-5 -ml-1 rotate-180"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="m11.5 6.5 3 3.5m0 0-3 3.5m3-3.5h-9"></path></svg>Previous</a><a tabindex="-1" aria-hidden="true" class="text-base font-semibold text-zinc-900 transition hover:text-zinc-600 dark:text-white dark:hover:text-zinc-300" href="/specs/cryptography">Cryptography</a></div><div class="ml-auto flex flex-col items-end gap-3"><a class="inline-flex gap-0.5 justify-center overflow-hidden text-sm font-medium transition rounded-full bg-zinc-100 py-1 px-3 text-zinc-900 hover:bg-zinc-200 dark:bg-zinc-800/40 dark:text-zinc-400 dark:ring-1 dark:ring-inset dark:ring-zinc-800 dark:hover:bg-zinc-800 dark:hover:text-zinc-300" aria-label="Next: Blobs" href="/specs/blob">Next<svg viewBox="0 0 20 20" fill="none" aria-hidden="true" class="mt-0.5 h-5 w-5 -mr-1"><path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" d="m11.5 6.5 3 3.5m0 0-3 3.5m3-3.5h-9"></path></svg></a><a tabindex="-1" aria-hidden="true" class="text-base font-semibold text-zinc-900 transition hover:text-zinc-600 dark:text-white dark:hover:text-zinc-300" href="/specs/blob">Blobs</a></div></div><div class="flex flex-col items-center justify-between gap-5 border-t border-zinc-900/5 pt-8 sm:flex-row dark:border-white/5"><p class="text-xs text-zinc-600 dark:text-zinc-400">© Copyright <!-- -->2024<!-- -->. All rights reserved.</p><div class="flex gap-4"><a class="group" href="https://bsky.app/profile/atproto.com"><span class="sr-only">Follow us on Bluesky</span><svg viewBox="0 0 360 320" aria-hidden="true" class="h-5 w-5 fill-zinc-700 transition group-hover:fill-zinc-900 dark:group-hover:fill-zinc-500"><path d="M180 141.964C163.699 110.262 119.308 51.1817 78.0347 22.044C38.4971 -5.86834 23.414 -1.03207 13.526 3.43594C2.08093 8.60755 0 26.1785 0 36.5164C0 46.8542 5.66748 121.272 9.36416 133.694C21.5786 174.738 65.0603 188.607 105.104 184.156C107.151 183.852 109.227 183.572 111.329 183.312C109.267 183.642 107.19 183.924 105.104 184.156C46.4204 192.847 -5.69621 214.233 62.6582 290.33C137.848 368.18 165.705 273.637 180 225.702C194.295 273.637 210.76 364.771 295.995 290.33C360 225.702 313.58 192.85 254.896 184.158C252.81 183.926 250.733 183.645 248.671 183.315C250.773 183.574 252.849 183.855 254.896 184.158C294.94 188.61 338.421 174.74 350.636 133.697C354.333 121.275 360 46.8568 360 36.519C360 26.1811 357.919 8.61012 346.474 3.43851C336.586 -1.02949 321.503 -5.86576 281.965 22.0466C240.692 51.1843 196.301 110.262 180 141.964Z"></path></svg></a><a class="group" href="https://github.com/bluesky-social"><span class="sr-only">Follow us on GitHub</span><svg viewBox="0 0 20 20" aria-hidden="true" class="h-5 w-5 fill-zinc-700 transition group-hover:fill-zinc-900 dark:group-hover:fill-zinc-500"><path fill-rule="evenodd" clip-rule="evenodd" d="M10 1.667c-4.605 0-8.334 3.823-8.334 8.544 0 3.78 2.385 6.974 5.698 8.106.417.075.573-.182.573-.406 0-.203-.011-.875-.011-1.592-2.093.397-2.635-.522-2.802-1.002-.094-.246-.5-1.005-.854-1.207-.291-.16-.708-.556-.01-.567.656-.01 1.124.62 1.281.876.75 1.292 1.948.93 2.427.705.073-.555.291-.93.531-1.143-1.854-.213-3.791-.95-3.791-4.218 0-.929.322-1.698.854-2.296-.083-.214-.375-1.09.083-2.265 0 0 .698-.224 2.292.876a7.576 7.576 0 0 1 2.083-.288c.709 0 1.417.096 2.084.288 1.593-1.11 2.291-.875 2.291-.875.459 1.174.167 2.05.084 2.263.53.599.854 1.357.854 2.297 0 3.278-1.948 4.005-3.802 4.219.302.266.563.78.563 1.58 0 1.143-.011 2.061-.011 2.35 0 .224.156.491.573.405a8.365 8.365 0 0 0 4.11-3.116 8.707 8.707 0 0 0 1.567-4.99c0-4.721-3.73-8.545-8.334-8.545Z"></path></svg></a></div></div></footer></div></div></div><script src="/_next/static/chunks/webpack-496a37b6c26ccd6a.js" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0]);self.__next_f.push([2,null])</script><script>self.__next_f.push([1,"1:HL[\"/_next/static/css/786ca9324488b5df.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"2:I[2846,[],\"\"]\n4:I[2972,[\"972\",\"static/chunks/972-f3553dcbba031b91.js\",\"135\",\"static/chunks/135-8f28b0a70a96c388.js\",\"212\",\"static/chunks/212-67e821188dcd5fb8.js\",\"784\",\"static/chunks/app/%5Blocale%5D/specs/repository/page-45ed8c439a324609.js\"],\"\"]\n5:I[2510,[\"972\",\"static/chunks/972-f3553dcbba031b91.js\",\"135\",\"static/chunks/135-8f28b0a70a96c388.js\",\"212\",\"static/chunks/212-67e821188dcd5fb8.js\",\"784\",\"static/chunks/app/%5Blocale%5D/specs/repository/page-45ed8c439a324609.js\"],\"Code\"]\n6:I[1684,[\"972\",\"static/chunks/972-f3553dcbba031b91.js\",\"135\",\"static/chunks/135-8f28b0a70a96c388.js\",\"212\",\"static/chunks/212-67e821188dcd5fb8.js\",\"784\",\"static/chunks/app/%5Blocale%5D/specs/repository/page-45ed8c439a324609.js\"],\"Heading\"]\n7:I[4707,[],\"\"]\n9:I[6423,[],\"\"]\nc:I[1060,[],\"\"]\n8:[\"locale\",\"en\",\"d\"]\nd:[]\n"])</script><script>self.__next_f.push([1,"0:[\"$\",\"$L2\",null,{\"buildId\":\"UWK7gfTTdjb8rbg3vyV6o\",\"assetPrefix\":\"\",\"urlParts\":[\"\",\"specs\",\"repository\"],\"initialTree\":[\"\",{\"children\":[[\"locale\",\"en\",\"d\"],{\"children\":[\"specs\",{\"children\":[\"repository\",{\"children\":[\"__PAGE__\",{}]}]}]},\"$undefined\",\"$undefined\",true]}],\"initialSeedData\":[\"\",{\"children\":[[\"locale\",\"en\",\"d\"],{\"children\":[\"specs\",{\"children\":[\"repository\",{\"children\":[\"__PAGE__\",{},[[\"$L3\",[\"$\",\"article\",null,{\"className\":\"flex h-full flex-col pb-24 pt-16\",\"children\":[\"$\",\"div\",null,{\"className\":\"flex-auto prose dark:prose-invert [html_:where(\u0026\u003e*)]:mx-auto [html_:where(\u0026\u003e*)]:max-w-2xl [html_:where(\u0026\u003e*)]:lg:mx-[calc(50%-min(50%,theme(maxWidth.lg)))] [html_:where(\u0026\u003e*)]:lg:max-w-3xl\",\"children\":[[\"$\",\"h1\",null,{\"children\":\"Repository\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":[\"$\",\"em\",null,{\"children\":[\"See the \",[\"$\",\"$L4\",null,{\"href\":\"../guides/data-repos\",\"children\":\"Data Repositories Guide\"}],\" for a higher-level introduction.\"]}]}],\"\\n\",[\"$\",\"p\",null,{\"children\":[\"Public atproto content (\",[\"$\",\"strong\",null,{\"children\":\"records\"}],\") is stored in per-account repositories (frequently shortened to \",[\"$\",\"strong\",null,{\"children\":\"repo\"}],\"). All currently active records are stored in the repository, and current repository contents are publicly available, but both content deletions and account deletions are fully supported.\"],\"className\":\"lead\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":[\"The repository data structure is content-addressed (a \",[\"$\",\"$L4\",null,{\"href\":\"https://en.wikipedia.org/wiki/Merkle_tree\",\"children\":\"Merkle-tree\"}],\"), and every mutation of repository contents (eg, addition, removal, and updates to records) results in a new commit \",[\"$\",\"$L5\",null,{\"children\":\"data\"}],\" hash value (CID). Commits are cryptographically signed, with rotatable signing keys, which allows recursive validation of content as a whole or in part.\"],\"className\":\"lead\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":[\"Repositories and their contents are canonically stored in binary \",[\"$\",\"$L4\",null,{\"href\":\"https://ipld.io/docs/codecs/known/dag-cbor/\",\"children\":\"DAG-CBOR\"}],\" format, as a graph of data objects referencing each other by content hash (CID Links). Large binary blobs are not stored directly in repositories, though they are referenced by hash (\",[\"$\",\"$L4\",null,{\"href\":\"https://github.com/multiformats/cid\",\"children\":\"CID\"}],\"). This includes images and other media objects. Repositories can be exported as \",[\"$\",\"$L4\",null,{\"href\":\"https://ipld.io/specs/transport/car/carv1/\",\"children\":\"CAR\"}],\" files for offline backup, account migration, or other purposes.\"],\"className\":\"lead\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"In the atproto federation architecture, the authoritative location of an account's repository is the associated Personal Data Server (PDS). An account's current PDS location is authoritatively indicated in the DID Document.\",\"className\":\"lead\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"In real-world use, it is expected that individual repositories will contain anywhere from dozens to millions of records.\",\"className\":\"lead\"}],\"\\n\",[\"$\",\"$L6\",null,{\"level\":2,\"id\":\"repo-data-structure-v3\",\"children\":\"Repo Data Structure (v3)\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":[\"This describes version \",[\"$\",\"$L5\",null,{\"children\":\"3\"}],\" of the repository binary format.\"]}],\"\\n\",[\"$\",\"p\",null,{\"children\":[\"Version \",[\"$\",\"$L5\",null,{\"children\":\"2\"}],\" had a slightly different commit object schema, but is mostly compatible with \",[\"$\",\"$L5\",null,{\"children\":\"3\"}],\".\"]}],\"\\n\",[\"$\",\"p\",null,{\"children\":[\"Version \",[\"$\",\"$L5\",null,{\"children\":\"1\"}],\" had a different MST fanout configuration, and an incompatible schema for commits and repository metadata. Version \",[\"$\",\"$L5\",null,{\"children\":\"1\"}],\" is deprecated, no repositories in this format exist in the network, and implementations do not need to support it.\"]}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"At a high level, a repository is a key/value mapping where the keys are path names (as strings) and the values are records (DAG-CBOR objects).\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":[\"A \",[\"$\",\"strong\",null,{\"children\":\"Merkle Search Tree\"}],\" (MST) is used to store this mapping. This content-addressed deterministic data structure stores data in key-sorted order. It is reasonably efficient for key lookups, key range scans, and appends (assuming sorted record paths). The properties of MSTs in general are described in this academic publication:\"]}],\"\\n\",[\"$\",\"blockquote\",null,{\"children\":[\"\\n\",[\"$\",\"p\",null,{\"children\":[\"Alex Auvolat, François Taïani. Merkle Search Trees: Efficient State-Based CRDTs in Open Networks. SRDS 2019 - 38th IEEE International Symposium on Reliable Distributed Systems, Oct 2019, Lyon, France. pp.1-10, ff10.1109/SRDS.2019.00032 (\",[\"$\",\"$L4\",null,{\"href\":\"https://inria.hal.science/hal-02303490/document\",\"children\":\"pdf\"}],\")\"]}],\"\\n\"]}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"The specific details of the MST as used in atproto repositories are described below.\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"Repo paths are strings, while MST keys are byte arrays. Neither may be empty (zero-length). While repo path strings are currently limited to a subset of ASCII (making encoding a no-op), the encoding is specified as UTF-8.\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":[\"Repo paths currently have a fixed structure of \",[\"$\",\"$L5\",null,{\"children\":\"\u003ccollection\u003e/\u003crecord-key\u003e\"}],\". This means a valid, normalized \",[\"$\",\"$L4\",null,{\"href\":\"./nsid\",\"children\":\"NSID\"}],\", followed by a \",[\"$\",\"$L5\",null,{\"children\":\"/\"}],\", followed by a valid \",[\"$\",\"$L4\",null,{\"href\":\"./record-key\",\"children\":\"Record Key\"}],\". The path should not start with a leading \",[\"$\",\"$L5\",null,{\"children\":\"/\"}],\", and should always have exactly two path segments. The ASCII characters allowed in the entire path string are currently: letters (\",[\"$\",\"$L5\",null,{\"children\":\"A-Za-z\"}],\"), digits (\",[\"$\",\"$L5\",null,{\"children\":\"0-9\"}],\"), slash (\",[\"$\",\"$L5\",null,{\"children\":\"/\"}],\"), period (\",[\"$\",\"$L5\",null,{\"children\":\".\"}],\"), hyphen (\",[\"$\",\"$L5\",null,{\"children\":\"-\"}],\"), underscore (\",[\"$\",\"$L5\",null,{\"children\":\"_\"}],\"), and tilde (\",[\"$\",\"$L5\",null,{\"children\":\"~\"}],\"). The specific path segments \",[\"$\",\"$L5\",null,{\"children\":\".\"}],\" and \",[\"$\",\"$L5\",null,{\"children\":\"..\"}],\" are not valid NSIDs or Record Keys, and will always be disallowed in repo paths.\"]}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"Note that repo paths for all records in the same collection are sorted together in the MST, making enumeration (via key scan) and export efficient. Additionally, the TID Record Key scheme was intentionally selected to provide chronological sorting of MST keys within the scope of a collection. Appends are more efficient than random insertions/mutations within the tree, and when enumerating records within a collection they will be in chronological order (assuming that TID generation was done correctly, which cannot be relied on in general).\"}],\"\\n\",[\"$\",\"h3\",null,{\"children\":\"Commit Objects\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"The top-level data object in a repository is a signed commit. The data fields are:\"}],\"\\n\",[\"$\",\"ul\",null,{\"children\":[\"\\n\",[\"$\",\"li\",null,{\"children\":[[\"$\",\"$L5\",null,{\"children\":\"did\"}],\" (string, required): the account DID associated with the repo, in strictly normalized form (eg, lowercase as appropriate)\"]}],\"\\n\",[\"$\",\"li\",null,{\"children\":[[\"$\",\"$L5\",null,{\"children\":\"version\"}],\" (integer, required): fixed value of \",[\"$\",\"$L5\",null,{\"children\":\"3\"}],\" for this repo format version\"]}],\"\\n\",[\"$\",\"li\",null,{\"children\":[[\"$\",\"$L5\",null,{\"children\":\"data\"}],\" (CID link, required): pointer to the top of the repo contents tree structure (MST)\"]}],\"\\n\",[\"$\",\"li\",null,{\"children\":[[\"$\",\"$L5\",null,{\"children\":\"rev\"}],\" (string, TID format, required): revision of the repo, used as a logical clock. Must increase monotonically. Recommend using current timestamp as TID; \",[\"$\",\"$L5\",null,{\"children\":\"rev\"}],\" values in the \\\"future\\\" (beyond a fudge factor) should be ignored and not processed.\"]}],\"\\n\",[\"$\",\"li\",null,{\"children\":[[\"$\",\"$L5\",null,{\"children\":\"prev\"}],\" (CID link, nullable): pointer (by hash) to a previous commit object for this repository. Could be used to create a chain of history, but largely unused (included for v2 backwards compatibility). In version \",[\"$\",\"$L5\",null,{\"children\":\"3\"}],\" repos, this field must exist in the CBOR object, but is virtually always \",[\"$\",\"$L5\",null,{\"children\":\"null\"}],\". NOTE: previously specified as nullable and optional, but this caused interoperability issues.\"]}],\"\\n\",[\"$\",\"li\",null,{\"children\":[[\"$\",\"$L5\",null,{\"children\":\"sig\"}],\" (byte array, required): cryptographic signature of this commit, as raw bytes\"]}],\"\\n\"]}],\"\\n\",[\"$\",\"p\",null,{\"children\":[\"An UnsignedCommit data object has all the same fields except for \",[\"$\",\"$L5\",null,{\"children\":\"sig\"}],\". The process for signing a commit is to populate all the data fields, and then serialize the UnsignedCommit with DAG-CBOR. The output bytes are then hashed with SHA-256, and the binary hash output (without hex encoding) is then signed using the current \\\"signing key\\\" for the account. The signature is then stored as raw bytes in a commit object, along with all the other data fields.\"]}],\"\\n\",[\"$\",\"p\",null,{\"children\":[\"The CID for a commit overall is generated by serializing a \",[\"$\",\"em\",null,{\"children\":\"signed\"}],\" commit object as DAG-CBOR. See notes on the \\\"blessed\\\" CID format below, and in particular be sure to use the \",[\"$\",\"$L5\",null,{\"children\":\"dag-cbor\"}],\" multicodec for CIDs linking to commit objects.\"]}],\"\\n\",[\"$\",\"p\",null,{\"children\":[\"Note that neither the signature itself nor the signed commit indicate either the type of key used (curve type), or the specific public key used. That information must be fetched from the account's DID document. With key rotation, verification of older commit signatures can become ambiguous. The most recent commit should always be verifiable using the current DID document. This implies that a new repository commit should be created every time the signing key is rotated. Such a commit does not need to update the \",[\"$\",\"$L5\",null,{\"children\":\"data\"}],\" CID link.\"]}],\"\\n\",[\"$\",\"h3\",null,{\"children\":\"MST Structure\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":[\"At a high level, the repository MST is a key/value mapping where the keys are non-empty byte arrays, and the values are CID links to records. The MST data structure should be fully reproducible from such a mapping of bytestrings-to-CIDs, with exactly reproducible root CID hash (aka, the \",[\"$\",\"$L5\",null,{\"children\":\"data\"}],\" field in commit object).\"]}],\"\\n\",[\"$\",\"p\",null,{\"children\":[\"Every node in the tree structure contains a set of key/CID mappings, as well as links to other sub-tree nodes. The entries and links are in key-sorted order, with all of the keys of a linked sub-tree (recursively) falling in the range corresponding to the link location. The sort order is from \",[\"$\",\"strong\",null,{\"children\":\"left\"}],\" (lexically first) to \",[\"$\",\"strong\",null,{\"children\":\"right\"}],\" (lexically latter). Each key has a \",[\"$\",\"strong\",null,{\"children\":\"depth\"}],\" derived from the key itself, which determines which sub-tree it ends up in. The top node in the tree contains all of the keys with the highest depth value (which for a small tree may be all depth zero, so a single node). Links to the left or right of the entire node, or between any two keys in the node, point to a sub-tree node containing keys that fall in the corresponding key range.\"]}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"An empty repository with no records is represented as a single MST node with an empty array of entries. This is the only situation in which a tree may contain an empty leaf node which does not either contain keys (\\\"entries\\\") or point to a sub-tree containing entries. The top of the tree must not be a an empty node which only points to a sub-tree. Empty intermediate nodes are allowed, as long as they point to a sub-tree which does contain entries. In other words, empty nodes must be pruned from the top and bottom of the tree, but empty intermediate nodes must be kept, such that sub-tree links do not skip a level of depth. The overall structure and shape of the MST is deterministic based on the current key/value content, regardless of the history of insertions and deletions that lead to the current contents.\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"For the atproto MST implementation, the hash algorithm used is SHA-256 (binary output), counting \\\"prefix zeros\\\" in 2-bit chunks, giving a fanout of 4. To compute the depth of a key:\"}],\"\\n\",[\"$\",\"ul\",null,{\"children\":[\"\\n\",[\"$\",\"li\",null,{\"children\":\"hash the key (a byte array) with SHA-256, with binary output\"}],\"\\n\",[\"$\",\"li\",null,{\"children\":\"count the number of leading binary zeros in the hash, and divide by two, rounding down\"}],\"\\n\",[\"$\",\"li\",null,{\"children\":\"the resulting positive integer is the depth of the key\"}],\"\\n\"]}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"Some examples, with the given ASCII strings mapping to byte arrays:\"}],\"\\n\",[\"$\",\"ul\",null,{\"children\":[\"\\n\",[\"$\",\"li\",null,{\"children\":[[\"$\",\"$L5\",null,{\"children\":\"2653ae71\"}],\": depth \\\"0\\\"\"]}],\"\\n\",[\"$\",\"li\",null,{\"children\":[[\"$\",\"$L5\",null,{\"children\":\"blue\"}],\": depth \\\"1\\\"\"]}],\"\\n\",[\"$\",\"li\",null,{\"children\":[[\"$\",\"$L5\",null,{\"children\":\"app.bsky.feed.post/454397e440ec\"}],\": depth \\\"4\\\"\"]}],\"\\n\",[\"$\",\"li\",null,{\"children\":[[\"$\",\"$L5\",null,{\"children\":\"app.bsky.feed.post/9adeb165882c\"}],\": depth \\\"8\\\"\"]}],\"\\n\"]}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"There are many MST nodes in repositories, so it is important that they have a compact binary representation, for storage efficiency. Within every node, keys (byte arrays) are compressed by eliding common prefixes, with each entry indicating how many bytes it shares with the previous key in the array. The first entry in the array for a given node must contain the full key, and a common prefix length of 0. This key compaction is internal to nodes, it does not extend across multiple nodes in the tree. The compaction scheme is mandatory, to ensure that the MST structure is deterministic across implementations.\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"The node data schema fields are:\"}],\"\\n\",[\"$\",\"ul\",null,{\"children\":[\"\\n\",[\"$\",\"li\",null,{\"children\":[[\"$\",\"$L5\",null,{\"children\":\"l\"}],\" (\\\"left\\\", CID link, nullable): link to sub-tree Node on a lower level and with all keys sorting before keys at this node\"]}],\"\\n\",[\"$\",\"li\",null,{\"children\":[[\"$\",\"$L5\",null,{\"children\":\"e\"}],\" (\\\"entries\\\", array of objects, required): ordered list of TreeEntry objects\",\"\\n\",[\"$\",\"ul\",null,{\"children\":[\"\\n\",[\"$\",\"li\",null,{\"children\":[[\"$\",\"$L5\",null,{\"children\":\"p\"}],\" (\\\"prefixlen\\\", integer, required): count of bytes shared with previous TreeEntry in this Node (if any)\"]}],\"\\n\",[\"$\",\"li\",null,{\"children\":[[\"$\",\"$L5\",null,{\"children\":\"k\"}],\" (\\\"keysuffix\\\", byte array, required): remainder of key for this TreeEntry, after \\\"prefixlen\\\" have been removed\"]}],\"\\n\",[\"$\",\"li\",null,{\"children\":[[\"$\",\"$L5\",null,{\"children\":\"v\"}],\" (\\\"value\\\", CID Link, required): link to the record data (CBOR) for this entry\"]}],\"\\n\",[\"$\",\"li\",null,{\"children\":[[\"$\",\"$L5\",null,{\"children\":\"t\"}],\" (\\\"tree\\\", CID Link, nullable): link to a sub-tree Node at a lower level which has keys sorting after this TreeEntry's key (to the \\\"right\\\"), but before the next TreeEntry's key in this Node (if any)\"]}],\"\\n\"]}],\"\\n\"]}],\"\\n\"]}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"When parsing MST data structures, the depth and sort order of keys should be verified. This is particularly true for untrusted inputs, but is simplest to just verify every time. Additional checks on node size and other parameters of the tree structure also need to be limited; see the \\\"Security Considerations\\\" section of this document.\"}],\"\\n\",[\"$\",\"h3\",null,{\"children\":\"CID Formats\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"The IPFS CID specification is very flexible, and supports a wide variety of hash types, a field indicating the type of content being linked to, and various string encoding options. These features are valuable to allow evolution of the repo format over time, but to maximize interoperability among implementations, only a specific \\\"blessed\\\" set of CID types are allowed.\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":[\"The blessed format for commit objects and MST node objects, when linking to commit objects, MST nodes (aka, \",[\"$\",\"$L5\",null,{\"children\":\"data\"}],\", or MST internal links), or records (aka, MST leaf nodes to records), is:\"]}],\"\\n\",[\"$\",\"ul\",null,{\"children\":[\"\\n\",[\"$\",\"li\",null,{\"children\":\"CIDv1\"}],\"\\n\",[\"$\",\"li\",null,{\"children\":[\"Multibase: binary serialization within DAG-CBOR (or \",[\"$\",\"$L5\",null,{\"children\":\"base32\"}],\" for JSON mappings)\"]}],\"\\n\",[\"$\",\"li\",null,{\"children\":[\"Multicodec: \",[\"$\",\"$L5\",null,{\"children\":\"dag-cbor\"}],\" (0x71)\"]}],\"\\n\",[\"$\",\"li\",null,{\"children\":[\"Multihash: \",[\"$\",\"$L5\",null,{\"children\":\"sha-256\"}],\" with 256 bits (0x12)\"]}],\"\\n\"]}],\"\\n\",[\"$\",\"p\",null,{\"children\":[\"In the context of repositories, it is also desirable for the overall data structure to be reproducible given the contents, so the allowed CID types are strictly constrained and enforced. Commit objects with non-compliant \",[\"$\",\"$L5\",null,{\"children\":\"prev\"}],\" or \",[\"$\",\"$L5\",null,{\"children\":\"data\"}],\" links are considered invalid. MST Node objects with non-compliant links to other MST Node objects are considered invalid, and the entire MST data structure invalid.\"]}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"More flexibility is allowed in processing the \\\"leaf\\\" links from MST to records, and implementations should retain the exact CID links used for these mappings, instead of normalizing. Implementations should strictly follow the CID blessed format when generating new CID Links to records.\"}],\"\\n\",[\"$\",\"$L6\",null,{\"level\":2,\"id\":\"car-file-serialization\",\"children\":\"CAR File Serialization\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":[\"The standard file format for storing data objects is Content Addressable aRchives (CAR). The standard repository export format for atproto repositories is \",[\"$\",\"$L4\",null,{\"href\":\"https://ipld.io/specs/transport/car/carv1/\",\"children\":\"CAR v1\"}],\", which have file suffix \",[\"$\",\"$L5\",null,{\"children\":\".car\"}],\" and mimetype \",[\"$\",\"$L5\",null,{\"children\":\"application/vnd.ipld.car\"}],\".\"]}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"The CARv1 format is very simple. It contains a small metadata header (which can indicate one or more \\\"root\\\" CID links), and then a series of binary \\\"blocks\\\", each of which is a data object. In the context of atproto repositories:\"}],\"\\n\",[\"$\",\"ul\",null,{\"children\":[\"\\n\",[\"$\",\"li\",null,{\"children\":[\"The first element of the CAR \",[\"$\",\"$L5\",null,{\"children\":\"roots\"}],\" metadata array must be the CID of the most relevant Commit object. for a generic export, this is the current (most recent) commit. additional CIDs may also be present in the \",[\"$\",\"$L5\",null,{\"children\":\"roots\"}],\" array, with (for now) undefined meaning or order\"]}],\"\\n\",[\"$\",\"li\",null,{\"children\":\"For full exports, the full repo structure must be included for the indicated commit, which includes all records and all MST nodes\"}],\"\\n\",[\"$\",\"li\",null,{\"children\":\"The order of blocks within the CAR file is not currently defined or restricted. implementations may have a \\\"preferred\\\" ordering, but should be tolerant of unexpected ordering\"}],\"\\n\",[\"$\",\"li\",null,{\"children\":\"Additional blocks, including records, may or may not be included in the CAR file\"}],\"\\n\"]}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"When importing CAR files, note that there may existing dangling CID references. For example, repositories may contain CID Links to blobs or records in other repositories, and the blocks corresponding to those blobs or references would likely not be included in the CAR file.\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"The CARv1 specification is agnostic about the same block appearing multiple times in the same file (\\\"Duplicate Blocks)\\\". Implementations should be robust to both duplication and de-duplication of blocks, and should also ignore any unnecessary or unlinked blocks.\"}],\"\\n\",[\"$\",\"$L6\",null,{\"level\":2,\"id\":\"repository-diffs\",\"children\":\"Repository Diffs\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"A concept which supports efficient synchronization of data between independent services is \\\"diffs\\\" of repository trees between different revisions. The basic principle is that a repository diff contains all the data (commit object, MST nodes, and records) that have changed between an older revision and the current revision of a repo. The diff can be \\\"applied\\\" to the older mirror of the repository, and the result will be the complete MST tree at the current (newer) commit revision.\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"Repo diffs can be serialized as CAR files, sometimes referred to as \\\"CAR slices\\\". Some details about diff CAR slices:\"}],\"\\n\",[\"$\",\"ul\",null,{\"children\":[\"\\n\",[\"$\",\"li\",null,{\"children\":[\"same format, version, and atproto-specific constraints as full repo export CAR files\",\"\\n\",[\"$\",\"ul\",null,{\"children\":[\"\\n\",[\"$\",\"li\",null,{\"children\":\"blocks \\\"should\\\" be de-duplicated by CID (only one copy included), though receiving implementations must be resilient to duplication\"}],\"\\n\"]}],\"\\n\"]}],\"\\n\",[\"$\",\"li\",null,{\"children\":[\"the root CID indicated in the CAR header (the first element of \",[\"$\",\"$L5\",null,{\"children\":\"roots\"}],\") should point to the commit block (which must be included)\"]}],\"\\n\",[\"$\",\"li\",null,{\"children\":\"any required blocks must be included even if they have appeared in the history of the repository previously. eg, if a record is created in rev C, deleted in rev F, and re-created in rev N, the diff \\\"since F\\\" must include the record block\"}],\"\\n\",[\"$\",\"li\",null,{\"children\":\"all \\\"created\\\" records must be included\"}],\"\\n\",[\"$\",\"li\",null,{\"children\":\"any records which have been \\\"deleted\\\" and do not exist in the current repo should not be included\"}],\"\\n\",[\"$\",\"li\",null,{\"children\":\"any records which have been \\\"updated\\\" should include the final version, and should not include the previous version\"}],\"\\n\",[\"$\",\"li\",null,{\"children\":\"all MST nodes in the current repo which didn't exist in the previous repo version must be included\"}],\"\\n\",[\"$\",\"li\",null,{\"children\":[\"with the exception of removed record data, the diff may include additional blocks, which receivers should ignore.\",\"\\n\",[\"$\",\"ul\",null,{\"children\":[\"\\n\",[\"$\",\"li\",null,{\"children\":\"however, diffs which intentionally contain a large amount of irrelevant block data to consume network or compute resources are considered a form of network abuse.\"}],\"\\n\"]}],\"\\n\"]}],\"\\n\"]}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"The diff is a partial Merkle tree, including a signed commit, and can be partially verified. This means that an observer which has successfully resolved the identity of the relevant account (including cryptographic public keys) can verify certain aspects of the data. The diff is a reliable \\\"proof chain\\\" for creation and updates of records: an observer can verify that the new or updated records have the specific record values in the overall repo as of the commit revision. If the observer knows of specific records (by repo path, or by full AT-URI) that have been deleted, they can verify that those records no longer exist in the repo as of the final commit revision.\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":[\"However, an observer which does not know the full state of the repository at the \\\"older\\\" revision \",[\"$\",\"em\",null,{\"children\":\"can not\"}],\" reliably enumerate all of the records that have been removed from the repository. Such an observer also can not see the previous values of deleted or updated records, either as full values or by CID. Note that the later is an intentional design goal for the diff concept: it is desired that content deletion happen rapidly and not \\\"draw attention\\\" to the content which has been deleted. It is technically possible for \\\"archival\\\" observers to track deletion events and lookup the previous content value, but this requires additional resources and effort.\"]}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"Sometimes repo diffs are generated automatically. For example, every commit to a repo can result in a diff against the immediately preceding commit. In other contexts, diffs are generated on demand: a diff can be requested \\\"since\\\" an arbitrary previous revision. It is not expected that repo hosts support generating diffs between two arbitrary revisions, only \\\"from\\\" an arbitrary older revision and the current revision. Repo hosts are not required to maintain a complete history of prior commits/revisions, and in some cases (such as account migration) may never have had prior repo history. Some details about how to interpret and service requests for diffs \\\"since\\\" a prior revision:\"}],\"\\n\",[\"$\",\"ul\",null,{\"children\":[\"\\n\",[\"$\",\"li\",null,{\"children\":\"it is helpful to track internally the commit revision when a block (record or MST node) was created or re-created. This enables querying blocks \\\"since\\\" a point in time\"}],\"\\n\",[\"$\",\"li\",null,{\"children\":[\"\\\"since\\\" revisions are not expected to be an exact match\",\"\\n\",[\"$\",\"ul\",null,{\"children\":[\"\\n\",[\"$\",\"li\",null,{\"children\":\"for example, if a repo had a sequence of commits \\\"333\\\", \\\"666\\\", \\\"999\\\", and a \\\"since\\\" value of \\\"444\\\" was requested, the changes in \\\"666\\\" and \\\"999\\\" should be included, as if the \\\"since\\\" parameter was \\\"666\\\"..\"}],\"\\n\"]}],\"\\n\"]}],\"\\n\",[\"$\",\"li\",null,{\"children\":[\"a host is allowed to include additional history, but is encouraged to return the minimal or most granular requested data\",\"\\n\",[\"$\",\"ul\",null,{\"children\":[\"\\n\",[\"$\",\"li\",null,{\"children\":\"for example, a host may have \\\"compacted\\\" repo rev history to a smaller number of commits. If a repo had commit history \\\"288\\\", \\\"300\\\", \\\"320\\\", \\\"340\\\", \\\"400\\\", and got a request \\\"since\\\" 340, it might return all changes since 300. Hosts are encouraged to return the smallest diff when possible (eg, “since” 340), but clients should be resilient.\"}],\"\\n\"]}],\"\\n\"]}],\"\\n\",[\"$\",\"li\",null,{\"children\":[\"if a host receives a “since” request earlier than the oldest available revision for a repository, it should return the full repository. This may happen if the host does not have the complete history of the repository.\",\"\\n\",[\"$\",\"ul\",null,{\"children\":[\"\\n\",[\"$\",\"li\",null,{\"children\":\"for example, if a repository had revisions \\\"140\\\", \\\"150\\\", and \\\"160\\\", then migrated to a new PDS and revisions continued \\\"161\\\" and \\\"170\\\", if the new PDS is asked for a diff \\\"since\\\" 150, the new PDS would probably need to return the full repository, because the earliest revision it would be aware of was \\\"160\\\" or \\\"161\\\" (depending on how migration was implemented).\"}],\"\\n\"]}],\"\\n\"]}],\"\\n\"]}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"In the specific case of chained commit-to-commit diffs which appear on the firehose, diffs should be \\\"minimal\\\": they should not contain additional records or additional history.\"}],\"\\n\",[\"$\",\"$L6\",null,{\"level\":2,\"id\":\"security-considerations\",\"children\":\"Security Considerations\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"Repositories are untrusted input: accounts have full control over repository contents, and PDS instances have full control over binary encoding. It is important to handle possible denial of service vectors from both hostile actors or accidental situations (eg, corrupted data or buggy implementations).\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"Generic precautions should be followed with CBOR decoding: a maximum serialized object size, a maximum recursion depth for nested fields, maximum memory budget for deserialized data, etc. Some CBOR libraries include these precautions by default, but others do not.\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"The efficiency of the MST data structure depends on key hashes being relatively randomly dispersed. Because accounts have control over Record Keys, they can mine for sets of record keys with particular depths and sorting order, which result in inefficient tree shapes, which can cause both large storage overhead, and network amplification in the context of federation streams. To protect against these attacks, implementations should limit the number of TreeEntries per Node to a statistically unlikely maximum length. It may also be necessary to limit the overall depth of the repo, or other parameters, to prevent more sophisticated key mining attacks.\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"When importing CAR files, the completeness of the repository structure should be verified. Additional unrelated blocks might be included in the CAR structure; care should be taken when injecting CAR contents directly in to backend block storage, to ensure resources are not wasted on un-referenced blocks. There may also be issues with cross-account contamination from CAR imports, for example previously-deleted records re-appearing via CAR import from an unrelated account.\"}],\"\\n\",[\"$\",\"$L6\",null,{\"level\":2,\"id\":\"possible-future-changes\",\"children\":\"Possible Future Changes\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"An optional in-repo mechanism for storing multiple versions of the same record (by path) may be implemented. Eg, adding additional path field to indicate the version by CID, timestamp, or monotonically increasing version integer.\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"Mechanisms for storing metadata associated with each record are being considered, for example, generic label, re-use rights, or hashtag metadata. This would allow mutating the metadata without mutating the record itself, and make some metadata generic across lexicons.\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"Repo path restrictions may be relaxed in other ways, including fewer or additional path segments, more allowed characters (including non-ASCII), etc. Paths will always be valid Unicode strings, mapped to MST keys (byte arrays) by UTF-8 encoding.\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"At the overall atproto specification level, additional \\\"blessed\\\" cryptographic algorithms may be added over time. Likewise, additional CID formats to reference records and blobs may be added. Internal CID format changes would require a repo format version bump.\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":[\"Repository CAR exports may include linked \\\"blobs\\\" (larger binary files). This might become the default, or a configurable option, or some another mechanism for blob export might be chosen (eg, \",[\"$\",\"$L5\",null,{\"children\":\".tar\"}],\" or \",[\"$\",\"$L5\",null,{\"children\":\".zip\"}],\" export).\"]}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"Record content could conceivably be something other than DAG-CBOR some day. This would probably be a repo format version bump. Note that it is possible to efficiently wrap other data formats in a DAG-CBOR wrapper (via a byte array field), or to have a small DAG-CBOR record type that links to a blob in arbitrary format.\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"Repository CAR exports may end up with a preferred block ordering scheme specified.\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"The CARv2 file format, which includes optimizations for some use cases, may be adopted in some form.\"}],\"\\n\",[\"$\",\"p\",null,{\"children\":\"Adding optional fields to commit and MST node objects may or may not result in a repo format version change. Changing the MST fanout, or any changes to the current MST fields, would be a full repo version change.\"}]]}]}],null],null],null]},[null,[\"$\",\"$L7\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\",\"$8\",\"children\",\"specs\",\"children\",\"repository\",\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L9\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"notFoundStyles\":\"$undefined\"}]],null]},[null,[\"$\",\"$L7\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\",\"$8\",\"children\",\"specs\",\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L9\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"notFoundStyles\":\"$undefined\"}]],null]},[[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/786ca9324488b5df.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\"}]],\"$La\"],null],null]},[null,[\"$\",\"$L7\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L9\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":\"404\"}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],\"notFoundStyles\":[]}]],null],\"couldBeIntercepted\":false,\"initialHead\":[null,\"$Lb\"],\"globalErrorComponent\":\"$c\",\"missingSlots\":\"$Wd\"}]\n"])</script><script>self.__next_f.push([1,"b:[[\"$\",\"meta\",\"0\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"1\",{\"charSet\":\"utf-8\"}],[\"$\",\"title\",\"2\",{\"children\":\"Repository - AT Protocol\"}],[\"$\",\"meta\",\"3\",{\"name\":\"description\",\"content\":\"Self-authenticating storage for public account content\"}],[\"$\",\"meta\",\"4\",{\"property\":\"og:title\",\"content\":\"Repository - AT Protocol\"}],[\"$\",\"meta\",\"5\",{\"property\":\"og:description\",\"content\":\"Self-authenticating storage for public account content\"}],[\"$\",\"meta\",\"6\",{\"property\":\"og:url\",\"content\":\"https://atproto.com/\"}],[\"$\",\"meta\",\"7\",{\"property\":\"og:site_name\",\"content\":\"AT Protocol\"}],[\"$\",\"meta\",\"8\",{\"property\":\"og:image\",\"content\":\"https://atproto.com/default-social-card.png\"}],[\"$\",\"meta\",\"9\",{\"property\":\"og:image:secure_url\",\"content\":\"https://atproto.com/default-social-card.png\"}],[\"$\",\"meta\",\"10\",{\"property\":\"og:image:width\",\"content\":\"1200\"}],[\"$\",\"meta\",\"11\",{\"property\":\"og:image:height\",\"content\":\"630\"}],[\"$\",\"meta\",\"12\",{\"property\":\"og:type\",\"content\":\"website\"}],[\"$\",\"meta\",\"13\",{\"name\":\"twitter:card\",\"content\":\"summary_large_image\"}],[\"$\",\"meta\",\"14\",{\"name\":\"twitter:title\",\"content\":\"Repository - AT Protocol\"}],[\"$\",\"meta\",\"15\",{\"name\":\"twitter:description\",\"content\":\"Self-authenticating storage for public account content\"}],[\"$\",\"meta\",\"16\",{\"name\":\"twitter:image\",\"content\":\"https://atproto.com/default-social-card.png\"}]]\n3:null\n"])</script><script>self.__next_f.push([1,"e:I[5552,[\"972\",\"static/chunks/972-f3553dcbba031b91.js\",\"135\",\"static/chunks/135-8f28b0a70a96c388.js\",\"28\",\"static/chunks/28-313384c6289a00c0.js\",\"369\",\"static/chunks/369-a583bbb81b96a7d8.js\",\"212\",\"static/chunks/212-67e821188dcd5fb8.js\",\"60\",\"static/chunks/60-3e1824554a9cf3f8.js\",\"203\",\"static/chunks/app/%5Blocale%5D/layout-8706067c5d993875.js\"],\"Providers\"]\nf:I[5211,[\"972\",\"static/chunks/972-f3553dcbba031b91.js\",\"135\",\"static/chunks/135-8f28b0a70a96c388.js\",\"28\",\"static/chunks/28-313384c6289a00c0.js\",\"369\",\"static/chunks/369-a583bbb81b96a7d8.js\",\"212\",\"static/chunks/212-67e821188dcd5fb8.js\",\"60\",\"static/chunks/60-3e1824554a9cf3f8.js\",\"203\",\"static/chunks/app/%5Blocale%5D/layout-8706067c5d993875.js\"],\"Layout\"]\n"])</script><script>self.__next_f.push([1,"a:[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"h-full\",\"suppressHydrationWarning\":true,\"children\":[\"$\",\"body\",null,{\"className\":\"flex min-h-full bg-white antialiased dark:bg-zinc-900\",\"children\":[\"$\",\"$Le\",null,{\"children\":[\"$\",\"div\",null,{\"className\":\"w-full\",\"children\":[\"$\",\"$Lf\",null,{\"allSections\":{\"/en.mdx\":[],\"/ja.mdx\":[],\"/pt.mdx\":[],\"/explorer\":[],\"/sdks\":[{\"title\":\"Official libraries\",\"id\":\"official-libraries\"},{\"title\":\"Community libraries\",\"id\":\"community-libraries\"}],\"/articles/atproto-for-distsys-engineers/en.mdx\":[{\"title\":\"Scaling the traditional Web backend\",\"id\":\"scaling-the-traditional-web-backend\"},{\"title\":\"Decentralizing our high-scale backend\",\"id\":\"decentralizing-our-high-scale-backend\"},{\"title\":\"Unifying the data model\",\"id\":\"unifying-the-data-model\"},{\"title\":\"Charting the flow of data\",\"id\":\"charting-the-flow-of-data\"},{\"title\":\"Building practical open systems\",\"id\":\"building-practical-open-systems\"}],\"/articles/atproto-for-distsys-engineers/ja.mdx\":[{\"title\":\"従来の Web バックエンドのスケーリング\",\"id\":\"web\"},{\"title\":\"大規模バックエンドの分散化\",\"id\":\"\"},{\"title\":\"データ モデルの統合\",\"id\":\"\"},{\"title\":\"データの流れを図に表す\",\"id\":\"\"},{\"title\":\"実用的なオープン システムの構築\",\"id\":\"\"}],\"/articles/atproto-for-distsys-engineers/pt.mdx\":[{\"title\":\"Escalando o backend tradicional da Web\",\"id\":\"escalando-o-backend-tradicional-da-web\"},{\"title\":\"Descentralizando nosso backend de alta escala\",\"id\":\"descentralizando-nosso-backend-de-alta-escala\"},{\"title\":\"Unificando o modelo de dados\",\"id\":\"unificando-o-modelo-de-dados\"},{\"title\":\"Mapeando o fluxo de dados\",\"id\":\"mapeando-o-fluxo-de-dados\"},{\"title\":\"Construindo sistemas abertos práticos\",\"id\":\"construindo-sistemas-abertos-praticos\"}],\"/articles/why-atproto\":[],\"/guides/data-repos/en.mdx\":[{\"title\":\"Data Layout\",\"id\":\"data-layout\"},{\"title\":\"Identifier Types\",\"id\":\"identifier-types\"}],\"/guides/data-repos/ja.mdx\":[{\"title\":\"データ レイアウト\",\"id\":\"\"},{\"title\":\"識別子の種類\",\"id\":\"\"}],\"/guides/data-repos/pt.mdx\":[{\"title\":\"Layout de dados\",\"id\":\"layout-de-dados\"},{\"title\":\"Tipos de Identificadores\",\"id\":\"tipos-de-identificadores\"}],\"/guides/faq/en.mdx\":[{\"title\":\"Is the AT Protocol a blockchain?\",\"id\":\"is-the-at-protocol-a-blockchain\"},{\"title\":\"Why not use ActivityPub?\",\"id\":\"why-not-use-activity-pub\"},{\"title\":\"Why create Lexicon instead of using JSON-LD or RDF?\",\"id\":\"why-create-lexicon-instead-of-using-json-ld-or-rdf\"},{\"title\":\"What is “XRPC,” and why not use ___?\",\"id\":\"what-is-xrpc-and-why-not-use\"}],\"/guides/faq/ja.mdx\":[{\"title\":\"AT プロトコルはブロックチェーンですか?\",\"id\":\"at\"},{\"title\":\"ActivityPub を使用しないのはなぜですか?\",\"id\":\"activity-pub\"},{\"title\":\"JSON-LD や RDF を使用する代わりに Lexicon を作成する理由\",\"id\":\"json-ld-rdf-lexicon\"},{\"title\":\"「XRPC」とは何ですか。なぜ ___ を使用しないのですか?\",\"id\":\"xrpc\"}],\"/guides/faq/pt.mdx\":[{\"title\":\"O Protocolo AT é uma blockchain?\",\"id\":\"o-protocolo-at-e-uma-blockchain\"},{\"title\":\"Por que não usar o ActivityPub?\",\"id\":\"por-que-nao-usar-o-activity-pub\"},{\"title\":\"Por que criar o Lexicon em vez de usar JSON-LD ou RDF?\",\"id\":\"por-que-criar-o-lexicon-em-vez-de-usar-json-ld-ou-rdf\"},{\"title\":\"O que é “XRPC” e por que não usar ___?\",\"id\":\"o-que-e-xrpc-e-por-que-nao-usar\"}],\"/guides/glossary/en.mdx\":[{\"title\":\"Atmosphere\",\"id\":\"atmosphere\"},{\"title\":\"AT Protocol\",\"id\":\"at-protocol\"},{\"title\":\"PDS (Personal Data Server)\",\"id\":\"pds-personal-data-server\"},{\"title\":\"AppView\",\"id\":\"app-view\"},{\"title\":\"Relay\",\"id\":\"relay\"},{\"title\":\"Lexicon\",\"id\":\"lexicon\"},{\"title\":\"Data Repo\",\"id\":\"data-repo\"},{\"title\":\"Collection\",\"id\":\"collection\"},{\"title\":\"Record\",\"id\":\"record\"},{\"title\":\"Blob\",\"id\":\"blob\"},{\"title\":\"Label\",\"id\":\"label\"},{\"title\":\"Handle\",\"id\":\"handle\"},{\"title\":\"DID (Decentralized ID)\",\"id\":\"did-decentralized-id\"},{\"title\":\"NSID (Namespaced ID)\",\"id\":\"nsid-namespaced-id\"},{\"title\":\"TID (Timestamp ID)\",\"id\":\"tid-timestamp-id\"},{\"title\":\"CID (Content ID)\",\"id\":\"cid-content-id\"},{\"title\":\"DAG-CBOR\",\"id\":\"dag-cbor\"},{\"title\":\"XRPC\",\"id\":\"xrpc\"}],\"/guides/glossary/ja.mdx\":[{\"title\":\"Atmosphere\",\"id\":\"atmosphere\"},{\"title\":\"AT プロトコル\",\"id\":\"at\"},{\"title\":\"PDS (パーソナル データ サーバー)\",\"id\":\"pds\"},{\"title\":\"AppView\",\"id\":\"app-view\"},{\"title\":\"リレー\",\"id\":\"\"},{\"title\":\"Lexicon\",\"id\":\"lexicon\"},{\"title\":\"データ リポジトリ\",\"id\":\"\"},{\"title\":\"コレクション\",\"id\":\"\"},{\"title\":\"レコード\",\"id\":\"\"},{\"title\":\"BLOB\",\"id\":\"blob\"},{\"title\":\"ラベル\",\"id\":\"\"},{\"title\":\"ハンドル\",\"id\":\"\"},{\"title\":\"DID (分散 ID)\",\"id\":\"did-id\"},{\"title\":\"NSID (名前空間 ID)\",\"id\":\"nsid-id\"},{\"title\":\"TID (タイムスタンプ ID)\",\"id\":\"tid-id\"},{\"title\":\"CID (コンテンツ ID)\",\"id\":\"cid-id\"},{\"title\":\"DAG-CBOR\",\"id\":\"dag-cbor\"},{\"title\":\"XRPC\",\"id\":\"xrpc\"}],\"/guides/glossary/pt.mdx\":[{\"title\":\"Atmosphere\",\"id\":\"atmosphere\"},{\"title\":\"AT Protocol\",\"id\":\"at-protocol\"},{\"title\":\"PDS (Personal Data Server)\",\"id\":\"pds-personal-data-server\"},{\"title\":\"AppView\",\"id\":\"app-view\"},{\"title\":\"Relay\",\"id\":\"relay\"},{\"title\":\"Lexicon\",\"id\":\"lexicon\"},{\"title\":\"Data Repo\",\"id\":\"data-repo\"},{\"title\":\"Collection\",\"id\":\"collection\"},{\"title\":\"Record\",\"id\":\"record\"},{\"title\":\"Blob\",\"id\":\"blob\"},{\"title\":\"Label\",\"id\":\"label\"},{\"title\":\"Handle\",\"id\":\"handle\"},{\"title\":\"DID (Decentralized ID)\",\"id\":\"did-decentralized-id\"},{\"title\":\"NSID (Namespaced ID)\",\"id\":\"nsid-namespaced-id\"},{\"title\":\"TID (Timestamp ID)\",\"id\":\"tid-timestamp-id\"},{\"title\":\"CID (Content ID)\",\"id\":\"cid-content-id\"},{\"title\":\"DAG-CBOR\",\"id\":\"dag-cbor\"},{\"title\":\"XRPC\",\"id\":\"xrpc\"}],\"/guides/applications/en.mdx\":[{\"title\":\"Introduction\",\"id\":\"introduction\"},{\"title\":\"Step 1. Starting with our ExpressJS app\",\"id\":\"step-1-starting-with-our-express-js-app\"},{\"title\":\"Step 2. Signing in with OAuth\",\"id\":\"step-2-signing-in-with-o-auth\"},{\"title\":\"Step 3. Fetching the user's profile\",\"id\":\"step-3-fetching-the-users-profile\"},{\"title\":\"Step 4. Reading \u0026 writing records\",\"id\":\"step-4-reading-and-writing-records\"},{\"title\":\"Step 5. Creating a custom \\\"status\\\" schema\",\"id\":\"step-5-creating-a-custom-status-schema\"},{\"title\":\"Step 6. Listening to the firehose\",\"id\":\"step-6-listening-to-the-firehose\"},{\"title\":\"Step 7. Listing the latest statuses\",\"id\":\"step-7-listing-the-latest-statuses\"},{\"title\":\"Step 8. Optimistic updates\",\"id\":\"step-8-optimistic-updates\"},{\"title\":\"Thinking in AT Proto\",\"id\":\"thinking-in-at-proto\"},{\"title\":\"Next steps\",\"id\":\"next-steps\"}],\"/guides/applications/ja.mdx\":[{\"title\":\"はじめに\",\"id\":\"\"},{\"title\":\"ステップ 1. ExpressJS アプリから始める\",\"id\":\"1-express-js\"},{\"title\":\"ステップ 2. OAuth でサインイン\",\"id\":\"2-o-auth\"},{\"title\":\"ステップ 3. ユーザーのプロファイルを取得する\",\"id\":\"3\"},{\"title\":\"ステップ 4. レコードの読み取りと書き込み\",\"id\":\"4\"},{\"title\":\"ステップ 5. カスタムの「ステータス」スキーマの作成\",\"id\":\"5\"},{\"title\":\"ステップ 6. ファイアホースをリッスン\",\"id\":\"6\"},{\"title\":\"ステップ 7. 最新のステータスを一覧表示する\",\"id\":\"7\"},{\"title\":\"ステップ 8. 楽観的更新\",\"id\":\"8\"},{\"title\":\"AT Proto で考える\",\"id\":\"at-proto\"},{\"title\":\"次のステップ\",\"id\":\"\"}],\"/guides/applications/pt.mdx\":[{\"title\":\"Introdução\",\"id\":\"introducao\"},{\"title\":\"Etapa 1. Começando com nosso aplicativo ExpressJS\",\"id\":\"etapa-1-comecando-com-nosso-aplicativo-express-js\"},{\"title\":\"Etapa 2. Entrando com OAuth\",\"id\":\"etapa-2-entrando-com-o-auth\"},{\"title\":\"Etapa 3. Obtendo o perfil do usuário\",\"id\":\"etapa-3-obtendo-o-perfil-do-usuario\"},{\"title\":\"Etapa 4. Lendo e escrevendo registros\",\"id\":\"etapa-4-lendo-e-escrevendo-registros\"},{\"title\":\"Etapa 5. Criando um esquema de \\\"status\\\" personalizado\",\"id\":\"etapa-5-criando-um-esquema-de-status-personalizado\"},{\"title\":\"Etapa 6. Ouvindo o firehose\",\"id\":\"etapa-6-ouvindo-o-firehose\"},{\"title\":\"Etapa 7. Listando os status mais recentes\",\"id\":\"etapa-7-listando-os-status-mais-recentes\"},{\"title\":\"Etapa 8. Atualizações otimistas\",\"id\":\"etapa-8-atualizacoes-otimistas\"},{\"title\":\"Pensando em AT Proto\",\"id\":\"pensando-em-at-proto\"},{\"title\":\"Próximos passos\",\"id\":\"proximos-passos\"}],\"/guides/identity/en.mdx\":[{\"title\":\"Identifiers\",\"id\":\"identifiers\"},{\"title\":\"DID Methods\",\"id\":\"did-methods\"},{\"title\":\"Handle Resolution\",\"id\":\"handle-resolution\"}],\"/guides/identity/ja.mdx\":[{\"title\":\"識別子\",\"id\":\"\"},{\"title\":\"DID メソッド\",\"id\":\"did\"},{\"title\":\"ハンドル解決\",\"id\":\"\"}],\"/guides/identity/pt.mdx\":[{\"title\":\"Identificadores\",\"id\":\"identificadores\"},{\"title\":\"Métodos DID\",\"id\":\"metodos-did\"},{\"title\":\"Resolução de identificadores\",\"id\":\"resolucao-de-identificadores\"}],\"/guides/lexicon/en.mdx\":[{\"title\":\"Why is Lexicon needed?\",\"id\":\"why-is-lexicon-needed\"},{\"title\":\"HTTP API methods\",\"id\":\"http-api-methods\"},{\"title\":\"Record types\",\"id\":\"record-types\"},{\"title\":\"Tokens\",\"id\":\"tokens\"},{\"title\":\"Versioning\",\"id\":\"versioning\"},{\"title\":\"Schema distribution\",\"id\":\"schema-distribution\"}],\"/guides/lexicon/ja.mdx\":[{\"title\":\"Lexicon が必要な理由\",\"id\":\"lexicon\"},{\"title\":\"HTTP API メソッド\",\"id\":\"http-api\"},{\"title\":\"レコード タイプ\",\"id\":\"\"},{\"title\":\"トークン\",\"id\":\"\"},{\"title\":\"バージョン管理\",\"id\":\"\"},{\"title\":\"スキーマの配布\",\"id\":\"\"}],\"/guides/lexicon/pt.mdx\":[{\"title\":\"Por que o Lexicon é necessário?\",\"id\":\"por-que-o-lexicon-e-necessario\"},{\"title\":\"Métodos de API HTTP\",\"id\":\"metodos-de-api-http\"},{\"title\":\"Tipos de registro\",\"id\":\"tipos-de-registro\"},{\"title\":\"Tokens\",\"id\":\"tokens\"},{\"title\":\"Versionamento\",\"id\":\"versionamento\"},{\"title\":\"Distribuição de esquema\",\"id\":\"distribuicao-de-esquema\"}],\"/guides/overview/en.mdx\":[{\"title\":\"Identity\",\"id\":\"identity\"},{\"title\":\"Data repositories\",\"id\":\"data-repositories\"},{\"title\":\"Federation\",\"id\":\"federation\"},{\"title\":\"Interoperation\",\"id\":\"interoperation\"},{\"title\":\"Achieving scale\",\"id\":\"achieving-scale\"},{\"title\":\"Algorithmic choice\",\"id\":\"algorithmic-choice\"},{\"title\":\"Account portability\",\"id\":\"account-portability\"},{\"title\":\"Speech, reach, and moderation\",\"id\":\"speech-reach-and-moderation\"},{\"title\":\"Specifications\",\"id\":\"specifications\"}],\"/guides/overview/ja.mdx\":[{\"title\":\"アイデンティティ\",\"id\":\"\"},{\"title\":\"データ リポジトリ\",\"id\":\"\"},{\"title\":\"フェデレーション\",\"id\":\"\"},{\"title\":\"相互運用\",\"id\":\"\"},{\"title\":\"スケールの実現\",\"id\":\"\"},{\"title\":\"アルゴリズムの選択\",\"id\":\"\"},{\"title\":\"アカウントの移植性\",\"id\":\"\"},{\"title\":\"スピーチ、リーチ、モデレーション\",\"id\":\"\"},{\"title\":\"仕様\",\"id\":\"\"}],\"/guides/overview/pt.mdx\":[{\"title\":\"Identidade\",\"id\":\"identidade\"},{\"title\":\"Repositórios de dados\",\"id\":\"repositorios-de-dados\"},{\"title\":\"Federação\",\"id\":\"federacao\"},{\"title\":\"Interoperação\",\"id\":\"interoperacao\"},{\"title\":\"Alcançando escala\",\"id\":\"alcancando-escala\"},{\"title\":\"Escolha algorítmica\",\"id\":\"escolha-algoritmica\"},{\"title\":\"Portabilidade de conta\",\"id\":\"portabilidade-de-conta\"},{\"title\":\"Fala, alcance e moderação\",\"id\":\"fala-alcance-e-moderacao\"},{\"title\":\"Especificações\",\"id\":\"especificacoes\"}],\"/guides/self-hosting/en.mdx\":[{\"title\":\"Table of Contents\",\"id\":\"table-of-contents\"},{\"title\":\"Preparation for self-hosting PDS\",\"id\":\"preparation-for-self-hosting-pds\"},{\"title\":\"Open your cloud firewall for HTTP and HTTPS\",\"id\":\"open-your-cloud-firewall-for-http-and-https\"},{\"title\":\"Configure DNS for your domain\",\"id\":\"configure-dns-for-your-domain\"},{\"title\":\"Check that DNS is working as expected\",\"id\":\"check-that-dns-is-working-as-expected\"},{\"title\":\"Installer on Ubuntu 20.04/22.04 and Debian 11/12\",\"id\":\"installer-on-ubuntu-20-04-22-04-and-debian-11-12\"},{\"title\":\"Verifying that your PDS is online and accessible\",\"id\":\"verifying-that-your-pds-is-online-and-accessible\"},{\"title\":\"Creating an account using pdsadmin\",\"id\":\"creating-an-account-using-pdsadmin\"},{\"title\":\"Creating an account using an invite code\",\"id\":\"creating-an-account-using-an-invite-code\"},{\"title\":\"Using the Bluesky app with your PDS\",\"id\":\"using-the-bluesky-app-with-your-pds\"},{\"title\":\"Updating your PDS\",\"id\":\"updating-your-pds\"},{\"title\":\"Getting help\",\"id\":\"getting-help\"}],\"/guides/self-hosting/ja.mdx\":[{\"title\":\"目次\",\"id\":\"\"},{\"title\":\"セルフホスティング PDS の準備\",\"id\":\"pds\"},{\"title\":\"クラウド ファイアウォールを HTTP および HTTPS 用に開く\",\"id\":\"http-https\"},{\"title\":\"ドメインの DNS を構成する\",\"id\":\"dns\"},{\"title\":\"DNS が期待どおりに動作していることを確認します\",\"id\":\"dns-2\"},{\"title\":\"Ubuntu 20.04/22.04 および Debian 11/12 のインストーラー\",\"id\":\"ubuntu-20-04-22-04-debian-11-12\"},{\"title\":\"PDS がオンラインでアクセス可能であることを確認する\",\"id\":\"pds-2\"},{\"title\":\"pdsadmin を使用してアカウントを作成する\",\"id\":\"pdsadmin\"},{\"title\":\"招待コードを使用してアカウントを作成する\",\"id\":\"\"},{\"title\":\"PDS で Bluesky アプリを使用する\",\"id\":\"pds-bluesky\"},{\"title\":\"PDS の更新\",\"id\":\"pds-3\"},{\"title\":\"ヘルプの取得\",\"id\":\"\"}],\"/guides/self-hosting/pt.mdx\":[{\"title\":\"Índice\",\"id\":\"indice\"},{\"title\":\"Preparação para auto-hospedagem de PDS\",\"id\":\"preparacao-para-auto-hospedagem-de-pds\"},{\"title\":\"Abra seu firewall de nuvem para HTTP e HTTPS\",\"id\":\"abra-seu-firewall-de-nuvem-para-http-e-https\"},{\"title\":\"Configure o DNS para seu domínio\",\"id\":\"configure-o-dns-para-seu-dominio\"},{\"title\":\"Verifique se o DNS está funcionando conforme o esperado\",\"id\":\"verifique-se-o-dns-esta-funcionando-conforme-o-esperado\"},{\"title\":\"Instalador no Ubuntu 20.04/22.04 e Debian 11/12\",\"id\":\"instalador-no-ubuntu-20-04-22-04-e-debian-11-12\"},{\"title\":\"Verificando se seu PDS está online e acessível\",\"id\":\"verificando-se-seu-pds-esta-online-e-acessivel\"},{\"title\":\"Criando uma conta usando pdsadmin\",\"id\":\"criando-uma-conta-usando-pdsadmin\"},{\"title\":\"Criando uma conta usando um código de convite\",\"id\":\"criando-uma-conta-usando-um-codigo-de-convite\"},{\"title\":\"Usando o aplicativo Bluesky com seu PDS\",\"id\":\"usando-o-aplicativo-bluesky-com-seu-pds\"},{\"title\":\"Atualizando seu PDS\",\"id\":\"atualizando-seu-pds\"},{\"title\":\"Obtendo ajuda\",\"id\":\"obtendo-ajuda\"}],\"/specs/at-uri-scheme\":[],\"/specs/atp\":[{\"title\":\"Protocol Structure\",\"id\":\"protocol-structure\"},{\"title\":\"Protocol Extension and Applications\",\"id\":\"protocol-extension-and-applications\"},{\"title\":\"What Is Missing?\",\"id\":\"what-is-missing\"},{\"title\":\"Future Work\",\"id\":\"future-work\"}],\"/specs/blob\":[{\"title\":\"Blob Metadata\",\"id\":\"blob-metadata\"},{\"title\":\"Blob Lifecycle\",\"id\":\"blob-lifecycle\"},{\"title\":\"Usage and Implementation Guidelines\",\"id\":\"usage-and-implementation-guidelines\"},{\"title\":\"Security Considerations\",\"id\":\"security-considerations\"},{\"title\":\"Possible Future Changes\",\"id\":\"possible-future-changes\"}],\"/specs/cryptography\":[{\"title\":\"ECDSA Signature Malleability\",\"id\":\"ecdsa-signature-malleability\"},{\"title\":\"Public Key Encoding\",\"id\":\"public-key-encoding\"},{\"title\":\"Usage and Implementation Guidelines\",\"id\":\"usage-and-implementation-guidelines\"},{\"title\":\"Possible Future Changes\",\"id\":\"possible-future-changes\"}],\"/specs/data-model\":[{\"title\":\"Relationship With IPLD\",\"id\":\"relationship-with-ipld\"},{\"title\":\"Data Types\",\"id\":\"data-types\"},{\"title\":\"blob Type\",\"id\":\"blob-type\"},{\"title\":\"JSON Representation\",\"id\":\"json-representation\"},{\"title\":\"Link and CID Formats\",\"id\":\"link-and-cid-formats\"},{\"title\":\"Usage and Implementation Guidelines\",\"id\":\"usage-and-implementation-guidelines\"},{\"title\":\"Security and Privacy Considerations\",\"id\":\"security-and-privacy-considerations\"},{\"title\":\"Possible Future Changes\",\"id\":\"possible-future-changes\"}],\"/specs/did\":[{\"title\":\"Blessed DID Methods\",\"id\":\"blessed-did-methods\"},{\"title\":\"AT Protocol DID Identifier Syntax\",\"id\":\"at-protocol-did-identifier-syntax\"},{\"title\":\"DID Documents\",\"id\":\"did-documents\"},{\"title\":\"Representation of Public Keys\",\"id\":\"representation-of-public-keys\"},{\"title\":\"Usage and Implementation Guidelines\",\"id\":\"usage-and-implementation-guidelines\"},{\"title\":\"Possible Future Changes\",\"id\":\"possible-future-changes\"}],\"/specs/event-stream\":[{\"title\":\"Streaming Wire Protocol (v0)\",\"id\":\"streaming-wire-protocol-v0\"},{\"title\":\"Usage and Implementation Guidelines\",\"id\":\"usage-and-implementation-guidelines\"},{\"title\":\"Security and Privacy Considerations\",\"id\":\"security-and-privacy-considerations\"},{\"title\":\"Possible Future Changes\",\"id\":\"possible-future-changes\"}],\"/specs/handle\":[{\"title\":\"Handle Identifier Syntax\",\"id\":\"handle-identifier-syntax\"},{\"title\":\"Additional Non-Syntax Restrictions\",\"id\":\"additional-non-syntax-restrictions\"},{\"title\":\"Identifier Examples\",\"id\":\"identifier-examples\"},{\"title\":\"Handle Resolution\",\"id\":\"handle-resolution\"},{\"title\":\"Usage and Implementation Guidelines\",\"id\":\"usage-and-implementation-guidelines\"},{\"title\":\"Possible Future Changes\",\"id\":\"possible-future-changes\"}],\"/specs/label\":[{\"title\":\"Schema and Data Model\",\"id\":\"schema-and-data-model\"},{\"title\":\"Value\",\"id\":\"value\"},{\"title\":\"Label Lifecycle: Negation and Expiration\",\"id\":\"label-lifecycle-negation-and-expiration\"},{\"title\":\"Signatures\",\"id\":\"signatures\"},{\"title\":\"Self-Labels in Records\",\"id\":\"self-labels-in-records\"},{\"title\":\"Labeler Service Identity\",\"id\":\"labeler-service-identity\"},{\"title\":\"Label Distribution Endpoints\",\"id\":\"label-distribution-endpoints\"},{\"title\":\"Labeler HTTP Headers\",\"id\":\"labeler-http-headers\"},{\"title\":\"Security Considerations\",\"id\":\"security-considerations\"},{\"title\":\"Usage and Implementation Guidelines\",\"id\":\"usage-and-implementation-guidelines\"},{\"title\":\"Possible Future Changes\",\"id\":\"possible-future-changes\"}],\"/specs/lexicon\":[{\"title\":\"Overview of Types\",\"id\":\"overview-of-types\"},{\"title\":\"Lexicon Files\",\"id\":\"lexicon-files\"},{\"title\":\"Primary Type Definitions\",\"id\":\"primary-type-definitions\"},{\"title\":\"Field Type Definitions\",\"id\":\"field-type-definitions\"},{\"title\":\"String Formats\",\"id\":\"string-formats\"},{\"title\":\"When to use $type\",\"id\":\"when-to-use-type\"},{\"title\":\"Lexicon Evolution\",\"id\":\"lexicon-evolution\"},{\"title\":\"Authority and Control\",\"id\":\"authority-and-control\"},{\"title\":\"Usage and Implementation Guidelines\",\"id\":\"usage-and-implementation-guidelines\"},{\"title\":\"Possible Future Changes\",\"id\":\"possible-future-changes\"}],\"/specs/nsid\":[],\"/specs/oauth\":[{\"title\":\"Clients\",\"id\":\"clients\"},{\"title\":\"Identity Authentication\",\"id\":\"identity-authentication\"},{\"title\":\"Authorization Scopes\",\"id\":\"authorization-scopes\"},{\"title\":\"Authorization Requests\",\"id\":\"authorization-requests\"},{\"title\":\"Tokens and Session Lifetime\",\"id\":\"tokens-and-session-lifetime\"},{\"title\":\"Demonstrating Proof of Possession (DPoP)\",\"id\":\"demonstrating-proof-of-possession-d-po-p\"},{\"title\":\"Authorization Servers\",\"id\":\"authorization-servers\"},{\"title\":\"Summary of Authorization Flow\",\"id\":\"summary-of-authorization-flow\"},{\"title\":\"Security Considerations\",\"id\":\"security-considerations\"},{\"title\":\"Possible Future Changes\",\"id\":\"possible-future-changes\"}],\"/specs/record-key\":[],\"/specs/repository\":[{\"title\":\"Repo Data Structure (v3)\",\"id\":\"repo-data-structure-v3\"},{\"title\":\"CAR File Serialization\",\"id\":\"car-file-serialization\"},{\"title\":\"Repository Diffs\",\"id\":\"repository-diffs\"},{\"title\":\"Security Considerations\",\"id\":\"security-considerations\"},{\"title\":\"Possible Future Changes\",\"id\":\"possible-future-changes\"}],\"/specs/xrpc\":[{\"title\":\"Lexicon HTTP Endpoints\",\"id\":\"lexicon-http-endpoints\"},{\"title\":\"Authentication\",\"id\":\"authentication\"},{\"title\":\"Service Proxying\",\"id\":\"service-proxying\"},{\"title\":\"Summary of HTTP Headers\",\"id\":\"summary-of-http-headers\"},{\"title\":\"Summary of HTTP Status Codes\",\"id\":\"summary-of-http-status-codes\"},{\"title\":\"Usage and Implementation Guidelines\",\"id\":\"usage-and-implementation-guidelines\"},{\"title\":\"Security and Privacy Considerations\",\"id\":\"security-and-privacy-considerations\"},{\"title\":\"Possible Future Changes\",\"id\":\"possible-future-changes\"}]},\"children\":[\"$\",\"$L7\",null,{\"parallelRouterKey\":\"children\",\"segmentPath\":[\"children\",\"$8\",\"children\"],\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L9\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[\"$\",\"div\",null,{\"className\":\"absolute inset-0 -z-10 mx-0 max-w-none overflow-hidden\",\"children\":[\"$\",\"div\",null,{\"className\":\"absolute left-1/2 top-0 ml-[-38rem] h-[25rem] w-[81.25rem] dark:[mask-image:linear-gradient(white,transparent)]\",\"children\":[\"$\",\"div\",null,{\"className\":\"absolute inset-0 bg-gradient-to-r from-[#6fa5ff] to-[#9dc0fb] opacity-40 [mask-image:radial-gradient(farthest-side_at_top,white,transparent)] dark:from-[#0090f2]/30 dark:to-[#7588ff]/30 dark:opacity-100\",\"children\":[\"$\",\"svg\",null,{\"aria-hidden\":\"true\",\"className\":\"absolute inset-x-0 inset-y-[-50%] h-[200%] w-full fill-black/40 stroke-black/50 mix-blend-overlay dark:fill-white/2.5 dark:stroke-white/5\",\"children\":[[\"$\",\"defs\",null,{\"children\":[\"$\",\"pattern\",null,{\"id\":\":S1:\",\"width\":72,\"height\":56,\"patternUnits\":\"userSpaceOnUse\",\"x\":-12,\"y\":4,\"children\":[\"$\",\"path\",null,{\"d\":\"M.5 56V.5H72\",\"fill\":\"none\"}]}]}],[\"$\",\"rect\",null,{\"width\":\"100%\",\"height\":\"100%\",\"strokeWidth\":0,\"fill\":\"url(#:S1:)\"}],[\"$\",\"svg\",null,{\"x\":-12,\"y\":4,\"className\":\"overflow-visible\",\"children\":[]}]]}]}]}]}],[\"$\",\"div\",null,{\"className\":\"mx-auto flex h-full max-w-xl flex-col items-center justify-center py-16 text-center\",\"children\":[[\"$\",\"p\",null,{\"className\":\"text-sm font-semibold text-zinc-900 dark:text-white\",\"children\":\"404\"}],[\"$\",\"h1\",null,{\"className\":\"mt-2 text-2xl font-bold text-zinc-900 dark:text-white\",\"children\":\"Page not found\"}],[\"$\",\"p\",null,{\"className\":\"mt-2 text-base text-zinc-600 dark:text-zinc-400\",\"children\":\"Sorry, we couldn’t find the page you’re looking for.\"}],[\"$\",\"$L4\",null,{\"className\":\"inline-flex gap-0.5 justify-center overflow-hidden text-sm font-medium transition rounded-full bg-zinc-900 py-1 px-3 text-white hover:bg-zinc-700 dark:bg-blue-400/10 dark:text-blue-400 dark:ring-1 dark:ring-inset dark:ring-blue-400/20 dark:hover:bg-blue-400/10 dark:hover:text-blue-300 dark:hover:ring-blue-300 mt-8\",\"href\":\"/\",\"children\":[false,\"Back to docs\",[\"$\",\"svg\",null,{\"viewBox\":\"0 0 20 20\",\"fill\":\"none\",\"aria-hidden\":\"true\",\"className\":\"mt-0.5 h-5 w-5 -mr-1\",\"children\":[\"$\",\"path\",null,{\"stroke\":\"currentColor\",\"strokeLinecap\":\"round\",\"strokeLinejoin\":\"round\",\"d\":\"m11.5 6.5 3 3.5m0 0-3 3.5m3-3.5h-9\"}]}]]}]]}]],\"notFoundStyles\":[]}]}]}]}]}]}]\n"])</script></body></html>

Pages: 1 2 3 4 5 6 7 8 9 10