feat(sdk-go): add harness package for CLI-based coding agent dispatch#271
Merged
feat(sdk-go): add harness package for CLI-based coding agent dispatch#271
Conversation
Implements the Go equivalent of the Python SDK's harness subsystem, enabling structured output extraction from external coding agents (opencode, claude-code) via subprocess execution. New harness/ package: - Provider interface with OpenCode and ClaudeCode implementations - Runner with schema validation, retry logic, and transient error handling - Schema utilities: prompt suffix generation, cosmetic JSON repair, stdout fallback extraction, follow-up prompt construction - CLI subprocess execution with timeout and environment management Agent integration: - HarnessConfig on agent.Config for default provider settings - agent.Harness() method mirrors Python SDK's .harness() API - Lazy-initialized runner with per-call option overrides Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Contributor
Performance
✓ No regressions detected |
Provider fixes validated through end-to-end testing: - opencode: use -p flag (not "run" subcommand), -c for cwd, -q for quiet mode; model is config/env-based not a CLI flag - claude-code: unset CLAUDECODE env var to allow spawning from within a Claude Code session - cli: support unsetting env vars (empty value = remove from env) Add examples/go_harness_demo with structured output extraction test for both providers. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Member
|
Will get on this. Should we also think about clearing python garbage collection? |
Contributor
Author
already did/merged XD |
…, SDK conventions - Remove dead package-level sync.Once/Runner variables (cross-agent contamination risk) - Guard CleanupTempFiles against '.' directory (destructive file deletion) - Replace bare log.Printf with configurable Runner.Logger (matches SDK convention) - Fix context cancellation leak in schema retry loop - Fix StructToJSONSchema to use reflect for proper type inference - Replace bubble sort with sort.Slice in extractJSONBlocks - Handle json.MarshalIndent errors in BuildPromptSuffix/BuildFollowupPrompt - Move isExecNotFound/truncate helpers from opencode.go to cli.go - Add provider name constants (ProviderOpenCode, ProviderClaudeCode) - Document env empty-string-means-unset convention - Document mergeOptions zero-value override semantics - Document cosmeticRepair brace-counting limitations - Tighten writeSchemaFile directory permissions (0o755 → 0o700) - Remove unused variable in runner_test.go - Update .env.example to use generic placeholders - Add loadEnv production-use note in demo
santoshkumarradha
approved these changes
Mar 16, 2026
Member
santoshkumarradha
left a comment
There was a problem hiding this comment.
Code Review — Approved ✅
All 18 findings from the initial review have been addressed:
CRITICAL (2/2 fixed)
- ✅ Removed dead package-level
sync.Once/*Runnervariables — eliminated cross-agent contamination risk - ✅ Guarded
CleanupTempFilesagainst"."directory — prevents destructive file deletion in shared workspaces
HIGH (5/5 fixed)
- ✅ Replaced all
log.Printfcalls with configurableRunner.Logger(defaults toio.Discard) — matches existing SDK convention (agent.gousescfg.Logger) - ✅ Fixed
StructToJSONSchemato usereflectfor proper type inference (string/int/float/bool/slice/struct) - ✅ Fixed context cancellation leak in schema retry loop — now returns immediately on
ctx.Done() - ✅ Documented
cosmeticRepairbrace-counting limitations - ✅ Replaced bubble sort with
sort.SliceinextractJSONBlocks
MEDIUM (7/7 fixed)
- ✅ Documented env empty-string-means-unset convention in
RunCLIandOptions.Env - ✅ Documented
mergeOptionszero-value override semantics - ✅ Moved
isExecNotFound/truncatefromopencode.gotocli.go - ✅ Added provider name constants (
ProviderOpenCode,ProviderClaudeCode) - ✅ Added error handling for
json.MarshalIndentinBuildPromptSuffix/BuildFollowupPrompt - ✅ Tightened
writeSchemaFiledirectory permissions (0o755→0o700) - ✅ Added production-use note to demo's
loadEnvfunction
LOW (4/4 fixed)
- ✅ Updated
.env.exampleto use generic placeholders - ✅ Removed unused
origExecutevariable inrunner_test.go - ✅ Added godoc to
agent/harness.go - ✅ Documented
math/randauto-seed behavior
Verification
go build ./...✅go vet ./...✅go test -race ./harness/...— 50 tests pass, race detector clean ✅- Full SDK test suite — 405 pass, 2 pre-existing failures in
aipackage (unrelated) ✅
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
harness/package to the Go SDK that enables dispatching tasks to external coding agents (opencode, claude-code) via subprocess execution with structured output extractionHarnessConfigandagent.Harness()method for seamless integrationWhat's included
New
sdk/go/harness/package (7 files)provider.go—Providerinterface andOptionsstruct with sensible defaultsopencode.go— OpenCode CLI provider (subprocess withopencode run)claudecode.go— Claude Code CLI provider (subprocess withclaude --print --output-format json)runner.go— Main orchestration: provider dispatch → schema validation → retry loop, with transient error detection and exponential backoffschema.go— Prompt suffix generation, JSON Schema file management, cosmetic JSON repair, stdout fallback extraction, follow-up prompt constructioncli.go— Subprocess execution with timeout, environment merging, ANSI strippingresult.go—RawResult,Result,FailureType,MetricstypesAgent integration (
sdk/go/agent/)harness.go—HarnessConfigtype, lazyHarnessRunner(), andagent.Harness()convenience methodagent.go— AddedHarnessConfigtoConfigstruct andharnessRunnerfield toAgentTest plan
go test ./...— all 6 packages green)🤖 Generated with Claude Code