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 (human-readable IronRAG catalog reference):
default:
library: knowledge/wiki
policies:
page: { on_missing: delete }
attachment: { on_missing: delete }
image: { on_missing: ignore } # content-addressed; may be shared across pagesRouting targets use the same canonical <workspace-slug>/<library-slug>
references shown by IronRAG and its MCP catalog. UUID targets and a separate
workspace field are not accepted. Rules can route one connector instance to
multiple libraries or workspaces; see routing.yaml.example
for the complete schema, every supported policy value, and the exact BookStack
facts and kinds available to match.
git 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). OPERATION_POLL_INTERVAL_SECONDS/OPERATION_POLL_BUDGET_SECONDStune how the framework polls asynchronous IronRAG mutations (revisions and deletes hand back an operation that is polled to a terminal state). A poll-budget timeout leaves the cursor on the previous source version so the next sweep retries instead of marking the version as handled.REWALK_CONCURRENCYbounds the fan-out of a post-upgrade full re-walk of IronRAG documents; keep it within the BookStack instance's rate limit.REAPER_LIST_TIMEOUT_SECONDSbounds post-sweep IronRAG document-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 refs
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.