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

@patchdock/sdk

v0.1.0-alpha.0

Published

Patchdock agent SDK: typed contracts, stage definitions, and the container runtime harness.

Readme

Patchdock SDK

Patchdock SDK is the typed authoring layer for agents that run inside a Patchdock pipeline. It lets a project define planner, executor, and reviewer agents while the main Patchdock instance continues to own orchestration, containers, mounts, retries, audit logs, and runtime validation.

The SDK keeps agent code focused on one contract:

typed input + preassigned context -> agent -> typed output

Patchdock supplies the input and context. The agent may use any logic or model internally, but its output must satisfy the stage contract so the next pipeline stage can consume it.

Installation

dock init is the recommended way to begin: it scaffolds .patchdock/ with starter agent files already matched to the runtime configuration. See Getting started.

To add the SDK to an existing TypeScript project instead:

pnpm add @hjyup/patchdock-sdk@alpha

The SDK is in alpha, so releases land on the alpha dist-tag and the API may still change between versions. Pin an exact version if you need stability. RELEASING.md covers how versions are cut.

Define agents and their contracts

Every agent file must default-export one of the three stage definitions: definePlanner, defineExecutor, or defineReviewer. The examples below use the built-in Codex adapter.

definePlanner

The planner receives a task and produces the plan that drives the rest of the pipeline.

import { codex, definePlanner } from "@hjyup/patchdock-sdk";

export default definePlanner({
  async run(ctx, input) {
    return codex(ctx, input);
  },
});

Planner input and output:

interface PlannerInput {
  task: Task;
}

interface PlanData {
  summary: string; // 1-2 sentences, shown in run results
  body: string; // markdown: the full plan
}

type PlannerRun = (ctx: StageContext, input: PlannerInput) => Promise<PlanData>;

Patchdock adds the creation timestamp after the planner returns. Nothing in the contracts carries an ID: the run ID (ctx.runId) and the attempt number address every stage output, so agents never mint or echo identifiers.

Structure inside body (approach, ordered steps, acceptance criteria) is a prompt convention for the executor and reviewer to read, not a schema. Keep the conventional headings so downstream stages know where to look.

defineExecutor

The executor receives the plan and previous review feedback, then works in the writable workspace.

import { codex, defineExecutor } from "@hjyup/patchdock-sdk";

export default defineExecutor({
  async run(ctx, input) {
    return codex(ctx, input);
  },
});

Executor input and output:

interface ExecutorInput {
  plan: Plan;
  reviews: Review[];
}

interface ExecutionResultData {
  status: "success" | "partial_success" | "failed";
  notes?: string; // markdown: what was done, what worked, what didn't
}

type ExecutorRun = (
  ctx: StageContext,
  input: ExecutorInput,
) => Promise<ExecutionResultData>;

The executor does not return a patch. It modifies files under ctx.paths.workspace, and the main Patchdock process extracts the authoritative git diff after execution.

defineReviewer

The reviewer receives the plan and execution history, then returns an accept or reject decision.

import { codex, defineReviewer } from "@hjyup/patchdock-sdk";

export default defineReviewer({
  async run(ctx, input) {
    return codex(ctx, input);
  },
});

Reviewer input and output:

interface ReviewerInput {
  plan: Plan;
  execution_results: ExecutionResult[];
  previous_reviews: Review[];
}

interface ReviewData {
  decision: "accept" | "reject";
  summary: string;
  feedback?: string; // markdown; required when decision is "reject"
}

type ReviewerRun = (ctx: StageContext, input: ReviewerInput) => Promise<ReviewData>;

On reject, feedback becomes the executor's context for the next attempt. By convention, list each issue with a severity and file:line reference so the retry knows exactly what to fix.

Customising agent behaviour

Codex does not own the stage definition. The project can inspect or transform the typed context and input before deciding how to invoke it:

import { codex, defineExecutor } from "@hjyup/patchdock-sdk";

export default defineExecutor({
  async run(ctx, input) {
    ctx.log(`Starting executor attempt ${ctx.attempt}/${ctx.maxAttempts}`);

    if (input.reviews.length > 0) {
      ctx.log("Passing previous review feedback to Codex");
    }

    return codex(ctx, input);
  },
});

The built-in model adapter is optional. A definition can instead run any code the project needs: a different provider, a local model, project-specific tools and services, or deterministic logic combined with model output. For example, a project can replace the Codex adapter with its own executor:

import {
  defineExecutor,
  type ExecutorInput,
  type ExecutionResultData,
  type StageContext,
} from "@hjyup/patchdock-sdk";
import { runMyModel } from "./my-model";
import { toExecutorOutput } from "./contracts";

async function run(
  ctx: StageContext,
  input: ExecutorInput,
): Promise<ExecutionResultData> {
  const result = await runMyModel({ ctx, input });
  return toExecutorOutput(result);
}

export default defineExecutor({ run });

