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

poke-crucible

v0.1.0

Published

Headless Gen 3 OU battle harness that ranks, critiques, and evolves Teams by Strength.

Readme

poke-crucible

Run masses of headless Gen 3 OU battles to rank Teams by how often they win. Both sides of every Battle are driven by one fixed, competent heuristic Pilot, so a result measures the Team, not the player. Three capabilities, each a single seam built on the last:

  • evaluate (Slice 1) — rank Teams by Strength against a fixed Gauntlet, or round-robin.
  • critique (Slice 2) — an LLM Critic explains one Team's weaknesses and matchup holes.
  • design (Slice 3) — the Designer evolves stronger Teams, with the LLM proposing mutations and naming the Archetypes it discovers.

Vocabulary lives in CONTEXT.md; the specs are the PRDs under docs/; decisions are the ADRs.

Install & build

npm install
npm run build      # compiles TypeScript to dist/

Requires Node ≥ 20. The stack is in-process TypeScript on the @pkmn/* toolkit (@pkmn/sim, @pkmn/sets, @pkmn/data) — no server, no network, no Python (ADR 0001).

CLI

# Absolute Strength vs the fixed Gauntlet
node dist/cli.js eval --mode gauntlet team.txt

# Relative Strength: rank several of your own Teams round-robin
node dist/cli.js eval --mode round-robin teamA.txt teamB.txt teamC.txt

# Pipe a single Team paste in on stdin
cat team.txt | node dist/cli.js eval

Options: --mode <gauntlet|round-robin> (default gauntlet), --battles <N> (default 100), --seed <string>, --gauntlet-version <v>, --out <file> (default poke-crucible-results.json). Each team file is standard Showdown export/paste text; multiple Teams in one file are separated by === [gen3ou] Name === header lines.

The CLI prints a ranked Strength table (with a 95% confidence interval and a per-matchup breakdown) and writes the full structured result to --out.

Programmatic API

The base seam is evaluate — the Critic and Designer build on it, not on the CLI:

import { evaluate } from 'poke-crucible';

const result = await evaluate({
  teams: showdownPasteText,              // string or array of pastes/{name,paste}
  opposition: { mode: 'gauntlet' },      // or { mode: 'round-robin' }
  battlesPerPairing: 100,
  seed: 'my-seed',
});
// result: ranked Strength rows (per-matchup win-rates tagged with Archetype),
// the seed, the Gauntlet version, and any illegal-Team validation errors.

Illegal Teams never throw past the seam — they come back as result.errors, named, so a bad Team can't silently poison a run.

How it works

  • Pilot (ADR 0002): one shared Gen 3 heuristic, identical on both sides, built in competence layers — secure a KO → pivot out of a losing matchup → recover → lay Spikes / spin → spread Toxic/burn/paralysis → set up → max damage. Every Strength number is relative to this Pilot.
  • Determinism: a master seed threads through @pkmn/sim's PRNG; each pairing's Battles derive sub-seeds deterministically and sides are swapped 50/50, so a fixed seed reproduces identical results.
  • Gauntlet (ADR 0003): a fixed, versioned roster of Archetype-labeled Gen 3 OU Teams. Every result records the version, so 62% Strength means the same thing next week. Two versions ship: g1 (default; hand-authored) and g2 (real Smogon ADV OU sample teams, fetched verbatim, --gauntlet-version g2). g1 stays the default baseline; swapping it is a deliberate rebaseline.
  • Parallelism: --concurrency <N> (or POKE_CONCURRENCY) runs Battles across N worker threads. All Battles of a run are dispatched together so the pool stays saturated; results are byte-identical to serial (each Battle keeps its own seed). Default is 1 (inline). It pays off on big, expensive runs — the Designer, large evaluations — where it gives roughly a 2× speedup on 4 workers; for small/fast runs the thread overhead can make it a wash, hence the default.

Gauntlet provenance (a deliberate deviation)

The design envisioned sourcing the Gauntlet from Smogon's sample teams + usage stats via fetch-and-parse. That is deferred: the g1 roster is hand-authored from canonical Smogon Gen 3 OU sets (see src/gauntlet/teams-g1.ts). Because the Gauntlet is versioned and every result records its version, re-sourcing later is a g2 bump, not a rewrite — nothing silently drifts.

Critic (LLM analysis — Slice 2)

Turn an evaluation into a readable, grounded critique of one Team:

node dist/cli.js critique team.txt
node dist/cli.js critique --model claude-sonnet-5 --effort low --battles 100 team.txt

The Critic runs the evaluation, then asks Claude (via the Claude Agent SDK) to explain the Team's weaknesses, the Archetypes that exploit them, the mechanism, and concrete legal fixes — writing a structured Critique JSON. It is told the Pilot under-rates stall (ADR 0004), so it caveats defense-dependent verdicts rather than presenting them as ground truth.

Auth (individual use): the Critic runs on your Claude subscription, not a pay-per-token key. Log in with Claude Code (or set CLAUDE_CODE_OAUTH_TOKEN), and make sure ANTHROPIC_API_KEY is unset — it shadows the subscription OAuth token and reverts to per-token billing. The model is called with all tools disabled and low reasoning effort; nothing runs on your filesystem.

Programmatically the seam is critique(input, model) / critiqueTeam(paste, model, opts); the model is any CritiqueModel (use StubCritiqueModel in tests, AgentSdkCritiqueModel live). See docs/prd-slice-2-critic.md.

Designer (discovery — Slice 3)

Evolve stronger Teams automatically. A population of legal Teams is scored each generation by a composite fitness (Gauntlet Strength + peer round-robin + a worst-matchup robustness term), bred by mutation and crossover, with the LLM proposing variants — driven by the Critic's findings — and naming the Archetypes it discovers.

# Evolve from a starting Team (omit the file to search from scratch)
node dist/cli.js design --population 8 --generations 4 team.txt

# Random operators only — no LLM, no subscription call
node dist/cli.js design --no-llm --population 8 --generations 4

Options: --population, --generations, --battles (per fitness pairing), --model / --effort (Designer LLM), --no-llm, --seed, --gauntlet-version, --out. Every candidate is validated legal Gen 3 OU; the run is deterministic under its seed and reports each Team's lineage, Archetype name, fitness components, plus the budget used and total Battles run. To bound compute it caches unchanged Teams, screens cheaply before spending full battles on contenders, and honours a hard battle cap.

Programmatically the seam is design(input, model, options); the model is any DesignerModel (StubDesignerModel for tests, AgentSdkDesignerModel live), and an optional critic lets the Critic drive the mutation proposals. Auth is the same subscription path as the Critic. See docs/prd-slice-3-designer.md.

Fitness is deliberately not raw win-rate (ADR 0004) — it rewards well-rounded Teams over glass cannons and dampens the Pilot's offense lean (see the limitation below for how far that goes).

Testing (the trust gate)

npm run typecheck
npm test

The suite asserts external behavior only, through the evaluate() seam (never the Pilot's individual move choices): determinism, sanity ordering (a strong Team out-Strengths a weak one), archetype non-bias (a solid stall Team stays competitive in a head-to-head ladder of the eight archetypes and can beat offense — the live check that the Pilot isn't biased against defense), legality, and stable win-rates. Every Gauntlet Team is asserted legal Gen 3 OU.

Known limitation: the Pilot's offense lean

The shared greedy Pilot systematically under-rates stall — offense plays near-optimally under greedy heuristics while stall needs long-term planning. In an archetype-vs-archetype ladder the best stall Team lands mid-lower (≈38% Strength, 6th of 8), not mid-pack.

This was probed exhaustively (ADR 0004): three Pilot improvements (anticipatory switching, tempo tweaks, a positional-eval Pilot) all failed to lift stall; real-sim look-ahead is infeasible (@pkmn/sim state can't be resumed after deserialization); and the Designer's composite fitness only partly corrects the lean — stall's worst matchups are genuinely ~0% under the Pilot, so a robustness term can't recover them.

The lean is therefore a known, bounded, documented property of the greedy-Pilot design, not a bug — every Strength number is explicitly relative to this Pilot (ADR 0002). Closing it needs a stronger Pilot (a shallow search or ML policy — deferred) or a non-Pilot signal of a Team's merit; both are future work. The Critic caveats defense-dependent verdicts and the Designer's fitness avoids rewarding glass cannons, so the slices degrade gracefully rather than silently trusting the lean.