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

@warlock.js/ai-workspace

v4.8.2

Published

Policy-jailed filesystem + shell workspace for @warlock.js/ai agents

Readme

@warlock.js/ai-workspace

Policy-jailed filesystem + shell workspace for @warlock.js/ai agents.

A workspace is the bounded place an agent reads, writes, and runs commands — a policy-enforced handle to a filesystem + shell that (a) vends tools to agents and (b) you can drive directly from code. One policy, one shared rule set, two ways to touch it: the agent uses ws.tools.*; you use the direct methods (ws.readFile, ws.exec, …). Importing the package registers the verb on the shared ai object, so it is reached as ai.workspace(policy) per the ai.-namespace convention.

Security: a policy jail, not OS isolation

The workspace is a policy jail, and it is honest about that — it is not an OS sandbox. Every path is realpath-resolved and must sit under cwd (or an allowPaths root); denyPaths globs are blocked even inside cwd; shell commands are gated by an executable allow/deny list; and process.env is never inherited wholesale (a command can't even find node/npm unless the policy opts in via shell.inheritEnv: ["PATH"]). What it does not do is contain what an allowed process does once it runs — an allowed node can still open a socket or read a file its own user can reach. For untrusted code you want real isolation (a container / microVM backend), which is a later phase. Treat this as least-privilege guardrails for a trusted agent, not a security boundary around a hostile one.

Install

npm install @warlock.js/ai-workspace

It declares @warlock.js/ai as a peer and depends on @warlock.js/fs; beyond those it uses only Node built-ins (node:child_process for the shell). Import the package once for its side effect so ai.workspace(...) is registered:

import "@warlock.js/ai-workspace";

Usage

1. Minimal build-loop agent

Hand the whole tool set to an agent and let it read, edit, and run tests until green. The failure comes back as tool data, so the agent self-corrects.

import "@warlock.js/ai-workspace";
import { ai } from "@warlock.js/ai";

const ws = ai.workspace({
  cwd: "/srv/acme-api",
  denyPaths: [".git/**", ".env*"],
  shell: { allow: ["npm", "node"], inheritEnv: ["PATH"], timeoutMs: 60_000 },
});

const dev = ai.agent({
  model: ai.openai.model({ name: "gpt-4o" }),
  tools: ws.tools.all(),
  maxTrips: 25,
});

await dev.execute("`npm test` fails on the cart-total suite. Make it green.");

2. Read-only reviewer (least privilege via tools.pick)

A reviewer needs to read and search — never to write or run a shell. Pick exactly those three tools, or take a readonly() projection (which omits every mutating tool and rejects the mutating direct methods).

const ws = ai.workspace({ cwd: "/srv/acme-api" });

const reviewer = ai.agent({
  model: ai.openai.model({ name: "gpt-4o" }),
  tools: ws.tools.pick("readFile", "grep", "glob"),
});

await reviewer.execute("Review src/cart for off-by-one bugs and summarize.");

// Equivalent, as a projection of the same jail:
const ro = ws.readonly();
ai.agent({ model, tools: ro.tools.all() }); // read_file + grep + glob only

3. Direct programmatic use (no LLM)

Drive the workspace from code — scaffold before an agent runs, or do a mechanical bulk migration under the read-before-edit stale-hash guard.

const ws = ai.workspace({
  cwd: "/srv/acme-api",
  shell: { allow: ["npm"], inheritEnv: ["PATH"] },
});

// Seed structure, install a dep, then hand off to an agent.
await ws.writeFile("src/routes.ts", ROUTES_BOILERPLATE);
await ws.exec("npm install zod");

// Bulk migration — no LLM needed.
for (const file of await ws.glob("src/models/**/*.ts")) {
  const { content, hash } = await ws.readFile(file);

  if (content.includes("legacyImport")) {
    await ws.editFile({
      path: file,
      oldString: 'import { legacyImport } from "../legacy";',
      newString: 'import { modernImport } from "../modern";',
      replaceAll: true,
      expectHash: hash, // rejected if the file moved underneath us
    });
  }
}

What's in this release (W1)

  • Policy jailcwd path jail (realpath-resolved), allowPaths / denyPaths, a fail-closed shell allow/deny list (deny wins), per-command timeout + output cap, and opt-in inheritEnv (no blanket process.env).
  • Backendslocal (default; @warlock.js/fs + node:child_process) and mock (in-memory, for hermetic disk-free tests).
  • Seven tools under ws.tools.*read_file, edit_file, write_file, run_shell, run_tests, grep, glob — each a ToolContract ready for ai.agent({ tools }).
  • Direct methodsreadFile / writeFile / editFile / exec / grep / glob / exists / mkdir / remove, sharing the exact same policy seam.
  • tools.all() / tools.pick(...) — every tool, or a least-privilege subset.
  • readonly() — a projection that vends only read/grep/glob and rejects every mutating direct method.
  • scope(subdir) — a sub-jailed view rooted at subdir (tighter blast radius).
  • Read-before-edit guardread_file returns a SHA-256 hash; edit_file requires an exact, unique oldString (or replaceAll) and rejects on an expectHash mismatch.

Deferred to later phases (intentionally absent here): the transactional lifecycle (snapshot / restore / diff / changes), on() hooks, dispose, usage(), and the worktree / container backends plus provisioning helpers.

Skills

Progressive-disclosure, per-task docs live under skills/:

  • use-a-workspace/ — build a jailed workspace and operate it (policy, tools, direct methods, readonly / scope).
  • build-loop-agent/ — wire ws.tools.all() into a coding agent that reads → edits → runs tests until green.