coreci-researchx-po d51c66d45b
ci / backend (uv, Python 3.12: ruff/mypy/pytest) (push) Successful in 32s
ci / frontend (Next.js on pnpm: typecheck/lint/test/build) (push) Successful in 1m36s
ci / backend (uv, Python 3.12: ruff/mypy/pytest) (pull_request) Successful in 32s
ci / frontend (Next.js on pnpm: typecheck/lint/test/build) (pull_request) Successful in 1m36s
Phase 4 slice 1: backend/.dockerignore (build-context hygiene)
2026-10-30 23:01:55 +00:00

ResearchX

TL;DR — ResearchX turns one question into a cited research report: pick a method, approve the plan, and the engine visits real web sources, with every claim anchored to a quoted passage from a page it actually read. The engine milestone (v0.2.5) is shipped and owner-approved; hosting goes live next (v0.3, in progress).

  • What — FastAPI backend (planning, search, extraction, verification, export gates) plus a Next.js frontend; the full test suite runs with zero API keys.
  • Why — Readers can check every citation back to its source passage; runs are resumable from durable state.
  • Action — no action — FYI. Developers: see the Quickstart below.
  • Details — frontend/README.md (web app); .ciagent/ (pipeline state and roadmap).

A deep-research studio where you bring your own model, storage, and memory; choose a research methodology before a single query fires; and every claim in the final report is anchored to a visited, verified, quotable source.

Status: MVP shipped (v0.2.5, owner-approved 2026-09-27) — the full research engine (FastAPI + asyncio state machine + adapter layer + attack-proven trust loop) behind the v0.1 frontend. Live mode covers the core research loop (G-002/G-009): the engine runs locally per the quickstart; library/settings/suggestions/refine stay mock-backed until v0.3+.

Quickstart

# frontend (prototype, mock-backed — works today)
cd frontend
corepack pnpm install
corepack pnpm dev          # http://localhost:3000

# backend (MVP — uv manages Python 3.12 and the venv)
cd backend
uv sync                    # installs deps + editable researchx package
uv run uvicorn researchx.api.app:app --reload --port 8000
uv run pytest              # full suite, zero API keys

Three clicks from cold start to initiated research.

Monorepo command map

Layer Install Dev Gates
backend (uv, Python 3.12) uv sync uv run uvicorn researchx.api.app:app --reload --port 8000 uv run ruff check src tests · uv run mypy src · uv run pytest
frontend (pnpm 12.6) corepack pnpm install corepack pnpm dev corepack pnpm typecheck · corepack pnpm lint · corepack pnpm test · corepack pnpm build

Engine architecture (v0.2 P2)

The research engine is a hand-rolled asyncio state machine:

PLANNING → AWAITING_APPROVAL → SEARCHING → EXTRACTING → REFLECTING ─┐
                (halt until             ↑ depth loop (dials.depth)  │
                 approved)              └────────────────────────────┘
→ SYNTHESIZING → VERIFYING → DONE  (+ CANCELLED / FAILED terminals)
  • Durable state: runs/<id>/state.json rewritten atomically after every transition; resume re-enters at the recorded cursor with the persisted plan
  • Event bus: typed events (run_started, query_fired, source_visited, passage_extracted, state_changed, run_done, run_error) — trace per run
  • Visited-only constraint: the writer's context is the evidence store and nothing else
  • Trust loop: SSRF-guarded liveness (live/stale/dead), quote anchoring (normalize + fuzzy ≥ 0.85, weak matches flagged), citation ledger JSON, exportable verification checklist, single-source vs corroborated confidence labels

Run artifacts per run: state.json, report.md, ledger.json, checklist.md.

Try it on fakes (no keys): uv run python -m researchx.engine.demo

Adversarial guarantees (v0.2 P4)

Every trust-loop claim is attacked by the adversarial suite (backend/tests/test_adversarial.py) — these are tests that try to fool the verifier, and their passing proves the defenses:

Attack Defense (proven)
Writer hallucinates a citation to a passage that was never stored Unknown passage IDs count as unanchored claims in the ledger; the export gate fails the report
Fabricated quote (matches nothing) Anchoring verdict: no match, flagged — never silently accepted
Near-miss quote (0.80–0.85 similarity) Flagged weak_match in the ledger — surfaced, not accepted
Liveness probe redirected to a private/metadata IP Per-hop redirect re-guarding classifies it dead (SSRF refusal)
Redirect chain ending at a gone page (410) Classified dead
Oversized page (5MB) response 2MB read cap — classifies without unbounded memory
Pause during the depth loop Durable state persists; resume completes the run over the HTTP API
Cancel mid-loop Terminal CANCELLED state persisted, never swallowed

