npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@raindrop-ai/opencode-plugin

v0.3.1

Published

Raindrop observability plugin for OpenCode — automatic session/event/span tracing

Readme

@raindrop-ai/opencode-plugin

Raindrop observability plugin for OpenCode with automatic session, event, and span tracing.

Install

pnpm add @raindrop-ai/opencode-plugin @opencode-ai/plugin

If your integration also uses the OpenCode SDK directly, install @opencode-ai/sdk as well.

Projects

If your org has multiple projects, route telemetry to a specific one by setting its slug via the RAINDROP_PROJECT_ID env var or the project_id key in ~/.config/opencode/raindrop.json (or project-level .opencode/raindrop.json):

{
  "project_id": "support-prod"
}

This sets the X-Raindrop-Project-Id header on every outbound request. Leave it unset (or use "default") to use your org's default Production project — the existing behavior. Single-project orgs need nothing new.

Payload size limits

Text fields (event input/output, span prompt/response and tool payloads) are capped at 1,000,000 characters per field and truncated with a ...[truncated by raindrop] marker. The cap is enforced before (or during) serialization, so oversized payloads cost the cap — not the payload — on the OpenCode host's event loop, and large events land truncated instead of being rejected at the ingest size limit. Hook error logs are rate-limited to one line per failure family per 30s so a persistent error can't flood the host's output.

Tool catalog capture (ai.prompt.tools)

OpenCode's step events carry no tool list, so the plugin cannot see the exact tools each model request was given. Instead it records the host's tool catalog for the step's model:

  • v1 plugin (@raindrop-ai/opencode-plugin): on the first step of a session for a given provider/model, the plugin calls client.tool.list({ query: { provider, model } }) (OpenCode's experimental /experimental/tool endpoint) once, caches the answer per session and model, and stamps it as ai.prompt.tools on every step span. The lookup is deduplicated while in flight, bounded by a 2s timeout, and never surfaces errors to OpenCode: when it fails, the attribute is simply absent.
  • v2 plugin (@raindrop-ai/opencode-plugin/v2): the v2 host has no per-model catalog endpoint; the plugin reads the registered tool list (ctx.tool.list(), after every plugin's tool.transform) with the same caching, timeout and no-throw rules.

Because this is OpenCode's catalog for that model, not the exact per-request set, catalog-derived spans also carry ai.prompt.tools.source = "opencode.tool.list". An explicit override (below) is exact and carries no source. Each element of ai.prompt.tools is a JSON document {"type":"function","name":…,"description"?:…,"inputSchema"?:<JSON Schema>}; a tool whose schema is not plain JSON Schema is recorded without inputSchema rather than with an invented one. The plugin has no separate content switch (prompts and responses are always recorded; only the system prompt is opt-in), so the catalog is recorded whenever tracing is on. Absent attribute = catalog unknown; [] = no tools.

tools override

Overrides the tool catalog recorded as ai.prompt.tools on every model span. Use when the integration cannot see the tools the model was given. The override replaces the catalog entirely (tools: [] records an empty catalog) and skips the catalog lookup.

raindrop.json (user- or project-level):

{
  "tools": [
    {
      "name": "get_weather",
      "description": "Get the current weather",
      "parameters": { "type": "object", "properties": { "city": { "type": "string" } }, "required": ["city"] }
    }
  ]
}

Programmatic options (v1 plugin(input, { tools }), v2 raindrop({ tools })) take precedence over the config file. Any recognized declaration shape is accepted (OpenAI {type:"function",function:{…}}, Anthropic input_schema, plain {name, description, parameters}, …).

Correlating per-message feedback signals

Each Raindrop event uses a client-generated event_id that isn't predictable from the outside. To let you attach a signal (e.g. a per-message thumbs up/down) to the right event, every finalized event carries the OpenCode assistant message id as properties.message_id (the msg_... of the turn's final assistant message). The same id is set as the message_id attribute on the turn's root span.

Given a msg_..., look up the event whose properties.message_id matches it, then send its event_id to /v1/signals:

// finalized event payload (track_partial)
{
  "event_id": "…",            // random, generated client-side
  "ai_data": { "convo_id": "ses_…" },
  "properties": { "message_id": "msg_…" }  // ← correlate on this
}

OpenCode v2 plugin API

OpenCode's newer plugin API (@opencode/plugin, @opencode/sdk v2) is served by the @raindrop-ai/opencode-plugin/v2 subpath. Use it instead of the default export when running against the v2 plugin host:

// opencode.json
{ "plugin": ["@raindrop-ai/opencode-plugin/v2"] }
npm install @raindrop-ai/opencode-plugin @opencode/plugin

The v2 entry exposes the plugin object plus a raindrop handle (users.identify, signals.track, currentEventId(sessionID), flush, shutdown). Configuration, event/tracing semantics, and payload bounds are the same as the v1 entry. @opencode/plugin and @opencode/sdk are optional peer dependencies — v1 users install neither.

Self-diagnostics

The plugin can inject a __raindrop_report tool that lets the agent flag serious, unrecoverable problems for developer review. When the agent calls it, a self diagnostics - <category> signal is posted to signals/track, attached to the session's currently-open turn event. The tool is invisible to the end user — its output is a bare acknowledgement and the model is instructed never to mention it.

Enable it via raindrop.json (~/.config/opencode/raindrop.json or .opencode/raindrop.json), or set RAINDROP_SELF_DIAGNOSTICS=true to override just the enabled flag:

{
  "self_diagnostics": { "enabled": true }
}

For the v2 host API, pass the option directly:

import raindrop from "@raindrop-ai/opencode-plugin/v2";

export default raindrop({ selfDiagnostics: { enabled: true } });

Optional signals (custom category → { description, sentiment? } map), guidance (extra instructions appended to the tool prompt), and tool_name / toolName overrides are supported. The built-in categories are:

  • missing_context — blocked on information or access the user cannot provide
  • repeatedly_broken_tool — a tool failed across multiple distinct attempts
  • capability_gap — the task needs a tool/permission/capability the agent lacks
  • complete_task_failure — the agent genuinely could not deliver what was asked

Signals only ship to the cloud destination, so the tool is not registered in local-only mode (no RAINDROP_WRITE_KEY).

Notes

  • @opencode-ai/plugin is required for the default (v1) export; @opencode/plugin for /v2.
  • @opencode-ai/sdk and @opencode/sdk are optional peer dependencies.
  • Tests live in the nested tests/ package and validate HTTP payloads and tracing behavior.

Application Git identity

OpenCode does not treat the edited project directory or ambient deploy/CI metadata in the plugin process as the agent-under-test revision. By default the new canonical application revision is unknown. Configure an app_git object in raindrop.json using commit_sha, commit_dirty, and ordinary branch, set RAINDROP_COMMIT_SHA / RAINDROP_COMMIT_DIRTY / RAINDROP_BRANCH, or set an explicit source_directory (or RAINDROP_GIT_SOURCE_DIRECTORY) that identifies the agent-under-test checkout. Set app_git to false to opt out. Automatic canonical branch discovery is off unless detect_branch is true.