A lightweight, local-first deep-research agent. Give it a topic → get a cited report. Auto-detects your Ollama / LM Studio models and only reaches for a cloud key when a step actually needs it.
NOT a DeerFlow wrapper. NOT a "super agent that does anything." One job, done locally, that turns on.
Web UI (recommended):
launch.bat
or manually:
python -m src.deepdesk.cli serve --port 8787
then open http://127.0.0.1:8787/ — you get a live "what ran · where · for how much" strip as the graph executes.
Headless:
python -m src.deepdesk.cli run "your topic" "optional constraints"
Requires Python 3.10+. Zero pip dependencies — it's pure standard library.
A graph runtime with scoped per-node state, per-node model routing, caching, embeddings, and a context monitor that prevents context-wall truncation.
intake → planner[CLOUD|LOCAL] → researcher×N[LOCAL] → writer[LOCAL] → reviewer[LOCAL|CLOUD] → report
Each node receives ONLY what it needs. See the spec: C:\SympleVault\Project_Notes\DeepDesk_Spec.md
DeepDesk/
├── pyproject.toml # optional install (no runtime deps)
├── launch.bat # one-click Windows launcher (no pip)
├── src/deepdesk/
│ ├── cli.py # run / serve entry point
│ ├── router.py # per-node local↔cloud decision (the moat)
│ ├── resources.py # Ollama / LM Studio detection + local generate()
│ ├── cloud.py # OpenAI-compatible client (free tiers: GitHub Models / Groq)
│ ├── cache.py # sqlite: llm cache, perf log, embedding + research cache
│ ├── embedding.py # local nomic-embed-text wrapper + cache
│ ├── context.py # ContextMonitor: per-run token budget + relevance condensation
│ ├── graph/ # nodes (planner, researcher, writer, reviewer) + state contract
│ └── ui/ # stdlib web server (SSE) + index.html
├── config/ # model presets, runtime config
├── data/ # local sqlite store (research memory + model perf log)
└── tests/ # per-node unit tests
DeepDesk is local-first: by default EVERY node runs on your local models. To let the planner use a free cloud key (coordination step) or as an escalation path, set a key AND opt in:
set GITHUB_TOKEN=ghp_... # free, no card
set DEEPDESK_ALLOW_CLOUD=1 # required — cloud is opt-in, not default
# or
set GROQ_API_KEY=gsk_...
set DEEPDESK_ALLOW_CLOUD=1
Without DEEPDESK_ALLOW_CLOUD=1, no cloud call is ever made. If a cloud call
DOES fail (e.g. a retired model you can't access), the router transparently
falls back to local — it never silently produces empty output.
pip install -e .
deepdesk run "your topic"