Replayable Autoresearch Ledger
July 17, 2026 ยท View on GitHub
The Go SDK exposes Autohand's persisted autoresearch engine through typed
JSON-RPC methods. A session proposes focused changes, evaluates each candidate,
records immutable measurements and decisions under .auto/, and can replay or
rescore earlier attempts without losing their original evidence.
Use a CLI build that supports autoresearch RPC methods. When CLI versions may
vary, check SDK.SupportedAgents or the low-level supported-command surface
before presenting autoresearch in your application.
Start or resume
started, err := agent.StartAutoresearch(ctx, &autohand.AutoresearchStartParams{
Objective: "Reduce checkout p95 latency without changing behavior",
MaxIterations: 12,
MetricName: "p95_ms",
MetricUnit: "ms",
Direction: autohand.AutoresearchLower,
MeasureCommand: "go test ./... -run BenchmarkCheckout -bench . -count 5",
ChecksCommand: "go test ./...",
FilesInScope: []string{"checkout/", "internal/cache/"},
Sampling: &autohand.AutoresearchSamplingOptions{
MinSamples: 3,
MaxSamples: 7,
ConfidenceThreshold: 0.9,
},
Constraints: []autohand.AutoresearchConstraint{{
MetricName: "error_rate",
Operator: autohand.AutoresearchConstraintLessThanOrEqual,
Threshold: 0,
}},
})
if err != nil {
return err
}
if !started.Success {
return fmt.Errorf("start autoresearch: %s", started.Error)
}
Calling StartAutoresearch for an existing paused session resumes its persisted
configuration. StopAutoresearch pauses the loop without deleting .auto/.
The returned Instruction is the loop prompt. Run it through the normal agent
stream when your host, rather than the CLI command surface, owns each iteration:
run, err := agent.Send(ctx, started.Instruction, nil)
if err != nil {
return err
}
events, err := run.Stream(ctx)
For the slash-command workflow, use agent.Autoresearch(ctx, objective, nil).
Inspect persisted evidence
status, err := agent.GetAutoresearchStatus(ctx)
history, err := agent.GetAutoresearchHistory(ctx)
for _, attempt := range history.Attempts {
fmt.Printf("%s replayable=%t pinned=%t state=%s\n",
attempt.AttemptID,
attempt.Replayable,
attempt.Pinned,
attempt.Materialization,
)
}
Each replayable attempt may contain its latest AutoresearchEvaluationRecord
and AutoresearchDecisionRecord. Samples retain all configured metrics;
aggregates use median and median absolute deviation so hosts do not need to
reconstruct summaries from console output.
Replay, rescore, compare, and Pareto
Replay evaluates a candidate in an isolated worktree:
original, err := agent.ReplayAutoresearch(ctx, &autohand.AutoresearchReplayParams{
AttemptID: candidate.AttemptID,
Evaluator: autohand.AutoresearchEvaluatorOriginal,
})
current, err := agent.ReplayAutoresearch(ctx, &autohand.AutoresearchReplayParams{
AttemptID: candidate.AttemptID,
Evaluator: autohand.AutoresearchEvaluatorCurrent,
})
Rescore reuses persisted measurements and appends a decision from the current policy. The constructors make the mutually exclusive selection explicit:
one, err := agent.RescoreAutoresearch(ctx,
autohand.AutoresearchRescoreAttempt(candidate.AttemptID))
all, err := agent.RescoreAutoresearch(ctx,
autohand.AutoresearchRescoreAll())
Compare two attempts and inspect the constraint-passing, non-dominated frontier:
comparison, err := agent.CompareAutoresearch(ctx, &autohand.AutoresearchCompareParams{
LeftAttemptID: "attempt-1",
RightAttemptID: "attempt-2",
})
pareto, err := agent.GetAutoresearchPareto(ctx)
Pin and prune safely
Pin artifacts that must survive retention:
_, err := agent.PinAutoresearch(ctx, &autohand.AutoresearchPinParams{
AttemptID: candidate.AttemptID,
Pinned: true,
})
Pruning previews by default. Apply only after showing the candidate list and receiving explicit confirmation:
dryRun := true
preview, err := agent.PruneAutoresearch(ctx, &autohand.AutoresearchPruneParams{
DryRun: &dryRun,
})
dryRun = false
applied, err := agent.PruneAutoresearch(ctx, &autohand.AutoresearchPruneParams{
DryRun: &dryRun,
Yes: true,
})
Events and hooks
The event stream includes AutoresearchLifecycleEvent for start, status, and
pause notifications, plus AutoresearchOperationEvent for history, replay,
rescore, compare, Pareto, pin, and prune progress.
switch event := event.(type) {
case autohand.AutoresearchLifecycleEvent:
fmt.Printf("autoresearch %s: %s\n", event.Phase, event.StatusText)
case autohand.AutoresearchOperationEvent:
fmt.Printf("autoresearch %s %s success=%t\n",
event.Operation, event.Phase, event.Success)
}
Hook constants cover the full lifecycle from HookEventAutoresearchStart
through HookEventAutoresearchComplete and HookEventAutoresearchError.
See examples/27-autoresearch-ledger for
an end-to-end runnable workflow.