OPEN SOURCE DEEP DIVE
OpenResearch: A Local-First Workspace That Turns Coding Agents into Research Agents
OpenResearch (orx) is alphaXiv's local-first research workspace: a single Rust binary that turns Claude Code, Codex, OpenCode, or Cursor into research agents that review literature, form hypotheses, run experiments, and produce artifacts. It organizes work as a git-native experiment tree under a fixed run contract, drives experiments through a repair/refill/promote/stop autoresearch loop, and treats run logs and manifests as the only evidence. Written from a close read of the v0.2.3 source and a hands-on run of the bundled nanochat demo.
What Separates a Coding Agent from a Research Agent
Claude Code, Codex, OpenCode, and Cursor can read code, change code, and run tests reliably. Dropped into a research workflow, however, they hit a structural gap: research is not "fix one problem" but "accumulate comparable evidence across a chain of dependent decisions". What changed in a run, which run it is compared against, and which stretch of log a conclusion rests on all dissolve into chat history and shell scrollback, gone by the time the next experiment starts. OpenResearch, whose CLI is called orx, is aimed squarely at that gap. It is alphaXiv's local-first research workspace: a single Rust binary that turns the coding agents above into research agents covering literature review, hypothesis formation, experiment execution, and artifact production. The repository was created on 7 June 2026; at the time of writing the latest release is v0.2.3 (16 September 2026), with roughly 3,500 stars and 232 forks under the MIT license, and a day at the top of GitHub Trending behind it.
The positioning is best summarized as local-first. Projects, conversations, experiments, runs, logs, code, and artifacts all live in a local data directory and a process-local SQLite database; orx up serves the dashboard at 127.0.0.1:4791. Creating a project or launching a run publishes nothing, and an openresearch.sh account only gates service-owned capabilities such as organizations and managed compute. The data directory is even relocatable: on startup the tool repairs internal absolute-path references, so a moved directory just works.
Four Non-Negotiable Rules
OpenResearch writes its methodology into the skill documents shipped with the CLI. The "cardinal rules" section opens by stating that these four are not style preferences: breaking any one silently invalidates your results. First, frozen nodes: the moment a run answers a node's question, including the root, the node freezes permanently, and a disappointing result is still a result. Before that it is provisional, and seeding dependencies or fixing its environment happens on its own branch; to try an idea you branch a child and edit the child. Second, a fixed contract: the run command and the environment are identical on every node, children inherit the parent's command verbatim, and behavior must never be varied through environment variables or env-prefixed commands such as LR=3e-4 python .... Third, vary code, not knobs: hyperparameters go into committed code or config, one child branch per variant, so that every node runs the same command over different code and the logged result summaries stay comparable. Fourth, grow the tree downward, not sideways: fan out a little within one round over a single decision, then promote that round's winner and descend onto it for the next round. A root with a long row of direct children and no grandchildren is the failure mode the documentation names explicitly.
flowchart TD R["baseline (frozen)"] --> A["LR 2e-5"] R --> B["LR 3e-5 (round winner)"] B --> C["wider MLP"] B --> D["vocab 8192"] D --> E["next round: branch on the winner"]
That shape is what the docs call stacked bushes: each round is a short bush of co-equal options for one decision, and rounds chain into depth through promotion. A flat fan spreads compute into a single parameter sweep; a noodle chain throws away comparison information; only stacked bushes let each winner carry forward into the next round.
The Autoresearch Loop: Repair, Refill, Promote, Stop
On top of the rules sits the loop that drives a project. Every completed run is a decision point with four moves. Repair: the run answered nothing, so fix this node's branch and relaunch the same node. Refill: the result is mediocre or inconclusive, so launch the next queued sibling to keep the round moving. Promote: the result is a clear win, so this node becomes the parent for the next round and the next batch of children branches off it rather than off the baseline, which is what makes wins carry forward. Stop: the goal is met or the branch is exhausted. The waiting primitive is orx exp wait --project: one completion returns once, you decide, then you re-issue it; a single wait call is not expected to block until everything finishes. After each wake you reconcile with orx runs and act on every newly terminal run, not just the line the wait printed. When nothing is in flight it returns drained: no runs in flight immediately, and that is the exit condition. Repairs are capped: two consecutive runs that answer nothing on one node means stop and ask a human, and the same failure hitting a second node means it is one setup problem, not two. After roughly three consecutive failed or regressed runs you stop and write the tree up as a descriptively named project artifact, and any turn that ran or changed experiments closes with a short summary, one line per relevant node: what it tested, its status, its headline result.
The Evidence Contract: Only Run Logs Count
Every substantive claim in chat about code, files, artifacts, or measured results must be followed immediately by a clickable reference: code and file facts use raw <file path="relative/path.py" /> tags, optionally with line ranges and an experiment branch, while measured results use <run id="runId" /> tags with an optional short label such as +3.65pp. The instruction is explicit: read the cited run's log before reporting the result, because status alone is not evidence. Logs are read through orx logs with --head, --bytes, and --range byte windows so whole logs never flood the context. The demo project's evidence pack also ships a run-manifest.json that records path, byte size, and SHA-256 for every preserved file, and lists the intentionally omitted directories (datasets, evaluation corpus, optimizer states, about 2 GB in total), so later analysis can tell what was produced from what is still locally available.
| Demo run metric | Recorded value |
|---|---|
| Base training scale | 5,000 steps / 81,920,000 tokens / 131.55 minutes on Apple Silicon MPS |
| Base validation BPB | 1.1658 (1.1878 at step 4,000, 1.1743 at 4,500, 1.1658 at 5,000, still falling at the endpoint) |
| CORE small-scale eval | OpenBookQA 0.2500, Winogrande 0.5625 (0.125 centered), Wikidata and Operators both 0.0000 |
| SFT stage | 1,500 steps / 39.07 minutes, validation BPB from 1.0174 down to 0.7389 |
| Final chat probe | Answers "Paris" to the capital-of-France prompt, then enters a numeric repetition loop |
Literature Review: The Main Agent Ranks Itself
orx discover offers keyword and embedding search over alphaXiv, OpenAlex, and bioRxiv; orx paper fetches a single paper by arXiv id or DOI. Two rules in the skill document are hard: ranking must be done by the main agent itself, never delegated to a subtask, and each candidate receives a difficulty score from 1 to 10 that decides follow-up depth, with zero, one, or two rounds of citation chasing. Scholarly claims must carry source links of the form alphaxiv.org/abs/<id> rather than project file or run tags. Running orx discover keyword "humanoid whole-body control" --limit 2 on a local install returned live alphaXiv results, including recent whole-body control work (arXiv 2609.15213), not cached samples.
Architecture: One Rust Binary over Local SQLite
Everything collapses into a single statically linked Rust binary: musl targets with rustls, so no system TLS dependency; storage is a local SQLite database through rusqlite; the dashboard is served by axum with the frontend bundle embedded via rust-embed, listening on 127.0.0.1:4791 by default. The UI is React 19 with Vite, TanStack Query, an xyflow experiment tree, an xterm terminal, and KaTeX math, with interface strings compiled per language by paraglide. The harness adapter injects one shared system prompt through each agent's native channel, and every chat session gets its own private git worktree of the project repository.
| Coding agent | System prompt channel | Session workspace |
|---|---|---|
| Claude Code | --append-system-prompt-file | private git worktree per session |
| Codex | developerInstructions | private git worktree per session |
| OpenCode | config instructions list | private git worktree per session |
| Cursor | project rules file | private git worktree per session |
Execution backends span local, SSH (with config aliases and custom ports), Slurm, Kubernetes, Ray, Hugging Face Jobs, Modal, Tinker, and managed OpenResearch compute; the same committed snapshot runs remotely without publishing the repository, and orx up --remote user@host keeps the browser on your laptop while the service runs next to the GPUs. The skill system is twelve modules under agent-skills/ (experiment tree, compute, evidence, literature review, figures, paper, reports, git, create, delegation, instances, customize), installed into each agent's skill directory with orx install-skills; the system prompt carries only durable per-turn context and procedural knowledge loads on demand. On the artifact side there are two more pipelines: live Overleaf sync over socket.io with browser-cookie import and credentials stored under AES-128-CBC with PBKDF2, plus local LaTeX compilation. The figures skill states plainly that default matplotlib output is not publishable.
orx up # launch the local dashboard, import or create a project
orx install-skills # install skills into your coding agents
orx projects # list local projects
orx project view <projectId> # see the experiment tree, get experiment ids
orx runs <projectId> # list runs, get run ids
orx logs <runId> --bytes 20000 # read a log byte window
orx exp run <experimentId> # launch a run on a node
orx discover keyword "humanoid whole-body control"
orx paper 2609.15213 # fetch one paper
Hands-On: What the Bundled Demo Actually Proves
The first-launch onboarding offers a nanochat demo project: three curated sessions and three experiment nodes, with the baseline completed and a doubled-learning-rate probe plus a vocab-8192 probe idle. The baseline session records a real end-to-end Apple Silicon run, and the chat states training scale, validation BPB, CORE scores, and SFT results one claim at a time, each followed by a run or file reference.
The honesty of the demo is the point. The log preserves the SFT model answering "Paris" and then repeating "345, 345, 345..."; the bottleneck report lists the 0.0000 Wikidata and Operators scores verbatim, cites Chinchilla, LIMA, TinyStories, and Textbooks Are All You Need to explain why falling validation loss does not mean acquired generation ability, and closes with a single-factor next experiment that changes only the pretraining token count: 278,396,928 tokens over 16,992 steps against the current 81,920,000 over 5,000. That is exactly the behavior the evidence contract is designed to produce.
Limits and Risks
The README states the biggest one itself: the remote service started by orx up --remote binds to loopback with no application-level authentication, so other users on that host can reach it; multi-user hosts need your own tunnel or authenticating proxy. Official release builds send opt-out, coarse telemetry tied to a random installation id, excluding code, prompts, file contents, paths, repository names, and tokens; source and development builds send nothing, and orx telemetry off disables it. Storage is single-machine SQLite, so multi-user collaboration and multi-machine sharing are outside the current model. Windows support is beta and requires Git for Windows. The demo evidence pack intentionally omits several gigabytes of weights and data, so reproducing the full workspace means re-running its run script.
Who Should Use It
If you already iterate on machine learning or robot learning experiments with coding agents, OpenResearch's value is turning experiment comparability from personal discipline into a tool-enforced constraint: frozen nodes remove post-hoc baseline edits, the fixed run contract removes environment-variable shortcuts, and stacked bushes remove flat sweeps. For the embodied AI community it fits sim2real ablations and round-by-round policy hyperparameter descent just as well. The precondition is accepting its methodological intensity: this is not a fancier experiment tracker but a research operating system that insists you decide what the current round is actually deciding.