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

@inkeep/openbolts-engine-runtime

v0.0.5

Published

Declarative engine orchestration for OpenBolts. `runEngine({ tasks, model })` is the sole public entry point — it creates the database, task list, MCP server, and adapter internally. The bridge is an implementation detail; consumers declare what they want

Readme

@inkeep/openbolts-engine-runtime

Declarative engine orchestration for OpenBolts. runEngine({ tasks, model }) is the sole public entry point — it creates the database, task list, MCP server, and adapter internally. The bridge is an implementation detail; consumers declare what they want and the system derives the rest.

Installation

bun add @inkeep/openbolts-engine-runtime @inkeep/openbolts-core @inkeep/openbolts-mcp @inkeep/openbolts-adapter-vercel-ai

Install the provider package for your model:

bun add @ai-sdk/anthropic           # Anthropic (Claude)
bun add @ai-sdk/openai              # OpenAI (GPT-4o)

Quick Start

import { anthropic } from '@ai-sdk/anthropic';
import { runEngine } from '@inkeep/openbolts-engine-runtime';

// Minimal — 2 required fields
const handle = runEngine({
  tasks: [{ title: 'Build auth module' }],
  model: anthropic('claude-sonnet-4-20250514'),
});
const result = await handle.run();

console.log(result.status);              // 'completed' | 'escalated' | 'paused' | 'failed'
console.log(result.telemetry.totalSteps); // total LLM steps across invocations
console.log(result.telemetry.invocationCount); // number of session invocations
await handle.cleanup();

With hooks and limits

const handle = runEngine({
  tasks: [
    { id: 'spec', title: 'Write spec' },
    { id: 'impl', title: 'Implement', dependsOn: ['spec'] },
    { id: 'test', title: 'Write tests', dependsOn: ['impl'] },
  ],
  model: anthropic('claude-sonnet-4-20250514'),
  hooks: {
    onIterationEnd: async (outcome, ctx) => {
      // Re-run tests when all tasks complete; reset on failure to iterate again.
      if (outcome.reason === 'all_complete') {
        const tests = await runTestSuite();
        if (!tests.passed) {
          return { action: 'retry', resetTasks: ['impl'], context: tests.error };
        }
        return 'pause';
      }
      if (outcome.reason === 'budget_exhausted') return 'pause';
      // Non-transient crashes (auth errors, deterministic bugs) escalate —
      // retrying them wastes budget with zero chance of success.
      if (outcome.reason === 'crashed' && outcome.error?.isTransient === false) {
        return { action: 'escalate', reason: `Non-transient: ${outcome.error.message}` };
      }
      return 'retry'; // backoff applied automatically on retry-worthy crashes
    },
  },
  limits: { maxBudgetUsd: 5, maxIterations: 5 },
});

const result = await handle.run();

Worker path (escape hatch — no LLM)

When you want full programmatic control without an LLM session loop, pass a worker function instead of model. runEngine discriminates the config type and routes to the same hooks and delegation infrastructure.

const handle = runEngine({
  tasks: [{ id: 'build', title: 'Build feature' }],
  worker: async (ctx) => {
    const output = await runBuild();
    await ctx.complete(ctx.tasks[0].id, output);
  },
});

ctx provides typed async methods mirroring the MCP tool surface: complete, block, delegate, checkDelegations, requestInput, spawn, note. See WorkerContext in the SDK docs.

Abort / timeout

const handle = runEngine({ tasks: [{ title: 'Long task' }], model: myModel });

// Cancel after 5 seconds
const runPromise = handle.run();
setTimeout(() => handle.abort(), 5000);
const result = await runPromise;
// result.status === 'paused', result.statusMessage === 'Aborted'

// Or pass an external AbortSignal
const result2 = await handle.run({ signal: AbortSignal.timeout(30_000) });

API Reference

runEngine(config): EngineRuntimeHandle

Creates and returns a handle for executing the engine loop. The config is a discriminated union — provide model for the agent (LLM) path or worker for the programmatic path. Use isAgentConfig() / isWorkerConfig() to narrow.

AgentConfig (agent / LLM path)

