diff --git a/README.md b/README.md
index c1a25c4ca..0eaca42ec 100755
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
@@ -43,7 +43,7 @@ SciTeX provides a **modular Python toolkit** that unifies the research workflow
## Demo
-**40 min, zero human intervention** — AI agent conducts full research pipeline:
+**40 min, minimal human intervention** — AI agent conducts full research pipeline:
> Literature search → Data analysis → Statistics → Figures → 21-page manuscript → Peer review simulation
@@ -304,8 +304,20 @@ The SciTeX system follows the Four Freedoms for Research below, inspired by [the
---
+## Star History
+
+
+
+
+
+
+
+
+
+---
+
-
+
\ No newline at end of file
diff --git a/docs/sphinx/generate_api_docs.py b/docs/sphinx/generate_api_docs.py
old mode 100644
new mode 100755
index ed42de709..5c7c6fa1b
--- a/docs/sphinx/generate_api_docs.py
+++ b/docs/sphinx/generate_api_docs.py
@@ -1,69 +1,243 @@
#!/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"
+ # Output to source/api/ (where Sphinx actually reads from)
+ modules_dir = script_dir / "source" / "api"
+ modules_dir.mkdir(parents=True, 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 `
- - Project scaffolding and code snippet templates
- * - :doc:`stx.decorators `
- - Type conversion (``@torch_fn``), batching (``@batch_fn``), caching, timeout
- * - :doc:`stx.introspect `
- - IPython-like code inspection: ``q()``, ``qq()``, ``dir()``, call graphs
- * - :doc:`stx.pd `
- - Pandas helpers: ``find_indi``, ``melt_cols``, ``merge_cols``, ``to_xyz``
- * - ``stx.gen``
- - General utilities: ``mk_spath()``, ``run()``, ``copy()/paste()``
- * - ``stx.str``
- - LaTeX formatting, axis labels, ``color_text()``, ``to_latex_style()``
- * - ``stx.dict``
- - ``DotDict``, ``flatten()``, ``safe_merge()``, ``listed_dict()``
- * - ``stx.db``
- - SQLite3 and PostgreSQL wrappers with batch operations
- * - ``stx.social``
- - Social media posting and Google Analytics
+SciTeX is organized into focused modules.
+All modules are accessible via ``import scitex as stx`` followed by ``stx.``.
.. toctree::
:maxdepth: 2
:caption: Core
- :hidden:
session
io
@@ -133,37 +18,94 @@ Templates, decorators, introspection, and data helpers.
.. toctree::
:maxdepth: 2
:caption: Science & Analysis
- :hidden:
stats
plt
dsp
diagram
+ canvas
.. toctree::
:maxdepth: 2
:caption: Literature & Writing
- :hidden:
scholar
writer
- linter
+ notebook
.. toctree::
:maxdepth: 2
:caption: Machine Learning
- :hidden:
ai
nn
+ torch
+ cv
+ benchmark
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Data & I/O
+
+ pd
+ db
+ dataset
+ schema
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Infrastructure
+
+ app
+ cloud
+ container
+ tunnel
+ cli
+ browser
+ capture
+ audio
+ notify
+ social
.. toctree::
:maxdepth: 2
:caption: Utilities
- :hidden:
+ gen
template
decorators
introspect
- pd
- gen
+ 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
+ dev
+ audit
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Other
+
+ events
+ project
diff --git a/docs/sphinx/modules/linalg.rst b/docs/sphinx/modules/linalg.rst
new file mode 100644
index 000000000..2f7ce9a85
--- /dev/null
+++ b/docs/sphinx/modules/linalg.rst
@@ -0,0 +1,7 @@
+linalg Module (``stx.linalg``)
+==============================
+
+.. automodule:: scitex.linalg
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/modules/media.rst b/docs/sphinx/modules/media.rst
new file mode 100644
index 000000000..34e386c28
--- /dev/null
+++ b/docs/sphinx/modules/media.rst
@@ -0,0 +1,7 @@
+media Module (``stx.media``)
+============================
+
+.. automodule:: scitex.media
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/modules/module.rst b/docs/sphinx/modules/module.rst
new file mode 100644
index 000000000..6ba06a686
--- /dev/null
+++ b/docs/sphinx/modules/module.rst
@@ -0,0 +1,7 @@
+module Module (``stx.module``)
+==============================
+
+.. automodule:: scitex.module
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/modules/msword.rst b/docs/sphinx/modules/msword.rst
new file mode 100644
index 000000000..a48391fae
--- /dev/null
+++ b/docs/sphinx/modules/msword.rst
@@ -0,0 +1,7 @@
+msword Module (``stx.msword``)
+==============================
+
+.. automodule:: scitex.msword
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/modules/notebook.rst b/docs/sphinx/modules/notebook.rst
new file mode 100644
index 000000000..b66a0a1c0
--- /dev/null
+++ b/docs/sphinx/modules/notebook.rst
@@ -0,0 +1,7 @@
+notebook Module (``stx.notebook``)
+==================================
+
+.. automodule:: scitex.notebook
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/modules/notify.rst b/docs/sphinx/modules/notify.rst
new file mode 100644
index 000000000..4dfc60e3a
--- /dev/null
+++ b/docs/sphinx/modules/notify.rst
@@ -0,0 +1,7 @@
+notify Module (``stx.notify``)
+==============================
+
+.. automodule:: scitex.notify
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/modules/os.rst b/docs/sphinx/modules/os.rst
new file mode 100644
index 000000000..be2fda313
--- /dev/null
+++ b/docs/sphinx/modules/os.rst
@@ -0,0 +1,7 @@
+os Module (``stx.os``)
+======================
+
+.. automodule:: scitex.os
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/modules/parallel.rst b/docs/sphinx/modules/parallel.rst
new file mode 100644
index 000000000..620d8333d
--- /dev/null
+++ b/docs/sphinx/modules/parallel.rst
@@ -0,0 +1,7 @@
+parallel Module (``stx.parallel``)
+==================================
+
+.. automodule:: scitex.parallel
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/modules/path.rst b/docs/sphinx/modules/path.rst
new file mode 100644
index 000000000..672ff6967
--- /dev/null
+++ b/docs/sphinx/modules/path.rst
@@ -0,0 +1,7 @@
+path Module (``stx.path``)
+==========================
+
+.. automodule:: scitex.path
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/modules/project.rst b/docs/sphinx/modules/project.rst
new file mode 100644
index 000000000..b0440a59f
--- /dev/null
+++ b/docs/sphinx/modules/project.rst
@@ -0,0 +1,7 @@
+project Module (``stx.project``)
+================================
+
+.. automodule:: scitex.project
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/modules/resource.rst b/docs/sphinx/modules/resource.rst
new file mode 100644
index 000000000..d4fbcc001
--- /dev/null
+++ b/docs/sphinx/modules/resource.rst
@@ -0,0 +1,7 @@
+resource Module (``stx.resource``)
+==================================
+
+.. automodule:: scitex.resource
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/modules/rng.rst b/docs/sphinx/modules/rng.rst
new file mode 100644
index 000000000..a6ab74def
--- /dev/null
+++ b/docs/sphinx/modules/rng.rst
@@ -0,0 +1,7 @@
+rng Module (``stx.rng``)
+========================
+
+.. automodule:: scitex.rng
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/modules/schema.rst b/docs/sphinx/modules/schema.rst
new file mode 100644
index 000000000..919582dbf
--- /dev/null
+++ b/docs/sphinx/modules/schema.rst
@@ -0,0 +1,7 @@
+schema Module (``stx.schema``)
+==============================
+
+.. automodule:: scitex.schema
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/modules/security.rst b/docs/sphinx/modules/security.rst
new file mode 100644
index 000000000..232a5da7f
--- /dev/null
+++ b/docs/sphinx/modules/security.rst
@@ -0,0 +1,7 @@
+security Module (``stx.security``)
+==================================
+
+.. automodule:: scitex.security
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/modules/sh.rst b/docs/sphinx/modules/sh.rst
new file mode 100644
index 000000000..7c4694af6
--- /dev/null
+++ b/docs/sphinx/modules/sh.rst
@@ -0,0 +1,7 @@
+sh Module (``stx.sh``)
+======================
+
+.. automodule:: scitex.sh
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/modules/social.rst b/docs/sphinx/modules/social.rst
new file mode 100644
index 000000000..cc82af401
--- /dev/null
+++ b/docs/sphinx/modules/social.rst
@@ -0,0 +1,7 @@
+social Module (``stx.social``)
+==============================
+
+.. automodule:: scitex.social
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/modules/str.rst b/docs/sphinx/modules/str.rst
new file mode 100644
index 000000000..b29b4f485
--- /dev/null
+++ b/docs/sphinx/modules/str.rst
@@ -0,0 +1,7 @@
+str Module (``stx.str``)
+========================
+
+.. automodule:: scitex.str
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/modules/tex.rst b/docs/sphinx/modules/tex.rst
new file mode 100644
index 000000000..e0f775bd9
--- /dev/null
+++ b/docs/sphinx/modules/tex.rst
@@ -0,0 +1,7 @@
+tex Module (``stx.tex``)
+========================
+
+.. automodule:: scitex.tex
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/modules/torch.rst b/docs/sphinx/modules/torch.rst
new file mode 100644
index 000000000..1a11fe241
--- /dev/null
+++ b/docs/sphinx/modules/torch.rst
@@ -0,0 +1,7 @@
+torch Module (``stx.torch``)
+============================
+
+.. automodule:: scitex.torch
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/modules/tunnel.rst b/docs/sphinx/modules/tunnel.rst
new file mode 100644
index 000000000..e28928527
--- /dev/null
+++ b/docs/sphinx/modules/tunnel.rst
@@ -0,0 +1,7 @@
+tunnel Module (``stx.tunnel``)
+==============================
+
+.. automodule:: scitex.tunnel
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/modules/types.rst b/docs/sphinx/modules/types.rst
new file mode 100644
index 000000000..f4f1e1031
--- /dev/null
+++ b/docs/sphinx/modules/types.rst
@@ -0,0 +1,7 @@
+types Module (``stx.types``)
+============================
+
+.. automodule:: scitex.types
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/modules/ui.rst b/docs/sphinx/modules/ui.rst
new file mode 100644
index 000000000..2a8a65a64
--- /dev/null
+++ b/docs/sphinx/modules/ui.rst
@@ -0,0 +1,7 @@
+ui Module (``stx.ui``)
+======================
+
+.. automodule:: scitex.ui
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/modules/utils.rst b/docs/sphinx/modules/utils.rst
new file mode 100644
index 000000000..9b893ac20
--- /dev/null
+++ b/docs/sphinx/modules/utils.rst
@@ -0,0 +1,7 @@
+utils Module (``stx.utils``)
+============================
+
+.. automodule:: scitex.utils
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/modules/web.rst b/docs/sphinx/modules/web.rst
new file mode 100644
index 000000000..5b6589d9d
--- /dev/null
+++ b/docs/sphinx/modules/web.rst
@@ -0,0 +1,7 @@
+web Module (``stx.web``)
+========================
+
+.. automodule:: scitex.web
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/ai.rst b/docs/sphinx/source/api/ai.rst
new file mode 100644
index 000000000..e5fb03cee
--- /dev/null
+++ b/docs/sphinx/source/api/ai.rst
@@ -0,0 +1,82 @@
+AI Module (``stx.ai``)
+======================
+
+Machine learning utilities for training, classification, and metrics
+with PyTorch and scikit-learn.
+
+Quick Reference
+---------------
+
+.. code-block:: python
+
+ import scitex as stx
+
+ # Training utilities
+ from scitex.ai import LearningCurveLogger, EarlyStopping
+
+ logger = LearningCurveLogger()
+ stopper = EarlyStopping(patience=10, direction="minimize")
+
+ for epoch in range(100):
+ # ... training loop ...
+ logger({"loss": loss, "acc": acc}, step="Training")
+ if stopper(val_loss, {"model": model_path}, epoch):
+ break
+
+ logger.plot_learning_curves(spath="curves.png")
+
+ # Classification
+ from scitex.ai import ClassificationReporter, Classifier
+
+ clf = Classifier()("SVC")
+ reporter = ClassificationReporter(output_dir="./results")
+ reporter.calculate_metrics(y_true, y_pred, y_proba)
+ reporter.save_summary()
+
+Training
+--------
+
+- ``LearningCurveLogger`` -- Track and visualize training/validation/test metrics across epochs
+- ``EarlyStopping`` -- Monitor validation metrics and stop when improvement plateaus
+
+Classification
+--------------
+
+- ``ClassificationReporter`` -- Unified reporter for single/multi-task classification (balanced accuracy, MCC, ROC-AUC, confusion matrices)
+- ``Classifier`` -- Factory for scikit-learn classifiers (SVC, KNN, Logistic Regression, AdaBoost, ...)
+- ``CrossValidationExperiment`` -- Cross-validation framework
+
+Metrics
+-------
+
+Standardized ``calc_*`` functions:
+
+- ``calc_bacc`` -- Balanced accuracy
+- ``calc_mcc`` -- Matthews Correlation Coefficient
+- ``calc_conf_mat`` -- Confusion matrix
+- ``calc_roc_auc`` -- ROC-AUC score
+- ``calc_pre_rec_auc`` -- Precision-Recall AUC
+- ``calc_feature_importance`` -- Feature importance scores
+
+Visualization
+-------------
+
+- ``plot_learning_curve`` -- Training/validation curves
+- ``stx_conf_mat`` -- Confusion matrix heatmap
+- ``plot_roc_curve`` -- ROC curve
+- ``plot_pre_rec_curve`` -- Precision-Recall curve
+- ``plot_feature_importance`` -- Feature importance bar plots
+
+Other
+-----
+
+- ``MultiTaskLoss`` -- Multi-task learning loss weighting
+- ``get_optimizer`` / ``set_optimizer`` -- Optimizer management
+- ``GenAI`` -- Generative AI wrapper (lazy-loaded)
+- Clustering: ``pca``, ``umap``
+
+API Reference
+-------------
+
+.. automodule:: scitex.ai
+ :members:
diff --git a/docs/sphinx/source/api/app.rst b/docs/sphinx/source/api/app.rst
new file mode 100644
index 000000000..a8374c34d
--- /dev/null
+++ b/docs/sphinx/source/api/app.rst
@@ -0,0 +1,7 @@
+app Module (``stx.app``)
+========================
+
+.. automodule:: scitex.app
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/audio.rst b/docs/sphinx/source/api/audio.rst
new file mode 100644
index 000000000..ab835cbfe
--- /dev/null
+++ b/docs/sphinx/source/api/audio.rst
@@ -0,0 +1,7 @@
+audio Module (``stx.audio``)
+============================
+
+.. automodule:: scitex.audio
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/audit.rst b/docs/sphinx/source/api/audit.rst
new file mode 100644
index 000000000..e7f92881e
--- /dev/null
+++ b/docs/sphinx/source/api/audit.rst
@@ -0,0 +1,7 @@
+audit Module (``stx.audit``)
+============================
+
+.. automodule:: scitex.audit
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/benchmark.rst b/docs/sphinx/source/api/benchmark.rst
new file mode 100644
index 000000000..014b80120
--- /dev/null
+++ b/docs/sphinx/source/api/benchmark.rst
@@ -0,0 +1,7 @@
+benchmark Module (``stx.benchmark``)
+====================================
+
+.. automodule:: scitex.benchmark
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/bridge.rst b/docs/sphinx/source/api/bridge.rst
new file mode 100644
index 000000000..8028c570b
--- /dev/null
+++ b/docs/sphinx/source/api/bridge.rst
@@ -0,0 +1,7 @@
+bridge Module (``stx.bridge``)
+==============================
+
+.. automodule:: scitex.bridge
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/browser.rst b/docs/sphinx/source/api/browser.rst
new file mode 100644
index 000000000..c91604cc8
--- /dev/null
+++ b/docs/sphinx/source/api/browser.rst
@@ -0,0 +1,7 @@
+browser Module (``stx.browser``)
+================================
+
+.. automodule:: scitex.browser
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/canvas.rst b/docs/sphinx/source/api/canvas.rst
new file mode 100644
index 000000000..210c63590
--- /dev/null
+++ b/docs/sphinx/source/api/canvas.rst
@@ -0,0 +1,7 @@
+canvas Module (``stx.canvas``)
+==============================
+
+.. automodule:: scitex.canvas
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/capture.rst b/docs/sphinx/source/api/capture.rst
new file mode 100644
index 000000000..7e0855faf
--- /dev/null
+++ b/docs/sphinx/source/api/capture.rst
@@ -0,0 +1,7 @@
+capture Module (``stx.capture``)
+================================
+
+.. automodule:: scitex.capture
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/clew.rst b/docs/sphinx/source/api/clew.rst
new file mode 100644
index 000000000..017427e08
--- /dev/null
+++ b/docs/sphinx/source/api/clew.rst
@@ -0,0 +1,94 @@
+Clew Module (``stx.clew``)
+==========================
+
+Hash-based provenance tracking for reproducible science. Clew (Ariadne's
+thread) records file hashes during ``@stx.session`` runs and traces
+dependency chains back to source.
+
+How It Works
+------------
+
+1. ``@stx.session`` starts a tracking session
+2. ``stx.io.load()`` records input file hashes
+3. ``stx.io.save()`` records output file hashes
+4. Session close computes a combined hash of all inputs/outputs
+5. Later, ``stx.clew`` can verify nothing has changed
+
+.. code-block:: python
+
+ import scitex as stx
+
+ # Automatic -- just use @stx.session + stx.io
+ @stx.session
+ def main():
+ data = stx.io.load("input.csv") # Tracked as input
+ result = process(data)
+ stx.io.save(result, "output.png") # Tracked as output
+ return 0
+
+ # Verify later
+ stx.clew.status() # Like git status
+ stx.clew.run("session_id") # Verify by hash
+ stx.clew.chain("output.png") # Trace to source
+
+CLI Commands
+------------
+
+.. code-block:: bash
+
+ scitex clew status # Show changed files
+ scitex clew list # List all tracked runs
+ scitex clew run # Verify a specific run
+ scitex clew chain # Trace dependency chain
+ scitex clew stats # Database statistics
+
+Verification Levels
+-------------------
+
+- **CACHE** -- Hash comparison only (fast). Checks if files match stored hashes.
+- **RERUN** -- Re-execute scripts and compare outputs (thorough). Catches logic errors.
+
+.. code-block:: python
+
+ # Fast: hash comparison
+ result = stx.clew.run("session_id")
+
+ # Thorough: re-execute and compare
+ result = stx.clew.run("session_id", from_scratch=True)
+
+Dependency Chains
+-----------------
+
+Clew traces ``parent_session`` links to build a DAG from final output
+back to original source:
+
+.. code-block:: python
+
+ chain = stx.clew.chain("final_figure.png")
+ # Shows: source.py → intermediate.csv → analysis.py → final_figure.png
+
+ # Visualize as Mermaid DAG
+ stx.clew.mermaid("session_id")
+
+Verification Statuses
+---------------------
+
+- ``VERIFIED`` -- Files match expected hashes
+- ``MISMATCH`` -- Files differ from stored hashes
+- ``MISSING`` -- Files no longer exist
+- ``UNKNOWN`` -- No prior tracking data
+
+Key Functions
+-------------
+
+- ``status()`` -- Show changed items (like ``git status``)
+- ``run(session_id)`` -- Verify a specific run
+- ``chain(target_file)`` -- Trace dependency chain
+- ``list_runs(limit, status)`` -- List tracked runs
+- ``stats()`` -- Database statistics
+
+API Reference
+-------------
+
+.. automodule:: scitex.clew
+ :members:
diff --git a/docs/sphinx/source/api/cli.rst b/docs/sphinx/source/api/cli.rst
new file mode 100644
index 000000000..c6054e8fd
--- /dev/null
+++ b/docs/sphinx/source/api/cli.rst
@@ -0,0 +1,7 @@
+cli Module (``stx.cli``)
+========================
+
+.. automodule:: scitex.cli
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/cloud.rst b/docs/sphinx/source/api/cloud.rst
new file mode 100644
index 000000000..6980fd71e
--- /dev/null
+++ b/docs/sphinx/source/api/cloud.rst
@@ -0,0 +1,7 @@
+cloud Module (``stx.cloud``)
+============================
+
+.. automodule:: scitex.cloud
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/compat.rst b/docs/sphinx/source/api/compat.rst
new file mode 100644
index 000000000..7438ae6ca
--- /dev/null
+++ b/docs/sphinx/source/api/compat.rst
@@ -0,0 +1,7 @@
+compat Module (``stx.compat``)
+==============================
+
+.. automodule:: scitex.compat
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/config.rst b/docs/sphinx/source/api/config.rst
new file mode 100644
index 000000000..11a770d0b
--- /dev/null
+++ b/docs/sphinx/source/api/config.rst
@@ -0,0 +1,88 @@
+Config Module (``stx.config``)
+===============================
+
+YAML-based configuration with priority resolution and path management.
+
+Priority Resolution
+-------------------
+
+All config values follow the same precedence:
+
+.. code-block:: text
+
+ direct argument > config/YAML > environment variable > default
+
+Quick Reference
+---------------
+
+.. code-block:: python
+
+ import scitex as stx
+
+ # Get global config (reads ~/.scitex/config.yaml)
+ config = stx.config.get_config()
+
+ # Resolve with precedence
+ log_level = config.resolve("logging.level", default="INFO")
+ # Checks: direct → YAML → SCITEX_LOGGING_LEVEL env → "INFO"
+
+ # Access nested values
+ config.get_nested("scholar", "crossref_email")
+
+ # Path management
+ paths = stx.config.get_paths()
+ paths.scholar # ~/.scitex/scholar
+ paths.cache # ~/.scitex/cache
+
+YAML Configuration
+------------------
+
+.. code-block:: yaml
+
+ # ~/.scitex/config.yaml (or ./config/*.yaml for projects)
+ logging:
+ level: INFO
+
+ scholar:
+ crossref_email: ${CROSSREF_EMAIL:-user@example.com}
+
+Environment variable substitution with ``${VAR:-default}`` syntax is
+supported in YAML files.
+
+Key Classes
+-----------
+
+- ``ScitexConfig`` -- YAML-based config with env var substitution and precedence resolution
+- ``PriorityConfig`` -- Dict-based config resolver for programmatic use
+- ``ScitexPaths`` -- Centralized path manager (all paths derive from ``~/.scitex/``)
+- ``EnvVar`` -- Environment variable definition dataclass
+
+Path Management
+---------------
+
+``ScitexPaths`` manages all SciTeX directories:
+
+.. code-block:: python
+
+ paths = stx.config.get_paths()
+ paths.base # ~/.scitex (SCITEX_DIR)
+ paths.logs # ~/.scitex/logs
+ paths.cache # ~/.scitex/cache
+ paths.scholar # ~/.scitex/scholar
+ paths.rng # ~/.scitex/rng
+ paths.capture # ~/.scitex/capture
+
+Utility Functions
+-----------------
+
+- ``get_config(path)`` -- Get singleton ScitexConfig instance
+- ``get_paths(base_dir)`` -- Get singleton ScitexPaths instance
+- ``load_yaml(path)`` -- Load YAML with env var substitution
+- ``load_dotenv(path)`` -- Load ``.env`` file
+- ``get_scitex_dir()`` -- Get SCITEX_DIR with precedence
+
+API Reference
+-------------
+
+.. automodule:: scitex.config
+ :members:
diff --git a/docs/sphinx/source/api/container.rst b/docs/sphinx/source/api/container.rst
new file mode 100644
index 000000000..6ac42573b
--- /dev/null
+++ b/docs/sphinx/source/api/container.rst
@@ -0,0 +1,7 @@
+container Module (``stx.container``)
+====================================
+
+.. automodule:: scitex.container
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/context.rst b/docs/sphinx/source/api/context.rst
new file mode 100644
index 000000000..7a7f5b8ff
--- /dev/null
+++ b/docs/sphinx/source/api/context.rst
@@ -0,0 +1,7 @@
+context Module (``stx.context``)
+================================
+
+.. automodule:: scitex.context
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/cv.rst b/docs/sphinx/source/api/cv.rst
new file mode 100644
index 000000000..e4b53ed96
--- /dev/null
+++ b/docs/sphinx/source/api/cv.rst
@@ -0,0 +1,7 @@
+cv Module (``stx.cv``)
+======================
+
+.. automodule:: scitex.cv
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/dataset.rst b/docs/sphinx/source/api/dataset.rst
new file mode 100644
index 000000000..8f600181a
--- /dev/null
+++ b/docs/sphinx/source/api/dataset.rst
@@ -0,0 +1,7 @@
+dataset Module (``stx.dataset``)
+================================
+
+.. automodule:: scitex.dataset
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/datetime.rst b/docs/sphinx/source/api/datetime.rst
new file mode 100644
index 000000000..78541bb81
--- /dev/null
+++ b/docs/sphinx/source/api/datetime.rst
@@ -0,0 +1,7 @@
+datetime Module (``stx.datetime``)
+==================================
+
+.. automodule:: scitex.datetime
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/db.rst b/docs/sphinx/source/api/db.rst
new file mode 100644
index 000000000..5945aa66d
--- /dev/null
+++ b/docs/sphinx/source/api/db.rst
@@ -0,0 +1,7 @@
+db Module (``stx.db``)
+======================
+
+.. automodule:: scitex.db
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/decorators.rst b/docs/sphinx/source/api/decorators.rst
new file mode 100644
index 000000000..b1a5f2fd0
--- /dev/null
+++ b/docs/sphinx/source/api/decorators.rst
@@ -0,0 +1,80 @@
+Decorators Module (``stx.decorators``)
+=======================================
+
+Function decorators for type conversion, batching, caching, and more.
+
+Quick Reference
+---------------
+
+.. code-block:: python
+
+ from scitex.decorators import torch_fn, batch_fn, cache_disk, timeout
+
+ @torch_fn
+ def process(x):
+ """Auto-converts inputs to torch tensors, outputs back."""
+ return x * 2
+
+ @batch_fn
+ def predict(data, batch_size=32):
+ """Process data in batches with progress bar."""
+ return model(data)
+
+ @cache_disk
+ def expensive_computation(params):
+ """Results cached to disk for reuse."""
+ return heavy_compute(params)
+
+ @timeout(seconds=30)
+ def risky_call():
+ """Raises TimeoutError if exceeds 30s."""
+ return external_api()
+
+Type Conversion
+---------------
+
+Auto-convert between data frameworks:
+
+- ``@torch_fn`` -- Inputs to PyTorch tensors, outputs back to original type
+- ``@numpy_fn`` -- Inputs to NumPy arrays
+- ``@pandas_fn`` -- Inputs to pandas objects
+- ``@xarray_fn`` -- Inputs to xarray objects
+
+Batch Processing
+----------------
+
+- ``@batch_fn`` -- Split input into batches with tqdm progress
+- ``@batch_numpy_fn`` -- NumPy conversion + batching
+- ``@batch_torch_fn`` -- PyTorch conversion + batching
+- ``@batch_pandas_fn`` -- Pandas conversion + batching
+
+Caching
+-------
+
+- ``@cache_mem`` -- In-memory function result caching
+- ``@cache_disk`` -- Persistent disk-based caching
+- ``@cache_disk_async`` -- Async disk caching
+
+Utilities
+---------
+
+- ``@deprecated(reason, forward_to)`` -- Mark functions as deprecated
+- ``@not_implemented`` -- Mark as not yet implemented
+- ``@timeout(seconds)`` -- Enforce execution time limits
+- ``@preserve_doc`` -- Preserve docstrings when wrapping
+
+Auto-Ordering
+-------------
+
+.. code-block:: python
+
+ from scitex.decorators import enable_auto_order
+
+ enable_auto_order()
+ # Now decorators are applied in optimal order regardless of code order
+
+API Reference
+-------------
+
+.. automodule:: scitex.decorators
+ :members:
diff --git a/docs/sphinx/source/api/dev.rst b/docs/sphinx/source/api/dev.rst
new file mode 100644
index 000000000..de05c5990
--- /dev/null
+++ b/docs/sphinx/source/api/dev.rst
@@ -0,0 +1,7 @@
+dev Module (``stx.dev``)
+========================
+
+.. automodule:: scitex.dev
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/diagram.rst b/docs/sphinx/source/api/diagram.rst
new file mode 100644
index 000000000..7e3a9f997
--- /dev/null
+++ b/docs/sphinx/source/api/diagram.rst
@@ -0,0 +1,99 @@
+Diagram Module (``stx.diagram``)
+=================================
+
+Paper-optimized diagram generation with Mermaid and Graphviz backends.
+
+Quick Reference
+---------------
+
+.. code-block:: python
+
+ from scitex.diagram import Diagram
+
+ # Create from Python
+ d = Diagram(type="workflow", title="Analysis Pipeline")
+ d.add_node("load", "Load Data", shape="stadium")
+ d.add_node("proc", "Process", shape="rounded", emphasis="primary")
+ d.add_node("save", "Save Results", shape="stadium", emphasis="success")
+ d.add_edge("load", "proc")
+ d.add_edge("proc", "save")
+
+ # Export
+ d.to_mermaid("pipeline.mmd")
+ d.to_graphviz("pipeline.dot")
+
+ # Or from YAML specification
+ d = Diagram.from_yaml("pipeline.diagram.yaml")
+
+YAML Specification
+------------------
+
+.. code-block:: yaml
+
+ type: workflow
+ title: SciTeX Analysis Pipeline
+
+ paper:
+ column: single # single or double
+ mode: publication # draft or publication
+ reading_direction: left_to_right
+
+ layout:
+ groups:
+ Input: [load, preprocess]
+ Analysis: [analyze, test]
+
+ nodes:
+ - id: load
+ label: Load Data
+ shape: stadium
+ - id: analyze
+ label: Statistical Test
+ shape: rounded
+ emphasis: primary
+
+ edges:
+ - from: load
+ to: analyze
+
+Node Shapes
+------------
+
+``box``, ``rounded``, ``stadium``, ``diamond``, ``circle``, ``codeblock``
+
+Node Emphasis
+-------------
+
+- ``normal`` -- Default (dark)
+- ``primary`` -- Key nodes (blue)
+- ``success`` -- Positive outcomes (green)
+- ``warning`` -- Issues (red)
+- ``muted`` -- Secondary (gray)
+
+Diagram Types
+-------------
+
+- ``workflow`` -- Left-to-right sequential processes
+- ``decision`` -- Top-to-bottom decision trees
+- ``pipeline`` -- Data pipeline stages
+- ``hierarchy`` -- Tree structures
+- ``comparison`` -- Side-by-side comparison
+
+Paper Modes
+-----------
+
+- **draft** -- Full arrows, medium spacing, all edges visible
+- **publication** -- Tight spacing, return edges invisible, optimized for column width
+
+Backends
+--------
+
+- **Mermaid** (``.mmd``) -- Web/markdown rendering
+- **Graphviz DOT** (``.dot``) -- Tighter layouts, render with ``dot -Tpng``
+- **YAML** (``.diagram.yaml``) -- Semantic spec, human/LLM-readable
+
+API Reference
+-------------
+
+.. automodule:: scitex.diagram
+ :members:
diff --git a/docs/sphinx/source/api/dict.rst b/docs/sphinx/source/api/dict.rst
new file mode 100644
index 000000000..7157aba95
--- /dev/null
+++ b/docs/sphinx/source/api/dict.rst
@@ -0,0 +1,7 @@
+dict Module (``stx.dict``)
+==========================
+
+.. automodule:: scitex.dict
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/dsp.rst b/docs/sphinx/source/api/dsp.rst
new file mode 100644
index 000000000..4e16f6f2d
--- /dev/null
+++ b/docs/sphinx/source/api/dsp.rst
@@ -0,0 +1,75 @@
+DSP Module (``stx.dsp``)
+========================
+
+Digital signal processing tools for filtering, spectral analysis,
+and time-frequency decomposition.
+
+Quick Reference
+---------------
+
+.. code-block:: python
+
+ import scitex as stx
+ import numpy as np
+
+ # Generate test signal
+ fs = 1000 # Hz
+ t = np.arange(0, 1, 1/fs)
+ signal = np.sin(2 * np.pi * 10 * t) + 0.5 * np.sin(2 * np.pi * 50 * t)
+
+ # Filtering
+ filtered = stx.dsp.filt.bandpass(signal, fs=fs, low=5, high=30)
+ low_pass = stx.dsp.filt.lowpass(signal, fs=fs, cutoff=20)
+ high_pass = stx.dsp.filt.highpass(signal, fs=fs, cutoff=5)
+
+ # Power spectral density
+ freqs, psd = stx.dsp.psd(signal, fs=fs)
+
+ # Band powers
+ powers = stx.dsp.band_powers(signal, fs=fs, bands={
+ "delta": (1, 4),
+ "theta": (4, 8),
+ "alpha": (8, 13),
+ "beta": (13, 30),
+ })
+
+ # Hilbert transform (analytic signal)
+ analytic = stx.dsp.hilbert(signal)
+ amplitude = np.abs(analytic)
+ phase = np.angle(analytic)
+
+ # Wavelet decomposition
+ coeffs = stx.dsp.wavelet(signal, fs=fs, freqs=np.arange(1, 50))
+
+Available Functions
+-------------------
+
+**Filtering** (``stx.dsp.filt``)
+
+- ``bandpass(signal, fs, low, high)``
+- ``lowpass(signal, fs, cutoff)``
+- ``highpass(signal, fs, cutoff)``
+- ``notch(signal, fs, freq)``
+
+**Spectral Analysis**
+
+- ``psd(signal, fs)`` -- Power spectral density
+- ``band_powers(signal, fs, bands)`` -- Power in frequency bands
+- ``wavelet(signal, fs, freqs)`` -- Continuous wavelet transform
+
+**Time-Frequency**
+
+- ``hilbert(signal)`` -- Analytic signal via Hilbert transform
+- ``pac(signal, fs)`` -- Phase-amplitude coupling
+
+**Utilities**
+
+- ``demo_sig(fs, duration)`` -- Generate demo signals for testing
+- ``crop(signal, start, end, fs)`` -- Crop signal to time range
+- ``detect_ripples(signal, fs)`` -- Detect sharp-wave ripples
+
+API Reference
+-------------
+
+.. automodule:: scitex.dsp
+ :members:
diff --git a/docs/sphinx/source/api/etc.rst b/docs/sphinx/source/api/etc.rst
new file mode 100644
index 000000000..b10d3a1f4
--- /dev/null
+++ b/docs/sphinx/source/api/etc.rst
@@ -0,0 +1,7 @@
+etc Module (``stx.etc``)
+========================
+
+.. automodule:: scitex.etc
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/events.rst b/docs/sphinx/source/api/events.rst
new file mode 100644
index 000000000..2039cfecd
--- /dev/null
+++ b/docs/sphinx/source/api/events.rst
@@ -0,0 +1,7 @@
+events Module (``stx.events``)
+==============================
+
+.. automodule:: scitex.events
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/gen.rst b/docs/sphinx/source/api/gen.rst
new file mode 100644
index 000000000..4a982c9fc
--- /dev/null
+++ b/docs/sphinx/source/api/gen.rst
@@ -0,0 +1,38 @@
+Gen Module (``stx.gen``)
+========================
+
+General utilities for path management, shell commands, and system operations.
+
+.. note::
+
+ Session management has moved to ``@stx.session`` (see :doc:`/core_concepts`).
+ The ``scitex.gen.start()`` / ``scitex.gen.close()`` pattern is deprecated.
+
+Quick Reference
+---------------
+
+.. code-block:: python
+
+ import scitex as stx
+
+ # Timestamped output directories
+ path = stx.gen.mk_spath("./results")
+ # → ./results/20260213_143022/
+
+ # Run shell commands
+ stx.gen.run("ls -la")
+
+ # Clipboard operations
+ stx.gen.copy("text to clipboard")
+ text = stx.gen.paste()
+
+ # String to valid path
+ stx.gen.title2path("My Experiment #1")
+ # → "my_experiment_1"
+
+API Reference
+-------------
+
+.. automodule:: scitex.gen
+ :members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/gists.rst b/docs/sphinx/source/api/gists.rst
new file mode 100644
index 000000000..b77c7eaf9
--- /dev/null
+++ b/docs/sphinx/source/api/gists.rst
@@ -0,0 +1,7 @@
+gists Module (``stx.gists``)
+============================
+
+.. automodule:: scitex.gists
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/git.rst b/docs/sphinx/source/api/git.rst
new file mode 100644
index 000000000..fcec156e3
--- /dev/null
+++ b/docs/sphinx/source/api/git.rst
@@ -0,0 +1,7 @@
+git Module (``stx.git``)
+========================
+
+.. automodule:: scitex.git
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/index.rst b/docs/sphinx/source/api/index.rst
index 6b7b42520..e8411e4f7 100644
--- a/docs/sphinx/source/api/index.rst
+++ b/docs/sphinx/source/api/index.rst
@@ -1,8 +1,113 @@
API Reference
=============
+SciTeX is organized into focused modules.
+All modules are accessible via ``import scitex as stx`` followed by ``stx.``.
+
.. toctree::
:maxdepth: 2
+ :caption: Core
- plt
+ session
io
+ config
+ logging
+ repro
+ clew
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Science & Analysis
+
+ stats
+ plt
+ dsp
+ diagram
+ canvas
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Literature & Writing
+
+ scholar
+ writer
+ notebook
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Machine Learning
+
+ ai
+ nn
+ torch
+ cv
+ benchmark
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Data & I/O
+
+ pd
+ db
+ dataset
+ schema
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Infrastructure
+
+ app
+ cloud
+ container
+ tunnel
+ cli
+ browser
+ capture
+ audio
+ notify
+ social
+
+.. toctree::
+ :maxdepth: 2
+ :caption: 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
+
+.. toctree::
+ :maxdepth: 2
+ :caption: Other
+
+ events
+ linter
+ project
diff --git a/docs/sphinx/source/api/introspect.rst b/docs/sphinx/source/api/introspect.rst
new file mode 100644
index 000000000..180c1dafb
--- /dev/null
+++ b/docs/sphinx/source/api/introspect.rst
@@ -0,0 +1,71 @@
+Introspect Module (``stx.introspect``)
+=======================================
+
+IPython-like code inspection for exploring Python packages.
+
+Quick Reference
+---------------
+
+.. code-block:: python
+
+ import scitex as stx
+
+ # Function signature (like IPython's func?)
+ stx.introspect.q("scitex.stats.test_ttest_ind")
+ # → name, signature, parameters, return type
+
+ # Full source code (like IPython's func??)
+ stx.introspect.qq("scitex.stats.test_ttest_ind")
+ # → complete source with line numbers
+
+ # List module members (like enhanced dir())
+ stx.introspect.dir("scitex.plt", filter="public", kind="functions")
+
+ # Recursive API tree
+ df = stx.introspect.list_api("scitex", max_depth=2)
+
+IPython-Style Shortcuts
+-----------------------
+
+- ``q(dotted_path)`` -- Signature and parameters (like ``func?``)
+- ``qq(dotted_path)`` -- Full source code (like ``func??``)
+- ``dir(dotted_path, filter, kind)`` -- List members with filtering
+
+Filters: ``"public"``, ``"private"``, ``"dunder"``, ``"all"``
+
+Kinds: ``"functions"``, ``"classes"``, ``"data"``, ``"modules"``
+
+Documentation
+-------------
+
+- ``get_docstring(path, format)`` -- Extract docstrings (``"raw"``, ``"parsed"``, ``"summary"``)
+- ``get_exports(path)`` -- Get ``__all__`` exports
+- ``find_examples(path)`` -- Find usage examples in tests/examples
+
+Type Analysis
+-------------
+
+- ``get_type_hints_detailed(path)`` -- Full type annotation analysis
+- ``get_class_hierarchy(path)`` -- Inheritance tree (MRO + subclasses)
+- ``get_class_annotations(path)`` -- Class variable annotations
+
+Code Analysis
+-------------
+
+- ``get_imports(path, categorize)`` -- All imports (AST-based, grouped by stdlib/third-party/local)
+- ``get_dependencies(path, recursive)`` -- Module dependency tree
+- ``get_call_graph(path, max_depth)`` -- Function call graph (with timeout protection)
+
+API Tree
+--------
+
+.. code-block:: python
+
+ # Generate full module tree as DataFrame
+ df = stx.introspect.list_api("scitex", max_depth=3, docstring=True)
+
+API Reference
+-------------
+
+.. automodule:: scitex.introspect
+ :members:
diff --git a/docs/sphinx/source/api/linalg.rst b/docs/sphinx/source/api/linalg.rst
new file mode 100644
index 000000000..2f7ce9a85
--- /dev/null
+++ b/docs/sphinx/source/api/linalg.rst
@@ -0,0 +1,7 @@
+linalg Module (``stx.linalg``)
+==============================
+
+.. automodule:: scitex.linalg
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/linter.rst b/docs/sphinx/source/api/linter.rst
new file mode 100644
index 000000000..e061949ff
--- /dev/null
+++ b/docs/sphinx/source/api/linter.rst
@@ -0,0 +1,133 @@
+Linter Module (``stx.linter``)
+===============================
+
+AST-based Python linter enforcing SciTeX conventions for reproducible
+scientific code.
+
+.. note::
+
+ ``stx.linter`` wraps the standalone
+ `scitex-linter `_ package.
+ Install with: ``pip install scitex-linter``.
+
+Quick Reference
+---------------
+
+.. code-block:: bash
+
+ # Check a file
+ scitex linter check my_script.py
+
+ # Check with specific severity
+ scitex linter check my_script.py --severity warning
+
+ # List all rules
+ scitex linter list-rules
+
+ # Filter by category
+ scitex linter list-rules --category session
+
+.. code-block:: python
+
+ from scitex_linter import check_file, list_rules
+
+ # Check a file
+ results = check_file("my_script.py")
+
+ # List available rules
+ rules = list_rules()
+
+Rule Categories
+---------------
+
+45 rules across 8 categories:
+
+.. list-table::
+ :header-rows: 1
+ :widths: 15 25 60
+
+ * - Prefix
+ - Category
+ - Examples
+ * - ``STX-S``
+ - **Session**
+ - Missing ``@stx.session``, missing ``if __name__`` guard, missing return
+ * - ``STX-I``
+ - **Import**
+ - Using ``import mngs`` instead of ``import scitex``, bare ``import numpy``
+ * - ``STX-IO``
+ - **I/O**
+ - Using ``open()`` instead of ``stx.io``, hardcoded paths
+ * - ``STX-P``
+ - **Plotting**
+ - Using ``plt.show()`` instead of ``stx.io.save``, missing ``set_xyt``
+ * - ``STX-ST``
+ - **Statistics**
+ - Using ``scipy.stats`` directly instead of ``stx.stats``
+ * - ``STX-PA``
+ - **Path**
+ - Hardcoded absolute paths, missing ``stx.gen.mk_spath``
+ * - ``STX-FM``
+ - **Format**
+ - Non-snake_case names, magic numbers, missing docstrings
+
+Severity Levels
+---------------
+
+- **error** -- Must fix (breaks reproducibility or correctness)
+- **warning** -- Should fix (best practice violations)
+- **info** -- Suggestions for improvement
+
+Interfaces
+----------
+
+The linter is available through multiple interfaces:
+
+**CLI:**
+
+.. code-block:: bash
+
+ scitex linter check script.py
+ scitex-linter check script.py # standalone CLI
+
+**Python API:**
+
+.. code-block:: python
+
+ from scitex_linter import check_file, check_source
+
+ results = check_file("script.py")
+ results = check_source("import numpy as np\n...")
+
+**Flake8 Plugin:**
+
+.. code-block:: bash
+
+ flake8 --select=STX script.py
+
+**MCP Tools:**
+
+.. code-block:: python
+
+ # Available as MCP tools for AI agents
+ linter_check(path="script.py", severity="warning")
+ linter_list_rules(category="session")
+ linter_check_source(source="...", filepath="")
+
+Configuration
+-------------
+
+Configure via ``pyproject.toml``:
+
+.. code-block:: toml
+
+ [tool.scitex-linter]
+ severity = "warning"
+ ignore = ["STX-S002", "STX-FM001"]
+
+API Reference
+-------------
+
+.. automodule:: scitex.linter
+ :members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/logging.rst b/docs/sphinx/source/api/logging.rst
new file mode 100644
index 000000000..f8a5512db
--- /dev/null
+++ b/docs/sphinx/source/api/logging.rst
@@ -0,0 +1,108 @@
+Logging Module (``stx.logging``)
+=================================
+
+Unified logging with file/console output, custom warnings, exception
+hierarchy, and stream redirection.
+
+Quick Reference
+---------------
+
+.. code-block:: python
+
+ import scitex as stx
+ from scitex import logging
+
+ # Get a logger
+ logger = logging.getLogger(__name__)
+ logger.info("Processing data")
+ logger.success("Analysis complete") # Custom level (31)
+ logger.fail("Model diverged") # Custom level (35)
+
+ # Configure globally
+ logging.configure(level="DEBUG", log_file="./run.log")
+ logging.set_level("WARNING")
+
+ # Temporary file logging
+ with logging.log_to_file("analysis.log"):
+ logger.info("This goes to both console and file")
+
+ # Warnings
+ logging.warn("Large dataset", category=logging.PerformanceWarning)
+ logging.warn_deprecated("old_func", "new_func", version="3.0")
+ logging.filterwarnings("ignore", category=logging.UnitWarning)
+
+Log Levels
+----------
+
+.. list-table::
+ :header-rows: 1
+ :widths: 20 15 65
+
+ * - Level
+ - Value
+ - Description
+ * - ``DEBUG``
+ - 10
+ - Detailed diagnostic information
+ * - ``INFO``
+ - 20
+ - General operational messages
+ * - ``WARNING``
+ - 30
+ - Something unexpected but not fatal
+ * - ``SUCCESS``
+ - 31
+ - Custom: operation completed successfully
+ * - ``FAIL``
+ - 35
+ - Custom: operation failed (non-fatal)
+ * - ``ERROR``
+ - 40
+ - Serious problem
+ * - ``CRITICAL``
+ - 50
+ - Program may not continue
+
+Warning Categories
+------------------
+
+- ``SciTeXWarning`` -- Base warning class
+- ``UnitWarning`` -- SI unit convention issues
+- ``StyleWarning`` -- Formatting issues
+- ``SciTeXDeprecationWarning`` -- Deprecated features
+- ``PerformanceWarning`` -- Performance issues
+- ``DataLossWarning`` -- Potential data loss
+
+Exception Hierarchy
+-------------------
+
+All inherit from ``SciTeXError``:
+
+- **I/O**: ``IOError``, ``FileFormatError``, ``SaveError``, ``LoadError``
+- **Config**: ``ConfigurationError``, ``ConfigFileNotFoundError``, ``ConfigKeyError``
+- **Path**: ``PathError``, ``InvalidPathError``, ``PathNotFoundError``
+- **Data**: ``DataError``, ``ShapeError``, ``DTypeError``
+- **Plotting**: ``PlottingError``, ``FigureNotFoundError``, ``AxisError``
+- **Stats**: ``StatsError``, ``TestError``
+- **Scholar**: ``ScholarError``, ``SearchError``, ``PDFDownloadError``, ``DOIResolutionError``
+- **NN**: ``NNError``, ``ModelError``
+- **Template**: ``TemplateError``, ``TemplateViolationError``
+
+Stream Redirection
+------------------
+
+.. code-block:: python
+
+ from scitex.logging import tee
+ import sys
+
+ # Redirect stdout/stderr to log files
+ sys.stdout, sys.stderr = tee(sys, sdir="./output")
+
+The ``@stx.session`` decorator handles this automatically.
+
+API Reference
+-------------
+
+.. automodule:: scitex.logging
+ :members:
diff --git a/docs/sphinx/source/api/media.rst b/docs/sphinx/source/api/media.rst
new file mode 100644
index 000000000..34e386c28
--- /dev/null
+++ b/docs/sphinx/source/api/media.rst
@@ -0,0 +1,7 @@
+media Module (``stx.media``)
+============================
+
+.. automodule:: scitex.media
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/module.rst b/docs/sphinx/source/api/module.rst
new file mode 100644
index 000000000..6ba06a686
--- /dev/null
+++ b/docs/sphinx/source/api/module.rst
@@ -0,0 +1,7 @@
+module Module (``stx.module``)
+==============================
+
+.. automodule:: scitex.module
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/msword.rst b/docs/sphinx/source/api/msword.rst
new file mode 100644
index 000000000..a48391fae
--- /dev/null
+++ b/docs/sphinx/source/api/msword.rst
@@ -0,0 +1,7 @@
+msword Module (``stx.msword``)
+==============================
+
+.. automodule:: scitex.msword
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/nn.rst b/docs/sphinx/source/api/nn.rst
new file mode 100644
index 000000000..a4f886c7d
--- /dev/null
+++ b/docs/sphinx/source/api/nn.rst
@@ -0,0 +1,80 @@
+NN Module (``stx.nn``)
+======================
+
+PyTorch neural network layers for signal processing and neuroscience
+applications.
+
+Quick Reference
+---------------
+
+.. code-block:: python
+
+ import scitex as stx
+ import torch
+
+ # Bandpass filtering as a differentiable layer
+ bpf = stx.nn.BandPassFilter(
+ bands=[[4, 8], [8, 13], [13, 30]], # theta, alpha, beta
+ fs=256, seq_len=1024
+ )
+ filtered = bpf(signal) # (batch, channels, 3, 1024)
+
+ # Power spectral density
+ psd = stx.nn.PSD(sample_rate=256)
+ power, freqs = psd(signal)
+
+ # Phase-amplitude coupling
+ pac = stx.nn.PAC(seq_len=1024, fs=256)
+ coupling = pac(signal)
+
+Signal Processing Layers
+-------------------------
+
+**Filtering** (all differentiable):
+
+- ``BandPassFilter(bands, fs, seq_len)`` -- Multi-band frequency filtering
+- ``BandStopFilter(bands, fs, seq_len)`` -- Reject frequency bands
+- ``LowPassFilter(cutoffs_hz, fs, seq_len)`` -- Anti-aliasing / smoothing
+- ``HighPassFilter(cutoffs_hz, fs, seq_len)`` -- High-frequency emphasis
+- ``GaussianFilter(sigma)`` -- Gaussian kernel smoothing
+- ``DifferentiableBandPassFilter(...)`` -- Learnable bandpass parameters
+
+**Spectral Analysis**:
+
+- ``Spectrogram(sampling_rate, n_fft)`` -- STFT-based magnitude spectrogram
+- ``PSD(sample_rate, prob)`` -- FFT-based power spectral density
+- ``Wavelet(samp_rate, freq_scale)`` -- Continuous wavelet transform
+
+**Phase & Coupling**:
+
+- ``Hilbert(seq_len)`` -- Analytic signal (phase + amplitude)
+- ``ModulationIndex(n_bins)`` -- Phase-amplitude coupling metric
+- ``PAC(seq_len, fs, ...)`` -- Complete PAC analysis pipeline
+
+Channel Manipulation
+--------------------
+
+- ``SwapChannels()`` -- Random channel permutation (training augmentation)
+- ``DropoutChannels(dropout)`` -- Drop entire channels
+- ``ChannelGainChanger(n_chs)`` -- Learnable per-channel scaling
+- ``FreqGainChanger(n_bands, fs)`` -- Learnable per-band scaling
+
+Attention & Shape
+-----------------
+
+- ``SpatialAttention(n_chs_in)`` -- Adaptive channel weighting
+- ``TransposeLayer(axis1, axis2)`` -- Dimension permutation
+- ``AxiswiseDropout(dropout_prob, dim)`` -- Drop entire axis
+
+Architectures
+-------------
+
+- ``ResNet1D(n_chs, n_out, n_blks)`` -- 1D residual network
+- ``BNet`` / ``BNet_Res`` -- Multi-head EEG classifier
+- ``MNet1000`` -- 2D CNN feature extractor
+
+API Reference
+-------------
+
+.. automodule:: scitex.nn
+ :members:
diff --git a/docs/sphinx/source/api/notebook.rst b/docs/sphinx/source/api/notebook.rst
new file mode 100644
index 000000000..b66a0a1c0
--- /dev/null
+++ b/docs/sphinx/source/api/notebook.rst
@@ -0,0 +1,7 @@
+notebook Module (``stx.notebook``)
+==================================
+
+.. automodule:: scitex.notebook
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/notify.rst b/docs/sphinx/source/api/notify.rst
new file mode 100644
index 000000000..4dfc60e3a
--- /dev/null
+++ b/docs/sphinx/source/api/notify.rst
@@ -0,0 +1,7 @@
+notify Module (``stx.notify``)
+==============================
+
+.. automodule:: scitex.notify
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/os.rst b/docs/sphinx/source/api/os.rst
new file mode 100644
index 000000000..be2fda313
--- /dev/null
+++ b/docs/sphinx/source/api/os.rst
@@ -0,0 +1,7 @@
+os Module (``stx.os``)
+======================
+
+.. automodule:: scitex.os
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/parallel.rst b/docs/sphinx/source/api/parallel.rst
new file mode 100644
index 000000000..620d8333d
--- /dev/null
+++ b/docs/sphinx/source/api/parallel.rst
@@ -0,0 +1,7 @@
+parallel Module (``stx.parallel``)
+==================================
+
+.. automodule:: scitex.parallel
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/path.rst b/docs/sphinx/source/api/path.rst
new file mode 100644
index 000000000..672ff6967
--- /dev/null
+++ b/docs/sphinx/source/api/path.rst
@@ -0,0 +1,7 @@
+path Module (``stx.path``)
+==========================
+
+.. automodule:: scitex.path
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/pd.rst b/docs/sphinx/source/api/pd.rst
new file mode 100644
index 000000000..9a34275d0
--- /dev/null
+++ b/docs/sphinx/source/api/pd.rst
@@ -0,0 +1,46 @@
+PD Module (``stx.pd``)
+======================
+
+Pandas DataFrame helper functions for common transformations.
+
+Quick Reference
+---------------
+
+.. code-block:: python
+
+ import scitex as stx
+ import pandas as pd
+
+ df = pd.DataFrame({
+ "subject": ["A", "A", "B", "B"],
+ "condition": ["ctrl", "exp", "ctrl", "exp"],
+ "score": [10, 15, 12, 18],
+ })
+
+ # Find individual (unique) values
+ subjects = stx.pd.find_indi(df, "subject")
+
+ # Convert to long format
+ melted = stx.pd.melt_cols(df, id_vars=["subject"])
+
+ # Merge columns
+ merged = stx.pd.merge_cols(df, cols=["subject", "condition"], sep="_")
+
+ # Force to DataFrame
+ stx.pd.force_df({"a": [1, 2], "b": [3, 4]})
+
+Available Functions
+-------------------
+
+- ``find_indi(df, col)`` -- Find unique individual identifiers
+- ``find_pval(df)`` -- Find p-value columns in a DataFrame
+- ``force_df(data)`` -- Convert any data to a DataFrame
+- ``melt_cols(df, id_vars)`` -- Melt columns to long format
+- ``merge_cols(df, cols, sep)`` -- Merge multiple columns into one
+- ``to_xyz(df, x, y, z)`` -- Reshape to x, y, z pivot format
+
+API Reference
+-------------
+
+.. automodule:: scitex.pd
+ :members:
diff --git a/docs/sphinx/source/api/project.rst b/docs/sphinx/source/api/project.rst
new file mode 100644
index 000000000..b0440a59f
--- /dev/null
+++ b/docs/sphinx/source/api/project.rst
@@ -0,0 +1,7 @@
+project Module (``stx.project``)
+================================
+
+.. automodule:: scitex.project
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/repro.rst b/docs/sphinx/source/api/repro.rst
new file mode 100644
index 000000000..0e8dc4fea
--- /dev/null
+++ b/docs/sphinx/source/api/repro.rst
@@ -0,0 +1,71 @@
+Repro Module (``stx.repro``)
+============================
+
+Reproducibility utilities: random state management, ID generation,
+timestamps, and array hashing.
+
+Quick Reference
+---------------
+
+.. code-block:: python
+
+ import scitex as stx
+
+ # Fix all random seeds (numpy, torch, random, ...)
+ rng = stx.repro.get() # Global manager (seed=42)
+ rng = stx.repro.reset(seed=123) # Reset with new seed
+
+ # Named generators for deterministic results
+ data_gen = rng.get_np_generator("data")
+ data = data_gen.random(100) # Same seed+name = same result
+
+ # Unique identifiers
+ stx.repro.gen_id()
+ # → "2026Y-02M-13D-14h30m15s_a3Bc9xY2"
+
+ stx.repro.gen_timestamp()
+ # → "2026-0213-1430"
+
+ # Verify reproducibility
+ rng.verify(data, "train_data") # First: caches hash
+ rng.verify(data, "train_data") # Later: verifies match
+
+RandomStateManager
+------------------
+
+Central class for managing random states across libraries.
+
+.. code-block:: python
+
+ rng = stx.repro.RandomStateManager(seed=42)
+
+ # Named generators (same name + seed = deterministic)
+ np_gen = rng.get_np_generator("experiment")
+ torch_gen = rng.get_torch_generator("model")
+
+ # Checkpoint and restore
+ rng.checkpoint("before_training")
+ rng.restore("before_training.pkl")
+
+ # Temporary seed change
+ with rng.temporary_seed(999):
+ noise = rng.get_np_generator("noise").random(10)
+
+Automatically fixes seeds for: ``random``, ``numpy``, ``torch`` (+ CUDA),
+``tensorflow``, ``jax``.
+
+Available Functions
+-------------------
+
+- ``get(verbose)`` -- Get or create global RandomStateManager singleton
+- ``reset(seed, verbose)`` -- Reset global instance with new seed
+- ``fix_seeds(seed, ...)`` -- Legacy function (use RandomStateManager instead)
+- ``gen_id(time_format, N)`` -- Generate unique timestamp + random ID
+- ``gen_timestamp()`` -- Generate timestamp string for file naming
+- ``hash_array(array_data)`` -- SHA256 hash of numpy array (16 chars)
+
+API Reference
+-------------
+
+.. automodule:: scitex.repro
+ :members:
diff --git a/docs/sphinx/source/api/resource.rst b/docs/sphinx/source/api/resource.rst
new file mode 100644
index 000000000..d4fbcc001
--- /dev/null
+++ b/docs/sphinx/source/api/resource.rst
@@ -0,0 +1,7 @@
+resource Module (``stx.resource``)
+==================================
+
+.. automodule:: scitex.resource
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/rng.rst b/docs/sphinx/source/api/rng.rst
new file mode 100644
index 000000000..a6ab74def
--- /dev/null
+++ b/docs/sphinx/source/api/rng.rst
@@ -0,0 +1,7 @@
+rng Module (``stx.rng``)
+========================
+
+.. automodule:: scitex.rng
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/schema.rst b/docs/sphinx/source/api/schema.rst
new file mode 100644
index 000000000..919582dbf
--- /dev/null
+++ b/docs/sphinx/source/api/schema.rst
@@ -0,0 +1,7 @@
+schema Module (``stx.schema``)
+==============================
+
+.. automodule:: scitex.schema
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/scholar.rst b/docs/sphinx/source/api/scholar.rst
new file mode 100644
index 000000000..2be71119e
--- /dev/null
+++ b/docs/sphinx/source/api/scholar.rst
@@ -0,0 +1,133 @@
+Scholar Module (``stx.scholar``)
+=================================
+
+Literature management: search papers, download PDFs, enrich BibTeX,
+and organize a local library across multiple projects.
+
+Quick Reference
+---------------
+
+.. code-block:: python
+
+ from scitex.scholar import Scholar
+
+ scholar = Scholar(project="my_research")
+
+ # Load and enrich BibTeX
+ papers = scholar.load_bibtex("references.bib")
+ enriched = scholar.enrich_papers(papers)
+ # Adds: DOIs, abstracts, citation counts, impact factors
+
+ # Save to library and export
+ scholar.save_papers_to_library(enriched)
+ scholar.save_papers_as_bibtex(enriched, "enriched.bib")
+
+ # Search your library
+ results = scholar.search_library("neural oscillations")
+
+ # Download PDFs
+ scholar.download_pdfs(dois, output_dir)
+
+CLI Usage
+---------
+
+.. code-block:: bash
+
+ # Full pipeline from BibTeX
+ scitex scholar bibtex refs.bib --project myresearch --num-workers 8
+
+ # Search papers
+ scitex scholar search "deep learning EEG"
+
+ # Download PDFs
+ scitex scholar download --doi 10.1038/nature12373
+
+ # Institutional authentication
+ scitex scholar auth --method openathens
+ scitex scholar auth --method shibboleth --institution "MIT"
+
+Data Sources
+------------
+
+Searches and enriches from:
+
+- **CrossRef** (167M+ papers) -- DOI resolution, citation counts
+- **Semantic Scholar** -- Abstracts, references, influence scores
+- **PubMed** -- Biomedical literature
+- **arXiv** -- Preprints
+- **OpenAlex** (284M+ works) -- Open metadata
+
+Key Classes
+-----------
+
+- ``Scholar`` -- Main entry point (search, enrich, download, organize)
+- ``Paper`` -- Type-safe metadata container (Pydantic model)
+- ``Papers`` -- Collection with filtering, sorting, and export
+- ``ScholarConfig`` -- YAML-based configuration
+- ``ScholarLibrary`` -- Local library storage and caching
+
+Paper Metadata
+--------------
+
+Each ``Paper`` contains structured metadata sections:
+
+.. code-block:: python
+
+ paper.metadata.basic # title, authors, year, abstract, keywords
+ paper.metadata.id # DOI, arXiv, PMID, Semantic Scholar ID
+ paper.metadata.publication # journal, impact factor, volume, issue
+ paper.metadata.citation_count # total + yearly breakdown (2015--2024)
+ paper.metadata.url # DOI URL, publisher, arXiv, PDFs
+ paper.metadata.access # open access status, license
+
+Filtering and Sorting
+---------------------
+
+.. code-block:: python
+
+ # Criteria-based filtering
+ recent = papers.filter(year_min=2020, has_doi=True)
+ elite = papers.filter(min_impact_factor=10, min_citations=500)
+
+ # Lambda filtering
+ custom = papers.filter(lambda p: "EEG" in (p.metadata.basic.title or ""))
+
+ # Sorting
+ papers.sort_by("year", reverse=True)
+ papers.sort_by("citation_count", reverse=True)
+
+ # Chaining
+ top_recent = papers.filter(year_min=2020).sort_by("citation_count", reverse=True)
+
+Project Organization
+--------------------
+
+.. code-block:: python
+
+ scholar = Scholar(project="review_paper")
+ scholar.list_projects()
+ papers = scholar.load_project()
+
+ # Export to multiple formats
+ scholar.save_papers_as_bibtex(papers, "output.bib")
+ papers.to_dataframe() # pandas DataFrame
+
+Storage Architecture
+--------------------
+
+.. code-block:: text
+
+ ~/.scitex/scholar/library/
+ +-- MASTER/ # Centralized master storage
+ | +-- 8DIGIT01/ # Hash-based unique ID from DOI
+ | | +-- metadata.json
+ | | +-- paper.pdf
+ +-- project_name/ # Project-specific symlinks
+ +-- Author-Year-Journal -> ../MASTER/8DIGIT01
+
+API Reference
+-------------
+
+.. automodule:: scitex.scholar
+ :members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/security.rst b/docs/sphinx/source/api/security.rst
new file mode 100644
index 000000000..232a5da7f
--- /dev/null
+++ b/docs/sphinx/source/api/security.rst
@@ -0,0 +1,7 @@
+security Module (``stx.security``)
+==================================
+
+.. automodule:: scitex.security
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/session.rst b/docs/sphinx/source/api/session.rst
new file mode 100644
index 000000000..8f16f4670
--- /dev/null
+++ b/docs/sphinx/source/api/session.rst
@@ -0,0 +1,213 @@
+Session Decorator (``@stx.session``)
+=====================================
+
+The ``@stx.session`` decorator is the primary entry point for SciTeX
+scripts. It wraps a function to provide automatic CLI generation,
+output directory management, configuration injection, and provenance tracking.
+
+Basic Usage
+-----------
+
+.. code-block:: python
+
+ import scitex as stx
+
+ @stx.session
+ def main(
+ data_path="data.csv", # CLI: --data-path data.csv
+ threshold=0.5, # CLI: --threshold 0.7
+ CONFIG=stx.INJECTED, # Auto-injected session config
+ plt=stx.INJECTED, # Pre-configured matplotlib
+ logger=stx.INJECTED, # Session logger
+ ):
+ """Analyze experimental data."""
+ data = stx.io.load(data_path)
+ result = process(data, threshold)
+ stx.io.save(result, "output.csv")
+ return 0 # exit code (0 = success)
+
+ if __name__ == "__main__":
+ main() # No arguments triggers CLI mode
+
+Run from the command line:
+
+.. code-block:: bash
+
+ python my_script.py --data-path experiment.csv --threshold 0.3
+ python my_script.py --help # Shows all parameters with defaults
+
+How It Works
+------------
+
+.. image:: ../_static/session_lifecycle.png
+ :width: 60%
+ :align: center
+ :alt: Session lifecycle: main() → Parse CLI → Create dir → Load config → Execute → SUCCESS or ERROR
+
+When ``main()`` is called **without arguments**, the decorator:
+
+1. **Parses CLI arguments** from the function signature (type hints and defaults become ``argparse`` options)
+2. **Creates a session directory** under ``script_out/RUNNING/{session_id}/``
+3. **Loads configuration** from ``./config/*.yaml`` files into ``CONFIG``
+4. **Injects globals** (``CONFIG``, ``plt``, ``COLORS``, ``logger``, ``rngg``) into the function
+5. **Redirects stdout/stderr** to log files
+6. **Executes the function** with parsed arguments
+7. **Moves output** from ``RUNNING/`` to ``FINISHED_SUCCESS/`` (or ``FINISHED_ERROR/``)
+
+When called **with arguments** (e.g., ``main(data_path="x.csv")``), the decorator
+is bypassed and the function runs directly -- useful for testing and notebooks.
+
+Output Directory Structure
+--------------------------
+
+Each run produces a self-contained output directory:
+
+.. code-block:: text
+
+ my_script_out/
+ +-- FINISHED_SUCCESS/
+ | +-- 2026Y-02M-13D-14h30m15s_Z5MR/
+ | +-- CONFIGS/
+ | | +-- CONFIG.yaml # Frozen configuration
+ | | +-- CONFIG.pkl # Pickled config
+ | +-- logs/
+ | | +-- stdout.log # Captured stdout
+ | | +-- stderr.log # Captured stderr
+ | +-- output.csv # Your saved files
+ | +-- sine.png # Your saved figures
+ | +-- sine.csv # Auto-exported figure data
+ +-- FINISHED_ERROR/
+ | +-- ... # Runs that returned non-zero
+ +-- RUNNING/
+ +-- ... # Currently active sessions
+
+The session ID format is ``YYYY-MM-DD-HH:MM:SS_XXXX`` where ``XXXX`` is
+a random 4-character suffix for uniqueness.
+
+Injected Parameters
+-------------------
+
+Use ``stx.INJECTED`` as the default value to receive auto-injected objects:
+
+.. list-table::
+ :header-rows: 1
+ :widths: 20 20 60
+
+ * - Parameter Name
+ - Type
+ - Description
+ * - ``CONFIG``
+ - ``DotDict``
+ - Session config with ``ID``, ``SDIR_RUN``, ``FILE``, ``ARGS``, plus all ``./config/*.yaml`` values
+ * - ``plt``
+ - module
+ - ``matplotlib.pyplot`` configured for the session (Agg backend, style settings)
+ * - ``COLORS``
+ - ``DotDict``
+ - Color palette for consistent plotting
+ * - ``logger``
+ - Logger
+ - SciTeX logger writing to session log files
+ * - ``rngg``
+ - ``RandomStateManager``
+ - Reproducibility manager (seeds fixed by default)
+
+Only request the parameters you need:
+
+.. code-block:: python
+
+ @stx.session
+ def main(n=100, CONFIG=stx.INJECTED):
+ """Minimal example -- only CONFIG injected."""
+ print(f"Session ID: {CONFIG.ID}")
+ print(f"Output dir: {CONFIG.SDIR_RUN}")
+ return 0
+
+CONFIG Object
+-------------
+
+The injected ``CONFIG`` is a ``DotDict`` supporting both dictionary and
+dot-notation access:
+
+.. code-block:: python
+
+ CONFIG["MODEL"]["hidden_size"] # dict-style
+ CONFIG.MODEL.hidden_size # dot-style (equivalent)
+
+It contains:
+
+.. code-block:: python
+
+ CONFIG.ID # "2026Y-02M-13D-14h30m15s_Z5MR"
+ CONFIG.PID # Process ID
+ CONFIG.FILE # Path to the script
+ CONFIG.SDIR_OUT # Base output directory
+ CONFIG.SDIR_RUN # Current session's output directory
+ CONFIG.START_DATETIME # When the session started
+ CONFIG.ARGS # Parsed CLI arguments as dict
+ CONFIG.EXIT_STATUS # 0 (success), 1 (error), or None
+
+Any YAML files in ``./config/`` are merged into CONFIG:
+
+.. code-block:: yaml
+
+ # ./config/EXPERIMENT.yaml
+ learning_rate: 0.001
+ batch_size: 32
+
+.. code-block:: python
+
+ # Accessible as:
+ CONFIG.EXPERIMENT.learning_rate # 0.001
+ CONFIG.EXPERIMENT.batch_size # 32
+
+Decorator Options
+-----------------
+
+.. code-block:: python
+
+ @stx.session(verbose=True, agg=False, notify=True, sdir_suffix="v2")
+ def main(...):
+ ...
+
+.. list-table::
+ :header-rows: 1
+ :widths: 20 15 15 50
+
+ * - Option
+ - Type
+ - Default
+ - Description
+ * - ``verbose``
+ - bool
+ - ``False``
+ - Enable verbose logging
+ * - ``agg``
+ - bool
+ - ``True``
+ - Use matplotlib Agg backend (set ``False`` for interactive plots)
+ * - ``notify``
+ - bool
+ - ``False``
+ - Send notification when session completes
+ * - ``sdir_suffix``
+ - str
+ - ``None``
+ - Append suffix to output directory name
+
+Best Practices
+--------------
+
+1. **One session per script** -- each ``.py`` file should have one ``@stx.session`` function
+2. **Return 0 for success** -- the return value becomes the exit status
+3. **Save outputs with** ``stx.io.save`` -- files go into the session directory and are provenance-tracked
+4. **Put config in YAML** -- use ``./config/*.yaml`` instead of hardcoding parameters
+5. **Use** ``stx.repro.fix_seeds()`` -- already called by default via ``rngg``
+
+API Reference
+-------------
+
+.. automodule:: scitex.session
+ :members:
+ :no-undoc-members:
+ :exclude-members: _InjectedSentinel
diff --git a/docs/sphinx/source/api/sh.rst b/docs/sphinx/source/api/sh.rst
new file mode 100644
index 000000000..7c4694af6
--- /dev/null
+++ b/docs/sphinx/source/api/sh.rst
@@ -0,0 +1,7 @@
+sh Module (``stx.sh``)
+======================
+
+.. automodule:: scitex.sh
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/social.rst b/docs/sphinx/source/api/social.rst
new file mode 100644
index 000000000..cc82af401
--- /dev/null
+++ b/docs/sphinx/source/api/social.rst
@@ -0,0 +1,7 @@
+social Module (``stx.social``)
+==============================
+
+.. automodule:: scitex.social
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/stats.rst b/docs/sphinx/source/api/stats.rst
new file mode 100644
index 000000000..17ca488dd
--- /dev/null
+++ b/docs/sphinx/source/api/stats.rst
@@ -0,0 +1,153 @@
+Stats Module (``stx.stats``)
+============================
+
+23 statistical tests with effect sizes, confidence intervals, and
+publication-ready formatting.
+
+Quick Reference
+---------------
+
+.. code-block:: python
+
+ import scitex as stx
+ import numpy as np
+
+ g1 = np.random.normal(0, 1, 50)
+ g2 = np.random.normal(0.5, 1, 50)
+
+ # Run a test
+ result = stx.stats.test_ttest_ind(g1, g2)
+
+ # Result is a flat dict with all details
+ print(result["statistic"]) # t-statistic
+ print(result["pvalue"]) # p-value
+ print(result["effect_size"]) # Cohen's d
+ print(result["stars"]) # Significance stars
+
+ # Get as DataFrame or LaTeX
+ df = stx.stats.test_ttest_ind(g1, g2, return_as="dataframe")
+ tex = stx.stats.test_ttest_ind(g1, g2, return_as="latex")
+
+Available Tests
+---------------
+
+**Parametric**
+
+- ``test_ttest_1samp(data, popmean)`` -- One-sample t-test
+- ``test_ttest_ind(g1, g2)`` -- Independent two-sample t-test
+- ``test_ttest_rel(g1, g2)`` -- Paired t-test
+- ``test_anova(*groups)`` -- One-way ANOVA
+- ``test_anova_2way(data, factor1, factor2)`` -- Two-way ANOVA
+- ``test_anova_rm(data, groups)`` -- Repeated measures ANOVA
+
+**Non-parametric**
+
+- ``test_mannwhitneyu(g1, g2)`` -- Mann-Whitney U test
+- ``test_wilcoxon(g1, g2)`` -- Wilcoxon signed-rank test
+- ``test_kruskal(*groups)`` -- Kruskal-Wallis H test
+- ``test_friedman(*groups)`` -- Friedman test
+- ``test_brunner_munzel(g1, g2)`` -- Brunner-Munzel test
+
+**Correlation**
+
+- ``test_pearson(x, y)`` -- Pearson correlation
+- ``test_spearman(x, y)`` -- Spearman rank correlation
+- ``test_kendall(x, y)`` -- Kendall tau correlation
+- ``test_theilsen(x, y)`` -- Theil-Sen robust regression
+
+**Categorical**
+
+- ``test_chi2(observed)`` -- Chi-squared test
+- ``test_fisher(table)`` -- Fisher's exact test
+- ``test_mcnemar(table)`` -- McNemar test
+- ``test_cochran_q(*groups)`` -- Cochran's Q test
+
+**Normality**
+
+- ``test_shapiro(data)`` -- Shapiro-Wilk test
+- ``test_ks_1samp(data)`` -- One-sample Kolmogorov-Smirnov test
+- ``test_ks_2samp(x, y)`` -- Two-sample Kolmogorov-Smirnov test
+- ``test_normality(*samples)`` -- Multi-sample normality check
+
+Seaborn-Style Data Parameter
+----------------------------
+
+All two-sample and one-sample tests accept an optional ``data`` parameter
+for DataFrame/CSV column resolution (like seaborn):
+
+.. code-block:: python
+
+ import pandas as pd
+
+ df = pd.read_csv("experiment.csv")
+
+ # Two-sample: column names as x/y
+ result = stx.stats.test_ttest_ind(x="before", y="after", data=df)
+
+ # One-sample: column name as x
+ result = stx.stats.test_shapiro(x="scores", data=df)
+
+ # Multi-group: value + group columns
+ result = stx.stats.test_anova(data=df, value_col="score", group_col="treatment")
+
+ # Also works with CSV path
+ result = stx.stats.test_ttest_ind(x="col1", y="col2", data="data.csv")
+
+Test Recommendation
+-------------------
+
+Not sure which test to use? Let SciTeX recommend:
+
+.. code-block:: python
+
+ recommendations = stx.stats.recommend_tests(
+ n_groups=2,
+ sample_sizes=[30, 35],
+ outcome_type="continuous",
+ paired=False,
+ )
+
+Output Formats
+--------------
+
+Every test supports ``return_as`` parameter:
+
+- ``"dict"`` (default) -- Returns plain dict with all results
+- ``"dataframe"`` -- Returns pandas DataFrame
+
+Descriptive Statistics
+----------------------
+
+.. code-block:: python
+
+ stx.stats.describe(data) # mean, std, median, IQR, etc.
+ stx.stats.effect_sizes.cohens_d(g1, g2) # Cohen's d
+ stx.stats.test_normality(g1, g2) # Multi-sample normality
+ stx.stats.p_to_stars(0.003) # "**"
+
+Multiple Comparison Correction
+------------------------------
+
+.. code-block:: python
+
+ corrected = stx.stats.correct_pvalues(
+ [0.01, 0.03, 0.05, 0.001],
+ method="fdr_bh",
+ )
+
+Post-hoc Tests
+--------------
+
+.. code-block:: python
+
+ stx.stats.posthoc_test(
+ [g1, g2, g3],
+ group_names=["Control", "Treatment A", "Treatment B"],
+ method="tukey",
+ )
+
+API Reference
+-------------
+
+.. automodule:: scitex.stats
+ :members:
diff --git a/docs/sphinx/source/api/str.rst b/docs/sphinx/source/api/str.rst
new file mode 100644
index 000000000..b29b4f485
--- /dev/null
+++ b/docs/sphinx/source/api/str.rst
@@ -0,0 +1,7 @@
+str Module (``stx.str``)
+========================
+
+.. automodule:: scitex.str
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/template.rst b/docs/sphinx/source/api/template.rst
new file mode 100644
index 000000000..44b943dd2
--- /dev/null
+++ b/docs/sphinx/source/api/template.rst
@@ -0,0 +1,86 @@
+Template Module (``stx.template``)
+====================================
+
+Project scaffolding and code snippet templates for quick starts.
+
+Project Templates
+-----------------
+
+.. code-block:: bash
+
+ # Clone a project template
+ scitex template clone research my_project
+ scitex template clone pip_project my_package
+ scitex template clone paper my_paper
+
+.. list-table::
+ :header-rows: 1
+ :widths: 20 80
+
+ * - Template
+ - Description
+ * - ``research``
+ - Full scientific workflow (scripts, data, docs, config)
+ * - ``research_minimal``
+ - Essential modules only
+ * - ``pip_project``
+ - Distributable Python package for PyPI
+ * - ``singularity``
+ - Reproducible containerized environment
+ * - ``paper_directory``
+ - Academic paper with LaTeX/BibTeX structure
+
+Git Strategies
+--------------
+
+.. list-table::
+ :header-rows: 1
+ :widths: 20 80
+
+ * - Strategy
+ - Behavior
+ * - ``child`` (default)
+ - Fresh git repo, isolated from template
+ * - ``parent``
+ - Use parent repo if available
+ * - ``origin``
+ - Preserve template's git history
+ * - ``None``
+ - No git initialization
+
+Code Templates
+--------------
+
+.. code-block:: bash
+
+ # List available code templates
+ scitex template code list
+
+ # Get a template
+ scitex template code session # Full @stx.session script
+ scitex template code session-minimal # Lightweight session
+ scitex template code session-plot # Figure-focused session
+ scitex template code session-stats # Statistics-focused session
+ scitex template code io # I/O operations
+ scitex template code plt # Plotting patterns
+ scitex template code stats # Statistical analysis
+ scitex template code scholar # Literature management
+
+Python API
+----------
+
+.. code-block:: python
+
+ from scitex.template import clone_template, get_code_template
+
+ # Clone project
+ clone_template("research", "my_experiment", git_strategy="child")
+
+ # Get code snippet
+ code = get_code_template("session", filepath="analyze.py")
+
+API Reference
+-------------
+
+.. automodule:: scitex.template
+ :members:
diff --git a/docs/sphinx/source/api/tex.rst b/docs/sphinx/source/api/tex.rst
new file mode 100644
index 000000000..e0f775bd9
--- /dev/null
+++ b/docs/sphinx/source/api/tex.rst
@@ -0,0 +1,7 @@
+tex Module (``stx.tex``)
+========================
+
+.. automodule:: scitex.tex
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/torch.rst b/docs/sphinx/source/api/torch.rst
new file mode 100644
index 000000000..1a11fe241
--- /dev/null
+++ b/docs/sphinx/source/api/torch.rst
@@ -0,0 +1,7 @@
+torch Module (``stx.torch``)
+============================
+
+.. automodule:: scitex.torch
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/tunnel.rst b/docs/sphinx/source/api/tunnel.rst
new file mode 100644
index 000000000..e28928527
--- /dev/null
+++ b/docs/sphinx/source/api/tunnel.rst
@@ -0,0 +1,7 @@
+tunnel Module (``stx.tunnel``)
+==============================
+
+.. automodule:: scitex.tunnel
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/types.rst b/docs/sphinx/source/api/types.rst
new file mode 100644
index 000000000..f4f1e1031
--- /dev/null
+++ b/docs/sphinx/source/api/types.rst
@@ -0,0 +1,7 @@
+types Module (``stx.types``)
+============================
+
+.. automodule:: scitex.types
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/ui.rst b/docs/sphinx/source/api/ui.rst
new file mode 100644
index 000000000..2a8a65a64
--- /dev/null
+++ b/docs/sphinx/source/api/ui.rst
@@ -0,0 +1,7 @@
+ui Module (``stx.ui``)
+======================
+
+.. automodule:: scitex.ui
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/utils.rst b/docs/sphinx/source/api/utils.rst
new file mode 100644
index 000000000..9b893ac20
--- /dev/null
+++ b/docs/sphinx/source/api/utils.rst
@@ -0,0 +1,7 @@
+utils Module (``stx.utils``)
+============================
+
+.. automodule:: scitex.utils
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/web.rst b/docs/sphinx/source/api/web.rst
new file mode 100644
index 000000000..5b6589d9d
--- /dev/null
+++ b/docs/sphinx/source/api/web.rst
@@ -0,0 +1,7 @@
+web Module (``stx.web``)
+========================
+
+.. automodule:: scitex.web
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/docs/sphinx/source/api/writer.rst b/docs/sphinx/source/api/writer.rst
new file mode 100644
index 000000000..c03eaeee1
--- /dev/null
+++ b/docs/sphinx/source/api/writer.rst
@@ -0,0 +1,166 @@
+Writer Module (``stx.writer``)
+==============================
+
+LaTeX manuscript compilation, figure/table management, bibliography
+handling, and IMRAD writing guidelines.
+
+.. note::
+
+ ``stx.writer`` wraps the standalone
+ `scitex-writer `_ package.
+ Install with: ``pip install scitex-writer``.
+
+Quick Reference
+---------------
+
+.. code-block:: python
+
+ from scitex.writer import Writer
+ from pathlib import Path
+
+ writer = Writer(Path("my_paper"))
+
+ # Compile manuscript → PDF
+ result = writer.compile_manuscript()
+ if result.success:
+ print(f"PDF: {result.output_pdf}")
+
+ # Compile supplementary materials
+ result = writer.compile_supplementary()
+
+ # Compile revision with change tracking
+ result = writer.compile_revision(track_changes=True)
+
+CLI Usage
+---------
+
+.. code-block:: bash
+
+ # Compile
+ scitex writer compile manuscript ./my-paper
+ scitex writer compile supplementary ./my-paper
+ scitex writer compile revision ./my-paper --track-changes
+
+ # Bibliography
+ scitex writer bib list ./my-paper
+ scitex writer bib add ./my-paper "@article{...}"
+
+ # Tables and figures
+ scitex writer tables add ./my-paper data.csv
+ scitex writer figures list ./my-paper
+
+ # Writing guidelines
+ scitex writer guidelines get abstract
+
+Project Structure
+-----------------
+
+A writer project follows this layout:
+
+.. code-block:: text
+
+ my_paper/
+ +-- 00_shared/
+ | +-- bibliography.bib
+ | +-- figures/
+ | +-- tables/
+ +-- 01_manuscript/
+ | +-- main.tex
+ | +-- sections/
+ +-- 02_supplementary/
+ | +-- main.tex
+ +-- 03_revision/
+ +-- main.tex
+
+Create a new project:
+
+.. code-block:: bash
+
+ scitex template clone paper my_paper
+
+Key Classes
+-----------
+
+- ``Writer`` -- Main entry point for compilation and project management
+- ``CompilationResult`` -- Compilation outcome (success, output path, logs)
+- ``ManuscriptTree`` -- Document tree for the main manuscript
+- ``SupplementaryTree`` -- Document tree for supplementary materials
+- ``RevisionTree`` -- Document tree for revision responses
+
+Document Management
+-------------------
+
+**Figures:**
+
+.. code-block:: python
+
+ # Add figure (copies image + creates caption file)
+ writer.add_figure("fig1", "plot.png", caption="Results")
+
+ # List figures
+ writer.list_figures()
+
+ # Convert between formats
+ writer.convert_figure("figure.pdf", "figure.png", dpi=300)
+
+**Tables:**
+
+.. code-block:: python
+
+ # Add table from CSV
+ writer.add_table("tab1", csv_content, caption="Demographics")
+
+ # CSV ↔ LaTeX conversion
+ writer.csv_to_latex("data.csv", "table.tex")
+ writer.latex_to_csv("table.tex", "data.csv")
+
+**Bibliography:**
+
+.. code-block:: python
+
+ # Add BibTeX entry
+ writer.add_bibentry('@article{key, title={...}, ...}')
+
+ # Merge multiple .bib files
+ writer.merge_bibfiles(output_file="bibliography.bib")
+
+Writing Guidelines
+------------------
+
+IMRAD guidelines for each manuscript section:
+
+.. code-block:: bash
+
+ scitex writer guidelines list
+ scitex writer guidelines get introduction
+
+.. code-block:: python
+
+ from scitex.writer import guidelines
+
+ # Get guideline for a section
+ guide = guidelines.get("methods")
+
+ # Build editing prompt: guideline + draft
+ prompt = guidelines.build("discussion", draft_text)
+
+Compilation Options
+-------------------
+
+.. code-block:: python
+
+ result = writer.compile_manuscript(
+ timeout=300, # Max compilation time (seconds)
+ no_figs=False, # Exclude figures
+ no_tables=False, # Exclude tables
+ draft=False, # Draft mode (fast, lower quality)
+ dark_mode=False, # Dark color scheme
+ quiet=False, # Suppress output
+ )
+
+API Reference
+-------------
+
+.. automodule:: scitex.writer
+ :members:
+ :show-inheritance:
diff --git a/pyproject.toml b/pyproject.toml
index 5165ad869..ba4fbff68 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -69,6 +69,7 @@ dependencies = [
"scitex-io>=0.2.0",
"scitex-stats>=0.2.0",
"scitex-audio>=0.1.0",
+ "scitex-notification>=0.1.0",
]
[project.urls]
diff --git a/src/scitex/_dev/_ecosystem.py b/src/scitex/_dev/_ecosystem.py
index c6270861d..04eae4f2b 100755
--- a/src/scitex/_dev/_ecosystem.py
+++ b/src/scitex/_dev/_ecosystem.py
@@ -43,6 +43,12 @@ class PackageInfo(TypedDict, total=False):
"github_repo": "ywatanabe1989/scitex-clew",
"import_name": "scitex_clew",
},
+ "scitex-notification": {
+ "local_path": "~/proj/scitex-notification",
+ "pypi_name": "scitex-notification",
+ "github_repo": "ywatanabe1989/scitex-notification",
+ "import_name": "scitex_notification",
+ },
"scitex-cloud": {
"local_path": "~/proj/scitex-cloud",
"pypi_name": "scitex-cloud",
diff --git a/src/scitex/_mcp_tools/notify.py b/src/scitex/_mcp_tools/notify.py
index ed7cbc832..1da7855f3 100755
--- a/src/scitex/_mcp_tools/notify.py
+++ b/src/scitex/_mcp_tools/notify.py
@@ -18,8 +18,7 @@ async def notify_send(
) -> str:
"""Send a notification via configured backends."""
from scitex_dev.mcp_utils import async_wrap_as_mcp
-
- from scitex.notify._mcp.handlers import notify_handler
+ from scitex_notification._mcp.handlers import notify_handler
return await async_wrap_as_mcp(
notify_handler,
@@ -46,8 +45,7 @@ async def notify_call(
Use repeat=2 to bypass iOS silent/manner mode (calls 30s apart).
"""
from scitex_dev.mcp_utils import async_wrap_as_mcp
-
- from scitex.notify._mcp.handlers import notify_handler
+ from scitex_notification._mcp.handlers import notify_handler
kwargs = {"repeat": repeat}
if to_number:
@@ -74,8 +72,7 @@ async def notify_sms(
) -> str:
"""Send an SMS via Twilio."""
from scitex_dev.mcp_utils import async_wrap_as_mcp
-
- from scitex.notify._backends._twilio import send_sms
+ from scitex_notification._backends._twilio import send_sms
kwargs = {}
if to_number:
@@ -93,8 +90,7 @@ async def notify_sms(
async def notify_backends() -> str:
"""List all notification backends and their availability."""
from scitex_dev.mcp_utils import async_wrap_as_mcp
-
- from scitex.notify._mcp.handlers import list_backends_handler
+ from scitex_notification._mcp.handlers import list_backends_handler
return await async_wrap_as_mcp(
list_backends_handler,
@@ -105,8 +101,7 @@ async def notify_backends() -> str:
async def notify_config() -> str:
"""Get current notification configuration."""
from scitex_dev.mcp_utils import async_wrap_as_mcp
-
- from scitex.notify._mcp.handlers import get_config_handler
+ from scitex_notification._mcp.handlers import get_config_handler
return await async_wrap_as_mcp(
get_config_handler,
diff --git a/src/scitex/cli/notify.py b/src/scitex/cli/notify.py
index d2c2d6579..73dfac3d3 100755
--- a/src/scitex/cli/notify.py
+++ b/src/scitex/cli/notify.py
@@ -307,8 +307,12 @@ def list_backends(as_json):
scitex notify backends --json
"""
try:
- from scitex.notify import DEFAULT_FALLBACK_ORDER, available_backends
- from scitex.notify._backends import BACKENDS
+ from scitex_notification._backends import BACKENDS # noqa: E402
+
+ from scitex.notify import ( # noqa: E402
+ DEFAULT_FALLBACK_ORDER,
+ available_backends,
+ )
available = available_backends()
@@ -363,7 +367,7 @@ def config(as_json):
scitex notify config --json
"""
try:
- from scitex.notify._backends._config import get_config
+ from scitex_notification._backends._config import get_config
cfg = get_config()
diff --git a/src/scitex/notify/__init__.py b/src/scitex/notify/__init__.py
index 41c3076af..219e1ac88 100755
--- a/src/scitex/notify/__init__.py
+++ b/src/scitex/notify/__init__.py
@@ -1,297 +1,30 @@
#!/usr/bin/env python3
-# Timestamp: "2026-01-13 (ywatanabe)"
-# File: /home/ywatanabe/proj/scitex-code/src/scitex/ui/__init__.py
+"""SciTeX Notify — thin wrapper delegating to scitex-notification package.
-"""SciTeX UI Module - User alerts and feedback.
-
-Usage:
- import scitex
-
- # Simple alert - uses fallback priority (audio → emacs → desktop → ...)
- scitex.notify.alert("2FA required!")
-
- # Specify backend (no fallback)
- scitex.notify.alert("Error", backend="email")
-
- # Multiple backends (tries all)
- scitex.notify.alert("Critical", backend=["audio", "email"])
-
- # Use fallback explicitly
- scitex.notify.alert("Important", fallback=True)
-
- # Make a phone call via Twilio
- scitex.notify.call("Critical alert!")
-
-Environment Variables:
- SCITEX_NOTIFY_DEFAULT_BACKEND: audio, email, desktop, webhook
- SCITEX_UI_DEFAULT_BACKEND: (deprecated) use SCITEX_NOTIFY_DEFAULT_BACKEND
+All notification logic lives in the standalone scitex-notification package.
+This module re-exports the public API for backward compatibility.
"""
-from __future__ import annotations
-
-import asyncio
-import os
-from typing import Optional, Union
-
-from ._backends import NotifyLevel as _AlertLevel
-from ._backends import available_backends as _available_backends
-from ._backends import get_backend as _get_backend
+from scitex_notification import (
+ DEFAULT_FALLBACK_ORDER,
+ alert,
+ alert_async,
+ available_backends,
+ call,
+ call_async,
+ sms,
+ sms_async,
+)
__all__ = [
"alert",
"alert_async",
- "available_backends",
"call",
"call_async",
"sms",
"sms_async",
+ "available_backends",
+ "DEFAULT_FALLBACK_ORDER",
]
-# Default fallback priority order
-DEFAULT_FALLBACK_ORDER = [
- "audio", # 1st: TTS audio (non-blocking, immediate)
- "emacs", # 2nd: Emacs minibuffer (if in Emacs)
- "matplotlib", # 3rd: Visual popup
- "playwright", # 4th: Browser popup
- "email", # 5th: Email (slowest, most reliable)
-]
-
-
-def available_backends() -> list[str]:
- """Return list of available alert backends."""
- return _available_backends()
-
-
-async def alert_async(
- message: str,
- title: Optional[str] = None,
- backend: Optional[Union[str, list[str]]] = None,
- level: str = "info",
- fallback: bool = True,
- **kwargs,
-) -> bool:
- """Send alert asynchronously.
-
- Parameters
- ----------
- message : str
- Alert message
- title : str, optional
- Alert title
- backend : str or list[str], optional
- Backend(s) to use. If None, uses default with fallback.
- level : str
- Alert level: info, warning, error, critical
- fallback : bool
- If True and backend fails, try next in priority order.
- Default True when backend=None, False when backend specified.
-
- Returns
- -------
- bool
- True if any backend succeeded
- """
- try:
- lvl = _AlertLevel(level.lower())
- except ValueError:
- lvl = _AlertLevel.INFO
-
- # Determine backends to try
- if backend is None:
- # No backend specified: use fallback priority
- default = os.getenv("SCITEX_NOTIFY_DEFAULT_BACKEND") or os.getenv(
- "SCITEX_UI_DEFAULT_BACKEND", "audio"
- )
- if fallback:
- # Start with default, then try others in priority order
- backends = [default] + [b for b in DEFAULT_FALLBACK_ORDER if b != default]
- else:
- backends = [default]
- else:
- # Backend specified: use it (with optional fallback)
- backends = [backend] if isinstance(backend, str) else list(backend)
- if fallback and len(backends) == 1:
- # Add fallback backends after the specified one
- backends = backends + [
- b for b in DEFAULT_FALLBACK_ORDER if b not in backends
- ]
-
- # Try backends until one succeeds
- available = _available_backends()
- for name in backends:
- if name not in available:
- continue
- try:
- b = _get_backend(name)
- result = await b.send(message, title=title, level=lvl, **kwargs)
- if result.success:
- return True
- except Exception:
- pass
-
- return False
-
-
-def alert(
- message: str,
- title: Optional[str] = None,
- backend: Optional[Union[str, list[str]]] = None,
- level: str = "info",
- fallback: bool = True,
- **kwargs,
-) -> bool:
- """Send alert synchronously.
-
- Parameters
- ----------
- message : str
- Alert message
- title : str, optional
- Alert title
- backend : str or list[str], optional
- Backend(s) to use. If None, uses fallback priority order.
- level : str
- Alert level: info, warning, error, critical
- fallback : bool
- If True and backend fails, try next in priority order.
-
- Returns
- -------
- bool
- True if any backend succeeded
-
- Fallback Order
- --------------
- 1. audio - TTS (fast, non-blocking)
- 2. emacs - Minibuffer message
- 3. matplotlib - Visual popup
- 4. playwright - Browser popup
- 5. email - Email (slowest)
- """
- try:
- asyncio.get_running_loop()
- import concurrent.futures
-
- with concurrent.futures.ThreadPoolExecutor() as executor:
- future = executor.submit(
- asyncio.run,
- alert_async(message, title, backend, level, fallback, **kwargs),
- )
- return future.result(timeout=30)
- except RuntimeError:
- return asyncio.run(
- alert_async(message, title, backend, level, fallback, **kwargs)
- )
-
-
-def call(
- message: str,
- title: Optional[str] = None,
- level: str = "info",
- to_number: Optional[str] = None,
- **kwargs,
-) -> bool:
- """Make a phone call via Twilio.
-
- Convenience wrapper for alert(backend="twilio").
- """
- return alert(
- message,
- title=title,
- backend="twilio",
- level=level,
- fallback=False,
- to_number=to_number,
- **kwargs,
- )
-
-
-async def call_async(
- message: str,
- title: Optional[str] = None,
- level: str = "info",
- to_number: Optional[str] = None,
- **kwargs,
-) -> bool:
- """Make a phone call via Twilio (async)."""
- return await alert_async(
- message,
- title=title,
- backend="twilio",
- level=level,
- fallback=False,
- to_number=to_number,
- **kwargs,
- )
-
-
-async def sms_async(
- message: str,
- title: Optional[str] = None,
- to_number: Optional[str] = None,
- **kwargs,
-) -> bool:
- """Send an SMS via Twilio (async).
-
- Parameters
- ----------
- message : str
- SMS body text
- title : str, optional
- Prepended to message if provided
- to_number : str, optional
- Override SCITEX_NOTIFY_TWILIO_TO
-
- Returns
- -------
- bool
- True if SMS sent successfully
- """
- from ._backends._twilio import send_sms as _send_sms
-
- result = await _send_sms(
- message,
- title=title,
- to_number=to_number,
- **kwargs,
- )
- return result.success
-
-
-def sms(
- message: str,
- title: Optional[str] = None,
- to_number: Optional[str] = None,
- **kwargs,
-) -> bool:
- """Send an SMS via Twilio.
-
- Parameters
- ----------
- message : str
- SMS body text
- title : str, optional
- Prepended to message if provided
- to_number : str, optional
- Override SCITEX_NOTIFY_TWILIO_TO
-
- Returns
- -------
- bool
- True if SMS sent successfully
- """
- try:
- asyncio.get_running_loop()
- import concurrent.futures
-
- with concurrent.futures.ThreadPoolExecutor() as executor:
- future = executor.submit(
- asyncio.run,
- sms_async(message, title, to_number, **kwargs),
- )
- return future.result(timeout=30)
- except RuntimeError:
- return asyncio.run(sms_async(message, title, to_number, **kwargs))
-
-
# EOF
diff --git a/src/scitex/notify/_mcp/handlers.py b/src/scitex/notify/_mcp/handlers.py
index b5e40e772..a4a56ed2d 100755
--- a/src/scitex/notify/_mcp/handlers.py
+++ b/src/scitex/notify/_mcp/handlers.py
@@ -25,6 +25,7 @@ async def notify_handler(
backend: Optional[str] = None,
backends: Optional[list[str]] = None,
timeout: float = 5.0,
+ **kwargs,
) -> dict:
"""Send notification via specified backend(s)."""
from .._backends import BACKENDS, NotifyLevel, get_backend
@@ -61,12 +62,13 @@ async def notify_handler(
)
continue
- b = get_backend(backend_name)
+ b = get_backend(backend_name, **kwargs)
result = await b.send(
message,
title=title,
level=notify_level,
timeout=timeout,
+ **kwargs,
)
results.append(