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

@biroai/agent-runtime

v2026.513.0

Published

**P2.2b** — Biro-native abstraction layer over coding-agent runtimes.

Readme

@biroai/agent-runtime

P2.2b — Biro-native abstraction layer over coding-agent runtimes.

Why this exists

Biro runs coding agents (Claude Code, Codex, OpenClaw, and future runtimes) inside sandboxes. Without a shared interface, each consumer would write its own ad-hoc wiring — different event shapes, different session lifecycles, different error types.

This package defines a single AgentRuntime interface that every runtime provider implements. The shape deliberately mirrors the Rivet Sandbox Agent SDK (rivet-dev/sandbox-agent v0.4.x, per doc/design/sandbox-abstraction.md). This means a future @biroai/adapter-rivet-runtime package can implement the interface by proxying to a Rivet binary running inside any sandbox, giving Biro six coding-agent runtimes for one adapter's worth of work.

The interface

AgentRuntime is a transport-agnostic interface with five concerns:

  • Session lifecyclecreateSession, getSession, listSessions, stopSession
  • MessagingpostMessage (enqueue a user turn; does not block on the agent's response)
  • Event streamingstreamEvents returns an AsyncIterable<BiroAgentEvent> that drains queued events then delivers live events as they arrive
  • Processesprocesses.list, processes.kill for processes running inside the session's sandbox
  • Filesystemfs.read, fs.write, fs.list, fs.delete within the session's working directory

All event types are drawn from @biroai/agent-events (BiroAgentEvent discriminated union). streamEvents ends naturally after emitting agent.session.ended.

The mock provider

InMemoryAgentRuntime is an in-memory implementation for tests and local development. It synthesizes realistic BiroAgentEvent sequences without spawning any real process:

import { InMemoryAgentRuntime } from "@biroai/agent-runtime/mock";

const runtime = new InMemoryAgentRuntime();
const handle = await runtime.createSession({
  kind: "mock",
  cwd: "/workspace",
  companyId: "acme",
  agentId: "dev-1",
  issueId: null,
});

await runtime.postMessage(handle.sessionId, { text: "Fix the tests." });

for await (const event of runtime.streamEvents(handle.sessionId)) {
  console.log(event.type);
  // agent.session.started -> agent.turn.completed
}

await runtime.stopSession(handle.sessionId);
// stream yields agent.session.ended, then completes

The mock intentionally does NOT simulate filesystems or process tables — fs.read and fs.write throw NotImplementedError. Only event-shape testing is in scope.

Providers

  • mock (in-memory, for tests) — already shipped. Import from "@biroai/agent-runtime/mock".
  • claude-code — spawns claude -p subprocesses. Status: minimal implementation. createSession/streamEvents/stopSession work; postMessage is unsupported (one-shot model — start a new session for a follow-up turn, optionally passing resumeSessionId to resume Claude's context). processes.* and fs.* throw NotImplementedError.

ClaudeCodeProvider usage

import { ClaudeCodeProvider } from "@biroai/agent-runtime";

const runtime = new ClaudeCodeProvider();
const handle = await runtime.createSession({
  kind: "claude-code",
  cwd: "/workspace",
  prompt: "Fix the failing tests.",  // required for claude-code
  companyId: "acme",
  agentId: "dev-1",
  issueId: null,
});

for await (const event of runtime.streamEvents(handle.sessionId)) {
  console.log(event.type);
  // agent.session.started -> agent.turn.completed -> agent.session.ended
}

ClaudeCodeProvider accepts a spawn option for dependency injection in tests — pass a factory that returns a ChildProcessLike to avoid spawning real subprocesses.

Status

Types + interface + mock + ClaudeCodeProvider. The ./mock subpath is kept separate from the root export intentionally — production code cannot accidentally import the test runtime.

Related

  • packages/agent-events/BiroAgentEvent schema and BiroRuntime literals
  • doc/design/sandbox-abstraction.md — rationale for the Rivet-shaped interface
  • ROADMAP-NEXT.md row P2.2 — context for this and adjacent tasks