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

@zkops/keel

v1.0.0

Published

Privacy-preserving AI pipeline SDK for Midnight Network

Readme

keel

Privacy-preserving AI pipeline SDK for Midnight Network.

@zkops/keel provides a composable pipeline abstraction for building verifiable, privacy-preserving workflows on Midnight. It bridges AI inference, zero-knowledge proof generation, and on-chain execution — giving developers a typed, observable interface for orchestrating multi-step workflows where computation is private, outputs are verifiable, and audit trails are cryptographically anchored.

npm version License Build


Installation

npm install @zkops/keel

Peer dependencies are optional and only required when using the corresponding sub-modules:

npm install ollama              # for @zkops/keel/witness with Ollama
npm install @anthropic-ai/sdk  # for @zkops/keel/witness with Anthropic
npm install openai             # for @zkops/keel/witness with OpenAI

Modules

The package exposes three entry points:

| Import path | Description | |---|---| | @zkops/keel | Core pipeline engine | | @zkops/keel/witness | AI model as a private ZK witness input | | @zkops/keel/prov | PROV-O provenance tracing with on-chain anchoring |


Core Pipeline

Build typed, observable pipelines from composable stages. Each stage is named and emits structured lifecycle events.

import { Pipeline, localStage, zkStage, anchorStage } from '@zkops/keel'

const pipeline = new Pipeline()
  .addStage(localStage('validate', async (input) => validate(input)))
  .addStage(zkStage('prove',       async (input) => generateProof(input)))
  .addStage(anchorStage('commit',  async (proof) => anchor(proof)))

const result = await pipeline.run(myInput, {
  onEvent: (e) => console.log(`[${e.kind}] ${e.stageName} ${e.durationMs}ms`)
})

Stage kinds

| Factory | Kind | Use when | |---|---|---| | localStage | local | Off-chain computation, data preparation | | zkStage | zk | ZK proof generation, Midnight contract interaction | | anchorStage | anchor | On-chain commitment, ledger writes | | branchStage | branch | Conditional routing to different sub-stages | | conditionalStage | conditional | Optional stage execution based on runtime state | | parallelStage | parallel | Concurrent independent stage execution |


Branching and Conditional Logic

branchStage

Routes execution to a different stage based on the result of a developer-supplied condition function. The condition can return any string, boolean, or number — used as the key to select the matching branch. The branch decision is recorded in the event stream and provenance graph.

import { Pipeline, branchStage, localStage } from '@zkops/keel'

const pipeline = new Pipeline()
  .addStage(
    branchStage('classify-product', {
      condition: (product) => product.category,
      branches: {
        pharmaceutical: pharmComplianceStage,
        textile:        textileComplianceStage,
        food:           foodSafetyStage,
      },
      fallback: defaultComplianceStage,
    })
  )

The fallback stage is optional. If no matching branch is found and no fallback is configured, the stage throws with a descriptive error.

conditionalStage

Runs a stage only when a condition returns true. When the condition returns false, the input passes through unchanged unless a fallback function is provided.

import { Pipeline, conditionalStage } from '@zkops/keel'

const pipeline = new Pipeline()
  .addStage(
    conditionalStage('high-value-review', {
      condition: (tx) => tx.value > 10_000,
      stage:     aiReviewStage,
      fallback:  async (tx) => ({ ...tx, reviewed: false }),
    })
  )

parallelStage

Runs multiple independent stages concurrently against the same input. Results are collected and passed to a developer-supplied merge function. If any stage throws, the parallel stage throws immediately.

import { Pipeline, parallelStage, localStage } from '@zkops/keel'

const pipeline = new Pipeline()
  .addStage(
    parallelStage('compliance-checks', {
      stages: [
        localStage('origin-check',    runOriginCheck),
        localStage('quality-check',   runQualityCheck),
        localStage('sanctions-check', runSanctionsCheck),
      ],
      merge: (results) => ({
        passed: results.every((r) => r.passed),
        checks: results,
      }),
    })
  )

AI Witness

Use AI model outputs as private inputs to ZK circuits. The model call runs locally or remotely via a provider-agnostic interface. The prompt, model output, and reasoning never reach the chain. A cryptographic receipt — containing hashed prompt, hashed output, model identity, and timestamp — is produced alongside the structured output.

import { Pipeline, zkStage }             from '@zkops/keel'
import { aiWitnessStage, ollamaWitness } from '@zkops/keel/witness'
import { z }                             from 'zod'

const witness = ollamaWitness({
  model:   'llama3.2',
  baseUrl: 'http://localhost:11434',
})

