Summary
When a single repository is split across multiple knowledge bases — the pattern
documented under Splitting Sources Across KBs in docs/guide.md — a push
webhook syncs only one of them. The others wait for their scheduled interval.
Expected
A push triggers a sync for every affected source, or at minimum every entry
carrying webhook: true.
Actual
Exactly one entry syncs. Which one depends on its position in sources:.
Reproduction
.oikb.yaml:
defaults:
interval: 1h
sources:
- name: shared
source: github:ORG/REPO
path: _shared
target-path: shared
kb-id: <kb-1>
webhook: true
github_secret: ${GITHUB_WEBHOOK_SECRET}
- name: client-a
source: github:ORG/REPO
path: clients/a
target-path: a
kb-id: <kb-2>
webhook: true
# ... four more entries, same source, different kb-id
Daemon startup:
6 source(s) configured
Scheduling github:ORG/REPO every 3600s (repeated 6×)
Push to the repository. One sync runs against <kb-1>; the other five knowledge
bases stay stale until their interval elapses.
Adding webhook: true to every entry does not change this.
Cause
src/oikb/webhooks.py returns on the first match:
def _find_entry_by_source(prefix: str, match: str) -> dict | None:
for entry in self._entries:
source = entry.get("source", "")
if source.startswith(prefix) and match in source and entry.get("webhook"):
return entry # <-- stops here
@router.post("/github")
async def github_webhook(request: Request):
...
repo = data.get("repository", {}).get("full_name", "")
entry = _find_entry_by_source("github:", repo)
if entry and _run_entry:
asyncio.create_task(_run_entry(entry)) # one entry only
_run_entry_locked then narrows further to a single knowledge base:
entries = [e for e in _entries if e.get("kb-id") == entry["kb-id"]] or [entry]
All entries here share the same source string, so match in source is true for
every one — but the loop returns the first and never reaches the rest.
Impact
The documented Splitting Sources Across KBs workflow has no working
push-trigger path. Affected users must either poll on a short interval or run an
external fan-out calling POST /sync/<name> once per entry.
Suggested fixes
Any of these would resolve it:
-
Fan out to all matching entries. Collect every entry with webhook: true
matching the repo and schedule _run_entry for each distinct kb-id.
_run_entry already takes a per-KB lock, so overlapping schedules are safe:
def _find_entries_by_source(prefix, match):
return [e for e in _entries
if e.get("source", "").startswith(prefix)
and match in e.get("source", "")
and e.get("webhook")]
-
A top-level webhooks: section listing which entries a delivery should
trigger, so the target set is explicit rather than implied by ordering.
-
Accept a target in the URL — /webhooks/github/<entry-name> — allowing one
webhook per entry. GitHub permits multiple webhooks per repository.
Documentation
The Webhooks section and the Splitting Sources Across KBs section of
docs/guide.md never reference each other. Regardless of which fix is chosen, a
sentence noting that one delivery syncs one knowledge base would save others this
debugging.
Environment
- oikb 0.5.0,
ghcr.io/open-webui/oikb:latest, daemon mode
- Six sources, one GitHub repository, six knowledge bases
- Each entry scoped with
path:, with target-path: for citation prefixes
Summary
When a single repository is split across multiple knowledge bases — the pattern
documented under Splitting Sources Across KBs in
docs/guide.md— a pushwebhook syncs only one of them. The others wait for their scheduled interval.
Expected
A push triggers a sync for every affected source, or at minimum every entry
carrying
webhook: true.Actual
Exactly one entry syncs. Which one depends on its position in
sources:.Reproduction
.oikb.yaml:Daemon startup:
Push to the repository. One sync runs against
<kb-1>; the other five knowledgebases stay stale until their interval elapses.
Adding
webhook: trueto every entry does not change this.Cause
src/oikb/webhooks.pyreturns on the first match:_run_entry_lockedthen narrows further to a single knowledge base:All entries here share the same
sourcestring, somatch in sourceis true forevery one — but the loop returns the first and never reaches the rest.
Impact
The documented Splitting Sources Across KBs workflow has no working
push-trigger path. Affected users must either poll on a short interval or run an
external fan-out calling
POST /sync/<name>once per entry.Suggested fixes
Any of these would resolve it:
Fan out to all matching entries. Collect every entry with
webhook: truematching the repo and schedule
_run_entryfor each distinctkb-id._run_entryalready takes a per-KB lock, so overlapping schedules are safe:A top-level
webhooks:section listing which entries a delivery shouldtrigger, so the target set is explicit rather than implied by ordering.
Accept a target in the URL —
/webhooks/github/<entry-name>— allowing onewebhook per entry. GitHub permits multiple webhooks per repository.
Documentation
The Webhooks section and the Splitting Sources Across KBs section of
docs/guide.mdnever reference each other. Regardless of which fix is chosen, asentence noting that one delivery syncs one knowledge base would save others this
debugging.
Environment
ghcr.io/open-webui/oikb:latest, daemon modepath:, withtarget-path:for citation prefixes