- TypeScript 56.3%
- Python 24.4%
- CSS 18.8%
- JavaScript 0.2%
- Makefile 0.2%
| backend | ||
| frontend | ||
| scripts | ||
| .gitignore | ||
| Makefile | ||
| README.md | ||
| THOUGHTS.md | ||
RAGOON
RAGOON is a local web interface for the Document RAG MVP API. It uploads and indexes documents, lets users select the exact sources used for retrieval, optionally sends an editable JSON format to /generate, and renders answers with chunk-level source traceability.
The browser never connects to Ollama, Qdrant, or the upstream RAG service directly. RAGOON uses the Document RAG API for both retrieval and Ollama model access:
Browser :5173
→ relative /api/*
→ RAGOON adapter :8001
→ SSH tunnel on 127.0.0.1:8000
→ remote Document RAG API :8000
├─→ Ollama (model discovery and generation)
└─→ Qdrant (document retrieval)
The small FastAPI adapter keeps the upstream location configurable, provides same-origin browser calls, validates files and requests, normalizes errors, and serves the built frontend in production.
Quick start
First time only
From this repository, install the dependencies and create the local configuration:
make install
cp backend/.env.example backend/.env
Start the application
First, open the SSH tunnel to the remote Document RAG API. This single forwarded API port carries both RAG operations and Ollama-backed model requests; Ollama's port does not need to be exposed to the local machine.
ssh -N \
-o ExitOnForwardFailure=yes \
-o ServerAliveInterval=30 \
-L 8000:127.0.0.1:8000 \
-p 2244 \
sergi@10.5.23.21
The command normally shows no output. Keep that terminal open for the entire RAGOON session; use Ctrl+C to close the tunnel. Reopen it after disconnecting, rebooting, or starting a new development session.
Once the tunnel is open, check both the RAG service and its Ollama model catalog through local port 8000:
curl http://127.0.0.1:8000/health
curl http://127.0.0.1:8000/models
Do not start the adapter or UI until /health succeeds. /models should return the Ollama models available through the RAG API; if it fails while /health succeeds, check Ollama on the remote host.
Then open two more terminals in this repository.
Terminal 1 — start the adapter backend on port 8001:
make backend-dev
Terminal 2 — start the UI on port 5173:
make frontend-dev
Open http://localhost:5173 in your browser.
After the first-time setup, reopen the tunnel and run these two make commands whenever you want to start the application. The complete request flow is:
UI :5173 → adapter :8001 → tunnel :8000 → remote RAG API → Ollama/Qdrant
Prerequisites
- Python 3.11 or newer
- uv
- Node.js 20 or newer and npm
- SSH access to the remote host
- The Document RAG API, Ollama, and Qdrant running on the remote host
Install
make install
cp backend/.env.example backend/.env
This creates backend/.venv from backend/uv.lock and installs frontend dependencies from frontend/package-lock.json.
Configuration
RAG_API_BASE_URL=http://127.0.0.1:8000
RAG_CONNECT_TIMEOUT_SECONDS=5
RAG_READ_TIMEOUT_SECONDS=300
APP_HOST=127.0.0.1
APP_PORT=8001
CORS_ORIGINS=http://localhost:5173
LOG_LEVEL=INFO
FRONTEND_DIST_PATH=../frontend/dist
AUTH_DB_PATH=data/auth.db
AUTH_BOOTSTRAP_ADMINS=sergi,andrea
AUTH_BOOTSTRAP_PASSWORD=
AUTH_SESSION_HOURS=24
AUTH_COOKIE_SECURE=false
AUTH_LEGACY_WORKSPACE_ID=
AUTH_LEGACY_WORKSPACE_NAME=Legacy default workspace
RAG_API_BASE_URL is normalized to remove trailing slashes and is never exposed to browser code. The local .env and backend/data/ are ignored by Git.
For a fresh installation, temporarily set AUTH_BOOTSTRAP_PASSWORD before the first backend start. The listed bootstrap admins are created only when absent, each with a private default workspace. After the first successful startup, remove the plaintext bootstrap password from .env; password changes and later restarts do not require it.
Existing installations can temporarily set AUTH_LEGACY_WORKSPACE_ID=default_workspace to register documents and folders indexed before authentication as a non-default workspace belonging to the first bootstrap administrator. New workspaces always receive random ws_… identifiers.
Run in development
First open the SSH tunnel to the Document RAG API and leave it running:
ssh -N \
-o ExitOnForwardFailure=yes \
-o ServerAliveInterval=30 \
-L 8000:127.0.0.1:8000 \
-p 2244 \
sergi@10.5.23.21
-L 8000:127.0.0.1:8000 maps local port 8000 to port 8000 on the remote host. The adapter accesses only this endpoint. The remote Document RAG API then talks to Ollama and Qdrant, so no separate local 11434 tunnel is required.
Keep the SSH terminal open. In another terminal, verify the RAG API and Ollama model discovery:
curl http://127.0.0.1:8000/health
curl http://127.0.0.1:8000/models
Then use two terminals from this repository:
make backend-dev
make frontend-dev
Open http://localhost:5173. Vite proxies relative /api requests to the RAGOON adapter at http://127.0.0.1:8001.
Application workflow
The application uses a conventional chat layout:
- Sign in with an administrator-created account.
- Select, create, or join a shared workspace below New chat in the left sidebar. Switching workspace changes its conversations, shared memory, and knowledge-base files together.
- Select or start private conversations from the left sidebar.
- Create memory folders in the sidebar, then create or place conversations inside them.
- Use the collapsible right Knowledge base pane to search, upload, organize, and select files without leaving the main screen. Knowledge folders are shared with all workspace members and limited to one level. Checked files influence prompts; unchecked files remain available but are not sent for retrieval. A folder checkbox selects or clears every indexed file it contains. The composer
+can upload a local file or import a public webpage URL; either is indexed, added to the current workspace, and selected without clearing existing sources. - Questions use Normal response by default. Use the adjacent format control to select or create a visual response layout. Its Lexical editor supports titles, headings, emphasis, quotes, code, and lists; RAGOON exports that document to Markdown and converts it into the JSON Schema sent to the RAG API.
- Choose an available Ollama model from the compact model submenu in the composer. The preference is saved per authenticated user and the exact model name is sent with each answer request.
- Enter a prompt. Active knowledge-base files apply to every conversation; with none active, requests go directly to the model's general knowledge.
After the first successful message, the UI makes a separate structured, non-RAG generation request for a short conversation title. This request has no chat_id or folder_id, so it does not affect chat or shared-folder memory.
Each conversation has an actions menu for manual renaming, moving it into or out of a memory folder, and permanent deletion. Deleting a conversation calls DELETE /chats/{chat_id} and removes its browser entry only after the upstream service has deleted that user's private chat memory. It does not delete knowledge-base files, memory folders, or the shared memory previously contributed to a folder.
Normal response sends no custom format field and displays the backend's default answer value as regular text. A visual response layout is edited with Lexical and stored internally as Markdown using Lexical's official import/export transformers. The UI compiles its ordered blocks into an object-shaped JSON Schema, sends it to the upstream API, and renders the returned fields back into Markdown. The generated schema remains available in a collapsed read-only disclosure for debugging. Legacy placeholder-based templates are converted into visual examples when loaded. Each chat response stores the layout used for that request so later edits do not change historical answers. User-created templates remain browser-local under rag-box.formats.v2.
Authentication, users, sessions, workspaces, memberships, knowledge folders, and document folder placement are stored in the adapter's SQLite database. Conversation navigation and active file selection remain browser-local MVP features. Chats are namespaced by the authenticated user and workspace. Active file IDs are stored once per workspace and reused across all conversations in it.
Passwords are stored only as salted scrypt hashes. Session tokens are random, stored server-side as hashes, and exchanged through HttpOnly, SameSite=Strict cookies. Password changes invalidate the user's other sessions. Only administrators can create users; every new user receives a private workspace.
Knowledge-base IDs are random permanent workspace identifiers and remain hidden from the UI. The owner can copy a revocable invite code to the clipboard and send it directly to another authenticated user. Generating a later invite invalidates the previous code.
Adapter API
The browser-facing adapter exposes:
GET /api/health
GET /api/models
POST /api/auth/login
POST /api/auth/logout
GET /api/auth/me
POST /api/auth/change-password
POST /api/admin/users
GET /api/workspaces
POST /api/workspaces
PATCH /api/workspaces/{workspace_id}
DELETE /api/workspaces/{workspace_id}
POST /api/workspaces/join
POST /api/workspaces/{workspace_id}/join-code
GET /api/documents
POST /api/documents/upload
POST /api/documents/from-url
POST /api/documents/{document_id}/reindex
DELETE /api/documents/{document_id}
PATCH /api/documents/{document_id}/knowledge-folder
GET /api/knowledge-organization
POST /api/knowledge-folders
PATCH /api/knowledge-folders/{folder_id}
DELETE /api/knowledge-folders/{folder_id}
GET /api/folders
GET /api/folders/{folder_id}
POST /api/folders
PATCH /api/folders/{folder_id}
DELETE /api/folders/{folder_id}
DELETE /api/chats/{chat_id}
POST /api/generate
The adapter derives X-User-Id from the authenticated server session. The browser sends only its selected X-Workspace-Id, and the adapter verifies membership before forwarding either identity upstream. Documents and folders are visible within a workspace; chat memory is isolated by workspace, user, and chat_id. Chats placed inside a folder also send folder_id, enabling shared folder memory. Conversation-memory folders remain separate from the adapter-managed knowledge folders that organize context files.
Workspace members have read and write access, but destructive operations on shared documents, knowledge folders, memory folders, and workspaces are owner-only. Personal default workspaces cannot be deleted. Every member can delete their own private conversations because the upstream operation is isolated by authenticated user, workspace, and chat ID. Deleting a private chat does not erase shared folder memory.
Workspace owners can rename their workspaces. The upstream RAG contract does not expose folder updates, so memory-folder renames are stored as workspace-shared aliases in the adapter while retaining the original folder_id; renaming therefore does not reset or delete shared memory.
The Improve prompt switch controls use_prompt_improver. It defaults to off for faster responses; turn it on when an extra LLM rewrite may help with an unclear prompt. A selected response layout compiles into a validated JSON Schema; the default Normal response omits a custom schema. The adapter also supports the upstream chat_id, folder_id, use_rag, top_k, max_output_tokens, and llm_model fields. Available model names come from upstream /models; RAGOON sends the selected name exactly and displays the model reported on each response. When the upstream API returns timings, the UI displays retrieval, generation, and total durations.
The Response depth selector provides three fixed latency/capacity presets:
| Level | top_k with RAG |
max_output_tokens |
|---|---|---|
| Fast | 4 | 1024 |
| Balanced | 8 | 2048 |
| Deep | 12 | 4096 |
These fixed settings control retrieval breadth and the maximum answer length, not a separate model reasoning mode. They apply equally to normal and structured responses; the UI does not infer a preset from the wording of the question. The selected visual layout guides the answer's headings, emphasis, and list structure.
Uploads must be real multipart files in the file field. The adapter accepts PDF, DOCX, TXT, Markdown, and HTML files and enforces a 50 MB limit. Public http/https URLs are forwarded to /documents/from-url; the upstream service remains responsible for redirect, address, timeout, and download-size safety checks. Generation requires a non-empty prompt. Documents are required only when use_rag is explicitly true; the UI sets it according to whether documents are selected.
Tests and checks
make test
make typecheck
make lint
make format
make check
make build
Backend tests mock the upstream RAG API. Frontend tests mock the adapter, so neither suite requires Ollama, Qdrant, or a live RAG service.
Production mode locally
make production
This builds frontend/dist and serves the complete application from http://127.0.0.1:8001. The Document RAG API must still be reachable at RAG_API_BASE_URL.
Troubleshooting
- Local port
8000already in use: find and stop the process using it, or close an older SSH tunnel before opening a new one. - RAG API unavailable: reopen the SSH tunnel, then verify
curl http://127.0.0.1:8000/healthandRAG_API_BASE_URL. - No Ollama models available: check
curl http://127.0.0.1:8000/models. If/healthworks but/modelsfails or is empty, inspect Ollama and the RAG API configuration on the remote host. - Upload rejected: send a supported real file, not a file path string.
- Document failed: use Reindex; inspect the upstream service if the failure repeats.
- No documents selectable: only documents with
indexedstatus can be selected. - Generation rejected: ensure the prompt is non-empty and the selected format is a valid JSON object. Documents are required only for RAG requests.
- Long generation timeout: increase
RAG_READ_TIMEOUT_SECONDSif the upstream model needs more than five minutes. - Upstream Qdrant/Ollama errors: diagnose those services on the RAG API host; this UI does not connect to them.
Current limitations
There is not yet TLS termination, MFA, password recovery, email delivery, centralized secret management, backend template/chat-list persistence, streaming generation, or cross-device chat synchronization. Set AUTH_COOKIE_SECURE=true and terminate TLS before exposing the service beyond a trusted local environment.