Skip to content

Repository files navigation

🔄 OmniRAG

Developed by Kristopher Clark · Solutions Architect at ZEDEDA

A high-performance, local-first AI Retrieval-Augmented Generation (RAG) tool built entirely in Rust with Redis for state management. OmniRAG synchronizes a local directory of files with an Open WebUI knowledge base — hashing files via SHA-256, tracking state atomically in Redis, dynamically prepending configurable context metadata, and interfacing with the Open WebUI REST API. Deployed as a 1:1 Pod architecture (one Rust container + one Redis container per Knowledge Base), OmniRAG is designed for edge computing environments where data sovereignty, offline capability, and low-latency AI inference are critical.


⚡ Quick Start

git clone https://github.com/krisclarkdev/omnirag.git &&cd omnirag
# ⚠️ Edit docker-compose.yml before starting:# 1. Change ./alpha-docs to the path to your documents folder# 2. Change ./redis-alpha to where you want Redis data persisted (or leave as-is)
docker compose pull
docker compose up -d
# Open http://localhost:3000 → Configure → Trigger Sync

📑 Table of Contents


✨ Features

  • Three-phase sync — Reconciles state, ingests new/updated files, and cleans up orphans
  • Pre-sync reconciliation — Queries Open WebUI before syncing to heal state and prevent duplicates; skips ghost files
  • SHA-256 change detection — Only re-uploads files whose contents actually changed
  • Context-dirty flag — Context changes via Web UI or CLI trigger re-upload on next sync without file modification
  • Configurable context header — Set a custom label per deployment (e.g., "Solutions Architect Context", "Project Lore")
  • Dynamic KB picker — Fetches available Knowledge Bases from Open WebUI and presents a dropdown selector
  • Convert to Markdown — Optionally wraps text files in language-specific code fences and uploads as .md for better LLM chunking
  • Configurable concurrency — Tune max simultaneous uploads (default 5, 0 = unlimited)
  • Context Manager dialog — Searchable, paginated modal for managing per-file context strings
  • Redis Functions (Lua) — Atomic server-side operations for state management
  • Redis AOF persistence — Native append-only file for durable state across container restarts
  • File filtering — Extension whitelist, OS file ignore list, and .ragignore support
  • API retry with backoff — Exponential backoff (3 attempts) on all Open WebUI API calls
  • Binary-safe context injection — Prepends metadata to text files only; binary files (PDF) are uploaded raw to prevent corruption
  • JSON REST API — Automation-ready endpoints for cron, n8n, webhooks, and external triggers
  • Swagger / OpenAPI — Interactive API docs at /docs with auto-generated OpenAPI 3.0 spec
  • Embedded Web UI — HTMX + Tailwind glassmorphism dark-mode dashboard with contextual help icons
  • CLI toolsset-context, get-context, sync, serve
  • 1:1 Pod architecture — Each Knowledge Base gets its own isolated Rust + Redis container pair
  • CI/CD ready — GitHub Actions workflow for automated Docker builds and GHCR publishing

🚀 Quick Start

Deploy with Docker Compose

# 1. Clone
git clone https://github.com/krisclarkdev/omnirag.git &&cd omnirag
# 2. ⚠️ Edit docker-compose.yml:# - Change ./alpha-docs to the path to your documents folder# - Change ./redis-alpha to where you want Redis data persisted (or leave as-is)# 3. Pull and deploy
docker compose pull
docker compose up -d
# 4. Configure via http://localhost:3000# 5. Click "▶ Trigger Sync" in the UI

Pull from GitHub Container Registry (GHCR)

Once the GitHub Actions workflow runs on your main branch, the image is published to GHCR:

services:
redis:
image: redis:7-alpinecommand: redis-server --appendonly yesvolumes:
- ./redis-data:/datarestart: unless-stoppedomnirag:
image: ghcr.io/krisclarkdev/omnirag:mainports:
- "3000:3000"volumes:
- ./my-documents:/ragenvironment:
- REDIS_URL=redis://redis:6379/0depends_on:
- redisrestart: unless-stopped

🖥️ Production Deployment

Once the GitHub Actions workflow completes on main, the Docker image is published to GHCR. Deploy to your server with:

