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

@guangnao/agent-os

v1.0.5

Published

AgentOS Kernel — a lightweight, type-safe agent operating system in TypeScript

Readme

@guangnao/agent-os

A microkernel operating system for LLM agents — not a framework, not a library.

The distinguishing line: the kernel owns execution and resources, and a process (an "agent") affects the world only through capability-mediated syscalls. That boundary — not the vocabulary — is what makes this a system.

  • Metered by construction — every LLM/tool call is charged to a per-process budget (tokens, $, tool-calls, wall-clock, memory). Over budget → the kernel kills it.
  • Least privilege — a process holds no ambient authority, only unforgeable capabilities you delegate. Attenuate and pass them like file descriptors.
  • Let it crash — link/monitor + OTP-style supervisors restart flaky agents.
  • Deterministic — record/replay driver I/O and a virtual clock reproduce a run byte-for-byte.
  • Batteries included — LLM (OpenAI-compatible), tools, KV, cross-node gateway, worker-thread offload, and a WASM sandbox drivers; a ready-made ReAct agent.

Install

npm install @guangnao/agent-os

ESM-only, types bundled. Node ≥ 18.

Quick start — a real LLM agent in ~30 lines

A ReAct agent that thinks → calls a tool → observes → answers, with every LLM and tool call metered by the kernel. Point it at any OpenAI-compatible endpoint (DeepSeek below).

import { Kernel, llmDriver, toolDriver, openaiChat, reactAgent } from '@guangnao/agent-os'
import type { ProcessImage, ToolSchema, AgentResult, BootGrant } from '@guangnao/agent-os'

// 1. Tools are plain functions; the agent reaches them through a metered device.
const tools = {
  calc: ({ op, a, b }: { op: string; a: number; b: number }) =>
    ({ result: op === 'mul' ? a * b : op === 'add' ? a + b : a - b }),
}
const schemas: ToolSchema[] = [{
  name: 'calc', description: 'arithmetic on two numbers',
  parameters: { type: 'object', required: ['op', 'a', 'b'], properties: {
    op: { type: 'string', enum: ['add', 'sub', 'mul'] }, a: { type: 'number' }, b: { type: 'number' },
  } },
}]

// 2. Boot a kernel; register the drivers (the only way out to the world).
const k = new Kernel()
k.registerDriver(llmDriver(openaiChat({
  apiKey: process.env.DEEPSEEK_API_KEY!,
  baseUrl: 'https://api.deepseek.com/v1',
  model: 'deepseek-chat',
})))
k.registerDriver(toolDriver(tools))

// 3. init delegates the llm + tools devices to a ReAct agent and awaits its answer.
const init: ProcessImage = { name: 'init', async main(sys) {
  const g = (await sys.recv<BootGrant>()).body
  const { cap } = await sys.spawn(
    reactAgent({ task: 'What is 23 * 19? Use calc, then give just the number.', tools: schemas }),
    { link: true, quota: { tokens: 200_000, usd: 1, toolCalls: 20, mem: 100_000 } },
  )
  await sys.send(cap, {}, { caps: [                       // delegate caps like fds
    sys.derive(g.devices['llm']!,   ['open']),
    sys.derive(g.devices['tools']!, ['open']),
    sys.selfCap(),
  ] })
  const r = (await sys.recv<AgentResult>()).body
  console.log(r.answer, `(${r.steps} steps)`)              // → 437 (2 steps)
} }

await k.boot(init, { grant: ['llm', 'tools'], quota: { tokens: 2_000_000, usd: 10, children: 4 } })

A process is just { name, async main(sys, args) }. It holds no kernel object — only sys, the syscall surface. Everything it can do (spawn, send, open a device, remember, read an LLM) is a syscall, charged and capability-checked.

Architecture (microkernel, 3 rings)

Ring 2 · Userland   — agents + services: pure main(sys) bodies, syscalls only
──────────────────── the syscall ABI (the only boundary)
Ring 1 · Services   — drivers (LLM/tools/memory), supervisors, name service
────────────────────
Ring 0 · Kernel     — PIDs · syscall dispatch · scheduler · accounting · cap table
                      · IPC switch · supervision mechanism · event log

| Subsystem | What it is | Agent twist | |---|---|---| | Process | kernel-owned PCB + PID; the kernel runs/parks/kills it | not an object you new | | Scheduler | cooperative, by reductions (syscall budget per quantum) + priority/EDF deadlines | schedules token/tool cost, not CPU time | | Accounting | hierarchical (cgroup) quotas: tokens, tool calls, $, wall-clock, memory, children | parent's budget bounds its whole subtree | | Capabilities | unforgeable handles; attenuate + delegate; no ambient authority | least-privilege, confused-deputy-proof | | IPC | mailboxes + a switch; caps ride on messages (fd-passing) | the only way agents share data | | Memory (MMU) | context window = paged address space; watermark evict → lossy summary → recall; OOM | pluggable keyword/vector recall | | Supervision | link/monitor → Down (kernel) + restart strategies (userland) | OTP "let it crash" | | Drivers | LLM/tools/memory/net behind one open/read/write | swap a vendor = swap a driver; metered at the chokepoint | | Event log | every syscall/charge/fault, stamped | ps/top, audit, deterministic replay |

