Install
$ agentstack add mcp-okforge-okforge-webui ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
okforge-webui
A LAN web UI and job runner for okforge knowledge bases: drop a scanned book in an inbox and drive it through VLM OCR, optional translation, and ingestion into an LLM-synthesized wiki — then browse, query, and publish the result. Built for local-first setups where the LLM is your own llama.cpp/vLLM box, not a cloud API.
The pipeline is five screens: probe (inspect the PDF: text layer? language? page count) → pilot (OCR a page or three, check the transcription and image crops before committing) → project (pick or name the project that collects the output) → run (chunked OCR → translate → markdown with live progress) → verify & use (review the markdown, ingest it into the project's knowledge base, then query and publish). OCR and ingestion are always separate steps, so the same tool doubles as a pure PDF→markdown converter — skip the ingest and take the files from md-out/.
Inputs: PDFs, page-scan images (jpg/png/tif/bmp — wrapped into PDF on upload so the OCR pipeline handles them), and your own markdown/text documents (added straight to a project, no OCR). Selecting several PDFs/images at once combines them into one PDF in natural file-name order — the upload shows the exact order and combined name before anything is sent. Other formats (docx, pptx, html …) should be pre-converted to markdown first.
What's in the box
- Serial job queue (sqlite + one worker, on purpose): one
addor
OCR run at a time protects single-slot LLM hosts and the engine's per-KB ingest lock. Jobs survive backend restarts; every finished job keeps its log. One-click resume/retry, a stall watchdog (flags, never kills), per-chunk ETA from real history, and a git pre-ingest snapshot of the KB before every add.
- Markdown first, ingest second: every run OCRs into the project's
md-out// folder (chunked .md + page maps + image crops); hand-made markdown/text files can be added to the same folder from the UI ("Add markdown…" — no OCR involved); ingesting that markdown into the knowledge base is a separate step — a one-click button in the verify stage (KB stats update chunk by chunk) or an auto-ingest toggle on the run. The KB is created on first ingest — or never, if all you wanted was the markdown.
- Archive-first deletes: removing an uploaded PDF, a project's
markdown, a published site, or a whole project moves it to trash/ (KBs retire to kbs-retired/) — nothing in the UI is destructive, restore is a mv back.
- OCR + image extraction via
okforge-vision-ocr (one VLM call per page: markdown transcription + photo bounding boxes together), with a table mode for pages the fast path mangles and a per-page re-OCR + re-ingest repair loop.
- Translation workflow for non-English scans: faithful transcription
first, page-by-page translation second — both language versions share one image directory and page citations survive.
- Wiki browser with lexical search (source hits carry real page
numbers), image lightbox, and markdown rendering.
- MCP server at
/mcp(streamable HTTP):list_projects,
project_status, ask, search, read_wiki_page. Connect any MCP client, e.g. claude mcp add --transport http okforge http:///mcp. Clients that don't surface MCP server instructions (Open-WebUI and other OpenAPI-bridged clients) should get the recommended system prompt from [docs/MCP_CLIENT_PROMPT.md](docs/MCPCLIENTPROMPT.md).
- Static-site publishing per KB via Quartz
— full-text search, graph view, backlinks — one button, then a printed rsync command to go public.
Prerequisites
- An OpenAI-compatible LLM endpoint — the whole pipeline's brain
(llama.cpp or vLLM on your own hardware, or a hosted service; see Configuration). For the OCR path the endpoint's model must be vision-capable (Qwen-VL family or similar) — it reads page images. Text-layer extraction, ingestion, and querying work with any capable chat model.
- Python 3.10+
- Git — for the clone; on Windows it also provides the
grep
binary the engine's query agent uses.
- Node.js 18+ — only for the optional static-site publishing
(Quartz); everything else runs without it. Quartz is a one-time, once-per-machine install into the shared quartz dir (/quartz, or OKFORGE_WEBUI_QUARTZ_DIR) — clone it, check out v5, npm ci, then npx quartz plugin install; the exact steps are in [OPERATIONS](docs/OPERATIONS.md#publishing-a-kb-as-a-website-quartz). Skipping the plugin install step is the usual first-publish failure: the build aborts with Could not resolve "../../.quartz/plugins", which is exactly the dir that step generates. On a LAN-only / offline box, also disable the default og-image emitter in quartz.config.ts (it fetches a font over the network at build time and otherwise fails); nothing else in Quartz needs outbound access.
Directory layout
/ e.g. /opt/okforge/ or C:\okforge\
okforge-webui/ ← this repo; .venv/ inside it
kbs// ← one self-contained knowledge base per subject
inbox/ ← PDF drop point for the web UI
md-out// ← OCR'd markdown per project (created on demand)
kbs-retired/ ← retired KBs (archive-first "delete")
trash/ ← web-UI deletes move things here, never erase
quartz/ ← shared Quartz install (site publishing, optional)
sites// ← published static sites (optional)
The base directory can be anywhere — all defaults are relative to where this repo sits (each is individually overridable by env var, see Configuration). Every KB is self-contained (sources, wiki, engine state, .env, its own git history) — copy the directory and you've copied the KB. The UI discovers KBs by scanning the KB root; nothing is registered anywhere else.
Install
Linux/macOS:
cd /opt/okforge # or any base dir
git clone https://github.com/okforge/okforge-webui
cd okforge-webui
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
mkdir -p ../kbs ../inbox
Windows (PowerShell):
cd C:\okforge # or any base dir
git clone https://github.com/okforge/okforge-webui
cd okforge-webui
python -m venv .venv
.venv\Scripts\pip install -r requirements.txt
md ..\kbs, ..\inbox
(PowerShell gotcha: anything in the current directory needs a .\ prefix to run — .\script.ps1, not script.ps1. The .venv\Scripts\… forms above already qualify.)
requirements.txt pins the two okforge packages from PyPI — the okforge engine (ingestion, wiki compilation, query; see its GETTINGSTARTED) and okforge-vision-ocr (pre-conversion console scripts) — plus the FastAPI backend's own dependencies.
Run it
One process serves the frontend, the API, and the MCP server. Run it from this repo's directory — python -m webui resolves the webui package relative to the current dir, so from anywhere else Python exits with No module named webui:
cd /okforge-webui
.venv/bin/python -m webui # Linux/macOS
.venv\Scripts\python -m webui # Windows
# browse http://:8500/
OKFORGE_WEBUI_HOST / OKFORGE_WEBUI_PORT change the bind (default 0.0.0.0:8500 — LAN-visible; use 127.0.0.1 to keep it local). Same trust model in every mode: LAN-only, no auth — don't expose it beyond a network you trust.
First time? Follow the [small-test walkthrough](#first-run--start-with-a-small-test) below before pointing it at a whole book.
To run it as a service: on Linux, [webui/deploy/okforge-webui-standalone.service](webui/deploy/okforge-webui-standalone.service) is a ready-to-edit systemd unit; on Windows, use Task Scheduler ("At startup", run \.venv\Scripts\python.exe -m webui) or NSSM.
Optional: Apache in front (Linux)
For port 80, a LAN vhost name, and an easy basic-auth option, deploy.sh installs Apache (static docroot + /api/ reverse proxy) in front of the same backend under systemd:
SERVER_NAME=okforge.local OKFORGE_WEBUI_ENDPOINTS="gpu1=http://gpu1:8080/v1" \
webui/deploy.sh
deploy.sh is idempotent — rerun it after changes (it restarts the backend, so never while a job is running). In this mode frontend files are served by Apache, so frontend-only changes are sudo rsync -a --delete webui/static/ /var/www/okforge-webui/ (standalone mode serves them straight from the repo — nothing to copy).
First run — start with a small test
Prove the whole loop — endpoint, OCR quality, ingest, query — on a handful of pages before committing to a book. Five pages take about ten minutes on a local GPU; a 300-page book is an overnight-plus run (see [ingest cost](docs/OPERATIONS.md#ingest-cost-at-collection-scale-measured)). Everything below happens in the browser at http://:8500/.
- Check the header. Pick your LLM server in the dropdown; the
status light beside it polls the server, so a steady light means you're actually talking to it. This choice gets baked into the knowledge base at first ingest (queries and MCP clients then use it too — [changeable later](#how-the-endpoint-choice-binds-to-a-kb)).
- Stage 1 — get a document in. Upload a short PDF — or a few
phone photos of pages, which combine into one PDF (the panel shows the page order before anything uploads; it comes from the file names). The probe runs automatically: scan means the OCR pipeline (the normal path), text means an embedded text layer you can optionally trust in stage 4.
- Stage 2 — pilot one page. Enter one page number with real
content on it (not the cover) and Run pilot. Read the transcription beside the rendered page; check the image crops. Bad OCR here means bad OCR everywhere, so fix it now — table mode for complex tables, --figures if line drawings were missed, or an OCR hint ("ignore marginalia"). Re-run until the page reads right.
- Stage 3 — create a project. Use a throwaway name like
MyBook-test — you'll delete it after the test (one click, and nothing is ever erased — it all moves to trash/).
- Stage 4 — run a small range. Set From page / to to a few
content pages, tick ingest into KB when OCR finishes, and Start run. The queue shows one plain-language row ("working — n/m chunks OCR'd"; ▸ expands the technical steps) and markdown appears in stage 5 as chunks finish.
- Stage 5 — verify and ask. Read the markdown. Watch the
knowledge-base stats tick up as chunks ingest; a one-line project description is written automatically at the end, and Publish unlocks when the last chunk is in. Then ask the knowledge base a question — answers cite source pages as (p. N).
- Happy? Delete the test and run for real. Delete project… in
stage 3, then repeat with the real project name and the full page range. (If you'd rather keep the test: make its range exactly the first chunk — e.g. pages 1–20 at the default 20 pages per chunk — and the full run will skip it instead of re-OCRing it.)
What a small test catches early: a wrong endpoint or non-vision model (pilot fails or returns junk), OCR quirks your document needs hints for, and a misconfigured model paying a hidden reasoning block on every call — a 20-page chunk should ingest in a couple of minutes on a local 27B model, not 27 (see the llm_extra_body note below).
Configuration
Everything is an environment variable (for the systemd deployments, set them in the unit — deploy.sh passes any that are exported when it runs). `` below means the directory this repo sits in.
> Note: these use the OKFORGE_WEBUI_* prefix. The pre-rebrand > OPENKB_WEBUI_* names (and OPENKB_DIR for the engine dir) still work > — the backend reads the new name first and falls back to the old one, > printing a one-time deprecation line on stderr naming what to rename.
| variable | default | meaning | |---|---|---| | OKFORGE_WEBUI_HOST | 0.0.0.0 | bind address (python -m webui) | | OKFORGE_WEBUI_PORT | 8500 | bind port (python -m webui) | | OKFORGE_WEBUI_ENDPOINTS | local=http://localhost:8080/v1 | LLM endpoints for the UI dropdown, comma-separated label=url[\|key[\|model]] — key and model only for hosted services (see below) | | OKFORGE_WEBUI_DEFAULT_ENDPOINT | first label | pre-selected endpoint | | OKFORGE_WEBUI_MODEL | openai/Qwen3.6-27B-MTP | model string new KBs are initialized with (per-endpoint model overrides it) | | OKFORGE_WEBUI_KB_ROOT | /kbs | where KBs live | | OKFORGE_WEBUI_INBOX | /inbox | PDF drop dir | | OKFORGE_WEBUI_MD_OUT | /md-out | per-project OCR'd markdown | | OKFORGE_WEBUI_RETIRED_DIR | /kbs-retired | where retired KBs move | | OKFORGE_WEBUI_TRASH | /trash | where web-UI deletes move things | | OKFORGE_WEBUI_QUARTZ_DIR | /quartz | shared Quartz install | | OKFORGE_WEBUI_SITES_DIR | /sites | published-site output | | OKFORGE_WEBUI_PUBLIC_SITE_HOST | localhost | public host for published sites' baseUrl | | OKFORGE_WEBUI_PUBLIC_SITE_DEST | user@host:/var/www/sites | rsync target shown by the go-public helper | | OKFORGE_WEBUI_NODE | node on PATH, else /usr/bin/node | node binary for Quartz builds | | OKFORGE_WEBUI_ENGINE_DIR | this repo | dir whose .venv holds the engine + okforge-vision-ocr console scripts — set this only if that .venv lives somewhere other than this repo (shared or parent-dir venv) |
The documented install puts .venv inside the repo, which is why OKFORGE_WEBUI_ENGINE_DIR needs no setting by default. If you instead share one .venv across checkouts or keep it in the base dir, point this var at the directory that contains it — otherwise the UI looks for openkb/okforge-vision-ocr under /.venv/bin and reports them missing.
Local llama.cpp/vLLM endpoints need only label=url. A hosted OpenAI-compatible service takes two more |-separated fields — its API key and the model in LiteLLM provider/model format:
OKFORGE_WEBUI_ENDPOINTS="gpu1=http://gpu1:8080/v1,openrouter=https://openrouter.ai/api/v1|sk-or-v1-...|openrouter/qwen/qwen3.6-27b"
KBs created on such an endpoint get the key in their .env, the model in their config.yaml, and a provider-appropriate thinking-off block (OpenRouter's reasoning.enabled=false instead of llama.cpp's chat_template_kwargs). OCR/translate jobs strip the LiteLLM provider prefix and pass the rest as the OpenAI-protocol model name. Note the key lives in plain text in the unit file/environment — acceptable on a single-operator LAN box; protect the systemd drop-in accordingly (chmod 640).
How the endpoint choice binds to a KB
The endpoint picked in the header is baked into each knowledge base at first ingest: that's when the KB's own .env (OPENAI_API_BASE, LLM_API_KEY) and config.yaml (model, thinking-off block) are written. From then on, everything that touches that KB — later ingests, the stage-5 Ask box, and the MCP server's ask tool — uses the KB's own endpoint, regardless of what the header currently shows. (The header selection still drives OCR/translate runs, which produce markdown before any KB exists.) So two KBs on one machine can happily run against two different LLM servers, and an MCP client querying a project lights up whichever server that project pins.
To repoint an existing KB (LLM moved to a new box, or a new model): edit those two files in the KB directory — .env for the URL and key, config.yaml for model: — and the next call uses them; no restart, nothing to re-register. Keep the llm_extra_body block a
…
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: okforge
- Source: okforge/okforge-webui
- License: MIT
- Homepage: https://okforge.github.io/dade-code-1935/
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.