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

ceo-engine

v0.1.0

Published

Monte Carlo tree search engine for prompt optimization.

Downloads

184

Readme

ceo-engine

A bandit-algorithm-based prompt optimizer for large language models.

Given a set of models, prompt templates, and inputs, ceo-engine searches for the combination that maximizes a quality signal within a budget. It organizes the search space as a three-level tree (Model, then Template, then Prompt) and runs multi-armed bandit strategies over that tree.

The library is provider-agnostic: it never calls an LLM itself. The caller drives a select/observe loop, sends the selected prompt to whatever LLM client they use, scores the response, and reports the result back. This keeps the engine deterministic and testable, and keeps all network and key handling on the caller's side.

Installation

ceo-engine is published to the npm registry and installs with any of the common package managers:

npm install ceo-engine
pnpm add ceo-engine
yarn add ceo-engine
bun add ceo-engine

The package ships dual type declarations and ESM, so it works the same across all four toolchains. Within this workspace it is consumed locally as a file dependency instead:

{
  "dependencies": {
    "ceo-engine": "file:../ceo-engine"
  }
}

Local development

Clone the repository, install dependencies, and build the distributable (type declarations plus ESM into dist):

npm install   && npm run build
pnpm install  && pnpm build
yarn          && yarn build
bun install   && bun run build

dev runs the local entry under tsx for quick experiments, and clean removes the dist directory.

Tests

The suite runs under Mocha, loading TypeScript through tsx (configured in .mocharc.json); specs live in test/:

npm test          # pnpm test, yarn test, or bun run test
npm run test:coverage   # coverage report via nyc

Note for bun users: run scripts as bun run test rather than bun test, since bun test invokes bun's own test runner instead of this package's Mocha script.

Quick start

import {
  PromptCeoEngine, TokenBudget,
  ThompsonSamplingSelector, LevelTraversal,
  LeafPropagation, NoPruning,
} from 'ceo-engine';

const engine = new PromptCeoEngine({
  models:    [{ id: 'anthropic:claude-haiku-4-5-20251001' }],
  templates: [
    { id: 'direct', content: '{{question}}' },
    { id: 'cot',    content: 'Think step by step.\n\n{{question}}' },
  ],
  variables:        [{ question: 'What is 2+2?' }],
  budget:           new TokenBudget(10000),
  treeTraversal:    new LevelTraversal(),
  nodeSelector:     new ThompsonSamplingSelector(),
  rewardAssignment: new LeafPropagation(),
  pruneStrategy:    new NoPruning(),
  optimizationMode: { type: 'leaf' },
  costPenalty:      0,
});

while (!engine.budget.exhausted) {
  const sel = engine.select();
  const response = await myLLMClient(sel.promptText);
  const quality  = myScorer(response);
  engine.observe(sel.selected, {
    quality,
    cost: countTokens(sel.promptText, response),
    rawResponses: [response],   // optional, included in engine.history
  });
}

// engine.history is populated automatically, no manual tracking needed
const { history } = engine;

To silence logging:

import { setLogger, NoopLogger } from 'ceo-engine';
setLogger(new NoopLogger());

How it works

A run is configured by four pluggable algorithm slots plus a budget:

  • nodeSelector: chooses which arm to pull at each tree level (the bandit policy).
  • treeTraversal: decides how the tree is walked when selecting and expanding.
  • rewardAssignment: propagates an observed reward through the tree.
  • pruneStrategy: removes unpromising branches as evidence accumulates.

The budget is the stopping condition. optimizationMode is either leaf (evaluate prompt leaves directly) or structure (evaluate aggregated samples per structure node). costPenalty turns on cost-aware scalarization so the reward trades quality against token cost.

Public API

src/index.ts re-exports the full surface. The main groups:

  • High-level prompt optimization: PromptCeoEngine, evaluation, generator interface, analytics, session, and controller (from prompt-ceo/).
  • Algorithm classes for each slot (selectors, traversals, rewards, pruning).
  • Posteriors, budgets, and scaling/scalarization strategies.
  • factories/: preset strategy bundles.
  • registry/: runtime plugin system, including createSelector, createPosterior, createBudget, and createEngine for building components from string ids.
  • Pareto helpers (computeParetoFrontier, dominates, computeCrowdingDistance) and logging (setLogger, NoopLogger).

Module map

  • prompt-ceo/: high-level public API on top of the core engine.
  • engines/: the tree-based bandit engine and base interfaces.
  • selectors/: ThompsonSampling, UCB, Random, SuccessiveHalving, Pareto, Active.
  • traversals/: Level, Depth, Beam, MCTS.
  • rewards/: Leaf, Full, Decay, Depth, Entropy propagation.
  • pruning/: NoPruning, TopK, ConfidenceBound, SuccessiveHalving, SequentialHalving.
  • posteriors/: Beta, NIG, multi-objective, and preference/feedback.
  • budgets/: Token, Time, Api, Human, Composite.
  • scaling/: CEOScaler, Chebyshev, Adaptive, QualityOnly, weighted scalarization.
  • factories/: strategy preset bundles.
  • registry/: runtime component registration and string-id construction.
  • tree/, primitives/, adapters/, utils/: tree structure, shared types, integration adapters, and logging.

Reproducibility

Seeded runs are byte-exact across versions: under a fixed seed the numeric sequence the engine emits is preserved. Any change that alters the order or count of pseudo-random draws (the samplers in utils/random.ts, posteriors/nig.ts, Beta sampling, or Fisher-Yates shuffling) breaks this guarantee and is avoided.

Roadmap

  • Multi-objective reward propagation (a vector of rewards up the tree) alongside the current single-scalar reward contract.
  • Preset configuration bundles in configs/presets.ts (for example Presets.default(), Presets.fast(), Presets.explore()).
  • Per-algorithm static metadata (id, name, description, hyperparameter schema) to enable config serialization, sweeps, and generated docs.
  • Self-registering algorithms so importing a class is enough to make it available by string name, with a runtime-enumerable algorithm catalogue exported from the public API.
  • Hyperband bracket scheduler wrapping Successive Halving.
  • A headless adapter directory and a planned Python wrapper that bundles the compiled JS and drives the same select/observe loop over a subprocess.