Set up a dev environment, run tests, follow the conventions, and extend Octopus (new tools & providers).
📎 Related: Code Structure · Tools Reference · Providers & Models
git clone https://github.com/Masriyan/Octopus-Ai.git
cd Octopus-Ai
python3 -m venv venv && source venv/bin/activate
pip install -r backend/requirements.txt
playwright install chromium # for the Web Browse tentacle
cp .env.example .env # add keys (optional)Run the two tiers separately for hot-reload:
# backend (auto-reload)
cd backend && python3 -m uvicorn main:app --reload --port 8000
# frontend (static)
cd frontend && python3 -m http.server 5500- Backend API docs:
http://localhost:8000/docs. - The frontend is a module script — serve it over HTTP (don't open
index.htmlviafile://, ES modules are blocked there).
cd backend
pytest tests/ -qThe suite covers the file tool, memory, and web tool. An autouse fixture in conftest.py points OCTOPUS_WORKSPACE_DIR at each test's tmp_path, so File/Shell tests stay inside the sandbox.
Monkeypatch the provider factory with a fake that yields the streaming event dicts:
import agent as agent_mod
class Fake:
supports_native_tools = True
async def chat_stream(self, messages, tools=None, model=None, temperature=0.7):
yield {"type": "text", "content": "hi"}
yield {"type": "done"}
async def chat(self, *a, **k): return {"type": "text", "content": "", "tool_calls": []}
agent_mod.get_provider = lambda name, cfg: Fake()You can then drive agent.process_message(...) directly, or hit the whole app (including the WebSocket) with FastAPI's TestClient:
from fastapi.testclient import TestClient
import main
with TestClient(main.app) as c:
cid = c.post("/api/conversations").json()["id"]
with c.websocket_connect(f"/ws/chat/{cid}") as ws:
ws.send_json({"content": "hi"})
# drain events until {"type":"done"}⚡ Tip: importing the backend pulls in
sentence-transformers/torch(heavy). For fast unit tests that don't need RAG, stub them before import:import sys for m in ("sentence_transformers","qdrant_client","qdrant_client.models","torch"): sys.modules[m] = NoneThis makes
VectorMemory.enabled = False(RAG no-ops) and the app boots instantly.
- PEP 8, type hints on signatures, docstrings on classes/public functions.
async/awaitfor all I/O. Tools must beasyncand return errors as{"status":"error", …}(never raise to the agent).- Keep functions focused; prefer small helpers.
- Treat any external/tool content as untrusted — wrap it and never let it act as instructions.
- Vanilla JS, no frameworks, no build step.
const/letonly; small descriptive functions; comment non-obvious logic.- Render model/tool output through
renderMarkdown(which sanitizes via DOMPurify) — neverinnerHTMLraw model text.
- One logical change per commit; clear messages; focused PRs.
data/,.env,venv/, caches are git-ignored — never commit secrets or runtime data.
backend/tools/your_tool.py— subclassBaseTool, implementasync execute. (Pattern in Tools Reference.)- Import + add it in
register_all_tools()(backend/tools/__init__.py). - Default toggle: add
tools_enabled.<category>: trueinconfig.py. - UI: add a checkbox
id="tool-<category>"infrontend/index.html(Tentacle Permissions), and an icon inapp.js(toolIcons+TOOL_ICONS). - Test it: instantiate and
await tool.execute(...).
backend/llm_providers.py— subclassBaseLLMProvider; implementchat_stream+chat; setsupports_native_tools. Convert the canonical OpenAI-style messages to your API (reuse the Anthropic/Gemini converters as references).- Add a branch in
get_provider(name, config). - (Optional)
list_models()+ a case inGET /api/models/{provider}. - UI: add the provider to the header
<select>and the settings provider cards, and handle it ingetModelsFor(frontend/js/app.js). - Config: add any new keys (e.g. a
base_url) toDEFAULT_CONFIGand.env.example.
Add it to backend/main.py. It will automatically be localhost-restricted and rate-limited. Keep responses JSON-serializable.
| Script | Purpose |
|---|---|
start.sh |
venv + deps + run backend (8000) and frontend (5500) |
backend/run_e2e.sh, backend/run_swarm_e2e.sh |
end-to-end helpers |
backend/test_playwright.py |
Playwright smoke check |
| To change… | Edit |
|---|---|
| The agent loop / planning / emulation | backend/agent.py |
| A model integration | backend/llm_providers.py |
| A tool's behavior | backend/tools/<tool>.py |
| Config defaults/keys | backend/config.py, .env.example |
| The UI markup | frontend/index.html |
| The UI logic | frontend/js/app.js |
| The look | frontend/css/main.css |
See Code Structure for the full map.