Metadata-Version: 2.4
Name: scitex-container
Version: 0.2.1
Summary: Unified container management for Apptainer and Docker
Project-URL: Homepage, https://github.com/ywatanabe1989/scitex-container
Project-URL: Documentation, https://scitex-container.readthedocs.io
Project-URL: Repository, https://github.com/ywatanabe1989/scitex-container.git
Author-email: Yusuke Watanabe <ywatanabe@scitex.ai>
License-Expression: AGPL-3.0-only
License-File: LICENSE
Keywords: apptainer,container,docker,mcp,sandbox,scitex,singularity
Requires-Python: >=3.10
Requires-Dist: click
Requires-Dist: packaging
Requires-Dist: pyyaml
Requires-Dist: scitex-config>=0.3.0
Requires-Dist: scitex-dev>=0.11.7
Provides-Extra: all
Requires-Dist: fastmcp>=2.0.0; extra == 'all'
Provides-Extra: dev
Requires-Dist: fastmcp>=2.0.0; extra == 'dev'
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
Requires-Dist: pytest-timeout>=2.0.0; extra == 'dev'
Requires-Dist: pytest>=7.0.0; extra == 'dev'
Requires-Dist: scitex-dev[cli-audit]>=0.11.7; extra == 'dev'
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: mcp
Requires-Dist: fastmcp>=2.0.0; extra == 'mcp'
Description-Content-Type: text/markdown

# SciTeX Container

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

<p align="center"><b>Unified container management for Apptainer/Singularity and Docker — versioned SIFs, atomic switch/rollback, and reproducible env snapshots.</b></p>

<p align="center">
  <a href="https://scitex-container.readthedocs.io/">Full Documentation</a> · <code>uv pip install scitex-container[all]</code>
</p>

<!-- scitex-badges:start -->
<p align="center">
  <a href="https://pypi.org/project/scitex-container/"><img src="https://img.shields.io/pypi/v/scitex-container?label=pypi" alt="pypi"></a>
  <a href="https://pypi.org/project/scitex-container/"><img src="https://img.shields.io/pypi/pyversions/scitex-container?label=python" alt="python"></a>
  <a href="https://github.com/ywatanabe1989/scitex-container/actions/workflows/rtd-sphinx-build-on-ubuntu-latest.yml"><img src="https://img.shields.io/github/actions/workflow/status/ywatanabe1989/scitex-container/rtd-sphinx-build-on-ubuntu-latest.yml?branch=develop&label=docs" alt="docs"></a>
</p>
<p align="center">
  <a href="https://github.com/ywatanabe1989/scitex-container/actions/workflows/pytest-matrix-on-ubuntu-py3-11-3-12-3-13.yml"><img src="https://img.shields.io/github/actions/workflow/status/ywatanabe1989/scitex-container/pytest-matrix-on-ubuntu-py3-11-3-12-3-13.yml?branch=develop&label=tests" alt="tests"></a>
  <a href="https://github.com/ywatanabe1989/scitex-container/actions/workflows/import-smoke-on-ubuntu-py3-12.yml"><img src="https://img.shields.io/github/actions/workflow/status/ywatanabe1989/scitex-container/import-smoke-on-ubuntu-py3-12.yml?branch=develop&label=install-check" alt="install-check"></a>
  <a href="https://github.com/ywatanabe1989/scitex-container/actions/workflows/newb-docs-quality-on-ubuntu-latest.yml"><img src="https://img.shields.io/github/actions/workflow/status/ywatanabe1989/scitex-container/newb-docs-quality-on-ubuntu-latest.yml?branch=develop&label=quality" alt="quality"></a>
  <a href="https://codecov.io/gh/ywatanabe1989/scitex-container"><img src="https://img.shields.io/codecov/c/github/ywatanabe1989/scitex-container/develop?label=cov" alt="cov"></a>
</p>
<!-- scitex-badges:end -->

---

## Problem and Solution

| # | Problem | Solution |
|---|---------|----------|
| 1 | **"Reproducible" containers drift** -- `Dockerfile` builds a different image each time because `apt-get install python3` floats | **Versioned SIF** -- `scitex-container build` pins the image content hash; `switch-version 2.19.5` is an atomic symlink flip |
| 2 | **Rollback requires docker tags + manual surgery** -- something breaks in prod; reverting to yesterday's container is 15 minutes of yak-shaving | **`rollback` is one command** -- previous active SIF restored; sandbox state preserved |
| 3 | **Paper "env" is `pip freeze`** -- useless without the python version, OS libs, CUDA driver | **`env_snapshot()`** -- full reproducibility capsule: container tag + pip freeze + conda env + apt packages + git commits, serialized as a single file for manuscript attachments |

## Architecture

```
scitex-container/
├── src/scitex_container/
│   ├── __init__.py              # apptainer, docker, host, env_snapshot
│   ├── apptainer/
│   │   ├── _build.py            # build SIF from def file (pinned hash)
│   │   ├── _versions.py         # list / switch / rollback (atomic symlink)
│   │   ├── _verify.py           # SIF + lock-file integrity
│   │   └── _exec.py             # build_exec_args for cloud terminal
│   ├── docker/                  # rebuild / restart compose services
│   ├── host/                    # TeX Live, ImageMagick, bind mounts
│   ├── _snapshot.py             # env_snapshot(): pip + conda + apt + git
│   ├── _cli/                    # scitex-container entrypoint
│   └── _mcp_tools/              # MCP server (opt-in)
└── tests/
```

## Installation

