feat(standards): codify codegen, ship generic Tier-B infra, add get_app_template + prompts; fix docs:// regressions

P0: fix doc:// -> docs:// across standards src/server/registry and regenerate stale mongo-ops bundle. P1: build recipe + spec-first routing now document the openapi-first codegen fast path (models/routes with --inject-request/--package). P4: CRUD template documents the model-vs-document id rule (BaseDocument owns id). P5: authless guidance (omit security keys). P6: template gains generic infra (http_cache, keyed SSE bus, KV port+in-memory+Redis), interfaces/openapi.py + .dockerignore + generic build test registered as components, and a get_app_template tool; genericity matrix marks LLM pool + human-in-loop as reference-app patterns. P7: intake/build/start_app/trial prompts. P8: template ships tests/integration/test_openapi_app_builds.py. Rebuilt standards + openapi-first bundles and re-collected.
This commit is contained in:
2026-10-13 03:26:51 +05:30
parent ef951a1913
commit fced40af59
109 changed files with 4082 additions and 5885 deletions

View File

@@ -6,7 +6,7 @@ helpers so an agent can find the right internal library — and pull exact
template code — before writing any infrastructure.
Resources:
doc://index, doc://nav, doc://modules/{module} (from the base server)
docs://index, docs://nav, docs://modules/{module} (from the base server)
registry://libraries (the structured catalog)
registry://components (the template component index)
@@ -15,9 +15,13 @@ Tools:
find_library (capability -> matching libraries + MCP endpoints)
list_app_components (the template component kinds)
get_app_component (kind -> exact template file, seed tokens renamed)
get_app_template (the whole app skeleton as a path -> content map)
Prompts:
start_app (collect the two axes, then emit the build prompt)
intake (the questions to gather before building)
build (the two axes -> deterministic build prompt)
start_app (combined entry: intake, then build)
trial (self-contained trial build into a scratch dir)
"""
from __future__ import annotations
@@ -35,6 +39,50 @@ def _pascal(name: str) -> str:
return "".join(part.capitalize() for part in re.split(r"[_\-\s]+", name) if part)
_INTAKE_TEXT = (
"# Start a new app — intake\n\n"
"Gather the following, then call `build` (or `start_app`) with the values:\n\n"
"1. App name + one-line purpose.\n"
"2. Axis 1 — resources: each resource, its fields, and relationships\n"
" (or paste `openapi.yaml`).\n"
"3. Axis 2 — pipelines: multi-step inputs? families + formats (or `none`).\n"
"4. Auth needed now? (yes/no; auth is deferred — `py-jwt` only).\n"
"5. Integrations: Mongo / ingestion formats / email / LLM provider.\n\n"
"Then: `build(app_name=..., resources=..., pipelines=..., auth=...)`.\n"
)
def _build_text(app_name: str, resources: str, pipelines: str, auth: str) -> str:
"""Render the deterministic build prompt from the two axes.
Args:
app_name (str): App name + one-line purpose.
resources (str): Axis 1 — resources, fields, relationships.
pipelines (str): Axis 2 — pipeline families + input formats.
auth (str): Whether auth is needed now ("yes"/"no").
Returns:
str: The build prompt.
"""
return (
f"# Build: {app_name}\n\n"
"## Spec\n"
f"- resources: {resources}\n"
f"- pipelines: {pipelines or 'none'}\n"
f"- auth: {auth}\n\n"
"## Method (deterministic)\n"
"1. Read `docs://modules/build_recipe` and follow it step by step.\n"
"2. Read `docs://modules/genericity_matrix` (Tier A/B/C) and "
"`docs://modules/layering_rules`.\n"
"3. Call `find_library(capability)` for db, di, routing, ingestion, "
"and pipeline; never reimplement a Tier A library.\n"
"4. Scaffold with `get_app_template()` (whole tree) or pull single "
"files with `list_app_components()` and "
"`get_app_component(kind, resource=..., family=...)`.\n"
"5. Author only Tier C; keep Tier B as shipped.\n"
)
class StandardsMCPServer(MCPServer):
"""MCP server for the `standards` bundle with discovery/scaffolding tools.
@@ -72,6 +120,32 @@ class StandardsMCPServer(MCPServer):
return entry
return None
def _template_files(self, prefix: str | None = None) -> dict[str, str]:
"""Read the vendored template tree as a path -> content map.
Args:
prefix (str | None): Optional path prefix to filter by (POSIX
separators, for example ``"infra/"``).
Returns:
dict[str, str]: Relative POSIX path -> UTF-8 file content, excluding
caches and bytecode.
"""
root = Path(self.mcp_root) / "templates" / "app"
files: dict[str, str] = {}
if not root.is_dir():
return files
for path in sorted(root.rglob("*")):
if not path.is_file():
continue
if "__pycache__" in path.parts or path.suffix == ".pyc":
continue
rel = path.relative_to(root).as_posix()
if prefix and not rel.startswith(prefix):
continue
files[rel] = path.read_text(encoding="utf-8")
return files
def _read_component(
self,
entry: dict[str, Any],
@@ -186,6 +260,66 @@ class StandardsMCPServer(MCPServer):
}
return self._read_component(entry, resource, family)
@self.app.tool()
def get_app_template(prefix: str = "") -> dict[str, Any]:
"""Return the whole app skeleton as a path -> content map.
Use this to scaffold in one shot instead of pulling components one
by one; combine with :func:`list_app_components` for the kind and
placeholder metadata. Seed tokens (``item`` / ``example``) are left
as-is here — fetch a renamed file with :func:`get_app_component`.
Args:
prefix (str): Optional path prefix filter with POSIX
separators, for example ``"infra/"`` or ``"pipelines/"``.
Empty returns every file.
Returns:
dict[str, Any]: ``{root, file_count, files: {relpath: content}}``.
"""
files = self._template_files(prefix or None)
return {
"root": "templates/app",
"file_count": len(files),
"files": files,
}
@self.app.prompt()
def intake() -> str:
"""Return the questions to gather before building an app.
Use this (or `start_app` with no arguments) to collect the two axes
and the integration list. Answer them, then call `build`.
Returns:
str: The intake questions.
"""
return _INTAKE_TEXT
@self.app.prompt()
def build(
app_name: str = "",
resources: str = "",
pipelines: str = "",
auth: str = "no",
) -> str:
"""Emit the deterministic build prompt from the two axes.
Args:
app_name (str): App name + one-line purpose.
resources (str): Axis 1 — resources, fields, relationships
(or a pasted openapi.yaml).
pipelines (str): Axis 2 — pipeline families + input formats.
auth (str): Whether auth is needed now ("yes"/"no").
Returns:
str: The build prompt, or the intake questions when the axes
are missing.
"""
if not app_name or not resources:
return _INTAKE_TEXT
return _build_text(app_name, resources, pipelines, auth)
@self.app.prompt()
def start_app(
app_name: str = "",
@@ -209,30 +343,36 @@ class StandardsMCPServer(MCPServer):
str: The intake questions, or the build prompt when complete.
"""
if not app_name or not resources:
return (
"# Start a new app — intake\n\n"
"Gather the following, then call `start_app` again with the values:\n\n"
"1. App name + one-line purpose.\n"
"2. Axis 1 — resources: each resource, its fields, and relationships\n"
" (or paste `openapi.yaml`).\n"
"3. Axis 2 — pipelines: multi-step inputs? families + formats (or `none`).\n"
"4. Auth needed now? (yes/no; auth is deferred — `py-jwt` only).\n"
"5. Integrations: Mongo / ingestion formats / email / LLM provider.\n\n"
"Then: `start_app(app_name=..., resources=..., pipelines=..., auth=...)`.\n"
)
return _INTAKE_TEXT
return _build_text(app_name, resources, pipelines, auth)
@self.app.prompt()
def trial(app_name: str = "", build_path: str = "") -> str:
"""Prompt a self-contained trial build into a scratch directory.
Use this to validate the standard end-to-end without touching a real
app: generate into a throwaway path, prove it builds, and record
findings.
Args:
app_name (str): App to build for the trial.
build_path (str): Where to write the trial app.
Returns:
str: The trial prompt.
"""
target = build_path or f"apps/{app_name or '<app>'}-trial"
return (
f"# Build: {app_name}\n\n"
"## Spec\n"
f"- resources: {resources}\n"
f"- pipelines: {pipelines or 'none'}\n"
f"- auth: {auth}\n\n"
"## Method (deterministic)\n"
"1. Read `doc://modules/build_recipe` and follow it step by step.\n"
"2. Read `doc://modules/genericity_matrix` (Tier A/B/C) and "
"`doc://modules/layering_rules`.\n"
"3. Call `find_library(capability)` for db, di, routing, ingestion, "
"and pipeline; never reimplement a Tier A library.\n"
"4. Pull exact files with `list_app_components()` and "
"`get_app_component(kind, resource=..., family=...)`.\n"
"5. Author only Tier C; keep Tier B as shipped.\n"
f"# Trial: {app_name or '<app>'}\n\n"
f"Build into `{target}` (a throwaway path) and validate the "
"standard end-to-end.\n\n"
"## Steps\n"
"1. Run the `build` prompt to get the deterministic build prompt.\n"
f"2. Scaffold into `{target}` only — never an existing app.\n"
"3. Prove it: `python -c \"import main\"` and `pytest`.\n"
"4. Record every friction point as a finding: missing component, "
"wrong codegen shape, ambiguous doc, or missing prompt.\n"
"5. Do not fix the standard from inside the trial; report findings "
"back so the standard can be amended.\n\n"
f"Delete `{target}` once you are satisfied.\n"
)