Metadata-Version: 2.4
Name: scitex
Version: 2.28.0
Summary: A comprehensive Python library for scientific computing and data analysis
Project-URL: Homepage, https://github.com/ywatanabe1989/scitex-python
Project-URL: Documentation, https://scitex.readthedocs.io
Project-URL: Repository, https://github.com/ywatanabe1989/scitex-python
Project-URL: Bug Tracker, https://github.com/ywatanabe1989/scitex-python/issues
Author-email: Yusuke Watanabe <ywatanabe@scitex.ai>
License-Expression: AGPL-3.0-only
License-File: LICENSE
Keywords: data-analysis,machine-learning,neural-networks,research,scientific-computing,signal-processing
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: GNU Affero General Public License v3
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Requires-Dist: beautifulsoup4>=4.12.0
Requires-Dist: natsort
Requires-Dist: numpy
Requires-Dist: packaging
Requires-Dist: pandas
Requires-Dist: pyyaml
Requires-Dist: scitex-app>=0.1.0
Requires-Dist: scitex-audio>=0.1.0
Requires-Dist: scitex-audit>=0.1.0
Requires-Dist: scitex-browser>=0.1.0
Requires-Dist: scitex-clew>=0.1.0
Requires-Dist: scitex-compat>=0.1.0
Requires-Dist: scitex-config>=0.3.0
Requires-Dist: scitex-core>=0.2.0
Requires-Dist: scitex-db>=0.1.0
Requires-Dist: scitex-dev>=0.1.0
Requires-Dist: scitex-dict>=0.1.0
Requires-Dist: scitex-etc>=0.1.0
Requires-Dist: scitex-gists>=0.1.0
Requires-Dist: scitex-io>=0.2.0
Requires-Dist: scitex-logging>=0.1.0
Requires-Dist: scitex-notebook>=0.1.0
Requires-Dist: scitex-notification>=0.1.0
Requires-Dist: scitex-parallel>=0.1.0
Requires-Dist: scitex-path>=0.1.0
Requires-Dist: scitex-repro>=0.1.0
Requires-Dist: scitex-scholar>=1.0.0
Requires-Dist: scitex-stats>=0.2.0
Requires-Dist: scitex-str>=0.1.0
Requires-Dist: scitex-types>=0.1.0
Requires-Dist: tqdm
Provides-Extra: agent-container
Requires-Dist: scitex-agent-container>=0.7.1; extra == 'agent-container'
Provides-Extra: ai
Requires-Dist: anthropic; extra == 'ai'
Requires-Dist: google-genai; extra == 'ai'
Requires-Dist: groq; extra == 'ai'
Requires-Dist: imbalanced-learn; extra == 'ai'
Requires-Dist: joblib; extra == 'ai'
Requires-Dist: markdown2; extra == 'ai'
Requires-Dist: matplotlib; extra == 'ai'
Requires-Dist: natsort; extra == 'ai'
Requires-Dist: openai; extra == 'ai'
Requires-Dist: pillow; extra == 'ai'
Requires-Dist: pyyaml; extra == 'ai'
Requires-Dist: requests; extra == 'ai'
Requires-Dist: ruamel-yaml; extra == 'ai'
Requires-Dist: scikit-learn; extra == 'ai'
Requires-Dist: scipy; extra == 'ai'
Requires-Dist: seaborn; extra == 'ai'
Requires-Dist: sktime>=0.21.0; extra == 'ai'
Requires-Dist: umap-learn; extra == 'ai'
Requires-Dist: xarray; extra == 'ai'
Provides-Extra: all
Requires-Dist: aiohttp; extra == 'all'
Requires-Dist: anthropic; extra == 'all'
Requires-Dist: beautifulsoup4; extra == 'all'
Requires-Dist: bibtexparser; extra == 'all'
Requires-Dist: build; extra == 'all'
Requires-Dist: catboost; extra == 'all'
Requires-Dist: click; extra == 'all'
Requires-Dist: connectedpapers-py; extra == 'all'
Requires-Dist: crawl4ai; extra == 'all'
Requires-Dist: crossref-local; extra == 'all'
Requires-Dist: csv2latex; extra == 'all'
Requires-Dist: feedparser; extra == 'all'
Requires-Dist: figrecipe>=0.16.0; extra == 'all'
Requires-Dist: flask>=2.0.0; extra == 'all'
Requires-Dist: geom-median; extra == 'all'
Requires-Dist: gitpython; extra == 'all'
Requires-Dist: google-genai; extra == 'all'
Requires-Dist: groq; extra == 'all'
Requires-Dist: h5py; extra == 'all'
Requires-Dist: html2text; extra == 'all'
Requires-Dist: httpx; extra == 'all'
Requires-Dist: imbalanced-learn; extra == 'all'
Requires-Dist: ipdb; extra == 'all'
Requires-Dist: ipython; extra == 'all'
Requires-Dist: jax; extra == 'all'
Requires-Dist: jedi; extra == 'all'
Requires-Dist: joblib; extra == 'all'
Requires-Dist: julius; extra == 'all'
Requires-Dist: line-profiler; extra == 'all'
Requires-Dist: lxml; extra == 'all'
Requires-Dist: lxml-html-clean; extra == 'all'
Requires-Dist: markdown; extra == 'all'
Requires-Dist: markdown2; extra == 'all'
Requires-Dist: matplotlib; extra == 'all'
Requires-Dist: mcp; extra == 'all'
Requires-Dist: memory-profiler; extra == 'all'
Requires-Dist: mne; extra == 'all'
Requires-Dist: mss; extra == 'all'
Requires-Dist: mypy; extra == 'all'
Requires-Dist: myst-parser; extra == 'all'
Requires-Dist: myst-parser>=2.0; extra == 'all'
Requires-Dist: natsort; extra == 'all'
Requires-Dist: nest-asyncio; extra == 'all'
Requires-Dist: numcodecs; extra == 'all'
Requires-Dist: openai; extra == 'all'
Requires-Dist: openalex-local; extra == 'all'
Requires-Dist: opencv-python; extra == 'all'
Requires-Dist: openpyxl; extra == 'all'
Requires-Dist: optuna; extra == 'all'
Requires-Dist: pdfplumber; extra == 'all'
Requires-Dist: piexif; extra == 'all'
Requires-Dist: pillow; extra == 'all'
Requires-Dist: playwright; extra == 'all'
Requires-Dist: playwright>=1.40.0; extra == 'all'
Requires-Dist: plotly; extra == 'all'
Requires-Dist: pre-commit; extra == 'all'
Requires-Dist: psutil; extra == 'all'
Requires-Dist: psycopg2-binary; extra == 'all'
Requires-Dist: pyarrow; extra == 'all'
Requires-Dist: pydantic; extra == 'all'
Requires-Dist: pygments; extra == 'all'
Requires-Dist: pymatreader; extra == 'all'
Requires-Dist: pymed; extra == 'all'
Requires-Dist: pymupdf; extra == 'all'
Requires-Dist: pypandoc; extra == 'all'
Requires-Dist: pypdf; extra == 'all'
Requires-Dist: pyperclip; extra == 'all'
Requires-Dist: pyright; extra == 'all'
Requires-Dist: pytesseract; extra == 'all'
Requires-Dist: pytest; extra == 'all'
Requires-Dist: pytest-asyncio; extra == 'all'
Requires-Dist: pytest-cov; extra == 'all'
Requires-Dist: pytest-env; extra == 'all'
Requires-Dist: pytest-json-report; extra == 'all'
Requires-Dist: pytest-mock; extra == 'all'
Requires-Dist: pytest-testmon; extra == 'all'
Requires-Dist: pytest-timeout; extra == 'all'
Requires-Dist: pytest-xdist; extra == 'all'
Requires-Dist: python-docx; extra == 'all'
Requires-Dist: python-lsp-server; extra == 'all'
Requires-Dist: pytorch-pretrained-vit; extra == 'all'
Requires-Dist: pyyaml; extra == 'all'
Requires-Dist: qrcode[pil]; extra == 'all'
Requires-Dist: readability-lxml; extra == 'all'
Requires-Dist: readchar; extra == 'all'
Requires-Dist: requests; extra == 'all'
Requires-Dist: ripple-detection; extra == 'all'
Requires-Dist: rope; extra == 'all'
Requires-Dist: ruamel-yaml; extra == 'all'
Requires-Dist: ruff; extra == 'all'
Requires-Dist: scholarly; extra == 'all'
Requires-Dist: scikit-learn; extra == 'all'
Requires-Dist: scipy; extra == 'all'
Requires-Dist: scitex-agent-container>=0.7.1; extra == 'all'
Requires-Dist: scitex-app>=0.1.0; extra == 'all'
Requires-Dist: scitex-audio>=0.1.0; extra == 'all'
Requires-Dist: scitex-audit>=0.1.2; extra == 'all'
Requires-Dist: scitex-browser>=0.1.8; extra == 'all'
Requires-Dist: scitex-clew>=0.2.5; extra == 'all'
Requires-Dist: scitex-cloud>=0.16.1; extra == 'all'
Requires-Dist: scitex-compat>=0.1.1; extra == 'all'
Requires-Dist: scitex-container; extra == 'all'
Requires-Dist: scitex-core>=0.2.2; extra == 'all'
Requires-Dist: scitex-dataset; extra == 'all'
Requires-Dist: scitex-db>=0.1.3; extra == 'all'
Requires-Dist: scitex-dev>=0.7.0; extra == 'all'
Requires-Dist: scitex-dict>=0.1.2; extra == 'all'
Requires-Dist: scitex-etc>=0.1.1; extra == 'all'
Requires-Dist: scitex-gists>=0.1.2; extra == 'all'
Requires-Dist: scitex-io>=0.2.0; extra == 'all'
Requires-Dist: scitex-linter>=0.3.5; extra == 'all'
Requires-Dist: scitex-logging>=0.1.2; extra == 'all'
Requires-Dist: scitex-notebook>=0.1.0; extra == 'all'
Requires-Dist: scitex-notification>=0.1.0; extra == 'all'
Requires-Dist: scitex-orochi>=0.13.0; extra == 'all'
Requires-Dist: scitex-parallel>=0.1.1; extra == 'all'
Requires-Dist: scitex-path>=0.1.2; extra == 'all'
Requires-Dist: scitex-repro>=0.1.2; extra == 'all'
Requires-Dist: scitex-scholar>=1.2.1; extra == 'all'
Requires-Dist: scitex-stats>=0.2.0; extra == 'all'
Requires-Dist: scitex-str>=0.1.1; extra == 'all'
Requires-Dist: scitex-template>=0.1.0; extra == 'all'
Requires-Dist: scitex-tunnel; extra == 'all'
Requires-Dist: scitex-types>=0.1.2; extra == 'all'
Requires-Dist: scitex-ui>=0.4.7; extra == 'all'
Requires-Dist: scitex-writer; extra == 'all'
Requires-Dist: seaborn; extra == 'all'
Requires-Dist: selenium; extra == 'all'
Requires-Dist: setuptools; extra == 'all'
Requires-Dist: sktime>=0.21.0; extra == 'all'
Requires-Dist: socialia>=0.3.1; extra == 'all'
Requires-Dist: sounddevice; extra == 'all'
Requires-Dist: sphinx; extra == 'all'
Requires-Dist: sphinx-autobuild; extra == 'all'
Requires-Dist: sphinx-autodoc-typehints; extra == 'all'
Requires-Dist: sphinx-autodoc-typehints>=1.25; extra == 'all'
Requires-Dist: sphinx-copybutton>=0.5; extra == 'all'
Requires-Dist: sphinx-rtd-theme; extra == 'all'
Requires-Dist: sphinx-rtd-theme>=2.0; extra == 'all'
Requires-Dist: sphinx>=7.0; extra == 'all'
Requires-Dist: sql-manager; extra == 'all'
Requires-Dist: sqlalchemy; extra == 'all'
Requires-Dist: statsmodels; extra == 'all'
Requires-Dist: stdlib-list; extra == 'all'
Requires-Dist: sympy; extra == 'all'
Requires-Dist: tabulate; extra == 'all'
Requires-Dist: tenacity; extra == 'all'
Requires-Dist: tensorflow; extra == 'all'
Requires-Dist: tensorpac; extra == 'all'
Requires-Dist: termplotlib; extra == 'all'
Requires-Dist: tomlkit; extra == 'all'
Requires-Dist: torch; extra == 'all'
Requires-Dist: torchaudio; extra == 'all'
Requires-Dist: torchsummary; extra == 'all'
Requires-Dist: torchvision; extra == 'all'
Requires-Dist: tqdm; extra == 'all'
Requires-Dist: twine; extra == 'all'
Requires-Dist: types-pyyaml; extra == 'all'
Requires-Dist: types-requests; extra == 'all'
Requires-Dist: types-setuptools; extra == 'all'
Requires-Dist: umap-learn; extra == 'all'
Requires-Dist: watchdog; extra == 'all'
Requires-Dist: webdriver-manager; extra == 'all'
Requires-Dist: wheel; extra == 'all'
Requires-Dist: xarray; extra == 'all'
Requires-Dist: xlrd; extra == 'all'
Requires-Dist: xlsx2csv; extra == 'all'
Requires-Dist: yq; extra == 'all'
Requires-Dist: zarr; extra == 'all'
Provides-Extra: app
Requires-Dist: scitex-app>=0.1.0; extra == 'app'
Provides-Extra: audio
Requires-Dist: scitex-audio>=0.1.0; extra == 'audio'
Provides-Extra: audit
Requires-Dist: scitex-audit>=0.1.2; extra == 'audit'
Provides-Extra: benchmark
Requires-Dist: psutil; extra == 'benchmark'
Provides-Extra: bridge
Requires-Dist: matplotlib; extra == 'bridge'
Requires-Dist: scipy; extra == 'bridge'
Provides-Extra: browser
Requires-Dist: aiohttp; extra == 'browser'
Requires-Dist: matplotlib; extra == 'browser'
Requires-Dist: playwright>=1.40.0; extra == 'browser'
Requires-Dist: scitex-browser>=0.1.8; extra == 'browser'
Provides-Extra: capture
Requires-Dist: mcp; extra == 'capture'
Requires-Dist: mss; extra == 'capture'
Requires-Dist: pillow; extra == 'capture'
Requires-Dist: playwright>=1.40.0; extra == 'capture'
Provides-Extra: clew
Requires-Dist: scitex-clew>=0.2.5; extra == 'clew'
Provides-Extra: cli
Requires-Dist: aiohttp; extra == 'cli'
Requires-Dist: beautifulsoup4; extra == 'cli'
Requires-Dist: click; extra == 'cli'
Requires-Dist: gitpython; extra == 'cli'
Requires-Dist: playwright; extra == 'cli'
Requires-Dist: pyyaml; extra == 'cli'
Requires-Dist: requests; extra == 'cli'
Provides-Extra: cloud
Requires-Dist: matplotlib; extra == 'cloud'
Requires-Dist: scitex-cloud>=0.16.1; extra == 'cloud'
Provides-Extra: compat
Requires-Dist: scitex-compat>=0.1.1; extra == 'compat'
Provides-Extra: config
Requires-Dist: pyyaml; extra == 'config'
Provides-Extra: container
Requires-Dist: scitex-container; extra == 'container'
Provides-Extra: context
Provides-Extra: core
Requires-Dist: scitex-core>=0.2.2; extra == 'core'
Provides-Extra: cv
Requires-Dist: opencv-python; extra == 'cv'
Requires-Dist: pillow; extra == 'cv'
Provides-Extra: dataset
Requires-Dist: scitex-dataset; extra == 'dataset'
Provides-Extra: datetime
Provides-Extra: db
Requires-Dist: psycopg2-binary; extra == 'db'
Requires-Dist: scitex-db>=0.1.3; extra == 'db'
Requires-Dist: sqlalchemy; extra == 'db'
Provides-Extra: decorators
Requires-Dist: joblib; extra == 'decorators'
Requires-Dist: matplotlib; extra == 'decorators'
Requires-Dist: pytest-asyncio; extra == 'decorators'
Requires-Dist: scipy; extra == 'decorators'
Requires-Dist: tqdm; extra == 'decorators'
Requires-Dist: xarray; extra == 'decorators'
Provides-Extra: dev
Requires-Dist: build; extra == 'dev'
Requires-Dist: jedi; extra == 'dev'
Requires-Dist: line-profiler; extra == 'dev'
Requires-Dist: markdown; extra == 'dev'
Requires-Dist: markdown2; extra == 'dev'
Requires-Dist: matplotlib; extra == 'dev'
Requires-Dist: memory-profiler; extra == 'dev'
Requires-Dist: mypy; extra == 'dev'
Requires-Dist: myst-parser; extra == 'dev'
Requires-Dist: pre-commit; extra == 'dev'
Requires-Dist: pygments; extra == 'dev'
Requires-Dist: pyright; extra == 'dev'
Requires-Dist: pytest; extra == 'dev'
Requires-Dist: pytest-asyncio; extra == 'dev'
Requires-Dist: pytest-cov; extra == 'dev'
Requires-Dist: pytest-env; extra == 'dev'
Requires-Dist: pytest-json-report; extra == 'dev'
Requires-Dist: pytest-mock; extra == 'dev'
Requires-Dist: pytest-testmon; extra == 'dev'
Requires-Dist: pytest-timeout; extra == 'dev'
Requires-Dist: pytest-xdist; extra == 'dev'
Requires-Dist: python-lsp-server; extra == 'dev'
Requires-Dist: pyyaml; extra == 'dev'
Requires-Dist: rope; extra == 'dev'
Requires-Dist: ruff; extra == 'dev'
Requires-Dist: scitex-container; extra == 'dev'
Requires-Dist: scitex-dev>=0.7.0; extra == 'dev'
Requires-Dist: scitex-tunnel; extra == 'dev'
Requires-Dist: setuptools; extra == 'dev'
Requires-Dist: sphinx; extra == 'dev'
Requires-Dist: sphinx-autobuild; extra == 'dev'
Requires-Dist: sphinx-autodoc-typehints; extra == 'dev'
Requires-Dist: sphinx-rtd-theme; extra == 'dev'
Requires-Dist: stdlib-list; extra == 'dev'
Requires-Dist: tomlkit; extra == 'dev'
Requires-Dist: twine; extra == 'dev'
Requires-Dist: types-pyyaml; extra == 'dev'
Requires-Dist: types-requests; extra == 'dev'
Requires-Dist: types-setuptools; extra == 'dev'
Requires-Dist: wheel; extra == 'dev'
Provides-Extra: devtools
Requires-Dist: joblib; extra == 'devtools'
Requires-Dist: matplotlib; extra == 'devtools'
Requires-Dist: ruamel-yaml; extra == 'devtools'
Requires-Dist: scipy; extra == 'devtools'
Requires-Dist: seaborn; extra == 'devtools'
Requires-Dist: xarray; extra == 'devtools'
Provides-Extra: diagram
Requires-Dist: pyyaml; extra == 'diagram'
Provides-Extra: dict
Requires-Dist: scitex-dict>=0.1.2; extra == 'dict'
Provides-Extra: docs
Requires-Dist: myst-parser>=2.0; extra == 'docs'
Requires-Dist: sphinx-autodoc-typehints>=1.25; extra == 'docs'
Requires-Dist: sphinx-copybutton>=0.5; extra == 'docs'
Requires-Dist: sphinx-rtd-theme>=2.0; extra == 'docs'
Requires-Dist: sphinx>=7.0; extra == 'docs'
Provides-Extra: dsp
Requires-Dist: h5py; extra == 'dsp'
Requires-Dist: joblib; extra == 'dsp'
Requires-Dist: matplotlib; extra == 'dsp'
Requires-Dist: readchar; extra == 'dsp'
Requires-Dist: ruamel-yaml; extra == 'dsp'
Requires-Dist: scipy; extra == 'dsp'
Requires-Dist: seaborn; extra == 'dsp'
Requires-Dist: sounddevice; extra == 'dsp'
Requires-Dist: tensorpac; extra == 'dsp'
Requires-Dist: xarray; extra == 'dsp'
Provides-Extra: dt
Requires-Dist: matplotlib; extra == 'dt'
Provides-Extra: etc
Requires-Dist: readchar; extra == 'etc'
Requires-Dist: scitex-etc>=0.1.1; extra == 'etc'
Provides-Extra: events
Provides-Extra: gen
Requires-Dist: h5py; extra == 'gen'
Requires-Dist: ipython; extra == 'gen'
Requires-Dist: joblib; extra == 'gen'
Requires-Dist: matplotlib; extra == 'gen'
Requires-Dist: pyperclip; extra == 'gen'
Requires-Dist: readchar; extra == 'gen'
Requires-Dist: requests; extra == 'gen'
Requires-Dist: scipy; extra == 'gen'
Requires-Dist: xarray; extra == 'gen'
Provides-Extra: gists
Requires-Dist: scitex-gists>=0.1.2; extra == 'gists'
Provides-Extra: git
Requires-Dist: gitpython; extra == 'git'
Requires-Dist: matplotlib; extra == 'git'
Provides-Extra: heavy
Requires-Dist: catboost; extra == 'heavy'
Requires-Dist: jax; extra == 'heavy'
Requires-Dist: julius; extra == 'heavy'
Requires-Dist: mne; extra == 'heavy'
Requires-Dist: optuna; extra == 'heavy'
Requires-Dist: psutil; extra == 'heavy'
Requires-Dist: pytorch-pretrained-vit; extra == 'heavy'
Requires-Dist: ripple-detection; extra == 'heavy'
Requires-Dist: tensorflow; extra == 'heavy'
Requires-Dist: torch; extra == 'heavy'
Requires-Dist: torchaudio; extra == 'heavy'
Requires-Dist: torchsummary; extra == 'heavy'
Requires-Dist: torchvision; extra == 'heavy'
Requires-Dist: umap-learn; extra == 'heavy'
Provides-Extra: hpc
Requires-Dist: scitex-hpc>=0.1.0; extra == 'hpc'
Provides-Extra: introspect
Provides-Extra: io
Requires-Dist: gitpython; extra == 'io'
Requires-Dist: h5py; extra == 'io'
Requires-Dist: html2text; extra == 'io'
Requires-Dist: joblib; extra == 'io'
Requires-Dist: lxml; extra == 'io'
Requires-Dist: lxml-html-clean; extra == 'io'
Requires-Dist: markdown; extra == 'io'
Requires-Dist: matplotlib; extra == 'io'
Requires-Dist: natsort; extra == 'io'
Requires-Dist: numcodecs; extra == 'io'
Requires-Dist: openpyxl; extra == 'io'
Requires-Dist: pdfplumber; extra == 'io'
Requires-Dist: piexif; extra == 'io'
Requires-Dist: pillow; extra == 'io'
Requires-Dist: plotly; extra == 'io'
Requires-Dist: pyarrow; extra == 'io'
Requires-Dist: pymatreader; extra == 'io'
Requires-Dist: pymupdf; extra == 'io'
Requires-Dist: pypdf; extra == 'io'
Requires-Dist: python-docx; extra == 'io'
Requires-Dist: pyyaml; extra == 'io'
Requires-Dist: qrcode[pil]; extra == 'io'
Requires-Dist: ruamel-yaml; extra == 'io'
Requires-Dist: scipy; extra == 'io'
Requires-Dist: scitex-io>=0.2.0; extra == 'io'
Requires-Dist: tqdm; extra == 'io'
Requires-Dist: xarray; extra == 'io'
Requires-Dist: xlrd; extra == 'io'
Requires-Dist: zarr; extra == 'io'
Provides-Extra: linalg
Requires-Dist: geom-median; extra == 'linalg'
Requires-Dist: joblib; extra == 'linalg'
Requires-Dist: matplotlib; extra == 'linalg'
Requires-Dist: scipy; extra == 'linalg'
Requires-Dist: sympy; extra == 'linalg'
Requires-Dist: xarray; extra == 'linalg'
Provides-Extra: linter
Requires-Dist: scitex-linter>=0.3.5; extra == 'linter'
Provides-Extra: logging
Requires-Dist: matplotlib; extra == 'logging'
Requires-Dist: scitex-logging>=0.1.2; extra == 'logging'
Provides-Extra: media
Provides-Extra: ml
Requires-Dist: anthropic; extra == 'ml'
Requires-Dist: google-genai; extra == 'ml'
Requires-Dist: groq; extra == 'ml'
Requires-Dist: imbalanced-learn; extra == 'ml'
Requires-Dist: joblib; extra == 'ml'
Requires-Dist: markdown2; extra == 'ml'
Requires-Dist: matplotlib; extra == 'ml'
Requires-Dist: natsort; extra == 'ml'
Requires-Dist: openai; extra == 'ml'
Requires-Dist: pillow; extra == 'ml'
Requires-Dist: pyyaml; extra == 'ml'
Requires-Dist: requests; extra == 'ml'
Requires-Dist: ruamel-yaml; extra == 'ml'
Requires-Dist: scikit-learn; extra == 'ml'
Requires-Dist: scipy; extra == 'ml'
Requires-Dist: seaborn; extra == 'ml'
Requires-Dist: sktime>=0.21.0; extra == 'ml'
Requires-Dist: umap-learn; extra == 'ml'
Requires-Dist: xarray; extra == 'ml'
Provides-Extra: module
Provides-Extra: msword
Requires-Dist: pypandoc; extra == 'msword'
Requires-Dist: python-docx; extra == 'msword'
Provides-Extra: nn
Requires-Dist: h5py; extra == 'nn'
Requires-Dist: ipdb; extra == 'nn'
Requires-Dist: joblib; extra == 'nn'
Requires-Dist: matplotlib; extra == 'nn'
Requires-Dist: readchar; extra == 'nn'
Requires-Dist: ruamel-yaml; extra == 'nn'
Requires-Dist: seaborn; extra == 'nn'
Requires-Dist: tensorpac; extra == 'nn'
Requires-Dist: xarray; extra == 'nn'
Provides-Extra: notebook
Requires-Dist: scitex-notebook>=0.1.0; extra == 'notebook'
Provides-Extra: notification
Requires-Dist: scitex-notification>=0.1.0; extra == 'notification'
Provides-Extra: orochi
Requires-Dist: scitex-orochi>=0.13.0; extra == 'orochi'
Provides-Extra: os
Provides-Extra: parallel
Requires-Dist: scitex-parallel>=0.1.1; extra == 'parallel'
Requires-Dist: tqdm; extra == 'parallel'
Provides-Extra: path
Requires-Dist: gitpython; extra == 'path'
Requires-Dist: matplotlib; extra == 'path'
Requires-Dist: scitex-path>=0.1.2; extra == 'path'
Provides-Extra: pd
Requires-Dist: xarray; extra == 'pd'
Provides-Extra: plt
Requires-Dist: figrecipe>=0.16.0; extra == 'plt'
Requires-Dist: joblib; extra == 'plt'
Requires-Dist: matplotlib; extra == 'plt'
Requires-Dist: piexif; extra == 'plt'
Requires-Dist: pillow; extra == 'plt'
Requires-Dist: pyyaml; extra == 'plt'
Requires-Dist: ruamel-yaml; extra == 'plt'
Requires-Dist: scipy; extra == 'plt'
Requires-Dist: seaborn; extra == 'plt'
Requires-Dist: termplotlib; extra == 'plt'
Requires-Dist: xarray; extra == 'plt'
Provides-Extra: project
Provides-Extra: repro
Requires-Dist: matplotlib; extra == 'repro'
Requires-Dist: scitex-repro>=0.1.2; extra == 'repro'
Provides-Extra: reproduce
Requires-Dist: matplotlib; extra == 'reproduce'
Requires-Dist: scitex-repro>=0.1.2; extra == 'reproduce'
Provides-Extra: resource
Requires-Dist: h5py; extra == 'resource'
Requires-Dist: joblib; extra == 'resource'
Requires-Dist: matplotlib; extra == 'resource'
Requires-Dist: psutil; extra == 'resource'
Requires-Dist: pyyaml; extra == 'resource'
Requires-Dist: readchar; extra == 'resource'
Requires-Dist: ruamel-yaml; extra == 'resource'
Requires-Dist: scipy; extra == 'resource'
Provides-Extra: rng
Requires-Dist: matplotlib; extra == 'rng'
Requires-Dist: scitex-repro>=0.1.2; extra == 'rng'
Provides-Extra: schema
Provides-Extra: scholar
Requires-Dist: aiohttp; extra == 'scholar'
Requires-Dist: beautifulsoup4; extra == 'scholar'
Requires-Dist: bibtexparser; extra == 'scholar'
Requires-Dist: connectedpapers-py; extra == 'scholar'
Requires-Dist: crawl4ai; extra == 'scholar'
Requires-Dist: crossref-local; extra == 'scholar'
Requires-Dist: feedparser; extra == 'scholar'
Requires-Dist: html2text; extra == 'scholar'
Requires-Dist: httpx; extra == 'scholar'
Requires-Dist: matplotlib; extra == 'scholar'
Requires-Dist: natsort; extra == 'scholar'
Requires-Dist: nest-asyncio; extra == 'scholar'
Requires-Dist: openalex-local; extra == 'scholar'
Requires-Dist: openpyxl; extra == 'scholar'
Requires-Dist: pdfplumber; extra == 'scholar'
Requires-Dist: pillow; extra == 'scholar'
Requires-Dist: playwright>=1.40.0; extra == 'scholar'
Requires-Dist: pydantic; extra == 'scholar'
Requires-Dist: pymed; extra == 'scholar'
Requires-Dist: pymupdf; extra == 'scholar'
Requires-Dist: pypdf; extra == 'scholar'
Requires-Dist: pytesseract; extra == 'scholar'
Requires-Dist: python-docx; extra == 'scholar'
Requires-Dist: pyyaml; extra == 'scholar'
Requires-Dist: requests; extra == 'scholar'
Requires-Dist: ruamel-yaml; extra == 'scholar'
Requires-Dist: scholarly; extra == 'scholar'
Requires-Dist: scikit-learn; extra == 'scholar'
Requires-Dist: scitex-scholar>=1.2.1; extra == 'scholar'
Requires-Dist: seaborn; extra == 'scholar'
Requires-Dist: selenium; extra == 'scholar'
Requires-Dist: sql-manager; extra == 'scholar'
Requires-Dist: sqlalchemy; extra == 'scholar'
Requires-Dist: tenacity; extra == 'scholar'
Requires-Dist: tqdm; extra == 'scholar'
Requires-Dist: watchdog; extra == 'scholar'
Requires-Dist: webdriver-manager; extra == 'scholar'
Provides-Extra: scholar-gui
Requires-Dist: click; extra == 'scholar-gui'
Requires-Dist: crossref-local; extra == 'scholar-gui'
Requires-Dist: flask>=2.0.0; extra == 'scholar-gui'
Requires-Dist: openalex-local; extra == 'scholar-gui'
Provides-Extra: security
Provides-Extra: session
Requires-Dist: matplotlib; extra == 'session'
Requires-Dist: pyyaml; extra == 'session'
Provides-Extra: sh
Requires-Dist: matplotlib; extra == 'sh'
Provides-Extra: social
Requires-Dist: socialia>=0.3.1; extra == 'social'
Provides-Extra: stats
Requires-Dist: matplotlib; extra == 'stats'
Requires-Dist: scipy; extra == 'stats'
Requires-Dist: scitex-stats>=0.2.0; extra == 'stats'
Requires-Dist: statsmodels; extra == 'stats'
Requires-Dist: tabulate; extra == 'stats'
Provides-Extra: str
Requires-Dist: matplotlib; extra == 'str'
Requires-Dist: natsort; extra == 'str'
Requires-Dist: scitex-str>=0.1.1; extra == 'str'
Requires-Dist: xarray; extra == 'str'
Provides-Extra: template
Requires-Dist: scitex-template>=0.1.0; extra == 'template'
Provides-Extra: tex
Requires-Dist: matplotlib; extra == 'tex'
Provides-Extra: torch
Requires-Dist: torch; extra == 'torch'
Provides-Extra: tunnel
Requires-Dist: scitex-tunnel; extra == 'tunnel'
Provides-Extra: types
Requires-Dist: scitex-types>=0.1.2; extra == 'types'
Requires-Dist: xarray; extra == 'types'
Provides-Extra: ui
Requires-Dist: scitex-ui>=0.4.7; extra == 'ui'
Provides-Extra: utils
Requires-Dist: h5py; extra == 'utils'
Requires-Dist: matplotlib; extra == 'utils'
Requires-Dist: natsort; extra == 'utils'
Requires-Dist: tqdm; extra == 'utils'
Requires-Dist: xarray; extra == 'utils'
Provides-Extra: verify
Requires-Dist: scitex-clew>=0.2.5; extra == 'verify'
Provides-Extra: web
Requires-Dist: aiohttp; extra == 'web'
Requires-Dist: anthropic; extra == 'web'
Requires-Dist: beautifulsoup4; extra == 'web'
Requires-Dist: google-genai; extra == 'web'
Requires-Dist: groq; extra == 'web'
Requires-Dist: joblib; extra == 'web'
Requires-Dist: markdown2; extra == 'web'
Requires-Dist: matplotlib; extra == 'web'
Requires-Dist: openai; extra == 'web'
Requires-Dist: pillow; extra == 'web'
Requires-Dist: pytest-asyncio; extra == 'web'
Requires-Dist: readability-lxml; extra == 'web'
Requires-Dist: requests; extra == 'web'
Requires-Dist: ruamel-yaml; extra == 'web'
Requires-Dist: scikit-learn; extra == 'web'
Requires-Dist: scipy; extra == 'web'
Requires-Dist: seaborn; extra == 'web'
Requires-Dist: tqdm; extra == 'web'
Requires-Dist: xarray; extra == 'web'
Provides-Extra: writer
Requires-Dist: csv2latex; extra == 'writer'
Requires-Dist: gitpython; extra == 'writer'
Requires-Dist: matplotlib; extra == 'writer'
Requires-Dist: pytest-asyncio; extra == 'writer'
Requires-Dist: scitex-writer; extra == 'writer'
Requires-Dist: xlsx2csv; extra == 'writer'
Requires-Dist: yq; extra == 'writer'
Description-Content-Type: text/markdown