# 1. SSH into your production server
ssh user@your-server
# 2. Create working directory
mkdir -p ~/omnirag &&cd~/omnirag
# 3. Create a docker-compose.yml that pulls from GHCR
cat > docker-compose.yml << 'EOF'services: redis: image: redis:7-alpine command: redis-server --appendonly yes volumes: - ./redis-data:/data restart: unless-stopped omnirag: image: ghcr.io/krisclarkdev/omnirag:main ports: - "3000:3000" volumes: - /path/to/your/documents:/rag:ro environment: - REDIS_URL=redis://redis:6379/0 depends_on: - redis restart: unless-stoppedEOF# 4. ⚠️ Edit docker-compose.yml — replace /path/to/your/documents# with the absolute path to your local documents folder, e.g.:# - /home/kris/knowledge-docs:/rag:ro# 5. Pull and start
docker compose pull
docker compose up -d
# 6. Verify
docker compose ps
docker compose logs -f omnirag
# 7. Open http://your-server:3000 → Configure → Trigger Sync

Updating to Latest Version

cd~/omnirag
docker compose pull
docker compose up -d

Optional: Reverse Proxy (Nginx)

server{listen443ssl;server_name omnirag.yourdomain.com;location / {proxy_passhttp://127.0.0.1:3000;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;}}

🏗️ Architecture: The 1:1 Pod

Kristopher Clark designed OmniRAG around a strict 1:1 Pod architecture, leveraging Rust for memory-safe, zero-cost-abstraction performance and Redis with AOF persistence for durable, atomic state management. The system stores its global configuration (config:global) and all per-file sync state in Redis. Because of this, each directory/Knowledge Base pair MUST have its own dedicated Redis container. Sharing a Redis container across multiple OmniRAG instances will result in config collisions and corrupted vector states.

The system enforces this strict 1:1 Pod model:

┌─── Pod (docker-compose) ─────────────────────────────────┐
│ │
│ ┌────────────────┐ ┌────────────────────────────┐ │
│ │ redis:7-alpine │ ◄──► │ omnirag (Rust) │ │
│ │ :6379 (AOF) │ │ │ │
│ └────────────────┘ │ ┌────────┐ ┌──────────┐ │ │
│ │ │ │ Axum │ │ Sync │ │ │
│ ┌──────▼──────┐ │ │ Web UI │ │ Engine │ │ │
│ │ ./redis-*/ │ │ │ + REST │ │ │ │ │
│ │ appendonly │ │ └────────┘ └──────────┘ │ │
│ │ .aof │ ▲ │ │ │
│ └─────────────┘ │ ▼ │ │
│ /rag ◄───────────────┘ Open WebUI API │ │
└──────────────────────────────────────────────────────────┘

Multi-Knowledge Base Deployment

To sync multiple directories to separate Knowledge Bases, run multiple isolated Pods in a single docker-compose.yml:

services:
# ── Pod 1: first project ─────────────────────────────redis-alpha:
image: redis:7-alpinecommand: redis-server --appendonly yesvolumes:
- ./redis-alpha:/dataomnirag-alpha:
build: .ports:
- "3000:3000"volumes:
- ./alpha-docs:/ragenvironment:
- REDIS_URL=redis://redis-alpha:6379/0depends_on:
- redis-alpha# ── Pod 2: second project ────────────────────────────redis-beta:
image: redis:7-alpinecommand: redis-server --appendonly yesvolumes:
- ./redis-beta:/dataomnirag-beta:
build: .ports:
- "3001:3000"volumes:
- ./beta-docs:/ragenvironment:
- REDIS_URL=redis://redis-beta:6379/0depends_on:
- redis-beta

Each Pod gets its own Redis data directory, port, and document volume. They are completely isolated — no shared state.

Data Flow

  1. Reconcile — Query Open WebUI KB file list, heal Redis state to prevent duplicates (skips ghost files not on disk)
  2. Walk/rag directory recursively (filtered by extension whitelist + .ragignore)
  3. Hash each file's contents (SHA-256)
  4. Compare against stored hash in Redis
  5. Upload new/changed files via Open WebUI API with retry (context prepended for text files only; binary files uploaded raw)
  6. Clean up orphaned files (deleted from disk → deleted from Open WebUI)

Redis Data Model

File State — Key: <sha256(absolute_path)>_<filename>

FieldDescription
absolute_pathFull filesystem path
content_hashSHA-256 of file contents
openwebui_file_idUUID from Open WebUI
context_textUser-defined context string
context_dirty"true" if context was changed and needs re-upload

Config — Key: config:global

FieldDefault
target_directory/rag
openwebui_url(set via UI)
openwebui_token(set via UI)
openwebui_knowledge_id(set via UI)
redis_urlredis://127.0.0.1:6379/0
context_header_labelFile Context

Redis Persistence

Redis runs with AOF (Append-Only File) enabled (--appendonly yes). The AOF log is written to /data/appendonly.aof inside the Redis container, which is bind-mounted to ./redis-<name> on the host. This ensures all state survives container restarts natively — no external backup layer needed.

Redis Functions (Lua)

Five server-side functions loaded via FUNCTION LOAD REPLACE at startup:

FunctionPurpose
get_formatted_contextReturns context as Markdown blockquote
check_file_existsKey existence check
verify_file_hashContent hash comparison
upsert_sync_stateAtomic field update (preserves context_text)
get_cleanup_batchSCAN-based batch retrieval for orphan cleanup

Three-Phase Sync

Phase 0 — Reconciliation:

Queries the Open WebUI API for all files in the target knowledge base. Matches each remote file against local Redis state by filename. If a file exists remotely but the UUID isn't tracked locally (e.g., crash between upload and state save), it heals the Redis entry to prevent duplicate uploads.

Ghost file detection: If a file exists in Open WebUI but the corresponding local file has been deleted from disk while the container was offline, the reconciliation phase skips healing ([GHOST]). Phase 2 will naturally detect these as orphans and clean them up from Open WebUI, avoiding unnecessary state churn.

Phase 1 — Ingestion (5 concurrent uploads via semaphore):

ConditionAction
File not in Redis[NEW] Upload → poll status → attach to KB → save state
File in Redis, hash matches, context clean[SKIP] No action
File in Redis, hash matches, context dirty[UPDATE] Re-upload with new context (set via Web UI or CLI)
File in Redis, hash differs[UPDATE] Delete old → upload new → save state

Phase 2 — Orphan Cleanup:

ConditionAction
Redis key but file missing from disk[ORPHAN:missing] Delete from Open WebUI → remove Redis key
Redis key but file now matches .ragignore / OS ignore / disallowed extension[ORPHAN:filtered] Delete from Open WebUI → remove Redis key

File Filtering

Files are filtered at three levels before processing:

FilterBehavior
Hidden/OS files.DS_Store, Thumbs.db, desktop.ini, .gitkeep always skipped
Extension whitelistOnly processes: .md, .txt, .pdf, .csv, .json, .yaml, .yml, .toml, .xml, .html, .htm, .rst, .log, .cfg, .ini, .conf, .py, .rs, .go, .js, .ts, .sh, .bat, .ps1
.ragignorePlace a .ragignore file in the root of /rag with one pattern per line (supports * wildcards, directory names, and exact paths). Lines starting with # are comments.

Example .ragignore:

# Skip the drafts folder
drafts
# Skip all log files in archives
archives/*.log
# Skip a specific file
notes/scratch.txt

Context Injection (Binary-Safe)

Context strings set via set-context are prepended to files as a Markdown header during upload. This happens in-memory only — local files are never modified.

File TypeBehavior
Text (.md, .txt, .csv, .json, .yaml, .py, .rs, etc.)Context prepended as Markdown blockquote
Binary (.pdf, and any non-text extension)Uploaded raw — no context injection to prevent file corruption

API Resiliency

All Open WebUI API calls use exponential backoff retry (3 attempts: 500ms → 1s → 2s):

  • 5xx / network errors → retry
  • 429 (rate limit) → retry
  • 4xx client errors → fail immediately (no retry)
  • Failed file → logged, skipped, continues sync (retried on next trigger)

Open WebUI API Integration

OperationEndpointWhen
List KB filesGET /api/v1/knowledge/{kb}Phase 0 reconciliation
UploadPOST /api/v1/files/New or updated file
Poll statusGET /api/v1/files/{id}/process/statusAfter upload
Attach to KBPOST /api/v1/knowledge/{kb}/file/addAfter processing complete
DeleteDELETE /api/v1/files/{id}Update (old version) or orphan

🧩 Best Practices: Chunking

The context string prepended by OmniRAG becomes part of the document text sent to Open WebUI for vector embedding. To ensure the context stays attached to the first logical section during chunking:

  • Chunk size: Set to ≥1500 tokens in your Open WebUI settings. This ensures the context blockquote and the first section of the document land in the same vector chunk.
  • Chunk overlap: Set to ≥150 tokens. This creates redundancy at chunk boundaries, so context fragments aren't lost if a split happens nearby.
  • No horizontal rule: The context format deliberately omits --- (Markdown horizontal rule) because modern text splitters (LangChain, LlamaIndex) treat --- as a hard chunk boundary, which would orphan the context from the document text.

Tip: If you're using Open WebUI's default settings, 1500 chunk size with 150 overlap is a reliable starting point for context-injected documents.


🤖 REST API (Automation)

OmniRAG exposes a JSON REST API under /api/v1/ designed for cron jobs, n8n workflows, webhooks, and any external automation. No authentication is required — secure access via network policy or reverse proxy.

Endpoints

EndpointMethodDescription
/api/v1/healthGETLiveness probe — returns service name and version
/api/v1/syncPOSTTrigger a sync — returns 202 Accepted or 409 Conflict
/api/v1/sync/statusGETPoll current sync status as JSON
/api/v1/openapi.jsonGETOpenAPI 3.0 specification (JSON)

GET /api/v1/health

curl http://localhost:3000/api/v1/health
{
"status": "ok",
"service": "omnirag",
"version": "0.1.0"
}

POST /api/v1/sync

curl -X POST http://localhost:3000/api/v1/sync

202 Accepted — sync started:

{
"status": "triggered",
"message": "Sync started"
}

409 Conflict — sync already in progress:

{
"status": "already_running",
"message": "A sync operation is already in progress"
}

GET /api/v1/sync/status

curl http://localhost:3000/api/v1/sync/status
{
"status": "completed",
"detail": "Completed successfully"
}

Status values: idle, running, completed, error, unknown.

Automation Examples

Cron (every 15 minutes):

*/15****curl -s -X POST http://localhost:3000/api/v1/sync > /dev/null

n8n HTTP Request Node:

  • Method: POST
  • URL: http://omnirag:3000/api/v1/sync
  • Authentication: None
  • Response Format: JSON

Docker Healthcheck:

services:
omnirag:
image: ghcr.io/<owner>/omnirag:mainhealthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/api/v1/health"]interval: 30stimeout: 5sretries: 3

Bash Trigger + Wait:

#!/bin/bash# Trigger sync and poll until complete
curl -s -X POST http://localhost:3000/api/v1/sync
whiletrue;do
STATUS=$(curl -s http://localhost:3000/api/v1/sync/status | jq -r .status)echo"Status: $STATUS"
[ "$STATUS"="completed" ] || [ "$STATUS"="error" ] &&break
sleep 5
done

💻 CLI

# Start the web server
omnirag serve
# Run sync manually (all 3 phases)
omnirag sync
# Set context for a file (prepended on upload)
omnirag set-context /rag/doc.md "Architecture reference for EVE-OS edge deployments."# Get formatted context
omnirag get-context /rag/doc.md
# > **Solutions Architect Context:**# > Architecture reference for EVE-OS edge deployments.# ---

CLI Flags

FlagEnv VarDefaultDescription
--redis-urlREDIS_URLredis://127.0.0.1:6379/0Redis connection

🌐 Web UI

Glassmorphism dark-mode dashboard served at http://localhost:3000:

  • Configuration panel — Set Open WebUI URL, API token, and Knowledge Base ID
  • Sync control — Trigger sync and monitor status in real-time (polls every 3s)
  • HTMX-powered — Dynamic updates without page reloads

HTMX Endpoints (Web UI)

EndpointMethodPurpose
/GETFull page
/api/configGETConfig form partial
/api/configPOSTSave config
/api/syncPOSTTrigger sync (returns HTML)
/api/sync/statusGETPoll status (returns HTML)
/api/contextsGETContext Manager file list
/api/contextsPOSTUpdate file context_text
/docsGETSwagger UI (interactive API docs)
/api/v1/openapi.jsonGETOpenAPI 3.0 specification

🐳 Docker

Dockerfile

Multi-stage build:

  1. Builder (rust:1.85-bookworm) — Compiles release binary
  2. Runtime (debian:bookworm-slim) — Installs redis-server, gosu, ca-certificates

Boot Sequence

entrypoint.sh
├── chown -R redis:redis /data
├── gosu redis redis-server --appendonly yes --dir /data --daemonize yes
├── Wait for Redis PONG (readiness check)
└── exec omnirag serve
├── Connect to Redis
├── Load Lua functions
└── Start Axum on :3000

Volume permissions: The entrypoint runs initially as root to chown the /data bind-mount, then uses gosu to drop privileges and start Redis as the redis user. This prevents "permission denied" errors when host directories have strict permissions.

docker-compose.yml

services:
omnirag:
image: ghcr.io/krisclarkdev/omnirag:mainextra_hosts:
- "host.docker.internal:host-gateway"ports:
- "3000:3000"volumes:
- ./my-documents:/rag:ro # Your files (change path as needed)environment:
- REDIS_URL=redis://redis:6379/0
- RUST_LOG=info,omnirag=debugrestart: unless-stopped

Networking: Connecting to Open WebUI

OmniRAG runs inside a Docker container and needs to reach your Open WebUI API. This requires special configuration when both services run on the same host.

Same-Host Deployment (Open WebUI on the same machine)

From inside a Docker container, localhost refers to the container itself — not the host machine. To reach services on the Docker host:

  1. Add extra_hosts to your docker-compose.yml (required on Linux):
omnirag-alpha:
image: ghcr.io/krisclarkdev/omnirag:mainextra_hosts:
- "host.docker.internal:host-gateway"
  1. Set the Open WebUI URL in the OmniRAG config to:
http://host.docker.internal:<PORT>

where <PORT> is the port Open WebUI listens on (e.g., 3000, 8080).

Tip: To find which port Open WebUI uses, run curl -s http://localhost:<PORT>/api/v1/knowledge/ from the host — the port that returns JSON is the correct one.

Remote Open WebUI (different machine)

If Open WebUI runs on a different server, use its hostname or IP directly:

https://openwebui.yourdomain.com

No extra_hosts needed in this case.

Port Customization

If port 3000 is already in use on your host (e.g., by Open WebUI), change the left side of the port mapping:

ports:
- "3001:3000"# Access OmniRAG at http://your-server:3001

Multi-Container Deployment (One Container per Collection)

OmniRAG uses a single global config per container — each instance syncs one local directory to one Open WebUI collection (Knowledge Base). This is by design: to sync multiple directories to different collections, run one Pod per collection:

services:
# ── Pod 1 ────────────────────────────────────────────redis-alpha:
image: redis:7-alpinecommand: redis-server --appendonly yesvolumes:
- ./redis-alpha:/dataomnirag-alpha:
image: ghcr.io/krisclarkdev/omnirag:mainextra_hosts:
- "host.docker.internal:host-gateway"ports:
- "3000:3000"volumes:
- ./alpha-docs:/rag:roenvironment:
- REDIS_URL=redis://redis-alpha:6379/0
- RUST_LOG=info,omnirag=debugdepends_on:
- redis-alpharestart: unless-stopped# ── Pod 2 ────────────────────────────────────────────redis-beta:
image: redis:7-alpinecommand: redis-server --appendonly yesvolumes:
- ./redis-beta:/dataomnirag-beta:
image: ghcr.io/krisclarkdev/omnirag:mainextra_hosts:
- "host.docker.internal:host-gateway"ports:
- "3001:3000"volumes:
- ./beta-docs:/rag:roenvironment:
- REDIS_URL=redis://redis-beta:6379/0
- RUST_LOG=info,omnirag=debugdepends_on:
- redis-betarestart: unless-stopped

Each Pod gets its own Redis data volume, independent configuration, and a separate Web UI port. Configure each via its own UI (localhost:3000, localhost:3001, etc.) with the target collection's Knowledge Base ID. Pods are fully isolated — they share nothing and can be started, stopped, or scaled independently.

Logging Configuration

OmniRAG uses the RUST_LOG environment variable for log verbosity:

LevelWhat you see
RUST_LOG=infoSync phases, file actions, errors
RUST_LOG=info,omnirag=debugAll of the above + API calls, filter decisions
RUST_LOG=warnOnly warnings and errors
# View container logs
docker logs -f omnirag
# Override at runtime
docker run -e RUST_LOG=debug ...

📐 Hardware Requirements & Scaling

The following T-shirt sizing guide provides realistic estimates based on OmniRAG's resource profile:

  • Redis RAM: ~300 bytes per tracked file (path + SHA-256 hash + UUID + context string)
  • App RAM: Up to 5 concurrent file buffers in memory (text files only; binary files passed through)
  • CPU: SHA-256 hash computation for every file during sync
  • Storage: Redis AOF file grows proportionally to total state size
TierFilesContainer RAMCPUAOF Storage
XS (Tiny)< 1,000128 MB0.5 vCPU< 5 MB
S (Small)1K – 5K256 MB1 vCPU5 – 25 MB
M (Medium)5K – 20K512 MB1 vCPU25 – 100 MB
L (Large)20K – 100K1 GB2 vCPU100 – 500 MB
XL (Enterprise)100K+2 GB+4 vCPU500 MB+

XL Tier Bottleneck Analysis

At the Enterprise tier (100K+ files), the primary bottleneck is Phase 1 directory walk + SHA-256 hashing, not memory. Redis comfortably holds 100K entries in ~30 MB of RAM. However:

  • SHA-256 hashing of 100K+ files on each sync cycle becomes CPU-bound. Each hash requires a full file read, so I/O throughput of the /rag volume also matters.
  • Open WebUI API rate limits may throttle uploads during initial ingestion. The 5-concurrent-upload semaphore prevents overwhelming the API, but the first-ever sync of 100K files will take hours.
  • Redis AOF rewrite can momentarily spike memory to 2× during background BGREWRITEAOF. The 2 GB recommendation accounts for this.

Recommendation for XL: Run on dedicated infrastructure with SSD-backed /rag volume. Consider increasing the semaphore limit (currently 5) for faster initial ingestion if your Open WebUI instance can handle it.


🧪 Testing

Test Suite

OmniRAG includes a comprehensive test suite covering all core components:

# Run all tests
cargo test# Run with output
cargo test -- --nocapture
Test ModuleTestsCoverageLocation
API Client10Upload, delete, KB operations, exponential backoff retry (5xx/429/4xx), poll statussrc/api.rs (inline)
Web REST API9Health endpoint, sync trigger (202/409), status phases (idle/running/completed/error), method validationtests/web_api_tests.rs
Sync Engine15Extension whitelist, OS file filtering, .ragignore parsing, binary-safe context injection, full pipelinetests/sync_tests.rs
Hashing & Config11SHA-256 identity, deterministic keys, empty file hash, config serialization roundtriptests/hashing_config_tests.rs

API Retry Test Matrix

ScenarioExpectedVerified
5xx → 5xx → 200Retry twice, succeed
429 → 429 → 200Retry twice, succeed
400 (client error)Fail immediately, no retry
500 → 500 → 500Fail after 3 attempts

REST API Test Matrix

ScenarioExpectedVerified
GET /api/v1/health200 + service info
POST /api/v1/sync (idle)202 Accepted
POST /api/v1/sync (running)409 Conflict
GET /api/v1/sync/status (all phases)Correct phase string
GET /api/v1/sync (wrong method)405 Method Not Allowed

🔄 CI/CD

GitHub Actions workflow at .github/workflows/docker-publish.yml:

TriggerAction
Push to mainBuild + push to GHCR
Pull RequestBuild only (verify compilation)
Release tag (v*)Build + push with semver tags

The workflow uses Docker Buildx with GitHub Actions cache for fast rebuilds.


📁 Source Files

FilePurpose
src/sync.rsThree-phase sync, file filtering, .ragignore, binary-safe context
src/api.rsOpen WebUI API client with retry + inline tests
src/web.rsAxum routes (HTMX + JSON REST API), HTML rendering
src/main.rsCLI parsing, Redis bootstrap
src/redis_client.rsLua function loading + FCALL wrappers
src/lua/rag_helpers.lua5 Redis Functions
src/config.rsAppConfig struct + Redis load/save
src/hashing.rsSHA-256 key/content hashing

Dependencies

tokio · axum · clap · redis · reqwest · walkdir · sha2 · serde · serde_json · hex · dotenvy · tower-http · tracing · tracing-subscriber

Dev:wiremock · tempfile · tower · http-body-util · serde_urlencoded


🧪 End-to-End Test Results

Test Environment

ComponentValue
DeploymentDocker Compose 1:1 Pod (omnirag-alpha + redis-alpha)
Test Directoryalpha-docs/ mounted at /rag
Open WebUILocal Open WebUI instance
Target KB"Test" (auto-discovered via Fetch KBs)

Test Files

FileTypeExpected Behavior
architecture.mdMarkdownUpload as-is
data_processor.pyPythonConvert → data_processor.md (code fence)
test_config.jsonJSONConvert → test_config.md (code fence)
release_notes.txtPlain textUpload as-is (.txt not converted)
secret_notes.txtPlain textExcluded by .ragignore
.ragignoreConfigPatterns: drafts, *.tmp, secret_notes.txt

Results

Test CaseStatusNotes
KB Dropdown Picker✅ PASSFetched 3 KBs from API, "Test" selected via dropdown
Help Icon Modals✅ PASSAll 6 fields have working ? icons with dialog content
Config Save/Load✅ PASSAll fields persisted to Redis and restored on reload
Convert to Markdown✅ PASS.py.md with Python fence, .json.md with JSON fence
Markdown Passthrough✅ PASS.md and .txt files uploaded without conversion
Binary Passthrough✅ PASSPDFs uploaded without context injection
.ragignore Filtering✅ PASSsecret_notes.txt excluded, 3 patterns loaded
Phase 1 Ingestion✅ PASS4 files uploaded as [NEW]
Phase 2 Cleanup✅ PASSNo orphans found
Open WebUI Verification✅ PASS4 files visible in "Test" KB with correct names/sizes
Swagger Docs Link✅ PASSHeader link navigates to /docs
Footer Credits✅ PASSGitHub link + "Built by Kristopher Clark"
Max Concurrent Uploads✅ PASSConfigurable via UI, default 5

Docker Logs (Abbreviated)

omnirag-alpha-1 | Loaded 3 patterns from .ragignore
omnirag-alpha-1 | Found 4 files to process (skipped: 0 unsupported ext, 1 ragignored)
omnirag-alpha-1 | [NEW] data_processor.py
omnirag-alpha-1 | [NEW] release_notes.txt
omnirag-alpha-1 | [NEW] test_config.json
omnirag-alpha-1 | [NEW] architecture.md
omnirag-alpha-1 | Uploaded 'data_processor.md' → file_id=...
omnirag-alpha-1 | Sync complete.

👤 About the Author

Kristopher Clark is a Solutions Architect at ZEDEDA, specializing in edge computing, EVE-OS, Kubernetes, and AI at the edge. He built OmniRAG with Rust and Redis to solve a real-world need: enabling private, high-performance retrieval-augmented generation entirely on local infrastructure — no cloud API dependencies, no data leaving the premises.

PlatformLink
🌐 Websitekristopherclark.com
🐙 GitHubkrisclarkdev
🌍 WikidataQ138685504

📄 License

Apache License 2.0 — see LICENSE for details.

About

Rust-based RAG sync engine for Open WebUI. Hashes, tracks, and synchronizes local files to AI knowledge bases with Redis state management and 1:1 Pod architecture.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages