Metadata-Version: 2.3
Name: oikb
Version: 0.1.2
Summary: Sync anything to Open WebUI Knowledge Bases
Author: Tim Baek
Author-email: Tim Baek <tim@openwebui.com>
License: MIT License
         
         Copyright (c) 2026 Open WebUI Inc.
         
         Permission is hereby granted, free of charge, to any person obtaining a copy
         of this software and associated documentation files (the "Software"), to deal
         in the Software without restriction, including without limitation the rights
         to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
         copies of the Software, and to permit persons to whom the Software is
         furnished to do so, subject to the following conditions:
         
         The above copyright notice and this permission notice shall be included in all
         copies or substantial portions of the Software.
         
         THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
         SOFTWARE.
Requires-Dist: click>=8.1
Requires-Dist: httpx>=0.27
Requires-Dist: pyyaml>=6.0
Requires-Dist: watchdog>=4.0
Requires-Dist: httpx ; extra == 'airtable'
Requires-Dist: boto3>=1.34 ; extra == 'all'
Requires-Dist: google-cloud-storage>=2.14 ; extra == 'all'
Requires-Dist: azure-storage-blob>=12.19 ; extra == 'all'
Requires-Dist: dropbox>=12.0 ; extra == 'all'
Requires-Dist: google-api-python-client>=2.100 ; extra == 'all'
Requires-Dist: google-auth>=2.25 ; extra == 'all'
Requires-Dist: beautifulsoup4>=4.12 ; extra == 'all'
Requires-Dist: httpx ; extra == 'asana'
Requires-Dist: azure-storage-blob>=12.19 ; extra == 'azure'
Requires-Dist: httpx ; extra == 'bitbucket'
Requires-Dist: httpx ; extra == 'bookstack'
Requires-Dist: httpx ; extra == 'clickup'
Requires-Dist: httpx ; extra == 'confluence'
Requires-Dist: pytest>=8.0 ; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23 ; extra == 'dev'
Requires-Dist: respx>=0.21 ; extra == 'dev'
Requires-Dist: httpx ; extra == 'discord'
Requires-Dist: httpx ; extra == 'discourse'
Requires-Dist: dropbox>=12.0 ; extra == 'dropbox'
Requires-Dist: httpx ; extra == 'freshdesk'
Requires-Dist: google-cloud-storage>=2.14 ; extra == 'gcs'
Requires-Dist: google-api-python-client>=2.100 ; extra == 'gdrive'
Requires-Dist: google-auth>=2.25 ; extra == 'gdrive'
Requires-Dist: httpx ; extra == 'gitbook'
Requires-Dist: httpx ; extra == 'github'
Requires-Dist: httpx ; extra == 'gitlab'
Requires-Dist: google-api-python-client>=2.100 ; extra == 'gmail'
Requires-Dist: google-auth>=2.25 ; extra == 'gmail'
Requires-Dist: httpx ; extra == 'guru'
Requires-Dist: httpx ; extra == 'hubspot'
Requires-Dist: httpx ; extra == 'jira'
Requires-Dist: httpx ; extra == 'linear'
Requires-Dist: httpx ; extra == 'notion'
Requires-Dist: boto3>=1.34 ; extra == 'r2'
Requires-Dist: boto3>=1.34 ; extra == 's3'
Requires-Dist: httpx ; extra == 'salesforce'
Requires-Dist: httpx ; extra == 'sharepoint'
Requires-Dist: httpx ; extra == 'slack'
Requires-Dist: httpx ; extra == 'teams'
Requires-Dist: beautifulsoup4>=4.12 ; extra == 'web'
Requires-Dist: httpx ; extra == 'zendesk'
Requires-Python: >=3.11
Provides-Extra: airtable
Provides-Extra: all
Provides-Extra: asana
Provides-Extra: azure
Provides-Extra: bitbucket
Provides-Extra: bookstack
Provides-Extra: clickup
Provides-Extra: confluence
Provides-Extra: dev
Provides-Extra: discord
Provides-Extra: discourse
Provides-Extra: dropbox
Provides-Extra: freshdesk
Provides-Extra: gcs
Provides-Extra: gdrive
Provides-Extra: gitbook
Provides-Extra: github
Provides-Extra: gitlab
Provides-Extra: gmail
Provides-Extra: guru
Provides-Extra: hubspot
Provides-Extra: jira
Provides-Extra: linear
Provides-Extra: notion
Provides-Extra: r2
Provides-Extra: s3
Provides-Extra: salesforce
Provides-Extra: sharepoint
Provides-Extra: slack
Provides-Extra: teams
Provides-Extra: web
Provides-Extra: zendesk
Description-Content-Type: text/markdown

