Sync a BookStack wiki into IronRAG: periodic polling + webhook intake, multimodal (pages + attachments + images).
Built on the IronRAG Connector Template — this repo only owns BookStack-specific code (REST client, markdown image collector, shelf reverse index, webhook verifier).
kind |
external key | source |
|---|---|---|
page |
bookstack:page:<id> |
/api/pages/{id}/export/markdown |
attachment |
bookstack:attachment:<id> |
/api/attachments/{id} (base64 decoded) |
image |
bookstack:image:<sha256-prefix-16> |
inline <img> URLs in page markdown (content-addressed dedup) |
Pages, attachments, and inline images all carry their original BookStack URL via
document_hint, which IronRAG surfaces in MCP citations.
Page attachments and inline images now ingest as attached context of their
source page instead of as peer documents. Each dependent is auto-linked to its
page via the framework's parent_external_key; no config change is required.
Sync loop runs every SYNC_INTERVAL_SECONDS (default 1800s) and ships only the diff: pages whose updated_at advanced since the last successful push. Webhook endpoint /webhook/bookstack (HMAC-SHA256 + admin bearer) routes through the same orchestrator.
Full sweeps collect routing facts from the /api/pages summary first. The
connector fetches full page context and refreshes the shelf index only when
routing.yaml rules require facts that are missing from the summary, such as
shelf or tag matches.
docker run -d \
--name ironrag-bookstack \
--env-file .env.local \
-v $(pwd)/routing.yaml:/app/routing.yaml:ro \
-v ironrag_bookstack_state:/var/lib/ironrag-connector \
-p 8088:8088 \
pipingspace/ironrag.bookstack:latestMinimal .env.local:
BOOKSTACK_BASE_URL=https://wiki.example.com
BOOKSTACK_TOKEN_ID=...
BOOKSTACK_TOKEN_SECRET=...
BOOKSTACK_WEBHOOK_SECRET=...
IRONRAG_BASE_URL=https://ironrag.example.com
IRONRAG_API_TOKEN=...
ADMIN_BEARER_TOKEN=...
RUN_MODE=bothrouting.yaml (single library):
default:
workspace: 00000000-0000-0000-0000-000000000000
library: 00000000-0000-0000-0000-000000000000
policies:
page: { on_missing: delete }
attachment: { on_missing: delete }
image: { on_missing: ignore } # content-addressed; may be shared across pagesgit clone git@github.com:mlimarenko/IronRAG.BookStack.git
cd IronRAG.BookStack
cp .env.example .env.local # fill in BookStack + IronRAG creds
cp routing.yaml.example routing.yaml
uv sync --all-extras
uv run pytest
uv run bookstack-connector- See docs/ARCHITECTURE.md for the page → external_key mapping and failure modes.
- Manual sweep trigger:
curl -X POST http://localhost:8088/sync/run -H "Authorization: Bearer $ADMIN_BEARER_TOKEN". - First sweep against a library that already contains BookStack docs: optionally run
uv run python -m bookstack_connector.seed_cursoronce to populate the SQLite cursor from existing IronRAG documents (avoids re-uploading on first pass). CURSOR_LIBRARY_LOOKUP_TIMEOUT_SECONDScontrols best-effort legacy cursor backfill separately from large upload/replace timeouts. If ownership lookup times out, cleanup for that historical library waits for a later sweep while duplicate uploads remain blocked.CURSOR_LIBRARY_LOOKUP_MAX_ROWS_PER_SWEEPcaps how many legacy cursor rows are backfilled before source enumeration; the rest are handled lazily per item or deferred.IRONRAG_MUTATION_TIMEOUT_SECONDSbounds upload/replace/delete admission calls separately from generic HTTP requests. Admission timeouts leave the cursor on the previous source version so the next sweep retries instead of marking the version as handled.REAPER_LIST_TIMEOUT_SECONDSbounds post-sweep IronRAG prefix-list requests so cleanup cannot hold the manual sync request after source enumeration has finished.
cp .env.example .env.local # BOOKSTACK_* + IRONRAG_* + ADMIN_BEARER_TOKEN
cp routing.yaml.example routing.yaml # map shelves/books → (workspace, library)
docker compose up -d
docker compose logs -fdocker-compose.yml pulls the released image, mounts
routing.yaml read-only, and persists the SQLite cursor in a named volume. With
the default RUN_MODE=both it also serves /webhook/bookstack on port 8088
(published on localhost) — front it with a TLS reverse proxy for public delivery.
- IronRAG — the RAG backend these connectors feed.
- Connector Template — the framework every connector builds on.
- Connectors: Confluence · BookStack · Git Repositories
MIT — see LICENSE.