Confluye
Features

Research

Durable bounded HTTP(S) research runs that persist untrusted snapshots and a Markdown result document.

A Research run fetches caller-supplied public URLs through the Research egress guard, stores canonical source snapshots, and writes one Markdown document. Output is labeled untrusted: each snapshot and the result document start with a caution that web pages are data, never instructions.

HTTP surface: /api/v1/research. Agents also use preview capability research.run (confirmation and idempotency required) and the related web.search / web.read / web.crawl tools (same egress, no durable run).

Create a run

POST /api/v1/research requires a workspace API key and Idempotency-Key.

FieldRules
queryRequired, trimmed, 1–2000 characters.
sourceUrlsRequired, 1–20 http:// or https:// URLs.
limitsOptional object. Missing keys use egress defaults.
LimitDefaultCreate max (schema)Egress default if omitted
maxDomains88
maxPages2020
maxDepth22
maxBytesPerPage2 MiB2 MiB
maxTotalBytes20 MiB20 MiB
maxDurationMs30 00030 000

Stable run id: research_ plus the first 32 hex chars of sha256(workspaceId + NUL + key). Same key and same query / sourceUrls / limits returns 200 { deduplicated: true, dispatch: { dispatched: false } } without a second enqueue. Same key, different payload: 409 conflict.

First create: 202 { run, deduplicated: false, dispatch }.

Dispatch

If REDIS_URL is set, the job is added to BullMQ queue research-runs (jobId = run id, 3 attempts, exponential backoff from 1s, removeOnComplete: 100, removeOnFail: 250). Worker concurrency: RESEARCH_WORKER_CONCURRENCY (default 4). If queue add throws, the run is marked failed (Research dispatch failed before queue acceptance.) and the error is rethrown.

If REDIS_URL is unset, enqueue runs the processor in the same request (dispatch.mode: "direct", queued: false). Tests that fetch blocked hosts therefore often return 202 with run.status: "failed" immediately.

Store: Prisma when shouldUseDurablePrismaStore("research") is true; otherwise a process in-memory store (lost on restart).

State

statusMeaning
queuedCreated, not yet markRunning.
runningClaimed from queued with cancelRequestedAt null.
succeededResult document persisted; resultDocumentId set.
failedEgress, dispatch, or processor error. error is the message.
canceledCancel requested while queued or running.

Prisma document id is research_document_{runId}, mimeType: text/markdown, tags ["research"], sourceUri: research:{runId}, indexingStatus: pending, status: ready, enabled: true. Name: Research - {query truncated to 120}.md. In-memory complete uses the same id prefix in a separate document map (not the Docs HTTP API unless Prisma is in use).

Cancel (POST .../{id}/cancel, idempotency required) sets canceled for queued/running, aborts an in-process controller, and removes a BullMQ job still waiting / delayed / prioritized. A terminal run is returned as-is (200); the test suite shows cancel of failed still returns failed.

Egress guard

Fetches use profile research (SSRF / DNS allowlist), User-Agent: FluxusResearchBot, and robots.txt (max 512 KiB). Allowed page types: text/html, application/xhtml+xml, text/plain. HTML is stripped to text; scripts are not kept as instructions. Duplicate canonical URLs in one run are skipped. Canonicalization lowercases host and sorts query params.

Private/link-local URLs are blocked by egress (a loopback sourceUrl fails the run).

Authorization

Workspace API key only. 401 without a valid bearer. 403 for personal/copilot keys. Foreign run ids: 404. Workspace id is always the key's workspace.

Next steps