docs(standards): vendor template into MCP bundle; add component tools + start_app prompt
This commit is contained in:
@@ -691,7 +691,9 @@
|
||||
<h1 id="infra-adapters">Infra Adapters</h1>
|
||||
<h2 id="summary">Summary</h2>
|
||||
<p>All external systems are reached through adapters in <code>infra/</code>. Prefer an
|
||||
existing internal library over writing a new adapter.</p>
|
||||
existing internal library over writing a new adapter; where no library exists,
|
||||
copy the Tier B scaffold from <code>templates/app</code>. See the Genericity Matrix for the
|
||||
Tier A / B / C split.</p>
|
||||
<hr />
|
||||
<h2 id="database-mongodb">Database (MongoDB)</h2>
|
||||
<ul>
|
||||
@@ -720,9 +722,10 @@ existing internal library over writing a new adapter.</p>
|
||||
<ul>
|
||||
<li>Transactions use a session context manager provided by the library.</li>
|
||||
</ul>
|
||||
<p><strong>Library:</strong> the Mongo operations library (see registry). Do not write raw
|
||||
Motor calls in the domain.</p>
|
||||
<p><strong>Tier A — Library (Mongo Ops).</strong> Do not write raw Motor calls in the domain;
|
||||
consult the registry and the library's MCP before touching the driver.</p>
|
||||
<h2 id="http-response-cache">HTTP response cache</h2>
|
||||
<p><strong>Tier B — template.</strong> Copy from <code>templates/app</code>; not a standalone library.</p>
|
||||
<p>A generic GET cache sits behind a decorator.</p>
|
||||
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-2-1">1</a></span>
|
||||
<span class="normal"><a href="#__codelineno-2-2">2</a></span></pre></div></td><td class="code"><div><pre><span></span><code><span id="__span-2-1"><a id="__codelineno-2-1" name="__codelineno-2-1"></a><span class="nd">@cache_response</span><span class="p">(</span><span class="n">ttl</span><span class="o">=</span><span class="mi">60</span><span class="p">)</span>
|
||||
@@ -735,14 +738,16 @@ Motor calls in the domain.</p>
|
||||
invalidation.</li>
|
||||
</ul>
|
||||
<h2 id="event-progress-bus">Event / progress bus</h2>
|
||||
<p><strong>Tier B — template.</strong> Copy from <code>templates/app</code>.</p>
|
||||
<p>A port with an in-memory default adapter (<code>publish</code>, <code>get_events</code>). Swap for a
|
||||
durable broker in production (see Worker & Progress).</p>
|
||||
<h2 id="external-clients-ingestion">External clients (ingestion)</h2>
|
||||
<p>External fetchers (files, mail, HTTP) are adapters that wrap ingestion
|
||||
libraries. Construct them in the composition root and inject into
|
||||
orchestrators.</p>
|
||||
<p><strong>Libraries:</strong> the ingestion library (formats) and the mail library (email).</p>
|
||||
<p><strong>Tier A — Libraries:</strong> Omniread (formats) and Mail Intake (email).</p>
|
||||
<h2 id="llm-clients">LLM clients</h2>
|
||||
<p><strong>Tier B — template.</strong> Copy the pool scaffold from <code>templates/app</code>.</p>
|
||||
<p>When a pipeline calls a model provider, route through a pool adaptor that
|
||||
handles provider selection, retries, and client lifecycle:</p>
|
||||
<div class="language-python highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-3-1">1</a></span>
|
||||
@@ -751,11 +756,19 @@ handles provider selection, retries, and client lifecycle:</p>
|
||||
</span></code></pre></div></td></tr></table></div>
|
||||
<p>Providers are selected by <code>LLM_PROVIDER</code> and configured by environment.</p>
|
||||
<h2 id="key-value-store">Key-value store</h2>
|
||||
<p><strong>Tier B — template.</strong> Copy from <code>templates/app</code>.</p>
|
||||
<p>For report/snapshot storage, provide a pluggable store port with a Redis
|
||||
adapter and an in-memory fallback.</p>
|
||||
<h2 id="rule">Rule</h2>
|
||||
<p>If a capability already exists as a library (DB, DI, ingestion, mail, auth,
|
||||
docs), <strong>use it</strong>. Writing a private copy of a library is a defect.</p>
|
||||
<ul>
|
||||
<li><strong>Tier A (libraries: DB, DI, ingestion, mail, auth, docs, pipelines)</strong> — use
|
||||
the library; writing a private copy is a defect. Query <code>find_library</code> first.</li>
|
||||
<li><strong>Tier B (cache, progress bus, LLM pool, KV store, composition shape, worker,
|
||||
tests)</strong> — these are template code, not libraries: copy them from
|
||||
<code>templates/app</code> rather than searching the registry.</li>
|
||||
<li><strong>Tier C (models, business logic, pipeline families, rules)</strong> — author them
|
||||
yourself.</li>
|
||||
</ul>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -482,27 +482,27 @@
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#reusable-as-is-do-not-rewrite" class="md-nav__link">
|
||||
<a href="#tier-a-library-backed-use-never-reimplement" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
Reusable as-is (do not rewrite)
|
||||
Tier A — Library-backed (use; never reimplement)
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#template-to-adapt-copy-then-change-names" class="md-nav__link">
|
||||
<a href="#tier-b-template-provided-copy-from-templatesapp-then-adapt" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
Template to adapt (copy, then change names)
|
||||
Tier B — Template-provided (copy from templates/app, then adapt)
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#app-specific-must-be-authored" class="md-nav__link">
|
||||
<a href="#tier-c-app-specific-must-be-authored" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
App-specific (must be authored)
|
||||
Tier C — App-specific (must be authored)
|
||||
</span>
|
||||
</a>
|
||||
|
||||
@@ -583,27 +583,27 @@
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#reusable-as-is-do-not-rewrite" class="md-nav__link">
|
||||
<a href="#tier-a-library-backed-use-never-reimplement" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
Reusable as-is (do not rewrite)
|
||||
Tier A — Library-backed (use; never reimplement)
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#template-to-adapt-copy-then-change-names" class="md-nav__link">
|
||||
<a href="#tier-b-template-provided-copy-from-templatesapp-then-adapt" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
Template to adapt (copy, then change names)
|
||||
Tier B — Template-provided (copy from templates/app, then adapt)
|
||||
</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
|
||||
<li class="md-nav__item">
|
||||
<a href="#app-specific-must-be-authored" class="md-nav__link">
|
||||
<a href="#tier-c-app-specific-must-be-authored" class="md-nav__link">
|
||||
<span class="md-ellipsis">
|
||||
App-specific (must be authored)
|
||||
Tier C — App-specific (must be authored)
|
||||
</span>
|
||||
</a>
|
||||
|
||||
@@ -636,101 +636,162 @@
|
||||
|
||||
<h1 id="genericity-matrix">Genericity Matrix</h1>
|
||||
<h2 id="summary">Summary</h2>
|
||||
<p>This page states precisely what is <strong>reusable as-is</strong>, what is a <strong>template to
|
||||
adapt</strong>, and what is <strong>app-specific and must be authored</strong>. Use it to scope a
|
||||
new build.</p>
|
||||
<p>This page states precisely what is <strong>library-backed</strong>, what is
|
||||
<strong>template-provided</strong>, and what is <strong>app-specific and must be authored</strong>. Use it
|
||||
to scope a new build and to know, for any given capability, whether to call a
|
||||
library, copy template code, or write it yourself.</p>
|
||||
<hr />
|
||||
<h2 id="reusable-as-is-do-not-rewrite">Reusable as-is (do not rewrite)</h2>
|
||||
<h2 id="tier-a-library-backed-use-never-reimplement">Tier A — Library-backed (use; never reimplement)</h2>
|
||||
<p>These capabilities already exist as internal libraries. Reach them through the
|
||||
library registry MCP (<code>find_library(capability)</code>) and read the library's own MCP
|
||||
for its API. Writing a private copy of any of these is a defect.</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Area</th>
|
||||
<th>Artifact</th>
|
||||
<th>Capability</th>
|
||||
<th>Library</th>
|
||||
<th>MCP</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Persistence: repositories, cache, populate, transactions</td>
|
||||
<td>Mongo Ops (<code>mongo_ops</code>)</td>
|
||||
<td><code>:8007</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Dependency injection / composition</td>
|
||||
<td>Hexa (<code>hexa</code>)</td>
|
||||
<td><code>:8008</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Deterministic multi-step transformation engine</td>
|
||||
<td>DAG Pipe (<code>dagpipe</code>)</td>
|
||||
<td><code>:8006</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Spec-first HTTP edge, client, codegen</td>
|
||||
<td>OpenAPI First (<code>openapi_first</code>)</td>
|
||||
<td><code>:8004</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Format-agnostic fetch + parse (HTML, PDF, CSV, XLSX)</td>
|
||||
<td>Omniread (<code>omniread</code>)</td>
|
||||
<td><code>:8003</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Read-only email ingestion</td>
|
||||
<td>Mail Intake (<code>mail_intake</code>)</td>
|
||||
<td><code>:8002</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>JWT auth primitives (register, login, introspect)</td>
|
||||
<td>Py JWT (<code>jwtlib</code>)</td>
|
||||
<td><code>:8005</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Documentation build (MkDocs + MCP)</td>
|
||||
<td>Doc Forge (<code>docforge</code>)</td>
|
||||
<td><code>:8001</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2 id="tier-b-template-provided-copy-from-templatesapp-then-adapt">Tier B — Template-provided (copy from <code>templates/app</code>, then adapt)</h2>
|
||||
<p>These are reusable internal components shipped <strong>inside</strong> the template — they are
|
||||
not independent libraries. Copy them as-is, then rename/populate only what is
|
||||
app-specific. They give every app the same wiring shape as the reference app.</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Component</th>
|
||||
<th>Template location</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Layering & dependency rule</td>
|
||||
<td>the package layout and import rules</td>
|
||||
<td>the package layout + import rules</td>
|
||||
<td>keep</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Composition root</td>
|
||||
<td>the <code>init.py</code> shape, idempotency, <code>get_svc</code> overloading</td>
|
||||
<td>Composition root shape</td>
|
||||
<td><code>init.py</code> (<code>get_svc</code>/<code>get_db</code>, idempotency)</td>
|
||||
<td>keep</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Web edge</td>
|
||||
<td><code>OpenAPIFirstApp</code> bootstrap, handler-name = <code>operationId</code>, thin handlers</td>
|
||||
<td>Spec-first web edge</td>
|
||||
<td><code>interfaces/openapi.py</code>, thin handlers bound to <code>operationId</code></td>
|
||||
<td>keep</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>CRUD slice</td>
|
||||
<td>the four-file pattern (model / ports-db / ports-service / converters)</td>
|
||||
<td>CRUD slice pattern</td>
|
||||
<td><code>domain/<resource>/{models.py, ports/db.py, ports/service.py, converters.py}</code></td>
|
||||
<td>rename + fill</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Generic CRUD service</td>
|
||||
<td>the base service adaptor</td>
|
||||
<td><code>infra/adapters/service.py</code> (<code>CrudsServiceAdaptor</code>)</td>
|
||||
<td>keep</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Repository factory</td>
|
||||
<td>base / populating / cached selection</td>
|
||||
<td><code>infra/db/repos/mongo.py</code> (<code>_repo_factory</code>)</td>
|
||||
<td>keep</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Worker</td>
|
||||
<td>the poll loop, backoff, retry, status machine</td>
|
||||
<td>Worker poll + status loop</td>
|
||||
<td><code>worker.py</code></td>
|
||||
<td>keep</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Progress bus</td>
|
||||
<td>the bus port + in-memory adapter + streaming endpoint</td>
|
||||
<td>Progress bus + streaming</td>
|
||||
<td>bus port + in-memory adapter + SSE endpoint</td>
|
||||
<td>keep</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Human-in-the-loop</td>
|
||||
<td>the durable pause + question document + resolve endpoint + resume map</td>
|
||||
<td>durable pause + question document + resolve endpoint + resume map</td>
|
||||
<td>keep</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Infra adaptors</td>
|
||||
<td>HTTP cache decorator, KV store port, LLM pool scaffold</td>
|
||||
<td>HTTP response cache</td>
|
||||
<td><code>cache_response</code> decorator + generation invalidation</td>
|
||||
<td>keep</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Testing</td>
|
||||
<td>integration harness with fakes, fixture-parity pattern</td>
|
||||
<td>Key-value store</td>
|
||||
<td>KV store port + Redis adapter + in-memory fallback</td>
|
||||
<td>keep</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Docs</td>
|
||||
<td>GSDFC + generated stubs + MCP bundle pipeline</td>
|
||||
<td>LLM client pool</td>
|
||||
<td>provider-select + retry pool scaffold</td>
|
||||
<td>keep</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Pipeline scaffold</td>
|
||||
<td><code>pipelines/shared/{ports,loader,registry}.py</code> + <code>pipelines/<family>/</code></td>
|
||||
<td>rename + fill</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Operator scripts</td>
|
||||
<td><code>scripts/</code> (<code>init()</code> / <code>get_svc()</code> / <code>shutdown()</code>)</td>
|
||||
<td>rename</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Testing harness</td>
|
||||
<td>integration fakes + fixture-parity pattern</td>
|
||||
<td>keep</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Project scaffolding</td>
|
||||
<td><code>pyproject.toml</code>, <code>Dockerfile</code>, <code>docker-compose.yaml</code>, <code>.env.example</code>, <code>openapi.yaml</code></td>
|
||||
<td>rename + fill</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2 id="template-to-adapt-copy-then-change-names">Template to adapt (copy, then change names)</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Artifact</th>
|
||||
<th>Change</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>pyproject.toml</code></td>
|
||||
<td>project name, dependencies</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>Dockerfile</code> / <code>docker-compose.yaml</code></td>
|
||||
<td>service name, ports, services</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>.env.example</code></td>
|
||||
<td>connection strings, provider keys</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>openapi.yaml</code></td>
|
||||
<td>every path/schema/operationId</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>scripts/</code></td>
|
||||
<td>seed and operator tasks</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2 id="app-specific-must-be-authored">App-specific (must be authored)</h2>
|
||||
<h2 id="tier-c-app-specific-must-be-authored">Tier C — App-specific (must be authored)</h2>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -752,7 +813,7 @@ new build.</p>
|
||||
<td>domain behaviour</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Pipeline families (if any)</td>
|
||||
<td>Pipeline families</td>
|
||||
<td>the transformation graph</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -765,6 +826,7 @@ new build.</p>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<hr />
|
||||
<h2 id="the-two-axes">The two axes</h2>
|
||||
<p>Everything app-specific reduces to <strong>two axes</strong>:</p>
|
||||
<ol>
|
||||
@@ -772,7 +834,8 @@ new build.</p>
|
||||
the OpenAPI contract.</li>
|
||||
<li><strong>Pipeline family</strong> — only if inputs require multi-step transformation.</li>
|
||||
</ol>
|
||||
<p>If you can specify those two axes, the rest of the app follows mechanically.</p>
|
||||
<p>If you can specify those two axes, the rest of the app follows mechanically:
|
||||
Tier A is imported, Tier B is copied, and Tier C is the only thing you author.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -665,7 +665,7 @@ can read a library's full API by connecting to its MCP and reading
|
||||
<td><code>hexa</code></td>
|
||||
<td>Declarative DI / composition-root tooling</td>
|
||||
<td>manual wiring, hand-written factories</td>
|
||||
<td><em>(see note)</em></td>
|
||||
<td><code>:8008</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Mongo Ops</td>
|
||||
@@ -714,7 +714,7 @@ can read a library's full API by connecting to its MCP and reading
|
||||
<td><em>(service)</em></td>
|
||||
<td>Central identity service (register/login/me/introspect)</td>
|
||||
<td>building auth endpoints yourself</td>
|
||||
<td>—</td>
|
||||
<td><em>(deferred)</em></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -767,9 +767,12 @@ matching library, its import name, its "use instead of" guidance, and its MCP
|
||||
endpoint. Query it before writing any infrastructure.</p>
|
||||
<h2 id="notes">Notes</h2>
|
||||
<ul>
|
||||
<li><strong>Hexa</strong> ships an MCP bundle but is not yet assigned a dedicated port in the
|
||||
hub config; it is reachable via the standards registry entry and will be
|
||||
wired to a port.</li>
|
||||
<li><strong>Hexa</strong> is a full library with its own MCP server on <code>:8008</code>: read
|
||||
<code>doc://index</code>, <code>doc://nav</code>, and <code>doc://modules/{module}</code> (e.g.
|
||||
<code>doc://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 deferred: it has no <code>pyproject.toml</code>/importable package and
|
||||
no MCP bundle. Do not reach for it yet; <code>py-jwt</code> covers token primitives.</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>
|
||||
|
||||
@@ -516,7 +516,7 @@ patterns, and the internal library catalog that agents consult while coding.</p>
|
||||
<li><strong>Worker & Progress</strong> — queued work, progress reporting, and visibility.</li>
|
||||
<li><strong>Human-in-the-Loop</strong> — guardrails and approvals inside automations.</li>
|
||||
<li><strong>Infra Adapters</strong> — how infrastructure connects without leaking into domain.</li>
|
||||
<li><strong>Genericity Matrix</strong> — what is generic vs app-specific.</li>
|
||||
<li><strong>Genericity Matrix</strong> — what is library-backed, template-provided, or authored.</li>
|
||||
<li><strong>Library Registry</strong> — the catalog of internal libraries behind all of it.</li>
|
||||
</ul>
|
||||
<p>Read the <strong>Wiki</strong> for the philosophy and rationale; these pages are the
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user