<!-- ---
!-- Timestamp: 2026-03-23 01:22:48
!-- Author: ywatanabe
!-- File: /home/ywatanabe/proj/scitex-python/README.md
!-- --- -->

# SciTeX (<code>scitex</code>)

<p align="center">
  <a href="https://scitex.ai">
    <img src="docs/assets/images/scitex-logo-blue-cropped.png" alt="SciTeX" width="400">
  </a>
</p>

<p align="center"><b>Python Library for Science. For AI and Human Researchers</b></p>

<p align="center">
  <a href="https://badge.fury.io/py/scitex"><img src="https://badge.fury.io/py/scitex.svg" alt="PyPI version"></a>
  <a href="https://pypi.org/project/scitex/"><img src="https://img.shields.io/pypi/pyversions/scitex.svg" alt="Python Versions"></a>
  <a href="https://scitex-python.readthedocs.io"><img src="https://readthedocs.org/projects/scitex-python/badge/?version=latest" alt="Documentation"></a>
  <a href="https://github.com/ywatanabe1989/scitex-python/blob/main/LICENSE"><img src="https://img.shields.io/github/license/ywatanabe1989/scitex-python" alt="License"></a>
</p>

<p align="center">
  <a href="https://scitex-python.readthedocs.io">Docs</a> &middot;
  <a href="https://scitex-python.readthedocs.io/en/latest/quickstart.html">Quick Start</a> &middot;
  <a href="https://scitex-python.readthedocs.io/en/latest/api/index.html">API</a> &middot;
  <code>pip install scitex[all]</code>
