Artur Mukhamadiev 3751ab26b5 deadline: configurable protocol maximum (default 900 s); book favicon
The 180 s query cap was enforced independently by the backend clamp, the
agent limits, and the container supervisor. All three now follow
CONFLUENCE_WEB_MAX_DEADLINE_SECONDS (default 900, allowed 60-3600): the
backend passes it into the container at launch, the supervisor reads it and
forwards it to the bridge, and both fall back to 900 s on invalid input. The
query timeout must not exceed it (startup fails otherwise). The supervisor
keeps a separate 180 s guard for a container that never receives a start
frame.

Add assets/book.svg as the tab icon: the backend serves assets/ and the CSP
allows same-origin images (the sanitizer still never emits <img>).
2026-09-15 13:38:44 +03:00
2026-09-14 17:06:32 +03:00

Confluence Research Web UI

A minimalist web UI that researches a Confluence Data Center instance with a pi agent running in a fresh, network-less rootless Docker container per query, and returns a cited Markdown answer plus optional files the agent produced. Each component documents its own interface in agent/README.md, backend/README.md and frontend/README.md.

The repository also contains the original standalone Confluence crawler, which is unchanged.

Components

Directory Role Developer guide
backend/ FastAPI service: credentials in memory, Confluence/model upstreams, authoritative tool history, container lifecycle, artifact downloads, serves the frontend backend/README.md
agent/ Container image: pinned pi SDK bridge, Python supervisor, local tools, artifact exporter agent/README.md
frontend/ Static UI (vendored marked, DOMPurify and thinking-orbs engine), same-origin mock server for UI development frontend/README.md
tests/integration/ Integration-stage tests connecting the real components this file
deploy/, scripts/, Makefile Deployment configuration and entry points this file

Requirements

  • Linux with a rootless Docker daemon (cgroup v2, memory/CPU/PID limits enforced). docker info must list rootless under Security Options.
  • Python 3.12+ in .venv (verified with 3.14.7), Node 22+ (verified with 26.7) and npm.
  • An OpenAI-compatible Chat Completions endpoint the backend can reach (key held by the backend only).
  • Network access from the backend host to the approved Confluence origin, optionally through a SOCKS5/HTTP proxy.
  • For browser checks: Google Chrome with --remote-debugging-port=9444.

Setup

python3 -m venv .venv && .venv/bin/python -m pip install -r requirements.txt
make install                 # also installs agent/ and frontend/ dev dependencies
make build-image             # builds confluence-pi-agent:rev1 and prints its image ID
cp deploy/confluence-web.env.example deploy/confluence-web.env   # then edit

deploy/confluence-web.env is git-ignored. Every variable is documented in the example file and in backend/README.md. Pin CONFLUENCE_WEB_RUNTIME_IMAGE to the image ID printed by make build-image for an exact runtime, set a deployment-unique CONFLUENCE_WEB_CONTAINER_LABEL_VALUE, and list only approved Confluence origins.

Run

make run                     # scripts/run-backend.sh deploy/confluence-web.env

The backend binds 127.0.0.1:8000 by default and serves the UI at http://127.0.0.1:8000/. Open it in a browser, click the key icon, enter the Confluence base URL including its context path (for example https://collab.lge.com/main, which must match an approved origin), your personal access token (PAT), test the connection, then ask a question. On instances that allow anonymous REST reads, "Test connection" proves the destination is reachable but cannot prove the PAT is valid; a wrong token then shows up as denied or missing pages. Credentials live only in browser memory and in the backend for the duration of a request; a page reload clears them.

Version 1 is a small-team deployment: one backend worker, one query at a time (a second query gets busy), loopback by default. The application has no login of its own; anyone who can reach the port can run queries with their own PAT. Never bind it to a network interface over plain HTTP, because every request carries the user's PAT. If you put a reverse proxy in front, it must accept 6*16 MiB + 64 KiB request bodies, pass client aborts through promptly, avoid buffering bodies to disk, and allow at least 200 s per request.

Serving colleagues on an internal network (IP only, TLS)

Uvicorn terminates TLS itself; no reverse proxy or DNS name is needed. The certificate comes from a private CA that is name-constrained to the listed IP addresses, so colleagues who import it are trusting it for those addresses only. A certificate issued by the same CA for any hostname or any other address is rejected by browsers and by OpenSSL (permitted subtree violation).

