Thanks for contributing. This repo has strict local-only behavior and regression guardrails, so please follow this workflow.
- Prefer opening an issue before starting features, bug fixes, refactors, or behavioral changes.
- If you already have a fix ready, opening an issue and PR together is fine.
- When an issue exists, link it in the PR description using
Fixes #<issue>orRefs #<issue>. - If no issue exists, include a short rationale/scope summary in the PR description.
- GitHub Issue Forms are enabled and blank issues are disabled.
- Use
.github/ISSUE_TEMPLATE/bug_report.ymlfor bug reports. - Use
.github/ISSUE_TEMPLATE/feature_request.ymlfor feature requests. - Use template title prefixes for consistent issue titles.
- Inactive issues may be marked stale after 23 days and closed 7 days later if there are still no updates.
- Bug title format:
[bug]: <short description> - Feature title format:
[feature]: <short description> - Pull requests use
.github/pull_request_template.mdand should include tested OpenCode version details.
- The published package runtime supports Node.js
>=20.0.0(matchespackage.jsonengines). - Repository development uses pnpm v11, which requires Node.js
>=22for the pnpm CLI. - Enable the pinned package manager and install dependencies with:
corepack enable
corepack prepare pnpm@11.0.0 --activate
pnpm installpnpm install runs prepare, which installs Husky hooks.
Pre-commit hooks currently run:
pnpm exec lint-staged(formats staged files via Prettier)pnpm run typecheckpnpm test
Pre-push hooks currently run:
pnpm install --frozen-lockfile
Run checks manually before opening a PR:
pnpm run typecheck
pnpm test
pnpm run buildUse pnpm run test:watch for local iteration. Use pnpm run build:check when you need the build plus package dry-run check.
PR and main pushes trigger .github/workflows/ci.yml (CI workflow):
- Job:
pnpm-qualityon Node22.x - Steps:
pnpm install --frozen-lockfile,pnpm run typecheck,pnpm run build,pnpm test, thenpnpm pack --pack-destinationto upload the package tarball artifact - Job:
runtime-smokeon Node20.xand22.x - Runtime smoke installs the packed package as a consumer with npm and verifies the default import,
./serverimport,./tuiexport resolution with the packageddist/tui.tsxpayload, plusengines.node >=20.0.0
Release workflow .github/workflows/publish-npm.yml runs on release/manual dispatch and uses pnpm for version sync, install, typecheck, build, and test before publishing. It keeps npm publish --access public only for the npm registry publish step.
Recommended settings for main:
- Require a pull request before merging.
- Require branches to be up to date before merging.
- Require status checks from workflow
CIforpnpm-qualityand everyruntime-smokematrix entry. - Select checks exactly as GitHub displays them in repository settings.
- Typical names look like
pnpm-quality,runtime-smoke (20.x),runtime-smoke (22.x)orCI / ...variants. - Block direct pushes to
mainfor non-admin users.
- Never invoke an LLM/model API to compute toast/report output. Everything must remain local and deterministic.
- Deterministic slash commands are dual-surface:
- the TUI dialog/palette path renders local dialogs and must not call
session.prompt(); - the server/web/desktop path registers
cfg.command, injects ignored/no-reply output withsession.prompt({ noReply: true, ignored: true }), and must throwhandled()so OpenCode does not continue intoprompt(...).
- the TUI dialog/palette path renders local dialogs and must not call
- Server/web/desktop slash commands (
/quota,/quota_status,/quota_announcements,/pricing_refresh,/tokens_*) must route throughbuildQuotaDialogCommandOutput(); do not duplicate command-output logic insrc/plugin.ts. - The handled-sentinel path can surface popup/log noise until upstream adds a clean cancellation API; keep docs aligned with anomalyco/opencode#18554 and anomalyco/opencode#18559.
- Keep
handled()/isCommandHandledError(...)tests aligned with the server/web/desktop handled-sentinel boundary. injectRawOutput()is shared by server/web/desktop slash commands and the servertool.quota_statuscompatibility path. Do not reuse it for TUI dialog command output.- Keep
tests/plugin.command-handled-boundary.test.ts,tests/tui-smoke.test.ts, andtests/command-handled.test.tsaligned with these invariants.
Additional boundary tests to keep healthy when touching plugin/provider logic:
tests/plugin.qwen-hook.test.tstests/quota-provider-boundary.test.ts
When adding a provider, keep the README setup wording tied to real behavior.
- For API-key/token providers that support
Existing OpenCode auth, global config, or env, start fromcontributing/provider-template/. - Copy the template files to the target paths listed in
contributing/provider-template/README.md. - Replace the example names, ids, env vars, and config keys before coding.
- Add tests for each supported auth source before using the shared README wording; do not leave copied template tests skipped, todo-only, or unresolved.
- In the PR checklist, state whether you started from the provider template; if not, explain why it does not apply.
- Do not use that wording for OAuth-only providers such as OpenAI.
- Prefer the smallest safe fix that addresses the root cause.
- Align behavior with current OpenCode production behavior rather than adding extra hook/output mutation layers.
- Preserve existing invariants and update/add boundary tests when behavior contracts change.
- We appreciate PRs that verify the fix against the current production released OpenCode version and note the tested version in the PR.
- Linked issue (
Fixes #...orRefs #...) when available, or included a short no-issue rationale in the PR. pnpm run typecheckpasses.pnpm testpasses.pnpm run buildpasses.- Verified behavior against the current production released OpenCode version, and included the tested version in the PR notes.
- Updated docs when user-facing commands/config/workflow changed (usually
README.md; update this file when contributor workflow changes). - For new API-key/token providers, started from
contributing/provider-template/or explained why the template does not apply. - For provider setup/auth wording changes, checked
contributing/provider-template/and verified README wording against implementation/tests.