coreci-researchx-po 70243eeb8b
ci / backend (uv, Python 3.12: ruff/mypy/pytest) (push) Successful in 31s
ci / frontend (Next.js on pnpm: typecheck/lint/test/build) (push) Successful in 1m35s
ci / backend (uv, Python 3.12: ruff/mypy/pytest) (pull_request) Successful in 31s
ci / frontend (Next.js on pnpm: typecheck/lint/test/build) (pull_request) Successful in 1m35s
fix: count a run completed at the DONE transition, not after it (researchx#28)
The cost counter was incremented by a watcher that awaited the run task, so it
lagged the status flip: the run read as done while /api/config still counted
zero completed runs. The increment now happens in the same step as the
transition to DONE, so any client that observes the run as done also observes
the counter.

Refs researchx#28
2026-10-27 05:18:51 +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%