```
**Step 4: Update `needsApiKey` / `needsApiKeyForSaving` in `app.js`**
Add `deep_agents` to the backends that don’t need a top-level API key (similar to `copilot_sdk`):
* In the `needsApiKey` function (\~line 900): add `else if (backend === 'deep_agents') return false;`
* In the `needsApiKeyForSaving` function (\~line 925): add `deep_agents` to the return false case alongside `opencode, copilot_sdk`
**Step 5: Manual test**
Run: `uv run pocketpaw --dev` Open dashboard, go to Settings. Verify “Deep Agents (LangChain) \[Beta]” appears in the backend dropdown. Select it and verify the model/max-turns fields appear.
**Step 6: Commit**
```bash
git add src/pocketpaw/frontend/js/app.js src/pocketpaw/frontend/js/websocket.js src/pocketpaw/frontend/templates/components/modals/settings.html
git commit -m "feat(ui): add Deep Agents backend settings to dashboard"
```
***
## Task 7: Update CLAUDE.md Documentation
**Files:**
* Modify: `CLAUDE.md`
**Step 1: Update the AgentRouter backend list**
In the Architecture > AgentLoop > AgentRouter > Backend section, add after the `copilot_sdk` entry:
```markdown
- `deep_agents` — LangChain Deep Agents with LangGraph runtime, built-in planning/subagent tools, and multi-provider support. Lives in `agents/deep_agents.py`.
```
**Step 2: Update the config env vars section if needed**
Add `deep_agents` to the `agent_backend` options list in the Key Conventions section.
**Step 3: Commit**
```bash
git add CLAUDE.md
git commit -m "docs: add deep_agents backend to architecture docs"
```
***
## Task 8: Run Full Test Suite
**Step 1: Run linter**
Run: `uv run ruff check src/pocketpaw/agents/deep_agents.py tests/test_deep_agents_backend.py tests/test_tool_bridge_deep_agents.py` Expected: No errors
**Step 2: Run format check**
Run: `uv run ruff format --check src/pocketpaw/agents/deep_agents.py` Expected: Already formatted
**Step 3: Run all tests**
Run: `uv run pytest --ignore=tests/e2e -x -v` Expected: All pass
**Step 4: Run registry integration test**
Run: `uv run python -c "from pocketpaw.agents.registry import get_backend_info; info = get_backend_info('deep_agents'); print(info.display_name if info else 'NOT FOUND')"` Expected: `Deep Agents (LangChain)` (if deepagents is installed) or `NOT FOUND` (graceful degradation if not installed)
***
## Summary of All Files Changed
| File | Action | Purpose |
| ------------------------------------------------------------------ | ------ | ------------------------- |
| `src/pocketpaw/agents/registry.py` | Modify | Add registry entry |
| `src/pocketpaw/config.py` | Modify | Add settings fields |
| `pyproject.toml` | Modify | Add optional dependency |
| `src/pocketpaw/agents/tool_bridge.py` | Modify | Add LangChain tool bridge |
| `src/pocketpaw/agents/deep_agents.py` | Create | Backend implementation |
| `src/pocketpaw/frontend/js/app.js` | Modify | Frontend settings keys |
| `src/pocketpaw/frontend/js/websocket.js` | Modify | Settings save |
| `src/pocketpaw/frontend/templates/components/modals/settings.html` | Modify | Settings UI panel |
| `CLAUDE.md` | Modify | Architecture docs |
| `tests/test_deep_agents_backend.py` | Create | Backend tests |
| `tests/test_tool_bridge_deep_agents.py` | Create | Tool bridge tests |
## Key Design Decisions
1. **No provider field** — Deep Agents uses `init_chat_model("provider:model")` natively, so the provider is embedded in the model string. No separate `deep_agents_provider` setting needed.
2. **No session persistence** — LangGraph supports checkpointing but wiring it in adds complexity. The history injection pattern (used by other backends) works for v1. Checkpointing can be added later.
3. **Built-in tools passthrough** — Deep Agents has its own planning/filesystem tools. We don’t exclude them (unlike Claude SDK where we exclude shell/fs tools). PocketPaw tools are additive.
4. **Beta flag** — Marked as beta like the other non-Claude backends.
Last updated: April 29, 2026
10 min read
[ Edit this page](https://github.com/pocketpaw/pocketpaw/edit/main/docs/plans/2026-03-19-deep-agents-backend.md)
Was this page helpful?
Yes No
---
# EE Cloud Module — Strip & Rebuild Design
> Self-hosted AI agent with a native desktop app. Controlled via Telegram, Discord, Slack, WhatsApp, or a web dashboard.
Copy page
Copy as MarkdownCopy page content for LLM
Open in ChatGPTAsk ChatGPT about this page
Open in ClaudeAsk Claude about this page
**Date**: 2026-04-04 **Scope**: `ee/cloud/` only — strip and rebuild with clean architecture **Consumer**: paw-enterprise (SvelteKit/Tauri desktop client) **Runtime**: headless mode (`pocketpaw serve`), no dashboard dependency
## Context
The ee/cloud module (2400 LOC, 26 files) was built incrementally with hotfixes. It provides multi-tenant workspace, group chat, pockets, sessions, and agent management backed by MongoDB (Beanie ODM) and real-time via Socket.IO.
**Problems**: no service layer, no validation, global state, Socket.IO tightly coupled to ASGI, swallowed exceptions, circular imports, zero tests.
**Decision**: gut it, keep the Beanie models (cleaned up), rewrite all logic with domain-driven subpackages.
## Architecture: Domain Subpackages
```plaintext
ee/cloud/
├── auth/ # register, login, profile, JWT
│ ├── router.py
│ ├── service.py
│ └── schemas.py
├── workspace/ # workspaces, members, invites, SMTP
│ ├── router.py
│ ├── service.py
│ └── schemas.py
├── chat/ # groups, DMs, messages, reactions, threads, WebSocket
│ ├── router.py
│ ├── service.py
│ ├── schemas.py
│ └── ws.py
├── pockets/ # pockets, widgets, sharing via links, agents
│ ├── router.py
│ ├── service.py
│ └── schemas.py
├── sessions/ # session CRUD, runtime proxy, pocket auto-link
│ ├── router.py
│ ├── service.py
│ └── schemas.py
├── agents/ # agent discovery, CRUD
│ ├── router.py
│ ├── service.py
│ └── schemas.py
├── shared/ # cross-cutting concerns
│ ├── deps.py # current_user, workspace_id, require_role()
│ ├── db.py # MongoDB connection + Beanie init
│ ├── errors.py # CloudError hierarchy + exception handler
│ ├── events.py # internal async pub/sub for side effects
│ └── permissions.py # role checks, pocket access, share link validation
├── models/ # existing Beanie models (cleaned up)
└── __init__.py # mount all routers
```
## Data Model Changes
| Model | Changes |
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| User | No change (fastapi-users BeanieBaseUser) |
| Workspace | Add `deleted_at` soft-delete, enforce seat limits at model level |
| Group | Add `last_message_at`, `message_count` counter |
| Message | Add `edited_at`, index on `(group_id, created_at)` for cursor pagination |
| Room | **Merge into Group** — DM is `type: "dm"` with 2 members |
| Pocket | Add `share_link_token`, `share_link_access` (view/comment/edit), `visibility` (private/workspace/public), `shared_with` (explicit user grants) |
| Session | Add `deleted_at` soft-delete |
| Invite | Add `revoked` flag, cleanup index on `expires_at` |
| Notification | Add `expires_at` for auto-cleanup |
| Comment, FileObj, Agent | No change |
**Session ↔ Pocket linking**: sessions auto-attach to pockets. Creating a pocket with `session_id` links the session. `Session.pocket_id` set on attachment.
## WebSocket Architecture (replacing Socket.IO)
Single endpoint: `ws://host/ws/cloud?token=