Help us shape the future of Go! Take the 2026 Go Developer Survey

opencode

package
v0.17.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 13, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Overview

Package opencode implements the OpenCode adapter for agentsync.

Package opencode implements the OpenCode adapter for agentsync.

settings.go: JSONC-aware merge for opencode.json. Uses tailscale/hujson to PARSE JSONC (comments + trailing commas) so a hand-edited opencode.json is not rejected. NOTE: the merged result is re-emitted as plain JSON — comments and trailing commas are NOT preserved (see MergeJSONC). Foreign keys/values are preserved; only the formatting/comments are lost. Comment-preserving mutation is deferred to v1.x (matches the README "Known limits").

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IngestMCPSpec

func IngestMCPSpec(raw map[string]any) source.MCPServerSpec

IngestMCPSpec translates one OpenCode-native MCP server spec — the value under opencode.json `/mcp/<id>` — into the canonical MCPServerSpec. It is the exact inverse of opencodeMCPSpec (Render). Exported so reconcile's key-level write-back reconstructs an opencode MCP server through the SAME translation the adapter uses, rather than assuming the dest shape matches the canonical model (it doesn't: command is an array, env is `environment`, type is local/remote).

func MergeJSONC

func MergeJSONC(existing []byte, ours map[string]any, ownedPointers []string) ([]byte, error)

MergeJSONC merges ours into existing JSONC content, removing ownedPointers no longer present in ours. Foreign keys and values are preserved.

Thin wrapper over the shared jsonkeys.MergeJSONC engine (hujson parse → Standardize → MergeKeys → plain-JSON emit; comments are NOT preserved — see its doc and the README "Known limits").

Types

type Adapter

type Adapter struct {
	// contains filtered or unexported fields
}

Adapter implements adapter.Adapter for OpenCode.

func New

func New(opts Options) *Adapter

New constructs an OpenCode adapter.

func (*Adapter) Apply

func (a *Adapter) Apply(ops []adapter.FileOp, w adapter.DestWriter) error

Apply routes every destination write through the supplied DestWriter rather than calling iox.AtomicWrite directly. This is the contract that keeps the foreign-collision backup guarantee honest — see the doc on adapter.DestWriter.

func (*Adapter) Detect

func (a *Adapter) Detect() (bool, error)

func (*Adapter) Ingest

func (a *Adapter) Ingest(scope adapter.Scope, project string) (source.Canonical, error)

Ingest reads OpenCode's native config files and returns a partial source.Canonical. It is the inverse of Render.

Round-trip notes:

  • Subagent `mode` (primary/all/subagent) is PRESERVED into the canonical frontmatter. The canonical `source.Subagent.Frontmatter` is a free-form map, so an OpenCode-specific key round-trips without a schema change; the render side re-emits an ingested `mode` verbatim, so a native primary/all agent is no longer demoted to subagent on the next apply.
  • Subagents still lose the Claude-side `tools`/`color` fields (dropped on render because OpenCode has no equivalent). Ingest reconstructs only what is present on disk.
  • Only agentsync-OWNED agents/commands are captured (see destOwned): the agents/ and commands/ directories are shared with the user's own hand-authored files, which are left untouched and never pulled into the canonical source.

func (*Adapter) IngestMCPSpec added in v0.15.0

func (a *Adapter) IngestMCPSpec(raw map[string]any) source.MCPServerSpec

IngestMCPSpec satisfies adapter.MCPSpecIngester by delegating to the package translator Ingest uses, so the dialect has exactly one definition.

func (*Adapter) KeyMergeStrategy

func (a *Adapter) KeyMergeStrategy() string

KeyMergeStrategy is opencode's single key-merge strategy: JSONC (opencode.json), which MUST be merged via hujson, not strict JSON.

func (*Adapter) Name

func (a *Adapter) Name() string

func (*Adapter) Render

func (a *Adapter) Render(r secrets.Resolved, scope adapter.Scope, project string) ([]adapter.FileOp, []adapter.Skip, error)

Render converts the resolved canonical into FileOps for OpenCode.

func (*Adapter) SetStderr

func (a *Adapter) SetStderr(w io.Writer)

SetStderr replaces the warning sink the adapter writes Ingest warnings to, so a CLI command can route adapter warnings through the same styled writer it uses for its own output. See claude.Adapter.SetStderr for the contract.

func (*Adapter) VersionRoots added in v0.7.5

func (a *Adapter) VersionRoots(scope adapter.Scope, project string) []string

VersionRoots implements adapter.VersionedDirs: ~/.config/opencode (its config dir) plus ~/.claude/skills (the shared Claude skills dir OpenCode also writes to). The apply tail de-nests + de-dups across adapters, so when Claude is also enabled, ~/.claude/skills is captured by Claude's ~/.claude repo instead of getting its own. Returns nil at project scope.

type Options

type Options struct {
	TargetRoot string // honors AGENTSYNC_TARGET_ROOT (real "/Users/x" in production)
	// LookPath overrides exec.LookPath for testing. nil means use exec.LookPath.
	LookPath func(file string) (string, error)
	// Stderr receives Ingest warnings (lenient-YAML notices, dropped components).
	// nil means os.Stderr.
	Stderr io.Writer
}

Options configure the adapter at construction.

type Paths

type Paths struct {
	ConfigDir       string // ~/.config/opencode
	Settings        string // ~/.config/opencode/opencode.json (user) or <proj>/opencode.json (project)
	AgentsDir       string // ~/.config/opencode/agents (user) or .opencode/agents (project)
	CommandsDir     string // ~/.config/opencode/commands (user) or .opencode/commands (project)
	ClaudeSkillsDir string // ~/.claude/skills user / <proj>/.claude/skills project — SHARED with Claude, read by OpenCode too (see doc above)
	Memory          string // AGENTS.md path
}

Paths resolves the destination paths for a given (scope, project, target-root).

Skills go to the SHARED Claude directory (ClaudeSkillsDir: ~/.claude/skills at user scope, <project>/.claude/skills at project scope), NOT to a dedicated .opencode/skills / ~/.config/opencode/skills. This is a deliberate, verified choice: per OpenCode upstream docs (https://opencode.ai/docs/skills/) OpenCode scans BOTH its own skills dirs AND the Claude ones — globally ~/.config/opencode/skills, ~/.claude/skills, and ~/.agents/skills; per-project .opencode/skills, .claude/skills, and .agents/skills. Because a skill is identical between Claude and OpenCode, agentsync renders it ONCE to the shared ~/.claude/skills that both harnesses read, rather than duplicating byte-for- byte copies into a second OpenCode-only tree (which would double the on-disk footprint and the drift surface). So `.opencode/skills` is intentionally unused, not overlooked. (docs/capability-matrix.md OpenCode notes.)

func ResolvePaths

func ResolvePaths(targetRoot, project string, projectScope bool) Paths

ResolvePaths returns the Paths for the given target root and optional project. projectScope=true + non-empty project uses project-local .opencode/ dirs.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL