An agentic research harness β a Claude-Code-style backend that answers hard questions by planning, running tools, and self-correcting in a loop instead of replying in a single shot.
Give it a question β optionally with uploaded files, folders, or images β and it decomposes the work into a plan, executes the steps as parallel sub-agents with real tools (web search, crawling, browser automation, document parsing, cross-document retrieval, code/shell execution), then evaluates, replans, and reflects until the answer is genuinely sufficient. Progress and the final Markdown answer stream live to a minimal web UI with multi-session chat history.
"Never take no for an answer." β the design principle: prefer trying another tool or approach over surfacing a refusal.
- Highlights
- Screenshots
- Features
- Tool Catalogue
- Architecture
- Quick Start
- Configuration
- Project Structure
- Development
- Docker
- Documentation
- License
- π§© Multi-agent planning β a NetworkX DAG of steps run as parallel sub-agents, with dynamic replanning mid-run.
- π Self-correcting loop β evaluator reshapes the plan; sub-agents critique their own results and gather more.
- π± Recursive fan-out β any agent can split its task into more parallel child agents at run time.
- π RAG-grade retrieval β hybrid embeddings + BM25 + Reciprocal Rank Fusion + rerank, across your whole document corpus.
- π οΈ ~16 real tools β from Google-grounded search to headless-browser automation to a Python/Bash sandbox.
- π‘ Live streaming β plan, tool activity, reflections, and the answer stream over SSE; runs can be stopped and revised.
- π Locale-aware β resolves the visitor's country to localize sources, units, language, and the scraping browser's fingerprint.
- π° Cost-aware & robust β token ledger, per-session budgets, timeouts, circuit breakers, caching, and context compaction.

