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

opencode-session-start

v0.1.0

Published

OpenCode plugin that runs a project's dev:start script once per active session.

Readme

opencode-session-start

OpenCode plugin that runs bun run dev:start once per session in each plugin/directory-instance activation when the session directory's package.json defines that script. Projects without the script are left untouched.

The lookup uses the session's exact directory; it does not walk up to a parent package.json. dev:start must terminate promptly. Use it to start or signal long-running work through a supervisor or background manager rather than running a foreground dev server, which would keep the first prompt waiting indefinitely.

For example, Rift Command delegates its long-running dev server to a user service, so its launcher returns promptly:

{
  "scripts": {
    "dev:start": "systemctl --user start app-name.service"
  }
}

Lifecycle and session behavior

OpenCode reads the local directory URL as a package, resolves this package's main entry (./src/index.ts), and asks Bun to import it dynamically. Path plugins must export an id, as this plugin does. With tuple configuration, OpenCode passes the tuple's object to the plugin's server(input, options) function.

Plugin initialization happens once per OpenCode directory instance. This plugin's session and startup tracking uses in-memory Set and Map state, so it is local to that instance and process and lasts only until the instance is disposed or the process exits. Separate OpenCode processes can therefore start the same project independently.

For each session:

  • Every newly created session starts dev:start once, including root, forked, child, and subagent sessions.
  • Existing or resumed root and child sessions do not emit session.created. Their first user message during the current plugin/directory-instance activation starts and awaits dev:start.
  • Creating a session without sending a message still starts the command. Output injection, if enabled, waits for that session's first user message.
  • Later messages in the same activation neither rerun startup nor receive its output again.
  • Different session IDs are tracked independently.

OpenCode dispatches session.created hooks without awaiting them. The plugin immediately records the resulting startup promise. OpenCode awaits chat.message hooks before persisting the user message, so an immediate first message awaits the same run and can receive the synthetic output part without starting a duplicate. Startup failure does not fail the first prompt.

Passive viewing or loading of an existing session cannot trigger startup: an OpenCode server plugin receives neither a session.created event nor a chat.message hook merely because a session is opened. Startup occurs when that existing session's first message is sent. Switching away from and back to a session in the same backend instance does not rerun startup. After the plugin instance or backend restarts, in-memory tracking is empty, so the first message sent to an existing session runs startup again. Multiple OpenCode processes maintain independent state and may each run startup for the same session.

Install

The commands below add this checkout's absolute local URL as a string entry while preserving other entries in the plugin array.

Install globally:

opencode plugin 'file:///home/david/Coding/adaptive/opencode-session-start' --global

This writes the global configuration at ~/.config/opencode/opencode.json or ~/.config/opencode/opencode.jsonc.

Install for the project from the target project's directory:

opencode plugin 'file:///home/david/Coding/adaptive/opencode-session-start'

This writes configuration under .opencode in the project worktree. It reuses an existing opencode.json or opencode.jsonc there, preferring JSON if both exist, and otherwise creates opencode.json.

The plugin has no external runtime dependency at present, and OpenCode does not install dependencies for a local URL. No build or bun install step is required merely to load this checkout.

Manual configuration

Add the URL to the appropriate global or project plugin array. OpenCode also reads project configuration from a root-level opencode.json or opencode.jsonc. Keep every existing plugin entry:

{
  "$schema": "https://opencode.ai/config.json",
  "plugin": [
    // Existing plugin entries remain here.
    "file:///home/david/Coding/adaptive/opencode-session-start",
  ],
}

The CLI also adds a string entry. To set options, replace only this plugin's string with a tuple:

{
  "$schema": "https://opencode.ai/config.json",
  "plugin": [
    // Existing plugin entries remain here.
    [
      "file:///home/david/Coding/adaptive/opencode-session-start",
      {
        "enabled": true,
        "verbosity": "normal",
        "injectOutput": false,
      },
    ],
  ],
}

Options:

  • enabled: enables startup behavior. Default: true.
  • verbosity: silent writes no OpenCode logs, normal logs completion and errors, and debug also logs skipped projects and command startup. Allowed values: silent, normal, or debug. Default: normal.
  • injectOutput: appends a synthetic text part containing the exit code and captured stdout/stderr to the first user message that consumes startup output. It does not create another message or model turn. Default: false.

The first message associated with startup waits for dev:start whether output injection is enabled or disabled. Output is captured in memory, so launcher commands should keep stdout and stderr concise.

Validate configuration

Run validation from the project whose effective configuration you want to inspect:

opencode --pure debug config

This skips external plugin loading and checks configuration schema and resolution without plugin bootstrap side effects. To resolve and load plugins as well, run:

opencode debug config

The second command can trigger plugin bootstrap side effects. Inspect its output and OpenCode logs rather than relying only on a successful exit code, because some plugin load failures may be skipped.

Restart requirements

Fully restart the OpenCode backend after changing configuration or options, adding or removing the plugin, updating the checkout, or editing its TypeScript source. There is no filesystem watcher that reliably reloads these changes. Opening a new tab or session is not sufficient.

Update safely

The local URL points directly to this checkout, so update the checkout in place rather than adding another plugin entry. If dependencies or the lockfile changed, run bun install; otherwise it is only needed for development checks. Validate the effective configuration, then fully restart the OpenCode backend.

Remove safely

There is no remove command in the inspected OpenCode version. Remove this plugin's string or tuple from the relevant plugin array without removing other entries, validate the configuration, and fully restart the OpenCode backend. Only then delete the checkout if it is no longer needed.

Development

Install development dependencies and run the existing checks:

bun install
bun run typecheck
bun run check
bun test

This package intentionally exposes its TypeScript source for local file:// loading, so development does not require a build step. After source changes, fully restart the OpenCode backend before testing the plugin.