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

@stablekernel/opencode-bgrun

v0.1.3

Published

Background job runner for AI coding agents with live session wake-to-act on OpenCode.

Readme

opencode-bgrun

Run long shell commands (test suites, builds, linters) as detached background jobs so your AI coding agent's session stays unblocked and its context stays clean. Output lands in a file under .run/; the command returns immediately. State is file-based, so a new agent session can pick up a job started by a prior one.

On OpenCode, a companion plugin wakes the originating agent session when a job finishes — so the agent proactively reads results and reacts, rather than waiting for a human to notice a notification.


Quick start

./install.sh        # symlink scripts + plugin + skill
# restart OpenCode  # required for the plugin to load

As an AI agent (OpenCode) — call the bgrun tool:

bgrun(command: "make test-short")
// returns immediately: "started: <job-id>"
// agent is woken automatically when the job finishes

As a human in a shell — call the script directly:

bgrun make test-short
# returns immediately; desktop notification fires on completion

How it works

Two audiences

AI agents on OpenCode call the bgrun tool — a first-class OpenCode plugin tool. The tool captures context.sessionID in-process and forwards it to the underlying shell script via a -s <session-id> flag. When the job finishes, the plugin wakes that exact session via client.session.promptAsync(). This is correct even when many concurrent agent sessions share the same directory.

Humans in a shell call the bgrun script directly. A human shell invocation has no live agent session to wake, so it is notify-only — a desktop notification fires via terminal-notifier (or osascript as fallback) when the job finishes. This is expected and honest behavior. Omitting -s always produces notify-only behavior.

Wake routing

The bgrun script writes sidecar files into <project-root>/.run/ for each job:

| Sidecar | Contents | |---------|----------| | .status | Key=value state: state, pid, exit, cmd, … | | .log | Captured command output | | .origin | Which tool launched the job (opencode | claude | cursor; defaults to opencode) | | .session | Session id to wake (written only when -s is passed) |

The .session sidecar is written atomically before the job is spawned, so even a job that finishes instantly is routed correctly — there is no race.

On completion the runner drops a .notify breadcrumb. The plugin polls .run/ (~1 s interval), atomically claims each .notify by renaming it to .notified (fire-once — survives plugin restarts), reads the .session sidecar for exact routing, and wakes that session. If no .session sidecar is present the plugin falls back to the most-recently-active session.

Non-fatal degradation: if the wake fails for any reason — plugin not loaded, SDK missing, etc. — the job still completes normally and the human desktop notification fires as usual.


Commands

Plugin tools (agent-facing)

These are registered by the plugin as first-class OpenCode tools. Agents call them directly — no shell access required.

| Tool | Purpose | |------|---------| | bgrun | Launch a command as a detached background job. Returns started: <job-id> immediately. Injects sessionID automatically so the plugin can wake this exact session on completion. | | bgclean | Delete completed job artifacts. Default: 7 days. Skips running jobs. The plugin also auto-cleans on startup (14-day default). |

Shell CLIs (human-facing)

Plain shell scripts — notify-only, no session wake. Available on PATH after npm i -g or install.sh.

| Command | Purpose | |---------|---------| | bgrun [--name <label>] <command…> | Launch a detached background job; desktop notification fires on completion (no session wake). --name sets a human-readable label used as the job slug. | | bgstatus [--json] [<job-id>] | Show status (running, done, crashed) and exit code; omit job-id to list all jobs. --json emits a machine-readable JSON array (fields: id, state, cmd, pid, start, end, exit, cwd, name, log_path). | | bgtail <job-id> [lines] | Print the last N lines of the job's log (default 40). | | bgwait <job-id> | Block until the job finishes; exits with the job's exit code. Exit 1 if job not found; exit 2 on timeout (1 hour). Useful for sequential shell scripting. | | bgkill <job-id> | Send SIGTERM to a running job and mark it killed. Exits 1 if the job is not running or not found. | | bgclean [days] | Delete job artifacts older than N days (default: 7). | | bgrun doctor | Health check: verifies BGRUN_DIR is writable, _bgrunner.sh is present, notification tools (osascript/notify-send) are available, and OpenCode is detected. Exits 0 if all required checks pass, 1 otherwise. |

Auto-cleanup: the plugin silently removes job artifacts older than 14 days each time OpenCode starts. Explicit bgclean calls default to 7 days — more aggressive, since you're asking for it. Both thresholds can be overridden by passing a days argument.


Configuration

All environment variables are optional. Defaults work out of the box for typical single-user installs.

| Variable | Default | Scope | Description | |---|---|---|---| | BGRUN_DIR | ~/.bgrun/jobs | Plugin + all shell CLIs | Override the directory where job artifacts (.status, .log, .notify, .session) are stored. Useful for CI, multi-user machines, or when you want jobs on a different volume. | | BGRUN_ACTIVATE | (none) | Shell CLI only | macOS bundle ID of the app to activate when a desktop notification is clicked (e.g. com.todesktop.230313mzl4w4u92). Has no effect without terminal-notifier. See desktop notifications for usage example. | | OPENCODE_CONFIG_DIR | ~/.config/opencode | Plugin only | Override the OpenCode config directory. Used as a fallback path to locate the @opencode-ai/plugin SDK when bare import fails. Rarely needed — only relevant when OpenCode is installed to a non-default config location. |

