Skip to content

OFFIS-RIT/kiwi

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

343 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

KIWI Logo

KIWI

Knowledge Graph Platform for Document Processing and AI-powered Q&A created by OFFIS e.V.

Bun Next.js License

FeaturesQuick StartProductionArchitectureLibrary UsageConfigurationDevelopmentDocumentation


Features

  • Document Processing – Upload and process PDFs, Office files, images, audio, video, HTML, email, calendars, contacts, CSV, JSON, XML, YAML, TOML, and Excel files
  • Adaptive PDF OCR Rendering – Automatically switches to high-resolution tiled rendering, with optional panel splitting for large technical drawings such as A1 and A0 sheets
  • Knowledge Graph Extraction – Uses AI to extract entities, relationships, and supporting evidence from uploaded documents
  • Graph Storage – Stores entities and relationships in a queryable knowledge graph backed by PostgreSQL and pgvector
  • Vector Search – Supports semantic retrieval over extracted document content
  • Graph Exploration Tools – Provides AI-assisted traversal, multi-hop path finding, and source-grounded exploration of graph data
  • Authentication & Authorization – Uses Better Auth for sessions, roles, LDAP, and email/password sign-in
  • User Management – Includes an admin UI for managing users, roles, and bans
  • Chat Interface – Lets users ask questions about their documents with streaming responses in both normal and agentic modes
  • Multi-Model Support – Works with OpenAI-compatible providers, OpenAI, Azure, Anthropic, and local inference backends where available

When using OpenAI reasoning models, temperature is fixed to 1.0, as required by the provider.

Tech Stack

Layer Technology
Frontend Next.js 16, React 19, TanStack Query, Tailwind CSS, Bun
Backend Bun, Elysia, Drizzle ORM
Auth Better Auth with admin roles, LDAP, and email/password
Database PostgreSQL + pgvector
Workflow OpenWorkflow with PostgreSQL-backed durable workflow storage
Storage RustFS (S3-compatible)
AI Vercel AI SDK with OpenAI, Azure, Anthropic, and compatible APIs

Quick Start

Prerequisites

Installation

# Clone the repository
git clone https://github.com/OFFIS-RIT/kiwi.git
cd kiwi

# Configure environment
cp .env.sample .env
# Edit .env with your AI credentials and local settings

# Start development infrastructure
docker compose up -d

# Start frontend, API, and worker
bun run dev

The application will be available at:

Database migrations are run manually in local development after the infrastructure is up.

First Time Setup

The rustfs-setup container automatically creates the S3 bucket on first start.

If you want to use a local OpenAI-compatible model backend such as Ollama, point the AI settings in .env to that endpoint.

For example, with Ollama:

docker exec -it ollama ollama pull <model-name>

Production

docker compose -f compose.prod.yml up -d  # Start production
docker compose -f compose.prod.yml down   # Stop production

compose.prod.yml also runs the migrations startup container automatically, which applies pending migrations before app services connect to the database.

SSL/TLS

Production uses Caddy as the edge proxy. The checked-in compose.prod.yml mounts ./caddy/Caddyfile, reads APP_DOMAIN, and does not require certificate files in ./certs.

Production Services

Service Description
caddy Edge proxy with HTTPS
frontend Next.js frontend
server Bun API server with /auth
worker Durable workflow worker
migrations Startup migration job
postgres PostgreSQL + pgvector
bouncer PostgreSQL connection pool
rustfs S3-compatible storage

Architecture

The frontend runs as a Next.js standalone server on Node 20. Browser-facing configuration such as API_URL and AUTH_URL is read from runtime environment variables, so the same built image can be deployed with different API/auth endpoints without rebuilding. Authentication mode is derived server-side from non-sensitive LDAP presence flags.

┌──────────────┐     ┌──────────────┐     ┌─────────────┐
│   Frontend   │────▶│    Caddy     │────▶│   Server    │
│  (Next.js)   │     │   (prod)     │     │    (Bun)    │
└──────────────┘     └──────────────┘     └─────────────┘
       │                                         │
       ▼                                         ▼
┌──────────────┐                          ┌─────────────┐
│    Auth      │                          │  PostgreSQL │
│  (/auth)     │                          │  + pgvector │
└──────────────┘                          └─────────────┘
                                                 ▲
                                                 │
                                         ┌──────────────┐
                                         │    Worker    │
                                         │  (workflow)  │
                                         └──────────────┘
                                           │        │
                                           ▼        ▼
                                     ┌──────────┐ ┌──────────────┐
                                     │  RustFS  │ │ Ollama/OpenAI│
                                     │ (S3)     │ │   (AI/LLM)   │
                                     └──────────┘ └──────────────┘

Processing Pipeline

  1. User uploads files → API stores the originals in RustFS
  2. API enqueues durable workflow runs in PostgreSQL within the request transaction
  3. Worker claims pending runs from workflow storage and processes files (PDF, Office files, images, audio, video, HTML, email, calendar/contact files, CSV, JSON, XML, YAML, TOML, Excel)
  4. Worker extracts entities/relations via AI and stores graph data in PostgreSQL with embeddings
  5. When all file workflows in a batch finish, description workflows are enqueued and the project returns to ready
  6. User queries via chat → vector search, graph traversal, or agentic tool exploration + AI response

