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

@procedures/procedure

v0.1.0

Published

Procedure scaffolding and management: procedure.new writes typed procedure files, plus get, list, define and the procedure store.

Readme

@procedures/procedure

npm version License: MIT TypeScript

Procedure scaffolding and meta-procedures for runtime procedure management.

Table of Contents

Overview

@procedures/procedure provides utilities for creating and managing procedures:

  • procedure.new: Scaffold new procedures with types and registration boilerplate
  • procedure.list: List all registered procedures in the runtime registry
  • procedure.get: Get metadata for a specific procedure
  • procedure.export: Export procedure definitions as JSON

This package simplifies procedure development by automating the creation of procedure files, type definitions, and registration code.

Installation

npm install github:mark1russell7/client-procedure#main

Dependencies:

  • @procedures/client (peer dependency)
  • zod ^3.24.0

Architecture

graph TB
    subgraph "Procedure Scaffolding"
        ProcNew[procedure.new]
        Templates[Code Templates]
        FileGen[File Generator]
    end

    subgraph "Generated Files"
        ProcFile[src/procedures/namespace/operation.ts]
        TypesFile[src/types.ts]
        IndexFile[src/procedures/namespace/index.ts]
        RegisterFile[src/register.ts]
    end

    subgraph "Meta-Procedures"
        ProcList[procedure.list]
        ProcGet[procedure.get]
        ProcExport[procedure.export]
    end

    subgraph "Runtime Registry"
        Registry[PROCEDURE_REGISTRY]
        Procedures[Registered Procedures]
    end

    ProcNew --> Templates
    Templates --> FileGen
    FileGen --> ProcFile
    FileGen --> TypesFile
    FileGen --> IndexFile

    ProcList --> Registry
    ProcGet --> Registry
    ProcExport --> Registry
    Registry --> Procedures

Scaffolding Flow

sequenceDiagram
    participant User
    participant ProcNew as procedure.new
    participant FS as File System
    participant Templates

    User->>ProcNew: procedure.new { name: "user.create" }
    ProcNew->>Templates: Generate procedure code
    Templates-->>ProcNew: Procedure file content
    ProcNew->>FS: Write src/procedures/user/create.ts
    ProcNew->>Templates: Generate types
    Templates-->>ProcNew: Type definitions
    ProcNew->>FS: Append to src/types.ts
    ProcNew->>Templates: Generate exports
    Templates-->>ProcNew: Export statement
    ProcNew->>FS: Update src/procedures/user/index.ts
    ProcNew->>FS: Add the procedure to src/register.ts
    ProcNew-->>User: Success + next steps

The scaffolded code compiles with the strict options of the workspace. A name whose path, file, type names or registration exists already is an error, and then nothing is written.

Quick Start

import { Client, LocalTransport, PROCEDURE_REGISTRY } from "@procedures/client";
import "@procedures/procedure"; // registers its procedures

const client = new Client(new LocalTransport({ registry: PROCEDURE_REGISTRY }));

// Scaffold a new procedure
const result = await client.exec(["procedure", "new"], {
  name: "user.create",
  description: "Create a new user account",
});

console.log(result.operations);
// [
//   "Creating directory: /project/src/procedures/user",
//   "Creating procedure file: /project/src/procedures/user/create.ts",
//   "Creating index: /project/src/procedures/user/index.ts",
//   "Appending types to: /project/src/types.ts",
//   "Next steps: ..."
// ]

API Reference

Procedures

procedure.new

Scaffold a new procedure with type definitions and boilerplate.

interface ProcedureNewInput {
  name: string;              // Dot-notation name (e.g., "user.create" or "fs.readJson")
  namespace?: string;        // Namespace override: the folder under src/procedures (defaults to first segment)
  description?: string;      // Procedure description
  path?: string;             // Project path (defaults to cwd)
  dryRun?: boolean;          // Preview without creating files
}

interface ProcedureNewOutput {
  success: boolean;
  procedurePath: string[];   // e.g., ["user", "create"]
  created: string[];         // Files created
  modified: string[];        // Files modified
  operations: string[];      // Operations performed
  errors: string[];          // Any errors
}

Example:

const result = await client.exec(["procedure", "new"], {
  name: "user.create",
  description: "Create a new user",
  path: "/path/to/package",
});

Generated Files:

The file of a procedure is src/procedures/<first segment>/<middle segments>/<last segment>.ts: api.v2.users.create gives src/procedures/api/v2/users/create.ts.

  1. Procedure File (src/procedures/user/create.ts):
/**
 * user.create procedure
 *
 * Create a new user
 */

import type { UserCreateInput, UserCreateOutput } from "../../types.js";

/**
 * Create a new user
 */
export async function userCreate(_input: UserCreateInput): Promise<UserCreateOutput> {
  // TODO: Implement user.create (rename _input to input when the code uses it)
  return {
    success: true,
    message: "Hello from user.create",
  };
}
  1. Type Definitions (appended to src/types.ts, which gets import { z } from "zod" if it has none, or is created):
// =============================================================================
// user.create Types - Create a new user
// =============================================================================

export const UserCreateInputSchema: z.ZodObject<{
  // TODO: Add input fields
}> = z.object({
  // TODO: Add input fields
});

