Files
Vishesh 'ironeagle' Bangotra 322741e00c
All checks were successful
continuous-integration/drone/push Build is passing
Document npm registry endpoints and auth gotchas
Add the exact pip/npm registry endpoints and secret names, the
scope-scoped (not global) registry requirement given Verdaccio's missing
uplink, the host-scoped _auth rule, the per-item Drone shell caveat, and
the Verdaccio storage uid/permissions gotcha behind the confusing
"404 no such package available" error on publish.
2026-10-21 01:31:07 +05:30

1021 lines
28 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="The rules and library registry of the standardized application blueprint.">
<link rel="icon" href="../assets/images/favicon.png">
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.6.23">
<title>Library Registry - Aetos Standards — Reference</title>
<link rel="stylesheet" href="../assets/stylesheets/main.84d31ad4.min.css">
<link rel="stylesheet" href="../assets/stylesheets/palette.06af60db.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:300,300i,400,400i,700,700i%7CJetBrains+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Inter";--md-code-font:"JetBrains Mono"}</style>
<script>__md_scope=new URL("..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
</head>
<body dir="ltr" data-md-color-scheme="slate" data-md-color-primary="deep-purple" data-md-color-accent="cyan">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#library-registry" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header md-header--shadow" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href=".." title="Aetos Standards — Reference" class="md-header__button md-logo" aria-label="Aetos Standards — Reference" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
Aetos Standards — Reference
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Library Registry
</span>
</div>
</div>
</div>
<form class="md-header__option" data-md-component="palette">
<input class="md-option" data-md-color-media="" data-md-color-scheme="slate" data-md-color-primary="deep-purple" data-md-color-accent="cyan" aria-hidden="true" type="radio" name="__palette" id="__palette_0">
</form>
<script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
</label>
<nav class="md-search__options" aria-label="Search">
<a href="javascript:void(0)" class="md-search__icon md-icon" title="Share" aria-label="Share" data-clipboard data-clipboard-text="" data-md-component="search-share" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9a3 3 0 0 0-3 3 3 3 0 0 0 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.15c-.05.21-.08.43-.08.66 0 1.61 1.31 2.91 2.92 2.91s2.92-1.3 2.92-2.91A2.92 2.92 0 0 0 18 16.08"/></svg>
</a>
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
</button>
</nav>
<div class="md-search__suggest" data-md-component="search-suggest"></div>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list" role="presentation"></ol>
</div>
</div>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href=".." title="Aetos Standards — Reference" class="md-nav__button md-logo" aria-label="Aetos Standards — Reference" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54"/></svg>
</a>
Aetos Standards — Reference
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href=".." class="md-nav__link">
<span class="md-ellipsis">
Home
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../01_build_recipe/" class="md-nav__link">
<span class="md-ellipsis">
Build Recipe
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../02_layering_rules.md" class="md-nav__link">
<span class="md-ellipsis">
Layering Rules
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../03_composition_root.md" class="md-nav__link">
<span class="md-ellipsis">
Composition Root
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../04_spec_first_routing.md" class="md-nav__link">
<span class="md-ellipsis">
Spec-First Routing
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../05_crud_template.md" class="md-nav__link">
<span class="md-ellipsis">
CRUD Template
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../06_pipeline_scaffold.md" class="md-nav__link">
<span class="md-ellipsis">
Pipeline Scaffold
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../07_worker_and_progress.md" class="md-nav__link">
<span class="md-ellipsis">
Worker & Progress
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../08_human_in_loop.md" class="md-nav__link">
<span class="md-ellipsis">
Human-in-the-Loop
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../09_infra_adaptors.md" class="md-nav__link">
<span class="md-ellipsis">
Infra Adapters
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../10_drone_pipelines.md" class="md-nav__link">
<span class="md-ellipsis">
Drone Pipelines
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../11_versioning_and_changelog.md" class="md-nav__link">
<span class="md-ellipsis">
Versioning & Changelog
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../15_repository_inventory.md" class="md-nav__link">
<span class="md-ellipsis">
Repository Inventory
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../12_genericity_matrix.md" class="md-nav__link">
<span class="md-ellipsis">
Genericity Matrix
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../14_auth_integration.md" class="md-nav__link">
<span class="md-ellipsis">
Auth Integration
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../13_library_registry.md" class="md-nav__link">
<span class="md-ellipsis">
Library Registry
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#summary" class="md-nav__link">
<span class="md-ellipsis">
Summary
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#catalog" class="md-nav__link">
<span class="md-ellipsis">
Catalog
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#how-to-choose" class="md-nav__link">
<span class="md-ellipsis">
How to choose
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#discovery" class="md-nav__link">
<span class="md-ellipsis">
Discovery
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#publishing-registry-auth" class="md-nav__link">
<span class="md-ellipsis">
Publishing &amp; registry auth
</span>
</a>
<nav class="md-nav" aria-label="Publishing &amp; registry auth">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#endpoints" class="md-nav__link">
<span class="md-ellipsis">
Endpoints
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#npm-scope-the-registry-never-set-it-globally" class="md-nav__link">
<span class="md-ellipsis">
npm: scope the registry, never set it globally
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#verdaccio-storage-permissions" class="md-nav__link">
<span class="md-ellipsis">
Verdaccio storage permissions
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#notes" class="md-nav__link">
<span class="md-ellipsis">
Notes
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<h1 id="library-registry">Library Registry</h1>
<h2 id="summary">Summary</h2>
<p>The Aetos ecosystem provides internal libraries for the shared concerns of
every application. <strong>Use them.</strong> Writing a private copy of any capability below
is a defect.</p>
<p>Each library also exposes its own documentation as an MCP server. An AI agent
can read a library's full API by connecting to its MCP and reading
<code>docs://index</code>, <code>docs://nav</code>, and <code>docs://modules/{module}</code>.</p>
<hr />
<h2 id="catalog">Catalog</h2>
<table>
<thead>
<tr>
<th>Library</th>
<th>Import</th>
<th>Purpose</th>
<th>Use instead of</th>
<th>MCP</th>
</tr>
</thead>
<tbody>
<tr>
<td>DAG Pipe</td>
<td><code>dagpipe</code></td>
<td>Deterministic state-transformation DAG engine</td>
<td>hand-rolled orchestration/topological ordering</td>
<td><code>:8006</code></td>
</tr>
<tr>
<td>Hexa</td>
<td><code>hexa</code></td>
<td>Declarative DI / composition-root tooling</td>
<td>manual wiring, hand-written factories</td>
<td><code>:8008</code></td>
</tr>
<tr>
<td>Mongo Ops</td>
<td><code>mongo_ops</code></td>
<td>Async MongoDB repositories, cache, populate, transactions</td>
<td>raw Motor CRUD and connection lifecycle</td>
<td><code>:8007</code></td>
</tr>
<tr>
<td>Omniread</td>
<td><code>omniread</code></td>
<td>Format-agnostic fetch + parse (HTML, PDF, CSV, XLSX)</td>
<td>custom scrapers/parsers</td>
<td><code>:8003</code></td>
</tr>
<tr>
<td>OpenAPI First</td>
<td><code>openapi_first</code></td>
<td>Spec-first FastAPI bootstrap, client, codegen</td>
<td>decorator routers and hand-written clients</td>
<td><code>:8004</code></td>
</tr>
<tr>
<td>Mail Intake</td>
<td><code>mail_intake</code></td>
<td>Provider-agnostic read-only email ingestion</td>
<td>Gmail OAuth + MIME parsing</td>
<td><code>:8002</code></td>
</tr>
<tr>
<td>Py JWT</td>
<td><code>jwtlib</code></td>
<td>JWT auth primitives (register/login/introspect)</td>
<td>password hashing + token code</td>
<td><code>:8005</code></td>
</tr>
<tr>
<td>Doc Forge</td>
<td><code>docforge</code></td>
<td>Docstring compiler → MkDocs + MCP docs</td>
<td>custom doc generators</td>
<td><code>:8001</code></td>
</tr>
<tr>
<td>Doc Weaver</td>
<td><code>doc-weaver</code></td>
<td>JSDoc compiler → TypeDoc + MCP docs (React/TS)</td>
<td>custom TypeScript doc generators</td>
<td><code>:8010</code></td>
</tr>
<tr>
<td>React Auth</td>
<td><code>react-auth</code></td>
<td>JWT-backed React auth UI: provider, login page, profile screens, bearer axios client</td>
<td>hand-rolled auth contexts and token handling in React apps</td>
<td><code>:8011</code></td>
</tr>
<tr>
<td>React OpenAPI</td>
<td><code>react-openapi</code></td>
<td>Spec-driven React admin UI (CRUD, tables, forms, SSE) derived from an OpenAPI document</td>
<td>per-resource hand-written admin screens</td>
<td><code>:8012</code></td>
</tr>
<tr>
<td>Auth Server</td>
<td><em>(service)</em></td>
<td>Central identity service (register/login/me/logout/introspect)</td>
<td>building auth endpoints yourself</td>
<td>spec: <code>docs://spec</code></td>
</tr>
</tbody>
</table>
<h2 id="how-to-choose">How to choose</h2>
<table>
<thead>
<tr>
<th>You need to…</th>
<th>Use</th>
</tr>
</thead>
<tbody>
<tr>
<td>persist and query documents</td>
<td>Mongo Ops</td>
</tr>
<tr>
<td>compose dependencies</td>
<td>Hexa</td>
</tr>
<tr>
<td>run a multi-step transformation</td>
<td>DAG Pipe</td>
</tr>
<tr>
<td>read/parse an arbitrary input format</td>
<td>Omniread</td>
</tr>
<tr>
<td>expose a contract-first HTTP API</td>
<td>OpenAPI First</td>
</tr>
<tr>
<td>ingest email</td>
<td>Mail Intake</td>
</tr>
<tr>
<td>authenticate users / verify tokens</td>
<td>Py JWT (+ Auth Server)</td>
</tr>
<tr>
<td>generate documentation</td>
<td>Doc Forge</td>
</tr>
<tr>
<td>generate React/TypeScript documentation</td>
<td>Doc Weaver</td>
</tr>
<tr>
<td>authenticate a React front-end</td>
<td>React Auth (+ Auth Server)</td>
</tr>
<tr>
<td>build a React admin UI from an OpenAPI spec</td>
<td>React OpenAPI</td>
</tr>
</tbody>
</table>
<h2 id="discovery">Discovery</h2>
<p>A single <strong>standards MCP</strong> exposes <code>find_library(capability)</code>, which returns the
matching library, its import name, its "use instead of" guidance, and its MCP
endpoint (or, for the auth-server service, a spec pointer). It also serves the
pinned auth-server OpenAPI contract at <code>docs://spec</code>. Query it before writing
any infrastructure.</p>
<h2 id="publishing-registry-auth">Publishing &amp; registry auth</h2>
<p>Python packages publish to the private index (<code>pip.aetoskia.com</code>, <code>pypiserver</code>)
and npm packages to the private registry (<code>npm.aetoskia.com</code>, Verdaccio). Both
authenticate against the <strong>same <code>htpasswd</code> file</strong> (<code>/auth/htpasswd</code>) used by the
Docker registry and the Traefik basic-auth middleware; registration is disabled,
so the CI credentials (<code>PIP_USERNAME</code> / <code>PIP_PASSWORD</code>, <code>NPM_USERNAME</code> /
<code>NPM_PASSWORD</code>) are one and the same account — there is no separate npm user.
Verdaccio requires <strong>bcrypt</strong> htpasswd entries; see
<a href="../90_drone_pipelines/">90 – Drone Pipelines</a> for the CI wiring.</p>
<h3 id="endpoints">Endpoints</h3>
<table>
<thead>
<tr>
<th>Registry</th>
<th>URL</th>
<th>Backend</th>
<th>CI secret</th>
</tr>
</thead>
<tbody>
<tr>
<td>PyPI</td>
<td><code>https://pip.aetoskia.com</code></td>
<td>pypiserver (<code>server-pi:6007</code>)</td>
<td><code>PIP_REPO_URL</code></td>
</tr>
<tr>
<td>npm</td>
<td><code>https://npm.aetoskia.com</code></td>
<td>Verdaccio (<code>server-pi:6008</code>)</td>
<td><code>NPM_REPO_URL</code></td>
</tr>
</tbody>
</table>
<p>Both are exposed through Traefik on the <code>websecure</code> entrypoint as <strong>bare
origins</strong> — no path, no trailing slash. Set the secret values exactly as above.</p>
<h3 id="npm-scope-the-registry-never-set-it-globally">npm: scope the registry, never set it globally</h3>
<p>Verdaccio here has <strong>no uplink / proxy</strong>, so it can only serve <code>@aetoskia/*</code>
packages. A global <code>registry=https://npm.aetoskia.com</code> in <code>.npmrc</code> would route
<em>every</em> dependency — including public transitive deps such as
<code>zod-to-json-schema</code> (pulled in by <code>@modelcontextprotocol/sdk</code>) — through
Verdaccio, which 404s on anything it does not host. Always scope the registry to
the account:</p>
<div class="language-text highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-1">1</a></span>
<span class="normal"><a href="#__codelineno-0-2">2</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1"></a>@aetoskia:registry=https://npm.aetoskia.com
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2"></a>//npm.aetoskia.com/:_auth=&lt;base64(user:password)&gt;
</span></code></pre></div></td></tr></table></div>
<p>Public deps then resolve from <code>registry.npmjs.org</code> and only <code>@aetoskia/*</code> hits
the private registry. The auth line must be <strong>scoped to the host</strong>
(<code>//host/:_auth=</code>), not a bare <code>_auth=</code> — modern npm rejects the bare form with
<code>ERR_INVALID_AUTH</code>. The drone template derives both from the package scope and
<code>NPM_REPO_URL</code> automatically; see
<a href="../90_drone_pipelines/">90 – Drone Pipelines</a>.</p>
<blockquote>
<p>The Drone pipeline runs each <code>commands:</code> list item in a <strong>separate shell</strong>, so
shell variables defined in one item do not survive into the next. Keep the
variable definitions and the commands that use them in the same <code>|</code> block.</p>
</blockquote>
<h3 id="verdaccio-storage-permissions">Verdaccio storage permissions</h3>
<p>Verdaccio runs as uid <strong>10001</strong> (<code>verdaccio</code>) inside <code>verdaccio/verdaccio</code>.
The <code>storage</code> directory is bind-mounted from the server
(<code>/mnt/omnissiah-vault/data/verdaccio/storage</code>); if it is owned by <code>root:root</code>
(mode <code>755</code>) the process cannot write to it and every publish fails with a
confusing <code>404 no such package available</code> (<code>NotFoundError</code> from
<code>local-storage</code>). Ensure the directory — and its <code>plugins</code> subdirectory — are
owned by <code>10001:101</code>:</p>
<div class="language-sh highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-1-1">1</a></span>
<span class="normal"><a href="#__codelineno-1-2">2</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-1-1"><a id="__codelineno-1-1" name="__codelineno-1-1"></a>sudo<span class="w"> </span>chown<span class="w"> </span>-R<span class="w"> </span><span class="m">10001</span>:101<span class="w"> </span>/mnt/omnissiah-vault/data/verdaccio/storage
</span><span id="__span-1-2"><a id="__codelineno-1-2" name="__codelineno-1-2"></a>docker<span class="w"> </span>restart<span class="w"> </span>npm-registry
</span></code></pre></div></td></tr></table></div>
<h2 id="notes">Notes</h2>
<ul>
<li><strong>Hexa</strong> is a full library with its own MCP server on <code>:8008</code>: read
<code>docs://index</code>, <code>docs://nav</code>, and <code>docs://modules/{module}</code> (e.g.
<code>docs://modules/hexa.container</code>) to discover the DI surface — <code>build(cls, *,
instances, config)</code> and the <code>PortNode</code> model.</li>
<li><strong>Auth Server</strong> is a <strong>service</strong>, not an importable library: it has no MCP
bundle by design. Read its client contract from the pinned OpenAPI document
via <code>docs://spec</code> and wire it by declaring a <code>bearerAuth</code> security scheme in
the app's own spec (see <strong>Auth Integration</strong>); <code>py-jwt</code> covers the
low-level token path.</li>
<li><strong>Doc Weaver</strong> is the TypeScript counterpart to <strong>Doc Forge</strong>: it reads
JSDoc comments and emits a TypeDoc site plus the same doc-forge-shaped MCP
bundle for React packages. Its convention is <strong>RDFC</strong> (the React Doc-forge
Convention), the JSDoc parallel to GSDFC.</li>
<li><strong>React Auth</strong> and <strong>React OpenAPI</strong> are front-end libraries (TypeScript,
React 18 + MUI + React Router peers), not Python services — they consume the
<strong>Auth Server</strong> and an OpenAPI document rather than serving one. Each ships
a wiki, a TypeDoc site and an MCP bundle like every other library above.</li>
<li>Library MCP servers expose <strong>documentation resources</strong> (not executable tools):
they tell an agent the available API surface so it does not invent code.</li>
</ul>
</article>
</div>
<script>var tabs=__md_get("__tabs");if(Array.isArray(tabs))e:for(var set of document.querySelectorAll(".tabbed-set")){var labels=set.querySelector(".tabbed-labels");for(var tab of tabs)for(var label of labels.getElementsByTagName("label"))if(label.innerText.trim()===tab){var input=document.getElementById(label.htmlFor);input.checked=!0;continue e}}</script>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
<button type="button" class="md-top md-icon" data-md-component="top" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg>
Back to top
</button>
</main>
<footer class="md-footer">
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"base": "..", "features": ["navigation.sections", "navigation.expand", "navigation.top", "navigation.instant", "navigation.tracking", "navigation.indexes", "content.code.copy", "content.code.annotate", "content.tabs.link", "content.action.edit", "search.highlight", "search.share", "search.suggest"], "search": "../assets/javascripts/workers/search.973d3a69.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
<script src="../assets/javascripts/bundle.f55a23d4.min.js"></script>
</body>
</html>