Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions .github/workflows/opencode-plugin.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
name: OpenCode plugin

# opencode-genclass (packages/opencode-plugin): typecheck, build and the unit tests (the V1 hooks, the V2 setup on a
# fake context, the digest against a stub bridge, parity with `genclass-mcp hook`), then in a second job the plugin
# in the real OpenCode binaries (test/smoke/run.mjs): opencode-ai@1.19.5 and @opencode/cli@2.2.5 from npm, the
# genclass server listed and connected through the plugin, a project's own genclass entry winning, and on 1.x the
# findings digest reaching a stub model's request. Every check talks to 127.0.0.1 only, besides npm (the binaries
# and @genclass/mcp). A separate workflow from ci.yml so it never blocks the main CI job; it publishes nothing.

on:
push:
paths:
- "packages/opencode-plugin/**"
- "packages/mcp/src/cli.ts"
- "packages/mcp/src/text.ts"
- "packages/mcp/package.json"
- "package-lock.json"
- ".github/workflows/opencode-plugin.yml"
pull_request:
paths:
- "packages/opencode-plugin/**"
- "packages/mcp/src/cli.ts"
- "packages/mcp/src/text.ts"
- "packages/mcp/package.json"
- "package-lock.json"
- ".github/workflows/opencode-plugin.yml"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: opencode-plugin-${{ github.ref }}
cancel-in-progress: true

jobs:
unit:
name: "opencode-genclass: typecheck, build, unit tests"
runs-on: ubuntu-latest
timeout-minutes: 10
env:
ONNXRUNTIME_NODE_INSTALL: skip
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm

- name: Install
run: npm ci --no-audit --no-fund

- name: Typecheck
run: npm run typecheck -w opencode-genclass

- name: Build
run: npm run build -w opencode-genclass

- name: Unit tests
working-directory: packages/opencode-plugin
run: npx vitest run

opencode:
name: "opencode-genclass in OpenCode 1.19.5 and 2.2.5"
needs: unit
runs-on: ubuntu-latest
timeout-minutes: 20
env:
ONNXRUNTIME_NODE_INSTALL: skip
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm

- name: Install
run: npm ci --no-audit --no-fund

- name: Build
run: npm run build -w opencode-genclass

- name: The plugin in the real binaries
run: node packages/opencode-plugin/test/smoke/run.mjs
123 changes: 123 additions & 0 deletions .github/workflows/release-opencode.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
name: Release OpenCode plugin

# Publishes opencode-genclass (packages/opencode-plugin) to npm from a tag `opencode-v<version>` whose version equals
# packages/opencode-plugin/package.json (e.g. opencode-v0.1.0), with npm provenance, the way release-mcp.yml publishes
# @genclass/mcp. Authentication: npm trusted publishing (OIDC, `id-token: write`); no npm token is stored.
#
# Owner setup:
# - First version only: npm configures trusted publishing from a package's own settings page, so the package must exist
# before this workflow can publish it. Push the tag once: the workflow builds, tests and uploads the tarball as the
# `opencode-tarball` artifact, and its publish step fails without a trusted publisher. Publish that exact tarball once
# from your own npm login (`npm publish opencode-genclass-<version>.tgz --access public`), then on npmjs.com:
# opencode-genclass → Settings → Trusted publishing → GitHub Actions: organization genclass-dev, this repository,
# workflow filename release-opencode.yml, environment npm-publish. Later versions publish from here.
# - The npm-publish GitHub environment (shared with release.yml and release-mcp.yml) asks its reviewers to approve.
# - The plugin starts `npx -y @genclass/mcp@<version>` (src/index.ts, kept in step by packages/mcp/test/manifests.test.ts):
# release that version of @genclass/mcp first (release-mcp.yml).

on:
push:
tags: ["opencode-v*"]

permissions:
contents: read

concurrency:
group: release-opencode-${{ github.ref }}
cancel-in-progress: false