| Field | Type | Required | Description | |-------|------|----------|-------------| | tasks | TaskDeclaration[] | Yes | Tasks with optional id, dependsOn, delegate, resultSchema | | model | LanguageModel \| ModelFactory | Yes | AI SDK model or factory | | instructions | string \| SystemModelMessage \| SystemModelMessage[] | No | System instructions (supports cache control) | | tools | Record<string, Tool \| MCPClientConfig \| StdioMcpConfig> | No | Additional tools (inline or MCP) beyond built-in engine tools | | skills | string[] | No | Skill names to discover and compose | | skillDirectories | string[] | No | Directories to search for skills | | stopWhen | StopCondition \| StopCondition[] | No | Inner tool-loop stop conditions | | hooks | { onIterationEnd?, onEscalation?, onTaskCompleted?, onTaskBlocked?, onTaskYielded? } | No | Iteration control + per-event observation hooks | | limits | { maxBudgetUsd?, maxBlockRetries?, maxIterations?, retryDelay? } | No | Engine limits + retry backoff config | | providerOptions | OpenBoltsProviderOptions | No | Provider-specific options (e.g., Claude Code settingSources, thinking) | | allowedTools, disallowedTools | string[] | No | Cross-provider tool scoping | | output | Output.object({ schema }) | No | Structured output from the agent | | elicitations | Record<string, { schema, description? }> | No | Pre-declared input request types | | db | DatabaseClient | No | Override default in-memory PGlite |

WorkerConfig (programmatic path)

| Field | Type | Required | Description | |-------|------|----------|-------------| | tasks | TaskDeclaration[] | Yes | Tasks with optional id, dependsOn, delegate | | worker | (ctx: WorkerContext) => Promise<void> | Yes | Worker function — calls ctx.complete / ctx.block / ctx.delegate / etc. | | hooks, limits, db | — | No | Same shared fields as AgentConfig |

EngineRuntimeHandle

interface EngineRuntimeHandle<TResult = unknown> {
  readonly runId: RunId;
  readonly journalId: JournalId;
  readonly listId: ListId;
  run(opts?: { signal?: AbortSignal }): Promise<RuntimeResult<TResult>>;
  abort(): void;
  /**
   * Resolve one or more pending child-escalations programmatically.
   * Returns `true` if at least one escalation was resolved.
   */
  resolveEscalation(resolutions: EscalationResolution[]): boolean;
  cleanup(): Promise<void>;
  [Symbol.asyncDispose](): Promise<void>;
}

await using handle = runEngine(config) is supported — cleanup fires automatically when the scope exits.

RuntimeResult

Discriminated union on status (MCP Tasks-aligned enum; 4 terminal states on the sync path):

| Variant | Fields | Description | |---------|--------|-------------| | completed | results: Map<string, TResult>, output?: TOutput, telemetry, children | All tasks completed; onIterationEnd returned pause on the all_complete outcome | | escalated | statusMessage: string, telemetry, children | Engine escalated (e.g., onIterationEnd returned escalate, non-transient crash) | | paused | statusMessage: string, telemetry, children | Engine paused (abort, budget exhausted, aborted during retry delay) | | failed | statusMessage: string, error: Error, telemetry, children | Unrecoverable error |

'working', 'input_required', and 'cancelled' are additional statuses on the async EngineRunResult (MCP lifecycle tools) but are not reachable via await handle.run() — see packages/docs/content/engine.mdx for the full terminal-states discussion.

RuntimeTelemetry

interface RuntimeTelemetry {
  totalSteps: number;
  invocationCount: number;
  totalInputTokens: number;
  totalOutputTokens: number;
  totalReasoningTokens: number;
  /** Cumulative wait time in ms across all retry backoffs in this run. */
  totalRetryDelayMs?: number;
  /** Count of D32 silent session-resume fallbacks observed (Claude Code only). */
  sessionResumeFallbacks?: number;
}

Utility exports

| Export | Description | |--------|-------------| | buildPrompt(item, config) | Assembles task prompt with journal context and dependency status | | buildSessionPrompt(config) | Session-scoped prompt with task overview + journal + delegation status | | mapExitReasonToAdapterResult(result) | Maps adapter exit reasons to engine action types | | discoverSkills(names, dirs?) | Loads skill metadata from directories | | composeInstructions(skills) | Composes skill instructions into system messages | | flattenInstructions(instructions) | Normalizes instruction variants to SystemModelMessage[] | | resolveConversationState(...) | Resolves prior conversation state from journal |

