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

@shardworks/tools-apparatus

v0.1.284

Published

The Instrumentarium — guild tool registry apparatus

Downloads

37,996

Readme

@shardworks/tools-apparatus

The Instrumentarium — the guild's tool registry. This apparatus scans installed tools from kit contributions and apparatus supportKits at startup, resolves permission-gated tool sets on demand, and serves as the single source of truth for "what tools exist and who can use them."

Both the CLI and the session layer (The Animator, via MCP) depend on The Instrumentarium to discover available tools. It sits low in the dependency graph — no dependencies on other apparatus.

@shardworks/tools-apparatus       — tool() factory, ToolDefinition type, tool registry, InstrumentariumApi
@shardworks/nexus (cli)           — queries InstrumentariumApi for CLI-callable tools
kits / apparatus supportKits      — contribute ToolDefinition[] via `tools` field

Installation

{
  "dependencies": {
    "@shardworks/tools-apparatus": "workspace:*"
  }
}

Plugin id: tools


API

The Instrumentarium exposes InstrumentariumApi via provides, accessed by other plugins as:

import { guild } from '@shardworks/nexus-core';
import type { InstrumentariumApi } from '@shardworks/tools-apparatus';

const instrumentarium = guild().apparatus<InstrumentariumApi>('tools');

InstrumentariumApi

interface InstrumentariumApi {
  /**
   * Resolve the tool set for a given set of permissions.
   *
   * Evaluates each registered tool against the permission grants:
   * - Tools with a `permission` field: included if any grant matches
   * - Permissionless tools: always included (default) or gated by `strict`
   * - Channel filtering applied last
   */
  resolve(options: ResolveOptions): ResolvedTool[];

  /**
   * Find a single tool by name. Returns null if not installed.
   */
  find(name: string): ResolvedTool | null;

  /**
   * List all installed tools, regardless of permissions.
   */
  list(): ResolvedTool[];

  /**
   * Start the Tool HTTP server.
   *
   * Serves all registered tools over HTTP with session-scoped authorization.
   * Binds to 127.0.0.1. Port defaults to guild.json tools.serverPort or 7471.
   */
  startToolServer(opts?: ToolServerOptions): Promise<ToolServerHandle>;
}

ResolvedTool

A tool with provenance metadata:

interface ResolvedTool {
  /** The tool definition (name, description, params schema, handler). */
  definition: ToolDefinition;
  /** Plugin id of the kit or apparatus that contributed this tool. */
  pluginId: string;
}

ResolveOptions

interface ResolveOptions {
  /**
   * Permission grants in `plugin:level` format.
   * Supports wildcards: `plugin:*`, `*:level`, `*:*`.
   */
  permissions: string[];
  /**
   * When true, permissionless tools are excluded unless the role grants
   * `plugin:*` or `*:*` for the tool's plugin. When false (default),
   * permissionless tools are included unconditionally.
   */
  strict?: boolean;
  /** Filter by caller type. Tools with no callableBy restriction pass all callers. */
  caller?: ToolCaller;
}

Usage Examples

