Deployment
Run OIKB next to Hrida.ai as a daemon. The image is ghcr.io/hrida-ai/hrida-oikb (amd64 and arm64). From v1.0.2 it includes the libraries for every connector (S3, R2, GCS, Azure, Dropbox, Google Drive / Gmail / Sites, web, Oracle, SharePoint certificate auth), so no extra install is needed.
The image is available to licensed clients only. Sign in before the first pull, with your GitHub user and a token that can read packages (read:packages):
echo $TOKEN | docker login ghcr.io -u <github-user> --password-stdinIn production, pin a version tag (for example :1.0.3) instead of :latest, so upgrades happen when you choose.
The image's working directory is /data. Mount your config at /data/.hrida-oikb.yaml and the daemon finds it without --config.
Docker
docker run -d --name hrida-oikb \
-e HRIDA_AI_URL=http://hrida-ai-studio:8080 \
-e HRIDA_AI_API_KEY=sk-... \
-e HRIDA_OIKB_API_KEY=your-daemon-key \
-e GITHUB_TOKEN=ghp_... \
-e LOG_FORMAT=json \
-v ./.hrida-oikb.yaml:/data/.hrida-oikb.yaml:ro \
-p 8002:8080 \
ghcr.io/hrida-ai/hrida-oikb:latest daemonTo sync local folders, mount them under /data too (for example -v ./docs:/data/docs:ro) and reference them as ./docs in the config.
Production Docker Compose
The repository ships docker-compose-oikb-prod.yaml: health check, log rotation, CPU/memory/process limits, no-new-privileges, and the port bound to 127.0.0.1 by default. It joins the external hridaai-network so it reaches Hrida.ai at http://hrida-ai-studio:8080.
Three files, three jobs:
| File | In Git? | Holds |
|---|---|---|
docker-compose-oikb-prod.yaml | Yes | Service definition and safe defaults |
.hrida-oikb.yaml | Yes (no secrets) | Which source syncs to which Knowledge Base, and when. Uses ${VAR} references |
.env | No | Hrida.ai API key, daemon key, connector credentials, Knowledge Base IDs |
1. Put the files on the server
sudo mkdir -p /opt/hrida-oikb && cd /opt/hrida-oikb
# copy docker-compose-oikb-prod.yaml, .env.example and .hrida-oikb.yaml here
cp .env.example .env && chmod 600 .env
docker network create hridaai-network 2>/dev/null || true.envCompose only reads a file named exactly .env, in the folder you run docker compose from. Other names are silently ignored.
2. Fill in .env
HRIDA_AI_URL=http://hrida-ai-studio:8080
HRIDA_AI_API_KEY=sk-...
HRIDA_OIKB_API_KEY=<openssl rand -hex 32>
HRIDA_OIKB_DOCKER_TAG=1.0.3
KB_DOCS_ID=8f3a2b1c-...
GITHUB_TOKEN=ghp_...
CONFLUENCE_URL=https://acme.atlassian.net/wiki
CONFLUENCE_USER=bot@acme.com
CONFLUENCE_TOKEN=...3. Define sources
defaults:
interval: 1h
concurrency: 4
filter:
max-size: 10mb
sources:
- name: hrida-docs
source: github:hrida-ai/hrida-ai-docs
path: docs
kb-id: ${KB_DOCS_ID}
- name: eng-confluence
source: confluence:ENG
kb-id: ${KB_ENG_ID}Check it before starting:
docker compose -f docker-compose-oikb-prod.yaml run --rm hrida-oikb validate --deep4. Start and verify
docker compose -f docker-compose-oikb-prod.yaml pull
docker compose -f docker-compose-oikb-prod.yaml up -d
docker compose -f docker-compose-oikb-prod.yaml ps # running + healthy
curl -fsS http://127.0.0.1:8002/health/ready
curl -X POST -H "Authorization: Bearer $HRIDA_OIKB_API_KEY" \
http://127.0.0.1:8002/sync/hrida-docsSettings
| Variable | Default | Purpose |
|---|---|---|
HRIDA_AI_URL | http://hrida-ai-studio:8080 | Hrida.ai URL |
HRIDA_AI_API_KEY | — | Hrida.ai API key. Required |
HRIDA_OIKB_API_KEY / _FILE | — (endpoints open) | Protects /history and /sync. Set one, not both |
HRIDA_OIKB_DOCKER_TAG | latest | Image version. Pin it in production |
HRIDA_OIKB_BIND_ADDR | 127.0.0.1 | Host interface the port is published on |
HRIDA_OIKB_PORT | 8002 | Published host port |
LOG_FORMAT | json | json or text |
OIKB_CONFIG_FILE | ./.hrida-oikb.yaml | Host path mounted as the config |
OIKB_CPU_LIMIT / OIKB_MEM_LIMIT | 2 / 1g | Resource ceilings |
OIKB_PIDS_LIMIT | 512 | Max processes |
Updating
| Change | Command |
|---|---|
| New image version | Edit HRIDA_OIKB_DOCKER_TAG, then pull and up -d |
.hrida-oikb.yaml edited | docker compose -f docker-compose-oikb-prod.yaml restart hrida-oikb |
.env edited | docker compose -f docker-compose-oikb-prod.yaml up -d (a restart doesn't reload .env) |
Webhooks from the internet
Put a TLS reverse proxy in front: route to hrida-oikb:8080 from a proxy container on hridaai-network, or to 127.0.0.1:8002 from a proxy on the host. Then point the source system at https://oikb.example.com/webhooks/github (and so on). See Webhooks.
GitHub Actions
Sync docs to a Knowledge Base on every push, with no server to run:
on:
push:
branches: [main]
paths: ["docs/**"]
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Sign in to the Hrida AI registry
run: echo "${{ secrets.HRIDA_GHCR_TOKEN }}" | docker login ghcr.io -u "${{ secrets.HRIDA_GHCR_USER }}" --password-stdin
- name: Sync docs to Hrida.ai
run: |
docker run --rm -v "$GITHUB_WORKSPACE/docs:/data/docs:ro" \
-e HRIDA_AI_URL -e HRIDA_AI_API_KEY \
ghcr.io/hrida-ai/hrida-oikb:1.0.3 sync /data/docs --kb-id "${{ secrets.KB_ID }}"
env:
HRIDA_AI_URL: ${{ secrets.HRIDA_AI_URL }}
HRIDA_AI_API_KEY: ${{ secrets.HRIDA_AI_API_KEY }}Because the image is private, a uses: docker://… step can't pull it. Store your GitHub user and a token that can read packages as the HRIDA_GHCR_USER and HRIDA_GHCR_TOKEN secrets, sign in, then run the image with docker run.
Kubernetes
Store the config in a ConfigMap and the keys in a Secret:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hrida-oikb
spec:
replicas: 1
selector:
matchLabels: { app: hrida-oikb }
template:
metadata:
labels: { app: hrida-oikb }
spec:
imagePullSecrets:
- name: ghcr-hrida # private image, see the note below
containers:
- name: hrida-oikb
image: ghcr.io/hrida-ai/hrida-oikb:latest
args: ["daemon"]
ports:
- containerPort: 8080
env:
- name: HRIDA_AI_URL
value: http://hrida-ai:8080
- name: HRIDA_AI_API_KEY
valueFrom: { secretKeyRef: { name: hrida-oikb-secrets, key: hrida-ai-api-key } }
- name: HRIDA_OIKB_API_KEY
valueFrom: { secretKeyRef: { name: hrida-oikb-secrets, key: hrida-oikb-api-key } }
- name: LOG_FORMAT
value: json
volumeMounts:
- name: config
mountPath: /data/.hrida-oikb.yaml
subPath: .hrida-oikb.yaml
livenessProbe:
httpGet: { path: /health/ready, port: 8080 }
periodSeconds: 30
readinessProbe:
httpGet: { path: /health, port: 8080 }
periodSeconds: 60
volumes:
- name: config
configMap:
name: hrida-oikb-config
---
apiVersion: v1
kind: Service
metadata:
name: hrida-oikb
spec:
selector: { app: hrida-oikb }
ports:
- port: 8080The image is private, so the cluster needs credentials to pull it (the imagePullSecrets
entry above). Create the ghcr-hrida secret once, in the same namespace, with your GitHub
user and a token that can read packages (read:packages):
kubectl create secret docker-registry ghcr-hrida \
--docker-server=ghcr.io --docker-username=<github-user> --docker-password=<token>Keep replicas: 1. Each replica would run its own schedule and duplicate every sync.
Troubleshooting
| Symptom | Fix |
|---|---|
docker pull: denied or unauthorized from ghcr.io | Not signed in, or your account has no access to the private image. Run docker login ghcr.io with a token that has read:packages; if it still fails, ask your Hrida AI contact to grant access |
Kubernetes pod stuck in ImagePullBackOff | The ghcr-hrida pull secret is missing, in another namespace, or holds an expired token. Recreate it (see Kubernetes) |
gh release download: release not found or HTTP 404 | No access to the private Hrida-AI/hrida-oikb repository, or that version doesn't exist. Check gh auth status and the repository's Releases page |
hrida-oikb: command not found right after installing | pip's scripts folder isn't on PATH (common on Windows). Run python -m hrida_oikb, or install with uv tool install / pipx install. See Installation |
'hrida-oikb' is not recognized as an internal or external command (Windows package) | Unzipping doesn't put it on PATH. Run install.cmd from the unzipped folder, then open a new window. See Installation |
sha256sum -c reports FAILED | The download is incomplete or altered. Delete it and download again; don't install it |
Connection refused or 401 Unauthorized from Hrida.ai | Check HRIDA_AI_URL and HRIDA_AI_API_KEY (hrida-oikb config get, or echo $HRIDA_AI_URL) |
405 Method Not Allowed for .../knowledge/<id>/sync/diff | That Studio doesn't have the knowledge sync API yet; a different API key won't help. Update Studio (see Requirements) |
403 Forbidden on sync/diff, sync/cleanup or an upload | The API key's user can't write to that Knowledge Base. Share it with them for writing, or use a key of its owner or an admin |
429 Too Many Requests on uploads | Studio accepts 20 uploads a minute from one address. The remaining files are uploaded on the next run |
hrida-oikb ls prints (empty), or hrida-oikb status fails, although the Knowledge Base has files | These two commands read the file list from where older Studio versions returned it. Check the Knowledge Base in Studio (Workspace › Knowledge); syncing is not affected |
A connector says to pip install a library (Docker) | The image is older than v1.0.2, which shipped without connector libraries. Update the image (docker compose pull) |
Container stays unhealthy although the daemon runs | Compose file from before v1.0.2: its healthcheck calls curl, which the image doesn't have. Use the healthcheck from the current docker-compose-oikb-prod.yaml |
No sync entries found | No .hrida-oikb.yaml in the current folder (in Docker: not mounted at /data/.hrida-oikb.yaml). Pass a source and --kb-id, or run hrida-oikb init |
Config fails to load or validate errors | sources must be a list of entries with source: and kb-id: |
${GITHUB_TOKEN} appears literally in an error | The variable isn't set. Add it to .env (uncommented) and run up -d |
| Sync runs but nothing appears in Hrida.ai | Wrong Knowledge Base ID, or the API key can't write to that Knowledge Base. Try hrida-oikb validate --deep |
/sync returns 401 | Send Authorization: Bearer $HRIDA_OIKB_API_KEY |
Container exits: both ..._API_KEY and ..._API_KEY_FILE set | Set only one |
| Webhook pushes don't trigger syncs | Entry needs webhook: true; endpoint must be reachable from the internet; check the daemon logs (unmatched pushes return 200 ignored) |
| Large syncs are slow | Raise concurrency, set filter.max-size, exclude what you don't need |
network hridaai-network ... could not be found | docker network create hridaai-network |
env_file / required parse error | Upgrade to Docker Compose v2.24+ |