export type UserCreateInput = z.infer<typeof UserCreateInputSchema>;

export interface UserCreateOutput {
  /** Whether the operation succeeded */
  success: boolean;
  /** Response message */
  message: string;
}
  1. Index Export (appended to src/procedures/user/index.ts):
export { userCreate } from "./create.js";
  1. Registration (added to src/register.ts: the imports, the definition, and the item of the registerProcedures([...]) array):
import { createProcedure, outputSchema, registerProcedures, zodAdapter } from "@procedures/client";
import { userCreate } from "./procedures/user/create.js";
import { UserCreateInputSchema, type UserCreateInput, type UserCreateOutput } from "./types.js";

const userCreateProcedure = createProcedure()
  .path(["user", "create"])
  .input(zodAdapter<UserCreateInput>(UserCreateInputSchema))
  .output(outputSchema<UserCreateOutput>())
  .meta({
    description: "Create a new user",
    args: [],
    shorts: {},
    output: "text",
  })
  .handler(async (input: UserCreateInput): Promise<UserCreateOutput> => userCreate(input))
  .build();

export function register(): void {
  registerProcedures([userCreateProcedure]);
}

If src/register.ts has no registerProcedures([...]) or registerAll([...]) call, the operations say what to add.

procedure.list

List the procedures of the registry, with an optional namespace filter.

interface ProcedureListInput {
  namespace?: string;         // Only the procedures of this first path segment
  includeMetadata?: boolean;  // Default: false
}

interface ProcedureListOutput {
  procedures: Array<{
    path: string[];
    key: string;              // "git.commit"
    description?: string;
    tags?: string[];
    hasHandler: boolean;
  }>;
  count: number;
}
const { procedures, count } = await client.exec(["procedure", "list"], { namespace: "git" });

procedure.get

Get the metadata of one procedure.

interface ProcedureGetInput {
  path: string[] | string;    // ["git", "commit"] or "git.commit"
}

interface ProcedureGetOutput {
  found: boolean;
  path?: string[];
  metadata?: Record<string, unknown>;
  hasHandler?: boolean;
  hasInputSchema?: boolean;
  hasOutputSchema?: boolean;
}

procedure.export

Export the path and the metadata of one procedure as a call ($proc).

interface ProcedureExportInput {
  path: string[] | string;
}

interface ProcedureExportOutput {
  success: boolean;
  definition?: { $proc: string[]; metadata?: Record<string, unknown> };
  error?: string;             // When the procedure does not exist
}

[!NOTE] The core package client also has procedure.list and procedure.get, for the procedures that procedure.define made. client-procedure registers its own versions with override: true. Thus the result depends on whether the host imports client-procedure: mark and the MCP server do.

Examples

Scaffold a Nested Procedure

const result = await client.exec(["procedure", "new"], {
  name: "api.users.permissions.grant",
  description: "Grant permission to a user",
});

// Generated path: ["api", "users", "permissions", "grant"]
// File: src/procedures/api/users/permissions/grant.ts

Dry Run Mode

// The plan of the scaffold, without a change of a file
const preview = await client.exec(["procedure", "new"], {
  name: "product.update",
  dryRun: true,
});

console.log(preview.operations);

Integration

Use with CLI

The procedure.new command is also available via the Mark CLI:

# Scaffold a new procedure
node packages/mark/dist/cli.js procedure new user.create --path packages/my-package

# With options
node packages/mark/dist/cli.js procedure new user.update \
  --description "Update user information" \
  --path packages/my-package \
  --dry-run

Use in Package Development

  1. Create package structure:
node packages/mark/dist/cli.js lib new my-client-package
pnpm install
  1. Scaffold procedures:
node packages/mark/dist/cli.js procedure new myapp.start --path packages/myapp
node packages/mark/dist/cli.js procedure new myapp.stop --path packages/myapp
node packages/mark/dist/cli.js procedure new myapp.status --path packages/myapp
  1. Implement handlers: Edit the generated files in src/procedures/myapp/*.ts. procedure new registered each procedure in src/register.ts.

  2. Build and test:

pnpm build
pnpm test

Naming Conventions

Procedure names follow dot-notation:

  • Single segment: greet → ["greet"]
  • Two segments: user.create → ["user", "create"]
  • Nested: api.users.permissions.grant → ["api", "users", "permissions", "grant"]
  • camelCase segments: fs.readJson → ["fs", "readJson"]

Generated identifiers:

  • camelCase for function names: user.create → userCreate
  • PascalCase for types: user.create → UserCreate
  • Files: the last segment, in the folders of the other segments: user.create → user/create.ts, api.users.permissions.grant → api/users/permissions/grant.ts

Two names can give the same identifiers (a.b.c and a.bC both give aBC). The second one is an error.

Requirements

  • Node.js: >= 22
  • TypeScript: >= 5.0
  • Dependencies:
    • @procedures/client (workspace:*)
    • zod ^3.24.0

License

MIT

See Also

  • @procedures/client - Core client/procedure system
  • @procedures/mark - CLI that uses procedure.new for scaffolding
  • Package scaffolding guide in ecosystem documentation