hkuds/ deeptutor
View on GitHubDeepTutor: Lifelong Personalized Tutoring. https://deeptutor.info/.
DeepTutor: Lifelong Personalized Tutoring. https://deeptutor.info/.
Features · Get Started · Explore · CLI · Ecosystem · Community
🤝 We welcome any kinds of contributing! Vote on roadmap items or propose new ones at
Roadmap, and see our Contributing Guide for branching strategy, coding standards, and how to get started.
[2026.9.2] v1.6.3 — Breaking front/back-end refactor, strict canonical routes and recoverable streams, plus learner/guardian accounts, grounded Reading, WeKnora, broader parsing, Python 3.14, and DashScope media.
[2026.8.31] v1.6.2 — Immersive YouTube learning, a plugin-driven Visualize catalog, three new agent harnesses, safer reading citations, multi-format MinerU, live Partner channel status, and guided updates.
[2026.8.30] v1.6.1 — One vendor key linked to every service it serves, a task model for background work, Settings as a searchable navigator, a sidebar you arrange, and first-party LightRAG.
[2026.8.27] v1.6.0 — Faithful EPUB reading and annotations, Courses with Little Tutor and Ask Questions, bounded web-source sync, shared Books with private learning state, and Serply/native search.
[2026.8.25] v1.5.17 — Partners each member owns with private conversations and linkable chat accounts, GitHub repos as a knowledge source, Antigravity CLI, browser WeChat QR login, and
deeptutor doctor.
[2026.8.22] v1.5.16 — MarginNote 4 libraries you connect and its add-on fills, Book pages that turn again, and tool-call ids, embeddings and temperature limits that stop breaking behind a gateway.
[2026.8.20] v1.5.15 — PageIndex OSS you host yourself with reasoning retrieval, a question bank you can finally file into, third-party tool/capability plugins, and Apache Tika parsing.
[2026.8.19] v1.5.14 — Immersive Reading: a document open beside the thread, cited page by page; DeepTutor configures itself from chat; IMA libraries you browse and write to; a notebook console.
[2026.8.17] v1.5.13 — Books stream while they compile, track your progress, and export to Markdown; a cost estimate before you approve a spine; and home starter suggestions drawn from memory.
[2026.8.13] v1.5.12 — Web search rebuilt with six new providers (Doubao, Bocha, Zhipu, Firecrawl, Qianfan, Aliyun IQS), a LiteParse parsing engine, MCP servers that reconnect on credential change, and CodeBuddy + OrcaRouter.
[2026.8.10] v1.5.11 — Prose around a DSML tool call stops vanishing, a truncated reply continues instead of ending, live memory usage in Settings, and LightRAG indexing off the event loop.
[2026.8.7] v1.5.10 — Every account signs in to its own Codex, model output language becomes its own setting, empty tool calls are rejected instead of retried, and uploads stop blocking the loop.
[2026.8.4] v1.5.9 — Gemini Embedding 2 on its native endpoint, a per-model reasoning effort control, a Novita AI gateway, retrieval roles for queries, and Compose deployments that keep all of
data/.
[2026.8.2] v1.5.8 — Memory: a real heap ceiling for the dev server, source installs serve a production build, bounded LLM client and index caches, and a keep-alive fix for stray 500s.
[2026.7.31] v1.5.7 — A per-account MCP Services store, 101 CLI Apps the tutor can run, credentials moved out of the sandbox's reach, and a mobile layout.
[2026.7.29] v1.5.6 — Remote Codex sign-in completes behind an SSH tunnel, generated files get their own card in Activity, non-English languages stop collapsing to Chinese, and book creation no longer times out.
[2026.7.26] v1.5.5 — Sign in with your ChatGPT plan via OpenAI Codex OAuth, an Eden AI provider, knowledge bases that report what they hold, traceable
ragcitations, and GraphRAG indexing without a workaround.
[2026.7.24] v1.5.4 — Maintenance sweep: the post-answer "generating" stall is gone, IM partners render Markdown tables faithfully, LLM JSON parsing is sturdier, plus quiz, create-KB form, and Math Animator fixes.
[2026.7.24] v1.5.3 — Themeable code blocks, four more coding CLIs in My Agents (Gemini, Kimi, opencode, MiMo), an Atlas Cloud LLM provider, and a broad chat, memory, embedding, and parsing reliability sweep.
[2026.7.19] v1.5.2 — Configurable chat attachment limits, PageIndex retrieval that reasons across your documents via agentic tool calls, broader Anthropic/OpenAI model support, and steadier Book, Knowledge Base, and chat UI.
[2026.7.9] v1.5.1 — Remove a single failed document from a knowledge base — even one stuck in an error state — instead of deleting and rebuilding the whole base.
[2026.7.4] v1.5.0 — LlamaIndex ingestion now honors your Document Parsing engine with multimodal image extraction, Partner & Soul ids stay URL-safe for non-Latin names, and optional RAG extras install cleanly on Python 3.14+.
[2026.6.30] v1.4.15 — A native Mattermost channel for Partners, plus fixes so Guided Learning multiple-choice questions grade correctly and a configured zero chunk overlap is honored.
[2026.6.29] v1.4.14 — Click an assigned partner to chat in one step, Deep Research flags partial reports, LightRAG indexes without MinerU, FAISS handles non-ASCII paths, and PocketBase sessions are isolated per user.
[2026.6.27] v1.4.13 — Partners support non-Latin names and become assignable to users, logos render after login (#599), tiny knowledge bases retrieve reliably, and containers start cleanly under rootless Podman.
[2026.6.24] v1.4.12 — A new LightRAG Server retrieval engine, a lightweight PyMuPDF4LLM parsing engine, and a FAISS vector backend that makes large knowledge-base retrieval dramatically faster.
[2026.6.23] v1.4.11 — Native tool calling on every cloud OpenAI-compatible provider, a redesigned admin Users page, LaTeX in quiz options, an honest session-loading spinner, and configurable container host binding.
[2026.6.21] v1.4.10 — A self-service Profile page with avatars, a rootless-ready container guide with a single-port request-time proxy, and deny-by-default MCP tools for non-admin users.
[2026.6.19] v1.4.9 — Settings polish: Search shows only the fields your provider needs, connection profiles can be renamed and auto-named by provider, and graded Mastery Path questions flow into your Question Bank.
[2026.6.18] v1.4.8 — Connect your own Partners under My Agents and consult them live in chat — answering through their own persona, library and skills — each with its own private memory.
[2026.6.18] v1.4.7 — Connect your local Claude Code / Codex and consult it live mid-turn, My Agents graduates to a top-level
/agents, and Partner conversations gain branch / resume / delete with a replayable trace.
[2026.6.17] v1.4.6 — Four-surface consolidation: a Space learning dashboard with importable My Agents and top-level Memory, a Knowledge Center with GraphRAG / PageIndex / LightRAG / linked-KB / Obsidian, opened-up Settings, and per-model capability gating.
[2026.6.14] v1.4.5 — Guided Learning rebuilt on the chat agent loop with a hard per-type mastery gate and a
/learningdashboard, a new loop-plugin framework, plus Markdown export / save-to-notebook for Partner conversations.
[2026.6.13] v1.4.4 — Install community skills from ClawHub with
deeptutor skill installbehind a security gate, plus real in-browser DOCX/XLSX previews for knowledge-base files.
[2026.6.12] v1.4.3 — TutorBot becomes Partners on a production-grade IM pipeline (15 channels, live streaming), Chat moves to a single agent loop, real per-user isolation, and a rebuilt Visualize.
[2026.5.28] v1.4.2 — Stability + polish: Gemini 2.5+ unblocked across Visualize and Chat, auth-routing fix (#485), smooth-streaming chat UX, a Recents sidebar, and Lemonade local-provider support.
[2026.5.27] v1.4.1 — Security + stability: TutorBot tool sandbox locked down, per-user resource isolation, multimodal image fallback, an HTTP/SSE API for TutorBots, and a v1.4.0 chat regression fix.
[2026.5.22] v1.4.0 — GA cut of v1.4: Auto Mode, three-layer Memory, agentic Deep Research / Solve / Question, LlamaIndex RAG refactor, Visualize/Animator merge, and restart-safe turn runtime.
[2026.5.21] v1.4.0-beta — Three-layer Memory workbench (L1/L2/L3), every chat capability rebuilt on a single agentic engine, LlamaIndex-only RAG, and a unified Settings + Capabilities surface.
[2026.5.10] v1.3.10 — Remote Docker CORS recovery,
DISABLE_SSL_VERIFYacross SDK providers, safer code-block citations, and optional Matrix E2EE add-on.
[2026.5.9] v1.3.9 — TutorBot Zulip and NVIDIA NIM support, safer thinking-model routing,
deeptutor start, sidebar tooltips, and session-store parity.
[2026.5.8] v1.3.8 — Optional multi-user deployments with isolated user workspaces, admin grants, auth routes, and scoped runtime access.
[2026.5.4] v1.3.7 — Thinking-model/provider fixes, visible Knowledge index history, and safer Co-Writer clear/template editing.
[2026.5.3] v1.3.6 — Catalog-based model selection for chat and TutorBot, safer RAG re-indexing, OpenAI Responses token-limit fixes, and Skills editor validation.
[2026.5.2] v1.3.5 — Smoother local launch settings, safer RAG queries, cleaner local embedding auth, and Settings dark-mode polish.
[2026.5.1] v1.3.4 — Book page chat persistence and rebuild flows, chat-to-book references, stronger language/reasoning handling, RAG document extraction hardening.
[2026.4.30] v1.3.3 — NVIDIA NIM + Gemini embedding support, unified Space context for chat history/skills/memory, session snapshots, RAG re-index resilience.
[2026.4.29] v1.3.2 — Transparent embedding endpoint URLs, RAG re-index resilience for invalid persisted vectors, memory cleanup for thinking-model output, Deep Solve runtime fix.
[2026.4.28] v1.3.1 — Stability: safer RAG routing & embedding validation, Docker persistence, IME-safe input, Windows/GBK robustness.
[2026.4.27] v1.3.0 — Versioned KB indexes with re-index workflow, rebuilt Knowledge workspace, embedding auto-discovery with new adapters, Space hub.
[2026.4.25] v1.2.5 — Persistent chat attachments with file-preview drawer, attachment-aware capability pipelines, TutorBot Markdown export.
[2026.4.25] v1.2.4 — Text/code/SVG attachments, one-command Setup Tour, Markdown chat export, compact KB management UI.
[2026.4.24] v1.2.3 — Document attachments (PDF/DOCX/XLSX/PPTX), reasoning thinking-block display, Soul template editor, Co-Writer save-to-notebook.
[2026.4.22] v1.2.2 — User-authored Skills system, chat input performance overhaul, TutorBot auto-start, Book Library UI, visualization fullscreen.
[2026.4.21] v1.2.1 — Per-stage token limits, Regenerate response across all entry points, RAG & Gemma compatibility fixes.
[2026.4.20] v1.2.0 — Book Engine "living book" compiler, multi-document Co-Writer, interactive HTML visualizations, Question Bank @-mention.
[2026.4.18] v1.1.2 — Schema-driven Channels tab, RAG single-pipeline consolidation, externalized chat prompts.
[2026.4.17] v1.1.1 — Universal "Answer now", Co-Writer scroll sync, unified settings panel, streaming Stop button.
[2026.4.15] v1.1.0 — LaTeX block math overhaul, LLM diagnostic probe, Docker + local LLM guidance.
[2026.4.14] v1.1.0-beta — Bookmarkable sessions, Snow theme, WebSocket heartbeat & auto-reconnect, embedding registry overhaul.
[2026.4.13] v1.0.3 — Question Notebook with bookmarks & categories, Mermaid in Visualize, embedding mismatch detection, Qwen/vLLM compatibility, LM Studio & llama.cpp support, and Glass theme.
[2026.4.11] v1.0.2 — Search consolidation with SearXNG fallback, provider switch fix, and frontend resource leak fixes.
[2026.4.10] v1.0.1 — Visualize capability (Chart.js/SVG), quiz duplicate prevention, and o4-mini model support.
[2026.4.10] v1.0.0-beta.4 — Embedding progress tracking with rate-limit retry, cross-platform dependency fixes, and MIME validation fix.
[2026.4.8] v1.0.0-beta.3 — Native OpenAI/Anthropic SDK (drop litellm), Windows Math Animator support, robust JSON parsing, and full Chinese i18n.
[2026.4.7] v1.0.0-beta.2 — Hot settings reload, MinerU nested output, WebSocket fix, and Python 3.11+ minimum.
[2026.4.4] v1.0.0-beta.1 — Agent-native architecture rewrite (~200k lines): Tools + Capabilities plugin model, CLI & SDK, TutorBot, Co-Writer, Guided Learning, and persistent memory.
[2026.1.23] v0.6.0 — Session persistence, incremental document upload, flexible RAG pipeline import, and full Chinese localization.
[2026.1.18] v0.5.2 — Docling support for RAG-Anything, logging system optimization, and bug fixes.
[2026.1.15] v0.5.0 — Unified service configuration, RAG pipeline selection per knowledge base, question generation overhaul, and sidebar customization.
[2026.1.9] v0.4.0 — Multi-provider LLM & embedding support, new home page, RAG module decoupling, and environment variable refactor.
[2026.1.5] v0.3.0 — Unified PromptManager architecture, GitHub Actions CI/CD, and pre-built Docker images on GHCR.
[2026.1.2] v0.2.0 — Docker deployment, Next.js 16 & React 19 upgrade, WebSocket security hardening, and critical vulnerability fixes.
✨ v1.6.3 is live.
pip install -U deeptutorpicks up the latest stable release.
DeepTutor is an agent-native learning workspace that connects tutoring, problem solving, quiz generation, research, visualization, and mastery practice in one extensible system.
DeepTutor ships four installation paths. They all share one workspace layout: settings live in data/user/settings/ under the directory you launch from (or under DEEPTUTOR_HOME / deeptutor start --home if you set one explicitly). For the full app, the recommended flow is pick a workspace directory → install → deeptutor init → deeptutor start.
Full local Web app + CLI, no clone required. Needs Python 3.11–3.14 and a Node.js 20+ runtime on PATH (the packaged Next.js standalone server is spawned by deeptutor start).
mkdir -p my-deeptutor && cd my-deeptutor
pip install -U deeptutor
deeptutor init # prompts for ports + LLM provider + optional embedding/search
deeptutor start # starts backend + frontend; keep the terminal open
deeptutor init prompts for backend port (default 8001), frontend port (default 3782), LLM provider / base URL / API key / model, an optional embedding provider for Knowledge Base / RAG, and an optional search provider for Web Search.
After deeptutor start, open the frontend URL printed in the terminal — by default http://127.0.0.1:3782. Press Ctrl+C in that terminal to stop both backend and frontend. Skipping deeptutor init is fine for a quick trial; the app boots with default ports and empty model settings, configure them later in Settings → Models.
For development against a checkout. Use Python 3.11–3.14 and Node.js 22 LTS to match CI and Docker.
git clone https://github.com/HKUDS/DeepTutor.git
cd DeepTutor
# Create a venv (macOS/Linux). Windows PowerShell:
# py -3.11 -m venv .venv ; .\.venv\Scripts\Activate.ps1
python3 -m venv .venv && source .venv/bin/activate
python -m pip install --upgrade pip
# Install backend + frontend deps
python -m pip install -e .
( cd web && npm ci --legacy-peer-deps )
deeptutor init
deeptutor start --dev
deeptutor start builds the local web/ frontend for production once and reuses it; --dev runs Next.js with HMR. Config layout, ports, and Ctrl+C match Option 1.
conda create -n deeptutor python=3.11
conda activate deeptutor
python -m pip install --upgrade pip
pip install -e ".[rag-lightrag]" # Built-in LightRAG engine (exact supported SDK)
pip install -e ".[graphrag]" # Microsoft GraphRAG engine (Python 3.11–3.13)
pip install -e ".[dev]" # tests/lint tools
pip install -e ".[partners]" # Partner IM channel SDKs
pip install -e ".[video-learning]" # compatibility extra; captions ship in the full/CLI installs
pip install -e ".[matrix]" # Matrix channel without E2EE/libolm
pip install -e ".[matrix-e2e]" # Matrix E2EE; requires libolm
pip install -e ".[math-animator]" # Manim addon; requires LaTeX/ffmpeg/system libs
Changing frontend dependencies: run npm install --legacy-peer-deps to refresh web/package-lock.json, then commit both web/package.json and web/package-lock.json.
Stuck dev server: if deeptutor start --dev reports an existing frontend that isn't responding, stop the PID it prints. If no Next.js process is actually running, the lock files are stale — remove them and retry:
rm -f web/.next/dev/lock web/.next/lock
deeptutor start --dev
One container for the full Web app. Images on GitHub Container Registry:
ghcr.io/hkuds/deeptutor:latest — latest stable releaseghcr.io/hkuds/deeptutor:<version> — exact release without the leading v (for example :1.6.3); pre-releases receive only their version tagSee CONTAINERIZATION.md for podman/rootless/read-only-rootfs deployments and the full per-installation guide.
docker run --rm --name deeptutor \
-p 127.0.0.1:3782:3782 \
-v deeptutor-data:/app/data \
ghcr.io/hkuds/deeptutor:latest
Only
3782needs to be published. The browser talks exclusively to the frontend origin; the Next.js middleware (web/proxy.ts) forwards/api/*and/ws/*to the FastAPI backend inside the container. Publishing8001(-p 127.0.0.1:8001:8001) is optional — handy only for hitting the API directly with curl or scripts.
Open http://127.0.0.1:3782. The container creates /app/data/user/settings/*.json on first boot; configure model providers from the Web Settings page. Config, API keys, logs, workspace files, memory, and knowledge bases persist in the deeptutor-data volume. Optional extras belong on the deployment, not in a shell: set DEEPTUTOR_EXTRAS (and DEEPTUTOR_APT_PACKAGES for system libraries) and every container started from it re-applies them, where a docker exec … pip install would be lost at the next compose down.
-p host:container mapping (e.g. -p 127.0.0.1:8088:3782). If you change container-side ports in /app/data/user/settings/system.json, restart and update the right side of each mapping to match.-d, then docker logs -f deeptutor to follow, docker stop deeptutor to stop, docker rm deeptutor before reusing the name. The deeptutor-data volume keeps your settings and workspace across restarts.Remote Docker / reverse proxy: the browser only talks to the frontend
origin (:3782); the in-container Next.js middleware forwards /api/* and
/ws/* to the backend server-side. For the common single-container case you
don't configure an API base at all — just point your reverse proxy / TLS
terminator at :3782. You only need an API base for a split deployment
(backend in a separate container/host): set next_public_api_base in
data/user/settings/system.json to the in-network address the frontend server
uses to reach the backend (it's read server-side, never sent to the browser).
{
"next_public_api_base": "http://backend:8001"
}
next_public_api_base_external (and its alias public_api_base) are accepted as
lower-precedence fallbacks. CORS uses frontend origins, not API URLs. With
auth disabled, DeepTutor permits normal HTTP/HTTPS browser origins by default.
With auth enabled, add exact frontend origins:
{
"cors_origins": ["https://deeptutor.example.com"]
}
Inside Docker, localhost is the container itself, not your host machine. To reach a model service running on the host, use the host gateway (recommended):
docker run --rm --name deeptutor \
-p 127.0.0.1:3782:3782 -p 127.0.0.1:8001:8001 \
--add-host=host.docker.internal:host-gateway \
-v deeptutor-data:/app/data \
ghcr.io/hkuds/deeptutor:latest
Then in Settings → Models, point the provider Base URL at host.docker.internal:
http://host.docker.internal:11434/v1http://host.docker.internal:11434/api/embedhttp://host.docker.internal:1234/v1http://host.docker.internal:8080/v1http://host.docker.internal:13305/api/v1Docker Desktop (macOS/Windows) usually resolves host.docker.internal without --add-host. On Linux, the flag is the portable way to create that hostname on modern Docker Engine.
Linux alternative — host networking: add --network=host and drop the -p flags. The container shares the host network directly, so open http://127.0.0.1:3782 (or the frontend_port in system.json), and host services can be reached with normal localhost URLs like http://127.0.0.1:11434/v1. Note that host networking exposes container ports directly on the host and may conflict with existing services — to keep them on loopback, set BACKEND_HOST=127.0.0.1 and FRONTEND_HOST=127.0.0.1 (see CONTAINERIZATION.md).
When you don't need the Web UI. The CLI-only package is installed from a source checkout, not from PyPI.
git clone https://github.com/HKUDS/DeepTutor.git
cd DeepTutor
# Create a venv (macOS/Linux). Windows PowerShell:
# py -3.11 -m venv .venv-cli ; .\.venv-cli\Scripts\Activate.ps1
python3 -m venv .venv-cli && source .venv-cli/bin/activate
python -m pip install --upgrade pip
python -m pip install -e ./packaging/deeptutor-cli
deeptutor init --cli
deeptutor chat
deeptutor init --cli shares the same data/user/settings/ layout as the full app but skips the backend/frontend port prompts. It still offers the Embedding and Search selectors (choose Skip when you do not need them), writes the key runtime files (system.json, auth.json, integrations.json, interface.json, model_catalog.json, main.yaml, agents.yaml), and prompts for the active LLM provider and model.
deeptutor chat # interactive REPL
deeptutor chat --capability deep_solve --tool rag --kb my-kb
deeptutor run chat "Explain Fourier transform"
deeptutor run deep_solve "Solve x^2 = 4" --tool rag --kb my-kb
deeptutor kb create my-kb --doc textbook.pdf
deeptutor memory show
deeptutor config show
The local deeptutor-cli install ships no Web assets or server dependencies. Keep the source checkout around — the editable install points to it. To add the Web app later, install the PyPI package (Option 1) and run deeptutor init + deeptutor start from the same workspace.
The built-in office skills — docx / pdf / pptx / xlsx — work by having the
model write a short Python script (python-docx, reportlab, openpyxl, …),
run it through the exec / code_execution tools, and hand back a download URL.
Those tools mount whenever a sandbox backend is active. DeepTutor selects the
strongest configured backend in this order:
DEEPTUTOR_SANDBOX_RUNNER_URL routes execution to the
hardened, least-privileged service from Dockerfile.runner.bwrap isolates the process and files.The sandbox_allow_subprocess setting in data/user/settings/system.json
(default true) controls only the last fallback. Set it to false (or export
DEEPTUTOR_SANDBOX_ALLOW_SUBPROCESS=0) to refuse subprocess execution when no
runner or bwrap backend is available; it does not disable those stronger
backends.
Everything under data/user/settings/ is plain JSON/YAML. The Settings page in the browser is the recommended editor.
| File | Purpose |
|:---|:---|
| model_catalog.json | Provider connections plus LLM, task, embedding, search, TTS, STT, image, and video profiles, credentials, and active selections |
| system.json | Backend/frontend ports, public API base, CORS, SSL verification, attachment directory and upload/extraction limits |
| auth.json | Optional auth toggle, username, password hash, token/cookie settings |
| integrations.json | Optional PocketBase and sidecar integration settings |
| interface.json | UI and model output language / theme / sidebar preferences |
| video_learning.json | Default YouTube/Invidious playback provider, Invidious origins, and optional transcript adapter |
| main.yaml | Runtime behavior defaults and path injection |
| agents.yaml | Capability/tool temperature and token settings |
Web Search references are filtered by default: only public http/https URLs
without embedded credentials or unusual ports are surfaced. Deployments can add
an education-focused domain policy in data/user/settings/system.json:
{
"web_search_source_filtering": {
"enabled": true,
"blocked_domains": ["spam.example"],
"trusted_domains": ["edu.cn", "arxiv.org"]
}
}
When trusted_domains is non-empty, references are limited to those domains
and their subdomains; blocked_domains always takes precedence.
Project-root .env is not read as an application config file. For a minimal model setup, open Settings → Models, add an LLM profile (Base URL / API key / model name), and save. Add an embedding profile only if you plan to use Knowledge Base / RAG features.
OpenAI-compatible LLM profiles also expose an API protocol setting. Keep
Auto for normal provider detection and compatible fallback, choose
Responses API for endpoints that only implement /responses, or choose
Chat Completions for endpoints that require /chat/completions. Forced
Responses mode is fail-closed: endpoint errors are returned instead of being
silently retried through Chat Completions. The equivalent profile field in
model_catalog.json is wire_api (auto, responses, or
chat_completions).
DeepTutor separates its installed code from its runtime workspace. By default,
the workspace is the directory where you run deeptutor init / deeptutor start; --home PATH or DEEPTUTOR_HOME overrides it. Runtime output is the
data directory inside that workspace, so the startup banner line beginning
with Workspace: identifies what to clean up.
Stop the app. Press Ctrl+C in the terminal running deeptutor start, or
run deeptutor stop [--home PATH] for a launcher started with --detach;
stop any running Partner and detached Docker containers before deleting data.
Remove runtime data only if you also want to erase all local state. This includes settings and API keys, chat history, sessions, Memory, Notebooks, Books, Reading state, Skills, Partners state, logs, Knowledge Bases, parse caches, generated artifacts, and the packaged frontend runtime cache.
First copy the exact Workspace: path from the startup banner and verify
that its data child is the intended DeepTutor data directory. Back it up
if anything may be needed later, then move that exact directory to your
operating system's Trash/Recycle Bin. Do not run a recursive deletion
command against a relative path or an unresolved environment variable.
Remove the installed package. Use the command that matches the distribution:
python -m pip uninstall deeptutor
python -m pip uninstall deeptutor-cli
If the virtual environment was created only for DeepTutor, remove it through
your environment manager. For a source install, deactivate the environment,
leave the source directory, and run git status --short inside that exact
checkout. Only move the checkout to Trash/Recycle Bin after confirming it
contains no unrelated or uncommitted work.
For the Docker path, inspect the exact container and named volume before removing them. Volume removal permanently erases the Docker-managed data:
docker ps -a --filter name=^/deeptutor$
docker volume inspect deeptutor-data
docker rm -f deeptutor
docker volume rm deeptutor-data
Start with the main surfaces you will use day to day: Chat, Partners, My Agents, Co-Writer, Book, Knowledge Center, Learning Space, Memory, and Settings. The tour then covers Multi-User deployments for shared, isolated workspaces.
If an answer loses an earlier constraint, cites weak evidence, or disagrees with selected material, collect the diagnostics in REASONING_SAFETY_CHECKLIST.md before opening an issue.
Chat is the default capability and where most work begins. A single thread can talk normally, call tools, ground itself in selected knowledge bases, read attachments, generate images, consult subagents, write notebook records, and continue with the same context across turns.
The loop is deliberately simple: the model thinks in rounds, calls tools when useful, observes the results, and finishes with a tool-free message. ask_user is special — instead of guessing, the agent can pause the turn, ask a structured clarifying question, and resume once you answer.
User-toggleable tools are brainstorm, web_search, paper_search, reason, and geogebra_analysis — plus imagegen and videogen once you configure the matching generation model. Contextual tools such as rag, kb_files, read_source, read_memory, write_memory, read_skill, load_tools, exec, web_fetch, ask_user, list_notebook, write_note, question_bank, github, and consult_subagent mount automatically when the turn has the right context.
Context comes in two kinds: sticky session context (capability, workspace or course, tools, knowledge bases, persona, model, and Reading / Mastery state) persists across turns; one-time references (files, chat history, books, reading sections, notebooks, question bank, imported agents) come from the + menu for a single turn. The voice button only transcribes the current message.
Home keeps Chat, Ask Questions, Quiz, Visualize, and Immersive Watching one click away; Research for cited reports and Solve for worked reasoning sit under More Capabilities. Mastery Path and Immersive Reading are dedicated sidebar workspaces; Reading adds verified clickable citations, saved citations and notes, source-grounded read-aloud / study guidance / vocabulary / quiz / translation actions, and notebook capture, while Course Study keeps its own course-bound context.
Partners are persistent companions with their own soul, model policy, library, memory, and channels. They are not a separate bot engine: every inbound web or IM message becomes a normal ChatOrchestrator turn inside a partner-scoped workspace. A partner is "a chat that has a personality and a phone number."
Each partner has a SOUL.md, model selection, channels, tool policy, and assigned library. Knowledge bases, skills, and notebooks are copied into data/partners/<id>/workspace/, so the same RAG, skill, notebook, and memory tools work without special cases. Authenticated non-admin users keep private partner sessions and relationship memory while the partner reads their personal memory read-only; admin, group, and unbound traffic use the shared partner scope.
The channel layer is schema-driven and can connect to IM platforms such as Feishu, Telegram, Slack, Discord, DingTalk, QQ/NapCat, WeCom, WhatsApp, Zulip, Mattermost, Matrix, Mochat, and Microsoft Teams depending on installed extras and configured credentials. A partner can also be connected as a subagent and consulted from a normal chat turn — see My Agents below.
For faster setup, the Partner channel page can create a Feishu/Lark app or WeCom AI bot, or sign a personal WeChat account in, from a QR scan drawn in the browser rather than the server log. Feishu/Lark detects the account domain and saves the scanning user as the initial allowed sender. WeCom keeps an existing allowlist and otherwise defaults to all users who can reach the bot, with a visible open-access warning; the manual channel forms remain available if a provider's scan protocol changes.
My Agents turns other agents into context for DeepTutor, and does two distinct things. Connect a live agent — Claude Code, Codex, Antigravity, Kimi, opencode, MiMo Code, Hermes Agent, OpenClaw, or DeepSeek Harness on your machine, or one of your Partners — and consult it from inside a chat turn: DeepTutor actually runs the other agent and streams its work into the Activity panel via the consult_subagent tool. Select it and its round limit with the Agent chip, or filter the same connected-agent list with @; the choice stays attached to the session.
Import past conversations — bring in your existing Claude Code and Codex history as named, searchable, resumable agents. Choose Claude history by project / working directory and Codex history by calendar date; refresh re-syncs that scope and pulls in new conversations. Reference one from a Chat turn via + → My Agents, and DeepTutor reads it as a third-party transcript — it stays their conversation, not DeepTutor's own voice.
Co-Writer is a split-view Markdown workspace for reports, tutorials, notes, and long-form learning artifacts. Documents autosave and render a live preview (KaTeX math, diagram fences), and can be saved back into notebooks when a draft becomes reusable context. Import a .docx to start a new draft, and export the current editor as Markdown or Word.
Its defining idea is surgical editing: select a span and ask DeepTutor to rewrite, expand, or shorten it. The edit agent can ground the change in a knowledge base or web evidence and keeps a trace of its tool calls. If the draft has not changed while it works, the result replaces the selected text directly and remains reversible with Undo.
Book turns selected sources into an interactive living book — not a static PDF, but a reading environment built from typed blocks. A book can start from knowledge bases, notebooks, question banks, or chat history; the creation flow proposes a chapter outline before content is generated, so you review the shape instead of accepting a blind one-shot output.
Each chapter compiles into editable typed blocks — text, callouts, quizzes, flash cards, timelines, code, figures, interactive HTML, animations, concept graphs, deep dives, and user notes — with its own Page Chat. Insert, move, regenerate, rewrite, or switch a block type; selected passages enter a reviewable learning-capture inbox. Progress, bookmarks, quiz attempts, captures, and Page Chat stay private per reader even when an admin book is shared read-only or for collaborative editing; shared deletion stays admin-only. Any book exports to Markdown, long compiles pause and resume, and deeptutor book health / refresh-fingerprints flag source drift.
Knowledge bases are the document collections behind RAG — they ground Chat turns, Co-Writer edits, Book generation, and Partner conversations. What's distinctive is a choice of retrieval engines: LlamaIndex (the default, hybrid vector + BM25 with optional cross-encoder reranking and exact-flat or HNSW FAISS indexes), PageIndex (reasoning retrieval with page-level citations, hosted or self-hosted OSS), GraphRAG and LightRAG (knowledge-graph retrieval), LightRAG Server (retrieval offloaded to an external LightRAG instance you connect over HTTP), WeKnora (retrieval from a knowledge base in your self-hosted deployment, without a local index or document copy), Tencent IMA (a library you curate in IMA — searched, browsed, and written back to over its OpenAPI), MarginNote 4 (your MN4 study data — documents, excerpts, mind-map cards and the links between them — pushed in by the app's Add-on and navigated with dedicated tools), or a linked Obsidian vault the tutor reads and writes in place. Each KB is bound to one engine.
Migrating an existing Obsidian, Hermes, or Markdown library? See Knowledge migration guide for connected-vault and indexed-copy paths.
Creating a KB, you either create new (upload documents and build a fresh index) or link existing (reuse an index built elsewhere, read in place with no re-index). A KB can also track GitHub repositories (repo, branch, glob) or documentation-site URLs (bounded crawl depth and page count); on-demand sync hash-diffs added, changed, and removed content so followed documentation stays current without re-uploading. Re-indexing writes a new flat version-N directory and keeps prior ones, so a working index is never destroyed mid-rebuild. A single document can be removed even from an error-state base — dropping a file that failed to parse without a full delete-and-rebuild. Document parsing — Text-only, MinerU, Docling, Tika, markitdown, PyMuPDF4LLM, or LiteParse — is chosen in Settings → Knowledge Base, with local model downloads off by default. Docling can also run in remote mode against a Docling Serve server (no local install or models needed), configured via Settings → Document Parsing (mode=remote, a server base URL, and an optional API key) or the DOCLING_MODE / DOCLING_API_BASE_URL / DOCLING_API_TOKEN environment variables. Tika is remote-only and points at the Apache Tika server configured on that page. The CLI mirrors the lifecycle with list/info/create/add/search/set-default/delete, source add/remove commands, list-sources, and sync.
The built-in LightRAG engine is installed with pip install 'deeptutor[rag-lightrag]'. That extra contains the supported LightRAG SDK but does not install MinerU. Choose MinerU independently in Document Parsing and either configure its cloud mode or install its current local CLI when structured parsing is wanted. MinerU accepts PDF, common raster images, DOCX, PPTX, and XLSX; the legacy magic-pdf command remains PDF-only. Text-only and the other parsing engines do not require MinerU.
Learning Space is the library, organization, and personalization layer. Conversations & Materials holds Chat History, notebooks — with records that move or copy between notebooks and a Markdown export — and a question bank that keeps your answer, reference answer, and explanation. Personalization holds personas, skills (SKILL.md playbooks), one-click MCP Services, and CLI Apps from the CLI-Anything catalog, each with an on-demand usage guide. The separate My Courses workspace groups subject conversations and tutor threads; each asset is offered only in the workflows that support it.
You don't have to write every skill yourself — Import from EduHub browses the community catalog and downloads a skill straight into your library through a security gate (see Ecosystem).
Memory is a file-backed, three-layer system you can read, curate, and audit — deliberately not a hidden vector store. L1 is the workspace mirror plus an append-only event trace (trace/<surface>/<date>.jsonl); L2 is per-surface curated facts (L2/<surface>.md) with references to L1 entities; L3 is cross-surface synthesis (L3/<profile|recent|scope|preferences>.md) that records its contributing L2 surfaces.
The Memory Graph shows the whole pyramid — L3 synthesis at the centre, L2 in the middle ring, L1 traces on the outside — with exact L2 → L1 evidence edges and L3 → contributing-surface links. Memory is tracked across chat, notebook, quiz, kb, book, partner, and cowriter surfaces; the consolidator's Update / Audit / Dedup budgets are tuned in Settings → Memory.
Settings is the operational control plane, with a live status strip (backend health and resident memory across the process tree) and a persistent, searchable navigator that reaches any page in one click: Appearance (theme, interface and model output language, code-block styling), Network (API base, ports, CORS), Models (Connections, LLM, Task models, Embedding, Search, Text-to-Speech, Speech-to-Text, Image Generation, Video Generation), Knowledge Base (document parsing engine), Chat (Video Learning, searchable tools, per-capability parameters, starting points, attachment caps), Partners & Agents (nine local harnesses), Learner profile (age, grade, curriculum, language, reading level, explanation style), Guardian (authorized learners, materials, reports, credential resets), Memory (the consolidator's budgets), and About (version checks and safe updates). A connection holds one vendor credential and mirrors it into every service that vendor can serve, so a key is entered once rather than pasted into five pages; task models pin a small, fast model for the work nobody asked for — naming a conversation, writing the composer's starting points — and resolve to the active default when left empty.
Video Learning under Settings → Chat defaults to the official privacy-enhanced YouTube IFrame Player. To keep playback local, set the administrator-managed Invidious API origin (for example http://127.0.0.1:3000), test it, select Invidious, and save. New or reopened videos pick up the provider immediately with the same material ID and progress. Invidious media is streamed through DeepTutor's byte-range proxy; upstream URLs are neither exposed to the browser nor stored on disk. If the instance fails, DeepTutor stays offline from YouTube until the learner explicitly chooses the native YouTube fallback. Public-caption tutoring is optional: install .[video-learning]; playback continues without it, while transcript-based Explain here is disabled with a reason.
Most sections use a draft-and-apply flow, so you can test a provider before committing it. You can also just ask in Chat: the assistant reads the current configuration, applies a change, and says whether it needs a restart or a re-index — probing a new model before it commits, so it cannot switch itself onto something unreachable. API keys never pass through the model, which opens the matching form for you instead. Four themes ship in the box — Default, Cream, Dark, and Glass. Project-root .env files are intentionally ignored; runtime configuration lives under data/user/settings/*.json unless DEEPTUTOR_HOME or deeptutor start --home points the app elsewhere.
OpenAI Codex OAuth (experimental). Picking OpenAI Codex under Models → LLM replaces the API-key fields with a browser sign-in that runs against your own ChatGPT plan, so no OPENAI_API_KEY is needed. Tokens live only in data/system/user-secrets/<owner>/private/openai-codex/ — in the multi-container Compose deployment, outside every tree the exec sandbox can reach — and DeepTutor never reads or modifies your ~/.codex CLI login. The model list comes from that account's live catalog; signing in publishes the profile but only becomes the active model when no LLM is configured yet. Because a token authorizes one person's plan, the profile is not shareable through user grants — each account signs in for itself, ordinary users included: their card sits under Models → LLM, and the resulting models, catalog, and sign-out stay private to that account.
Default local Docker and Podman deployments use separate loopback networks and need a temporary bridge during sign-in. Follow the temporary local Codex OAuth bridge guide for the exact Docker, Compose, Podman, and teardown commands.
For a remote deployment, the browser's localhost and the server's localhost are different machines, so an ordinary reverse proxy alone cannot carry the browser's localhost callback to the server. Use an SSH tunnel as the callback bridge. The tunnel reaches the already-published Web port; Next.js rewrites only the exact callback path to the public callback broker, and the broker validates state before routing to the original OAuth operation. The callback listener remains on the backend loopback, ports 1455 and 1457 are not published, and this path supports the default Docker bridge network.
ssh -N -L 1455:127.0.0.1:3782 <ssh-user>@<server-host>
If DeepTutor reports fallback callback port 1457, use:
ssh -N -L 1457:127.0.0.1:3782 <ssh-user>@<server-host>
Run only the one command that matches the actual callback port; never run both. 3782 is only the example Web port: it is the configured frontend/container port reported as callback_forward_port. That value does not guarantee that the same port is listening on the SSH host's 127.0.0.1. If Docker or Podman publishes a different host port, or a reverse proxy listens on a different port, replace only the right-hand target port (3782 above) with the Web port actually listening on the SSH host's 127.0.0.1; keep the left-hand callback port as 1455 or 1457. <server-host> is the SSH host whose loopback owns that listening port. If the browser URL names a reverse proxy or load balancer, replace it with the correct SSH frontend host.
The CLI prints the tunnel command and then immediately tries to open the browser. On a remote deployment, keep the authorization page open without completing it, establish the printed tunnel in another terminal, and only then continue authorization.
Remote-topology detection has a localhost boundary. If Web itself is reached through an SSH or IDE localhost forward, the browser cannot tell that the server is remote. For the current Web operation, leave its authorization page unfinished, read redirect_uri in that operation's authorize URL to identify callback port 1455 or 1457, and create the second tunnel from that local port to the actual Web port. Alternatively, cancel that Web operation and start a new one with the CLI; the CLI output belongs to the new operation and must not be used for the existing Web operation. Quota errors and catalog failures are reported as-is and never fall back to a paid provider. This compatibility path is experimental: the upstream interface may change.
Authentication is off by default — DeepTutor runs single-user. Turn it on and one data/ tree hosts an admin workspace, isolated per-user workspaces, and partner workspaces side by side:
data/
├── user/ # Admin workspace + global settings
├── users/<uid>/ # Per-user scope: chat history, memory, notebooks, KBs
├── partners/<id>/workspace/ # Partner (synthetic-user) scope
├── cli-apps/ # Installed CLI apps, mounted read-only into the sandbox
└── system/ # auth · grants · audit · user-secrets/<owner> (OAuth tokens)
The first registered user becomes admin and owns model catalogs, provider credentials, shared knowledge bases, skills, canonical shared books, and per-user grants. Admin-created local users choose Standard, Learner, or Custom. Learner locks learning capabilities and material policy, adds an adaptive profile, and supports revocable device credentials with expiry and daily limits; authorized guardians can view reports, approve materials, and reset credentials. Other users get isolated workspaces plus scoped models, KBs, skills, partners, and shared-book access without receiving raw API keys. If auth.json already carries a username + password_hash, that account is the admin: /register stays closed and accounts created from /admin/users are always role=user until you promote them.
Enable it: turn auth on in data/user/settings/auth.json, restart deeptutor start, register the first admin at /register, then add users from /admin/users and assign models, KBs, skills, partners, tool/MCP/CLI-app policy, and code-execution access through grants; configure shared books under each user's Book access panel.
PocketBase stays a single-user integration — keep
integrations.pocketbase_urlblank for multi-user deployments unless you've wired up an external user store.
One deeptutor binary, two ways in: an interactive REPL for people who live in the terminal, and structured JSON for other agents that drive DeepTutor as a tool. Same capabilities, tools, and knowledge bases either way.
deeptutor chat opens an interactive REPL and selects a mode with --capability; deeptutor run <capability> "<message>" takes that capability as its first positional argument and exits after one turn. Both accept --tool, --kb, and --config.
deeptutor chat # interactive REPL
deeptutor chat --capability deep_solve --kb my-kb --tool rag
deeptutor run chat "Explain the Fourier transform" --tool rag --kb textbook
deeptutor run deep_research "Survey 2026 papers on RAG" \
--config mode=report --config depth=standard
Core workspace management is here too — knowledge bases (kb), sessions (session), partners (partner), skills (skill), notebooks, memory, and config; course and session organization remain in the Web app. Full list below.
DeepTutor is built to be operated by another agent. Add --format json to any run and each turn streams NDJSON — one event per line (content, tool_call, tool_result, done, …), every line tagged with its session_id. Runs are headless-safe: an ask_user pause with no TTY auto-resolves with an empty reply instead of hanging.
# One shot, machine-readable
deeptutor run deep_solve "Find d/dx[sin(x^2)]" --tool reason --format json
# Chain turns in one stateful session — capture the id, reuse it
SID=$(deeptutor run deep_research "Survey 2026 papers on RAG" \
--config mode=report --config depth=standard --format json \
| jq -r 'select(.type=="done").session_id')
deeptutor run deep_question "Quiz me on that survey" --session "$SID" --format json
The repo ships a root SKILL.md — a ~200-line handover doc that teaches any tool-using LLM the whole surface in one read. Hand it to Claude Code, Codex, or OpenCode (they pick up SKILL.md automatically), or wrap deeptutor run as a tool in a LangChain / AutoGen loop. Full recipes: Agent Handoff.
| Command | Description |
|:---|:---|
| deeptutor init | Create or update data/user/settings for the current workspace |
| deeptutor doctor [--online] | Check whether the workspace is ready to start a session; --online also probes the configured model provider, --format json prints the report |
| deeptutor start [--home PATH] [--dev] [--detach] [--no-browser] | Launch backend + frontend together; optionally detach or suppress browser opening |
| deeptutor stop [--home PATH] | Stop a launcher started with --detach |
| deeptutor serve [--port PORT] | Start only the FastAPI backend |
| deeptutor run <capability> <message> | Run a single capability turn (chat, ask_questions, deep_solve, deep_question, deep_research, visualize, math_animator, mastery_path, immersive_reading, course_study, immersive_watching); add --format json for NDJSON output |
| deeptutor chat | Interactive REPL with capability, tool, KB, notebook, and history controls |
| deeptutor partner list/create/start/stop | Manage IM-connected partners |
| deeptutor kb list/info/create/add/search/set-default/delete/list-sources/sync | Manage knowledge bases and synchronize registered GitHub/web sources (with source add/remove commands) |
| deeptutor skill search/install/list/remove/login/logout/publish/update | Manage skills, install from hubs, and publish your own (eduhub:<slug> by default, see Ecosystem) |
| deeptutor memory show/clear | Inspect L2/L3 memory docs or clear L1/all memory |
| deeptutor session list/show/open/rename/delete | Manage shared sessions |
| deeptutor notebook list/create/show/add-md/replace-md/remove-record | Manage notebooks from Markdown files |
| deeptutor book list/health/refresh-fingerprints | Inspect books and refresh source fingerprints |
| deeptutor plugin list/info | Inspect registered tools and capabilities |
| deeptutor config show | Print configuration summary |
| deeptutor provider login <provider> | Provider auth (openai-codex OAuth login; github-copilot validates an existing Copilot auth session; codebuddy validates CodeBuddy SDK auth and starts login when needed) |
The CLI-only package lives in packaging/deeptutor-cli. In this checkout, install it from source:
python -m pip install -e ./packaging/deeptutor-cli
It isn't published to PyPI yet, so the main Get Started section keeps the source-install path.
DeepTutor skills use the open Agent-Skills format — a folder with a SKILL.md playbook (YAML frontmatter + Markdown) and optional reference files. Nothing about it is DeepTutor-specific, so any registry that speaks the format becomes a source for your library. DeepTutor ships with EduHub — our own education-focused skill registry — wired in as the default hub.
EduHub is the community hub DeepTutor launched for sharing teaching-oriented agent skills — Socratic tutors, flashcard builders, essay feedback, exam blueprints, concept explainers, and more. It is built into DeepTutor, so there's nothing to configure: a bare slug or an eduhub: prefix resolves to it.
Find and install — in the browser, open Learning Space → Skills → Import from EduHub to browse the catalog and download a skill straight into your library. From the terminal:
deeptutor skill search "socratic tutor" # search EduHub (the default hub)
deeptutor skill install socratic-tutor # fetch → verify → register
deeptutor skill install eduhub:socratic-tutor@1.2.0 # pin a hub and a version
deeptutor skill list # local skills with their hub provenance
Publish your own — package a SKILL.md and share it back to the community:
deeptutor skill login # browser sign-in to EduHub
deeptutor skill publish ./my-skill # interactive: pick a track + tags, then upload
deeptutor skill update # roll back or release a new version
EduHub is also a standalone, ClawHub-compatible registry, so agents that aren't DeepTutor (Claude Code, Codex, …) can use it directly through the eduhub CLI — npx eduhub install socratic-tutor.
Whatever the source, every import passes the same safety gate before anything touches your workspace:
--allow-unverified;always: is stripped, so a downloaded skill can never force itself into every system prompt;.hub-lock.json for audits and updates.In multi-user deployments, browser imports land in the authenticated caller's skill layer, while CLI and admin-console installs target the owner/admin workspace; admin skills stay hidden and read-only for ordinary users until granted.
Because DeepTutor speaks the open Agent-Skills format, ClawHub works as a first-class source too — it's built in alongside EduHub. Pick it with the hub prefix:
deeptutor skill search "git release notes" --hub clawhub
deeptutor skill install clawhub:git-release-notes@1.0.1
deeptutor skill install clawhub:udiedrichsen/stock-analysis
When several publishers share the same slug, search shows each publisher and a
fully scoped install ref (clawhub:<ownerHandle>/<slug>).
Add more registries in data/user/settings/skill_hubs.json: a type: "clawhub" entry points at any compatible HTTP API (EduHub and ClawHub both speak it), type: "command" wraps whatever fetch CLI a registry ships, and "default" chooses the hub used for bare slugs. All of them feed the same import gate.
DeepTutor is an open-source project led by Bingxi Zhao within the HKUDS Group, and it iterates in a fully open-source form, built together with the community. So far, we DO NOT have paid online products of any form. Feel free to reach out at bingxizhao39@gmail.com for discussions, ideas, or collaboration.
Heartfelt thanks to Chao Huang, director of the Data Intelligence Lab @ HKU, and to our HKUDS labmates for their warm support — especially Jiahao Zhang, Zirui Guo, and Xubin Ren. We're also deeply grateful to the open-source community: your stars, issues, pull requests, and discussions shape DeepTutor every single day.
DeepTutor also stands on the shoulders of outstanding open-source projects that gave us both tools and inspiration:
| Project | Role / Inspiration | |:---|:---| | LlamaIndex | RAG pipeline and document-indexing backbone | | nanobot | Ultra-lightweight agent engine that powered the original TutorBot (HKUDS) | | LightRAG | Simple & fast RAG (HKUDS) | | AutoAgent | Zero-code agent framework (HKUDS) | | AI-Researcher | Automated research pipeline (HKUDS) | | OpenClaw | Open agent gateway and skill ecosystem behind ClawHub | | Codex | Agent-native coding CLI that inspired our CLI workflow | | Claude Code | Agentic coding CLI that inspired the DeepTutor agent loop | | ManimCat | AI-driven math animation generation for Math Animator |
We want DeepTutor to keep iterating and improving — and ultimately to become a gift we give back to the open-source community. Our roadmap is updated continuously; vote on items there or propose new ones. If you'd like to contribute, see the Contributing Guide for branching strategy, coding standards, and how to get started.
We hope DeepTutor becomes a gift for the community. 🎁
Licensed under the Apache License 2.0.
No comments yet. Set the tone — say what you would want to know.