jobs:
publish:
name: "opencode-genclass: verify, build, test, publish with provenance"
runs-on: ubuntu-latest
timeout-minutes: 30
environment: npm-publish
permissions:
contents: read
id-token: write # OIDC token for npm trusted publishing and the provenance attestation
env:
ONNXRUNTIME_NODE_INSTALL: skip
steps:
- uses: actions/checkout@v4
with:
ref: ${{ github.ref }}

- uses: actions/setup-node@v4
with:
node-version: 22
registry-url: https://registry.npmjs.org
cache: npm

# trusted publishing needs npm >= 11.5.1 (Node 22 ships npm 10)
- name: npm 11
run: npm install -g npm@11 && npm --version

- name: The tag names the package version, and the server it starts is on npm
run: |
TAG="${GITHUB_REF_NAME#opencode-v}"
PKG=$(node -p "require('./packages/opencode-plugin/package.json').version")
echo "tag $TAG, package.json $PKG"
test "$TAG" = "$PKG"
MCP=$(node -p "require('./packages/mcp/package.json').version")
grep -q "\"@genclass/mcp@$MCP\"" packages/opencode-plugin/src/index.ts
npm view "@genclass/mcp@$MCP" version

- name: Install
run: npm ci --no-audit --no-fund

- name: Typecheck
run: npm run typecheck -w opencode-genclass

- name: Build
run: npm run build -w opencode-genclass

- name: Unit tests
working-directory: packages/opencode-plugin
run: npx vitest run

- name: The plugin in the real OpenCode binaries
run: node packages/opencode-plugin/test/smoke/run.mjs

- name: Pack
id: pack
working-directory: packages/opencode-plugin
run: |
FILE=$(npm pack --silent | tail -1)
echo "file=$FILE" >> "$GITHUB_OUTPUT"
sha512sum "$FILE"
tar -tzf "$FILE" | sort > "$FILE.files.txt"
cat "$FILE.files.txt"
# the built plugin, its README, changelog and licence; no tests or sources
grep -q "package/dist/index.js" "$FILE.files.txt"
grep -q "package/LICENSE" "$FILE.files.txt"
! grep -q "package/test/" "$FILE.files.txt"
! grep -q "package/src/" "$FILE.files.txt"

- uses: actions/upload-artifact@v4
with:
name: opencode-tarball
path: |
packages/opencode-plugin/${{ steps.pack.outputs.file }}
packages/opencode-plugin/${{ steps.pack.outputs.file }}.files.txt
if-no-files-found: error

- name: Publish with provenance
working-directory: packages/opencode-plugin
run: |
VERSION=$(node -p "require('./package.json').version")
case "$VERSION" in
*-*) DIST_TAG=$(echo "${VERSION#*-}" | cut -d. -f1) ;;
*) DIST_TAG=latest ;;
esac
npm publish "${{ steps.pack.outputs.file }}" --provenance --access public --tag "$DIST_TAG"

- name: Verify the registry signature and provenance
run: |
VERSION=$(node -p "require('./packages/opencode-plugin/package.json').version")
mkdir -p "$RUNNER_TEMP/verify" && cd "$RUNNER_TEMP/verify"
npm init -y > /dev/null
for i in $(seq 1 40); do npm view "opencode-genclass@$VERSION" version --prefer-online && break; sleep 20; done
for i in $(seq 1 10); do npm install --no-audit --no-fund --ignore-scripts "opencode-genclass@$VERSION" && break; sleep 30; done
for i in $(seq 1 20); do npm audit signatures && break; echo "attestations not served yet, retry $i"; sleep 30; done
# the published module has one default export with id, setup and server
node --input-type=module -e "import('opencode-genclass').then((m) => { const d = m.default; if (Object.keys(m).join() !== 'default' || d.id !== 'genclass' || typeof d.setup !== 'function' || typeof d.server !== 'function') process.exit(1); })"
48 changes: 48 additions & 0 deletions docs/adoption/listings/opencode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# OpenCode: where GenClass goes, and how