const DecisionSchema = z.object({
  approved:   z.boolean(),
  confidence: z.number().min(0).max(100),
  reason:     z.string(),
})

const pipeline = new Pipeline()
  .addStage(
    aiWitnessStage('ai-guard', witness, {
      prompt: (input) => `Evaluate this operation: ${JSON.stringify(input)}`,
      schema: DecisionSchema,
      map:    (result, input) => {
        if (!result.output.approved) {
          throw new Error(`Rejected: ${result.output.reason}`)
        }
        return { ...input, receipt: result.receipt }
      },
    })
  )
  .addStage(
    zkStage('execute', async ({ input, receipt }) => submitToChain(input, receipt))
  )

Supported providers

| Provider | Factory | Requires | |---|---|---| | Ollama (local) | ollamaWitness | ollama | | Anthropic | anthropicWitness | @anthropic-ai/sdk | | OpenAI | openAIWitness | openai |

All providers implement the same AIWitnessProvider interface. Custom providers can be supplied by implementing that interface directly.


Provenance Tracing

Attach a provenance tracer to any pipeline to automatically record every stage execution as a PROV-O compliant activity. The resulting graph is content-addressed and can be anchored on-chain via any anchor provider.

import { Pipeline, localStage }           from '@zkops/keel'
import { ProvenanceTracer, consoleAnchor } from '@zkops/keel/prov'

const tracer = new ProvenanceTracer({
  agent: {
    id:      'my-service',
    type:    'zkops:pipeline',
    version: '1.0.0',
  },
  anchor: consoleAnchor(),
})

const pipeline = new Pipeline()
  .addStage(localStage('process', async (input) => process(input)))

tracer.attach(pipeline)

await pipeline.run(myInput)
await tracer.anchor()

const graph = tracer.getGraph()
console.log(graph.rootHash)   // deterministic hash of the full execution
console.log(graph.activities) // PROV-O activities, one per stage

Anchor providers

| Factory | Behaviour | |---|---| | noopAnchor() | Returns the hash without side effects. Suitable for testing. | | consoleAnchor() | Logs the hash to stdout. Suitable for development. | | customAnchor(fn) | Calls your function with the root hash. Wire up any ledger. |

Supply a customAnchor to write the hash to a Midnight contract, IPFS, or any other persistence layer:

import { customAnchor } from '@zkops/keel/prov'

const anchor = customAnchor(async (rootHash) => {
  const tx = await midnightClient.submitAnchor(rootHash)
  return {
    rootHash,
    anchoredAt:    Date.now(),
    transactionId: tx.id,
    blockHeight:   tx.blockHeight,
  }
})

Events

Every stage emits structured events to the onEvent callback and to any attached ProvenanceTracer. Events are typed as a discriminated union.

type PipelineEvent =
  | PipelineEventBase   // kind: 'start' | 'complete' | 'error'
  | BranchEvent         // kind: 'branch' — includes branchTaken and conditionKey
  | ParallelEvent       // kind: 'parallel' — includes stageNames
await pipeline.run(input, {
  onEvent: (e) => {
    if (e.kind === 'branch')   console.log(`branch: ${e.branchTaken} (key: ${e.conditionKey})`)
    if (e.kind === 'parallel') console.log(`parallel: ${e.stageNames.join(', ')}`)
    if (e.kind === 'error')    console.error(`error in ${e.stageName}:`, e.error)
  }
})

Repository Structure

packages/
  core/      internal — pipeline engine, stage primitives, types
  witness/   internal — AI witness providers and stage factory
  prov/      internal — PROV-O provenance tracer and anchor providers
  keel/      published — @zkops/keel umbrella package

examples/
  counter/   Midnight counter contract wrapped as a keel pipeline

The three internal packages are not published to npm. All public API is exported through @zkops/keel.


Development

Prerequisites

  • Node.js 22+
  • pnpm 9+

Setup

git clone https://github.com/zkops/keel.git
cd keel
pnpm install
pnpm build
pnpm test

Commands

| Command | Description | |---|---| | pnpm build | Build all packages via Turborepo | | pnpm test | Run all test suites with coverage | | pnpm lint | Run ESLint across all packages | | pnpm typecheck | Run TypeScript type checking | | pnpm release | Build and publish to npm via Changesets |


Contributing

Contributions are welcome. Please open an issue before submitting a pull request for significant changes. All pull requests require passing tests, lint, and type checks.


License

Apache-2.0. See LICENSE for details.

Portions of the counter example are based on the Midnight counter example by Midnight Foundation, also Apache-2.0. See examples/counter/NOTICE.