dsh-autoresearch
No description
- Stars
- 0
- Language
- TypeScript
- Created
- Aug 14, 2026
- Updated
- Oct 13, 2026
Introduction
dsh-autoresearch
Unofficial, third-party plugin for bounded, metric-driven optimization in DeepSeek Harness, inspired by Karpathy's autoresearch.
Independent project: dsh-autoresearch is maintained by EveGoodEvening. It is not affiliated with, endorsed by, or sponsored by DeepSeek or Andrej Karpathy.
The autoresearch tool measures a baseline, lets an agent edit allowed files in an isolated Git worktree, and keeps only strict improvements. The Host controls evaluation; SQLite records results for inspection and recovery.
Supported versions
| Component | Supported | Tested |
|---|---|---|
DSH CLI (@deepseek-ai/dsh) and DSH service peers | 0.2.0-rc.2 (exact, coordinated family) | 0.2.0-rc.2 |
Cordis (@deepseek-ai/cordis) | ~4.0.4 | 4.0.4 |
| Node.js | ^22.19.0 || >=24.2.0 | 24.18.0 |
Tested pairing observed on 2026-10-04. Use the scoped Cordis fork, not unscoped cordis. DSH is a prerelease pairing; other DSH versions are not declared supported. Daily upstream compatibility checks do not automatically expand these ranges.
Install
dsh plugin --profile <name> add dsh-autoresearch
dsh --profile <name> --dump-config
The dump should contain id: autoresearch and name: dsh-autoresearch. Use dsh plugin, not plain pnpm add, to activate the bundle.
The Host needs agents, jobs, subprocess, systemPrompt, and tools. Background runs also need dsh-tool-jobs in the calling Agent; the Web standard preset and base/headless compositions provide it.
Use
Register an evaluator first. The Host-owned evaluatorRegistrations registry is intentionally empty by default: the agent cannot choose an arbitrary evaluator command. Here is a complete toy setup; the Host evaluator computes the distance to 3, rather than trusting a model-reported score. It demonstrates the protocol, not scientific effectiveness.
In a clean, trusted Git repository, create and commit these two files at the repository root:
judge.mjs
import { readFileSync } from 'node:fs'
const { value } = JSON.parse(readFileSync('candidate.json', 'utf8'))
if (typeof value !== 'number' || !Number.isFinite(value)) {
throw new TypeError('value must be a finite number')
}
const distance = Math.abs(value - 3)
if (!Number.isFinite(distance)) throw new RangeError('distance must be finite')
console.log(JSON.stringify({ distance }))
candidate.json
{ "value": 10 }
cordis.patch.yml
After installing the plugin, put this override in the chosen profile's $DSH_HOME/profiles/<name>/cordis.patch.yml (merge it into any existing patch list):
- id: autoresearch
name: dsh-autoresearch
config:
defaultMaxExperiments: 20
defaultTimeoutMs: 900000
evaluatorRegistrations:
- id: toy-distance
command: node
args: [judge.mjs]
metricName: distance
metricDirection: minimize
metricParserVersion: final-line-json-v1
evaluatorFiles: [judge.mjs]
dataset: { kind: none }
Profile overrides replace the whole row config, not a deep merge. This minimal row retains the required run defaults; the Config schema materializes omitted deployment defaults from the shipped patch. Retain any existing deployment overrides, model-routing settings and evaluator registrations when replacing the row. Restart the profile and inspect dsh --profile <name> --dump-config before use.
node must be available to the Host. The evaluator runs shell-free with fixed argv; omitting cwd selects the isolated evaluation worktree root. It must exit successfully and end stdout with a JSON object containing exactly one key, the registered metric name, with a finite numeric value: this baseline ends with {"distance":7}. Earlier stdout may contain logs; do not add trailing blank lines. judge.mjs is protected against candidate edits. This example explicitly uses no dataset; the schema also supports protected local dataset files or an externally identified dataset.
Call autoresearch
From that repository, ask the agent to call:
{
"objective": "Reduce the Host-measured distance to 3 by editing candidate.json",
"run_tag": "toy-distance-1",
"evaluator_id": "toy-distance",
"mutable_globs": ["candidate.json"],
"max_experiments": 5
}
repositorydefaults to the agent's working directory. Use a fresh, Git-saferun_tagfor each new run.- Runs are background jobs by default. Inspect or stop them with
job_list,job_output, andjob_kill; use"mode": "foreground"to wait for completion. - Cancellation waits for evaluator cleanup, reconciles the accepted Git state, and releases the run lock only after durable terminal settlement.
- Plugin unload or hot reload cancels active runs and waits for proposal children and jobs to settle.
- Optional inputs:
target(stopping threshold),timeout_ms(per-attempt watchdog), andconstraints(advisory guidance, not acceptance rules). - To resume, replace
run_tagandevaluator_idwithresume_run_idand retain the original run policy. The stored evaluator registration is revalidated before execution.
Defaults: 20 candidates, deployment cap 100, 15-minute evaluator watchdog per attempt (Host cap 60 minutes), and one active run per repository. The baseline is separate from the candidate cap. Git has independent Host-only limits: gitTimeoutMs defaults to 900000 (integer range 1–2147483647); gitMaxStdoutBytes and gitMaxStderrBytes each default to 1048576, independently of evaluator output caps. See Config for deployment limits and retention.
Behavior and safety
- Bounded scalar search. Baseline first; one minimized or maximized scalar, strict improvement only.
constraintsand approval guidance are advisory, not acceptance rules or permission grants. Hard human approval must be enforced by Host policy. This does not establish scientific efficacy or fair resource allocation. - Narrow changes, bounded provenance. Only
mutable_globsmay change; declared evaluator/local dataset files are read-only to candidates. SQLite records decisions and bounded evaluator/dataset/policy evidence; resume revalidates it and fails closed on mismatch or legacy registrations. This is not a complete runtime-image identity. - Managed execution, not confinement. Evaluation uses
ctx.subprocessfor fixed shell-free argv/environment, bounded stdout/stderr collection, a per-attempt watchdog, cancellation/termination and process-tree quiescence checks before continuation. Completion waits for managed cleanup; a watchdog is not a compute budget. A Git worktree and this lifecycle do not confine filesystem access, other processes, network, privileges or hostile same-UID interference. Use trusted code; hostile-code support requires an external isolation provider and an explicit Host/product decision, not this plugin alone. - Fail closed when uncertain. Proposal/report/policy errors are terminal; safely quiescent candidate evaluator failures consume a slot and may continue. Baseline failures stop; uncertain process state blocks recovery/continuation. Crash takeover after abnormal Host death requires Linux
/procevidence; other platforms remain conservatively blocked. - Public metadata is not secret. Metric name/direction/parser, evaluator ID and generated workspace/branch/commit identity are intentionally disclosed to proposal children; never put credentials there. Raw evaluator argv/environment mappings are not forwarded. Exact known-value redaction of permitted untrusted display/history data is limited, not universal confidentiality.
Development
Use pnpm 11.7.0. Build before testing: integration tests load lib/.
pnpm install --frozen-lockfile
pnpm run typecheck
pnpm run build
pnpm run test
pnpm run release:smoke
release:smoke checks a packed install and the real DSH Web profile outside the checkout. Run it after tests, not concurrently: packing rebuilds lib/.
For local installation, build and run dsh plugin --profile <name> add .. Releases use the publish workflow with npm Trusted Publishing and a matching v<package-version> tag.
See CHANGELOG.md for release history.
License
MIT © 2026 EveGoodEvening
Source attributions and upstream license declarations are preserved in THIRD_PARTY_NOTICES.md.