- Bun v1.0+
- An opencode installation for manual testing
git clone https://github.com/devtheops/opencode-plugin-otel
cd opencode-plugin-otel
bun installInstall dependencies in the checkout with bun install. In the project where you run
OpenCode, create .opencode/plugins/otel/index.ts:
export { default } from "/path/to/opencode-plugin-otel/src/index.ts"OpenCode V2 discovers the directory automatically and loads TypeScript via Bun, so
there is no build step during development. A plugins entry pointing directly to
an absolute .ts file is rejected by OpenCode 2.0.1.
Branching:
maintargets OpenCode V2. The OpenCode V1 plugin is maintained on thev1branch (branched from the last1.xtag) — open V1 bug/security fixes againstv1, notmain.
| Command | Description |
|---|---|
bun run lint |
Run ESLint, including JSDoc formatting checks |
bun run check:jsdoc-coverage |
Enforce minimum JSDoc coverage for exported API declarations |
bun run typecheck |
Type-check all sources without emitting |
bun test |
Run the test suite |
src/
├── index.ts — Plugin entrypoint (V2 default export)
├── plugin.ts — setup(): config, hooks, event subscription
├── state.ts — shared OTel SDK + tracing state
├── types.ts — Shared types (Level, HandlerContext, Instruments, etc.)
├── config.ts — Environment config loading and log level resolution
├── otel.ts — OTel SDK setup, resource construction, instrument creation
├── probe.ts — TCP connectivity probe for the OTLP endpoint
├── util.ts — Utility functions (errorSummary, setBoundedMap)
└── handlers/
├── session.ts — session.created / session.execution.* / session.status
├── step.ts — session.step.* (LLM spans + token/cost metrics)
├── tool.ts — session.tool.* (tool spans, subagents, duration, commits)
├── permission.ts — permission.asked / permission.replied
└── chat-headers.ts — context preview and model.request / WebSocket propagation
The easiest way to verify telemetry is being emitted is to run a local OpenTelemetry collector:
docker run --rm -p 4317:4317 \
otel/opentelemetry-collector:latestThen set OPENCODE_ENABLE_TELEMETRY=1 and start opencode. The collector will print received spans and metrics to stdout.
This project follows Conventional Commits. All commits must be structured as:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
| Type | When to use |
|---|---|
feat |
A new feature (triggers a minor version bump) |
fix |
A bug fix (triggers a patch version bump) |
perf |
A performance improvement |
refactor |
Code change that is neither a fix nor a feature |
test |
Adding or updating tests |
docs |
Documentation only changes |
ci |
CI/CD configuration changes |
chore |
Maintenance tasks (dependency updates, etc.) |
build |
Changes to the build system |
Append ! after the type or add a BREAKING CHANGE: footer:
feat!: drop support for OTLP HTTP
BREAKING CHANGE: only OTLP/gRPC is supported going forward
feat(handlers): add support for file.edited event
fix(probe): handle malformed endpoint URL without throwing
docs: update Datadog configuration example
chore(deps): bump @opentelemetry/api to 1.10.0
- Fork the repo and create a branch from
main:git checkout -b feat/my-feature - Make your changes and ensure
bun run lint,bun run check:jsdoc-coverage,bun run typecheck, andbun testpass - Commit using Conventional Commits format
- Open a pull request with a clear, human-readable title and link any related issues in the description
Releases are handled via GitHub Actions. See the release workflow. To cut a release, push a version tag:
git tag v1.2.3
git push origin v1.2.3The version bump should follow SemVer based on the commits since the last release:
fixcommits → patch (1.0.x)featcommits → minor (1.x.0)BREAKING CHANGEcommits → major (x.0.0)