Skip to content

Latest commit

 

History

History
241 lines (206 loc) · 13.7 KB

File metadata and controls

241 lines (206 loc) · 13.7 KB

OpenCode host

AgentsMD supports the OpenCode 1.18.32 CLI interface on POSIX hosts. The adapter checks that exact version and its required flags before a model run. Other versions need compatibility proof before this support claim expands. Provider availability is independent of host support; select an exact provider/model for each run. No model becomes a global default.

Instructions and Skills

OpenCode composes project AGENTS.md found while walking up from its working directory with global $XDG_CONFIG_HOME/opencode/AGENTS.md, defaulting to ~/.config/opencode/AGENTS.md; OPENCODE_CONFIG_DIR selects a custom global directory. CLAUDE.md is a project fallback, and ~/.claude/CLAUDE.md is a global fallback when the OpenCode global file is absent. Configured instructions add further sources. AgentsMD does not edit that configuration. See the official instruction rules.

OpenCode loads Skills on demand from $OPENCODE_CONFIG_DIR/skills/<name>/SKILL.md, defaulting to ~/.config/opencode/skills, and also from the shared ~/.agents/skills and ~/.claude/skills directories. Link AgentsMD Skills only into the OpenCode directory. Codex and Grok Build scan ~/.agents/skills, and Grok scans ~/.claude/skills, so shared links duplicate every Skill on a host that already uses the plugin. The skills command group below creates and removes those owned links. Verify available names with opencode debug skill in the intended repository. See official Skill discovery. Host-native frontmatter differs. OpenCode ignores unrecognized fields. AgentsMD Skills are model-invocable on every host, with approval gates inside each Skill body.

The global contract requires the full Project Direction triad before project work. OpenCode runs no Codex lifecycle hook, so the AgentsMD plugin below delivers the same loader payload in the system prompt instead. Without that plugin, a fresh session must read those files and applicable project instructions explicitly. The bounded adapter includes this obligation in its handoff prompt. It also requires current canonical instruction identity and adjacent private preferences. Use the shared setup walkthrough for initialization, discovery checks and the explicit reading fallback.

Install, update, status and uninstall

Use AGENTSMD_DIR for an extracted released artifact or stable canonical checkout of a released tag. The source must be a regular global/AGENTS.md outside plugin caches. Release identity is verified through the distribution workflow; the link command verifies path ownership and bytes, not GitHub release status.

"$AGENTSMD_DIR/bin/agentsmd-opencode" install --source "$AGENTSMD_DIR/global/AGENTS.md"
"$AGENTSMD_DIR/bin/agentsmd-opencode" status --source "$AGENTSMD_DIR/global/AGENTS.md"
"$AGENTSMD_DIR/bin/agentsmd-opencode" update --source "$AGENTSMD_DIR/global/AGENTS.md"

Commands emit JSON including source and target hashes when readable. Install and update initialize adjacent private preferences only when absent. Shared path checks reject cache-bound sources and targets. Ownership means a symlink's absolute lexical destination exactly matches the explicitly supplied canonical source. Status distinguishes missing, regular-file, other-path, broken-link, divergent-link, cache-bound-link, and owned-link. A broken link also reports whether its destination is owned. Only a healthy owned link returns status exit code zero. A regular file containing identical bytes is still user-owned and preserved.

Install creates a missing link or verifies an already-correct link. Update can repair a broken owned link. When an extracted release changes the source path, identify the previous canonical release explicitly:

"$AGENTSMD_DIR/bin/agentsmd-opencode" update \
  --source "$AGENTSMD_DIR/global/AGENTS.md" --previous-source "$PREVIOUS_AGENTSMD_DIR/global/AGENTS.md"
"$AGENTSMD_DIR/bin/agentsmd-opencode" uninstall --source "$AGENTSMD_DIR/global/AGENTS.md"

Update refuses any target that is not the exact previous owned link. Uninstall removes only the exact supplied owned link, including a broken owned link. There is no force replacement option in this adapter. For an authorized migration, the common agentsmd-global-instructions install --host opencode --source "$AGENTSMD_DIR/global/AGENTS.md" --replace preserves a recoverable backup. Source files, shared Skills, opencode.json, opencode.jsonc, preferences and credentials remain in place. Start a fresh OpenCode session after a supported install or update.