REQ-23 (≥99% citation liveness) is a per-run export gate enforced by the verification checklist, plus an opt-in keyed live tier (cd backend && uv run pytest -m live) — the zero-key CI suite never asserts it vacuously.

The E2E happy path (≤3 clicks: ask, choose, approve) is validated against the real FastAPI + engine stack, defaults only — not the mock (frontend/src/lib/api/e2e-real-stack.test.ts).

Adapter configuration (v0.2)

All keys resolve from env files only (.env, .env.secrets, .env.* — never the shell environment, never git):

Variable Scope Used by
OLLAMA_API_KEY model (cloud) Ollama cloud endpoint https://ollama.com/v1; absent/keyless falls back to http://localhost:11434/v1 automatically
OLLAMA_BASE_URL model Overrides the default cloud base URL
TAVILY_API_KEY search Tavily default search; absent falls back to the keyless DuckDuckGo adapter (degraded mode — surfaced in the run trace)

The test suite needs no keys: fake model/search adapters (REQ-31) drive every engine test.

Live mode (v0.2 P3)

The frontend runs mock-backed by default (works standalone, zero keys). To run the core research loop against the real backend:

# terminal 1 — backend (fake adapters by default; real Ollama/Tavily adapters
# are used by the engine in v0.2.5+ wiring — the served API currently ships
# fake-adapter runs for demos and tests; see Adapter configuration below)
cd backend && uv run uvicorn researchx.api.app:app --reload --port 8000

# terminal 2 — frontend in live mode
cd frontend && NEXT_PUBLIC_RESEARCHX_API_MODE=live corepack pnpm dev

Live mode covers the core loop (Ask → Choose → approve plan → live trace → report + ledger); the library, settings persistence, suggestions, refine, and graph surfaces stay mock-backed until v0.3. The API surface: POST /api/runs, GET /api/methodologies, run lifecycle (approve/pause/cancel/resume), GET /api/runs/{id}/events (SSE), GET /api/config, report + ledger artifacts.

What's in the prototype

Screen What it does
/ask One question box + one optional context box — plus two opt-in helpers below and beside them: open-question suggestions (follow-ups from your past runs, one click fills the box) and the Refine question dialogue (a few clarifying answers → a composed, sharper question). Neither ever auto-starts.
/choose All 8 locked methodology cards — mock ETA, cost estimate, why-recommended, and the 12 methodology dials behind each card's Advanced drawer.
/run/[id] Plan & Run: approve the research plan (sub-questions, source universe, outline), watch the live trace stream, pause/resume or cancel.
/run/[id]/report Reading Room: the report with page-anchored citations — hover or focus any [n] marker for the exact quoted passage — plus the citation ledger and Markdown/JSON exports.
/library Stored reports filed into auto-categorized folders (sortable, links into the Reading Room), the Connections panel (shared sources ⇄, related topics →), plus v2-preview project graph and task inbox.
/settings API-key status (masked, never raw), the reports storage directory, methodology defaults with the resolved 12 dials, appearance, and about/version.

The persistent shell (every screen): sidebar nav + adapter connection-status dots, top bar with the ⌘K navigation palette (screens + stored reports) and the avatar menu (local profile, Settings, About).

All data flows through a typed ApiClient interface backed by MockApiClient — the same components will talk to the FastAPI backend via the OpenAPI-generated client in the MVP milestone, with zero rewrites.

Scripts

Run inside frontend/:

Command Purpose
pnpm dev Dev server on :3000
pnpm build Production build
pnpm lint ESLint (flat config)
pnpm typecheck tsc --noEmit (strict)
pnpm test Vitest + Testing Library (jsdom)

Repository layout

frontend/   Next.js 15 App Router, TypeScript strict, Tailwind v4, Vitest
.ciagent/   Pipeline state (roadmap, requirements, plans, checkpoints)

Milestone v0.2 (MVP: FastAPI backend, research engine, adapter layer, trust loop) begins only after this prototype is approved.

S
Description
ResearchX — deep-research studio: BYO model/storage/memory, methodology-first, visited-only verified citations
Readme 2.2 MiB
2026-09-30 14:23:14 +00:00
Languages
TypeScript 58.4%
Python 38%
Shell 2.2%
CSS 1.1%
Dockerfile 0.2%
Other 0.1%