Checked 2026-11-03 against the OpenCode binaries (`opencode-ai` 1.19.5 and `@opencode/cli` 2.2.5 from npm, run in
throwaway HOME directories), the published plugin APIs (`@opencode-ai/plugin` 1.19.5, `@opencode/plugin` 2.2.5) and
anomalyco/opencode at `dev` 79c80c7ca2c0bb24db98670f8fe0c1c0d5133630. opencode.ai was not reachable from the session
(its proxy refused the host), so the documentation pages below are quoted from the session brief's reading of them,
and everything this file says works was run with the binaries. Nothing here has been submitted. The prepared upstream
change and its report: [../contributions/opencode/](../contributions/opencode/README.md).

## Two OpenCode lines

- **OpenCode 1.x**: npm `opencode-ai` (1.19.5), plugin API `@opencode-ai/plugin`, docs at opencode.ai/docs. Config key
`plugin`, MCP servers as a flat `mcp.<name>` map.
- **OpenCode 2.x**: npm `@opencode/cli` (2.2.5), plugin API `@opencode/plugin`, docs at opencode.ai/v2/docs (per the
brief, Homebrew's default formula and Arch install 2.x). Config key `plugins`, MCP servers under `mcp.servers`; the
flat 1.x `mcp.<name>` map still loads (checked: `genclass` listed and connected on 2.2.5).

## What is in place in GenClass

| What | Where | Works today |
|---|---|---|
| The MCP server by JSON | `opencode.json` `mcp.genclass` (`packages/mcp/README.md`, generated from `packages/mcp/src/clients.ts`) | yes, both lines (`npx -y @genclass/mcp@0.2.1`) |
| The MCP server from the command line | `opencode mcp add genclass -- npx -y @genclass/mcp@0.2.1` | yes; 1.19.5 writes the global `~/.config/opencode/opencode.jsonc` (when none exists), 2.2.5 the project's `opencode.json` (`--global` for the global one) |
| The `genclass` skill | `.claude/skills/genclass/` (`npx -y @genclass/mcp@0.2.1 init`) or `.agents/skills/genclass/` (`npx skills add genclass-dev/genclass-plugin -a opencode`, skills CLI 1.7.6) | yes on 1.19.5 (`opencode debug skill` lists it from both); 2.2.5 has no skill listing command, not checked |
| `/genclass-explore <url> <steps>` | `.opencode/commands/genclass-explore.md`, written by `init` when `.opencode/` exists | yes on 1.19.5 (`opencode debug config` lists the command) |
| The plugin `opencode-genclass` | `packages/opencode-plugin`: the server plus new findings in each prompt | not on npm: the owner publishes it (`.github/workflows/release-opencode.yml`, tag `opencode-v0.1.0`; the first version by hand from the workflow's tarball) |

## Where to list it, once `opencode-genclass` is on npm

1. **OpenCode's ecosystem page** (`packages/web/src/content/docs/ecosystem.mdx` in anomalyco/opencode, rendered at
opencode.ai/docs/ecosystem): "Want to add your OpenCode related project to this list? Submit a PR." A Plugins
table, rows appended at the end, links to the plugin's source. Documentation PRs are exempt from the linked-issue
check (CONTRIBUTING.md, "Link Issues When Required"); base on `dev`; title `docs: ...`; the PR template's
sections; "Long, AI-generated PR descriptions and issues may be ignored. Write a short explanation in your own
words." Ready: [../contributions/opencode/upstream.patch](../contributions/opencode/upstream.patch) and
[PR.md](../contributions/opencode/PR.md). No star threshold or promotional-PR rule was found.
2. **awesome-opencode** (github.com/awesome-opencode/awesome-opencode) and **opencode.cafe**: named on the ecosystem
page as the community aggregators. Not prepared in this session (their entry formats were not read); a later
session or the owner adds them after the ecosystem row.
3. **opencode.ai/docs/mcp-servers** ("You can submit a PR if you want to document other servers", per the brief): an
MCP server page entry is possible without the plugin; not prepared here, because a server page there would only
repeat the JSON block, and the plugin row is the stronger entry.

## When OpenCode 2.x becomes npm's `opencode` default

Switch the README's JSON block to `"mcp": { "servers": { "genclass": { "type": "local", "command": [...] } } }` (no
`enabled`; 2.x's field is `disabled`), and say `plugins` before `plugin` in the plugin's README. The plugin itself
already serves both lines from one export.
18 changes: 18 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions packages/mcp/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@

## Unreleased

- **OpenCode: the command-line install and the skill paths, and an `/genclass-explore` command from `init`.** The
OpenCode block (README, `config opencode`, `genclass_setup`) adds `opencode mcp add genclass -- npx -y
@genclass/mcp@<version>` and where each line writes it: OpenCode 1.19.5 to the global configuration
(`~/.config/opencode/opencode.jsonc` when there is none yet, at `mcp.genclass`), OpenCode 2.2.5 to the project's
`opencode.json` at `mcp.servers.genclass` (`--global` for the global one); both checked with the binaries. The
JSON block stays the flat `mcp.genclass` map, which 1.19.5 documents and 2.2.5 still loads (checked: listed and
connected). It also says that OpenCode loads the `genclass` skill from `.claude/skills/` (what `init` writes) and
`.agents/skills/` (`npx skills add genclass-dev/genclass-plugin -a opencode`), both listed by `opencode debug skill`
on 1.19.5. `init` writes `.opencode/commands/genclass-explore.md` when the project has an `.opencode/` directory:
the explore procedure of the skill's section 2 as an OpenCode command (`/genclass-explore <url> <steps>`), with the
`genclass:init` marker in its frontmatter, so a rerun replaces its own file and leaves one without the marker
(1.19.5 lists it in `opencode debug config`). The OpenCode plugin, `opencode-genclass` (packages/opencode-plugin),
pins this package's version and joins `test/manifests.test.ts`.

- **The plugin's repository vendors the server, and the lockfile is gone.** In
[genclass-dev/genclass-plugin](https://github.com/genclass-dev/genclass-plugin), `.mcp.json` and the hook run
`node ${CLAUDE_PLUGIN_ROOT}/server/genclass-mcp.mjs` instead of `npx -y @genclass/mcp@<version>`: `server/cli.mjs`
Expand Down
10 changes: 9 additions & 1 deletion packages/mcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ AI Assistant: Settings, Tools, AI Assistant, Model Context Protocol (MCP), Add,

### OpenCode

`opencode.json` in the project (`~/.config/opencode/opencode.json` for all projects), or `opencode mcp add`:
`opencode.json` in the project (`~/.config/opencode/opencode.json` for all projects):

```json
{
Expand All @@ -281,6 +281,14 @@ AI Assistant: Settings, Tools, AI Assistant, Model Context Protocol (MCP), Add,
}
```

Or from the command line. OpenCode 1.x writes it to the global configuration (`~/.config/opencode/opencode.jsonc` when there is none yet), so use the JSON above for one project; OpenCode 2.x writes the project's `opencode.json` (as `mcp.servers.genclass`; `--global` for the global one):

```bash
opencode mcp add genclass -- npx -y @genclass/mcp@0.2.1
```

OpenCode also loads the `genclass` skill from `.claude/skills/`, where `npx -y @genclass/mcp@0.2.1 init` writes it, and from `.agents/skills/`, where `npx skills add genclass-dev/genclass-plugin -a opencode` installs it.

<!-- install:end -->

Any other MCP client: a stdio server, command `npx`, arguments `-y @genclass/mcp@0.2.1`, no environment variables
Expand Down
Loading