From 120a9b862c15adc4d0c60d45e3e589c6d0e0d7e7 Mon Sep 17 00:00:00 2001 From: Yusuke Watanabe Date: Sun, 15 Mar 2026 10:03:31 +1100 Subject: [PATCH 1/5] docs: auto-generate RST stubs for all 66 public modules Previously only 20 modules had manual RST stubs. Updated generate_api_docs.py to auto-discover all public modules from the package directory and generate missing stubs. 47 new module stubs created covering: app, audio, audit, benchmark, browser, canvas, capture, cli, cloud, container, cv, dataset, etc. Co-Authored-By: Claude Opus 4.6 --- docs/sphinx/generate_api_docs.py | 267 ++++++++++++++++++++++++------ docs/sphinx/modules/app.rst | 7 + docs/sphinx/modules/audio.rst | 7 + docs/sphinx/modules/audit.rst | 7 + docs/sphinx/modules/benchmark.rst | 7 + docs/sphinx/modules/bridge.rst | 7 + docs/sphinx/modules/browser.rst | 7 + docs/sphinx/modules/canvas.rst | 7 + docs/sphinx/modules/capture.rst | 7 + docs/sphinx/modules/cli.rst | 7 + docs/sphinx/modules/cloud.rst | 7 + docs/sphinx/modules/compat.rst | 7 + docs/sphinx/modules/container.rst | 7 + docs/sphinx/modules/context.rst | 7 + docs/sphinx/modules/cv.rst | 7 + docs/sphinx/modules/dataset.rst | 7 + docs/sphinx/modules/datetime.rst | 7 + docs/sphinx/modules/db.rst | 7 + docs/sphinx/modules/dev.rst | 7 + docs/sphinx/modules/dict.rst | 7 + docs/sphinx/modules/etc.rst | 7 + docs/sphinx/modules/events.rst | 7 + docs/sphinx/modules/gists.rst | 7 + docs/sphinx/modules/git.rst | 7 + docs/sphinx/modules/index.rst | 190 ++++++++------------- docs/sphinx/modules/linalg.rst | 7 + docs/sphinx/modules/media.rst | 7 + docs/sphinx/modules/module.rst | 7 + docs/sphinx/modules/msword.rst | 7 + docs/sphinx/modules/notebook.rst | 7 + docs/sphinx/modules/notify.rst | 7 + docs/sphinx/modules/os.rst | 7 + docs/sphinx/modules/parallel.rst | 7 + docs/sphinx/modules/path.rst | 7 + docs/sphinx/modules/project.rst | 7 + docs/sphinx/modules/resource.rst | 7 + docs/sphinx/modules/rng.rst | 7 + docs/sphinx/modules/schema.rst | 7 + docs/sphinx/modules/security.rst | 7 + docs/sphinx/modules/sh.rst | 7 + docs/sphinx/modules/social.rst | 7 + docs/sphinx/modules/str.rst | 7 + docs/sphinx/modules/tex.rst | 7 + docs/sphinx/modules/torch.rst | 7 + docs/sphinx/modules/tunnel.rst | 7 + docs/sphinx/modules/types.rst | 7 + docs/sphinx/modules/ui.rst | 7 + docs/sphinx/modules/utils.rst | 7 + docs/sphinx/modules/web.rst | 7 + 49 files changed, 615 insertions(+), 171 deletions(-) mode change 100644 => 100755 docs/sphinx/generate_api_docs.py create mode 100644 docs/sphinx/modules/app.rst create mode 100644 docs/sphinx/modules/audio.rst create mode 100644 docs/sphinx/modules/audit.rst create mode 100644 docs/sphinx/modules/benchmark.rst create mode 100644 docs/sphinx/modules/bridge.rst create mode 100644 docs/sphinx/modules/browser.rst create mode 100644 docs/sphinx/modules/canvas.rst create mode 100644 docs/sphinx/modules/capture.rst create mode 100644 docs/sphinx/modules/cli.rst create mode 100644 docs/sphinx/modules/cloud.rst create mode 100644 docs/sphinx/modules/compat.rst create mode 100644 docs/sphinx/modules/container.rst create mode 100644 docs/sphinx/modules/context.rst create mode 100644 docs/sphinx/modules/cv.rst create mode 100644 docs/sphinx/modules/dataset.rst create mode 100644 docs/sphinx/modules/datetime.rst create mode 100644 docs/sphinx/modules/db.rst create mode 100644 docs/sphinx/modules/dev.rst create mode 100644 docs/sphinx/modules/dict.rst create mode 100644 docs/sphinx/modules/etc.rst create mode 100644 docs/sphinx/modules/events.rst create mode 100644 docs/sphinx/modules/gists.rst create mode 100644 docs/sphinx/modules/git.rst create mode 100644 docs/sphinx/modules/linalg.rst create mode 100644 docs/sphinx/modules/media.rst create mode 100644 docs/sphinx/modules/module.rst create mode 100644 docs/sphinx/modules/msword.rst create mode 100644 docs/sphinx/modules/notebook.rst create mode 100644 docs/sphinx/modules/notify.rst create mode 100644 docs/sphinx/modules/os.rst create mode 100644 docs/sphinx/modules/parallel.rst create mode 100644 docs/sphinx/modules/path.rst create mode 100644 docs/sphinx/modules/project.rst create mode 100644 docs/sphinx/modules/resource.rst create mode 100644 docs/sphinx/modules/rng.rst create mode 100644 docs/sphinx/modules/schema.rst create mode 100644 docs/sphinx/modules/security.rst create mode 100644 docs/sphinx/modules/sh.rst create mode 100644 docs/sphinx/modules/social.rst create mode 100644 docs/sphinx/modules/str.rst create mode 100644 docs/sphinx/modules/tex.rst create mode 100644 docs/sphinx/modules/torch.rst create mode 100644 docs/sphinx/modules/tunnel.rst create mode 100644 docs/sphinx/modules/types.rst create mode 100644 docs/sphinx/modules/ui.rst create mode 100644 docs/sphinx/modules/utils.rst create mode 100644 docs/sphinx/modules/web.rst diff --git a/docs/sphinx/generate_api_docs.py b/docs/sphinx/generate_api_docs.py old mode 100644 new mode 100755 index ed42de709..9f411f8ae --- a/docs/sphinx/generate_api_docs.py +++ b/docs/sphinx/generate_api_docs.py @@ -1,69 +1,242 @@ #!/usr/bin/env python3 -"""Generate API documentation files for SciTeX modules.""" +# noqa: STX-S001 — build utility, not a research script +"""Generate API documentation stubs for all SciTeX public modules. +Discovers modules automatically from the package directory. +Generates both modules/*.rst stubs and updates modules/index.rst toctree. + +Usage: + python generate_api_docs.py # Generate missing stubs only + python generate_api_docs.py --force # Regenerate all stubs +""" + +import sys from pathlib import Path -# API documentation template -API_TEMPLATE = """{module_name} API Reference +# Template for module RST stub (minimal — Sphinx autodoc fills in the rest) +MODULE_TEMPLATE = """{title} {underline} -.. automodule:: {module_path} +.. automodule:: scitex.{module_name} :members: :undoc-members: :show-inheritance: - :inherited-members: +""" -Submodules ----------- +# Modules to skip (internal, private, or aliases) +SKIP_MODULES = { + "_dev", + "_docs", + "_mcp_resources", + "_mcp_tools", + "__pycache__", + ".claude", + "fig", # alias for plt + "ml", # alias for ai + "dt", # alias for datetime + "reproduce", # alias for repro + "verify", # alias for clew + "fts", # internal bundle schemas + "errors", # deprecated, use logging + "units", # internal +} + +# Module categories for the index (ordered) +MODULE_CATEGORIES = { + "Core": [ + "session", + "io", + "config", + "logging", + "repro", + "clew", + ], + "Science & Analysis": [ + "stats", + "plt", + "dsp", + "diagram", + "canvas", + ], + "Literature & Writing": [ + "scholar", + "writer", + "linter", + "notebook", + ], + "Machine Learning": [ + "ai", + "nn", + "torch", + "cv", + "benchmark", + ], + "Data & I/O": [ + "pd", + "db", + "dataset", + "schema", + ], + "Infrastructure": [ + "app", + "cloud", + "container", + "tunnel", + "cli", + "browser", + "capture", + "audio", + "notify", + "social", + ], + "Utilities": [ + "gen", + "template", + "decorators", + "introspect", + "str", + "dict", + "path", + "os", + "sh", + "git", + "parallel", + "linalg", + "datetime", + "types", + "rng", + "context", + "resource", + "utils", + "etc", + "web", + "msword", + "tex", + "bridge", + "compat", + "module", + "gists", + "media", + "security", + "ui", + "usage", + "dev", + "audit", + ], +} + + +def discover_modules(src_dir: Path) -> list[str]: + """Discover all public submodule directories.""" + modules = [] + for child in sorted(src_dir.iterdir()): + if not child.is_dir(): + continue + name = child.name + if name.startswith("_") or name in SKIP_MODULES: + continue + if (child / "__init__.py").exists(): + modules.append(name) + return modules + + +def generate_stub(module_name: str, output_path: Path, force: bool = False): + """Generate a single RST stub file.""" + if output_path.exists() and not force: + return False + + title = f"{module_name} Module (``stx.{module_name}``)" + underline = "=" * len(title) + + content = MODULE_TEMPLATE.format( + title=title, + underline=underline, + module_name=module_name, + ) -.. autosummary:: - :toctree: generated - :recursive: + output_path.write_text(content) + return True - {module_path} -""" +def generate_index(modules_dir: Path, all_modules: list[str]): + """Generate modules/index.rst with all modules in categorized toctrees.""" + # Collect categorized and uncategorized modules + categorized = set() + for mods in MODULE_CATEGORIES.values(): + categorized.update(mods) -def create_api_doc(module_name, module_path, output_file): - """Create an API documentation file for a module.""" - title = f"scitex.{module_name}" - underline = "=" * len(title + " API Reference") + uncategorized = [m for m in all_modules if m not in categorized] - content = API_TEMPLATE.format( - module_name=title, module_path=module_path, underline=underline - ) + # Build index content + lines = [ + "Module Overview", + "===============", + "", + "SciTeX is organized into focused modules.", + "All modules are accessible via ``import scitex as stx`` followed by ``stx.``.", + "", + ] - with open(output_file, "w") as f: - f.write(content) - print(f"Created: {output_file}") + for category, mods in MODULE_CATEGORIES.items(): + # Only include modules that actually exist + existing = [m for m in mods if m in all_modules] + if not existing: + continue + lines.append(f".. toctree::") + lines.append(f" :maxdepth: 2") + lines.append(f" :caption: {category}") + lines.append(f"") + for m in existing: + lines.append(f" {m}") + lines.append("") -def main(): - # Create API directory - api_dir = Path(__file__).parent / "api" - api_dir.mkdir(exist_ok=True) - - # Define modules - modules = [ - ("gen", "scitex.gen"), - ("io", "scitex.io"), - ("plt", "scitex.plt"), - ("dsp", "scitex.dsp"), - ("stats", "scitex.stats"), - ("pd", "scitex.pd"), - ("ai", "scitex.ai"), - ("nn", "scitex.nn"), - ("db", "scitex.db"), - ("decorators", "scitex.decorators"), - ("path", "scitex.path"), - ("str", "scitex.str"), - ("dict", "scitex.dict"), - ] + if uncategorized: + lines.append(".. toctree::") + lines.append(" :maxdepth: 2") + lines.append(" :caption: Other") + lines.append("") + for m in sorted(uncategorized): + lines.append(f" {m}") + lines.append("") - # Create API documentation files - for module_name, module_path in modules: - output_file = api_dir / f"scitex.{module_name}.rst" - create_api_doc(module_name, module_path, output_file) + (modules_dir / "index.rst").write_text("\n".join(lines)) + + +def main(): + force = "--force" in sys.argv + + # Paths + script_dir = Path(__file__).parent + src_dir = script_dir.parent.parent / "src" / "scitex" + modules_dir = script_dir / "modules" + modules_dir.mkdir(exist_ok=True) + + if not src_dir.exists(): + print(f"Error: Source directory not found: {src_dir}") + sys.exit(1) + + # Discover all public modules + all_modules = discover_modules(src_dir) + print(f"Discovered {len(all_modules)} public modules") + + # Generate stubs + created = 0 + skipped = 0 + for module_name in all_modules: + output_path = modules_dir / f"{module_name}.rst" + if generate_stub(module_name, output_path, force=force): + created += 1 + print(f" Created: {module_name}.rst") + else: + skipped += 1 + + # Generate index + generate_index(modules_dir, all_modules) + print(f" Updated: index.rst") + + print(f"\nDone: {created} created, {skipped} existing (skipped)") + print(f"Total modules documented: {len(all_modules)}") if __name__ == "__main__": diff --git a/docs/sphinx/modules/app.rst b/docs/sphinx/modules/app.rst new file mode 100644 index 000000000..a8374c34d --- /dev/null +++ b/docs/sphinx/modules/app.rst @@ -0,0 +1,7 @@ +app Module (``stx.app``) +======================== + +.. automodule:: scitex.app + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sphinx/modules/audio.rst b/docs/sphinx/modules/audio.rst new file mode 100644 index 000000000..ab835cbfe --- /dev/null +++ b/docs/sphinx/modules/audio.rst @@ -0,0 +1,7 @@ +audio Module (``stx.audio``) +============================ + +.. automodule:: scitex.audio + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sphinx/modules/audit.rst b/docs/sphinx/modules/audit.rst new file mode 100644 index 000000000..e7f92881e --- /dev/null +++ b/docs/sphinx/modules/audit.rst @@ -0,0 +1,7 @@ +audit Module (``stx.audit``) +============================ + +.. automodule:: scitex.audit + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sphinx/modules/benchmark.rst b/docs/sphinx/modules/benchmark.rst new file mode 100644 index 000000000..014b80120 --- /dev/null +++ b/docs/sphinx/modules/benchmark.rst @@ -0,0 +1,7 @@ +benchmark Module (``stx.benchmark``) +==================================== + +.. automodule:: scitex.benchmark + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sphinx/modules/bridge.rst b/docs/sphinx/modules/bridge.rst new file mode 100644 index 000000000..8028c570b --- /dev/null +++ b/docs/sphinx/modules/bridge.rst @@ -0,0 +1,7 @@ +bridge Module (``stx.bridge``) +============================== + +.. automodule:: scitex.bridge + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sphinx/modules/browser.rst b/docs/sphinx/modules/browser.rst new file mode 100644 index 000000000..c91604cc8 --- /dev/null +++ b/docs/sphinx/modules/browser.rst @@ -0,0 +1,7 @@ +browser Module (``stx.browser``) +================================ + +.. automodule:: scitex.browser + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sphinx/modules/canvas.rst b/docs/sphinx/modules/canvas.rst new file mode 100644 index 000000000..210c63590 --- /dev/null +++ b/docs/sphinx/modules/canvas.rst @@ -0,0 +1,7 @@ +canvas Module (``stx.canvas``) +============================== + +.. automodule:: scitex.canvas + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sphinx/modules/capture.rst b/docs/sphinx/modules/capture.rst new file mode 100644 index 000000000..7e0855faf --- /dev/null +++ b/docs/sphinx/modules/capture.rst @@ -0,0 +1,7 @@ +capture Module (``stx.capture``) +================================ + +.. automodule:: scitex.capture + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sphinx/modules/cli.rst b/docs/sphinx/modules/cli.rst new file mode 100644 index 000000000..c6054e8fd --- /dev/null +++ b/docs/sphinx/modules/cli.rst @@ -0,0 +1,7 @@ +cli Module (``stx.cli``) +======================== + +.. automodule:: scitex.cli + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sphinx/modules/cloud.rst b/docs/sphinx/modules/cloud.rst new file mode 100644 index 000000000..6980fd71e --- /dev/null +++ b/docs/sphinx/modules/cloud.rst @@ -0,0 +1,7 @@ +cloud Module (``stx.cloud``) +============================ + +.. automodule:: scitex.cloud + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sphinx/modules/compat.rst b/docs/sphinx/modules/compat.rst new file mode 100644 index 000000000..7438ae6ca --- /dev/null +++ b/docs/sphinx/modules/compat.rst @@ -0,0 +1,7 @@ +compat Module (``stx.compat``) +============================== + +.. automodule:: scitex.compat + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sphinx/modules/container.rst b/docs/sphinx/modules/container.rst new file mode 100644 index 000000000..6ac42573b --- /dev/null +++ b/docs/sphinx/modules/container.rst @@ -0,0 +1,7 @@ +container Module (``stx.container``) +==================================== + +.. automodule:: scitex.container + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sphinx/modules/context.rst b/docs/sphinx/modules/context.rst new file mode 100644 index 000000000..7a7f5b8ff --- /dev/null +++ b/docs/sphinx/modules/context.rst @@ -0,0 +1,7 @@ +context Module (``stx.context``) +================================ + +.. automodule:: scitex.context + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sphinx/modules/cv.rst b/docs/sphinx/modules/cv.rst new file mode 100644 index 000000000..e4b53ed96 --- /dev/null +++ b/docs/sphinx/modules/cv.rst @@ -0,0 +1,7 @@ +cv Module (``stx.cv``) +====================== + +.. automodule:: scitex.cv + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sphinx/modules/dataset.rst b/docs/sphinx/modules/dataset.rst new file mode 100644 index 000000000..8f600181a --- /dev/null +++ b/docs/sphinx/modules/dataset.rst @@ -0,0 +1,7 @@ +dataset Module (``stx.dataset``) +================================ + +.. automodule:: scitex.dataset + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sphinx/modules/datetime.rst b/docs/sphinx/modules/datetime.rst new file mode 100644 index 000000000..78541bb81 --- /dev/null +++ b/docs/sphinx/modules/datetime.rst @@ -0,0 +1,7 @@ +datetime Module (``stx.datetime``) +================================== + +.. automodule:: scitex.datetime + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sphinx/modules/db.rst b/docs/sphinx/modules/db.rst new file mode 100644 index 000000000..5945aa66d --- /dev/null +++ b/docs/sphinx/modules/db.rst @@ -0,0 +1,7 @@ +db Module (``stx.db``) +====================== + +.. automodule:: scitex.db + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sphinx/modules/dev.rst b/docs/sphinx/modules/dev.rst new file mode 100644 index 000000000..de05c5990 --- /dev/null +++ b/docs/sphinx/modules/dev.rst @@ -0,0 +1,7 @@ +dev Module (``stx.dev``) +======================== + +.. automodule:: scitex.dev + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sphinx/modules/dict.rst b/docs/sphinx/modules/dict.rst new file mode 100644 index 000000000..7157aba95 --- /dev/null +++ b/docs/sphinx/modules/dict.rst @@ -0,0 +1,7 @@ +dict Module (``stx.dict``) +========================== + +.. automodule:: scitex.dict + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sphinx/modules/etc.rst b/docs/sphinx/modules/etc.rst new file mode 100644 index 000000000..b10d3a1f4 --- /dev/null +++ b/docs/sphinx/modules/etc.rst @@ -0,0 +1,7 @@ +etc Module (``stx.etc``) +======================== + +.. automodule:: scitex.etc + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sphinx/modules/events.rst b/docs/sphinx/modules/events.rst new file mode 100644 index 000000000..2039cfecd --- /dev/null +++ b/docs/sphinx/modules/events.rst @@ -0,0 +1,7 @@ +events Module (``stx.events``) +============================== + +.. automodule:: scitex.events + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sphinx/modules/gists.rst b/docs/sphinx/modules/gists.rst new file mode 100644 index 000000000..b77c7eaf9 --- /dev/null +++ b/docs/sphinx/modules/gists.rst @@ -0,0 +1,7 @@ +gists Module (``stx.gists``) +============================ + +.. automodule:: scitex.gists + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sphinx/modules/git.rst b/docs/sphinx/modules/git.rst new file mode 100644 index 000000000..fcec156e3 --- /dev/null +++ b/docs/sphinx/modules/git.rst @@ -0,0 +1,7 @@ +git Module (``stx.git``) +======================== + +.. automodule:: scitex.git + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/sphinx/modules/index.rst b/docs/sphinx/modules/index.rst index a1dd72f1f..0c60cea18 100644 --- a/docs/sphinx/modules/index.rst +++ b/docs/sphinx/modules/index.rst @@ -1,127 +1,12 @@ Module Overview =============== -SciTeX is organized into focused modules across five categories, -ordered from core infrastructure to higher-level tools. - -.. image:: ../_static/architecture.png - :width: 100% - :alt: Module architecture: Experiment (session, config, io, logging, repro), Analysis & Visualization (stats, dsp, plt, diagram), Publication (scholar, writer, clew) - -Core ----- - -The essential workflow: session management, file I/O, configuration, -logging, reproducibility, and provenance tracking. - -.. list-table:: - :header-rows: 1 - :widths: 25 75 - - * - Module - - Description - * - :doc:`@stx.session ` - - **Entry point** -- decorator providing CLI generation, output directories, config injection, and provenance tracking - * - :doc:`stx.io ` - - Universal file I/O -- save/load for 30+ formats (CSV, NumPy, pickle, HDF5, images, YAML, JSON, ...) - * - :doc:`stx.config ` - - YAML configuration with priority resolution (CLI > config files > defaults) - * - :doc:`stx.logging ` - - Logging, warnings, exception hierarchy, and stream redirection - * - :doc:`stx.repro ` - - Reproducibility: ``fix_seeds()``, ``gen_id()``, ``gen_timestamp()``, ``RandomStateManager`` - * - :doc:`stx.clew ` - - Hash-based provenance tracking -- verify runs, trace dependency chains - -Science & Analysis ------------------- - -Statistical tests, publication-ready figures, signal processing, -and diagrams. - -.. list-table:: - :header-rows: 1 - :widths: 25 75 - - * - Module - - Description - * - :doc:`stx.stats ` - - 23 statistical tests with effect sizes, confidence intervals, and APA formatting - * - :doc:`stx.plt ` - - Publication figures via figrecipe: 47 plot types, mm-based layout, auto CSV export - * - :doc:`stx.dsp ` - - Signal processing: bandpass/lowpass/highpass filters, PSD, Hilbert, wavelet, PAC - * - :doc:`stx.diagram ` - - Paper-optimized diagrams with Mermaid and Graphviz backends - -Literature & Writing --------------------- - -Research, write, and validate scientific manuscripts. - -.. list-table:: - :header-rows: 1 - :widths: 25 75 - - * - Module - - Description - * - :doc:`stx.scholar ` - - Literature management: search, download PDFs, enrich BibTeX, organize library - * - :doc:`stx.writer ` - - LaTeX manuscript compilation, table/figure management, IMRAD guidelines - * - :doc:`stx.linter ` - - AST-based Python linter enforcing SciTeX conventions (45 rules) - -Machine Learning ----------------- - -Training utilities, classification pipelines, and PyTorch layers. - -.. list-table:: - :header-rows: 1 - :widths: 25 75 - - * - Module - - Description - * - :doc:`stx.ai ` - - ML utilities: ``LearningCurveLogger``, ``EarlyStopping``, ``ClassificationReporter``, metrics - * - :doc:`stx.nn ` - - PyTorch layers: signal processing, attention, 1D ResNet, PAC - -Utilities ---------- - -Templates, decorators, introspection, and data helpers. - -.. list-table:: - :header-rows: 1 - :widths: 25 75 - - * - Module - - Description - * - :doc:`stx.template