Legacy .run/ migration: If the plugin detects a legacy .run/ directory with existing jobs in your project root, it prints a one-time informational message on startup suggesting you set BGRUN_DIR=./.run to preserve that layout, or let new jobs accumulate in the default ~/.bgrun/jobs. This message is not an error — no action is required; jobs in the old directory continue to be readable by the shell CLIs if you point BGRUN_DIR accordingly.


Install details

Recommended: npm install via opencode.json (coworkers / CI)

Add the following entry to the plugins array in your opencode.json:

{
  "plugins": [
    "@stablekernel/[email protected]"
  ]
}

OpenCode installs the package into ~/.cache/opencode/packages/@stablekernel/opencode-bgrun@<version>/node_modules/@stablekernel/opencode-bgrun/ and loads the plugin automatically on startup. No PATH setup is needed for the agent (tool) path — the plugin resolves bin/bgrun by absolute path at runtime.

Local / dev install (repo clone)

./install.sh

Creates symlinks:

| Source | Destination | |--------|-------------| | bin/bgrun, bin/bgstatus, bin/bgtail, bin/bgclean | ~/.local/bin/ | | plugin/bgrun-wake.js | ~/.config/opencode/plugin/ | | skill/run-bg/ | ~/.config/opencode/skills/run-bg/ |

./uninstall.sh removes those symlinks.

Restart OpenCode after install. OpenCode discovers plugins in ~/.config/opencode/plugin/ at startup — no opencode.json entry is needed — but the plugin is not hot-loaded; a restart is required for the tool registration and completion poller to become active.

Optional: human shell CLI

The bgrun tool (plugin-registered) is what AI agents call and it works automatically from the npm install — no PATH setup required. It also delivers the session-wake feature.

The human shell commands (bgrun, bgstatus, bgtail, bgclean) are optional and notify-only — they fire a desktop notification on completion but do not wake an agent session. (Agent-wake is exclusively the plugin bgrun tool.) After an npm install via opencode.json those scripts are not on your PATH; typing bgrun in a terminal will produce command not found.

Recommended: install.sh --cli-only

Recommended: install via npm global:

npm i -g @stablekernel/opencode-bgrun

This puts bgrun, bgstatus, bgtail, and bgclean on your PATH automatically via npm's bin map.

Alternatively, if you have the repo cloned, run ./install.sh --cli-only to symlink just the four CLI scripts into ~/.local/bin without touching the plugin or skill (which the npm install already provides):

# If you have the repo cloned:
./install.sh --cli-only

# See all modes:
./install.sh --help

--cli-only also works without a clone when the plugin is already installed via the opencode.json npm spec. It auto-discovers the scripts inside OpenCode's package cache at:

~/.cache/opencode/packages/@stablekernel/opencode-bgrun@<version>/node_modules/@stablekernel/opencode-bgrun/bin/

The version segment in the path is discovered dynamically, so it keeps working across version bumps. To use this mode you need the install.sh script itself — grab it from the repo or copy it from the cache dir above.

To remove: ./uninstall.sh --cli-only.

Manual alternative

If you prefer, symlink directly from the npm global cache:

PKG="$HOME/.cache/opencode/packages/@stablekernel/[email protected]/node_modules/@stablekernel/opencode-bgrun"
mkdir -p "$HOME/.local/bin"
for cmd in bgrun bgstatus bgtail bgclean; do
  ln -sf "$PKG/bin/$cmd" "$HOME/.local/bin/$cmd"
done
# Ensure ~/.local/bin is on PATH (add to ~/.zshrc or ~/.bashrc if needed):
# export PATH="$HOME/.local/bin:$PATH"

Plugin SDK resolution

The plugin loads the OpenCode SDK (@opencode-ai/plugin) via a resolution cascade: bare import first, then the OpenCode config directory. If the SDK cannot be found the poller still runs (desktop notifications work), but the bgrun tool and agent-wake require a successful SDK load.

Optional: desktop notifications

macOS: Install terminal-notifier for richer notifications with click-through support:

brew install terminal-notifier

To get click-through to your editor when a notification fires, set BGRUN_ACTIVATE to your editor's bundle ID in your shell profile:

# ~/.zshrc
export BGRUN_ACTIVATE=com.example.YourEditor

Linux: notify-send is automatically detected and used if available — no setup required. Run bgrun doctor to confirm it is found.


Scope and portability

The live-agent wake is OpenCode-specific. Only an in-process plugin can call client.session.promptAsync() to wake a live OpenCode session — a CLI path and an HTTP bridge were both proven dead-ends. This component cannot be ported without a per-tool equivalent.

The file-based job runner (bin/) is tool-agnostic: plain POSIX sh, no OpenCode dependency. The .origin sidecar is the intended routing seam for per-tool plugins — a Cursor or Claude Code integration would read .origin and apply its own wake mechanism. These are separate future deliverables; the core runner works today regardless of which agent (or no agent) is present.

Summary: OpenCode-first for the full agent-wake experience; core job runner is portable.


Components

bin/
  bgrun              # Launch a detached job; writes .run/ sidecars; bgrun doctor for health check
  _bgrunner.sh       # Detached executor (invoked by bgrun, not directly)
  bgstatus           # Check job status; --json for machine-readable output
  bgtail             # Tail job log output
  bgwait             # Block until a job finishes; exit with its exit code
  bgkill             # Send SIGTERM to a running job
  bgclean            # Remove old .run/ artifacts
plugin/
  bgrun-wake.js      # OpenCode plugin: registers bgrun tool + runs completion poller
skill/
  run-bg/            # OpenCode skill: teaches agents when/how to use bgrun
install.sh           # Symlink everything into place
uninstall.sh         # Remove symlinks