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

@agentpm/sdk

v0.1.5

Published

AgentPM™ Node SDK

Downloads

421

Readme

AgentPM™ Node SDK

A lean, framework-agnostic Node.js SDK for running AgentPM tools and inspecting installed agent packages from your app or agent runtime.

  • 🔎 Discovers tools installed by agentpm install in .agentpm/tools (project) and ~/.agentpm/tools (user), with AGENTPM_TOOL_DIR override.
  • 📦 Loads installed agents from .agentpm/agents and exposes their resolved tool refs from agent.lock.
  • 🚀 Executes entrypoints in a subprocess (node/python) and exchanges JSON over stdin/stdout.
  • 🧩 Metadata-aware: withMeta returns func + meta (name, version, description, inputs, outputs).
  • 🧪 Adapters: tiny helpers (e.g. LangChain) without forcing extra deps.

Requires Node 20+. Ships ESM + CJS builds. Types included.


Installation

Using pnpm (recommended):

pnpm add @agentpm/sdk

With npm:

npm i @agentpm/sdk

With yarn:

yarn add @agentpm/sdk

If you'll use the optional LangChain adapter:

pnpm add @langchain/core
# npm i @langchain/core
# yarn add @langchain/core

Quick Start

Minimal usage

import { load } from '@agentpm/sdk';

// spec format: "@scope/name@version"
const summarize = await load('@zack/[email protected]');

const result = await summarize({ text: 'Long document content...' });
console.log(result.summary);

With metadata (build richer tool descriptions)

import { load, toLangChainTool } from '@agentpm/sdk';

const loaded = await load('@zack/[email protected]', { withMeta: true });
const { func: summarize, meta } = loaded;

const richDescription =
  `${meta.description ?? ''} ` +
  `Inputs: ${JSON.stringify(meta.inputs)}. ` +
  `Outputs: ${JSON.stringify(meta.outputs)}.`;

console.log(richDescription);
console.log((await summarize({ text: 'hello' })).summary);

// Optional: turn it into a LangChain tool (requires @langchain/core)
const lcTool = await toLangChainTool(loaded);

Load an installed agent package

import { load, loadAgent } from '@agentpm/sdk';

const agent = await loadAgent('@zack/[email protected]');
const firstTool = agent.resolvedTools[0];
const tool = await load(`${firstTool.name}@${firstTool.version}`);

loadAgent() returns:

  • the installed agent manifest
  • the installed agent root path
  • reserved refs (skills, knowledge, memory, profiles) as metadata
  • resolvedTools from agent.lock v2

It does not execute the agent package or orchestrate the tools for you.

CJS require

const { load } = require('@agentpm/sdk');

Where tools are discovered

Resolution order:

  1. AGENTPM_TOOL_DIR (environment variable)
  2. ./.agentpm/tools (project-local)
  3. ~/.agentpm/tools (user-local)

Each tool lives in a directory like:

.agentpm/
  tools/
    @zack/summarize/
      0.1.0/
        agent.json
        (tool files…)

Installed registry agent packages live separately:

.agentpm/
  agents/
    @zack/support-agent/
      0.1.0/
        agent.json
        README.md

Where installed agents are discovered

Resolution order for loadAgent():

  1. AGENTPM_AGENT_DIR (environment variable)
  2. ./.agentpm/agents (project-local)
  3. ~/.agentpm/agents (user-local)

You can also override per call:

await loadAgent('@zack/[email protected]', {
  agentDirOverride: '/path/to/agents',
});

Manifest & Runtime Contract

agent.json (minimal fields used by the SDK):

{
  "name": "@zack/summarize",
  "version": "0.1.0",
  "description": "Summarize long text.",
  "inputs": {
    "type": "object",
    "properties": { "text": { "type": "string", "description": "Text to summarize" } },
    "required": ["text"]
  },
  "outputs": {
    "type": "object",
    "properties": { "summary": { "type": "string", "description": "Summarized text" } },
    "required": ["summary"]
  },
  "entrypoint": {
    "command": "node",
    "args": ["dist/cli.js"],
    "cwd": ".",
    "timeout_ms": 60000,
    "env": {}
  }
}

Execution contract:

  • SDK writes inputs JSON to the process stdin.
  • Tool writes a single outputs JSON object to stdout.
  • Non-JSON logs should go to stderr.
  • Process must exit with code 0 on success.

Interpreter whitelist: node, nodejs, python, python3. The SDK validates the interpreter and checks it’s present on PATH.


TypeScript & Module Formats

  • ESM import: import { load } from "@agentpm/sdk" → loads dist/index.js (ESM).
  • CJS require: const { load } = require("@agentpm/sdk") → loads dist/index.cjs (CJS).
  • Types: dist/index.d.ts.