The strict boundary is the returned output: it must satisfy PlanData, ExecutionResultData, or ReviewData for the pipeline to continue.

Supported models

| Model | Status | Import | | ------ | -------- | ---------------- | | Codex | Built in | @hjyup/patchdock-sdk | | Claude | Planned | n/a |

Built-in adapters use the same context and contracts as custom agents, so swapping between them requires no changes to the surrounding pipeline.

Into the details

How an agent is loaded

Each agent filename must match the stage mapping in .patchdock/config.yml:

stages:
  planner: planner.ts
  executor: executor.ts
  reviewer: reviewer.ts

The main Patchdock instance then consumes the file as follows:

write typed input
    -> mount configured agent
    -> import its default definition
    -> validate input
    -> call run(ctx, input)
    -> validate output
    -> stamp the plan's creation timestamp
    -> pass result to the next stage

Context

Patchdock constructs StageContext before invoking an agent:

type Stage = "planner" | "executor" | "reviewer";

interface StageContext {
  stage: Stage;
  runId: string;
  paths: {
    repo?: string;
    workspace?: string;
  };
  tokenBudget: number | null;
  attempt: number;
  maxAttempts: number;
  log: (entry: string | StageLogEvent) => void;
}

interface StageLogEvent {
  source: string;
  event: string;
  level?: "debug" | "info" | "warn" | "error";
  message?: string;
  [field: string]: unknown;
}
  • stage identifies which definition is running.
  • runId identifies the current run. It is the only identity Patchdock assigns, and it names the run's audit log directory, published branch, and stage containers.
  • paths contains the conventional mount locations available to the stage.
  • tokenBudget contains the configured budget or null when unlimited.
  • attempt and maxAttempts let retry-aware agents adapt their behaviour.
  • log(entry) writes a structured event or a plain agent message into the Patchdock audit log.

Use ctx.log for progress and diagnostic information:

ctx.log(`Running ${ctx.stage} for run ${ctx.runId}`);

ctx.log({
  source: "my-agent",
  event: "verification_completed",
  level: "info",
  command: "pnpm test",
  exit_code: 0,
});

The stage audit stream is JSON Lines. Plain strings are wrapped as agent/message events. The Codex adapter records lifecycle, command, file-change, tool-call, error, and token-usage summaries; it deliberately excludes reasoning, agent prose, command output, tool arguments/results, and patch bodies. Logs are not contract output: only the object returned from run is passed to the pipeline.

Runtime toolchains

The scaffolded agent image targets TypeScript and JavaScript repositories: Debian Bookworm with Node.js 22, npm, tsx, Git, ripgrep, make, and curl, and no C toolchain, Python, or other language runtime. PATCHDOCK_TOOLCHAIN_SUMMARY in the Dockerfile is injected verbatim into every agent prompt, so a repository that needs a different toolchain must extend the image and that summary together.

Codex is also instructed to inspect repository manifests and lockfiles, prefer existing repository scripts, run focused checks after editing, and report missing tools or unrun checks instead of implying verification succeeded.

Mounts

Mounts are capabilities assigned by the main Patchdock runtime:

| Stage | Path | Access | Purpose | | ------------ | ------------ | ---------- | ------------------------------------------------------ | | Planner | /repo | Read-only | Inspect the original repository while producing a plan | | Executor | /workspace | Read-write | Modify the isolated repository clone | | Reviewer | /workspace | Read-only | Inspect the executor's resulting workspace | | All stages | /agents | Read-only | Load configured agent modules | | Runtime only | /io | Read-write | Exchange validated input and output JSON |

Read locations from ctx.paths instead of hardcoding them, and only use the path assigned to the current stage. Changes made outside /workspace are container-local and disappear with the container, so executor edits must be written under ctx.paths.workspace for Patchdock to extract them.

Contract and validation rules

Contracts are checked at two boundaries:

  1. The TypeScript SDK validates input before the agent runs and validates its returned output afterward.
  2. The Go host validates the same domain contract again before the result reaches the next stage or the audit record.

Validation failures stop the stage. Invalid data is never passed to the next agent.

The main rules agent authors need to respect are:

  • Default-export one definition matching the configured stage.
  • Return the output type belonging to that definition.
  • Use snake-case JSON field names such as execution_results and previous_reviews.
  • Planner output requires a non-empty summary and body.
  • Executor status must be success, partial_success, or failed.
  • Reviewer decision must be accept or reject; a rejected review must carry non-empty feedback (accepted reviews may include it for non-blocking notes).
  • Do not return identifiers, timestamps, or the executor patch. The run ID and the attempt number are the runtime's to assign, and both already reach you on ctx.
  • Write executor file changes only into the writable workspace.

Development checks

When changing the SDK or its examples, run:

cd sdk
pnpm typecheck
pnpm lint
pnpm test
pnpm format:check

The files generated by dock init should remain aligned with the definitions and contracts documented here.