Query Modes

Mode API Description
Normal mode=normal Vector similarity search with path finding between relevant entities
Agentic mode=agentic Agentic exploration using graph tools for autonomous knowledge discovery

Graph Exploration Tools (Agentic Mode)

Tool Capability
list_files List files in the current graph and return file IDs for follow-up tool calls
search_entities Find entities by name, alias, type, or short topical query
list_entities Scan entities broadly, optionally scoped to specific files
search_relationships Search relationships relevant to a query and return relationship IDs
get_relationships Retrieve relationships for known entity IDs
get_entity_neighbours Traverse directly connected entities from a selected entity
get_path_between_entities Find multi-hop paths between two entities
get_sources Retrieve source evidence and citation IDs for entities or relationships
ask_clarifying_questions Ask the user for missing information when the graph and prior context are insufficient

Library Usage

KIWI is organized as a Bun workspace monorepo. The main applications and shared packages are:

Package Purpose
apps/frontend Next.js frontend for document upload, graph browsing, admin flows, and chat
apps/api Elysia API server, auth bridge, route handlers, and OpenWorkflow integration
apps/worker Background worker that executes durable workflows for file processing
packages/ai Shared AI adapters, prompt helpers, chat message types, and tool wiring
packages/auth Better Auth server and client setup, permissions, and auth helpers
packages/db Drizzle schema, tables, and database access
packages/files Shared RustFS and S3 file utilities
packages/graph Graph extraction, chunking, loaders, and processing logic
packages/logger Shared logging and OpenTelemetry helpers

This structure keeps frontend, API, worker, and shared business logic aligned while still allowing each app to ship independently.


Configuration

Copy .env.sample to .env and configure:

Environment Variables
Variable Description
LOG_LEVEL API log level
APP_DOMAIN Public domain used by Caddy for HTTPS and /s3 proxying
AUTH_SECRET Secret key for authentication
AUTH_URL Public auth base URL
TRUSTED_ORIGINS Comma-separated origins allowed to call auth/API with credentials
AUTH_CROSS_SUBDOMAIN_COOKIES Enable Better Auth cross-subdomain cookies
AUTH_COOKIE_DOMAIN Optional cookie domain for shared auth sessions across subdomains
WORKER_CONCURRENCY Maximum number of workflow runs processed in parallel by the worker
API_URL Frontend API base URL (runtime; no rebuild needed)
INTERNAL_AUTH_URL Server-to-server auth URL inside Docker (defaults to AUTH_URL)
BUILD_LABEL Frontend build label, set via CI build arg
APPLE_CLIENT_ID Apple OAuth client ID
APPLE_CLIENT_SECRET Apple OAuth client secret
APPLE_BUNDLE_ID Apple bundle identifier (optional)
GOOGLE_CLIENT_ID Google OAuth client ID
GOOGLE_CLIENT_SECRET Google OAuth client secret
MICROSOFT_CLIENT_ID Microsoft OAuth client ID
MICROSOFT_CLIENT_SECRET Microsoft OAuth client secret
MICROSOFT_TENANT_ID Microsoft tenant ID (optional)
MICROSOFT_AUTHORITY_URL Microsoft authority URL (optional)
LDAP_URL LDAP server URL
LDAP_BIND_DN LDAP bind DN
LDAP_PASSW LDAP bind password
LDAP_BASE_DN LDAP base DN
LDAP_SEARCH_ATTR LDAP search attribute
LDAP_*_CONFIGURED Non-sensitive frontend LDAP presence flags, derived in production compose
MASTER_USER_ID Master user ID (string)
MASTER_USER_NAME Optional display name for the bootstrapped master user
MASTER_USER_EMAIL Optional email for the bootstrapped master user
MASTER_USER_PASSWORD Optional password for bootstrapping a credential login for master user
MASTER_USER_API_KEY Optional Better Auth API key bound to the master user
DATABASE_URL Host PgBouncer PostgreSQL connection string
DATABASE_DIRECT_URL Host direct PostgreSQL connection string
S3_REGION S3 region
S3_ENDPOINT Host RustFS endpoint
TLS_EMAIL Optional ACME contact email used by Caddy
S3_ACCESS_KEY_ID S3 access key
S3_SECRET_ACCESS_KEY S3 secret key
S3_BUCKET S3 bucket name
AI_TEXT_CONCURRENCY Worker-local maximum concurrent text requests
AI_IMAGE_CONCURRENCY Worker-local maximum concurrent image requests
AI_EMBEDDING_CONCURRENCY Worker-local maximum concurrent embedding requests
AI_AUDIO_CONCURRENCY Worker-local maximum concurrent audio requests
AI_VIDEO_CONCURRENCY Worker-local maximum concurrent video requests
OTEL_EXPORTER_OTLP_ENDPOINT Optional OTLP endpoint fallback for log export
OTEL_EXPORTER_OTLP_LOGS_ENDPOINT Optional OTLP logs endpoint
OTEL_EXPORTER_OTLP_HEADERS Optional OTLP export headers

