Codex 支持尚未进入 PyPI 正式版,需用 pip install git+https://github.com/jordan-gibbs/hyperresearch 从 GitHub 安装;Codex 默认禁止写文件和联网,须用 --sandbox workspace-write -c sandbox_workspace_write.network_access=true 启动;Codex 无浏览器通道,遇登录墙或反爬的来源会留在升级队列中
hyperresearch
jordan-gibbsMIT活跃维护把 Claude Code 或 Codex 变成深度研究智能体,自动采集、检索并综合网页资料,沉淀成可持续积累、可搜索的持久化 Wiki。
Convert Claude Code or Codex into the most intelligent Deep Research Agent. Collect, search, and synthesize web research into a persistent, searchable wiki that builds on itself. Hosted API + MCP: hyperresearch.ai
cd your-project
pip install hyperresearch
hyperresearch installREADME 未说明硬件要求;运行依赖 Python 3.11–3.14,研究过程需文件写入与网络访问
把 Claude Code 或 Codex 变成深度研究代理,产出带引用审计、可复用来源库的研究报告
把 Claude Code 或 Codex 变成深度研究智能体,自动采集、检索并综合网页资料,沉淀成可持续积累、可搜索的持久化 Wiki。
核心能力
- 16 步分层流水线,从拆解问题到成稿逐阶段执行
- 每条引用发布前由怀疑式核查器验证是否支撑原句
- 多源学术检索按 DOI 与标题去重,覆盖论文、临床试验与 SEC 文件
- 所有来源存入可检索的 markdown+SQLite 库供后续会话复用
- 崩溃的运行凭 manifest 从断点步骤恢复
容易踩的坑
- v0.13.0最新正式版2026-10-27 · 2026-10-27 21:19 UTC
- Step prompts agree with each other (#102). Settles the contract conflicts listed in the issue: the no-re-synthesis invariant names the ship gate's compression pass as its one exception; width-sweep fetchers take no new topic searches but still chase the primary sources their batch cites; step 7 has a documented path for fewer than the target tensions when step 4 justified zero loci; a failed critic is re-spawned once and otherwise leaves an empty
critic_failedfindings file, since the ship gate checks all four exist; the step 11 outline leaves out Opinionated Synthesis forshortreports; the step 1 example no longer shows a wrapper requirement in the decomposition; the readability recommender writes a JSON object, matching its schema; the polish auditor receiveswrapper_contract_pathso it knows whether to keep YAML frontmatter; step 16 hands off to the ship gate instead of declaring the run done; the one-chapter case in step 1.5 is described as an escape hatch; and the cite-check Goal states that non-numeric citations are sampled. - The pipeline runs on the OpenAI Codex CLI.
hyperresearch install . --target codexinstalls the entry skill at.agents/skills/hyperresearch/, invoked as$hyperresearch <query>, along with the 18 step procedures as plain files under.hyperresearch/codex/steps/, the subagent roster as custom agents in.codex/agents/*.toml, a Stop hook in.codex/hooks.json, and anAGENTS.mdblock. The step procedures are plain files because Codex caps the skill listing and has no skill-to-skill invocation.--target allinstalls both platforms.--global --target codexwrites the skill to~/.agents/skills/and the agents to~/.codex/agents/.--target claudeis the default and installs the same layout as before. Differences on Codex: there is no browser lane, so blocked fetches stay queued and are listed for the user; the Read+Edit tool locks are instructions rather than enforcement; and the Stop hook (hyperresearch run stop-gate) blocks the session from ending mid-pipeline. The Stop hook exists because an earlier Codex attempt answered inline and never touched the vault. Codex's sandbox defaults to read-only with no network, so a session needs--sandbox workspace-write -c sandbox_workspace_write.network_access=true. hyperresearch documents these flags and never writes to Codex's config. - The repo is a Codex plugin marketplace too.
.codex-plugin/plugin.jsonand.agents/plugins/marketplace.jsonpublish the samedeep-researchbootstrap skill as the Claude Code plugin:codex plugin marketplace add jordan-gibbs/hyperresearch, thencodex plugin add hyperresearch@hyperresearch. The skill no longer assumes Claude Code. On Codex it runsinstall --target codexand then reads the entry skill directly, because Codex discovers skills when a session starts. It gainslicenseandcompatibilityfrontmatter and anagents/openai.yaml. Codex namespaces plugin skills, so from the plugin it is$hyperresearch:deep-research; installed standalone withnpx skills add jordan-gibbs/hyperresearch -a codex(to.agents/skills/deep-research/) it is$deep-research. Theopenai.yamlstarter prompt names the skill in words rather than by a$mention that would only match one of those. The README now leads with Claude Code and Codex install paths side by side. run resumefollows the tier step 1 declared. A run is initialized with the installed gear's step list, and step 1 can reclassify it (usually tolight) inprompt-decomposition.json. The ship gate already honoured that tier;resume_positiondid not, so a light-tier run that finished step 2 was told to resume at step 3, a step its tier skips.run resume,run statusand the Codex Stop gate now use the declared tier's steps. Found during the first live Codex run.- The SSRF gate resolves the name httpx connects to (#161).
check_urllooked up the hostname as urlparse returns it, andgetaddrinfoencodes
- Step prompts agree with each other (#102). Settles the contract conflicts listed in the issue: the no-re-synthesis invariant names the ship gate's compression pass as its one exception; width-sweep fetchers take no new topic searches but still chase the primary sources their batch cites; step 7 has a documented path for fewer than the target tensions when step 4 justified zero loci; a failed critic is re-spawned once and otherwise leaves an empty
- v0.12.02026-09-24 · 2026-09-24 14:37 UTC
查看更新说明
Scholarly search filters, a Serply web provider, and the repo as a Claude Code plugin (
/plugin marketplace add jordan-gibbs/hyperresearch).Behaviour change: crawl4ai's headless browser now verifies TLS certificates. A bad certificate raises
CertVerificationError;[fetch] browser_verify_tls = falseopts out.Migration: the v13 migration makes
is_retractednullable (unknown vs. checked) and runs on first open.Security: IPv4-mapped IPv6 classified by its IPv4; run tags and note ids confined to the vault; OA URLs through the SSRF gate.
Also: Python 3.14, a PDF lane for the builtin provider, fence-length-aware code stripping, and an OpenAlex outage no longer erases a known retraction. Full list in CHANGELOG.md.
- v0.11.12026-09-11 · 2026-09-11 21:15 UTC
查看更新说明
Seven fixes from the backlog sweep
- Markdown links no longer mint stub notes (#93, reported by @ThiagoMafra-Integrare).
[[Label]](https://…)— everywhere on GitHub READMEs, awesome-lists and Wikipedia-shaped pages — parsed as a wikilink, andrepair --stub(default on, and mandated after every session) turned each one into a real note that then topped_most-linkedand inflated PageRank.WIKI_LINK_REnow refuses a]]immediately followed by(; the hygiene filter also rejects unsubstituted{…}placeholders and unbalanced brackets. Resolver-minted stubs are excluded from both rankers and have their stale centrality zeroed, so vaults polluted before this fix recover on the nextgraph rank. The stub marker is centralized so the minting sites and the filter cannot drift. claims ingestfinds the claims (#69, reported by @fduple). The default scan read only the legacyresearch/temp/, while every producer and consumer had moved toresearch/runs/<tag>/temp/— so the claims table was empty in every real run andclaims matrix/targetswere dead on arrival. The default now scans both;--tagnarrows to the run. A zero-file default scan prints a hint instead of a bare zero.- A Semantic Scholar rate limit is reported as a rate limit (#70, reported by @fduple). A 429 was folded into "No metadata found" — an affirmatively wrong diagnosis. 429s now retry three times with backoff (honouring
Retry-After), and an exhausted budget surfaces asrate_limitedinsources scoreoutput rather thanmissing. Nothing is cached for a throttle, so the next run retries. OptionalS2_API_KEYsupport, scoped tosemanticscholar.orghosts only — the fetch helper is shared with Unpaywall and Europe PMC, and an unscoped header would have shipped the key to them. run resumenames a skill that exists, chapters reach the manifest, step 8 keeps its preflight gaps (#100, from @darlingm's contract audit in #88).resumeprintedhyperresearch-2for a skill namedhyperresearch-2-width-sweep, and CLAUDE.md advertisesresumeas the recovery path — the slug now comes from the installer's own step table.set_chapter()had zero callers; it is gone, and thechapter-planevent the partition skill already emits now registers the chapter, so a resumed dissertation reports what is actually pending. Step 8's subagent wrote to the same file the preflight had just written; it gets its own output and a merge step, and gap records carry theidthe dispatch already referenced.- Every pipeline constant is authored once (#101, from @darlingm's contract audit in #88).
citation_density_minsat unread on the profile while two gates hardcoded their own number; the draft orchestrator hardcoded word targets the synthesizer templated, so onpremierthe two halves of a run were 60% apart; step 4 templatedloci_analystsand then said "both" and wroteloci-a.json/loci-b.json. A new test asserts everyProfilefield is read somewhere outsideprofiles.py— and it found eight more dead fields (comparisons_tensions,source_tensions,tension_survey,tension_full_reads,corpus_critic_fetchers,citation_totals,utility_scoring,vault_check_interval_s), all now wired into the prose that had been hardcoding them.char_targets_no_word_boundaryis authored per gear at the 3:1 ratio the profile already used, which moved full's argumentative range from 20000–25000 to 15000–30000 — the old span was 1.25× against a 2× word span. - Citation density is per 1000 effective words, not per 1000 characters (#76). The floor meant something roughly 3× stricter for CJK than for English. The denominator reuses #64's boundary detection: whitespace tokens where they exist, characters ÷
chars_per_word_no_word_boundary(3.0) where they don't. The floor is re-derived ascitation_density_min = 9.0per 1000 words, which is what 1.5 per 1000 characters worked out to for English prose — English verdict
- Markdown links no longer mint stub notes (#93, reported by @ThiagoMafra-Integrare).
- v0.11.02026-09-11 · 2026-09-11 18:17 UTC
查看更新说明
SSRF gate + size caps for fetches (builtin, crawl4ai entry points, PDF and image downloads)
- The builtin provider, the crawl4ai entry points, and PDF and image downloads now go through an SSRF gate (
web/safe_http.py): http/https only; hostnames resolving to private, loopback, link-local, multicast, reserved, CGNAT (RFC 6598), or unspecified addresses are refused (cloud metadata, RFC1918,[::1],100.64.0.0/10, …). Not covered: the fixed-host API calls incore/embed.pyandcore/scholar.py, which take no attacker-influenced URLs. On thesafe_getpaths (builtin provider, PDF and image downloads) redirects are followed manually and every hop is revalidated. The browser lanes (crawl4aifetch(),fetch_many(), and the visible-window path) are gated at entry AND re-checked on the URL the browser actually landed on — the browser follows redirects internally, so the entry check alone cannot vouch for the destination. A post-hoc recheck cannot stop the request that already fired (blind SSRF survives it), but it keeps private-network content out of the vault; the same-host case skips the extra DNS lookup. Refused URLs in a batch are logged and skipped, not fatal. The hostname check is best-effort against DNS rebinding (httpx re-resolves at connect time); the residual window is documented in the module docstring. [fetch] allow_private_hosts— escape hatch for self-hosted mirrors and intranet sources: hostnames (exact, case-insensitive) or CIDRs that may be fetched despite resolving to private space. Empty by default; consulted bycheck_urleverywhere, including redirect hops and the final-URL recheck. A malformed CIDR entry errors loudly instead of being silently ignored.- Response-size caps, streamed and enforced mid-body so a lying or chunked server cannot exhaust memory. Configurable via new
[fetch]settingsmax_html_bytes(10 MiB),max_pdf_bytes(25 MiB),max_image_bytes(2 MiB). A gate refusal on an image download is printed, not silently swallowed. - No unverified-TLS retry. A certificate failure on a PDF fetch is a refusal that names the existing
pdf_verify_tls = falseopt-out — never an automatic verify-off retry, which a MITM could force with a bad cert. The refusal is its own exception type (CertVerificationError), and a cert-refused PDF is never handed to the browser fallback lane: that lane runs with TLS errors ignored, so "falling back" there would be the automatic unverified retry by another name. In a batch it is a loud skip instead.
Scholarly discovery: eight sources through one client layer
Academic discovery used to be four URL templates rendered into the agent's instructions by
core/agent_docs.py, which the model was trusted to assemble and call by hand. No retry, no rate limiting, no dedup, no offline tests — and one of those templates shipped[email protected], a shared placeholder on every install, which is exactly the anti-pattern the open-access resolver refuses to commit for Unpaywall. It is now a real package.hpr scholar searchandhpr scholar sources. One query hits every configured provider, merges records that are the same work, and returns one list.sourceslists what is wired, what each covers, and why anything is unavailable — so a user is never guessing which source to reach for.- Dedup is by DOI first, then normalized title within ±1 year. The year tolerance is deliberate: providers disagree systematically about online-first versus print year for the same article. Two different DOIs never merge regardless of title, which is what stops four 2025 reprints of a famous paper from collapsing into one record. A work confirmed by several providers carries them in
also_in, with the highest citation count and the longest abstract. --limitis per provider, not a cap on the merged list. A post-merge cap would show only the first provider's records at small limits and make every other source look emp
- The builtin provider, the crawl4ai entry points, and PDF and image downloads now go through an SSRF gate (
- v0.10.12026-09-11 · 2026-09-11 16:03 UTC
查看更新说明
A maintenance release. Everything here is a contributed fix, and two of them unblock users who could not ship a run at all.
-
The
length-in-rangeverify gate no longer measures CJK reports with a Latin-script ruler (#71, fixed by @tetra4rnav in #64).verify_runcounted whitespace-separated tokens, which in Japanese or Chinese counts almost nothing — a correctly-sized report measured roughly 20x short andrun finishhard-blocked it, with no honest way past the gate. Length is now measured in characters when whitespace doesn't segment the text, against a newchar_targets_no_word_boundaryprofile field. Detection is by average token length rather than Unicode range, which matters: Hangul is space-delimited, and a range-based check would have broken Korean while fixing Japanese. This shipped tomainthree days after the 0.10.0 tag and has been sitting unreleased since. -
hpr serveno longer hangs on an idle browser connection (#87, reported by @muppavv, fixed by @maximilliangrand in #96). The viewer ran a single-threadedHTTPServerwhose handler set no read timeout, so one socket that connected and sent nothing starved every other client — and Chrome opens exactly such a preconnect socket, which meant the first page load with--opencould poison the server. The symptom was indistinguishable from a hang: no error, no CPU. NowThreadingHTTPServerwith a handler read timeout. The shared SQLite connection that made threading unsafe was correctly retired at the same time, rather than papered over with a lock. -
An invalid
--statusis rejected instead of silently corrupting a note (@MarceloSenai in #89).NoteMetahad novalidate_assignment, sonote update --status evergreeenwrote the typo straight to frontmatter. The note then failed validation on the next sync, dropped out of the index, andnote listkept serving the stale row — every later edit to that note going unindexed too. The valid set is read from theNoteStatusenum rather than a hand-maintained list, so it can't drift. -
"Purchase this article" is recognised as a paywall (@MarceloSenai in #91). The phrase list had "buy this article" and "purchase pdf" but not this one, so those interstitials passed as full text and open-access recovery never ran — the note kept an abstract while the report cited it as though the paper had been read. The gate's own comment used this exact phrase as its worked example.
-
The registered PreToolUse hook command quotes the script path (@dajiaohuang in #98).
installwrotenode <path>into.claude/settings.jsonunquoted, and a hook command runs through a shell — so a project directory containing a space split the path there and node was handed a truncated script, making the hook exit 1 on everyGlob,Grep,WebSearchandWebFetchcall. Paths with spaces are ordinary (a Windows user directory, anything underMy Documents). Installs written before this change keep the old entry, because the installer treats any existing hyperresearch hook as already installed; removing that entry and re-runninginstallpicks up the fix.
-
用户点评
登录用户的真实使用记录,可按版本和硬件筛选还没有人点评。第一个说出真实体验的人最有价值。
Hyperresearch turns Claude Code into a deep research agent, and it's #1 on the DRACO deep research benchmark, ahead of Claude Research, ChatGPT, Gemini and Perplexity. It runs in OpenAI Codex too. A tier-adaptive 16-step pipeline takes one prompt and produces an adversarially-audited report with full source provenance. Every source it reads lands in a persistent, searchable vault, so each session starts smarter than the last.
Don't want to run it locally? Hyperresearch is the hosted version: the same pipeline, with no Claude Code or Codex install needed.
[!NOTE] New: hyperresearch runs on OpenAI Codex. One command installs the full pipeline for Codex: entry skill, step procedures, the subagent roster as Codex custom agents, and a Stop hook that keeps Codex from skipping steps. Same vault, same ship gate as on Claude Code.
pip install hyperresearch && hyperresearch install . --target codex codex --sandbox workspace-write -c sandbox_workspace_write.network_access=true # then: $hyperresearch <question>Codex support ships in the next PyPI release; until then install from GitHub with
pip install git+https://github.com/jordan-gibbs/hyperresearch. Details and what differs on Codex: Codex.
See a sample report
Read a full report before you install anything. These are unedited Deep runs from the hosted version, and you don't need to log in:
- Toast vs Square vs Clover: a restaurant POS competitor analysis, built mostly from SEC filings (241 sources)
- Buying a $2M HVAC business: multiples, SBA loans and diligence (213 sources)
- Who is winning AI coding agents, October 2026 (259 sources)
These are the same kind of Deep runs that put Hyperresearch at #1 on DRACO. Method and per-task scores are on the benchmark page.
Why it wins
- 250+ sources in a single run. The
premierscale profile targets 100–130 in the width sweep alone; citation chasing and gap-fill fetches more than double what actually lands in the corpus. - Every citation is verified before the report ships. A skeptical cite-checker audits whether each cited source actually supports its sentence. Hallucinated quotes and unacknowledged retractions are hard blocks at the gate.
- Syndication doesn't count as consensus. An independence audit clusters derivative copies, so five reprints of one press release argue with the weight of one source.
- Adversarial by construction. Four critics attack every draft in parallel, and a tool-locked patcher can only apply surgical edits. It physically cannot rewrite the report.
- Eight scholarly sources, one query.
hpr scholar searchhits OpenAlex, Crossref, CORE, DOAB, ClinicalTrials.gov, SEC EDGAR and FRED through one client layer and returns a single list deduplicated by DOI and title. Books, trials and filings come back alongside papers, each tagged so the pipeline knows which is which. The humanities and social sciences are covered on purpose, not as an afterthought. - Paywalled papers get read, not skimmed. A closed paper normally enters a vault as a 1,500-character abstract that the report then cites as though it had been read. Hyperresearch asks Unpaywall, Europe PMC and CORE for a legal open-access copy and stores the full text instead, even when the publisher blocks the fetch outright. Every substitution is disclosed in the note, the frontmatter, and the CLI output.
- Nothing is thrown away. Every source lands in a searchable markdown-plus-SQLite vault that your next session reuses before it fetches anything new.
- Crashed runs resume. Each run keeps a manifest;
run resumepicks up at the exact step where it died. - Scales from 30 minutes to a dissertation. Bounded queries auto-route to a 5-step fast path. Opt-in dissertation runs (experimental) write 25K–80K words across chapters, from 300–450 sources.
Browse the vault by DOI, venue, citation count, retraction status, or retrieved manuscript version with scholarly metadata filters.
Install
Works in Claude Code and OpenAI Codex: same pipeline, same vault.
cd your-project
pip install hyperresearch
hyperresearch install # Claude Code, then: /hyperresearch <anything>
hyperresearch install . --target codex # OpenAI Codex, then: $hyperresearch <anything>
--target all installs both side by side. Codex sessions need write access and network, see below.
Prefer a plugin or a single skill? Each route below installs one bootstrap skill, deep-research, that sets the pipeline up in the current project on first use. It still needs pip install hyperresearch.
| Claude Code | OpenAI Codex | |
|---|---|---|
| Plugin | /plugin marketplace add jordan-gibbs/hyperresearch/plugin install hyperresearch@hyperresearch | codex plugin marketplace add jordan-gibbs/hyperresearchcodex plugin add hyperresearch@hyperresearch |
| Skill (skills.sh) | npx skills add jordan-gibbs/hyperresearch -a claude-code | npx skills add jordan-gibbs/hyperresearch -a codex |
| Invoke | /hyperresearch:deep-research <question> (plugin)/deep-research <question> (skill) | $hyperresearch:deep-research <question> (plugin)$deep-research <question> (skill) |
Or just ask for deep research in plain words; the skill triggers on its description.
Python 3.11–3.14.
Power users:
hyperresearch install --globalmakes/hyperresearchreachable from every Claude Code session anywhere, at the cost of ~15 lines in every session's system reminder. Per-project install (above) keeps unrelated CC sessions clean.
The bootstrap skill
The repo is a Claude Code plugin marketplace, a Codex plugin marketplace, and a skills.sh source, and all three ship the same skill, deep-research. It checks for the hyperresearch CLI, runs hyperresearch install for the agent it is running in (--target codex under Codex), and hands off to the pipeline. The pipeline itself still comes from the Python package.
If Claude Code does not pick up the newly installed skills and subagents, restart it in the same directory and run /hyperresearch <question>. Codex discovers skills at session start, so on first use the bootstrap reads the freshly installed entry skill directly; later sessions can start with $hyperresearch <question>.
Codex
The same pipeline runs on the OpenAI Codex CLI.
cd your-project
pip install hyperresearch && hyperresearch install . --target codex
This installs the entry skill at .agents/skills/hyperresearch/, the step procedures under .hyperresearch/codex/steps/, the subagents as custom agents in .codex/agents/, a Stop hook in .codex/hooks.json, and a short block in AGENTS.md. --target all installs the Claude Code and Codex versions side by side. --global --target codex puts the entry skill in ~/.agents/skills/ and the agents in ~/.codex/agents/.
Research needs to write files and reach the network, and Codex allows neither by default. Start the session with both enabled, then invoke the skill:
codex --sandbox workspace-write -c sandbox_workspace_write.network_access=true
# then, in the session:
$hyperresearch <anything>
# non-interactive:
codex exec --sandbox workspace-write -c sandbox_workspace_write.network_access=true \
--dangerously-bypass-hook-trust "\$hyperresearch <anything>"
You pass these as flags; hyperresearch never edits your Codex config. codex exec cannot ask you to trust the project's hooks, so without --dangerously-bypass-hook-trust the Stop hook below does not run. Only pass it for hooks you have read (.codex/hooks.json).
Subagents inherit the session's model. To pin a model per role, add a codex_models override to a profile in .hyperresearch/config.toml and re-run hyperresearch install . --target codex:
[profile.full]
codex_models = { fetcher = "gpt-5.4-mini", critics = "gpt-5.5" }
What is different on Codex:
- No browser lane. Codex has no Claude-in-Chrome equivalent, so fetches blocked by a login wall or bot wall stay in the escalation queue, and the final message lists them for you.
- Tool locks are instructions, not enforcement. Codex custom agents have no per-agent tool allowlist. The patcher and polish auditor are told to make surgical edits only, but nothing stops them from doing more.
- A Stop hook guards the pipeline.
hyperresearch run stop-gateblocks the session from ending while the newest run is mid-pipeline, so Codex cannot quietly answer inline and stop. Codex runs a project's hooks only after you trust them.
The 16-step research pipeline
The entry skill is a thin router. It pins down the canonical research query, then invokes one step skill per phase via Claude Code's Skill tool (on Codex, it reads one step file per phase from .hyperresearch/codex/steps/). Each step's procedure loads into context only when that step actually runs. That's what stops a long pipeline from quietly dropping steps as its context rots.
| # | Step | What it does | Tiers |
|---|---|---|---|
| 1 | Decompose | Canonical query → atomic items + coverage matrix + tier classification | all |
| 1.5 | Chapter partition | Group atomic items into 4–10 chapters; steps 2–10 then loop per chapter | dissertation |
| 2 | Width sweep | Multi-perspective search plan + parallel fetcher waves | all |
| 3 | Contradiction graph | Pair contradictions across the corpus into ranked clusters | full |
| 4 | Loci analysis | Two parallel loci-analysts → scored loci with source budgets | full |
| 5 | Depth investigation | K parallel depth-investigators → interim notes with committed positions | full |
| 6 | Cross-locus reconcile | Reconcile committed positions → comparisons.md | full |
| 7 | Source tensions | Extract expert disagreements → source-tensions.json | full |
| 8 | Corpus critic | "What source would overturn this?" + targeted gap-fill fetch | full |
| 9 | Evidence digest | Top claims + verbatim quotes → evidence-digest.md | full |
| 10 | Triple draft | Per-angle source curation + 3 parallel draft sub-orchestrators (light: single draft) | all |
| 11 | Synthesize | Plan + outline + spawn synthesizer subagent → final_report.md | full |
| 12 | Critics | 4 adversarial critics in parallel → findings JSONs | full |
| 13 | Gap-fetch | Targeted fetch wave for critic-identified vault gaps | full |
| 14 | Patcher | Surgical Edit hunks applied to draft (tool-locked Read+Edit) | full |
| 14.5 | Cite-check | Verify citation-sentence bindings; skeptical LLM spot-check; second surgical patch pass | full |
| 15 | Polish | Hygiene + filler pass (tool-locked Read+Edit subagent) | all |
| 16 | Readability audit | Recommender writes JSON suggestions; orchestrator selectively applies | all |
Tiers and gears: the two scale levers
Tiers route per query. Step 1 auto-classifies light vs full. dissertation is opt-in only; ask for it in your prompt. It is experimental: its length, read-budget and citation targets are configured but not yet wired in (#103).
| Tier | What runs | Typical time |
|---|---|---|
light | bounded factual queries, surveys, comparisons: 1 → 2 → 10 → 15 → 16 | ~30–40 min |
full (default) | deep argumentative analysis with adversarial review: all 16 steps + cite-check | ~1.5–2.5 h at full gear |
dissertation (experimental) | chaptered mega-runs: 300–450 sources across 4–10 chapters, 25K–80K words | ~4–8 hours |
Gears set the scale of the standard pipeline: the source targets, depth budgets, and word targets rendered into the step skills.
hyperresearch profile list # all profiles + descriptions + current gear
hyperresearch profile use premier # 100–130 sources, doubled depth budget (~3–5 h)
hyperresearch profile use full # back to the 55–80-source baseline
The gear persists per project and survives reinstalls. Custom gears: define [profile.<name>] in .hyperresearch/config.toml (any knob: source targets, loci caps, draft counts, word targets, per-agent models) and profile use <name>.
Run levers: what voice the report is written in
Tiers and gears set how much work happens. Levers set what kind of report comes out, and step 1 picks them from your prompt's verb shape. An explicit directive in your prompt always wins.
| Lever | Values | What changes |
|---|---|---|
register | teach / survey / analyze / advocate | "Teach me X" gets a pedagogical explainer; "what's the landscape" gets a map of the field with no verdict; analyze (the default) gets the evaluative argument; advocate defends one named thesis |
domain_notes | freeform | Sourcing strategy, evidence norms, recency window for the field in question |
inference_depth | surface / standard / deep | The rabbithole dial. Step 4 can upgrade it after seeing what the corpus actually holds |
The levers render into role-scoped shim files that spawn templates paste verbatim into subagent prompts, so the critics move with the register instead of undoing it. In survey register the dialectic critic flags unfair representation rather than missing commitment, and the polish auditor stops striking hedges. In advocate all of them tighten instead.
The cite-checker and the ship gate receive no shim at all. Verification never softens by mode.
hyperresearch levers set <tag> inference_depth=deep --rerender # go deeper mid-run
hyperresearch run status -j # see what step 1 chose
The two load-bearing principles
-
Patch, never regenerate. After step 11 produces the synthesized report (or step 10 for light tier), the only modifications are surgical Edit hunks. The patcher and polish auditor are tool-locked to
[Read, Edit]at the Claude Code allowlist level so they physically cannot Write a new draft (on Codex this lock is an instruction, not enforcement). Per-hunk caps make "just rewrite it" mechanically impossible. Critic findings that don't fit a small hunk escalate as structural issues. -
Canonical research query is gospel. The verbatim user prompt is persisted to
research/runs/<vault_tag>/query.mdonce and re-read by every subsequent step and every spawned subagent. Wrapper requirements (save paths, citation format, terminal sections) are a separate contract.
Subagent roster
Models are profile config, not hardcode. The table shows the shipped defaults, and you can override any of them in .hyperresearch/config.toml: [profile.full] with models = { fetcher = "haiku" } swaps every fetcher to Haiku on the next install or profile use.
| Agent | Default model | Role |
|---|---|---|
hyperresearch-fetcher | Sonnet | URL fetching via crawl4ai; runs 8–12 in parallel per wave |
hyperresearch-source-analyst | Sonnet | End-to-end digest of any single long source >5000 words |
hyperresearch-loci-analyst | Sonnet | Reads the width corpus, returns 1–8 depth loci with rationale |
hyperresearch-depth-investigator | Sonnet | Investigates one locus, writes one interim note with a committed position |
hyperresearch-corpus-critic | Sonnet | "What source would overturn the current direction?" pre-draft gap analysis |
hyperresearch-draft-orchestrator | Opus | One per draft angle; reads its curated source list and writes one draft |
hyperresearch-synthesizer | Opus | Reads all 3 drafts, writes the final report (two-pass write, Read+Write locked) |
hyperresearch-dialectic-critic | Opus | Counter-evidence the draft missed |
hyperresearch-depth-critic | Opus | Shallow spots interim notes could fill |
hyperresearch-width-critic | Opus | Topical corners the corpus supports but the draft ignores |
hyperresearch-instruction-critic | Opus | Structural mismatches against the prompt's atomic items |
hyperresearch-patcher | Opus | Tool-locked [Read, Edit]. Applies critic findings as surgical Edit hunks |
hyperresearch-cite-checker | Sonnet | Skeptically verifies sampled citation-sentence bindings before ship |
hyperresearch-polish-auditor | Opus | Tool-locked [Read, Edit]. Cuts filler, strips hygiene leaks |
hyperresearch-readability-recommender | Opus | Writes JSON suggestions for paragraph rhythm and list/table conversion |
hyperresearch-browser-fetcher | Sonnet | Drains the escalation queue by driving your real Chrome (Claude-in-Chrome) |
The vault: persistent, searchable, compounding
Most deep research harnesses are one-shot: report out, everything else discarded. Hyperresearch keeps what it reads. Every fetched source lands in a SQLite-indexed vault that future sessions search before they fetch.
hyperresearch search "ion-trap gate fidelity" -j # Full-text search
hyperresearch search "quantum" --include-body -j # Full-body search
hyperresearch note show <id1> <id2> <id3> -j # Batch-read notes
hyperresearch graph hubs -j # Most-connected notes
hyperresearch graph backlinks <id> -j # Reverse links
hyperresearch lint -j # Health check (broken links, missing tags)
Markdown is truth, SQLite is cache. Notes live as plain markdown with YAML frontmatter in research/notes/. The SQLite index is fully rebuildable: delete it and hyperresearch sync reconstructs it from the markdown. Open the vault in any editor, version it in git. You don't need the tool installed to read your own research.
PDFs fetch directly. hyperresearch fetch auto-detects PDF URLs (arXiv, NBER, SSRN, direct .pdf links) and extracts full text via pymupdf. Raw PDFs land in research/raw/<note-id>.pdf and the note's raw_file: frontmatter links back.
Provenance breadcrumbs. Every fetched source carries a --suggested-by link back to whatever surfaced it. The chain forms a rooted tree from seed fetches; the provenance lint rule catches disconnected components.
Semantic search, if you want it. hyperresearch embed sync populates embeddings (provider-pluggable: voyage, openai, or the default none, which needs zero API keys) and search --semantic blends vector similarity with full-text ranking.
Curation: notes have a lifecycle
Every session ends with a curation pass, and notes move through draft → review → evergreen, or stale → deprecated → archive as material ages out. That's what keeps a vault from turning into a landfill of half-read pages.
hyperresearch note update <id> --summary "..." --add-tag <t> -j # promote a draft
hyperresearch dedup -j # near-duplicate pairs by content similarity
hyperresearch topic tree -j # the topic hierarchy
hyperresearch index build -j # regenerate index pages
hyperresearch batch set-status stale --tag <t> -j # bulk lifecycle moves
hyperresearch link --note <id> --dry-run -j # wiki-links the linker would add
You are not locked in
The vault is markdown in a directory. Everything below is a convenience on top of that, not a dependency.
hyperresearch export json -o out.json # every note as structured JSON
hyperresearch export vault <dir> # a filtered subset to another directory
hyperresearch import <dir> # pull an existing markdown collection in
hyperresearch git changed -j # notes with uncommitted changes
hyperresearch git log -j # notes touched by recent commits
hyperresearch watch # auto-sync while you edit in your own editor
Use the vault outside Claude Code
An MCP server. pip install hyperresearch[mcp], then hyperresearch mcp speaks stdio, so Claude Desktop, Cursor, or anything else that speaks MCP can work the same vault. Thirteen tools: search_notes, read_note, read_many, list_notes, get_backlinks, get_hubs, vault_status, lint_vault, check_source, list_sources, fetch_url, create_note, update_note.
A local web UI. hyperresearch serve --open starts a stdlib HTTP server on port 8080 with note browsing, tag pages, search, and an interactive link graph. No build step and no JavaScript dependencies.
Source ranking: quality is persistent, not vibes
Every source accumulates a composite quality_score built from source-type tier, fetch-time utility, citation authority (from OpenAlex / Semantic Scholar, including retraction flags), and vault PageRank centrality:
hyperresearch sources score -j # Enrich DOI-bearing notes: citations, venue, retractions
hyperresearch graph rank -j # PageRank over the link + provenance graph
hyperresearch search "q" --ranked -j # Quality-weighted full-text search
hyperresearch sources independence -j # Cluster syndicated/derivative copies: 5 copies of one press release = 1 vote
hyperresearch claims search "q" -j # Query extracted claims across all sources
Retracted sources are floored to near-zero quality, and a ship-time retraction sweep re-checks every cited DOI fresh, so a retraction published yesterday is caught today. Even on vault sources reused from old runs.
Runs: resumable, budgeted, verified
Every run owns an isolated workspace (research/runs/<vault_tag>/) and a manifest. Concurrent runs never collide, and a crashed run resumes exactly where it stopped:
hyperresearch run status -j # Step-by-step status, spend, escalation queue depth
hyperresearch run resume -j # Exact next step + Skill invocation to continue
hyperresearch run report -j # Per-step wall-time / spend / source-yield telemetry
hyperresearch run verify <tag> -j # Ship gate: headings, length, citation density, cite-check resolution
run init --budget 50 caps estimated API-equivalent spend; crossing the cap blocks the run rather than letting it quietly balloon. And before any report ships, the verification battery runs: quote-integrity (every quoted span must exist verbatim in a vault note), retracted-citations (citing a retracted source unacknowledged blocks the ship), numeric-consistency (numbers untraceable to evidence get flagged), plus the cite-check step's per-citation binding audit.
What's structurally enforced
- Verbatim prompt as gospel.
scaffold-promptlint blocks if the scaffold doesn't open with the user's exact prompt - Locus coverage. Every step 4 locus must have a step 5 interim note; missing interims flag as errors
- Patch-only modification. Steps 14, 15, 16 are tool-locked to
[Read, Edit]. They cannot regenerate the draft - Critical findings never silently skip.
patch-surgerylint surfaces any critical finding the patcher couldn't apply - Quoted text must exist.
quote-integritylint blocks any quoted span that doesn't appear verbatim in a vault note; hallucinated quotes cannot ship - Retractions block the ship. Citing a retracted source without acknowledging the retraction is a hard error at the final gate
- Schema integrity.
tier,content_type, andtypeare SQLite CHECK-constrained vocabularies; corrupted frontmatter cannot poison the index - Hygiene leaks caught on the way out. Scaffold sections, YAML frontmatter, and prompt echoes are stripped by step 15 before ship
- Fetched text is data, never instructions. Web-fetched bodies are served inside an
<untrusted-source>fence on bothnote showandsearch, so a page telling the agent to ignore its instructions is read as content
The web is hostile input
A research agent reads hundreds of pages it did not choose, and any one of them can contain text addressed to the agent rather than to you.
Every body fetched from the web is served wrapped in <untrusted-source url="..."> delimiters with an inline treat-as-data preamble, on both paths that serve bodies (note show in single, batch, and JSON forms, and search with bodies included). Notes your own pipeline subagents wrote pass through unwrapped. Forged fence tags inside a fetched body are neutralized and left visible for forensics, the url attribute is HTML-escaped with control characters stripped, and in search the wrapping happens after token-budget truncation so the closing fence can never be severed. The fetcher, depth-investigator, draft-orchestrator, and source-analyst prompts all carry a policy block telling them not to launder a fenced page's directives into trusted output.
Resolved URLs from third-party APIs get the same treatment. An open-access location arrives inside someone else's JSON, so it's checked for scheme, embedded credentials, and publicly-routable resolution before anything fetches it.
Web providers
The [web] provider setting in .hyperresearch/config.toml picks how pages are fetched and, for the providers that support it, how the web is searched. All are optional extras except the default.
builtin(default) — plain HTTP fetch with no search. Zero extra dependencies; the starting point everything else improves on.crawl4ai— headless browser fetch with stealth, PDF extraction and the browser-escalation lane. The one the pipeline is tuned for.pip install "hyperresearch[crawl4ai]".exa— neural web search and page extraction. Needs an API key.pip install "hyperresearch[exa]".tavily— search and extraction built for agents. Needs an API key.pip install "hyperresearch[tavily]".parallel— Parallel's Search MCP endpoint, which needs no account or key. Search only — bulk fetch waves degrade to per-URL, so it is a good search provider rather than a replacement for the crawl4ai fetch path. Every request from one process carries a random session ID that Parallel uses for correlation and rate limiting on its side.pip install "hyperresearch[parallel]".serply— Serply's Google search API, with page fetch through the same key (API docs). Search results are fetched to full page text, falling back to the snippet when a page cannot be fetched. Needs an API key; no extra install.
# .hyperresearch/config.toml
[web]
provider = "crawl4ai"
Every fetch lane verifies TLS certificates by default: builtin, the PDF downloads, and crawl4ai's headless browser. A bad certificate fails the fetch with CertVerificationError; nothing retries it unverified. For a cert-broken site you trust, set the opt-out for the lane that refused it under [fetch]: browser_verify_tls = false for crawl4ai's headless browser, pdf_verify_tls = false for PDFs. The builtin provider has no opt-out. The visible-window browser used with a login profile (--visible, and the LinkedIn / Twitter-style domains) still accepts bad certificates, because some of the walled sites it exists for serve broken chains.
Authenticated crawling + the browser lane
Fetch from LinkedIn, Twitter, paywalled sites or anything you can log into:
hyperresearch setup # Browser opens. Log into your sites. Done.
LinkedIn, Twitter, Facebook, Instagram, and TikTok automatically use a visible browser to avoid session kills.
Blocked fetches escalate instead of dying. When headless crawling hits a login wall or bot wall mid-run, the URL queues as an escalation (hyperresearch escalation list -j). If you have the Claude-in-Chrome extension, the browser-fetcher agent drains the queue by driving your real, logged-in Chrome. Hard boundary: CAPTCHAs, 2FA, and logins are never solved automatically. They're consolidated into one message and handed to you.
Scholarly discovery: eight sources, one query, one deduplicated list
For any topic with a research literature, search the scholarly sources BEFORE web search. They return citation-ranked canonical works; web search returns derivative commentary. That advice used to be delivered as a list of URL templates the agent was trusted to assemble by hand — no retry, no rate limiting, no dedup, no tests. It is now a real client layer:
hpr scholar search "Byzantine iconoclasm" -j # every available source, merged
hpr scholar search "GLP-1 cardiovascular outcomes" --scope papers -j
hpr scholar search "credit default swaps" -s edgar -s fred -j
hpr scholar sources # what is wired, what each covers
One call queries every configured source, merges records that are the same work (by DOI first, then by normalized title and year), and returns one list. A work found by two providers carries both in also_in, with the higher citation count and the longer abstract. Every provider shares one cache, one per-host courtesy rate limiter, and one result shape.
The literature sources:
- OpenAlex — ~250M works across every discipline, including books, book chapters and theses. The right default outside STEM, where the incumbent tools are weakest.
- Crossref — the DOI registry itself. Authoritative metadata for ~160M registered works, including registrations too new for anything else to have indexed.
- CORE — the largest open-access full-text aggregator. Hosts the text rather than linking to it, so it is also a full-text resolver (below). Needs a key:
CORE_API_KEY. - DOAB — peer-reviewed open-access scholarly books and chapters. The only source here that finds the book rather than a review of it, which matters because in the humanities the book, not the article, is the unit of publication.
- RePEc — listed so the gap is visible rather than silent. Their API has no search function;
hpr scholar sourcessays so and points at OpenAlex and Crossref for the DOI-bearing series.
The specialist sources — citable records that are not papers, tagged by work_type so the pipeline never mistakes one for literature:
- ClinicalTrials.gov — registered studies including the ones that never produced a paper. No key.
- SEC EDGAR — full-text search over filings. The SEC rejects any request without a contact address in the User-Agent, so set
HYPERRESEARCH_CONTACT_EMAIL. - FRED — Federal Reserve economic series. Needs a key:
FRED_API_KEY, which is never written to the cache.
Setting HYPERRESEARCH_CONTACT_EMAIL also puts you in the OpenAlex and Crossref "polite pools", which are rate-limited far more generously than anonymous traffic. No placeholder is ever sent on your behalf.
After the scholarly sweep, run web searches for context, news, non-academic angles, and at least one adversarial search ("criticism of X", "limitations of X").
Open-access full text: read this before you cite
A paywalled paper otherwise enters the vault as an abstract, and the pipeline then reasons over ~1,500 characters while citing the work as though the paper had been read. To close that, when a fetch lands a thin page carrying a DOI, hyperresearch asks Unpaywall, Europe PMC and CORE, in that order, for a legal open-access copy and stores that text in the note body instead. Unpaywall needs a contact address and Europe PMC covers biomedicine only; CORE is the broad net that catches everything else, and it hosts the text directly rather than pointing at a repository that may 403.
The note's source: still points at the URL you asked for. The body may have come from somewhere else. That substitution is disclosed in four places, and you should know all of them:
- A banner at the top of the note body, naming the URL the text actually came from and which version it is.
oa_url/oa_source/oa_version/oa_license/oa_recovery_kindin the note's frontmatter.- An
oablock inhpr note show <id> --json, carryingbody_is_not_from_source: true. - A line in the output of
hpr fetchandhpr fetch-batch.
Rescued notes: nothing in them came from the source
The same lookup runs when a source can't be read at all — a 403, a login wall, a bot wall. Those are where a paywalled paper is most completely lost, and, since a DOI identifies the work rather than the host, where a legal copy is most likely to exist elsewhere.
A note built that way is a stronger claim than a substitution, and it is marked differently: oa_recovery_kind: rescued, nothing_from_source: true in note show, and a banner that says the source URL was never read. Take it literally. The title, the authors, and every word of the body are the open-access copy's — nothing was read from the URL in source:. If you would rather have no note than a note assembled entirely from a substitute, set oa_rescue_blocked = false.
Two limits worth knowing. Rescue needs a DOI, and a source that returned nothing offers no page to read one out of, so it only fires when the DOI is in the URL itself (a doi.org link) or in a wall page's citation_doi meta tag. A bare publisher URL with no DOI in it fails exactly as it did before. And a rescued source is not queued for the browser-escalation lane, because the paper is already in hand — if you want the publisher's own page specifically, fetch it through that lane yourself.
Versions are not interchangeable. Unpaywall will happily hand back an accepted manuscript or a submitted preprint when no published copy is open. hyperresearch prefers the version of record and records what it got in oa_version, but if that says acceptedVersion or submittedVersion, check any direct quotation against the published paper before it reaches a report. The body banner says so too.
Configure it under [scholar] in .hyperresearch/config.toml:
[scholar]
oa_recovery = true # set false to disable entirely
contact_email = "" # REQUIRED by Unpaywall's terms — empty means Unpaywall is skipped
oa_min_full_text_chars = 6000 # bodies shorter than this trigger a lookup
oa_prefer_published = true # version of record over preprints
oa_max_attempts = 3 # candidate copies to try before giving up
oa_rescue_blocked = true # also run when the source can't be read at all
Out of the box contact_email is empty, so only Europe PMC runs and recovery is limited to papers in its open-access subset. Set it to a real address to enable Unpaywall — their terms require one, and shipping a shared placeholder would get that placeholder rate-limited for every hyperresearch user at once.
Publishers block their own open-access PDFs often enough that one attempt isn't enough, so hyperresearch walks a candidate list: every PDF Unpaywall knows about, then the landing pages, then Europe PMC's structured full text (parsed from JATS, which beats pymupdf on a two-column PDF — real section boundaries, no header bleed, no column interleaving). Europe PMC is only queried once Unpaywall's copies are exhausted.
Recovery never fails a fetch and never lowers quality. A candidate has to clear two bars to be accepted: more text than you already had, and enough text to clear oa_min_full_text_chars. That second bar is what stops a repository record page — title, authors, a 200-word summary — from passing for full text just by being marginally longer than the publisher's abstract. If no candidate clears both, you keep the abstract and no oa block appears. Rescue only ever turns a failed fetch into a note, never the reverse: when a blocked source has no open-access copy, the command fails exactly as it always did.
What it doesn't do
- It doesn't replace your judgment on which sources matter. The agent picks, you steer.
- It can't fetch what's behind a paywall you haven't logged into. Open-access recovery finds a legal free copy when one exists — even when the publisher blocks the fetch outright — but when none exists you get the abstract, or nothing, and the note says so.
- On Claude Code it runs on Anthropic models via the subagent roster (per-agent assignments come from the profile's model map). On Codex, subagents use the session's model unless a Codex override is configured. Usage scales with tier, gear, and corpus size. The Codex port is new and has not been benchmarked yet; the Claude Code pipeline is the one that has been benchmarked.
- The lint gate catches structural failures (missing scaffold, broken provenance, unresolved CRITICALs). It cannot guarantee factual accuracy, that's still your call.
Requirements
- Python 3.11+
- Claude Code, or the OpenAI Codex CLI