Resolve tools for a session (The Loom's use case):

// The Loom resolves role → permissions, then asks the Instrumentarium
const tools = instrumentarium.resolve({
  permissions: ['stdlib:read', 'stdlib:write', 'animator:read'],
  caller: 'anima',
});
// → ResolvedTool[] — all anima-callable tools matching those permission grants

Resolve with strict mode (lock down permissionless tools):

const tools = instrumentarium.resolve({
  permissions: ['stdlib:*'],
  strict: true,
});
// → Only tools from the stdlib plugin (both permissioned and permissionless)

Find a specific tool:

const tool = instrumentarium.find('commission-show');
if (tool) {
  const result = await tool.definition.handler({ id: 'writ-123' });
}

List everything installed (the CLI's use case):

const cliTools = instrumentarium.list()
  .filter(r => !r.definition.callableBy || r.definition.callableBy.includes('cli'))
  .map(r => r.definition);

Permission Model

The Instrumentarium is role-agnostic — it receives an already-resolved permissions array and returns matching tools. Role definitions and permission grants are owned by the Loom.

How permissions work

Each tool may declare a permission level (e.g. 'read', 'write', 'admin'). Callers provide permission grants in plugin:level format:

| Grant format | Meaning | |---|---| | stdlib:read | Exact match — grants read tools from the stdlib plugin | | stdlib:* | Plugin wildcard — grants all tools from stdlib | | *:read | Level wildcard — grants read tools from any plugin | | *:* | Superuser — grants all tools from all plugins |

There is no permission hierarchywrite does not imply read. Each level must be granted explicitly, or use wildcards.

Permissionless tools

Tools without a permission field are permissionless. In default mode, they are always included in resolution results. In strict mode, they are excluded unless the caller has plugin:* or *:* for the tool's plugin.


Tool HTTP Server

The Instrumentarium can serve all registered tools over HTTP, enabling out-of-process clients (such as detached session babysitters) to proxy tool calls back to the guild.

Starting the server

const instrumentarium = guild().apparatus<InstrumentariumApi>('tools');
const handle = await instrumentarium.startToolServer({ port: 7471 });
// → { port: 7471, url: 'http://127.0.0.1:7471', close() }

The port defaults to guild.jsontools.serverPort, or 7471 if not configured:

{
  "tools": {
    "serverPort": 7471
  }
}

Route mapping

Tool names map to REST routes. The first hyphen splits the name into resource and action:

| Tool name | Route | Method | |---|---|---| | writ-list | GET /api/writ/list | GET (permission: read) | | writ-create | POST /api/writ/create | POST (permission: write) | | writ-remove | DELETE /api/writ/remove | DELETE (permission: delete) | | signal | GET /api/signal | GET (no permission) |

Session-scoped authorization

Tools restricted to non-patron callers (e.g. callableBy: ['anima']) require a session ID header. Session babysitters register authorized tool sets before proxying calls:

POST /sessions
{ "sessionId": "s-abc123", "tools": ["writ-list", "writ-create"] }

GET /api/writ/list
X-Session-Id: s-abc123
→ 200 OK

DELETE /sessions/s-abc123
→ 200 OK

Patron-callable and unrestricted tools are accessible without a session header.

ToolServerHandle

interface ToolServerHandle {
  port: number;
  url: string;
  close(): Promise<void>;
}

Utility exports

The route mapping functions are exported for use by other packages (e.g. the Oculus):

import { toolNameToRoute, permissionToMethod, coerceParams } from '@shardworks/tools-apparatus';

Kit Interface

Kits contribute tools via a tools field in their kit export:

import { tool } from '@shardworks/tools-apparatus';
import { z } from 'zod';

const showTool = tool({
  name: 'commission-show',
  description: 'Show details of a commission',
  permission: 'read',
  params: {
    id: z.string().describe('Commission id'),
  },
  handler: async ({ id }) => {
    const stacks = guild().apparatus<StacksApi>('stacks');
    const writs = stacks.readBook<Writ>('clerk', 'writs');
    return await writs.get(id);
  },
});

export default {
  kit: {
    requires: ['tools'],
    tools: [showTool],
  },
} satisfies Plugin;

Each entry in the tools array is a ToolDefinition produced by the tool() factory. The Instrumentarium scans these contributions at startup via ctx.kits() and reactively via the apparatus:started lifecycle event.


Exports

// Tool authoring API (canonical home)
import { tool, type ToolDefinition, type ToolCaller } from '@shardworks/tools-apparatus';

// Instrumentarium API
import {
  type InstrumentariumApi,
  type ResolvedTool,
  type ResolveOptions,
  createInstrumentarium,
} from '@shardworks/tools-apparatus';

// Tool server utilities
import {
  type ToolServerHandle,
  type ToolServerOptions,
  type ToolsConfig,
  toolNameToRoute,
  permissionToMethod,
  coerceParams,
  SessionRegistry,
} from '@shardworks/tools-apparatus';

The default export is the apparatus plugin instance, ready for use in guild.json:

import instrumentarium from '@shardworks/tools-apparatus';
// → Plugin with apparatus.provides = InstrumentariumApi