TreeMap
A free, open-source disk-space visualizer. Squarified treemap, duplicate hunting, disk-full forecasting, and cleanup that only ever moves files to the Trash.
翻譯準備中
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Deep research platform that builds cited reports from trusted sources, then challenges those sources on request.
翻譯準備中
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
Deep research dossier platform — A structured source-gathering, reasoning, and long-form research workflow that preserves the distinction between primary evidence and documented sources, built for rigorous scientific and investigative work.
Not a chatbot. Not a hallucination machine. A disciplined investigation engine with epistemic governance built in.
Mode B: Recommended — Vercel Frontend + Emma Backend (Split Deployment)
bash
chmod +x scripts/setup-postgres.sh
DB_PASSWORD=your_password ./scripts/setup-postgres.sh檢視完整 README ↗Deep research dossier platform — A structured source-gathering, reasoning, and long-form research workflow that preserves the distinction between primary evidence and documented sources, built for rigorous scientific and investigative work.
Not a chatbot. Not a hallucination machine. A disciplined investigation engine with epistemic governance built in.
Model change, 13 Oct 2026 (Brandon). Double-check and the internal challenger (
double_check,internal_challenger, every research kind) now use Kimi K2 Thinking (moonshotai/kimi-k2-thinkingon OpenRouter,moonshotai/Kimi-K2-Thinkingon Hugging Face) instead of Hermes 4 70B. Why: OpenRouter has no host for Hermes 4 70B (endpoints: [], checked 13 Oct 2026) and the Hugging Face account has no credit, so those steps had no usable route. Kimi K2 Thinking runs on OpenRouter first and falls back to the same model on Hugging Face; no other model is used in its place. Hermes 4 70B stays on the allowlist and can still be chosen for one run. Change inbackend/src/config/researchEnsemblePresets.ts; record indocs/RJ-025-same-model-failover.md.
┌─────────────────────────────────────────────────────────────────┐
│ RECOMMENDED TOPOLOGY │
│ │
│ Vercel (frontend) │
│ └── React + Vite build (served via Vercel CDN) │
│ VITE_API_BASE_URL → Emma runtime VM │
│ VITE_SOCKET_URL → Emma runtime VM │
│ VITE_EXPORTS_BASE_URL → Emma runtime VM │
│ │
│ Emma runtime VM │
│ ├── ResearchOne API (Express + Socket.IO) │
│ ├── BullMQ Workers (Ingestion, Embedding, Research, Atlas) │
│ ├── Nginx (API + WebSocket + /exports reverse proxy) │
│ └── /opt/researchone/exports/ (Atlas JSONL files) │
│ │
│ Emma Postgres VM │
│ └── PostgreSQL + pgvector (corpus, chunks, embeddings, │
│ claims, contradictions, reports, discovery audit) │
│ │
│ Emma Redis VM │
│ └── Redis (BullMQ job queues, job state, caching) │
│ │
│ OpenRouter (remote inference — server-side only) │
│ Tiered defaults (V1) in backend/src/config/index.ts (per-role │
│ env overrides). Examples: Kimi K2 Thinking + DeepSeek-R1 │
│ (planning & core reasoning); Claude Sonnet 4.5 + Gemini 2.5 │
│ Pro (reports & sections); GPT-5-mini (structured JSON). │
│ │
│ V2 ensemble (Research One 2) routes critical-path roles │
│ through OpenRouter on verified multi-provider open-weights │
│ reasoners: DeepSeek V3.2 (10+ providers), V3.1 (10+), │
│ R1-0528 (5), Qwen3-235B Thinking (4), Kimi K2 Thinking (3). │
│ Adversarial roles use Dolphin-Mistral-24B-Venice-Edition and │
│ Sao10K L3.3-Euryale-70B. Single-provider Hermes / huihui-ai │
│ HF slugs are allowlisted for user-opt-in only — see │
│ docs/V2_MODEL_SELECTION_CRITERIA.md. │
└─────────────────────────────────────────────────────────────────┘
All services including frontend on the same VM. Not recommended for new deployments.
The frontend assumes same-origin /api and same-origin socket connection.
To use this mode: do not set VITE_API_BASE_URL, VITE_SOCKET_URL, or VITE_EXPORTS_BASE_URL.
established_fact | strong_evidence | testimony | inference | speculation| Stage | Role | Purpose |
|---|---|---|
| 1 | Planner | Decomposes query into sub-questions, retrieval targets, hypothesis, falsification criteria |
| 2 | Discovery | Autonomously identifies and ingests external sources when corpus is sparse |
| 3 | Retriever | Gathers sources from enriched corpus via hybrid vector+FTS search |
| 4 | Retriever Analysis | Evaluates source-corroboration tiers, flags outliers and bridges |
| 5 | Reasoner | Builds structured argument chains, tags all claims by source-corroboration tier |
| 6 | Double-check | Attacks conclusions, finds alternatives, prevents confirmation bias |
| 7 | Synthesizer | Writes the complete long-form research report |
| 8 | Verifier | Epistemic quality gate — ensures citation, contradiction, and tier standards are met |
| 9 | Report save | Stores report, sections, and verification metadata |
| 10 | Epistemic persistence | Extracts and persists claims, contradictions, and section citations |
Revision API endpoints:
POST /api/reports/:id/revisionsGET /api/reports/:id/revisionsGET /api/reports/:id/revisions/:revisionIdRevision pipeline agents/services:
Behavior:
root_report_id, parent_report_id, version_number) and never overwrites finalized reports.revision:progress, revision:completed).Key tables:
Corpus / retrieval
sources — Every external resource ingested (with provenance: imported_via, discovered_by_run_id, discovery_query, etc.)documents — Processed document content (parse_method, extraction_metadata)chunks — Segmented fragments for retrieval (with FTS indexes)embeddings — pgvector vectors for semantic search (HNSW index)entities / entity_mentions — Named entity extractioningestion_artifacts — Optional ingestion audit (hashes, parse warnings)ingestion_audit_log / run_ingestion_state / run_user_overrides / user_ingestion_consent — Dual-pipeline ingestion tracking (migration 023)Research runs / reports
research_runs — Full workflow execution records with model logs and discovery summaryreports + report_sections — Structured long-form research reportsreport_citations — Evidence → section links (with chunk_quote, citation_order, discovery_origin)claims — Discrete factual assertions with evidence tiers (run/report linked)contradictions — Explicit contradiction records (first-class data, run/report linked)atlas_exports — Embedding Atlas export snapshotsdiscovery_events — Audit log for all autonomous discovery activityerror_log — Structured error trackingReport revisions
report_revision_requests — post-publication revision requestsreport_revisions — revision metadata + version linkagereport_revision_sections — before/after section snapshotsreport_revision_diffs — structured diff recordsreport_revision_comments / report_revision_citations — optional review and citation annotationsDossiers / planning (the dossier pass)
research_plans + plan_revisions — structured plan intent and revision historydossier_statistics — epistemic rollup stats per dossierv_dossier — security-invoker view joining runs + plans + stats (canonical dossier read path)account_preferences — per-user account-level settingssaved_orchestration_profiles — user/org-scoped saved orchestration profile presetsAcademic formatting (the formatting-engine pass)
evidence_aliases — stable [E1]-style citation aliases per report/citation pairreport_exports — export job records (format, citation style, status)Users / organisations / auth
users / orgs / org_members — multi-tenant identity (Clerk-style IDs)byok_keys — per-user encrypted Bring Your Own Key entriesBilling / subscriptions / wallet
user_wallets + wallet_ledger — credit wallet and ledgerwallet_holds — credit holds scoped to research runsuser_subscriptions + stripe_webhook_events — Stripe subscription stateuser_tiers + tier_addons — resolved access tier per userreport_monitors + report_monitor_events — Living Reports monitor subscriptions (Work Order T)stripe_customers — Stripe customer recordsbilling_events — structured billing audit logTelemetry / cost
agent_executions + model_pricing — per-LLM-call cost telemetry sidecar (see Rule 25)landing_persona_events — anonymous persona analytics (no user ID)Admin / compliance
admin_actions_log — admin action audit trailretention_events — workspace/report expiry trackinguser_notifications — in-app notification feedMigrations are additive and currently span 001_initial_schema.sql through 043_billing_events.sql in backend/src/db/migrations/.
There are two different places configuration lives. Do not mix them up:
| Where | What goes there |
|---|---|
backend/.env on the Emma VM (and the templates backend/.env.production.example / backend/.env.development.example) | Runtime secrets for the Node API: database, Redis, OpenRouter, JWT_SECRET, CORS_ORIGINS, etc. No EMMA_* keys — the running app never reads those names. |
| GitHub → Settings → Secrets and variables → Actions | Only for the Deploy backend to Emma workflow: EMMA_HOST, EMMA_USER, EMMA_SSH_KEY, etc. These are not copied into backend/.env unless you explicitly use the optional EMMA_WRITE_BACKEND_ENV secret (which writes the whole API env file on the server — still not individual EMMA_SSH_* lines in the template). |
If deploy fails with SSH or permission errors, the fix is in GitHub repository secrets and server SSH authorized_keys for EMMA_USER, not in backend/.env.production.example.
Baseline: copy backend/.env.production.example → backend/.env on the VM (see table below). The fenced block below is a narrative superset (optional integrations + examples); the committed template holds the maintained minimum — merge extra keys from here when you enable a feature.
NODE_ENV=production
PORT=3001
# Database
DATABASE_URL=postgresql://researchone:<password>@<postgres-vm>:5432/researchone
DB_HOST=<postgres-vm>
DB_PORT=5432
DB_NAME=researchone
DB_USER=researchone
DB_PASSWORD=<password>
# Redis — runtime queue uses REDIS_HOST + REDIS_PORT (backend/src/queue/redis.ts)
REDIS_HOST=<redis-vm>
REDIS_PORT=6379
REDIS_URL=redis://<redis-vm>:6379 # optional; not used by ioredis — host/port are authoritative
REDIS_PASSWORD= # set if requirepass is enabled
REDIS_USERNAME= # set if ACL username is enabled
# OpenRouter (server-side only — never in Vercel) — V1 / closed-weights routing
OPENROUTER_API_KEY=
OPENROUTER_BASE_URL=https://openrouter.ai/api/v1
OPENROUTER_DATA_COLLECTION=allow
# Hugging Face Inference Providers (server-side only — never in Vercel) —
# V2 user-opt-in routing for the huihui-ai abliterated line, NousResearch HF
# slugs, and dphn/dolphin-2.9.2-qwen2-72b. NOT required for the V2 defaults,
# which route through OpenRouter. Set this only if admins wire HF-routed
# slugs into a per-run override in the Research One 2 page. Provision a
# "read" token from https://huggingface.co/settings/tokens.
HF_TOKEN=
# Optional Together fallback provider (server-side only). When set, calls to
# HF repo ids that fail with provider_unavailable will be retried against
# Together. Leave blank to disable the provider-level fallback (recommended
# unless you have a vetted Together account that hosts the same uncensored
# weights — see docs/V2_MODEL_SELECTION_CRITERIA.md before enabling).
TOGETHER_API_KEY=
TOGETHER_BASE_URL=https://api.together.xyz/v1
# Security (server-side only — never in Vercel)
JWT_SECRET=
CORS_ORIGINS=https://<your-vercel-project>.vercel.app,https://<your-custom-frontend-domain>
# Clerk authentication (backend runtime)
# Note: backend runtime uses CLERK_SECRET_KEY and CLERK_WEBHOOK_SECRET.
# CLERK_PUBLISHABLE_KEY is included in backend template for ops visibility.
CLERK_PUBLISHABLE_KEY=pk_live_REPLACE
CLERK_SECRET_KEY=sk_live_REPLACE
CLERK_WEBHOOK_SECRET=whsec_REPLACE
ADMIN_USER_IDS=
ADMIN_RUNTIME_TOKEN=
# Embedding
EMBEDDING_DIMENSIONS=1536
EMBEDDING_BATCH_SIZE=20
# Optional model override:
# EMBEDDING_MODEL=openai/text-embedding-3-small
# Ingestion
MAX_CHUNK_SIZE=1000
CHUNK_OVERLAP=200
MAX_FILE_SIZE_MB=50
# Exports — canonical path must match nginx /exports alias
EXPORTS_DIR=/opt/researchone/exports
ATLAS_BACKUP_DIR=
ATLAS_AUTO_EXPORT_ON_EMBEDDING=false
# Admin runtime control
RUNTIME_RESTART_COMMAND=pm2 restart researchone-api
RUNTIME_LOG_OUT=
RUNTIME_LOG_ERR=
# Autonomous discovery
DISCOVERY_ENABLED=true
SEARCH_PROVIDER=tavily
TAVILY_API_KEY=
TAVILY_BASE_URL=https://api.tavily.com/search
SEARCH_PROVIDER_API_KEY=
SEARCH_PROVIDER_BASE_URL=
MAX_DISCOVERY_QUERIES_PER_RUN=5
DISCOVERY_INGEST_TIMEOUT_MS=90000
MAX_EXTERNAL_DISCOVERY_RESULTS=25
MAX_EXTERNAL_INGEST_PER_RUN=10
# With PROVIDER_ROUTING_ENABLED=true, unset query and ingest values default to 12 and 24.
PROVIDER_ROUTING_ENABLED=
# A model checks that every source is about the question, before ingest and after retrieval.
# On unless set to false. Set false only in an emergency.
DISCOVERY_RELEVANCE_GATE_ENABLED=
# Optional scholarly/provider enrichment settings
PARALLEL_API_KEY=
PARALLEL_BASE_URL=https://api.parallel.ai/v1
SCITE_API_KEY=
SCITE_BASE_URL=https://api.scite.ai/v1
OPENALEX_USER_AGENT=ResearchOne/1.0 (mailto:[email protected])
CROSSREF_USER_AGENT=ResearchOne/1.0 (mailto:[email protected])
# Parallel monitor / Living Reports (WO T)
PARALLEL_MONITOR_API_KEY=
PARALLEL_MONITOR_WEBHOOK_SECRET=
# BYOK encryption
BYOK_ENCRYPTION_KEY=
# BYOK_ENCRYPTION_KEY_PREVIOUS=
# Optional featured report publishing
FEATURED_REPORT_GITHUB_TOKEN=
FEATURED_REPORT_GITHUB_OWNER=GooseyPrime
FEATURED_REPORT_GITHUB_REPO=newontology
FEATURED_REPORT_GITHUB_PATH=content/featured-reports/latest.md
FEATURED_REPORT_GITHUB_BRANCH=main
# Optional Nomic Atlas integration
NOMIC_API_KEY=
NOMIC_ATLAS_DATASET_SLUG=intellme
NOMIC_ATLAS_BASE_URL=https://api-atlas.nomic.ai
NOMIC_AUTO_UPLOAD_ON_EXPORT=false
# Optional InTellMe integration
INTELLME_API_KEY=
INTELLME_API_SECRET=
# Off unless INTELLME_API_URL is set; there is no default address.
INTELLME_API_URL=
# Model and fallback overrides are optional and omitted here for brevity.
# See backend/src/config/index.ts for the full list of *_MODEL / *_FALLBACK keys.
This fenced block is an illustrative superset (core keys + optional integrations). For Emma/production, start from backend/.env.production.example, then add any optional keys you need from this section or feature-specific docs — the committed template is the baseline file to copy.
Which .env file is which (do not confuse these):
| File | Role |
|---|---|
backend/.env.example | Local-dev starter scaffold — copy to backend/.env for laptop work; for production use backend/.env.production.example instead |
backend/.env.production.example | Committed template for Emma/production — copy to backend/.env and edit |
backend/.env.development.example | Committed template for local backend dev — copy to backend/.env for laptop work |
backend/.env | Real runtime secrets — gitignored; this is what Node and PM2 use on the VM and locally |
Emma runtime production setup:
cp backend/.env.production.example backend/.env
# edit backend/.env — never commit it
VITE_API_BASE_URL=https://<emma-runtime-vm-domain>
VITE_SOCKET_URL=https://<emma-runtime-vm-domain>
VITE_EXPORTS_BASE_URL=https://<emma-runtime-vm-domain>
VITE_CLERK_PUBLISHABLE_KEY=pk_live_REPLACE
# Optional (currently unused by default checkout flow):
# VITE_STRIPE_PUBLISHABLE_KEY=pk_live_REPLACE
Origin-only (API base URLs): VITE_API_BASE_URL, VITE_SOCKET_URL, and VITE_EXPORTS_BASE_URL must be origins only (scheme + host, no path): correct https://api.example.com, wrong https://api.example.com/api. The client appends /api itself (resolveApiBaseUrl in frontend/src/utils/api.ts). Use the hostname nginx serves on the Emma VM, not the Vercel URL.
Not origins: VITE_CLERK_PUBLISHABLE_KEY stays a Clerk pk_live_... / pk_test_... key, never a URL. Sign-in/up redirect paths are configured in the Clerk Dashboard — VITE_CLERK_SIGN_IN_URL / VITE_CLERK_AFTER_SIGN_IN_URL etc. in frontend/.env.example are for local/reference parity only; frontend/src/main.tsx does not read them at build time.
Redeploy the frontend after changing any embedded VITE_* value.
If your VM only exposes HTTP on port 80 (no TLS / no listener on 443), use http:// in the three API-related VITE_* URLs until TLS is configured. Public https:// smoke tests only work when HTTPS is actually terminated (443).
Diagnosing “404” on research: In the browser Network tab, check the host of POST .../research. If it is your Vercel domain, VITE_API_BASE_URL was missing at build time. If the host is correct but the path is /api/api/..., remove the extra /api or trailing slash from VITE_API_BASE_URL. If research starts but fails later, open “Show error details” on the run and read failure_meta.endpoint: an OpenRouter URL means fix OPENROUTER_BASE_URL on the Emma VM, not Vercel.
Smoke test from your machine (Emma edge): use https:// only if TLS is configured; otherwise http:// on port 80.
curl -sS -o /dev/null -w "%{http_code}\n" "https://<emma-api-host>/api/health"
curl -sS -i -X POST "https://<emma-api-host>/api/research" \
-H "Content-Type: application/json" \
-d '{"query":"smoke test"}'
On the VM, localhost always works for the API process:
curl -sS "http://127.0.0.1:3001/api/health"
Expect 200 on health and 202 on research. On the VM, confirm OPENROUTER_BASE_URL is a base URL only (for example https://openrouter.ai/api/v1), not a full /chat/completions path — see backend/src/config/index.ts.
Windows (PowerShell): use -o NUL instead of -o /dev/null for the health curl line; /dev/null can trigger curl: (23) client returned ERROR on write even when the HTTP status is 200.
Never put these in Vercel: OPENROUTER_API_KEY, JWT_SECRET, DATABASE_URL, DB_PASSWORD, REDIS_PASSWORD
Use the explicit development template for local backend work:
cp backend/.env.development.example backend/.env
chmod +x scripts/setup-postgres.sh
DB_PASSWORD=your_password ./scripts/setup-postgres.sh
chmod +x scripts/setup-redis.sh
./scripts/setup-redis.sh
One-time: clone this repo to /opt/researchone, configure backend/.env, run scripts/setup-runtime.sh for nginx/user/exports.
Canonical app root: /opt/researchone (must match ecosystem.config.js cwd). All PM2 commands that use ecosystem.config.js must be run from that directory, not from backend/:
cd /opt/researchone
Deploy / update (idempotent): runs git fetch + reset to origin/main, full npm ci, build, migrate, PM2 from the ecosystem file, and a localhost health smoke test:
cd /opt/researchone
cp backend/.env.production.example backend/.env # first time only; then edit backend/.env
./scripts/deploy-runtime.sh
After changing only backend/.env (no git pull):
cd /opt/researchone
pm2 restart researchone-api --update-env
# In Vercel dashboard, add environment variables:
# VITE_API_BASE_URL=https://<emma-runtime-vm>
# VITE_SOCKET_URL=https://<emma-runtime-vm>
# VITE_EXPORTS_BASE_URL=https://<emma-runtime-vm>
# VITE_CLERK_PUBLISHABLE_KEY=pk_live_REPLACE
# Deploy via Vercel Git integration or:
cd frontend && npx vercel --prod
If the Vercel project Root Directory is the monorepo root, the root vercel.json applies. If the root is frontend/, use frontend/vercel.json so client-side routes like /research rewrite to index.html.
main push)Merging to main triggers Vercel for the frontend independently. The workflow .github/workflows/deploy-backend-emma.yml SSHs to the Emma VM and runs scripts/deploy-runtime.sh: the VM fetches and resets to origin/main, runs npm ci (full install, including devDependencies required for migrations), npm run build, npm run migrate, npm run bootstrap:application-role (creates application_role when migration 021 could not — requires DATABASE_ADMIN_URL on the VM or via the DATABASE_ADMIN_URL Actions secret; the decoded admin URL is not exported for the rest of the deploy script so PM2 --update-env never inherits it), then starts or reloads PM2 from ecosystem.config.js. The final smoke test requires /api/health HTTP 200 and status not down (no silent green deploy when core checks fail). The backend is not built in Actions and rsynced anymore; the VM always runs the current tree from git.
RLS / application_role: Managed Postgres often runs migrations with a user that cannot CREATE ROLE, so migration 021_rls_setup.sql may complete without creating application_role. Read docs/RUNBOOKS/application-role-bootstrap.md for the privileged bootstrap, verification SQL, and the difference between DATABASE_URL and DATABASE_ADMIN_URL.
Secrets for this workflow can live in either place — not both required:
production → Environment secrets. If you use these, the workflow job must declare environment: production (see .github/workflows/deploy-backend-emma.yml); otherwise secrets.EMMA_SSH_KEY is empty and webfactory/ssh-agent fails with “ssh-private-key argument is empty”.These are not listed in backend/.env.production.example because Actions reads them only at workflow runtime:
| Secret | Required | Description |
|---|---|---|
EMMA_HOST | Yes | SSH hostname or IP of the Emma runtime API VM |
EMMA_USER | Yes | SSH user with write access to the deploy path and permission to run git, npm, and pm2 |
EMMA_SSH_KEY | Yes | Private key (full PEM), including -----BEGIN ... PRIVATE KEY----- and -----END... lines — the same material as your local id_rsa / .pem file, not the .pub public key |
EMMA_DEPLOY_PATH | No | App root on the server; default /opt/researchone (must match ecosystem.config.js cwd) |
EMMA_PORT | No | SSH port on the VM; default 22. Set if sshd listens elsewhere. Regenerate EMMA_KNOWN_HOSTS with ssh-keyscan -p <port> -H <host> when the port is not 22. |
EMMA_KNOWN_HOSTS | No | One or more lines from ssh-keyscan for EMMA_HOST (recommended) |
EMMA_WRITE_BACKEND_ENV | No | Opt-in: multiline contents written to backend/.env on the VM before deploy (only if you choose CI-managed secrets) |
DATABASE_ADMIN_URL | No | Opt-in: privileged Postgres connection string (superuser or CREATEROLE + DDL rights). If set, the workflow passes it to the VM as DATABASE_ADMIN_URL_B64 (base64); deploy-runtime.sh decodes into a subshell-only env for bootstrap, then unsets it before PM2 (--update-env). GitHub masks the secret in logs. Alternatively, put DATABASE_ADMIN_URL only in backend/.env on the server and omit this secret. |
If EMMA_SSH_KEY “looks right” but SSH still fails: confirm the matching public key is in EMMA_USER’s ~/.ssh/authorized_keys on the VM; confirm the secret is the private key for that pair; paste the PEM with no extra quotes or Key:: prefixes; for ed25519 use BEGIN OPENSSH PRIVATE KEY PEM as output by ssh-keygen. Workflows triggered from fork PRs do not receive repository secrets — use workflow_dispatch on main or merge to main on this repo.
Emma VM: must be a git clone of this repo with origin reachable; backend/.env must exist on the server unless you use EMMA_WRITE_BACKEND_ENV.
If the workflow fails with Connection timed out to EMMA_HOST port 22: GitHub-hosted runners run on the public internet. The VM must have a routable EMMA_HOST (not a private LAN IP), sshd listening on EMMA_PORT (default 22), and your cloud firewall / security group must allow inbound TCP from the internet (or from GitHub Actions IP ranges if you restrict sources). Your laptop working while Actions times out usually means the runner’s IP is blocked.
Manual run: Actions → “Deploy backend to Emma” → Run workflow.
After pulling new backend migrations, run npm run migrate on Emma so tables/columns exist for runtime model overrides (004_runtime_model_overrides.sql) and research run progress polling (005_research_run_progress_columns.sql).
Model routing (UI): Sidebar → Models (/models) — requires admin token; saves overrides in Postgres (not .env). Same allowlist as reasoningModelPolicy.
PM2 logs in System status: If runtime logs return 404, set RUNTIME_LOG_OUT and RUNTIME_LOG_ERR on the server to paths from pm2 describe researchone-api (the API tries several default paths automatically).
docker-compose up postgres redis
# Backend
cd backend
cp .env.development.example .env # local dev backend defaults
npm run dev
# Frontend (separate terminal)
cd frontend
cp .env.example .env.local # leave VITE_* blank for same-origin mode
npm run dev
ResearchOne/
├── backend/
│ ├── .env.production.example # Emma runtime production template (copy → .env)
│ ├── .env.development.example # Local backend development template (copy → .env)
│ ├── .env.example # Local-dev starter scaffold (copy → .env for laptop work)
│ ├── src/
│ │ ├── api/
│ │ │ ├── app.ts # Express application
│ │ │ └── routes/ # All API routes (admin, atlas, auth, billing, byok,
│ │ │ # corpus, dossiers, graph, health, ingestion,
│ │ │ # landing, monitors, notifications, reports,
│ │ │ # research, runs, sources)
│ │ ├── config/ # Configuration (all env vars)
│ │ ├── db/
│ │ │ ├── migrations/
│ │ │ │ ├── 001_initial_schema.sql
│ │ │ │ └── … through 043_billing_events.sql
│ │ │ ├── migrate.ts # Migration runner
│ │ │ └── pool.ts # PostgreSQL connection pool (RLS context)
│ │ ├── jobs/ # Cron jobs (retention cleanup, tier reset)
│ │ ├── queue/
│ │ │ ├── queues.ts # BullMQ queue definitions
│ │ │ ├── redis.ts # Redis connection (with password support)
│ │ │ └── workers.ts # BullMQ workers
│ │ └── services/
│ │ ├── agents/ # Agent framework utilities
│ │ ├── billing/ # Stripe billing, subscriptions, wallet
│ │ ├── byok/ # Bring-Your-Own-Key encryption
│ │ ├── discovery/ # Autonomous external research discovery
│ │ │ ├── discoveryOrchestrator.ts
│ │ │ ├── providerTypes.ts
│ │ │ └── providers/ # Search provider abstraction
│ │ ├── embedding/ # Embedding generation + Atlas export
│ │ ├── formatting/ # Academic formatting engine (Pandoc/CSL/LaTeX)
│ │ ├── ingestion/ # Source ingestion (PDF, markdown, txt, URL)
│ │ │ ├── pdfExtractor.ts
│ │ │ ├── markdownNormalizer.ts
│ │ │ └── ingestionService.ts
│ │ ├── monitoring/ # Living Reports / report monitors
│ │ ├── notifications/ # In-app notification feed
│ │ ├── openrouter/ # Model routing + prompts (all roles w/ fallbacks)
│ │ ├── planning/ # Dossier plan orchestration (the dossier pass)
│ │ ├── reasoning/ # Research orchestrator + epistemic persistence
│ │ │ ├── researchOrchestrator.ts
│ │ │ ├── claimExtractor.ts
│ │ │ ├── contradictionExtractor.ts
│ │ │ └── citationMapper.ts
│ │ ├── research/ # Research-run lifecycle helpers
│ │ ├── retention/ # Workspace / report retention policy
│ │ ├── retrieval/ # Hybrid vector + FTS retrieval
│ │ ├── telemetry/ # Cost sidecar (agent_executions)
│ │ ├── tier/ # Tier access checks and reset
│ │ └── users/ # User / org helpers
├── frontend/
│ ├── .env.example # Vercel env template
│ └── src/
│ ├── pages/ # All UI pages
│ ├── components/ # Reusable UI components
│ ├── store/ # Zustand global state
│ └── utils/
│ ├── api.ts # Configurable baseURL (VITE_API_BASE_URL)
│ └── socket.ts # Configurable socket URL (VITE_SOCKET_URL)
├── scripts/ # Infrastructure setup scripts
├── docker-compose.yml
└── ecosystem.config.js # PM2 config
Research direction and paper-building are restricted to reasoning-class models only, including all fallbacks.
The deployment allowlist lives in reasoningModelPolicy.ts and is split into a V1 / closed-weights side (OpenRouter slugs, used by the V1 ensemble) and a V2 / uncensored open-weights side (HF repo ids, used by the V2 ensemble). V2 has its own binding selection criteria — see docs/V2_MODEL_SELECTION_CRITERIA.md and the ResearchOne PolicyOne epistemic preamble (RLHF refusal-aligned primaries are forbidden in V2 because they cause drift back toward consensus-debunking and silent omission of anomalous findings, which the policy explicitly prohibits).
Confirm V1 OpenRouter IDs still exist in OpenRouter’s model list or GET https://openrouter.ai/api/v1/models — stale slugs return HTTP 404 from /chat/completions. For V2 defaults, also require a successful runtime /chat/completions probe (same envelope as production); catalog presence alone can still yield No allowed providers are available under account provider filters. V2 HF repo ids are validated against the HF Inference Providers catalog.
anthropic/claude-3.5-haikuanthropic/claude-3.7-sonnetanthropic/claude-sonnet-4anthropic/claude-sonnet-4.5deepseek/deepseek-chatdeepseek/deepseek-r1deepseek/deepseek-v3.2google/gemini-2.5-flashgoogle/gemini-2.5-prometa-llama/llama-3.3-70b-instructmistralai/mistral-small-3.2-24b-instructmoonshotai/kimi-k2-thinkingopenai/gpt-5-miniopenai/o1openai/o3openai/o3-miniqwen/qwen3-235b-a22bV2 default primaries are split into two categories:
Critical-path roles (planner / reasoner / synthesizer / utility / verifier) — must have ≥ 2 live OpenRouter upstreams. Verified 2026-04-28-PM:
deepseek/deepseek-v3.2 — 10+ providers (Baidu, SiliconFlow, DeepInfra, AtlasCloud, Novita, Chutes, Parasail, Friendli, Google, Alibaba). Default planner / synthesizer / utility across all objectives.deepseek/deepseek-chat-v3.1 — 10+ providers. Utility / synthesis fallback.deepseek/deepseek-r1-0528 — 5 providers (DeepInfra, SiliconFlow, AtlasCloud, Novita, Together). Default reasoner / change_planner.qwen/qwen3-235b-a22b-thinking-2507 — 4 providers (Alibaba, DeepInfra, AtlasCloud, Novita). Reasoner / change_planner fallback.moonshotai/kimi-k2-thinking — 3 providers (Novita, Google, AtlasCloud). Planner fallback / novel-application primary.Adversarial roles (double-check / internal_challenger) — low-refusal Hermes line on OpenRouter, chosen after Venice Dolphin + Euryale slugs failed runtime /chat/completions under typical provider policy despite appearing in the catalog (2026-05-10). Listing on GET /api/v1/models is not sufficient — defaults must pass the same smoke probe as startup preflight (openrouterPreflight.ts). Operators can verify slugs with npm run probe:openrouter-models (backend dir).
moonshotai/kimi-k2-thinking — default for both adversarial roles since 13 Oct 2026 (see the note at the top).nousresearch/hermes-4-70b — the default until 13 Oct 2026; allowlisted, can be chosen for one run. OpenRouter lists no host for it.nousresearch/hermes-3-llama-3.1-70b — allowlisted second choice; never used as a backup (RJ-025).Experimental opt-in only (not defaults): cognitivecomputations/dolphin-mistral-24b-venice-edition:free, sao10k/l3.3-euryale-70b — allowlisted for per-run overrides.
Environment: never Bash-source backend/.env in shell scripts; use dotenv (src/bootstrap/loadEnv.ts) or npm scripts that load it safely.
V2 USER-OPT-IN HF Inference allowlist — single-provider on HF Inference (mostly featherless-ai-only). Admins can wire these in via per-run overrides on the Research One 2 page when HF routing is acceptable. The 2026-04-28 outage demonstrated they are not safe as defaults.
huihui-ai/DeepSeek-R1-Distill-Llama-70B-abliteratedhuihui-ai/Llama-3.3-70B-Instruct-abliteratedhuihui-ai/Qwen2.5-72B-Instruct-abliteratedNousResearch/DeepHermes-3-Llama-3-8B-PreviewNousResearch/Hermes-3-Llama-3.1-70BDavidAU/Llama-3.2-8X3B-MOE-Dark-Champion-Instruct-uncensored-abliterated-18.4Bdphn/dolphin-2.9.2-qwen2-72bV2 USER-OPT-IN FALLBACK ONLY — these RLHF-aligned slugs remain allowlisted so admins / users can wire them in via per-run overrides if a primary is unreachable. They are NOT used by any V2 default preset and never fire silently. If you enable per-role fallback to one of these, the live trace records usedFallback=true with the model id so you can tell the report was generated through a refusal-aligned model.
deepseek-ai/DeepSeek-R1-Distill-Llama-70Bmeta-llama/Llama-3.3-70B-InstructQwen/Qwen2.5-14B-InstructQwen/Qwen2.5-32B-InstructQwen/Qwen2.5-72B-InstructQwen/QwQ-32B-PreviewRole separation for report generation now uses:
Revision roles also enforce reasoning-only routing:
All prompts inject a shared reasoning-first epistemic preamble:
When a research run starts, a discovery planner stage evaluates whether external sources are needed. If yes:
MAX_EXTERNAL_INGEST_PER_RUN)discovery_events for full auditabilityRecommended production setup:
DISCOVERY_ENABLED=trueSEARCH_PROVIDER=tavilyTAVILY_API_KEY=...OPENROUTER_API_KEY=...OPENROUTER_BASE_URL=https://openrouter.ai/api/v1Optional/legacy alternatives:
SEARCH_PROVIDER=brave (legacy optional provider; requires SEARCH_PROVIDER_API_KEY)SEARCH_PROVIDER=generic (legacy optional provider; requires SEARCH_PROVIDER_BASE_URL)SEARCH_PROVIDER=cascade (optional architecture path; not the recommended default)| Type | Route | Notes |
|---|---|---|
| URL | POST /api/ingestion/url | HTML extraction with boilerplate removal, canonical URL, meta description |
| Plain text | POST /api/ingestion/text | Direct text with title |
| File upload (.txt) | POST /api/ingestion/file | UTF-8 text |
| File upload (.md) | POST /api/ingestion/file | Markdown → clean text with structure preservation |
| File upload (.pdf) | POST /api/ingestion/file | PDF → extracted text via pdf-parse |
All ingestion paths preserve provenance metadata: imported_via, discovered_by_run_id, discovery_query, source_rank, fetch_method, original_mime_type, original_filename, canonical_url, retrieval_timestamp.
/api/atlas/export or the Atlas UI page.jsonl file from /exports/ (or via VITE_EXPORTS_BASE_URL in Vercel mode)dense_cluster_candidate → consensus; outlier_candidate → leads; bridge_candidate → overlooked connectionsAtlas points now include: source_type, imported_via, discovered_by_run_id, discovery_query, source_rank, evidence_tier, cluster_hint.
See LICENSE file.
EMMA_PUBLIC_HEALTH_URL | No | Opt-in: full URL for an extra curl after deploy (use http:// or https:// to match your TLS setup) |