Recent additions (unify-engine-resume)

  • Envelope tools: parents update child-engine work definitions via add-child-tasks / send-child-message MCP tools (or applyEnvelopeChange directly). Parent-envelope principle (D2): envelope operations never write execution state. See packages/docs/content/engine.mdx and packages/docs/content/mcp.mdx.
  • Unified resume primitive: runEngine(config, { resume: { runId, listId, journalId, strategy } }) (internal; use via retry-engine-run or add-child-tasks) re-enters an existing run on durable state.
  • Durable journal entries in DEFAULT_RENDER_INCLUDE_TYPES: system:parent_directive, system:run_failed, system:session_resume_failed. Surfaced to resumed agents via renderEntries.
  • handle.resolveEscalation(resolutions) — top-level API for programmatic escalation resolution (complement to the provide-input MCP tool).

Test-infrastructure dependencies (unify-engine-resume)

The unit-tier recipe tests use @faker-js/faker, randexp, and zod-schema-faker to synthesize deterministic tool-call payloads from Zod schemas without booting a real LLM. Rationale and usage conventions live in src/__tests__/helpers/TESTING_CONVENTIONS.md. These are devDependencies only — they do not ship in the published package.

Breaking changes (unify-engine-resume)

Seven breaking changes landed together; migrate each independently. Full details and migration snippets in packages/docs/content/engine.mdx#breaking-changes.

| # | Change | Migration hint | |---|--------|----------------| | 1 | ContinuationStrategy union: { type: 'continue' } removed, folded into { type: 'resume', fork? } | Replace the string literal 'continue' with 'resume'; pass fork: true to preserve the old 'fork' branch. | | 2 | ConversationState.origin enum tightened to 'fresh' \| 'resume' \| 'fork' | Writes of legacy 'continue' throw; reads coerce to 'resume' with a warn. Drop the 'continue' branch in any switch(origin). | | 3 | canComplete gate ctx rename — ctx.resumeChildctx.applyEnvelopeChange(runId, { message?, tasks? }, opts?) | TypeScript flags the rename at compile time. JS/widened-to-any consumers must audit. | | 4 | MCP tool resume-delegation-child removed → add-child-tasks + send-child-message | Split the old combined call into two verb-specific calls; each writes its own system:parent_directive entry that composes chronologically. | | 5 | VercelAiAdapter default maxRetries0 (was SDK default 2) via new vercelAiMaxRetries field | Restore legacy via new VercelAiAdapter({ model, vercelAiMaxRetries: 2 }). Rationale: session-manager (Layer 4) owns the retry policy. | | 6 | isTransientError treats api_error (5xx / 529 / "server error") as transient (was non-retryable) | The engine now retries with backoff up to limits.maxIterations instead of escalating on iteration 1. Opt out via onIterationEndescalate for category === 'api_error'. | | 7 | limits.retryDelay.jitter defaults to 'full' (was deterministic) | Tests asserting exact delay values must set jitter: 'none'. Multi-engine deployments benefit automatically from thundering-herd protection. |

Architecture

runEngine(config) → EngineRuntimeHandle
  │
  ├─ Discriminate: model present → declarative. adapter present → escape hatch.
  │
  ├─ Declarative path (session manager):
  │   1. Create db (or use provided)
  │   2. Create TaskList from tasks + dependsOn/sequential
  │   3. Auto-generate actor IDs, relations
  │   4. Discover skills (factory-time)
  │   5. Detect provider (Claude Code vs standard API)
  │   6. Create sessionScope MCP server
  │   7. Create internal bridge adapter
  │   8. Run session manager loop:
  │      while(true) {
  │        buildSessionPrompt → bridgeAdapter → analyzeOutcome
  │        → onIterationEnd → action (retry/escalate/pause)
  │      }
  │
  └─ handle.run({ signal? }) → Promise<RuntimeResult>
     handle.abort()
     handle.cleanup()