Skill links

skills install creates one owned symlink per Skill directory that holds a SKILL.md, named after that directory, under $OPENCODE_CONFIG_DIR/skills, otherwise $XDG_CONFIG_HOME/opencode/skills, defaulting to ~/.config/opencode/skills. The command resolves that directory exactly as the instruction link resolves its own.

"$AGENTSMD_DIR/bin/agentsmd-opencode" skills install --source "$AGENTSMD_DIR/skills"
"$AGENTSMD_DIR/bin/agentsmd-opencode" skills update --source "$AGENTSMD_DIR/skills"
"$AGENTSMD_DIR/bin/agentsmd-opencode" skills status --source "$AGENTSMD_DIR/skills"
"$AGENTSMD_DIR/bin/agentsmd-opencode" skills uninstall --source "$AGENTSMD_DIR/skills"
opencode debug skill

Each entry reports one of the instruction link's states: missing, regular-file, other-path, broken-link, divergent-link, cache-bound-link and owned-link. The ownership rule is the same: a symlink whose absolute lexical destination exactly matches the supplied Skill directory. Install creates missing links and verifies existing owned links. It never replaces an existing entry of any kind. Each entry is decided on its own, as the instruction link decides its single target, so a blocked entry is preserved and reported while the remaining Skills still install, and the command exits 2. Uninstall removes only exact owned links, including a broken owned link, and exits 2 when any entry was not an owned link. Status exits 0 only when every Skill is an owned link.

Update installs and verifies the current inventory first. Only after that succeeds does it retire exact owned links whose source no longer contains SKILL.md. A blocked replacement or empty source preserves the old links. This migrates the former separate skills to the single Operations bundle without removing unrelated installations. Repeat updates are safe.

Install reports the Skills present in the source directory. Status and uninstall also report any target entry whose link destination is exactly <source>/<name>, so an owned link survives removal of its source Skill and uninstall still removes it. Install and update require an existing source directory.

Sources inside plugins/cache are rejected, including a single Skill directory that resolves into a plugin cache; that entry is refused before any link is created. A target is rejected when the Skill directory resolves under ~/.agents/skills, ~/.claude/skills, ~/.grok/skills or a plugins/cache path. Codex and Grok Build scan ~/.agents/skills, and Grok scans ~/.claude/skills, so links there would list every Skill twice on a host that already uses the plugin. Skill links do not expand the bounded run contract, which stays pinned to 1.18.32. Run opencode debug skill in a fresh session in the intended repository and confirm each AgentsMD Skill appears exactly once.

Plugin link

plugin install creates one owned symlink named agentsmd-project-direction.js under $OPENCODE_CONFIG_DIR/plugins, otherwise $XDG_CONFIG_HOME/opencode/plugins, defaulting to ~/.config/opencode/plugins. The command resolves that directory exactly as the instruction and Skill links resolve their own. The source is the canonical clone or released artifact root, or its opencode/agentsmd-project-direction.js file.

"$AGENTSMD_DIR/bin/agentsmd-opencode" plugin install --source "$AGENTSMD_DIR"
"$AGENTSMD_DIR/bin/agentsmd-opencode" plugin status --source "$AGENTSMD_DIR"
"$AGENTSMD_DIR/bin/agentsmd-opencode" plugin uninstall --source "$AGENTSMD_DIR"

OpenCode loads that module and the plugin appends the Project Direction block to the model's system prompt on every request in the session's working directory. It runs bin/project-direction hook --host opencode beside the link's canonical target with a synthetic SessionStart input, so OpenCode receives the payload the Codex hook emits, including the not_in_repository and uninitialized verdicts. Any loader failure leaves the system prompt unchanged and logs one agentsmd-project-direction: line to stderr. Start a fresh OpenCode session after install; a running session keeps its loaded plugins.

The plugin uses experimental.chat.system.transform, which is experimental in OpenCode 1.18.32, the version the bounded run adapter pins. The plugin context exposes no host version, so the pin is documented, not enforced at runtime. Treat a different OpenCode version as unproved until the seam is rechecked.