</p>

---

This repository provides `scitex`, the orchestration layer of the SciTeX ecosystem — solving key problems in scientific research:

## Problem and Solution

| # | Problem | Solution |
|---|---------|----------|
| 1 | **Fragmented tools** -- literature search, statistics, figures, and writing each require separate tools with incompatible formats | **Unified toolkit** -- `import scitex as stx` provides 73 modules under one namespace, accessible via Python API, CLI, and MCP. These modules are standalone packages but loosely coupled through a plugin registry — each works on its own, yet composes into designed synergy (save a figure → auto-exports CSV + YAML recipe → hash-tracked by Clew → citeable in scitex-writer). |
| 2 | **No verification** -- existing tools address whether work *could* be reproduced, not whether it *has* been verified | **Cryptographic verification** -- Clew builds SHA-256 hash-chain DAGs linking every manuscript claim back to source data |
| 3 | **AI agents lack context** -- general-purpose LLMs cannot operate across the full research lifecycle without domain-specific tools | **323 MCP tools** -- AI agents run statistics, create figures, search literature, and compile manuscripts through structured tool calls |
| 4 | **No custom tooling** -- every lab needs domain-specific tools, but building and sharing them requires deep infrastructure knowledge | **App Maker and Store** -- researchers create custom apps with [scitex-app](https://github.com/ywatanabe1989/scitex-app) SDK and share via [SciTeX Cloud](https://scitex.ai) |
| 5 | **Vendor lock-in** -- cloud research tools (Overleaf, Zotero, Mendeley, Colab, GitHub Copilot) keep data on third-party servers and depend on APIs that can disappear overnight or monetize tomorrow | **Open and self-hostable** -- every SciTeX package is AGPL-3.0; the full 39-package ecosystem runs on your own hardware (or SciTeX Cloud which itself is self-hostable); cloud integrations are pluggable extras, not requirements |

## SciTeX and Research Workflow

<p align="center">
    <img src="scripts/assets/workflow_out/workflow.png" alt="SciTeX Research Workflow" width="600">
</p>
<p align="center"><sub><b>Figure 1.</b> SciTeX research pipeline -- from literature search to manuscript compilation, with every step cryptographically linked.</sub></p>

## Demo — Automated Research from Data to Manuscript

**40 min, minimal human intervention** — an AI agent using SciTeX completed a full research cycle: literature search, statistical analysis, publication-ready figures, a 21-page manuscript, and peer review simulation. More demos are available at [https://scitex.ai/demos/](https://scitex.ai/demos/).

<p align="center">
  <a href="https://scitex.ai/demos/watch/scitex-automated-research/">
    <img src="docs/assets/images/scitex-demo.gif" alt="SciTeX Demo" width="800">
  </a>
</p>

## Installation

```bash
pip install scitex[all]                # Recommended: everything (may take >1 hour on first install — see Installation Tips)
```

<details>
<summary><strong>Per-module extras</strong></summary>

```bash
pip install scitex                     # Core only (minimal)
pip install scitex[plt,stats,scholar]  # Typical research setup
pip install scitex[plt]                # Publication-ready figures (figrecipe)
pip install scitex[stats]              # Statistical testing (23+ tests)
pip install scitex[scholar]            # Literature search, PDF download, BibTeX enrichment
pip install scitex[writer]             # LaTeX manuscript compilation
pip install scitex[audio]              # Text-to-speech
pip install scitex[ai]                 # LLM APIs (OpenAI, Anthropic, Google) + ML tools
pip install scitex[dataset]            # Scientific datasets (DANDI, OpenNeuro, PhysioNet)
pip install scitex[browser]            # Web automation (Playwright)
pip install scitex[capture]            # Screenshot capture and monitoring
pip install scitex[cloud]              # Cloud platform integration
```

Requires Python 3.10+. We recommend [uv](https://docs.astral.sh/uv/) for fast installs.
</details>

<details>
<summary><strong>Installation Tips — timeouts, mirrors, <code>[all]</code> size</strong></summary>

`pip install scitex[all]` pulls the full 33-package ecosystem plus heavy extras (playwright browsers, torch, jax, pymupdf, Apptainer/Docker integrations, etc.). On a typical connection it can take **30–90 minutes** — more if PyPI is slow. Common fixes:

```bash
# 1. Extend pip's socket timeout (default 15s) — stops big wheel pulls from aborting mid-stream
pip install --timeout 600 --retries 5 "scitex[all]"

# 2. Use uv — 10-30× faster resolver, far better retry behaviour
pip install uv && uv pip install "scitex[all]"

# 3. Install in groups if a single run keeps failing
pip install scitex[io,stats,plt]         # core analysis layer first
pip install scitex[scholar,writer]       # research layer
pip install scitex[audio,browser,dataset,cloud]   # heavy extras last

# 4. Mirror — for networks where pypi.org is unreliable
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple "scitex[all]"
```

If a single dep hangs, identify it with `pip install -v` and install that package alone with `--no-deps`, then resume the full install.
</details>

<details>
<summary><strong>Module Overview</strong></summary>

| Category | Modules | Description |
|----------|---------|-------------|
| **Core** | `session`, `io`, `config`, `clew` | Experiment tracking, file I/O, config, cryptographic verification |
| **Analysis** | `stats`, `plt`, `dsp`, `linalg` | Statistics, plotting, signal processing, linear algebra |
| **Research** | `scholar`, `writer`, `diagram`, `canvas` | Literature, manuscripts, diagrams, figure composition |
| **ML/AI** | `ai`, `nn`, `torch`, `cv`, `benchmark` | LLM APIs, neural networks, PyTorch, computer vision |
| **Data** | `pd`, `db`, `dataset`, `schema` | Pandas utilities, databases, scientific datasets |
| **Infra** | `app`, `cloud`, `tunnel`, `container` | App SDK, cloud, SSH tunnels, containers |
| **Automation** | `browser`, `capture`, `audio`, `notification` | Web automation, screenshots, TTS, notifications |
| **Dev** | `dev`, `template`, `linter`, `introspect` | Ecosystem tools, scaffolding, code analysis |

</details>

## Packages — 3-Layer Cascade Architecture

The 33-package ecosystem follows a strict **dependency cascade**: upstream imports middle imports downstream, never the reverse. Downstream apps must work standalone; the umbrella only orchestrates.

```
Upstream (orchestration — SOC, integration tests only)
    scitex (scitex-python), scitex-cloud
        │ imports / re-exposes
        ▼
Middle (shared infrastructure — wraps, doesn't replace)
    scitex-io, scitex-stats, scitex-app, scitex-ui, scitex-audio, scitex-dev
        │ integrates / wraps via plugin registry
        ▼
Downstream (standalone apps — own IO/GUI, unit tests)
    figrecipe, scitex-writer, scitex-scholar, scitex-clew, scitex-notebook,
    scitex-dataset, scitex-tunnel, scitex-container, scitex-browser, scitex-linter,
    openalex-local, crossref-local, socialia, + utility leaves
    (scitex-{path,str,dict,logging,types,db,repro,audit,parallel,compat,gists,etc,core})
```

**One-line contract**: downstream does not know upstream exists; upstream does not duplicate downstream logic. See [07_arch-upstream-and-downstream](src/scitex/_skills/general/01_arch_01_upstream-and-downstream.md) for full rules (testing, cascade, interfaces) and [08_arch-dependency-and-version-pinning](src/scitex/_skills/general/01_arch_02_dependency-and-version-pinning.md) for dep-pinning.

## Quick Start

<details>
<summary><strong><code>@scitex.session</code> -- Reproducible Experiment Tracking</strong></summary>

One decorator gives you: auto-CLI, YAML config injection, random seed fixation, structured output, and logging.

```python
import scitex as stx
import numpy as np

@stx.session
def main(
    data_path: str = "./data.csv",   # --data-path data.csv
    n_samples: int = 100,            # --n-samples 200
    CONFIG=stx.session.INJECTED,     # Aggregated ./config/*.yaml
    plt=stx.session.INJECTED,        # Pre-configured matplotlib
    logger=stx.session.INJECTED,     # Session logger
):
    """Analyze data. Docstring becomes --help text."""
    
    # Load
    data = stx.io.load(data_path)
    
    # Demo data
    x = np.linspace(0, 2 * np.pi, n_samples)
    y = np.sin(x) + np.random.randn(n_samples) * 0.1
    
    # FigRecipe Plot
    fig, ax = stx.plt.subplots()
    ax.plot(x, y)
    ax.set_xyt("Time", "Amplitude", "Noisy Sine Wave")
    
    # Save sine.png + sine.csv with logging message
    stx.io.save(fig, "sine.png")
    
    return 0

if __name__ == "__main__":
    main()
```

```bash
$ python script.py --data-path experiment.csv --n-samples 200
$ python script.py --help
# usage: script.py [-h] [--data-path DATA_PATH] [--n-samples N_SAMPLES]
# Analyze data. Docstring becomes --help text.
```

```
script_out/FINISHED_SUCCESS/2026-03-18_14-30-00_Z5MR/
├── sine.png, sine.csv         # Figure + auto-exported plot data
├── CONFIGS/CONFIG.yaml        # Frozen parameters
└── logs/{stdout,stderr}.log   # Execution logs
```

The injected `CONFIG` is a `DotDict` merging YAML user configs with session-resolved keys:

| Key | Meaning |
|-----|---------|
| `CONFIG.ID` | Session identifier, e.g. `2026-04-23T21-30-00_Z5MR` |
| `CONFIG.PID` | Python process ID |
| `CONFIG.START_DATETIME` | When the session started |
| `CONFIG.FILE` | Path to caller script |
| `CONFIG.SDIR_OUT` | Base output dir, e.g. `analysis_out/` |
| `CONFIG.SDIR_RUN` | This run's dir, e.g. `analysis_out/FINISHED_SUCCESS/<ID>/` |
| `CONFIG.ARGS` | Parsed CLI args |
| `CONFIG.MODEL.*` | Values from `./config/MODEL.yaml` (one namespace per YAML file) |

Use `CONFIG.SDIR_RUN / "results.csv"` to re-load a file saved earlier in the same session. A frozen copy of `CONFIG` is persisted to `CONFIG.SDIR_RUN/CONFIGS/{CONFIG.yaml,CONFIG.pkl}` so any run is fully auditable. See [25_session-config](./src/scitex/_skills/general/07_api_01_session-config.md) for the full reference.
</details>


<details>
<summary><strong><code>scitex.io</code> -- Unified File I/O (50+ Formats)</strong></summary>

```python
import scitex as stx

# Save and load -- format detected from extension.
# symlink_from_cwd=True drops a symlink at cwd so round-trip by filename works;
# without it, save() routes to <script>_out/ and load() must use an absolute path.
stx.io.save(df, "results.csv", symlink_from_cwd=True)
df = stx.io.load("results.csv")

stx.io.save(arr, "data.npy", symlink_from_cwd=True)
arr = stx.io.load("data.npy")

stx.io.save(fig, "figure.png")       # Also exports figure data as CSV
stx.io.save(config, "config.yaml")
stx.io.save(model, "model.pkl")

# Aggregate ./config/*.yaml into a single DotDict
CONFIG = stx.io.load_configs(config_dir="./config")
print(CONFIG.MODEL.hidden_size)      # Dot-notation access

# Register custom formats
@stx.io.register_saver(".custom")
def save_custom(obj, path, **kw):
    with open(path, "w") as f:
        f.write(str(obj))

@stx.io.register_loader(".custom")
def load_custom(path, **kw):
    with open(path) as f:
        return f.read()
```

Supports: CSV, JSON, YAML, TOML, HDF5, NPY, NPZ, PKL, PNG, JPG, SVG, PDF, Excel, Parquet, Zarr, INI, TXT, MAT, WAV, MP3, BibTeX, and more.

**Built-in features**: Auto directory creation, path resolution to `<script_name>_out/`, symlinks (`symlink_from_cwd=True`), save logging with file size, and Clew hash tracking.
</details>

<details>
<summary><strong><code>scitex.plt</code> -- Reproducible, Restylable Figures</strong></summary>

Powered by [figrecipe](https://github.com/ywatanabe1989/figrecipe). Figures are **reproducible nodes** in the Clew verification DAG -- scientific data and visual style are decomposed, so figures can be restyled (fonts, colors, layout) without altering the underlying data hash. Every figure auto-exports its data as CSV + a YAML recipe for exact reproduction.

```python
import scitex as stx
fig, axes = stx.plt.subplots(1, 3)
axes[0].stx_line(x, y)
axes[0].set_xyt("Time", "Value", "Line")

axes[1].stx_violin([g1, g2, g3])
axes[1].set_xyt("Group", "Score", "Violin")

axes[2].stx_heatmap(corr_matrix)
axes[2].set_xyt("X", "Y", "Heatmap")
stx.io.save(fig, "analysis.png")  # Saves analysis.png + analysis.csv + analysis.yaml

# Restyle without changing data (hash stays valid for Clew verification)
stx.plt.reproduce("analysis.yaml", style="nature")
```
</details>

<details>
<summary><strong><code>scitex.stats</code> -- Publication-Ready Statistics (23+ Tests)</strong></summary>

```python
import scitex as stx
result = stx.stats.run_test("ttest_ind", group1, group2, return_as="dataframe")
# Returns: p-value, effect size (Cohen's d), CI, normality check, power
recommendations = stx.stats.recommend_tests(data)
stx.stats.annotate(ax, test=result, style="apa")   # stars + "t(58) = 2.34, p = .021, d = 0.60" on a matplotlib Axes
```
</details>

<details>
<summary><strong><code>scitex.scholar</code> -- Literature Management</strong></summary>

Search, download, enrich papers. Backed by local CrossRef (167M+) and OpenAlex (250M+) databases.

```python
import scitex as stx
scholar = stx.scholar.Scholar()                             # lazy-load library
papers = scholar.process_papers(["neural oscillations working memory"])
scholar.download_pdfs_from_dois(["10.1038/s41586-024-07804-3"])
scholar.enrich_papers(bibtex_path="references.bib")
```

```bash
scitex scholar search "neural oscillations" --n 20
scitex scholar bibtex references.bib --output enriched.bib
```
</details>

<details>
<summary><strong><code>scitex.writer</code> -- LaTeX Manuscript Compilation</strong></summary>

```python
import scitex as stx
stx.writer.compile.manuscript("paper/")                     # latexmk wrapper
stx.writer.figures.add("paper/", "results.png", caption="Main results")
stx.writer.tables.add("paper/", "stats.csv", caption="Statistical summary")
```
</details>

<details>
<summary><strong><code>scitex.notification</code> -- Multi-Backend Notifications</strong></summary>

Get notified when experiments finish -- via desktop, phone call, SMS, or email -- with automatic fallback.

```python
import scitex as stx
stx.notification.alert("Experiment complete: accuracy = 94.2%")
stx.notification.call("Training diverged -- loss is NaN")
stx.notification.sms("GPU job finished on node-42")

@stx.session(notify=True)   # Notifies on completion or failure
def main(CONFIG=stx.session.INJECTED): ...
```
</details>

<details>
<summary><strong><code>scitex.clew</code> -- Cryptographic Verification for AI-Driven Science</strong></summary>

As AI agents produce research at scale, the question shifts from *"could this be reproduced?"* to *"has this been verified?"*. Clew builds a **SHA-256 hash-chain DAG** linking every manuscript claim back to source data.

```python
import scitex as stx

# Every stx.io.load/save automatically records file hashes -- zero config
stx.clew.status()                          # {'verified': 12, 'mismatched': 0, 'missing': 0}
stx.clew.chain("results/figure1.png")      # Trace one file back to source data
stx.clew.dag(claims=True)                  # Verify all manuscript claims

# Register traceable assertions
stx.clew.add_claim(
    file_path="paper/main.tex", claim_type="statistic", line_number=142,
    claim_value="t(58) = 2.34, p = .021",
    source_session="2026-03-18_14-30-00_Z5MR", source_file="results/stats.csv",
)

stx.clew.mermaid(claims=True)              # Visualize provenance DAG
```

| Mode | Function | Answers |
|------|----------|---------|
| **Project** | `clew.dag()` | Is the whole project intact? |
| **File** | `clew.chain("output.csv")` | Can I trust this specific file? |
| **Claim** | `clew.verify_claim("Fig 1")` | Is this manuscript assertion valid? |

**L1** hash comparison (ms) / **L2** sandbox re-execution (min) / **L3** registered timestamp proof (optional).

<p align="center">
  <img src="docs/clew-dag.png" alt="Clew DAG" width="300">
</p>
<p align="center"><sub><b>Figure 2.</b> Clew verification DAG -- green nodes are verified (hash match), red nodes have mismatches. Each node shows its SHA-256 hash prefix.</sub></p>

</details>

<details>
<summary><strong><code>scitex.audio</code> -- Text-to-Speech (ElevenLabs / LuxTTS / gTTS / pyttsx3)</strong></summary>

```python
import scitex as stx
stx.audio.speak("Training complete. Accuracy ninety-four percent.")
stx.audio.speak("Offline only", backend="pyttsx3")                  # force offline
stx.audio.speak("Report", output_path="report.mp3", play=False)     # TTS → file
```
Backends fall back automatically: ElevenLabs (paid, highest) → LuxTTS (offline, 48 kHz, voice-cloning) → gTTS (free online) → pyttsx3 (offline espeak).
</details>

<details>
<summary><strong><code>scitex.dataset</code> -- OpenNeuro / DANDI / PhysioNet / Zenodo Fetcher</strong></summary>

```python
import scitex as stx
ds = stx.dataset.neuroscience.openneuro.fetch_all_datasets(max_datasets=10)
stx.dataset.neuroscience.dandi.fetch_all_datasets(max_datasets=10)
hits = stx.dataset.search_datasets(ds, text_query="phase-amplitude coupling")
```
Uniform API across neuroscience / biomedical / clinical-trial repositories.
</details>

<details>
<summary><strong><code>scitex.container</code> -- Apptainer / Docker Management</strong></summary>

```python
import scitex as stx
stx.container.apptainer.build(def_name="recipe")        # versioned SIF
stx.container.apptainer.switch_version("2.19.5")        # atomic active-SIF flip
stx.container.apptainer.rollback()                      # revert to previous
snap = stx.container.env_snapshot()                     # full env for papers
```
Reproducible HPC containers — build, version, rollback, env-snapshot for manuscripts.
</details>

<details>
<summary><strong><code>scitex.tunnel</code> -- Persistent SSH Reverse Tunnels</strong></summary>

```python
import scitex as stx
stx.tunnel.setup(port=8888, bastion_server="gw.example.com")
stx.tunnel.status()                                     # {"8888": "active"}
```
NAT traversal for lab machines — autossh-backed systemd service.
</details>

<details>
<summary><strong><code>scitex.linter</code> -- 47-Rule Convention Checker</strong></summary>

```python
import scitex as stx
issues = stx.linter.lint_file("src/")
for i in issues:
    print(f"{i.filepath}:{i.line} [{i.rule.id}] {i.message}")
```
Lints SciTeX projects for ecosystem conventions (`stx.io.save` usage, CONFIGS naming, matplotlib prefs, import hygiene). Complements ruff/flake8.
</details>

<details>
<summary><strong><code>scitex.repro</code> -- Seed Everything + Array Hashing</strong></summary>

```python
import scitex as stx
rng = stx.repro.RandomStateManager(seed=42)             # seeds random + numpy + torch + tf
run_id = stx.repro.gen_ID()                             # "20260423_2155_abc12345"
digest = stx.repro.hash_array(np_array)                 # deterministic SHA
```
One call seeds every RNG; generates experiment-run IDs; hashes arrays for fingerprinting.
</details>

<details>
<summary><strong><code>scitex.parallel</code> -- Threaded Map with tqdm</strong></summary>

```python
import scitex as stx
results = stx.parallel.run(download, [(u,) for u in urls], n_jobs=-1)
```
Drop-in parallel map for I/O-bound work — HTTP fetches, file reads, API calls. tqdm progress bar built-in.
</details>

<details>
<summary><strong><code>scitex.path</code> -- Project-Aware Paths &amp; Session Dirs</strong></summary>

```python
import scitex as stx
root = stx.path.find_git_root()                     # walk up for .git/
out = stx.path.get_spath("results.csv")             # → {script}_out/results.csv
stx.path.create_relative_symlink(src, dst)          # relative (portable) symlink
latest = stx.path.find_latest(".", "model_", ".pt") # model_v003.pt (highest version)
stx.path.fix_broken_symlinks("dir/", remove=True)   # cleanup dangling links
```
Auto-routes saves to `{script}_out/` and resolves session-scoped paths so `@stx.session` scripts produce dated, hash-trackable output dirs with no boilerplate.
</details>

<details>
<summary><strong><code>scitex.logging</code> -- Extended Logging + Exception Hierarchy + Tee</strong></summary>

```python
import scitex as stx
logger = stx.logging.getLogger(__name__)
logger.success("Training converged at epoch 87")    # SUCCESS level (custom)
logger.fail("Validation loss diverged")             # FAIL level (custom)

# Structured warnings with SciTeX categories
stx.logging.warn_deprecated("old_api", replacement="new_api", version="3.0")
stx.logging.warn_data_loss("NaN values dropped in column 'bp'")

# Typed exceptions (30+ subclasses of SciTeXError)
raise stx.logging.ShapeError("expected (N, 2), got (N, 3)")

# Tee stdout/stderr to a log file
with stx.logging.Tee("run.log"):
    main()                                           # prints go to screen + file
```
Extends stdlib `logging` with SUCCESS/FAIL levels, a 30+ class exception tree (`IOError`/`ShapeError`/`ConfigKeyError`/...), structured warning categories, and tee-to-file. `SCITEX_LOGGING_LEVEL` env var sets default at import.
</details>

<details>
<summary><strong><code>scitex.db</code> -- SQLite3 / PostgreSQL with ndarray BLOB Storage</strong></summary>

```python
import scitex as stx, numpy as np

db = stx.db.SQLite3("experiments.db")
with db:                                             # context-manager transaction
    db.execute("CREATE TABLE IF NOT EXISTS runs (id TEXT, acc REAL)")
    db.save_array("weights_epoch_87", np.random.rand(1024, 1024))   # compressed BLOB

df = db.to_df("runs")                                # pandas round-trip
w = db.load_array("weights_epoch_87")                # typed ndarray back
db.check_health()                                    # integrity + schema drift
stx.db.delete_duplicates(conn, "runs", columns=["id"])
```
SQLite / PostgreSQL clients with first-class compressed-ndarray BLOBs, dataframe round-trips, health checks, and duplicate removal. Drop-in replacement for hand-rolling `pickle → BLOB` storage or SQLAlchemy Core when you don't need an ORM.
</details>

<details>
<summary><strong><code>scitex.browser</code> -- Playwright Helpers for Scientific Scraping</strong></summary>

```python
import scitex as stx, asyncio

async def grab_pdf():
    async with stx.browser.SyncBrowserSession() as session:
        page = await session.new_page()
        await page.goto("https://journal.example/article/123")
        await stx.browser.click_with_fallbacks_async(
            page, ["button.download-pdf", "a[href$='.pdf']"]   # fall through selectors
        )
        await stx.browser.save_as_pdf_async(page, "article.pdf")

asyncio.run(grab_pdf())
```
Playwright wrappers with: Chrome-PDF-viewer download helper, popup/cookie dismissers (`close_popups_async`, `PopupHandler`), cursor/click/step overlays for debug video recording, console-log collectors, test-failure artifact capture. Drop-in replacement for raw Playwright scripts + stealth plugins.
</details>

<details>
<summary><strong>Utility modules — lower-level helpers</strong></summary>

| Module | Purpose | Key API |
|--------|---------|---------|
| `stx.str` | Text / LaTeX fallback / colored prints | `printc`, `safe_latex_render`, `grep` |
| `stx.dict` | `DotDict` + safe merge / flatten | `DotDict`, `safe_merge`, `flatten` |
| `stx.types` | Union type aliases + predicates | `ArrayLike`, `ColorLike`, `is_array_like` |
| `stx.audit` | Unified security scan (bandit / shellcheck / pip-audit) | `audit()` |
| `stx.compat` | Deprecation shims | `@deprecated`, `notify` legacy alias |
| `stx.etc` | Terminal keypress helpers | `wait_key`, `count` |

See [docs/05_ADDITIONAL_MODULES.md](./docs/05_ADDITIONAL_MODULES.md) for full examples.
</details>

> **[Agentic usage](./docs/06_AGENTIC_USAGE.md)** — MCP setup, example prompts, real one-shot outputs, and skill-trigger testing.

> **[Full API reference](https://scitex-python.readthedocs.io/en/latest/api/index.html)** &middot; **[Examples](./examples/)** &middot; **[Module status](./docs/04_MODULE_STATUS.md)**

<details>
<summary><strong>CLI Commands</strong></summary>

```bash
scitex --help-recursive                  # Show all commands
scitex scholar search "topic"            # Search literature
scitex scholar fetch "10.1038/..."       # Download paper by DOI
scitex stats recommend                   # Suggest statistical tests
scitex clew status                       # Project verification overview
scitex clew dag --claims                 # Verify all manuscript claims
scitex audio speak "Analysis complete"   # Text-to-speech
scitex notification alert "Job finished" # Multi-backend notification
scitex template clone research my_proj   # Scaffold a project
scitex dev versions                      # Check ecosystem versions
scitex mcp list-tools                    # List all MCP tools (323)
```

> **[Full CLI reference](./docs/01_CLI_COMMANDS.md)**
</details>

<details>
<summary><strong>MCP Server (323 tools across 23 modules)</strong></summary>

Turn AI agents into autonomous researchers via [MCP](https://modelcontextprotocol.io/).

| Category | Tools | | Category | Tools | | Category | Tools |
|----------|-------|-|----------|-------|-|----------|-------|
| plt | 73 | | crossref | 15 | | io | 5 |
| cloud | 50 | | dev | 13 | | template | 4 |
| writer | 38 | | introspect | 12 | | openalex | 4 |
| scholar | 22 | | stats | 10 | | linter | 3 |
| clew | 9 | | dataset | 8 | | social | 3 |
| project | 6 | | notify | 5 | | tunnel | 3 |
| docs | 4 | | ui | 2 | | usage | 2 |

```json
{"mcpServers": {"scitex": {"command": "scitex", "args": ["mcp", "start"],
  "env": {"SCITEX_ENV_SRC": "${SCITEX_ENV_SRC}"}}}}
```

> **[Full MCP reference](./docs/02_MCP_TOOLS.md)**
</details>

## Configuration

```bash
cp -r .env.d.examples .env.d   # 1. Copy examples
$EDITOR .env.d/                # 2. Edit credentials
source .env.d/entry.src        # 3. Source in shell
```

> **[Full configuration reference](./.env.d.examples/README.md)**


## SciTeX Ecosystem

[`scitex-cloud`](https://github.com/ywatanabe1989/scitex-cloud) is a self-hosted web application that serves as a collaborative research workspace — with a built-in Writer, Scholar, and App Store where researchers build custom tools using [`scitex-app`](https://github.com/ywatanabe1989/scitex-app) SDK and [`scitex-ui`](https://github.com/ywatanabe1989/scitex-ui) components, then share them with the community. A live instance is hosted at [scitex.ai](https://scitex.ai).

<!-- hook-bypass: line-limit -->
<details>
<summary><strong>Full Ecosystem (37 packages, grouped by primary interface)</strong></summary>

Each package exposes the ecosystem via up to six interfaces: Python library, CLI, MCP tools, Claude Code skills, hooks, and HTTP. Ratings: ⭐⭐⭐ = primary / canonical surface, ⭐⭐ = strong secondary, ⭐ = thin, — = not provided. Packages are grouped by their *primary* interface — the one users should reach for first.

### Python-first (library API is primary)

| Package | Module | Interfaces | Description |
|---------|--------|-----------|-------------|
| [crossref-local](https://github.com/ywatanabe1989/crossref-local) | `stx.scholar` | Py ⭐⭐⭐ · CLI ⭐⭐ · MCP ⭐⭐ · Skills ⭐⭐ · Hook — · HTTP — | Offline, zero-API-key DOI lookup + full-text search over the CrossRef corpus |
| [openalex-local](https://github.com/ywatanabe1989/openalex-local) | `stx.scholar` | Py ⭐⭐⭐ · CLI ⭐⭐ · MCP ⭐⭐ · Skills ⭐⭐ · Hook — · HTTP — | Offline, zero-API-key search over the full OpenAlex academic corpus |
| [scitex-browser](https://github.com/ywatanabe1989/scitex-browser) | `stx.browser` | Py ⭐⭐⭐ · CLI — · MCP — · Skills ⭐⭐ · Hook — · HTTP — | Playwright wrappers for scientific web scraping + AI-agent browsing |
| [scitex-compat](https://github.com/ywatanabe1989/scitex-compat) | `stx.compat` | Py ⭐⭐⭐ · CLI — · MCP — · Skills ⭐ · Hook — · HTTP — | Backward-compatibility shims for deprecated SciTeX APIs |
| [scitex-core](https://github.com/ywatanabe1989/scitex-core) | `stx.core` | Py ⭐⭐⭐ · CLI — · MCP — · Skills ⭐⭐ · Hook — · HTTP — | Foundation layer for the SciTeX ecosystem |
| [scitex-dataset](https://github.com/ywatanabe1989/scitex-dataset) | `stx.dataset` | Py ⭐⭐⭐ · CLI ⭐ · MCP ⭐⭐ · Skills ⭐⭐ · Hook — · HTTP — | Unified dataset-discovery API across 7 scientific repositories |
| [scitex-db](https://github.com/ywatanabe1989/scitex-db) | `stx.db` | Py ⭐⭐⭐ · CLI ⭐ · MCP — · Skills ⭐⭐ · Hook — · HTTP — | Relational-DB wrapper for scientific Python |
| [scitex-dict](https://github.com/ywatanabe1989/scitex-dict) | `stx.dict` | Py ⭐⭐⭐ · CLI — · MCP — · Skills ⭐ · Hook — · HTTP — | Dictionary utilities for scientific Python |
| [scitex-etc](https://github.com/ywatanabe1989/scitex-etc) | `stx.etc` | Py ⭐⭐⭐ · CLI — · MCP — · Skills ⭐ · Hook — · HTTP — | Miscellaneous SciTeX utilities |
| [scitex-gists](https://github.com/ywatanabe1989/scitex-gists) | `stx.gists` | Py ⭐⭐⭐ · CLI — · MCP — · Skills ⭐ · Hook — · HTTP — | SigmaPlot v12 macro snippets as printable Python functions |
| [scitex-logging](https://github.com/ywatanabe1989/scitex-logging) | `stx.logging` | Py ⭐⭐⭐ · CLI — · MCP — · Skills ⭐⭐ · Hook — · HTTP — | Enhanced Python logging + warnings + exceptions for SciTeX |
| [scitex-parallel](https://github.com/ywatanabe1989/scitex-parallel) | `stx.parallel` | Py ⭐⭐⭐ · CLI — · MCP — · Skills ⭐ · Hook — · HTTP — | Minimal thread-pool parallel execution for scientific Python |
| [scitex-path](https://github.com/ywatanabe1989/scitex-path) | `stx.path` | Py ⭐⭐⭐ · CLI — · MCP — · Skills ⭐⭐ · Hook — · HTTP — | Project-aware path utilities for scientific Python |
| [scitex-plt](https://github.com/ywatanabe1989/scitex-plt) | `stx.plt` | Py ⭐⭐⭐ · CLI — · MCP ⭐⭐⭐ · Skills ⭐⭐ · Hook — · HTTP — | Publication-ready plotting (thin wrapper around figrecipe) |
| [scitex-repro](https://github.com/ywatanabe1989/scitex-repro) | `stx.repro` | Py ⭐⭐⭐ · CLI — · MCP — · Skills ⭐⭐ · Hook — · HTTP — | Reproducibility helpers for scientific Python experiments |
| [scitex-stats](https://github.com/ywatanabe1989/scitex-stats) | `stx.stats` | Py ⭐⭐⭐ · CLI ⭐ · MCP ⭐⭐ · Skills ⭐⭐ · Hook — · HTTP — | Publication-ready statistical testing for 23 tests |
| [scitex-str](https://github.com/ywatanabe1989/scitex-str) | `stx.str` | Py ⭐⭐⭐ · CLI — · MCP — · Skills ⭐⭐ · Hook — · HTTP — | Text-processing utilities for scientific Python |
| [scitex-types](https://github.com/ywatanabe1989/scitex-types) | `stx.types` | Py ⭐⭐⭐ · CLI — · MCP — · Skills ⭐ · Hook — · HTTP — | Type aliases and runtime type guards for scientific Python |

### CLI-first

| Package | Module | Interfaces | Description |
|---------|--------|-----------|-------------|
| [scitex-agent-container](https://github.com/ywatanabe1989/scitex-agent-container) | `stx.agent_container` | Py ⭐⭐ · CLI ⭐⭐⭐ · MCP — · Skills ⭐⭐ · Hook — · HTTP — | Declarative YAML-based AI agent lifecycle management (tmux/screen/SSH) |
| [scitex-app](https://github.com/ywatanabe1989/scitex-app) | `stx.app` | Py ⭐⭐ · CLI ⭐⭐⭐ · MCP ⭐⭐ · Skills ⭐⭐ · Hook — · HTTP — | App-developer SDK for SciTeX workspace apps |
| [scitex-audit](https://github.com/ywatanabe1989/scitex-audit) | `stx.audit` | Py ⭐ · CLI ⭐⭐⭐ · MCP ⭐ · Skills ⭐ · Hook — · HTTP — | Unified repo security scanner for scientific Python projects |
| [scitex-clew](https://github.com/ywatanabe1989/scitex-clew) | `stx.clew` | Py ⭐⭐ · CLI ⭐⭐⭐ · MCP ⭐⭐ · Skills ⭐⭐ · Hook — · HTTP — | Hash-based reproducibility verification for scientific pipelines |
| [scitex-container](https://github.com/ywatanabe1989/scitex-container) | `stx.container` | Py ⭐⭐ · CLI ⭐⭐⭐ · MCP ⭐⭐ · Skills ⭐⭐ · Hook — · HTTP — | Unified container management for Apptainer/Singularity + Docker |
| [scitex-dev](https://github.com/ywatanabe1989/scitex-dev) | `stx.dev` | Py ⭐⭐ · CLI ⭐⭐⭐ · MCP ⭐⭐ · Skills ⭐⭐ · Hook — · HTTP — | Developer utilities for maintaining the whole SciTeX ecosystem |
| [scitex-notebook](https://github.com/ywatanabe1989/scitex-notebook) | `stx.notebook` | Py ⭐⭐ · CLI ⭐⭐⭐ · MCP ⭐ · Skills ⭐⭐ · Hook — · HTTP — | Jupyter notebook reproducibility — verify, compile to DAG, convert to script |
| [scitex-tunnel](https://github.com/ywatanabe1989/scitex-tunnel) | `stx.tunnel` | Py ⭐ · CLI ⭐⭐⭐ · MCP ⭐⭐ · Skills ⭐⭐ · Hook — · HTTP — | Persistent, auto-reconnecting SSH reverse tunnels for NAT traversal |

### MCP-first

| Package | Module | Interfaces | Description |
|---------|--------|-----------|-------------|
| [scitex-audio](https://github.com/ywatanabe1989/scitex-audio) | `stx.audio` | Py ⭐⭐ · CLI ⭐ · MCP ⭐⭐⭐ · Skills ⭐⭐ · Hook — · HTTP — | Unified text-to-speech with automatic backend fallback |
| [socialia](https://github.com/ywatanabe1989/socialia) | `stx.social` | Py ⭐ · CLI ⭐ · MCP ⭐⭐⭐ · Skills ⭐⭐ · Hook — · HTTP — | Unified posting + analytics client for 6 social platforms |

### Hook-first

| Package | Module | Interfaces | Description |
|---------|--------|-----------|-------------|
| [scitex-linter](https://github.com/ywatanabe1989/scitex-linter) | `stx.linter` | Py ⭐ · CLI ⭐⭐ · MCP ⭐ · Skills ⭐⭐ · Hook ⭐⭐⭐ · HTTP — | AST-based linter for reproducible-research Python (pre-commit hook) |

### Mixed (multiple equally-primary interfaces)

| Package | Module | Interfaces | Description |
|---------|--------|-----------|-------------|
| [figrecipe](https://github.com/ywatanabe1989/figrecipe) | `stx.plt` | Py ⭐⭐⭐ · CLI ⭐ · MCP ⭐⭐⭐ · Skills ⭐⭐ · Hook — · HTTP — | Publication-ready matplotlib figures with mm-precision layouts |
| [scitex-cloud](https://github.com/ywatanabe1989/scitex-cloud) | `stx.cloud` | Py ⭐ · CLI ⭐⭐⭐ · MCP ⭐⭐⭐ · Skills ⭐⭐ · Hook — · HTTP ⭐⭐ | SciTeX Cloud operational surface (55 MCP tools) |
| [scitex-io](https://github.com/ywatanabe1989/scitex-io) | `stx.io` | Py ⭐⭐⭐ · CLI ⭐ · MCP ⭐⭐ · Skills ⭐⭐⭐ · Hook — · HTTP — | Universal one-call file I/O for 30+ scientific formats |
| [scitex-notification](https://github.com/ywatanabe1989/scitex-notification) | `stx.notification` | Py ⭐⭐ · CLI ⭐ · MCP ⭐⭐⭐ · Skills ⭐⭐ · Hook — · HTTP — | One-call alerting across 9 backends (audio/desktop/email/Telegram/...) |
| [scitex-orochi](https://github.com/ywatanabe1989/scitex-orochi) | `stx.orochi` | Py ⭐⭐ · CLI ⭐⭐ · MCP ⭐⭐ · Skills ⭐⭐ · Hook — · HTTP ⭐⭐ | Agent Communication Hub — real-time WebSocket messaging between agents |
| [scitex-scholar](https://github.com/ywatanabe1989/scitex-scholar) | `stx.scholar` | Py ⭐⭐⭐ · CLI ⭐⭐⭐ · MCP ⭐⭐ · Skills ⭐⭐ · Hook — · HTTP — | End-to-end scientific-literature toolkit |
| [scitex-ui](https://github.com/ywatanabe1989/scitex-ui) | `stx.ui` | Py ⭐⭐ · CLI ⭐ · MCP ⭐⭐ · Skills ⭐⭐ · Hook — · HTTP ⭐⭐ | Shared frontend framework for SciTeX web apps |
| [scitex-writer](https://github.com/ywatanabe1989/scitex-writer) | `stx.writer` | Py ⭐ · CLI ⭐⭐⭐ · MCP ⭐⭐⭐ · Skills ⭐⭐ · Hook — · HTTP — | End-to-end LaTeX manuscript toolchain (45 MCP tools) |
</details>

>Four Freedoms for Research
>
>0. The freedom to **run** your research anywhere -- your machine, your terms.
>1. The freedom to **study** how every step works -- from raw data to final manuscript.
>2. The freedom to **redistribute** your workflows, not just your papers.
>3. The freedom to **modify** any module and share improvements with the community.
>
>AGPL-3.0 -- because research infrastructure deserves the same freedoms as the software it runs on.

---

<p align="center">
  <a href="https://star-history.com/#ywatanabe1989/scitex-python&Date">
    <img alt="Star History" src="https://api.star-history.com/svg?repos=ywatanabe1989/scitex-python&type=Date" />
  </a>
</p>

<p align="center">
  <a href="https://scitex.ai"><img src="docs/assets/images/scitex-icon-navy-inverted.png" alt="SciTeX" width="40"/></a>
</p>

<!-- EOF -->