Requires Python >= 3.10.

```bash
pip install scitex-container
```

With MCP server support (for AI agent integration):

```bash
pip install scitex-container[mcp]
```

Full installation:

```bash
pip install scitex-container[all]
```

## Quick Start

```bash
# Unified status dashboard
scitex-container status

# Build Apptainer SIF from definition file
scitex-container build --def-name scitex-final

# Version management
scitex-container list
scitex-container switch 2.19.5
scitex-container rollback

# Show all commands
scitex-container --help-recursive
```

## Four Interfaces

<details open>
<summary><strong>Python API</strong></summary>

<br>

```python
import scitex_container

# Apptainer container management
scitex_container.apptainer.build(def_name="scitex-final", sandbox=True)
scitex_container.apptainer.list_versions(containers_dir="/opt/containers")
scitex_container.apptainer.switch_version("2.19.5", containers_dir="/opt/containers")
scitex_container.apptainer.rollback(containers_dir="/opt/containers")

# Host package management
scitex_container.host.check_packages()

# Docker operations
scitex_container.docker.rebuild(env="prod")
scitex_container.docker.restart(env="prod")

# Environment reproducibility snapshot
snapshot = scitex_container.env_snapshot()
```

<details>
<summary><strong>Verification API</strong></summary>

<br>

```python
from pathlib import Path
import scitex_container

# Verify container integrity
result = scitex_container.apptainer.verify(sif_path="/opt/containers/scitex-final.sif")
# Returns: {sif, def_origin, pip_lock, dpkg_lock, overall}

# Command builder for scitex-cloud terminal integration
args = scitex_container.apptainer.build_exec_args(
    container_path="/opt/containers/scitex-final.sif",
    username="user01",
    host_user_dir=Path("/data/users/user01"),
    host_project_dir=Path("/data/projects/proj01"),
    project_slug="proj01",
    texlive_prefix="/usr",
)
```

</details>

</details>

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

<br>

```bash
scitex-container status                 # Unified dashboard
scitex-container build scitex-final     # Build SIF
scitex-container list                   # List versions
scitex-container switch 2.19.5         # Switch version
scitex-container rollback              # Revert to previous
scitex-container verify                # Verify SIF integrity
scitex-container env-snapshot          # Reproducibility snapshot
```

<details>
<summary><strong>Sandbox Operations</strong></summary>

<br>

```bash
scitex-container sandbox create --sif scitex-final.sif
scitex-container sandbox maintain --sandbox scitex-sandbox/
```

</details>

<details>
<summary><strong>Host Package Management</strong></summary>

<br>

```bash
scitex-container host install          # Install TeX Live + ImageMagick
scitex-container host check            # Verify host packages
scitex-container host mounts           # Show configured bind mounts
```

</details>

<details>
<summary><strong>Docker Operations</strong></summary>

<br>

```bash
scitex-container docker rebuild        # Rebuild Compose services
scitex-container docker restart        # Restart services
```

</details>

</details>

<details>
<summary><strong>MCP Server</strong></summary>

<br>

scitex-container exposes an MCP server so AI agents (Claude, etc.) can manage containers autonomously.

```bash
# Start MCP server
scitex-container-mcp

# Diagnostics and tool listing
scitex-container mcp doctor
scitex-container mcp list-tools -vv
```

| Tool | Description |
|------|-------------|
| `status` | Unified container/host status dashboard |
| `build` | Build SIF from definition file |
| `list` | List available container versions |
| `switch` | Switch active container version |
| `rollback` | Roll back to previous version |
| `sandbox_create` | Create writable sandbox from SIF |
| `docker_rebuild` | Rebuild Docker Compose services |
| `host_install` | Install host-side packages |
| `env_snapshot` | Capture reproducibility snapshot |
| `verify` | Verify SIF integrity against lock files |

</details>

<details>
<summary><strong>Skills</strong></summary>

<br>

Skills provide workflow-oriented guides that AI agents query to discover capabilities and usage patterns.

```bash
scitex-container skills list              # List available skill pages
scitex-container skills get SKILL         # Show main skill page
scitex-dev skills export --package scitex-container  # Export to Claude Code
```

| Skill | Content |
|-------|---------|
| `quick-start` | Install and first-use examples |
| `python-api` | Full Python API with signatures |
| `cli-reference` | CLI commands reference |
| `mcp-tools` | MCP tools for AI agents |
| `environment` | Environment variables |

</details>

## Demo

```mermaid
sequenceDiagram
    participant U as user
    participant SC as scitex-container
    participant FS as /opt/containers
    U->>SC: build --def-name scitex-final
    SC->>FS: scitex-final-2.19.6.sif (pinned)
    U->>SC: switch 2.19.5
    SC->>FS: active.sif -> scitex-final-2.19.5.sif
    U->>SC: rollback
    SC->>FS: active.sif -> scitex-final-2.19.6.sif
    U->>SC: env-snapshot
    SC-->>U: snapshot.json (SIF hash + pip + conda + apt + git)
```

## Part of SciTeX

`scitex-container` is part of [**SciTeX**](https://scitex.ai). Install via
the umbrella with `pip install scitex[container]` to use as
`scitex.container` (Python) or `scitex container ...` (CLI).

```python
import scitex_container

# Capture snapshot for Clew integration
snapshot = scitex_container.env_snapshot()
# snapshot includes: container version, SIF hash, lock files, host packages
```

>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 we believe research infrastructure deserves the same freedoms as the software it runs on.

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

<!-- EOF -->