If you see ERR_MODULE_NOT_FOUND for index.mjs, ensure your package.json maps the exports to dist/index.js (ESM) and dist/index.cjs (CJS).


Development (this repo)

pnpm i

# build / test / lint / format
pnpm build
pnpm test
pnpm lint
pnpm format

# dev watch
pnpm dev

Pre-commit hooks (Husky v9+)

pnpm dlx husky@latest init
printf 'pnpm lint-staged
' > .husky/pre-commit
chmod +x .husky/pre-commit

package.json essentials:

{
  "type": "module",
  "main": "./dist/index.cjs",
  "module": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "types": "./dist/index.d.ts",
      "import": "./dist/index.js",
      "require": "./dist/index.cjs",
    },
  },
  "scripts": {
    "build": "tsup src/index.ts --format cjs,esm --dts --clean",
    "test": "vitest run",
    "lint": "eslint . --max-warnings 0",
    "format": "prettier --check .",
  },
}

ESLint v9 (flat config)

Create eslint.config.mjs:

import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import prettier from 'eslint-config-prettier';

export default tseslint.config(
  { ignores: ['dist/**'] },
  js.configs.recommended,
  ...tseslint.configs.recommended,
  prettier,
);

Add @types/node in dev deps for TypeScript Node built-ins:

pnpm add -D @types/node

Optional: LangChain adapter

This SDK provides toLangChainTool(loaded, ...) which returns a dynamic tool. We keep @langchain/core as an optional peer. Install it only if you need the adapter:

pnpm add @langchain/core

In code:

import { load, toLangChainTool } from '@agentpm/sdk';

const loaded = await load('@zack/[email protected]', { withMeta: true });
const tool = await toLangChainTool(loaded);

Publishing

# ensure your exports map and files list are correct
pnpm install
pnpm test && pnpm build
npm pack            # confirm the tarball contents
npm publish --dry-run  # double-check what would be published


# publish (scoped packages default to private without access flag)
pnpm publish --access public

Optional in package.json:

"publishConfig": {
  "access": "public",
  "registry": "https://registry.npmjs.org/"
}

Running mixed-runtime Agent apps with Docker

Some AgentPM tools run on Node, some on Python—and your agent may need to spawn both. Using Docker gives you a single, reproducible environment where both interpreters are installed and on PATH, which avoids the common “interpreter not found” issues that pop up on PaaS/CI or IDEs.

Why Docker?

✅ Hermetic: Python + Node versions are pinned inside the image.

✅ No PATH drama: node/python are present and discoverable.

✅ Prod/CI parity: the same image runs on your laptop, CI, and servers.

✅ Easy secrets: pass API keys via env at docker run/Compose time.

✅ Fewer surprises: consistent OS libs for LLM clients, SSL, etc.

When to use it

  • You deploy to platforms that don’t let you apt-get both runtimes.
  • Your agent uses tools with different interpreters (Node + Python).
  • Your local dev/IDE PATH differs from production and causes failures.
  • You want reproducible builds and easy rollback.

How to use it

  1. Copy the provided Dockerfile into your repo.
  2. (Optional) Pre-install tools locally with agentpm install ... and commit or copy .agentpm/tools/ into the image, or run agentpm install at build time if your CLI is available in the image.
  3. Build & run:
docker build -t agent-app .
docker run --rm -e OPENAI_API_KEY=$OPENAI_API_KEY agent-app
  1. For development, use the docker-compose.yml snippet to mount your source and pass env vars conveniently.

Troubleshooting

  • Set AGENTPM_DEBUG=1 to print the SDK’s project root, search paths, merged PATH, and resolved interpreters.
  • You can force interpreters via:
AGENTPM_NODE=/usr/bin/node
AGENTPM_PYTHON=/usr/local/bin/python3.11
  • Prefer absolute interpreters in agent.json.entrypoint.command for production (e.g., /usr/bin/node). The SDKs still enforce the Node/Python family.

Troubleshooting

  • ERR_MODULE_NOT_FOUND for ESM Your package.json likely points to dist/index.mjs but your build emits dist/index.js. Fix the exports map or configure tsup to output .mjs.

  • Husky "add is DEPRECATED" In v9+, use husky init and write hook files directly (see above).

  • ESLint can't find config ESLint v9 uses flat config. Create eslint.config.mjs as shown.

  • Types for @langchain/core Keep @langchain/core as a peer (optional). For build-time types in this repo, install it as a devDependency and mark it external in tsup.config.ts.


License

MIT — see LICENSE.