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

background-agents

v0.1.2

Published

A TypeScript SDK for interacting with various AI coding agents (Claude, Codex, OpenCode, Gemini, Pi)

Downloads

89

Readme

Background Agents SDK

A TypeScript SDK for running AI coding agents (Claude, Codex, Gemini, Goose, OpenCode, Pi) in secure Daytona sandboxes. Designed for background execution with polling-based event streaming.

import { Daytona } from "@daytonaio/sdk"
import { createSession } from "background-agents"

const daytona = new Daytona({ apiKey: process.env.DAYTONA_API_KEY })
const sandbox = await daytona.create()

const session = await createSession("claude", {
  sandbox,
  env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY }
})

await session.start("Refactor the auth module")

// Poll for events
while (await session.isRunning()) {
  const { events } = await session.getEvents()
  for (const event of events) {
    if (event.type === "token") process.stdout.write(event.text)
  }
  await new Promise(r => setTimeout(r, 1000))
}

await sandbox.delete()

Features

  • Secure sandboxed execution — Agents run in isolated Daytona sandboxes
  • Background execution — Start agents, poll for events, survive restarts
  • Unified API — One interface for Claude, Codex, Gemini, Goose, OpenCode, and Pi
  • Zero-friction setup — Provider CLI auto-installed in sandbox
  • Session persistence — Resume conversations across runs and restarts

Provider support

| Provider | Status | Auth | |----------|--------|------| | Claude | ✅ | ANTHROPIC_API_KEY or CLAUDE_CODE_CREDENTIALS | | Codex | ✅ | OPENAI_API_KEY | | Goose | ✅ | Provider-specific (e.g. OPENAI_API_KEY, ANTHROPIC_API_KEY) | | OpenCode | ✅ | Provider-specific (e.g. OPENAI_API_KEY, ANTHROPIC_API_KEY, GOOGLE_API_KEY) | | Gemini | ✅ | GEMINI_API_KEY | | Pi | ✅ | Provider-specific (e.g. ANTHROPIC_API_KEY, OPENAI_API_KEY) |

CLI reference commands

| Provider | CLI Command | |----------|-------------| | Claude | claude -p --output-format stream-json --verbose --dangerously-skip-permissions "prompt" | | Codex | codex exec --json --skip-git-repo-check --yolo "prompt" | | Goose | goose run --output-format stream-json --text "prompt" | | OpenCode | opencode run --format json --variant medium "prompt" | | Gemini | gemini --output-format stream-json --yolo -p "prompt" | | Pi | pi --mode json -p "prompt" |


Prerequisites

A Daytona API key for secure sandboxed execution.

export DAYTONA_API_KEY=dtn_your_api_key

Installation

npm install background-agents @daytonaio/sdk

Quick start

import { Daytona } from "@daytonaio/sdk"
import { createSession } from "background-agents"

// 1. Create sandbox
const daytona = new Daytona({ apiKey: process.env.DAYTONA_API_KEY })
const sandbox = await daytona.create()

// 2. Create session
const session = await createSession("claude", {
  sandbox,
  env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY },
  model: "sonnet",
  systemPrompt: "You are a helpful coding assistant.",
})

// 3. Start a task
await session.start("Create a hello world script")

// 4. Poll for events
while (await session.isRunning()) {
  const { events } = await session.getEvents()
  for (const event of events) {
    if (event.type === "token") process.stdout.write(event.text)
    if (event.type === "tool_start") console.log(`\n[Tool: ${event.name}]`)
    if (event.type === "end") console.log("\nDone.")
  }
  await new Promise(r => setTimeout(r, 1000))
}

// 5. Cleanup
await sandbox.delete()

Restart-tolerant workflows

The SDK is designed for long-running tasks that may outlive your server process. Persist sandbox.id and session.id, then reattach after restart.

import { Daytona } from "@daytonaio/sdk"
import { createSession, getSession } from "background-agents"

const daytona = new Daytona({ apiKey: process.env.DAYTONA_API_KEY! })
const sandbox = await daytona.create()

// Start a task
const session = await createSession("claude", {
  sandbox,
  env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
  model: "sonnet",
})
await session.start("Do a long-running refactor...")

// Persist these IDs, then exit
const sandboxId = sandbox.id
const sessionId = session.id  // Save this to reattach later

// --- After restart ---