Driver standard library

| Driver | Purpose | |---|---| | llmDriver(chat) | LLM device; wrap any ChatFn | | openaiChat(cfg) | a ChatFn for any OpenAI-compatible API (OpenAI, DeepSeek, …); pass onDelta on a request for SSE token streaming | | toolDriver(tools) | expose plain functions as a metered tool device | | kvDriver() | a shared key-value store device | | gatewayDriver(forward) | cross-node IPC over a trusted channel (in-process / private link) | | secureGatewayDriver(forward, key) | cross-node IPC over a hostile wire — HMAC-sealed, replay-protected | | workerDriver(tasks) | offload CPU tasks to real worker_threads (isolated heap, another core) | | wasmDriver(modules) | run untrusted compute in a zero-import WebAssembly sandbox |

Beyond the basics

  • Deterministic record/replay — journal driver I/O; replay reproduces a run exactly.
  • Virtual clock — discrete-event time; sleeps cost zero real time, traces are byte-identical.
  • Snapshot / migration — kernel.snapshot(pid) → durable state (context + mailbox + budget); kernel.restore(snap, image) resumes it on any kernel (live migration across nodes).
  • Event-sourcing store — MemoryStore / FileStore persist every event + I/O; rebuild a replayable journal from disk.
  • Vector recall — context page-in via KeywordRecaller (default) or VectorRecaller(embed).
  • Supervisors & name service — supervisor({ strategy, children }) (one_for_one / one_for_all / rest_for_one) and a capability broker.

Security & operations

  • Authenticated transport — off-machine messages are HMAC-SHA256 sealed over a canonical (to, nonce, body) encoding; kernel.ingress() verifies in constant time and drops replays. Capabilities never cross the wire — a verified peer can address a pid, never forge authority over one.
  • Crash recovery — Kernel.replayFrom(store) rebuilds a kernel that replays persisted driver I/O, reproducing a run exactly with no live calls. The event-sourcing log is the recovery mechanism.
  • Backpressure — quota.maxMailbox bounds an inbox; a full one parks senders until the consumer drains it (no drops, order preserved).
  • Metrics — kernel.metrics() and kernel.metricsText() (Prometheus exposition) over the whole event history.
  • ABI versioning — ABI_VERSION is stamped into snapshots; restore refuses an incompatible version rather than silently resuming mismatched state.
  • Tested for robustness — property tests (accounting conservation/atomicity, capability attenuation), adversarial tests (malicious-driver quota-kill), and chaos tests (spawn/kill churn) run on a seeded PRNG.

Performance

Single-core, cooperative kernel — these are one-core ceilings. Reproduce with npm run bench:

IPC round-trips      ~530k /s   send → recv → send → recv
Process spawn+exit   ~135k /s   spawn → notify → exit (O(caps-owned) revoke — flat under load)
Context switches     ~2.1M /s   sys.yield (O(1) dispatch — flat to thousands of procs)
Fan-in recv          ~1.2M /s   32 senders → 1 deep mailbox (O(1) dequeue — flat under load)
Driver reads         ~840k /s   syscall + driver dispatch + accounting
Memory remember      ~2.2M /s   context write
Memory recall        ~1.6M /s   keyword page-in
Memory under paging  ~900k /s   write at the mem ceiling (O(1) amortized — flat vs resident size)

Parallel I/O         ~16×       16 latency-bound reads: sys.readAll vs sequential

sys.readAll(handle, reqs) fires every request concurrently under a single park — a ReAct turn's N tool calls become one network-bound wait, not N — while staying fully metered and replay-deterministic (op ids are assigned in order).

(Apple M-series, Node 25; indicative, not a controlled benchmark.)

Real network + true isolation

  • TCP transport — serveTcp(env => kernel.ingress(env)) + dialTcp(host, port) move HMAC-sealed envelopes over real sockets between kernels on different ports/machines. Authentic frames are delivered; tampered/forged ones are dropped at ingress.
  • Sandboxed agents — sandbox(code) runs untrusted agent logic in a real worker thread (separate V8 isolate + heap). It holds no reference to sys, the cap table, or kernel memory; its only authority is a mediated syscall RPC through a trusted reference-monitor shim (allow-listed syscalls + the usual capability/quota checks). It can't read kernel memory, forge a capability, or call a syscall it wasn't granted.

Honest scope

Production-shaped but young — naming it straight:

  • Distributed has authenticated envelopes + replay guard + a real TCP transport, but no built-in service discovery, failure detector, or partition handling yet.
  • WASM sandbox confines compute; the agent-process isolation story is sandbox() (worker-thread), not WASM-of-the-whole-agent.
  • Migration serializes a process's context + mailbox + budget, not its JS stack — so it migrates message-loop state machines, not arbitrary suspended call stacks.
  • Preemption is cooperative. The kernel is one JS thread; every syscall charges a reduction and yields/faults at the quantum, so a loop over any syscall can't wedge it. But a syscall-free CPU loop (for(;;){…}) can't be preempted from within the same thread — offload CPU-bound work to workerDriver/wasmDriver (separate threads), the same way you'd never block Node's event loop.

Requirements

  • Node ≥ 18, ESM ("type": "module" or .mjs).
  • TypeScript optional but recommended — full types ship with the package.

License

MIT