# 📚 oikb

Keep your [Open WebUI](https://github.com/open-webui/open-webui) Knowledge Bases in sync. Point it at a local directory, a GitHub repo, a Confluence space, an S3 bucket, or any of 30+ supported sources. Only new and modified files are uploaded via incremental SHA-256 diffing.

> [!IMPORTANT]
> Requires **Open WebUI 0.9.6+**

## Quick Start

```bash
pip install oikb

export OPEN_WEBUI_URL=http://localhost:3000
export OPEN_WEBUI_API_KEY=sk-your-api-key

# Sync a directory to a Knowledge Base
oikb sync ./docs --kb-id your-kb-id

# Or watch for changes and auto-sync continuously
oikb watch ./docs --kb-id your-kb-id
```

Or with Docker:

```bash
docker run --rm \
  -e OPEN_WEBUI_URL=http://host.docker.internal:3000 \
  -e OPEN_WEBUI_API_KEY=sk-your-key \
  -v ./docs:/data \
  ghcr.io/open-webui/oikb watch /data --kb-id your-kb-id
```

## Commands

| Command | Description |
|---|---|
| `oikb sync <source>` | Incremental sync to a Knowledge Base |
| `oikb watch <source>` | Watch for changes and auto-sync |
| `oikb diff <source>` | Preview what a sync would do |
| `oikb ls` | List files in a Knowledge Base |
| `oikb status` | Show KB info and file count |
| `oikb reset` | Delete all files in a Knowledge Base |
| `oikb config` | Manage saved URL and API key |

## 30+ Connectors

Beyond local directories, oikb can sync from remote sources using the same `oikb sync <source>` interface.

| Category | Sources |
|---|---|
| **Code Repos** | GitHub, GitLab, Bitbucket |
| **Cloud Storage** | S3, GCS, Azure Blob, Dropbox, R2, Google Drive, SharePoint |
| **Wikis & KBs** | Confluence, Notion, BookStack, Discourse, GitBook, Guru |
| **Ticketing** | Jira, Linear, Zendesk, Freshdesk, Asana, ClickUp, Airtable |
| **Messaging** | Slack, Discord, Microsoft Teams, Gmail |
| **Sales & CRM** | Salesforce, HubSpot |
| **Web** | Website / Sitemap crawler |

```bash
oikb sync github:owner/repo --kb-id your-kb-id
oikb sync confluence:ENG --kb-id your-kb-id
oikb sync s3://bucket/prefix --kb-id your-kb-id
oikb sync slack:C0123ABC --kb-id your-kb-id
```

Some connectors need an optional extra: `pip install oikb[gdrive]`, `pip install oikb[s3]`, or `pip install oikb[all]` for everything.

## Configuration

Resolved in order (highest priority wins):

1. **CLI flags** (`--url`, `--token`)
2. **Environment variables** (`OPEN_WEBUI_URL`, `OPEN_WEBUI_API_KEY`)
3. **Config file** (`~/.config/oikb/config.yaml`)

### Multi-source (`.oikb.yaml`)

Define multiple sources in a single config file:

```yaml
sync:
  - source: ./docs
    kb: project-docs
  - source: github:owner/wiki
    kb: team-wiki
    branch: main
  - source: confluence:ENG
    kb: eng-handbook
```

```bash
oikb sync              # Sync all entries
oikb sync --name docs  # Sync a specific entry
```

## Docker Compose

Run as a sidecar alongside Open WebUI:

```yaml
services:
  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    ports:
      - "3000:8080"

  oikb:
    image: ghcr.io/open-webui/oikb:latest
    environment:
      - OPEN_WEBUI_URL=http://open-webui:8080
      - OPEN_WEBUI_API_KEY=${OPEN_WEBUI_API_KEY}
    volumes:
      - ./docs:/data
    command: watch /data --kb-id ${KB_ID}
    depends_on:
      - open-webui
    restart: unless-stopped
```

## GitHub Actions

```yaml
- name: Sync docs to Open WebUI
  uses: docker://ghcr.io/open-webui/oikb:latest
  with:
    args: sync /github/workspace/docs --kb-id ${{ secrets.KB_ID }}
  env:
    OPEN_WEBUI_URL: ${{ secrets.OPEN_WEBUI_URL }}
    OPEN_WEBUI_API_KEY: ${{ secrets.OPEN_WEBUI_API_KEY }}
```

## How It Works

1. Scan source, compute checksums
2. Send manifest to Open WebUI `/sync/diff`
3. Delete stale files, create missing directories
4. Upload only new and modified files

## License

MIT. See [LICENSE](LICENSE) for details.