// Reattach to existing session
const sandbox = await daytona.get(sandboxId)
const session = await getSession(sessionId, { sandbox })

// Continue polling
const { events, running } = await session.getEvents()
for (const event of events) {
  if (event.type === "token") process.stdout.write(event.text)
}

// Cancel if needed
await session.cancel()

API reference

createSession(provider, options)

Creates a session. The provider CLI is installed automatically.

const session = await createSession("claude", {
  sandbox,                                    // Daytona sandbox
  env: { ANTHROPIC_API_KEY: "sk-..." },      // Environment variables
  model: "sonnet",                            // Optional: model name
  systemPrompt: "You are helpful.",           // Optional: system prompt
})

session.start(prompt)

Starts a background task. Returns immediately with process info.

const { pid, outputFile } = await session.start("Your task here")

session.getEvents()

Polls for new events since last call.

const { events, running } = await session.getEvents()
// events: Event[] - new events since last poll
// running: boolean - true if agent is still running

session.isRunning()

Returns true while the agent is running.

session.cancel()

Kills the running agent process.

getSession(sessionId, options)

Reattaches to an existing session by ID.

const session = await getSession(
  sessionId,   // session.id from createSession()
  { sandbox }
)

Event types

| Event | Description | Fields | |-------|-------------|--------| | session | Session started | id: string | | token | Streamed text | text: string | | tool_start | Tool invoked | name: string, input?: unknown | | tool_delta | Tool streaming | text: string | | tool_end | Tool finished | output?: string | | end | Task complete | error?: string | | agent_crashed | Process crashed | message?: string, output?: string |

type Event =
  | { type: "session"; id: string }
  | { type: "token"; text: string }
  | { type: "tool_start"; name: string; input?: unknown }
  | { type: "tool_delta"; text: string }
  | { type: "tool_end"; output?: string }
  | { type: "end"; error?: string }
  | { type: "agent_crashed"; message?: string; output?: string }

Model selection

| Provider | Example | Docs | |----------|---------|------| | Claude | model: "sonnet" | Claude Code models | | Codex | model: "gpt-4o" | Codex CLI models | | Goose | model: "gpt-4o" | Goose providers | | OpenCode | model: "openai/gpt-4o" | OpenCode models | | Gemini | model: "gemini-2.0-flash" | Gemini CLI model | | Pi | model: "sonnet" or model: "openai/gpt-4o" | Pi CLI models |


How it works

  1. Sandbox — Create a Daytona sandbox for isolated execution
  2. CLI install — Provider CLI is installed in the sandbox automatically
  3. Background execution — Agent runs via nohup, outputs to a log file
  4. Polling — SDK polls the log file for new JSON events
  5. Completion — A .done file signals when the agent finishes
  6. Cleanup — You call sandbox.delete() when done
┌─────────────┐     ┌──────────────────────────────────────┐
│   Your App  │────▶│          Daytona Sandbox             │
│             │     │  ┌─────────────┐    ┌─────────────┐  │
│  (polling)  │◀────│  │  Log File   │◀───│  Agent CLI  │  │
│             │     │  └─────────────┘    └─────────────┘  │
└─────────────┘     └──────────────────────────────────────┘

Debug mode

Set CODING_AGENTS_DEBUG=1 to enable debug logging:

CODING_AGENTS_DEBUG=1 npx tsx your-script.ts

Claude OAuth credentials

Claude can authenticate via ANTHROPIC_API_KEY or CLAUDE_CODE_CREDENTIALS. The latter uses OAuth credentials from a Claude Pro/Max subscription.

First, sign in locally:

claude auth login

Then retrieve your credentials:

| OS | Command | |----|---------| | macOS | security find-generic-password -s "Claude Code-credentials" -w | | Linux | cat ~/.claude/.credentials.json | | Windows | type %USERPROFILE%\.claude\.credentials.json |

Pass the output as CLAUDE_CODE_CREDENTIALS. The SDK automatically writes it to ~/.claude/.credentials.json in the sandbox.


Development

Build, test, and iterate locally. Start by installing dependencies and running the unit test suite:

npm install
npm run build
npm test

For integration and end-to-end testing, see TESTING.md.

For testing scenarios, you can use the deterministic Eliza agent, which requires no provider API key.


Resources

SandboxDaytona Docs · Daytona GitHub

AgentsClaude Code · Codex CLI · Gemini CLI · Goose · OpenCode · Pi


License

MIT