# weibaohui/openDeepWiki

> Go server (not AIDotNet's OpenDeepWiki) where Eino agent chains with shell access plan a wiki, write each page and answer chat.

- Category: [Open-source DeepWiki](https://llms-technical-reviews.com/open-source-deepwiki/)
- Repository: https://github.com/weibaohui/openDeepWiki (reviewed at commit `bf64e72c1c4b379c24b41ddcc289bcd9b282bc49`, 2026-03-26)
- Stars: 101 · Language: Go · License: n/a
- Canonical page: https://llms-technical-reviews.com/p/opendeepwiki-go/

## Overview

This is **weibaohui/openDeepWiki**, a Go project. It is not **AIDotNet/OpenDeepWiki**, the larger C#/.NET project reviewed on this site under the slug `opendeepwiki`. The two share a name and a goal, but no code, stack or authors. This one is a single Go binary (Gin, GORM, CloudWeGo's Eino ADK) with a React and Ant Design X front end embedded in it. Prompts, logs and generated wiki titles are in Chinese.

The design is agent-first. There is no file chunking, no embedding index and no static page plan. When a repository is added, the server shallow-clones it. A two-agent chain (`toc_editor` then `toc_checker`) then explores the checkout with file and shell tools and emits a YAML list of chapters with outlines and hints. Each chapter becomes a queued task. Another chain of three agents writes, lints and fact-checks that page. Agents are YAML files that are hot-reloaded from disk. Models are API-key rows in the database with priority-ordered failover.

Around that core sit a chat assistant over WebSocket, an MCP server for coding tools, incremental updates driven by `git pull` and diff, document versions and ratings, PDF export, and push-sync to another instance.

## Architecture

```mermaid
flowchart LR
  UI["React UI (embedded)"] --> API["Gin /api router"]
  API --> RS["RepositoryService"]
  RS --> CLONE["git clone --depth 1"]
  RS --> BUS["Event buses"]
  BUS --> TS["TaskService"]
  TS --> SCHED["Pending scheduler (10 s)"]
  SCHED --> ORCH["Orchestrator (1 worker)"]
  ORCH --> W["Writers: toc / default / api / db / incremental"]
  W --> SEQ["Eino SequentialAgent"]
  SEQ --> TOOLS["list_dir, read_file, search_files, run_terminal_command"]
  SEQ --> PM["ProxyChatModel + model pool"]
  W --> DB["SQLite or MySQL (GORM)"]
  API --> CHAT["Chat WebSocket: chat_assistant"]
  CHAT --> PM
  MCP["/mcp/streamable"] --> DOCS["DocumentService keyword search"]
  DOCS --> DB
```

| Component | Path | Role |
|---|---|---|
| Entry point | `backend/cmd/server/main.go` | Wires repos, services, writers, buses, orchestrator, MCP and router |
| Writers | `backend/internal/domain/writers/` | `toc`, `default`, `api`, `dbmodel`, `incremental`, `title_rewriter`, `doc_rewriter`, `user_request` |
| Agent runtime | `backend/internal/pkg/adkagents/` | YAML loader and watcher, `Manager`, `BuildSequentialAgent`, model pool, rate limiter |
| Agent tools | `backend/internal/pkg/adkagents/tools/` | File listing, reading and search, shell, skills, `read_doc` |
| Agent definitions | `backend/agents/*.yaml` | Instructions, tool lists, `maxIterations`, optional `model` per agent |
| Tasks | `backend/internal/service/task*.go`, `orchestrator/` | Task state machine, `RunAfter` dependencies, ants worker pool |
| Documents | `backend/internal/service/document.go` | Versions, keyword search, export |
| Chat | `backend/internal/handler/chat_handler.go` | WebSocket hub and streaming of agent events |
| MCP | `backend/internal/mcp/server.go` | Five read-only tools over the generated docs |
| Sync and activity | `backend/internal/service/sync/`, `activity_scheduler.go` | Push to a remote instance; scheduled incremental refresh |

## How a request flows

Adding a repository and getting its wiki:

1. **Create.** `POST /api/repositories` calls `RepositoryService.Create`. It normalises HTTPS or SSH URLs, rejects duplicates by host/owner/repo, and stores a `pending` row with a timestamped local path ([repository.go](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/service/repository.go#L63-L97)).
2. **Clone and plan.** The repo-added event runs `CloneRepository`, which starts `git clone --depth 1` in a goroutine (10-minute timeout). The same handler immediately publishes a `TocWrite` event ([repo_event_subscriber.go](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/subscriber/repo_event_subscriber.go#L36-L57), [repository_clone.go](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/service/repository_clone.go#L15-L124), [git.go](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/pkg/git/git.go#L42-L65)).
3. **Queue.** Tasks are created as `pending`. Every 10 seconds, `enqueuePendingTasks` pushes them into the global orchestrator once their `RunAfter` dependency has succeeded ([task.go](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/service/task.go#L183-L254)). The orchestrator is an `ants` pool started with **one** worker, despite a comment that says two ([main.go](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/cmd/server/main.go#L140-L145)).
4. **TOC.** `tocWriter.genDirList` builds a `SequentialAgent` of `toc_editor` and `toc_checker` and asks for strict YAML with `dirs` and `analysis_summary`. `parseDirList` unmarshals the reply, and each dir becomes a `DocWrite` task with its outline and hints stored ([toc.go](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/domain/writers/toc.go#L56-L180)).
5. **Write a page.** `CreateDocWriteTask` first inserts a placeholder document (title cut to 20 runes) ([task_helper.go](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/service/task_helper.go#L43-L85)). When the task runs, `defaultWriter.genDocument` chains `document_generator`, `markdown_checker` and `document_checker`. Its prompt holds the repo path, title, outline and hints ([default.go](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/domain/writers/default.go#L64-L120)).
6. **Run agents.** `RunAgentToLastContent` iterates the Eino runner and keeps the last message. That text is the page ([agent_factory.go](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/pkg/adkagents/agent_factory.go#L52-L147)).
7. **Save.** `executeTaskLogic` writes the content into the placeholder document. A rewrite task creates a new version and moves the `IsLatest` flag ([task.go](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/service/task.go#L296-L357)).

API and database-model chapters are not part of the automatic plan. They are separate buttons (`/api-analyze`, `/db-model-analyze`) that queue the `apiWriter` or `dbModelWriter` chains.

## Key components

### Agents as YAML

`Manager.createADKAgent` turns a definition into an Eino `ChatModelAgent` ([manager.go](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/pkg/adkagents/manager.go#L238-L346)). It picks a model: the named pool, one named key, or a dynamic proxy over all enabled keys. It resolves each tool name through `ToolProvider`, sets 3 retries on rate-limit errors, and appends the iteration cap to the instruction. Unknown tool names are skipped with only a log line. For example, `chat_assistant.yaml` lists `git_log` and `git_show`, which the provider does not implement ([tools_providers.go](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/pkg/adkagents/tools_providers.go#L19-L44)). Every tool is rooted at the shared `Data.RepoDir`, not at the current repository's folder. An agent writing about one repo can therefore read the others.

### Shell access

Most writer agents get `run_terminal_command`. It runs `sh -c <command>` with a 30-second timeout. The empty allow-list means all commands are allowed, and the only guards are a working-directory check and a substring test for `..` ([cmd.go](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/pkg/adkagents/tools/cmd.go#L72-L126)). The agents read untrusted repository content, so a prompt injection in a README can reach a shell on the server. Run it in a container.

### Model pool

API keys are database rows (provider, base URL, model, priority, status). The provider `anthropic` gets Eino's Claude client with `MaxTokens: 4096`. Everything else goes through the OpenAI-compatible client ([model_provider.go](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/pkg/adkagents/model_provider.go#L140-L194)). `ProxyChatModel` tries up to three models from the pool in turn and records token usage per task ([proxy_model.go](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/pkg/adkagents/proxy_model.go#L64-L140)). The Claude client also overwrites request headers to pose as the Claude Code CLI (`claude-cli` user agent, `claude-code-20250219` beta) ([claude_header_transport.go](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/pkg/adkagents/claude_header_transport.go#L20-L44)).

### Chat and MCP

The chat handler puts the repo's metadata and a list of document titles and IDs into a system message, adds the last 20 messages, and streams the `chat_assistant` agent's events over WebSocket ([chat_handler.go](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/handler/chat_handler.go#L502-L581)). The agent can `read_doc` a generated page or read raw source with the file tools. The MCP server registers `list_repositories`, `get_repository`, `search_documents`, `read_document` and `get_document_summary` ([server.go](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/mcp/server.go#L57-L123)). Search is a case-insensitive substring scan over every latest document in memory, capped at 20 hits ([document.go](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/service/document.go#L331-L401)).

### Incremental updates

The incremental writer runs `git pull` (unshallowing when needed), summarises the diff since the stored commit, and asks `incremental_editor`/`incremental_checker` which chapters to add or rewrite. It then queues `DocWrite` or content-rewrite tasks. An activity scheduler can trigger this automatically for repos in `completed` state ([activity_scheduler.go](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/service/activity_scheduler.go#L95-L112)).

## Extending it

- **Agents.** Edit or add YAML under the agent directory (`AGENT_DIR`). Defaults are extracted from the binary on first start, and a polling file watcher reloads changes. Agent versions are tracked in the database.
- **Skills.** Agents can call `list_skills` and run scripts from `SKILL_DIR` through the shell tool. One sample skill ships: `go-backend-stack-analyzer`.
- **Writers.** Implement `domain.Writer` (`Name`, `Generate`) and register it with `taskService.AddWriters` in `main.go`.
- **Models.** Add rows on the API-key page. Any OpenAI-compatible endpoint works. A `model` field in an agent's YAML pins that agent to one key.
- **External tools.** Point an MCP client at `/mcp/streamable`. `/.well-known/openapi.yaml` describes the REST API.

## Running it

- **Build.** `make build` builds the front end, embeds it and the agents, and produces one Go binary. Docker images use Alpine and expose 8080. `make dev` runs the hot-reload setup.
- **Config.** `config.yaml` (or `CONFIG_PATH`) sets the port, the database (`sqlite` default, or `mysql` via `DB_TYPE`/`DB_DSN`) and the data and repo directories. LLM keys are **not** in the config file, whatever the README's quick-start says. They are added in the UI and stored in the database.
- **Requirements.** `git` on the PATH, network access to the git host and the LLM endpoints. A `github.token` key appears in the example config, but no Go code reads it, so private repos depend on the host's own git credentials.
- **Security.** No authentication on any route, and CORS `*` with credentials ([router.go](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/router/router.go#L25-L64)), plus the shell tool above. Treat it as a single-user tool behind a firewall.

## Strengths and caveats

- **Strength: grounded in the code.** Pages come from agents that read the actual files. The generator prompt requires a source link on every code block and forbids invented code, and a separate `document_checker` pass reviews the draft.
- **Strength: operational features.** Task state machine, retries, stuck-task cleanup, per-task token accounting, document versions and ratings, model failover, incremental refresh and MCP. That is more operations tooling than most projects of this size have.
- **Strength: configurable without recompiling.** Prompts, tool sets and model choice per agent are plain YAML.
- **Caveat: serial and slow.** With one orchestrator worker, a repo's chapters are written one at a time, and the generator agent alone may take up to 100 tool iterations per page.
- **Caveat: plan races the clone.** The TOC task is queued while the clone is still running, and nothing waits for `ready`. On a slow clone, the first plan can see a partial tree or fail and need a retry.
- **Caveat: Chinese-only output.** The TOC prompt asks for Chinese titles, and no language setting exists.
- **Caveat: unsafe defaults.** Unrestricted `sh -c`, cross-repo file access and an open API make it unsuitable for untrusted repos or shared hosting as shipped.
- **Caveat: small details.** The `BuildSequentialAgent` error in `genDirList` is never checked, and `WriteComplete` events are published with no subscriber.

*Sources: code at bf64e72, verified Q&A.*

## How weibaohui/openDeepWiki answers the Open-source DeepWiki questions

### How is a repository ingested and chunked? (answered)

Repository ingestion starts when a user submits a Git URL via `POST /api/repositories`. The `RepositoryService.Create()` method normalizes the URL (supporting HTTPS and SSH formats via `git.NormalizeRepoURL`), checks for duplicates, and persists the repo with `pending` status. An async event (`RepositoryEventAdded`) triggers `cloneRepository()` in `repository_clone.go`, which uses `git clone --depth 1` (shallow clone) to clone into `{Data.RepoDir}/{repoName}-{timestamp}`. After cloning, it records the branch, commit hash, and directory size, then transitions the repo to `ready` status. **There is no chunking or file-level filtering** — the entire repository is available at the filesystem level. Analysis is performed by AI agents that read files directly using tools (`read_file`, `list_dir`, `search_files` in `tools_providers.go`). Supported hosts: any Git host reachable via HTTP/HTTPS or SSH — the URL normalizer validates the format but does not restrict hosts. Large-repo limits are limited only by the shallow clone strategy (`--depth 1`); there is no explicit file-count or size cap in the code.


Citations: [backend/internal/service/repository.go:63-97](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/service/repository.go#L63-L97) · [backend/internal/service/repository_clone.go:47-124](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/service/repository_clone.go#L47-L124) · [backend/internal/pkg/git/git.go:42-65](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/pkg/git/git.go#L42-L65) · [backend/internal/pkg/adkagents/tools_providers.go:19-44](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/pkg/adkagents/tools_providers.go#L19-L44)

### How is retrieval (RAG) implemented? (answered)

There is **no vector embeddings model or vector store**. Retrieval is entirely keyword-based. `DocumentService.SearchDocuments()` performs case-insensitive substring matching across document title, filename, and content fields (lines 331–401 of `document.go`). Results are capped at 20 with snippet generation (200 characters around the keyword match). The MCP server exposes `search_documents`, `read_document`, and `get_document_summary` tools that wrap these same keyword searches. In the Q&A chat system, the assistant agent receives the full repo metadata and a list of all documents (titles and DocIDs) injected into the system message. It can then call the `read_doc(doc_id)` tool to retrieve the complete document content when answering questions — this is agentic file reading, not RAG. There is no embedding, no top-k vector search, no similarity scoring anywhere in the codebase. The use of `ModelWithMetadata` and `ChatModel` wrappers (e.g., `ProxyChatModel`) shows that after an LLM receives context through the agent tools, generation happens directly via the configured provider model.


Citations: [backend/internal/service/document.go:328-401](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/service/document.go#L328-L401) · [backend/internal/mcp/server.go:86-122](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/mcp/server.go#L86-L122) · [backend/internal/handler/chat_handler.go:502-522](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/handler/chat_handler.go#L502-L522) · [backend/internal/pkg/adkagents/tools_providers.go:36-37](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/pkg/adkagents/tools_providers.go#L36-L37)

### How is the wiki structure (table of contents) determined? (answered)

The wiki table of contents is determined by an **LLM agent** — not by statically parsing the file tree. Triggered via `POST /api/repositories/:id/directory-analyze`, it creates a `TocWrite` task that invokes the `TocWriter` (`toc.go`). The writer builds a sequential agent pipeline of two sub-agents: `toc_editor` (analyzes the repo and proposes topics) then `toc_checker` (validates and corrects the list). The agent prompt passes the local repo path and asks it to identify the project type, tech stack, and generate a structured task list. The agent outputs must be strict YAML with two fields: `dirs` (array of objects with `title`, `sort_order`, `outline`, and `hint`) and `analysis_summary`. Each generated `dir` creates a `DocWrite` sub-task. Evidence (hints) from the TOC analysis — such as file locations, aspect details, and source references — are saved to the `TaskHint` repo and later fed to page-generation agents as context cues. The output YAML is parsed via `parseDirList()`, which does YAML extraction and unmarshalling against the `DirMakerGenerationResult` struct.

> **Editor's note.** Correction: the TOC pass runs automatically when a repository is added (handleRepoAdded publishes a TocWrite event right after starting the clone); POST /directory-analyze is only a manual re-trigger.

Citations: [backend/internal/domain/writers/toc.go:56-86](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/domain/writers/toc.go#L56-L86) · [backend/internal/domain/writers/toc.go:110-155](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/domain/writers/toc.go#L110-L155) · [backend/internal/domain/dirmaker.go:1-23](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/domain/dirmaker.go#L1-L23) · [backend/internal/domain/writer_interface.go:40-55](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/domain/writer_interface.go#L40-L55)

### How are individual pages generated? (answered)

Individual pages are generated by specialized **writer** implementations, all implementing the `Writer` interface with `Generate(ctx, localPath, title, taskID)`. Each writer builds a sequential agent pipeline from 2–3 sub-agents. For example, `defaultWriter` uses `document_generator` → `markdown_checker` → `document_checker`; `dbModelWriter` uses `db_model_explorer` → `document_checker` → `markdown_checker`; `apiWriter` uses `api_explorer` → `document_checker` → `markdown_checker`. The agent receives the local repo path, the document title, an outline (from the TOC stage), and context hints. Hints are searched by domain-specific keywords: the DB model writer searches hints for `"sql", "ddl", "schema", "model"` etc., while the API writer searches for `"api", "route", "handler", "endpoint"` etc. Each writer's prompt instructs Markdown output. Diagrams (Mermaid) are rendered client-side: the frontend's `MermaidRender.tsx` component renders Mermaid blocks in generated Markdown, with special handling for character escaping and dark/light theme support. Tasks run independently through an event bus and orchestrator, enabling parallelism — multiple pages can be generated concurrently. Document versions are tracked via a `Version` integer and `IsLatest` flag; regenerating a page creates a new version while preserving older ones.

> **Editor's note.** Correction: pages are not generated concurrently. main.go initialises the global orchestrator with one worker (InitGlobalOrchestrator(1, ...)), so DocWrite tasks run strictly one after another.

Citations: [backend/internal/domain/writers/default.go:64-120](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/domain/writers/default.go#L64-L120) · [backend/internal/domain/writers/dbmodel.go:59-113](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/domain/writers/dbmodel.go#L59-L113) · [backend/internal/domain/writers/api.go:62-118](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/domain/writers/api.go#L62-L118) · [frontend/src/components/markdown/MermaidRender.tsx:84-150](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/frontend/src/components/markdown/MermaidRender.tsx#L84-L150) · [backend/internal/model/models.go:48-63](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/model/models.go#L48-L63)

### How are model providers configured? (answered)

Provider configuration is managed through the `APIKey` model stored in the database. Each key has fields: `provider`, `base_url`, `api_key`, `model`, `priority`, `status` (`enabled`/`disabled`/`unavailable`). The `EnhancedModelProviderImpl` reads keys from the `api_key` repo to create model instances. Two provider types are supported: `"anthropic"` uses the `claude.NewChatModel` with native Claude config (supporting thinking features and the Claude Code HTTP client), while all other providers default to OpenAI-compatible via `openai.NewChatModel` — this means any OpenAI-compatible endpoint (local Ollama, vLLM, etc.) works by setting the appropriate `base_url`. Per-stage model assignment is configured per Agent YAML definition: each agent can set a `model` field (referencing an APIKey by name) or `use_model_pool` for multi-model fallback. The `ProxyChatModel` wraps the model with automatic retry, rate-limit detection, and failover across the priority-ordered model pool. On rate-limit errors, the `RateLimiter` marks the model unavailable and `GetNextModel()` picks the next available one from the pool. If no model name is specified, a dynamic `ProxyChatModel` auto-selects from all database-enabled keys.


Citations: [backend/internal/pkg/adkagents/model_provider.go:140-194](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/pkg/adkagents/model_provider.go#L140-L194) · [backend/internal/pkg/adkagents/manager.go:238-273](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/pkg/adkagents/manager.go#L238-L273) · [backend/internal/pkg/adkagents/proxy_model.go:14-60](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/pkg/adkagents/proxy_model.go#L14-L60) · [backend/internal/model/api_key.go:9-49](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/model/api_key.go#L9-L49)

### How is interactive Q&A / chat implemented? (answered)

Interactive Q&A is implemented over **WebSocket**. A session is created via `POST /api/repositories/:id/chat/sessions`, then the frontend upgrades to a WebSocket at `/repositories/:id/chat/sessions/:session_id/stream`. The client sends JSON `{"type":"message","content":"..."}` and the server streams back event types: `thinking_start`, `content_delta` (streaming text chunks), `tool_call`, and `assistant_end`. The chat agent in `chat_handler.go` (the `runAgent` method) injects repo metadata (name, URL, branch, commit, description) plus a full document list with `DocID`s into the system message. The agent can call `read_doc(doc_id)` to retrieve full document content — this is the primary retrieval mechanism. Conversation history (last 20 messages) is sent as context. Streaming is achieved by iterating the Eino ADK runner's event stream and forwarding each `content_delta` to the client. Tool calls are streamed to the frontend in real-time and saved to the database. Message limit is 1000 per session. The MCP server (`mcp/server.go`) provides a parallel external-facing interface with `search_documents`, `read_document`, `get_document_summary`, `list_repositories`, and `get_repository` tools — this is how external AI tools (Claude Code, etc.) query the wiki. No deep-research mode was found in the codebase.

> **Editor's note.** Correction: besides read_doc, the chat agent can read raw source via list_dir, read_file and search_files; the git_log and git_show tools listed in chat_assistant.yaml do not exist in ToolProvider and are silently dropped.

Citations: [backend/internal/handler/chat_handler.go:265-310](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/handler/chat_handler.go#L265-L310) · [backend/internal/handler/chat_handler.go:486-694](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/handler/chat_handler.go#L486-L694) · [backend/internal/mcp/server.go:57-122](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/mcp/server.go#L57-L122) · [backend/internal/model/models.go:129-173](https://github.com/weibaohui/openDeepWiki/blob/bf64e72c1c4b379c24b41ddcc289bcd9b282bc49/backend/internal/model/models.go#L129-L173)
