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

orbitx

v0.3.8

Published

An AI SDK providing agents, swarms, planners, skills, MCP tools, workflows, and multi-provider AI integrations.

Readme

OrbitX Logo

📖 Full documentation — a deeper, page-by-page guide (providers, agents, swarms, tools, skills, MCP transport, streaming, full API reference), written to be useful both to humans learning the library and to AI agents coding against it.

Installation

npm install orbitx

Demo

Quick Start

The fastest way to get an agent running is SimpleAgent — give it a provider, an instruction, and a list of tools/skills.

import { OllamaProvider, SimpleAgent, GetCurrentTimeTool } from "orbitx";

const ollamaProvider = new OllamaProvider("gemma4:e4b");

const agent = new SimpleAgent({
  aiProvider: ollamaProvider,
  instruction: "You are a helpful assistant.",
  tools: [GetCurrentTimeTool()],
});

let oldRole: "assistant" | "tool" | "user" | undefined;

agent.run("what is current time?", (chunk) => {
  if (oldRole !== chunk.role) {
    process.stdout.write(`\n${chunk.role}: `);
    oldRole = chunk.role;
  }
  process.stdout.write(chunk.content);

  if (chunk.done && chunk.role === "assistant" && chunk.toolCalls?.length) {
    console.log(chunk.toolCalls);
  }
  if (chunk.role === "tool") {
    console.log({ toolCallId: chunk.toolCallId, toolName: chunk.toolName });
  }

  if (chunk.done) {
    process.stdout.write("\n\n");
    oldRole = undefined;
  }
});

All tools and skills passed in are baked into the system prompt once, up front — there's no separate routing/selection step deciding what the model can see turn to turn.

Recovering an agent's state

getCurrentAgentStates() returns a plain JSON-serializable snapshot (messages, memory, token counters). Save it wherever you like, and pass it back in as initData to resume the exact same agent later — a process restart, a saved session, etc.

import { writeFileSync, existsSync, readFileSync } from "fs";

const initData = existsSync("./state.json")
  ? JSON.parse(readFileSync("./state.json", "utf-8"))
  : undefined;

const agent = new SimpleAgent({
  aiProvider: ollamaProvider,
  instruction: "You are a helpful assistant.",
  tools: [GetCurrentTimeTool()],
  ...(initData ? { initData } : {}),
});

// after any run() call:
writeFileSync("./state.json", JSON.stringify(agent.getCurrentAgentStates()));

Old messages are never rewritten once written — the agent only ever appends. When the conversation grows past its memory limit, OrbitX keeps the full history intact on disk (messagesFull) and instead resets the model's working context window from a running summary of what it already did, so it can keep going indefinitely without losing the ability to act on what happened earlier.

Providers

OrbitX ships with pluggable AI providers so you can swap models without changing your agent logic.

Ollama

import { OllamaProvider } from "orbitx";

const ollamaProvider = new OllamaProvider("gemma4:e4b");

DeepSeek

import { DeepSeekProvider } from "orbitx";

const deepseekProvider = new DeepSeekProvider("api-key", "deepseek-v4-flash");

Anthropic

import { AnthropicProvider } from "orbitx";

const anthropicProvider = new AnthropicProvider("api-key", "claude-sonnet-5");

OpenAI

import { OpenAIProvider } from "orbitx";

const openaiProvider = new OpenAIProvider("api-key", "gpt-5");

Think effort