AI model adapters, provider model names, and provider credentials are managed per organization through the /models API. Model credentials are encrypted with AUTH_SECRET before being stored in PostgreSQL. Existing AI_* model environment variables are still read during startup as a bootstrap source: when an organization has no row for a model type, Kiwi seeds one from those legacy variables and then uses the database-backed configuration.

Authentication Mode (Credentials vs LDAP)

LDAP is auto-enabled when all LDAP env vars are present (LDAP_URL, LDAP_BIND_DN, LDAP_PASSW, LDAP_BASE_DN, LDAP_SEARCH_ATTR). When LDAP is active, email/password sign-up and sign-in are disabled automatically.

The API and frontend both derive the mode with the shared @kiwi/auth helper. The API derives from actual LDAP values and logs a warning for partial configuration. The frontend derives from non-sensitive LDAP_*_CONFIGURED presence flags so LDAP bind credentials do not need to be present in the frontend container.

Cross-Subdomain Cookies

To share auth sessions across subdomains, configure the backend with:

  • TRUSTED_ORIGINS set to a comma-separated list of frontend origins, for example https://app.example.com,https://admin.example.com
  • AUTH_CROSS_SUBDOMAIN_COOKIES=true
  • AUTH_COOKIE_DOMAIN=.example.com (or the most specific shared domain you need)

Example:

AUTH_URL=https://auth.example.com/auth
TRUSTED_ORIGINS=https://app.example.com,https://admin.example.com
AUTH_CROSS_SUBDOMAIN_COOKIES=true
AUTH_COOKIE_DOMAIN=.example.com

When you deploy behind Caddy on one host, keep the frontend on relative paths:

  • API_URL=/api
  • AUTH_URL=/auth

Example:

AUTH_URL=https://kiwi.example.com/auth
TRUSTED_ORIGINS=https://kiwi.example.com
API_URL=/api

For local Bun development without Caddy, point the frontend directly at the API/auth server:

AUTH_URL=http://localhost:4321/auth
API_URL=http://localhost:4321

OpenWorkflow uses DATABASE_DIRECT_URL instead of a separate workflow-specific connection variable. Use DATABASE_URL for pooled application queries and DATABASE_DIRECT_URL for migrations and workflow storage.

The frontend uses next-intl with cookie-based locale selection via NEXT_LOCALE. Supported locales are de and en. A valid NEXT_LOCALE cookie takes precedence. If the cookie is missing or invalid, the frontend selects the preferred supported locale from Accept-Language, including region variants such as en-US; if no supported locale is requested, it falls back to en.

For production, set these variables to the container-network endpoints used inside the Compose stack:

DATABASE_URL=postgresql://kiwi:kiwi@bouncer:5432/kiwi?sslmode=disable
DATABASE_DIRECT_URL=postgresql://kiwi:kiwi@postgres:5432/kiwi?sslmode=disable
S3_ENDPOINT=http://rustfs:9000

Development

docker compose up -d  # Start PostgreSQL, PgBouncer, and RustFS
bun run dev           # Start frontend, API, and worker
docker compose down   # Stop infrastructure

Archive uploads in the Docker/production API image include extraction tools automatically. Local Bun API development that handles archive uploads requires bsdtar from libarchive-tools, plus gzip, bzip2, xz, zstd, and brotli:

sudo apt-get install -y --no-install-recommends brotli bzip2 gzip libarchive-tools xz-utils zstd

Run database migrations manually after the infrastructure is up and before starting the app processes. When MASTER_USER_ID is configured, the API also ensures the matching user exists as an admin with the configured profile fields. If MASTER_USER_API_KEY is also configured, the API bootstraps that value as a managed Better Auth API key for the master user.

Development Services

Service Port Description
frontend 3000 Next.js dev server
server 4321 Bun API server with /auth
worker - Durable workflow worker
postgres 5433 Direct PostgreSQL connection
bouncer 5432 PgBouncer pooled connection
rustfs 9000, 9001 S3-compatible storage

Worker Runtime

The background worker in apps/worker executes durable workflow runs stored in PostgreSQL.

  • API requests enqueue process, delete, and description workflow runs transactionally.
  • The worker polls pending runs, claims a lease, heartbeats while work is in progress, and retries failures with backoff.
  • File indexing fans out to one process workflow per file. Once all file workflows in a correlation finish, description workflows are enqueued automatically.
  • Delete operations use delete workflows and refresh affected descriptions before the project returns to ready.
# Start the full local stack
bun run dev

# Start only the worker
bun --cwd apps/worker run dev

AGENTS.md

Document Description
AGENTS.md Repo technologies, commands, and style

License

MIT

About

Turn your documents into a searchable knowledge graph. Upload files, let AI extract entities and relationships, then ask questions in natural language. Built with Typescript and Next.js. Self-hostable with Docker Compose.

Resources

License

Code of conduct

Contributing

Stars

14 stars

Watchers

1 watching

Forks

Packages

 
 
 

Contributors

Languages