Composer β attach a π file or a π folder (only supported types are ingested), then ask.
Research engine
- Multi-agent research β the planner decomposes the question; the orchestrator runs ready DAG nodes as parallel sub-agents; the evaluator reshapes the plan (add / drop / reorder / insert steps); the answer is synthesized and streamed.
- Dynamic plan reshaping β the evaluator can append steps, drop pending ones, and inject dependency edges to reorder or insert a prerequisite mid-run, without deadlocking the DAG.
- Recursive sub-agent fan-out β the
spawn_subagentstool splits a task into N independent child agents (each with the full tool set), bounded by configurable depth / fan-out. - Sub-agent self-reflection β after each pass a sub-agent critiques its own result ("sufficient, or gather more?") and loops until sufficient or capped.
- Source-chasing extraction β when a source only points to another document, the agent follows the reference (crawl β link map β download β raw-HTML inspection β browser interaction) instead of stopping at the pointer.
Retrieval & knowledge (RAG)
- Hybrid cross-document retrieval β
corpus_searchsearches every uploaded document and image at once, fusing dense embeddings (semantic) and sparse BM25 (lexical) via Reciprocal Rank Fusion, then LLM-reranks the candidates β the shape used by OpenAI file_search / Vertex AI RAG Engine. - Structure-aware chunking β chunks respect heading boundaries and carry a breadcrumb, so every retrieved passage says where it came from.
- Embedding cache β chunk embeddings are cached on disk per source artifact (keyed by model + chunk params), so follow-up questions and later turns never re-embed.
- Single-document retrieval β
bm25_search(lexical) anddoc_navigate(PageIndex reasoning over a section tree) for pinpoint work in one file. - File, folder & image Q&A β upload individual files or an entire folder (only supported types are ingested, structure preserved); images are auto-described via Gemini vision and folded into the searchable corpus.
Interaction & UI
- Single-page web UI (vanilla JS) β ask questions, attach files/folders, watch the plan and activity stream, render Markdown + Mermaid.
- Streaming + stop + revise β SSE streams plan/tool/reflection/answer events; a run can be stopped mid-flight and revised with a new instruction, reusing prior results.
- Multi-session continuity β prior conversation and artifacts feed into new turns; each query is a new "turn" with its own plan scoped by turn number.
- Right-panel tabs β Plan (per-turn step groups), Activity (full trace), and Files (session artifacts as a tree, downloadable).
- Export β download a chat as clean Markdown, or a full export with per-turn plan steps + activity trace.
Robustness & operations
- Per-model context & thinking selection β choose model + thinking level (low/medium/high) per session from a central catalogue that drives context windows and output caps.
- Live "now" β every model turn is stamped with the current date/time (and, optionally, the user's country) so reasoning about recency and "latest" beats the training cutoff.
- Country / locale context β resolves the visitor's country (browser-detected or configured) to localize sources, units, language, and pin the scraping browser's locale, timezone, geolocation, and
Accept-Language. - Dynamic robustness β per-tool timeouts, a per-session circuit breaker for flaky tools, an in-session result cache, a no-progress guard, and refusal detection.
- Context management β large excerpts fed generously against the 1M-token window; the tool loop is compacted (summarized) once it crosses a model-derived threshold.
- Cost accounting β every LLM call is written to a token ledger; per-session input/output totals are tracked and shown, with an optional per-session budget cap and per-run wall-clock timing.
- Persistent activity trace β every meaningful event is persisted, so a session replays its full trace on reopen and in exports.
Agents call tools via manual function-calling. Each tool declares a JSON schema, a timeout, and whether it's "breakable" (subject to circuit-breaking).
| Tool | Category | What it does |
|---|---|---|
web_search |
π Web | DuckDuckGo search (region-configurable, retries transient backends). |
gemini_search |
π Web | Fast factual answer grounded in Google Search, with source URLs. |
crawl_url |
π Web | Headless-browser fetch β clean Markdown + a structured link map + a raw-HTML artifact. |
discover_sitemap |
π Web | Enumerate a site's page URLs from robots.txt + sitemaps (recursive, httpx-only). |
browser_use |
π Web | Prompt-driven browser automation for JS-heavy / interactive pages. |
download_file |
π₯ Files | Fetch a remote file into the session as an artifact. |
parse_document |
π Docs | Convert PDF/DOCX/XLSX/PPTX/HTML/β¦ to Markdown (MarkItDown). |
read_artifact |
π Docs | Read a chunk of parsed Markdown or a raw text artifact by offset. |
bm25_search |
π Retrieval | Lexical BM25 search within one parsed document. |
doc_navigate |
π Retrieval | PageIndex: reason over a document's section tree to pull the right section. |
corpus_search |
π Retrieval | Hybrid embeddings + BM25 + RRF + rerank across ALL documents. |
analyze_image |
ποΈ Vision | Ask a question about an uploaded/downloaded image. |
python_exec |
π» Sandbox | Run Python for computation / data wrangling. |
bash_exec |
π» Sandbox | Run shell commands. |
deep_think |
π§ Reasoning | Pure-reasoning step (no I/O): analysis β options β recommendation β next steps. |
spawn_subagents |
π± Orchestration | Fan a task out into N parallel child agents with the full tool set. |
Layered FastAPI service. Routes parse input and call services; services own business logic and call repositories; repositories own all DB access.
flowchart TD
UI[ui/index.html<br/>vanilla JS SPA] -->|REST + SSE| API[api/v1/sessions.py]
API --> SESS[SessionService]
API --> AGENT[AgentService<br/>single-turn chat]
API --> ORCH[OrchestratorService<br/>multi-agent research]
ORCH --> PLAN[PlannerService<br/>plan / evaluate / revise / reflect / synthesize]
ORCH --> LOOP[agent_loop<br/>tool-calling loop]
AGENT --> LOOP
PLAN --> LLM[LlmClient<br/>Gemini wrapper + embeddings]
LOOP --> LLM
LOOP --> TOOLS[Tool registry ~16 tools]
ORCH --> BUS[event_bus<br/>SSE queue + stop flag]
API -->|drains queue, persists trace| REPO[(Repositories)]
REPO --> DB[(SQLite / async SQLAlchemy)]
TOOLS --> EXT[External: Gemini, web,<br/>headless browsers, files]
Stack: Python 3.14 (via uv) Β· FastAPI + Uvicorn Β· async SQLAlchemy 2.x
(SQLite by default, Postgres-capable) Β· Google Gemini (google-genai) Β·
NetworkX (plan DAG) Β· MarkItDown, crawl4ai, browser-use, ddgs, rank-bm25, NumPy.
Install uv:
curl -LsSf https://astral.sh/uv/install.sh | sh# 1. Create the environment with the pinned Python version
uv venv --python 3.14.2
# 2. Install dependencies
uv pip install -r requirements.txt
# 3. Configure β copy the sample and set your Gemini key
cp .env.sample .env
# edit .env β set GEMINI_API_KEY=...
GEMINI_API_KEYis the only required value; everything else has a sensible default (seeapp/core/config.py).
uv run uvicorn main:app --reload- π₯οΈ Web UI β open http://127.0.0.1:8000/ui/ β ask a question, attach files or a folder, watch the plan/activity stream, and export a chat as Markdown.
- β€οΈ Health check β http://127.0.0.1:8000/health
uv runexecutes inside the project environment automatically β no manual activation needed.
All knobs live in .env (loaded by app/core/config.py). The
ones most worth knowing:
| Setting | Default | Purpose |
|---|---|---|
GEMINI_API_KEY |
β | Required. Google Gemini API key. |
GEMINI_MODEL |
gemini-3.1-flash-lite |
Default chat/reasoning model (per-session override in the UI). |
EMBEDDING_MODEL |
gemini-embedding-001 |
Embedding model for corpus_search. |
EMBEDDING_DIMENSIONS |
768 |
Embedding vector size (Matryoshka truncation). |
CORPUS_TOP_K |
8 |
Passages corpus_search returns per query. |
CORPUS_RERANK |
true |
LLM-rerank fused candidates for precision. |
MAX_AGENT_ITERATIONS |
120 |
Max tool-loop turns for single-agent chat. |
MAX_PLAN_ITERATIONS |
60 |
Max planβexecuteβevaluate replans per research run. |
SUBAGENT_MAX_ITERATIONS |
60 |
Max tool-loop turns per sub-agent. |
MAX_PLAN_NODES |
48 |
Hard cap on plan-graph nodes (runaway guard). |
SUBAGENT_MAX_REFLECTIONS |
2 |
Self-critique rounds per sub-agent. |
SESSION_TOKEN_BUDGET |
0 |
Per-session token cap (0 = unlimited). |
USER_COUNTRY |
β | Fallback locale context (ISO-2 code or name); UI overrides per request. |
Unlimited iterations: the iteration caps accept
0(or any non-positive value) to mean no limit β the loop then runs until the model answers, the run is stopped, the token budget is hit, or the no-progress guard trips. Pair this with a token budget, since the iteration cap is otherwise the main runaway guard.
main.py # entrypoint: create_app() factory + uvicorn runner
app/
βββ api/v1/ # HTTP routers (sessions, health) + aggregator
βββ core/ # config, model catalogue, logging, exceptions, request context
βββ db/ # async engine / session / Base + lightweight migrations
βββ models/ # SQLAlchemy ORM models
βββ repositories/ # all DB access & ORM queries
βββ schemas/ # Pydantic DTOs (some double as Gemini structured-output schemas)
βββ services/ # planner, orchestrator, agent loop, LLM client, event bus, use-cases
βββ tools/ # agent tools + registry (search, crawl, retrieval, exec, browser, β¦)
βββ retrieval/ # PageIndex section tree + chunking + hybrid RRF ranking
utils/ # pure helpers (response envelope, geo/locale, β¦)
tests/ # pytest + httpx (offline, fake LLM via dependency_overrides)
ui/ # single-file vanilla-JS SPA
docs/ # design docs (idea, implementation plan)
app/uses namespace packages (no__init__.py) β run mypy with--explicit-package-bases.
uv run pytest -v # tests (offline, no API key needed)
uv run ruff check . # lint
uv run mypy --explicit-package-bases . # type-check
uv run pre-commit install # enable git hooks (ruff + mypy)Contributions follow the Backend Engineering Guide (KISS / YAGNI / DRY / SoC / SOLID, strict layering, full type annotations).
docker compose up --buildThe image uses the python:3.14.2-slim base and installs dependencies with uv.
Production: replace
--reloadwith a production-ready configuration and setENV=production,DEBUG=False. SQLite is the default store; the database URL is configurable (Postgres-capable).
.github/REPO_MAP.mdβ architecture, component responsibilities, feature map, and important concepts..github/copilot-instructions.mdβ the engineering guide governing all AI-assisted and human contributions.docs/β the original brief (idea.md) and the phased implementation plan.
No license has been declared yet. Until a LICENSE file is added, all rights are
reserved by the authors β add one (e.g. MIT / Apache-2.0) to make reuse terms
explicit.