The entry reports the Skill links' ownership states: missing, owned-link, divergent-link, regular-file, other-path and broken-link. Install creates a missing link and verifies an existing owned link. It never replaces an existing entry of any kind; a foreign entry is preserved and reported, and the command exits 2. Status exits 0 only for a healthy owned link.

Install alone validates the source. It rejects a path holding any symlinked component and requires a regular plugin file at <clone root>/opencode/agentsmd-project-direction.js beside a regular <clone root>/bin/project-direction, because the plugin runs the loader of its own clone. Status and uninstall derive ownership from the lexical link destination only, so an owned link stays reportable and removable after the clone was removed, emptied, altered or replaced by an alias. Uninstall removes any owned entry and nothing else. Sources under plugins/cache, a cache-bound target and a file under another name or outside an opencode directory are rejected everywhere, because those checks are lexical.

Bounded implementation run

The coordinator supplies the complete Issue scope, accepted decisions, exact base and dependency state, and granted authority in a prompt file. Repository root and starting HEAD must match before dispatch. The base must be an exact available commit. The output directory must not exist.

"$AGENTSMD_DIR/bin/agentsmd-opencode" run \
  --cwd "$ISSUE_WORKSPACE" \
  --issue https://github.com/OWNER/REPO/issues/NUMBER \
  --base "$EXACT_BASE_SHA" --head "$EXACT_HEAD_SHA" \
  --model "$EXACT_PROVIDER_MODEL" --permissions configured \
  --prompt-file "$TASK_PROMPT" --output "$NEW_RECEIPT_DIRECTORY" --timeout 900

configured preserves OpenCode's configured permissions with closed stdin. auto adds --auto only when that tool mode has been granted; explicit OpenCode denials remain effective. Neither mode is a sandbox or a grant of production, credential, merge, release or installation authority. Use an exclusive task workspace and scoped host permissions. The adapter inherits the host environment and lets OpenCode use its existing authentication; it never reads credential files or writes configuration. See the official CLI contract.

Each run starts a new session and writes a private directory containing raw JSON events, stderr, extracted text and receipt.json. Raw model/tool output can contain private task data, so review it before publishing. The receipt records Issue, working directory, exact base and before/after HEAD, requested model and permission mode, prompt hashes, version, timestamps, process exit status, session IDs, result, working-tree status and evidence hashes. It does not dump the environment. Timeout terminates the process group and records failure. Malformed events, host errors, missing session/text evidence and nonzero exit status cannot produce a candidate. A candidate is an unreviewed implementer result. The coordinator verifies scope, model/session evidence, exact-SHA proof, review and external authority independently.

Proof and remaining host differences

python3 -m unittest tests.test_opencode -v tests isolated HOME/XDG ownership, config and credential preservation, lifecycle transitions, Skill and plugin link install, repeat install, preserved user entries, uninstall and rejected shared directories, explicit CLI arguments, stale-head refusal, malformed events, errors and timeout. It uses a fake CLI and spends no model quota. python3 -m unittest tests.test_opencode_plugin -v runs the plugin module under Node against a fixture repository and asserts that the appended system entry equals the loader payload byte for byte, that an installed link resolves the canonical loader, and that an unreachable or failing loader leaves the system prompt unchanged. It skips when node is absent. The full repository and versionctl suites remain the deterministic release gates.

Issue #78 separately requires one requested fresh-session fixture using the real CLI and an authorized model. Record version, selected model, global and project instruction composition, full Project Direction hashes, shared Skill discovery, fixture read/write result and exact HEAD. That fixture proves only the exercised integration. User-owned behavioral Live Verification through ordinary work on real projects remains separately pending until user evidence exists, as defined by root AGENTS.md.

OpenCode does not reproduce Codex app-native task coordination, memory, connectors, computer/browser UI tools or lifecycle hooks. The plugin covers system-prompt delivery only; it reproduces no UserPromptSubmit or subagent refresh semantics. Host-native tools and permissions remain OpenCode's responsibility; AgentsMD supplies the shared operating contract and the narrow CLI handoff.