Every provider accepts a universal thinkEffort option (0-1, e.g. 0.5 or 0.8) instead of a provider-specific string — each provider maps it onto whatever scale it actually accepts (DeepSeek's none/low/high/max, OpenAI/Ollama's low/medium/high, Anthropic's numeric thinking budget), and it's silently ignored by providers/models that don't support thinking at all:

import { AnthropicProvider } from "orbitx";

const anthropicProvider = new AnthropicProvider("api-key", "claude-sonnet-5", { thinkEffort: 0.7 });

See the docs for the per-provider mapping and how thinking text streams (where supported).

Two providers: main + image

An agent uses exactly two provider roles — main (drives the agent loop itself) and image (describes image tool output, e.g. screenshots, so the main conversation doesn't have to carry raw image bytes). Pass a single provider to use it for both roles, or an array to split them:

import { BaseAgent, DeepSeekProvider, OllamaProvider } from "orbitx";

const agent = new BaseAgent({
  aiProvider: [
    { type: "main", aiProvider: new DeepSeekProvider("api-key", "deepseek-v4-flash") },
    { type: "image", aiProvider: new OllamaProvider("llava:latest") },
  ],
  instruction: "You are a helpful assistant.",
  mcpClient,
  allowedTools: [/* ... */],
});

Available Tools

Tools are grouped by domain. Import each group's array (e.g. FsTools()) to get every tool in that group at once, or import individual tools by name.

Filesystem (FsTools)

⚠️ EXTREMELY IMPORTANT WARNING ABOUT FsWriteFileTool / FsDeleteTool ⚠️

🔴 CRITICAL: FsWriteFileTool and FsDeleteTool can permanently overwrite, delete, or corrupt existing files – no undo available.

We strongly prefer running bash commands through MCPComputer, which provides a sandboxed, isolated environment – protecting your host system from accidental damage.

| Tool | Purpose | |---|---| | FsReadFileTool | Read a text file, paging through large files by line. | | FsWriteFileTool | Write/overwrite a file's full content (creates parent dirs as needed). ⚠️ No undo. | | FsEditFileTool | Replace a specific line range in an existing file without rewriting the whole thing. | | FsListDirTool | List a directory's entries, paged by index for large directories. | | FsCreateDirTool | Create a directory, including missing parents. | | FsDeleteTool | Permanently delete a file or directory (recursive optional). ⚠️ No undo. | | FsMoveTool | Move or rename a file or directory. | | FsStatTool | Check whether a path exists and get its metadata (type, size, modified time). |

Bash / processes (BashTools)

⚠️ EXTREMELY IMPORTANT WARNING ABOUT BashRunTool ⚠️

🔴 CRITICAL: Shell commands can permanently delete files, corrupt data, modify system settings, or execute harmful operations – no undo available.

We strongly prefer running bash commands through MCPComputer, which provides a sandboxed, isolated environment – protecting your host system from accidental damage.

| Tool | Purpose | |---|---| | BashRunTool | Launch a shell command as a background process; returns immediately if it's still running after waitMs (e.g. a dev server). | | BashWaitTool | Wait again on a previously started process and get its latest status/output. | | BashLogsTool | Read a process's combined stdout/stderr, paged by line. | | BashListTool | List every process launched so far with its status. | | BashWriteInputTool | Send text to a running process's stdin (answer an interactive prompt like (y/n)). | | BashTerminateTool | Terminate a running process. |

Browser (BrowserTools)

Drives a real headless browser session.

| Tool | Purpose | |---|---| | BrowserCreateSessionTool | Open a new headless browser session at a URL, returns its sessionId. | | BrowserRemoveSessionTool | Close and remove a browser session. | | BrowserGetSessionsTool | List all currently open session ids. | | BrowserNavigateTool | Navigate an existing session to a new URL. | | BrowserReadTool | Read the page as a text outline (headings, tables, links, forms), assigning ref ids to clickable/fillable elements. | | BrowserClickTool | Click a [CLICKABLE] element by ref id. | | BrowserFillTool | Type into a [FILLABLE] element by ref id; can submit via Enter if the field's form has no visible submit button. | | BrowserSubmitFormTool | Submit a [FORM] ref directly — for forms with no visible submit button. | | BrowserScrollInfoTool | Get total scrollable length and current scroll position. | | BrowserScrollTool | Scroll to a given vertical pixel position. | | BrowserConsoleTool | Read captured browser console log messages. | | BrowserNetworkTool | Read captured network request/response activity. | | BrowserNetworkStatusTool | Check whether the page currently has in-flight network activity (use before assuming a "no response yet" state means something broke). | | BrowserInjectTool | Evaluate arbitrary JS in the page and return the result. | | BrowserScreenshotTool | Capture a screenshot; can be described by the image provider instead of passed raw to the main model. |

Todo lists (TodoTools)

| Tool | Purpose | |---|---| | TodoCreateListTool | Create a new todo list, returns its todoListId. | | TodoRemoveListTool | Remove one or more todo lists (and their tasks). | | TodoGetListsTool | Get all existing todo list ids. | | TodoGetListTool | Get all tasks belonging to a list. | | TodoCreateTaskTool | Create one or more tasks inside a list. | | TodoRemoveTaskTool | Remove one or more tasks by id. | | TodoCheckTaskTool | Set the checked/unchecked state of one or more tasks. |

Present / deliverables (PresentTools)

| Tool | Purpose | |---|---| | PresentAddTool | Present a file to the user by copying it into the present folder (zip folders first — this only accepts single files). | | PresentClearTool | Clear out every file currently presented. | | PresentGetListTool | Get the list of files currently presented. |

Utility (UtilTools)

| Tool | Purpose | |---|---| | GetCurrentTimeTool | Get the current date/time (ISO string, unix timestamp, timezone). | | DelayTool | Wait a given number of milliseconds (max 60000ms) before continuing. |

Swarm (getAgentTools)

The tools a group of agents uses to hire, task, and report to each other. Unlike the other domains this one returns a handle, not an array — handle.tools goes into your tool pool, and the handle itself goes into SwarmBase, because both sides share the state built with it (the shared hire pool, and which swarm the tools drive).

const agentTools = getAgentTools({ maxHired: 5 });

const swarm = new SwarmBase({
  tools: [...FsTools(), ...BashTools(), ...UtilTools(), ...agentTools.tools],
  agents: DefaultAgents(),   // planner, reasoner, backend, frontend, tester, research
  default: "planner",
  agentTools,
  aiProvider,
});

const done = await swarm.run("Build the checkout flow", chunk => {
  process.stdout.write(`[${chunk.agentId}] ${chunk.content}`);
});
// true only once the planner AND every agent it hired are idle

| Tool | Purpose | |---|---| | agent-types | List the kinds of agent this swarm can hire — description, ratings, how many are working, slots left. | | agent-hire | Spawn an agent of a type, optionally into a group and with a standing briefing. | | agent-fire | Release one of your own hires and free its slot. | | agent-active | List every hired agent — id, type, groups, parent, busy. | | agent-prompt | Hand a task to one of your hires; returns immediately, the answer arrives later as a report. | | agent-report-parent | Send a result to the agent that hired you, ending your turn. | | agent-report-group | Message your group's other members; your parent never sees it. |

Which agent can do what is decided by its allowedTools — hiring tools for a planner, reporting tools for a worker — and agents themselves are written as reusable AgentDefinitions (the Skill idea, applied to agents) that you import rather than assemble.

DefaultAgents() ships a pipeline, not just a list: the planner hires a reasoner (five personas arguing for a measured five minutes before answering), then a backend agent that must publish an API contract, then a tester that verifies that contract against the running server before it reaches anyone, then one to three frontend agents in a shared group who agree on the scaffold and claim files between themselves so they never overwrite each other, and finally a tester on the whole flow. Point the shared MCPClient at an MCPComputer and all of that happens inside a container instead of on your machine. Full walkthrough in the docs.

Available Skills

A Skill bundles instructions with the tools that go with them. Passing a skill into an agent adds its tools automatically and folds its instructions into the system prompt.

| Skill | Purpose | |---|---| | PlannerSkill | Stands up a persistent, checkable todo list for any large/multi-step/vague job so progress survives long conversations and context resets. | | BigTaskSkill | Keeps the agent from stopping short on large or ambitious jobs — no declaring victory on a partial slice, no handing a big job back half-finished. | | LongTaskEfficiencySkill | Keeps a long job efficient — batching, avoiding redundant reads, checkpointing, not gold-plating — without giving up on getting through the full scope. | | NodeBackendSkill | Building, running, and debugging Node.js backends: APIs, servers, CLIs, workers, schedulers, DB access layers — new or existing. | | ReactFrontendSkill | Building, running, and debugging modern React (.tsx/.jsx) projects, typically Vite-scaffolded — new or existing. | | UiUxDesignSkill | Visual and interaction design quality for any user-facing UI — layout, hierarchy, feedback states, accessibility, responsiveness. | | BackendSecuritySkill | Hardening server-side code that touches auth, sessions, tokens, uploads, DB queries, payments, or any trust boundary. | | CodeVerificationSkill | Running the right type checker/build/lint/test suite before handing code back, and telling real bugs apart from sandbox artifacts. | | WebEndToEndTestSkill | Testing a live web app like a real user would (fill, click, navigate) and verifying via the rendered page, console, and network — not by reading source and assuming. | | ResearchSkill | Answering questions that need real, current information from the live web — opens pages, cross-checks multiple sources, never trusts one page. | | PresentSkill | Deciding how to hand back a job's output as files (individually or zipped) and cleaning build artifacts out first. |

Building from the Base Agent

For full control over the MCP server, connection, and client, compose an agent from the base primitives:

import {
  OllamaProvider,
  MCPConnection,
  MCPServer,
  MCPClient,
  BaseAgent,
  GetCurrentTimeTool,
} from "orbitx";

const ollamaProvider = new OllamaProvider("gemma4:e4b");

const connection = new MCPConnection();

const mcpServer = new MCPServer(connection);
mcpServer.registerTool(GetCurrentTimeTool());

const mcpClient = new MCPClient("DEFAULT_ENV", connection);

const agent = new BaseAgent({
  aiProvider: ollamaProvider,
  instruction: "",
  mcpClient,
  allowedTools: [GetCurrentTimeTool()],
});

let oldRole: "assistant" | "tool" | "user" | undefined;

agent.run("what is current time?", (chunk) => {
  if (oldRole !== chunk.role) {
    process.stdout.write(`\n${chunk.role}: `);
    oldRole = chunk.role;
  }
  process.stdout.write(chunk.content);
  if (chunk.done) {
    process.stdout.write("\n\n");
    oldRole = undefined;
  }
});

IPC Connections

Run your MCP server as a separate process and connect to it over an inter-process communication (IPC) channel:

import os from "os";
import { MCPIPCConnection } from "orbitx";

const path =
  os.platform() === "win32" ? `\\\\.\\pipe\\mcp_test` : `/tmp/mcp_test.sock`;

const ipcConnection = new MCPIPCConnection({ mode: "server", socketPath: path });

WS Connections

Run your MCP server as a separate process and connect to it over an web-socket communication (WS) channel:

import os from "os";
import { MCPWSConnection } from "orbitx";

const wsConnection = new MCPWSConnection({ mode: "server", host: "0.0.0.0", port: 9257, token: "1234" });

Creating a Custom Tool

Define your own tools with MCPTool to extend an agent's capabilities and integrate with your own ecosystem.

import { MCPTool } from "orbitx";

export const SumTool = () => new MCPTool({
  name: "math-sum",
  description: "get two numbers and sum them",
  inputs: [
    {
      name: "first",
      type: "number",
      description: "first number",
      required: true,
    },
    {
      name: "second",
      type: "number",
      description: "second number",
      required: true,
    },
  ],
  execute: async (_envID: string, inputs: Record<string, any>) => {
    const { first, second } = inputs;

    if (typeof first !== "number") {
      throw new Error("first must be a number");
    }
    if (typeof second !== "number") {
      throw new Error("second must be a number");
    }

    return { output: first + second };
  },
});

Use it like any built-in tool:

const agent = new SimpleAgent({
  aiProvider: ollamaProvider,
  instruction: "You are a helpful assistant.",
  tools: [SumTool()],
});

Creating a Custom Skill

A Skill bundles instructions with the tools it needs, so an agent that includes it automatically gets both.

import { Skill, FsReadFileTool, FsWriteFileTool } from "orbitx";
import { SumTool } from "./sum-tool.js";

export const MathHelperSkill = () => new Skill({
  name: "math-helper",
  description:
    "Use this skill whenever the user asks for arithmetic that should be computed exactly " +
    "rather than estimated from the model's own reasoning — sums, running totals, or " +
    "anything written to a file afterward.",
  instructions: `
- Always use the math-sum tool for addition instead of computing it yourself.
- If asked to save a result, write it to disk with fs-write-file and confirm the path back to the user.
  `,
  tools: [
    SumTool(),
    FsReadFileTool(),
    FsWriteFileTool(),
  ],
});
const agent = new SimpleAgent({
  aiProvider: ollamaProvider,
  instruction: "You are a helpful assistant.",
  skills: [MathHelperSkill()],
});

MCPComputer (Experimental Feature)

Spins up a sandboxed Docker container running the MCP server and returns a ready-to-use client connection — no need to manage IPC sockets, ports, or tokens manually.

import { MCPComputer } from "orbitx";

const computer = new MCPComputer("/path/to/mount", [3000, 8080]);
await computer.start();

const connection = computer.getConnection();
await computer.stop();
  • mountPath: host directory mounted into the container
  • ports: ports to expose, or "*" for host network mode (Linux only, or Windows via WSL2)
  • getConnection(): returns a ready MCPConnection (IPC on Linux/macOS, WebSocket on Windows)
  • stop(): kills the container

Requires the aliafsordeh/orbitx-sandbox:0.1 image (pull it, or build from the Dockerfile.sandbox reference on our GitHub page).