# Modules and installation [Handbook](README.md) ยท [Related guide](TESTING.md) DeepTutor has one source repository and disjoint Python distributions. `deeptutor` owns the shared turn runtime, CLI and Python SDK. Feature distributions add code into the same package namespace without overwriting core files. `deeptutor-cli` is a compatibility metapackage: it depends on core and owns no Python files or console scripts. `deeptutor[full]` is an installation profile, not a permanent metapackage that would prevent removing individual applications. The modular distribution family starts with 1.7.0 and must be published together at each release. The 1.6.15 and earlier packages use the previous layout and do not have these boundaries. Local wheel builds are also supported. ## Source checkout ```sh python -m pip install -r requirements/full.txt python -m pip install -e . --no-deps (cd web && npm ci --legacy-peer-deps) deeptutor module list deeptutor module disable solve deeptutor module enable solve ``` In a checkout all source modules are present. `enable` and `disable` exercise the same assembly rules as wheel installs. `install` and `uninstall` deliberately require a wheel environment, so they never delete tracked source files. Source requirements are generated by `python scripts/sync_module_requirements.py`. Use `--check` in CI to detect drift. `requirements/core.txt` and `server.txt` are minimal; `full.txt` supplies the ordinary complete source/Docker runtime. Source archives and Docker images are recognized by the project file and module build script, without requiring `.git`. Optional source dependencies can be added with `python scripts/install_extras.py `; this resolves module requirements without installing duplicate feature wheels over the source tree. ## Optional document parsers For Docling, LiteParse, MarkItDown, or PyMuPDF4LLM, replace `` below with `docling`, `liteparse`, `markitdown`, or `pymupdf4llm`. The Document Parsing settings page does not install packages into a running server. - **Docker:** add `parse-` to `DEEPTUTOR_EXTRAS` in the existing deployment's environment configuration, preserving any other declared extras. Recreate the same service with its existing configuration and mounts (for Compose, use the same project and Compose files with `docker compose up -d`). The entrypoint reapplies these extras on each startup. Installation failures are nonfatal: inspect the service's startup logs before rechecking availability. Data mounts preserve user data, not Python packages in the container. - **Source:** stop DeepTutor, then run `python scripts/install_extras.py parse-` from the checkout using the server's Python environment. Restart the same instance. - **Wheels:** stop DeepTutor, then run `deeptutor module install parser-` in the server's Python environment. Restart with the same runtime home. Do not use this command over a source tree. Return to Document Parsing settings and choose **Recheck availability**. This only refreshes engine availability; it does not install packages. Docling's remote-server mode remains usable without the local package. Model downloads are a separate action after the local package becomes available. ## Independent wheel installation ```sh python scripts/build_modules.py --output dist/modules python -m venv /tmp/deeptutor-modules /tmp/deeptutor-modules/bin/python -m pip install --find-links dist/modules deeptutor /tmp/deeptutor-modules/bin/deeptutor module install solve --wheelhouse dist/modules /tmp/deeptutor-modules/bin/deeptutor module install renderer-manim --wheelhouse dist/modules /tmp/deeptutor-modules/bin/deeptutor module disable solve /tmp/deeptutor-modules/bin/deeptutor module enable solve /tmp/deeptutor-modules/bin/deeptutor module uninstall solve --dry-run /tmp/deeptutor-modules/bin/deeptutor module uninstall solve ``` Use the equivalent `Scripts/python.exe` and `Scripts/deeptutor.exe` on Windows. Run commands with the same `DEEPTUTOR_HOME` as the application. Python packages are installed per environment; enabled state lives in `/data/system/modules.json` and applies to that deployment, not one learner. `--wheelhouse` supplements the package index with locally built wheels. Install `server` for the API, then `web` for packaged Web assets. The Web wheel requires assets produced by `scripts/prepare_web_package.py` for `deeptutor start`; a source development server uses the checkout's `web/` directory. Build and release automation prepares Web assets before building the wheel family. ## Upgrade from 1.6.15 Stop the old process and back up its runtime home. Build the candidate wheels with packaged Web assets first. In a disposable copy of the old environment, upgrade with `python -m pip install --upgrade --find-links dist/modules "deeptutor[full]=="`. If the legacy `deeptutor-cli` is installed, first uninstall it with `python -m pip uninstall deeptutor-cli`, then run the upgrade command, optionally adding the new compatibility alias. The legacy CLI owns the same Python files as the new core: pip installs its new core dependency before removing the old CLI, which deletes the new files. Removing the old CLI first avoids this collision and retains runtime-home data. For CLI-only migration, install `deeptutor-cli==` after that uninstall. Use the exact candidate version to avoid resolving an older published release. Keep `DEEPTUTOR_HOME` unchanged, run `pip check`, inspect `deeptutor module list`, and exercise chat, persisted sessions and Web startup before upgrading the real environment. Never test against the only copy of user data. The bare core upgrade does not retain the old full-app profile. `deeptutor/__version__.py` is the version source for all builds, including the source CLI compatibility package. Extras are templates in `tool.deeptutor.optional-dependencies`; both setuptools and the module builder resolve their internal pins to that version. A release bump must not leave dependencies pointing at the previous module family. ## Ownership and assembly `deeptutor/modules/manifests/*.json` is the authoritative catalog. Each manifest owns paths, dependency requirements, turn capabilities, loop extensions, tool names, API routers and authorization policies, CLI groups, navigation paths and background service callbacks. Longest matching path wins. Shared protocols and lightweight context metadata stay in core; feature implementations stay in their own distribution. The builder rejects overlapping wheel files. | Module family | Contents | | --- | --- | | core | Durable turns, chat, ask-questions, shared tools, CLI/SDK, settings and sessions | | server / web | API and authentication adapters / packaged Next.js assets | | solve / questions / research | Planning loop / question generation / research pipeline | | visualize / renderer-manim | HTML/SVG/chart visualizers / optional Manim pipeline | | video-lesson / audio-overview | Browser lessons / audio overview generation | | knowledge / parsing | Retrieval and ingestion / document parsing implementations | | reading / mastery / books | Reading and watching / guided learning / book application | | memory / notebook / co-writer / calendar | Optional application services and their routes | | partners / providers | Companion runtime and channel SDKs / optional model-provider SDKs | | parser-* | Additional parser dependency distributions, requiring parsing | Dependencies are explicit and acyclic. For example, reading currently requires knowledge, parsing, mastery and notebook because its application uses those stores. Books also requires questions, visualize and mastery for its standard chapter blocks and selected-source grounding. Optional integrations are listed separately: Calendar works without Mastery, Research and Questions work without Knowledge, and Parsing never imports knowledge storage. Selecting an unavailable integration returns an installation hint. Knowledge Frontier requires both Research and Knowledge; a tool contribution can declare additional requirements without forcing those modules onto every use of its owning application. Disabling a dependency is blocked until its enabled dependents are disabled. Uninstalling a dependency is blocked while any installed dependent remains, including disabled dependents. Enabling/installing resolves dependencies in order. Core cannot be disabled or removed. The loader does not import absent or disabled capability/loop implementations. Request schemas are lazy. Loop extensions are instantiated once per turn and activation is re-evaluated as context changes; instances are never shared across turns. Managed plugin revocation is still checked. Background start/stop callbacks remain paired for partial-startup rollback. Existing API authentication policies remain on the contributed routers; module state is not a permission grant. `GET /api/modules` requires authentication and exposes installed, enabled and ready separately. The Runtime settings page displays these states and offline commands. Sidebar and page access use navigation ownership; API route assembly also excludes absent modules, including feature-specific paths in shared routers. Readiness checks package requirements, matching core/module versions and external executables. Configured provider credentials and service connectivity remain in the existing settings readiness system. ## Lifecycle guarantees Official modules share one interpreter. Running application containers hold a shared environment lease; module changes require an exclusive lease, across processes. A second lease protects deployment selection when different Python environments share the same home. Stop CLI turns and API workers before changing packages or selection. Direct external `pip` commands cannot be prevented by this advisory lock. Install first resolves dependencies, rejects replacement of an existing package version, and builds the exact resolved artifacts before modifying the environment. If installation fails after adding packages, those newly added distributions are removed, including when saving selection fails. Malformed selection is rejected before any package mutation. Selection is atomically replaced only after package operations succeed. Use a new environment or an explicit environment upgrade for dependency conflicts. This is not an atomic filesystem transaction across a machine crash; standard pip repair/reinstallation remains the recovery path for an interrupted machine. Uninstall removes only the selected distribution. Shared dependencies are retained because other applications may use them. User settings, sessions, notebooks, knowledge bases, generated artifacts and credentials are never purged. Reinstall uses the retained data. There is no implicit data-deletion command. Parser package installation from a running settings/setup session now returns an offline module command. It no longer upgrades packages beneath active turns. Model-weight downloads remain background jobs, because they do not alter Python code. Third-party managed plugins retain their existing isolated environments. ## Third-party worker extensions Managed plugin workers use their own environments and lifecycle, separately from official module wheels. See [plugin streaming and cancellation](PLUGINS.md#worker-protocol-and-cancellation) and the [runnable example](examples/learning_echo/README.md). ## Validation ```sh python scripts/sync_module_requirements.py --check python -m pytest tests/modules tests/test_packaging_metadata.py python scripts/build_modules.py --output dist/modules python scripts/check_module_install.py --wheelhouse dist/modules --extended ``` The install smoke creates a disposable virtual environment, uses a local mock model (no provider credentials), checks core chat and durable replay, installs Solve, runs it, uninstalls it, verifies persisted files, checks core again, then reinstalls Solve. Extended mode installs Parsing, Research and Calendar without Knowledge or Mastery, exercises parsing and its cache plus independent research and calendar paths, then removes each module while verifying Solve and retained data. The source isolation tests also prohibit undeclared imports in a fresh subprocess for each of the 25 modules and assemble their contributions. Manim additionally needs system rendering libraries, FFmpeg and LaTeX. A render and cancellation test should accompany changes to its renderer. The Web application remains one frontend distribution; independently replaceable third-party frontend bundles are outside this Python module contract. ## Implementation and verification - [deeptutor/modules/manifests/](../deeptutor/modules/manifests/) - [scripts/build_modules.py](../scripts/build_modules.py) - [scripts/check_module_install.py](../scripts/check_module_install.py)