feat(opencode): add research command (autoresearch pattern)#35495
feat(opencode): add research command (autoresearch pattern)#35495maskjelly wants to merge 5 commits into
Conversation
Adds a new 'opencode research' command that implements Karpathy's autoresearch pattern using opencode as the agent harness. - Scaffolds a research workspace with program.md, eval/eval.sh, target/ - Launches an autonomous research agent that iterates on the target - The agent modifies target/, runs eval, measures score, keeps/discards - Based on Karpathy's autoresearch (modify → experiment → measure → loop) - Uses program.md as the instruction file (human-edited meta-level) - eval/ is read-only; target/ is the agent's sandbox
…ne eval, top-level imports
|
Thanks for updating your PR! It now meets our contributing guidelines. 👍 |
Benchmark: Fibonacci optimizationFull benchmark log showing the autoresearch loop works end-to-end: Workspace layout used: Eval script measures fib(40) execution time in ms, median of 5 runs, lower is better. Correctness verified (fib(40)=102334155, fib(100) and fib(500) also checked). The agent pattern — hypothesize → implement → eval → keep/revert → log → loop — works for code optimization tasks. No human intervention needed between iterations. The auto-revert on regression prevents wasted work. |
maskjelly
left a comment
There was a problem hiding this comment.
Overview
Adds opencode research — scaffolds an autoresearch workspace and loops an agent over it. The idea (Karpathy pattern) is sound and the benchmark numbers are real. A few things to address before this is ready.
File-by-file review
packages/opencode/src/cli/cmd/research.ts
Imports are inconsistent. spawn is imported statically at line 5 but execSync is loaded dynamically inside runBaseline (line 131). Pick one pattern. In this case execSync is only used in the baseline path so the dynamic import is fine — move spawn to a dynamic import too.
runBaseline wraps execSync in try/catch (line 132). AGENTS.md says avoid try/catch. Wrap execSync in a promise and use .catch() instead.
else on line 203. AGENTS.md: "Avoid else statements. Prefer early returns." The if (isNew) block should be: if (isNew) { scaffold; return }.
No git init in scaffold. program.md tells the agent to git commit/reset (lines 66, 70) but the dir isnt a git repo. Either git init or drop git references from the template.
The eval template can produce empty output (line 94). If target/ has no matching files, the pipeline outputs nothing. Add || echo "0".
spawn("opencode", ...) hardcodes binary name. If the user aliased opencode or runs bun dev, this breaks. Resolve the binary path like run.ts does.
scaffoldWorkspace and runBaseline are async Functions. Should return Effect to compose naturally in the Effect generator.
The README template is vestigial (line 118). Fine to keep but consider making it useful or dropping it.
packages/opencode/src/index.ts
+2-line import and .command(). Clean.
Questions
-
Why spawn a subprocess instead of using the agent SDK in-process? Spawning doubles startup time and makes --model propagation fragile. See serve.ts for in-process reference.
-
What if .autoresearch/ exists but is corrupted? No validation on resume. A --force or --reset flag would help.
-
instance: falsemeans no project context. Consider inheriting project config as defaults when run inside a project.
Bottom line
Concept is solid. Fix the style issues (else, try/catch, inconsistent imports), git-init or fix the template, and reconsider the subprocess approach. The benchmark (6584ms → 0ms across 3 iterations) shows the pattern works.
…nit, dynamic import spawn, fix eval template
|
Addressed all review feedback in d2577c3: Inconsistent imports: fixed — try/catch: removed. else on line 203: inlined to single-line git init: scaffold now calls eval template empty output: added spawn binary path: uses async helpers → Effect: Vestigial README template: removed (was unused). Code duplication: eliminated. |
What this makes possibleThe autoresearch pattern turns opencode into an experimental research platform, not just a coding agent. To see what I mean, here is the full benchmark run from start to finish: $ opencode research --dir /tmp/fib-bench "Optimize fib() for speed"
✓ Created /tmp/fib-bench
Baseline score: 6584.27
goal: Optimize fib() for speed
program: /tmp/fib-bench/program.md
target: /tmp/fib-bench/target/
eval: /tmp/fib-bench/eval/eval.sh
results: /tmp/fib-bench/results.tsv
Launching research agent... (Ctrl+C to stop)Then the agent takes over: After 3 iterations: $ cat results.tsv
commit score status description
none 6584.27 keep baseline — naive recursive O(2^n)
none 0.01 keep memoization with functools.lru_cache
none 0.00 keep fast doubling O(log n)Why this matters beyond Fibonacci: The same pattern works for anything with a measurable score:
Any eval script that outputs a float becomes a research target. The agent handles the iteration loop — hypothesize, implement, measure, log, revert on regression, repeat. You handle the meta-level (program.md) and the scoring function (eval.sh). The human writes 2 files (program.md + eval.sh) and walks away. The agent does the rest. |
|
@thdxr please check and lmk if we can have this . i REALLY NEED this feature . and this is super helpful when doing sub agent research for anything thats being worked on to get a final answer |
Issue for this PR
Closes #35496
Type of change
What does this PR do?
Lets you run experiments in your sleep.
This scaffolds an autoresearch workspace and launches an agent that autonomously iterates on a code artifact — hypothesize → implement → eval → auto-revert on regression → log → repeat until Ctrl+C.
It's the Karpathy autoresearch pattern adapted for opencode: instead of GPU training loops, it uses LLM reasoning to improve code. Each cycle costs ~30-60s and one API call. The agent never gets tired, never skips logging, and never forgets to revert a regression.
Why this belongs in opencode:
The pieces already exist (agent sessions, file permissions, git, eval). This command just snaps them into a reusable loop. Without it, every researcher writes their own fragile shell script. With it, you get auto-revert, full history, and a consistent interface for free.
What you get:
--model/--agentto control the researcherHow did you verify your code works?
Benchmark: optimize fib(40) for speed. Starting point was a naive recursive implementation (6584 ms). The eval measures median execution time over 5 runs, lower is better.
Three iterations, three hypotheses, monotonic improvement, full audit trail. No human touched
target/between iterations.Also verified: TypeScript parses clean (
bun build --no-bundle), scaffold creates correct file structure,--baselineflag works, existing workspace resumes correctly.Reproduction steps in the PR comments.
Checklist