make tls IP=172.26.10.20          # creates deploy/tls/{ca,server}.{key,crt}; git-ignored

Then in deploy/confluence-web.env:

CONFLUENCE_WEB_BIND_HOST=172.26.10.20
CONFLUENCE_WEB_TLS_CERT=./deploy/tls/server.crt
CONFLUENCE_WEB_TLS_KEY=./deploy/tls/server.key

Restart with make run and open https://172.26.10.20:8000/. Under HTTPS the session cookie gains the Secure flag automatically and the same-origin check expects https:// origins.

Hand colleagues only deploy/tls/ca.crt, imported once as a trusted root (Windows: double-click, "Trusted Root Certification Authorities"; macOS: Keychain Access; Chrome on Linux: chrome://settings/certificates; Firefox: Settings, Certificates, Authorities). They can read the constraint themselves in the certificate details ("Name Constraints: Permitted IP ..."). Keep ca.key and server.key on the server host. The server certificate is valid for 825 days (the browser maximum); rotate it with the same CA by deleting deploy/tls/server.* and re-running make tls with the CA files kept, or rotate everything by deleting the directory.

Network-free UI development against explicit fakes (no Docker, PAT dev-pat, URL https://approved.example.com):

make run-dev

Credentials, expiry and limits

  • Confluence PAT: entered in the browser per session, sent only to the backend over the same origin, never stored, logged, or passed to the container. The token inherits your Confluence permissions.
  • Model key: backend environment only (CONFLUENCE_WEB_MODEL_API_KEY). For a local llama.cpp server any placeholder works.
  • Session cookie cw_session: HttpOnly, SameSite=Strict, marks artifact ownership only. It is not authentication.
  • Artifacts: at most 20 files, 10 MiB each, 50 MiB per query, 500 MiB total; downloadable for 15 minutes after a successful query, then deleted. Failed or cancelled queries keep nothing.
  • Query: 180 s total deadline by default (CONFLUENCE_WEB_QUERY_TIMEOUT_SECONDS, up to CONFLUENCE_WEB_MAX_DEADLINE_SECONDS, default 900 s) plus 10 s cleanup, prompt up to 16 MiB, answer up to 128 MiB, 100 Confluence calls and 50 model calls per query, container limited to 1 GiB RAM, 1 CPU, 128 processes, no network.
  • Model tokens: CONFLUENCE_WEB_MODEL_CONTEXT_WINDOW_TOKENS and ..._MAX_OUTPUT_TOKENS describe the provider; they are independent of the byte limits above. Large pages or answers can exceed the model's context before the application limits; the UI then shows model_context_exceeded or model_output_limit.

Checks

Command What it runs Needs
make check Crawler + backend + integration (no Docker) pytest, agent host tests, frontend unit/contract tests nothing external
make check-docker Backend real-Docker checks, backend + real runtime image + scripted peers, real provider adapter + runtime, runtime image/isolation/boundary checks rootless Docker, built images
make check-browser Real Chrome against the real backend (scripted runtime), frontend's own e2e suite Chrome on 127.0.0.1:9444, Node

Each subsystem's own commands are documented in its guide and can be run independently:

CONFLUENCE_PAT=synthetic-token-no-network CONFLUENCE_URL=https://approved.example.com .venv/bin/python -m pytest tests/backend
npm --prefix agent test && npm --prefix agent run proof
npm --prefix frontend test && npm --prefix frontend run test:e2e

Fake modes (CONFLUENCE_WEB_DEV_MODE, the backend fake image, the frontend mock server, the runtime's fake backend peer) are explicit opt-ins and never activate on a production failure.

Standalone crawler

Crawls Confluence Data Center pages into Markdown files using a PAT from .env (CONFLUENCE_URL, CONFLUENCE_PAT; see .env.example). PATs require Confluence Data Center / Server 7.9+.

python main.py --space KEY --out output/KEY   # one space
python main.py --all --out output             # all visible spaces
pytest -m live                                # live crawler tests (uses .env)

Each page becomes output/<space>/<page_id>_<slug>.md with YAML front matter. The web backend imports only the crawler's pure conversion functions; it never reads .env.

Description
No description provided
Readme 548 KiB
Languages
Python 52%
JavaScript 26.9%
TypeScript 15.3%
CSS 3.2%
HTML 1.1%
Other 1.5%