Skip to content

ADR: Harness support for opencode #137

Description

@savitharaghunathan

Context

The harness today is coupled to goose in three places:

  1. Lifecycleinternal/goose/lifecycle.go starts goose serve, translates
    LLM credentials to goose-specific env vars (GOOSE_PROVIDER, GOOSE_MODEL,
    ANTHROPIC_API_KEY, etc.), and manages the process.

  2. Skill discovery — PR ✨ Symlink skills dir for native goose discovery #136
    symlinks .agents/skills/opt/skills so
    goose's native skill platform finds mounted SkillCards. This path
    (.agents/skills) is goose-specific. opencode uses a different convention.

  3. ACP protocolinternal/acp/ implements the ACP WebSocket protocol
    (JSON-RPC over WS). goose implements ACP natively. opencode does not — it
    would need an adapter or a different integration path.

ADR 0001 already anticipates multiple runtimes (layer 1.5 runtime images:
agent-base-goose, agent-base-opencode) and states that subagent delegation
is a runtime concern. But the harness has no abstraction for swapping runtimes.

Questions to resolve

  • Lifecycle interface: What does the harness need from a runtime? Start,
    health check, stop, port. Should this be a Go interface the harness calls, or
    a process convention (binary name, env vars, exit codes)?

  • Skill delivery: goose scans $HOME/.agents/skills and <cwd>/.agents/skills.
    What does opencode scan? Do we need per-runtime symlink targets, or is there a
    shared convention (e.g., Agent Skills spec directories)?

  • ACP compatibility: Does opencode support ACP? If not, what's the
    integration path — ACP adapter sidecar, stdin/stdout, HTTP API? The harness
    tee (ADR 0008) assumes ACP for live viewer streaming and HITL.

  • Prompt assembly: The harness builds a single prompt from context layers
    and sends it via ACP. If a runtime doesn't support ACP, how does the prompt
    reach the agent?

  • Rules (from ADR: Skill loading and prompt assembly #135): type: rule SkillCards need to be always-loaded in the
    prompt regardless of runtime. The mechanism (env var like KONVEYOR_RULES,
    .goosehints, or runtime-agnostic config file) should work across runtimes.

  • Provider credentials: providerEnv() maps KONVEYOR_LLM_* to
    goose-specific env vars. opencode likely expects different var names. Should
    this mapping live in the harness or in the runtime image?

Goose-specific surface area

Area Goose coupling opencode equivalent
goose serve Binary + CLI flags ?
GOOSE_PROVIDER / GOOSE_MODEL Env vars ?
ACP WebSocket Native support ?
.agents/skills/ Native skill discovery ?
.goose/ state dir gitignore'd ?
--with-builtin developer CLI flag ?
.goosehints Runtime-specific config ?

Expected output

An ADR documenting:

  • The runtime abstraction boundary (what the harness expects vs. what the runtime provides)
  • How skill delivery works across runtimes
  • How ACP or an alternative protocol handles observability and HITL
  • Whether provider credential mapping belongs in the harness or the image

Metadata

Metadata

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions