Skip to content
Merged
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
33 changes: 33 additions & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Check OpenCode plugin

on:
pull_request:
push:
branches: [main]
workflow_dispatch:

permissions:
contents: read

jobs:
check:
runs-on: ubuntu-latest
strategy:
matrix:
opencode: ["1.15.11", "1.18.35"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
- run: npm ci
- run: npm run check
- name: Check generated standalone plugin
run: git diff --exit-code -- assets/opencode/plugins/render.ts
- name: Install OpenCode CLI
run: npm install --prefix "$RUNNER_TEMP/opencode-cli" --no-audit --no-fund "opencode-ai@${{ matrix.opencode }}"
- name: Test packed npm package and GitHub installer in OpenCode
run: npm run test:integration
env:
OPENCODE_BIN: ${{ runner.temp }}/opencode-cli/node_modules/.bin/opencode
41 changes: 32 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ Until the package is published to npm, install the local OpenCode plugin, skills
curl -fsSL https://raw.githubusercontent.com/render-oss/render-opencode-plugin/main/install.sh | bash
```

This writes files to `~/.config/opencode/`:
The installer requires Node.js 18+ or Bun. It writes files to OpenCode's config directory: `$OPENCODE_CONFIG_DIR` when set, otherwise `$XDG_CONFIG_HOME/opencode`, otherwise `~/.config/opencode/`:

- `plugins/render.ts`
- `skills/render-*/SKILL.md`
- `commands/deploy-to-render.md`
- `commands/check-render-status.md`
- `agents/render.md`

The installer doesn't overwrite existing files unless you pass `--force`:
On upgrades, unchanged bundled files update automatically and obsolete bundled files are removed. A tracking manifest records installed file hashes; known unchanged files from version 0.1.0 are also recognized. Your modified files and unrelated files are preserved. Use `--force` to replace modified files:

```bash
curl -fsSL https://raw.githubusercontent.com/render-oss/render-opencode-plugin/main/install.sh | bash -s -- --force
Expand Down Expand Up @@ -62,7 +62,9 @@ Add the npm package to your OpenCode config:
}
```

OpenCode installs npm plugins with Bun at startup and caches them in `~/.cache/opencode/node_modules/`. This flow requires the package to be published to npm.
OpenCode installs npm plugins with Bun at startup and caches them in its XDG cache directory (normally `~/.cache/opencode/node_modules/`). This flow requires the package to be published to npm.

Choose either the GitHub plugin or the npm plugin. When switching from GitHub to npm, remove the installed `plugins/render.ts`; OpenCode loads local and npm plugins independently and would otherwise run both validation hooks.

## Installing skills, commands, and the agent

Expand All @@ -74,14 +76,14 @@ Run the explicit setup command after adding the plugin:
npx @render/opencode-plugin setup
```

This opt-in step writes files to `~/.config/opencode/`:
This opt-in step uses the same config-directory defaults as the GitHub installer and writes:

- `skills/render-*/SKILL.md`
- `commands/deploy-to-render.md`
- `commands/check-render-status.md`
- `agents/render.md`

The setup command doesn't overwrite existing files unless you pass `--force`.
Rerun setup after updating the npm package to upgrade the bundled skills, commands, and agent. Unchanged installed files update automatically, obsolete bundled files are removed, and your edits are preserved. Use `--force` to replace modified files.

```bash
npx @render/opencode-plugin setup --force
Expand Down Expand Up @@ -125,11 +127,17 @@ This merges the following server into `opencode.json`:
}
```

Set `RENDER_API_KEY` in your environment before using Render MCP.
Set `RENDER_API_KEY` in the environment of the process that launches OpenCode, then verify the connection:

```bash
opencode mcp list
```

The generated configuration uses API-key authentication with OAuth disabled. Setup preserves an existing `mcp.render` entry, including disabled or custom authentication settings, unless you pass `--force`.

## Setting up the Render CLI

The plugin can validate Blueprints with the Render CLI.
The plugin validates Blueprints with the Render CLI. Render CLI 2.28.0 is tested with this plugin.

1. Install the Render CLI:

Expand All @@ -143,13 +151,17 @@ brew install render
render login
```

3. Verify access:
3. Select the workspace used for validation and verify access:

```bash
render workspace set <workspace-id>
render whoami -o json
render blueprints validate ./render.yaml --output json
```

If `render whoami -o json` fails, fix authentication before relying on live Render workflows in OpenCode.
For API-key authentication, set `RENDER_API_KEY` instead of running `render login`. You can also set `RENDER_WORKSPACE` to select the workspace without changing saved CLI configuration. OpenCode must inherit these environment variables. Validation sends the Blueprint to Render for checking; it does not create or deploy resources.

The plugin passes the requested filename explicitly and resolves relative paths from the OpenCode session directory. It validates after `write`, `edit`, and `apply_patch` changes, including moved files, and skips reads and deletions. The explicit validation tool runs once per invocation.

## Using the plugin

Expand Down Expand Up @@ -187,6 +199,17 @@ Verify the package before publishing:
npm run check
```

`npm run build` generates `assets/opencode/plugins/render.ts` from the same source as the npm plugin. Commit that generated file; do not edit it directly. Both installers use `assets/setup.mjs` for copying, upgrade tracking, and MCP configuration.

Install the OpenCode CLI and run the packaged integration tests:

```bash
npm install --prefix /tmp/render-opencode-cli opencode-ai@1.18.35
OPENCODE_BIN=/tmp/render-opencode-cli/node_modules/.bin/opencode npm run test:integration
```

The tests pack and install the npm package, exercise its executable, and start isolated OpenCode servers for both installation flows. A local scripted model and fake Render CLI test skills, command delegation, filename resolution, and validation hooks without model charges or Render credentials. CI runs the suite against OpenCode 1.15.11 and 1.18.35. Set `OPENCODE_INTEGRATION_KEEP=1` to retain temporary test artifacts.

## License

MIT. See [LICENSE](LICENSE).
97 changes: 97 additions & 0 deletions assets/legacy-assets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
{
"version": 1,
"release": "0.1.0",
"files": {
"agents/render.md": "f42e605266a0d7ab63742947cc355240e4e5dcd132a0bc753e72de466e1ef6b2",
"commands/check-render-status.md": "151f5486e6d98de77ca887cd78a3a4974a0de2a9ea9583882a3a7e48a92f0bd1",
"commands/deploy-to-render.md": "0f538b22278bbe51936328ddae331ed9015d924736ba4fc86674d0a1afffd26f",
"plugins/render.ts": "eec3c2057cf8132af815ac90a1de9ef384fd13179b841244b43418f75791753f",
"skills/render-background-workers/SKILL.md": "fd9959a0c5d9271a504619ba4d15a1fd2904545e72323afd6863fa90a3e5f273",
"skills/render-background-workers/references/graceful-shutdown.md": "54f352641990b797c348d88b5d4b5264038498d67a58f5acd3cc19b31ba40387",
"skills/render-background-workers/references/queue-framework-setup.md": "1d887bdee550f5267b8d8573978ac9c5cb2051a563ea6d3623a49de1911a73ac",
"skills/render-blueprints/SKILL.md": "70ce7fae4f13ddd53402ab42dc30d66dafa8f8e75060a0976e8879d361febc79",
"skills/render-blueprints/references/common-mistakes.md": "0a3107c8451f0c84f52f315e15192f93073709fcf83cfd993cc1a63587a64445",
"skills/render-blueprints/references/field-reference.md": "809e6ee5af86d396626e33c969691ba2a49c1d306c2fea8a3626e3355b05794a",
"skills/render-blueprints/references/preview-environments.md": "a42e2e1db3897fa0bbe6e5da2bc549361c130d3faa88485e907e8672d095820d",
"skills/render-blueprints/references/wiring-patterns.md": "fa950b248129a7256c3ee4bcfc4c07a145ff103c327905c43c9caf03103de718",
"skills/render-cli/SKILL.md": "92a67216566df7f243b718aa88b6790d5b6205b33c66788bccfb2b697a29f418",
"skills/render-cli/references/command-cheatsheet.md": "384ded822a3e9b1bc1f69d7dacdfcc50f78263834aab8aa39d2afb8eeaf4c23c",
"skills/render-cron-jobs/SKILL.md": "19c2e2986049b2ae11799e3d2a8e746095ed0ac3ee313ea4b8ac1126bf86a195",
"skills/render-cron-jobs/references/cron-patterns.md": "d0af830f2c04285957e326253b5b2b29ac26f7586608ea62a68d609e8c6a0dbf",
"skills/render-cron-jobs/references/migration-from-scheduler.md": "2e5256e3ce4cb9a550fb7c852e4298d5a98913d750cec7358cb013f94158df31",
"skills/render-debug/SKILL.md": "412c2cff904fbdff6bb561ed18583e64ae6ab172d2979f1cc34464374cf04d91",
"skills/render-debug/references/database-debugging.md": "56074ca16ad9c7ddcd54406d28cc8191361154441ba9ea3c26b2233e839cc0cc",
"skills/render-debug/references/error-patterns.md": "181adb011f797dea7a8e803ba305f66b2d6276af0a9017c1e944679714882809",
"skills/render-debug/references/log-analysis.md": "0794530dbf7171035794d570929974f071983ec70d0d00f2f3028ce7c630d3ee",
"skills/render-debug/references/metrics-debugging.md": "b1aced9c341013f4860845914ccf628d9553f50745894ffd989b5b55433c25f5",
"skills/render-debug/references/quick-workflows.md": "2fd73b7a9d3fa228bd25edfb9b93e510a99af1f760714a43244c560d20276d56",
"skills/render-debug/references/troubleshooting.md": "e7e1076db7c50d620809ec47764e459d2b95b0f59d248afcdb0287f90515a306",
"skills/render-deploy/SKILL.md": "e5104c536096f19f8ba1d0a46a277fc0e87fde76fd39fa4a45ced044e42935f8",
"skills/render-deploy/assets/docker.yaml": "3fd98d72fc490df5c2a57ee5ddb3997347d31ea72ac68035f6442e787a19e091",
"skills/render-deploy/assets/go-api.yaml": "fed7f5f2f59dc98cfc505533177d7b35dd3a993e6a93d0a6be1fae59a676af0b",
"skills/render-deploy/assets/nextjs-postgres.yaml": "0c3d482632b88c0e5f3dc620d32b06216b356205b1fd988f69b6fc69ee41d2d3",
"skills/render-deploy/assets/node-express.yaml": "1785a380074f7439e983f0cd50381559fd804a76c56f8d2da7d988a30ac8b519",
"skills/render-deploy/assets/python-django.yaml": "ce9e540e8cff7171557223044f61a83a058f0012831d07f99750cac70a4e236c",
"skills/render-deploy/assets/static-site.yaml": "d0a7df7c7a987049ec3609c28f1fdeef8e2e01f534c64372c6079746df286ac1",
"skills/render-deploy/references/blueprint-spec.md": "52cdb41c930c22ec5578c2e56cef33ffbba910ef6c72de57965908be7ec54139",
"skills/render-deploy/references/codebase-analysis.md": "54c4fe84ae50a4b358f7c9048dfcd68f9eddd88ddfbe24c50b4be7949dc9f6a7",
"skills/render-deploy/references/configuration-guide.md": "41070d43ab849759b09f0c2bf463bacabf7ae3044343e7c78f3e33b7ff38a886",
"skills/render-deploy/references/deployment-details.md": "fa6aa90a707494fcc9438b65829ef4891b9ed03c1cf69d6323fbd997b1f6782a",
"skills/render-deploy/references/direct-creation.md": "3b148def3c12061582229599616b680f57972c86a8782e22a765cf261ec80adc",
"skills/render-deploy/references/error-patterns.md": "b5556cdd3ba832e8f33602cf207cd80872df9c89ed17fe92129a56903176675b",
"skills/render-deploy/references/post-deploy-checks.md": "bd1e3e24abe6c9eb63164ac8ada9b285ceaffbd1722f58bbc1d3d94af4c59911",
"skills/render-deploy/references/runtimes.md": "285b66f9fbb7b20195be80d3bc91bdfc82944c779debbffad85f08ba338b414f",
"skills/render-deploy/references/service-types.md": "2e95dab603df7f692d1e403431985dba88303d490507623165369c0c7b4c2b22",
"skills/render-deploy/references/troubleshooting-basics.md": "f999b13fc56ff62ccf6eec593d0e4cee94e52dec27a815e40d68532bf558a4ca",
"skills/render-disks/SKILL.md": "12d9bb7f5db6eb964e12584bc25d2d7006e53d04c75c178146c4d18acef5ebf3",
"skills/render-disks/references/sizing-and-snapshots.md": "91f75261c62caa2d8827cfcad216a0718ff997458b47daa7b67e762ad08b2282",
"skills/render-docker/SKILL.md": "dc892116e86904a6336dad6e801c9f0acc6431a60ab646599c78070aa167c288",
"skills/render-docker/references/dockerfile-patterns.md": "cc0255c7f8ef1da6a120b44d169a34b301b81a96018260b1491513d23a4a7dee",
"skills/render-docker/references/optimization-guide.md": "9f86683edf8b7a9b49d1030f2742b2355079189fd5b6fd73d2eb17a086ce67fd",
"skills/render-docker/references/registry-setup.md": "758a6af56fb49e08345121e87fee1786ac167da0dd865807af5bf01540efb4ef",
"skills/render-domains/SKILL.md": "ef6dc4bd1c66b87c15a66679a8a8b8eb584f874ec2b8fcb8403588d01e30f91b",
"skills/render-domains/references/dns-configuration.md": "74fce3662688ad8d82da77ab0ac784c7da9898e1f0b3f45ac93a309986fbd06a",
"skills/render-env-vars/SKILL.md": "ed9182eb9983aa07d3b19aca9c85da7b1d743280077b7363aec576e8c9c3a249",
"skills/render-env-vars/references/platform-variables.md": "1aa9dee6543cbe2415a592dd243fb8875484df32f8b9b4b6d8aad99c1520f96e",
"skills/render-env-vars/references/wiring-reference.md": "d9142f8f94edff7226231194a3637f1f25f91579314ae6b625dedbd70daad9cb",
"skills/render-keyvalue/SKILL.md": "c9e72f9fbbaa7c0e004774ac09ecf91a7d9e85d0b282574bbfc60c578cbab856",
"skills/render-keyvalue/references/connection-examples.md": "d569bf0c06d0ec4a548537a869a63fb794ebca5ae18d222ed3735ab9fbf8c70a",
"skills/render-keyvalue/references/troubleshooting.md": "7a22bdd8d6256bebf2fa5df02aa192389e8f676a5aae13a6ec8ebd2d686e5cb4",
"skills/render-mcp/SKILL.md": "0034cbba6e97c895efd5cf3400947a628f064949383a8e003a52241449d6a8bd",
"skills/render-mcp/references/troubleshooting.md": "3210fb908bb22ceffef9fc3fe0999314724eb9bbe07e1e80f68725757099c507",
"skills/render-migrate-from-heroku/SKILL.md": "03634b5a7ad35d98b9eab63b293a422e81cd406a314ae573c32f11e07dd2c0c5",
"skills/render-migrate-from-heroku/references/blueprint-example.md": "03952bb581ccf98b6dda59736103ad24f7ebf36feb4f26134327cbc673e289bc",
"skills/render-migrate-from-heroku/references/buildpack-mapping.md": "70efd55e8059bb130c4487acef860028758d5aeebb68f8c0e187feb3975e95a6",
"skills/render-migrate-from-heroku/references/data-migration.md": "7fbb0a09b7f2884f9c22ce1568ef7fbff3394d6992e4db23fbac638a7206c190",
"skills/render-migrate-from-heroku/references/mcp-setup.md": "c0336d1c9761be36662dc5b605273852b63da9559fdc7186b9c0d72cf03855d0",
"skills/render-migrate-from-heroku/references/preflight-checklist.md": "8c11c40cc8289bdf2bac9c8570e58b88975bf362b7ef1cf479d1efc886064447",
"skills/render-migrate-from-heroku/references/service-mapping.md": "c1ff1e178b2ac43f97756d9d22f70a502ac79a6e396d6c4ef49a1997a97a1b5c",
"skills/render-monitor/SKILL.md": "17f1b66a73bab95209182828f4442fc11b6bcf1ef0cc4714e473b6c307ce0e8b",
"skills/render-monitor/references/metrics-guide.md": "2957ba36ff7f595627685278ee6bf440be8c6b8f501d077863dfcba08915eada",
"skills/render-networking/SKILL.md": "abf617735c016c444e183b4edfcaacbcc2263c5a744de291e3baa6ff27865e0e",
"skills/render-networking/references/communication-patterns.md": "1f1f32c3c5f3a24bd6d572638a869c9ae198aa25030068fd357bd79d0a7b7cb2",
"skills/render-networking/references/troubleshooting.md": "522c8d45c53fb0b0e4b0ad6603cf8b87a5a66578ad475d8e5b573f6d9f834dfa",
"skills/render-postgres/SKILL.md": "bf12cea2449e74870841ae28c540bee97ac1a979125b51160ff547a8a72b5609",
"skills/render-postgres/references/backup-and-recovery.md": "c53c61ec76b3a4c2385b6c713fac6284a778178c06b14b0b31b16bf61f87bc00",
"skills/render-postgres/references/connection-guide.md": "1fbcb0cc9fc9c7d7a07b05c1393839ef9dd489b409d1c09dd2b03c1144688f39",
"skills/render-postgres/references/performance-tuning.md": "0b215c4fa702e54a988d2b2e95fc1404f198b099fac890577e64f8dd160ac051",
"skills/render-private-services/SKILL.md": "c2abc9b0663fe23837084ef6ba642fa5dce9f481fad3d160c2c920461a4d8d5c",
"skills/render-private-services/references/patterns.md": "1367babfd6ad092772b69372893f41061d54b1beb228205628d3d629d4370b72",
"skills/render-scaling/SKILL.md": "d9741ad68172e7e476bb08d1f2ecede357209eec8e4c1b3b6f8a2d2b9daabad3",
"skills/render-scaling/references/autoscaling-guide.md": "d3e171860bd2e8fbf2bdcf5391e80357947e42db243ad7431da38fdc484fdd1a",
"skills/render-scaling/references/instance-types.md": "fd44fbb18fecbe276a4f1d0d2e21f438bb52d6a213042ae61934a72165647dde",
"skills/render-static-sites/SKILL.md": "5d927eb5a89770aabd19034771925d643272d4b42aa4368035072a453b7a6a69",
"skills/render-static-sites/references/framework-configs.md": "69e686b2505599fbda0e9ab7149703cc64834352570a2c0e0d946303cfcc75fa",
"skills/render-static-sites/references/routing-and-headers.md": "309af4b48a91f6fc7b92599eb4a23817040fe1b48807b1328bcd376d356f4940",
"skills/render-web-services/SKILL.md": "4ce0323558f56635994018f5f80824b7d2be98cee52df0ec8a10f89b79f85186",
"skills/render-web-services/references/custom-domains.md": "ddeca625a4545d4d58f70505f1f1390903377ee74fa185ff233ac812cfd8cc37",
"skills/render-web-services/references/deploy-lifecycle.md": "f798b49c5b80b908151e833b8649f0f966af4c933dd2dcd30e1bee3598195256",
"skills/render-web-services/references/health-check-patterns.md": "dcd9e317aa262b2debcacef1990cb1472c27d2833415f964ce1d5e19087043e9",
"skills/render-workflows/SKILL.md": "b682cba179c244ae4c64a6f7b2f45fa50ecad8836f423a39d020a50cf94de773",
"skills/render-workflows/references/local-development.md": "54bcaa96eefffdabb45ed60a6e10d860c23232fdfae253dfb134b05b83e22e1e",
"skills/render-workflows/references/manual-scaffolding.md": "a0fff3a2704da17e6559de41622b399f0f747dc79f0c6e24c187662b81adb66e",
"skills/render-workflows/references/quick-reference.md": "e160a91db989d27560194a7ebebabecfce5b863f3be10399d17619b9f0080044",
"skills/render-workflows/references/task-patterns.md": "456acdf32d1bed89e933f81f5458d8b0bbf2eb81c1985cce3671cacfee7cab61",
"skills/render-workflows/references/troubleshooting.md": "acd0b028c533f7ac242215005a6f33e65ba7c8141af2de7474047d1259a2e56e"
}
}
Loading
Loading