Skip to main content
Version: 0.8.5

OpenCode Integration (Native Claude Skills Spec)

Uses the native Claude skills specification — the same family as Kilo Code (and Pi): OpenCode auto-discovers SKILL.md files under project-local .opencode/skills/, .claude/skills/, and .agents/skills/ (walking up from the working directory to the git worktree root) and under the global ~/.config/opencode/skills/, ~/.claude/skills/, and ~/.agents/skills/, and also accepts explicit skills.paths in opencode.json. Unlike Kilo Code, OpenCode does not honour disable-model-invocation: true — only name, description, license, compatibility, and metadata are recognized skill-frontmatter fields; unknown fields are ignored — so the three skills' explicit-only invocation is reproduced through an opencode.json override. That override is the one real difference from a Kilo Code setup.

Prerequisites

  • Jira auth configured — per-request Basic auth from .jst/jira-sdlc-tools.local.env, no login step (see jira-api-reference.md §9)
  • gh (GitHub CLI) authenticated
  • .jst/jira-sdlc-tools.env and .jst/jira-sdlc-tools.local.env — see project-config.md
  • OpenCode installed (opencode in your PATH).

Install / Wire-up Steps

Everything lives in one project-root opencode.json (the direct analog of Kilo Code's kilo.jsonc). opencode.json must be in the project root — OpenCode does not read it from .opencode/ or any other subdirectory. It does three things at once: points OpenCode at this plugin's skills, keeps the model from auto-invoking them, and registers the explicit slash commands that run them inline. It is a copy-me template, not a committed file — the same decision KILO.md made for kilo.jsonc: a checked-in copy would pin a machine-specific absolute path (and a model id that goes stale); the </PATH> token lets each user substitute their own install location, and the repo stays free of per-machine config.

  1. Create opencode.json in your project root (OpenCode does not read it from .opencode/ or any subdirectory; JSONC opencode.jsonc is also accepted):

    {
    "$schema": "https://opencode.ai/config.json",
    "skills": {
    "paths": ["</PATH>"]
    },
    "permission": {
    "skill": {
    "jira-task-assigner": "deny",
    "jira-task-executor": "deny",
    "jira-task-reviewer": "deny"
    }
    },
    "command": {
    "jira-task-assigner": {
    "description": "Break a feature/task/bug into Jira issues, branches, and worktrees.",
    "subtask": false,
    "template": "Read and execute the jira-task-assigner skill instructions in </PATH>/jira-task-assigner/SKILL.md. $ARGUMENTS"
    },
    "jira-task-executor": {
    "description": "Implement the issue implied by the current worktree's branch end-to-end.",
    "subtask": false,
    "template": "Read and execute the jira-task-executor skill instructions in </PATH>/jira-task-executor/SKILL.md. $ARGUMENTS"
    },
    "jira-task-reviewer": {
    "description": "Review sub-task PRs from the parent issue's worktree.",
    "subtask": false,
    "template": "Read and execute the jira-task-reviewer skill instructions in </PATH>/jira-task-reviewer/SKILL.md. $ARGUMENTS"
    }
    }
    }

    What each block does:

    • skills.paths — points OpenCode's skill discovery at this plugin's skills directory (this is the OpenCode analog of Kilo's kilo.jsonc skills.paths).
    • permission.skill.<name>: "deny" — keeps each of the three skills out of the agent's available-skills list so the model cannot auto-invoke it from ambient chat; this is how OpenCode reproduces disable-model-invocation: true (which it ignores).
    • command.<name> — registers the explicit /<name> slash command that runs the skill inline; its template points the model at the matching SKILL.md, and subtask: false keeps it in the primary session (see Caveats).
  2. Replace </PATH> with the absolute path to this plugin's skills directory on your machine:

    • Local clone (stable, recommended): …/jira-sdlc-tools/plugins/jira-sdlc/skills — the directory that contains the three skill folders plus _shared/.
    • Marketplace install: ~/.claude/plugins/cache/<MARKETPLACE>/jira-sdlc/<version>/skills — this path is version-stamped and changes on reinstall, so it is more fragile than a clone path.
  3. Restart OpenCode (or reload its config) so the new opencode.json, skills, and commands take effect. The three /jira-task-* commands appear in the command list.

    Alternatively, drop a copy or symlink of the three skill folders plus _shared/ into .opencode/skills/ (or .claude/skills/) at your project root so OpenCode discovers them without a paths entry — in which case, drop the skills.paths line and adjust each command's template to the discovered location.

Invoking the Three Skills

Call the explicit slash commands registered above. OpenCode has no plugin namespace, so the commands are bare (not /jira-sdlc:…):

  • /jira-task-assigner — break down a task into Jira issues with branches
  • /jira-task-executor — implement an issue from its worktree
  • /jira-task-reviewer — review sub-task PRs from the parent worktree

Because permission.skill.<name>: "deny" keeps each skill out of the model's available-skills, the model will not auto-trigger these skills on ambient chat — they run only via the commands above.

Platform-Specific Caveats

  • disable-model-invocation: true is not honoured. Recognized skill frontmatter on OpenCode is name, description, license, compatibility, metadata only; unknown fields (including disable-model-invocation) are ignored. The reproduction is two-part: permission.skill.<name>: "deny" keeps each skill out of the agent's available-skills so the model cannot auto-invoke it, and command.<name> provides the explicit /-command. Known gap: OpenCode's "deny" blocks the skill's skill-tool load entirely — it does not distinguish auto- vs. explicit-tool invocation the way Claude's flag does — so the explicit surface comes only from the registered command, not from the skill tool. The net behaviour matches Claude's "explicit-only" intent, but the mechanism is "command-only," not "skill-registered-but-gated." If any user needs a skill callable both ways on OpenCode, that is not reproducible with deny; leave that skill out of the permission.skill block and rely on it being ignored by description only.
  • allowed-tools is also ignored. The skills declare allowed-tools: Bash, Read, Grep, Glob[, Edit], Write, AskUserQuestion in frontmatter (Edit on the executor only); OpenCode does not read this field — which also means the Claude-side AskUserQuestion name in the list is inert here by construction, not a compatibility risk. Tool access during a run is governed instead by OpenCode's own permission config (bash, edit, read, webfetch, etc. → allow / ask / deny). Expect approval prompts for bash / edit / write unless your config allows them up front.
  • subtask: false keeps each run inline (live context). Each command sets subtask: false so it executes in the primary session rather than an isolated subagent; the scripts the skills run then see live session context (recent discussion, in-session variables). With subtask: true — or if the default agent runs in subagent mode — the skill runs in an isolated subagent without that context, which is not what these skills want, since they shell out to scripts that read local env and branch state.
  • No pinned model id. The model field is deliberately omitted from each command, so commands inherit the session / default model instead of pinning a literal that goes stale. Add a model to a command only if you want to pin one; any literal written today will eventually read as stale.
  • The marketplace cache is not auto-discovered. OpenCode discovers the .opencode/skills/, .claude/skills/, and .agents/skills/ trees (project-local, walking up to the git worktree root) plus the ~/.config/opencode/skills/, ~/.claude/skills/, and ~/.agents/skills/ globals — but not Claude Code's ~/.claude/plugins/cache/. A Claude-Code marketplace install of this plugin is therefore not picked up automatically; point skills.paths at the cache path explicitly (version-stamped — see step 2) or use a local clone. (The shared ~/.claude/skills/ global is discovered, so a global drop-in there is seen by both Claude Code and OpenCode.)
  • external_directory may gate reads of skills outside the project. If </PATH> points outside your project root (the marketplace cache, or a clone elsewhere on disk), OpenCode's external_directory permission may prompt before the model reads the SKILL.md. Allow it in your config, or use the drop-in / symlink alternative in step 3 so the skills live inside the project.
  • The skill bodies cross-reference each other as /jira-sdlc:…. Internally the three SKILL.md files refer to sibling skills by the Claude Code plugin namespace (e.g. "re-run /jira-sdlc:jira-task-executor"). Those are prose pointers, not commands OpenCode can invoke; on OpenCode the user re-runs the bare /jira-task-… command instead. (The same namespace-mismatch note applies to drop-in installs — see CURSOR.md Method 2.)
  • Verified in OpenCode. The install and invocation steps were run end-to-end in OpenCode. The config keys, the frontmatter-recognition list, the subtask semantics, and the permission-vs-disable-model-invocation distinction were confirmed working. opencode.json must be in the project root — OpenCode will not read it from any subdirectory.