JSPM

  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 2
  • Score
    100M100P100Q41376F
  • License Apache-2.0

Stable abstraction layer over CLI coding agents (Claude Code, Codex, Gemini CLI, OpenCode)

Package Exports

  • agentslist
  • agentslist/model-helpers
  • agentslist/resolver-helpers
  • agentslist/types

Readme

agentslist

Stable abstraction layer over CLI coding agents (Claude Code, Codex CLI, Gemini CLI, OpenCode). Detects installed agents, resolves capabilities, executes prompts, and normalizes output — all through a single, agent-agnostic API.

Install

npm install agentslist agentslist-db

Requires Node.js >= 18. The agentslist-db package provides the compatibility database consumed at runtime.

Quick Start

import { run } from "agentslist";

const result = await run({
  prompt: "Refactor this function to use async/await",
  working_dir: "/path/to/project",
  output: { format: "json" },
});

console.log(result.status);       // "success"
console.log(result.output.text);  // Agent's text response
console.log(result.output.json);  // Parsed JSON (when format is "json")

API

detect(options?): Promise<DetectedAgent[]>

Find all installed CLI agents by running detection commands from the database.

import { detect } from "agentslist";

const agents = await detect();
// [
//   {
//     id: "claude-code",
//     binary: "claude",
//     version: "2.1.7",
//     path: "/usr/local/bin/claude",
//     env_authenticated: true
//   },
//   { id: "gemini-cli", binary: "gemini", version: "0.27.2", ... }
// ]

Options:

Field Type Description
db_path string Custom path to the DB directory. Defaults to bundled database.

Returns: DetectedAgent[] — sorted by id. Empty array if no agents are found.


plan(request, options?): Promise<ExecutionPlan>

Resolve an execution request into a concrete execution plan without running it. Useful for previewing what CLI command would be generated.

import { plan } from "agentslist";

const p = await plan({
  prompt: "Add tests for the auth module",
  model: "claude-sonnet-4-5-20250929",
  output: { format: "json" },
  max_turns: 5,
});

console.log(p.binary);                         // "claude"
console.log(p.args);                           // ["--print", "--output-format", "json", "--model", ...]
console.log(p.env);                            // { ... }
console.log(p.compatibility_report.overall);   // "full"

Options:

Field Type Description
agent string Force a specific agent by id ("claude-code", "codex", "gemini-cli", "opencode"). Auto-selects first detected agent if omitted.
db_path string Custom database path.

Returns: ExecutionPlan

interface ExecutionPlan {
  agent_id: string;
  binary: string;
  args: string[];
  env: Record<string, string>;
  stdin?: string;
  output_parser: string;                  // "plain_text" | "json_object" | "ndjson_stream"
  compatibility_report: CompatibilityReport;
  model_resolution?: ModelResolution;     // Present when request.model is specified
  protocol?: {
    type: ProtocolType;
    features: string[];
  };
}

When request.model is specified, the resolver validates the token against the agent's model bindings, resolves aliases (e.g. "opus" to "claude-opus-4-6"), and applies fallback chains for blocked models. The result is captured in model_resolution.


run(request, options?): Promise<ExecutionResult>

Execute the full pipeline end-to-end: detect agent, resolve plan, spawn process, parse output.

import { run } from "agentslist";

const result = await run({
  prompt: "Write a hello world in Rust",
  working_dir: process.cwd(),
  timeout_seconds: 60,
});

if (result.status === "success") {
  console.log(result.output.text);
}

Options:

Field Type Description
agent string Force a specific agent.
db_path string Custom database path.
timeout_ms number Override timeout in milliseconds. Overrides request.timeout_seconds.

Returns: ExecutionResult

interface ExecutionResult {
  agent: { id: string; version: string };
  status: "success" | "error" | "timeout" | "budget_exceeded" | "turn_limit";
  exit_code: number;
  output: {
    text?: string;    // Extracted text (via json_response_path or plain stdout)
    json?: unknown;   // Parsed JSON object (when output format is json)
    raw: string;      // Raw stdout
  };
  compatibility: CompatibilityReport;
  duration_ms: number;
  resolved_command: {
    binary: string;
    args: string[];
    env: Record<string, string>;
  };
}

check(request, options?): Promise<CompatibilityReport>

Check whether an agent supports the requested capabilities without executing anything.

import { check, summarize } from "agentslist";

const report = await check({
  prompt: "...",
  output: { format: "json", schema: { type: "object" } },
  session: { resume_id: "abc-123" },
});

console.log(report.overall);    // "full" | "degraded" | "unsupported" | "unknown"
console.log(summarize(report)); // Human-readable summary

Returns: CompatibilityReport

interface CompatibilityReport {
  overall: "full" | "degraded" | "unsupported" | "unknown";
  details: CapabilityDetail[];
}

interface CapabilityDetail {
  capability: CapabilityId;                // e.g. "output.json", "session.resume"
  status: "supported" | "degraded" | "unsupported" | "unknown";
  message?: string;                        // Explanation for non-supported statuses
  fallback_used?: boolean;
}

spawn(request, options?): Promise<AgentSession>

Start an interactive session with streaming events and follow-up messaging.

import { spawn } from "agentslist";

const session = await spawn(
  { prompt: "Review this codebase for security issues" },
  { agent: "claude-code", cwd: "/path/to/project" },
);

for await (const event of session.events) {
  switch (event.type) {
    case "message":
      process.stdout.write(event.content);
      break;
    case "tool_call":
      console.log(`Tool: ${event.name}`, event.input);
      break;
    case "approval_request":
      await session.respond(event.id, { behavior: "allow" });
      break;
    case "cost_update":
      console.log(`Cost: $${event.cost_usd.toFixed(4)}`);
      break;
    case "error":
      console.error(event.message);
      break;
  }
}

const result = await session.wait();

SpawnOptions:

Field Type Description
agent string Force a specific agent.
db_path string Custom database path.
cwd string Working directory for the spawned process.
env Record<string, string> Additional environment variables.
cancel_grace_ms number Grace period before SIGKILL after cancel. Default: 5000.

AgentSession interface:

Member Type Description
events AsyncIterable<AgentEvent> Normalized event stream.
send(message) Promise<void> Send a follow-up message.
respond(requestId, response) Promise<void> Respond to an approval request.
cancel() Promise<void> Gracefully cancel (SIGTERM, then SIGKILL after grace period).
wait() Promise<ExecutionResult> Wait for process exit.
sessionId string | null Protocol-provided session ID (readonly).
pid number | undefined Child process PID (readonly).

AgentEvent types:

Type Key Fields Description
message content, partial Text output from the agent.
thought content Internal reasoning (when exposed).
tool_call id, name, input Agent invoked a tool.
tool_result id, output Tool returned a result.
approval_request id, tool_name, input Agent requests permission. Call session.respond() to allow/deny.
session_start session_id Session ID assigned by the agent.
file_change path, diff? A file was modified.
plan steps Agent's execution plan.
context_usage tokens_used, tokens_limit? Token usage update.
cost_update cost_usd, tokens_in, tokens_out Cost tracking data.
done result? Agent finished.
error message An error occurred.
raw data Unparsed protocol data.

listModels(options?): Promise<ModelListResult>

List all models available for a specific agent and version, grouped by status.

import { listModels } from "agentslist";

const models = await listModels({ agent: "claude-code" });

console.log(models.agent_id);            // "claude-code"
console.log(models.default_model);       // "claude-sonnet-4-5-20250929"
console.log(models.selection_mode);      // "allowlist" | "passthrough"
console.log(models.supported);           // ModelBindingWithCatalog[]
console.log(models.deprecated);          // ModelBindingWithCatalog[]

Options:

Field Type Description
agent string Agent id. Auto-selects first detected agent if omitted.
version string Override agent version. Defaults to detected version.
db_path string Custom database path.

Returns: ModelListResult

interface ModelListResult {
  agent_id: string;
  version: string;
  default_model?: string;
  selection_mode: "allowlist" | "passthrough";
  unknown_model_behavior: "passthrough" | "error" | "unknown";
  supported: ModelBindingWithCatalog[];
  preview: ModelBindingWithCatalog[];
  deprecated: ModelBindingWithCatalog[];
  blocked: ModelBindingWithCatalog[];
}

interface ModelBindingWithCatalog {
  binding: ModelBinding;
  catalog?: ModelCatalogEntry;           // Catalog metadata (provider, family, lifecycle)
}

checkModel(token, options?): Promise<ModelCheckResult>

Check if a model token is compatible with a specific agent and version. Resolves aliases and reports status.

import { checkModel } from "agentslist";

const result = await checkModel("opus", { agent: "claude-code" });

console.log(result.resolution.status);        // "matched"
console.log(result.resolution.resolved_model_id);  // "claude-opus-4-6"
console.log(result.summary);                  // 'Model "claude-opus-4-6" is supported'

// Deprecated model
const dep = await checkModel("claude-3-5-haiku-20241022", { agent: "claude-code" });
console.log(dep.resolution.status);           // "matched_deprecated"
console.log(dep.resolution.warnings);         // [{ type: "deprecated", message: "..." }]
console.log(dep.resolution.suggestions);      // ["claude-sonnet-4-5-20250929", ...]

Options:

Field Type Description
agent string Agent id. Auto-selects first detected agent if omitted.
version string Override agent version.
db_path string Custom database path.

Returns: ModelCheckResult

interface ModelCheckResult {
  resolution: ModelResolution;
  summary: string;                        // Human-readable description
}

interface ModelResolution {
  status: "matched" | "matched_deprecated" | "matched_preview"
        | "fallback" | "passthrough" | "blocked" | "no_model";
  requested_token?: string;
  resolved_model_id?: string;
  effective_token?: string;               // The token passed to --model flag
  default_model?: string;                 // Agent's default model for reference
  warnings: ModelWarning[];
  suggestions: string[];                  // Alternative model IDs
}

interface ModelWarning {
  type: "deprecated" | "preview" | "blocked" | "unknown_token" | "fallback" | "lifecycle";
  message: string;
}

findAgentsForModel(modelId, options?): Promise<CrossAgentModelInfo[]>

Find which agents support a given canonical model ID.

import { findAgentsForModel } from "agentslist";

const agents = await findAgentsForModel("claude-opus-4-6");
// [
//   {
//     agent_id: "claude-code",
//     agent_name: "Claude Code",
//     status: "supported",
//     accepted_tokens: ["opus", "claude-opus-4-6"],
//     is_default: false
//   }
// ]

Options:

Field Type Description
db_path string Custom database path.

Returns: CrossAgentModelInfo[]

interface CrossAgentModelInfo {
  agent_id: string;
  agent_name: string;
  status: "supported" | "deprecated" | "blocked" | "preview";
  accepted_tokens: string[];
  is_default: boolean;
}

ExecutionRequest

The full request shape accepted by run(), plan(), check(), and spawn():

interface ExecutionRequest {
  // --- Prompt ---
  prompt: string;                          // The main prompt text
  prompt_file?: string;                    // Read prompt from file instead
  piped_input?: string;                    // Data piped to stdin
  system_prompt?: {
    strategy?: "replace" | "append";       // Replace or append to default system prompt
    content?: string;                      // Inline system prompt
    file?: string;                         // System prompt from file
    append_file?: string;                  // Additional system prompt file (appended)
  };

  // --- Media ---
  images?: string[];                       // Image file paths
  file_attach?: string[];                  // Files to attach

  // --- Context ---
  context?: {
    include_files?: string[];              // Specific files to include
    include_globs?: string[];              // Glob patterns to include
    exclude_globs?: string[];              // Glob patterns to exclude
  };

  // --- Output ---
  output?: {
    format?: "text" | "json" | "stream_json";
    schema?: Record<string, unknown>;      // JSON Schema for structured output
    file?: string;                         // Write output to file
    diff?: boolean;                        // Show diffs instead of full files
    markdown_render?: boolean;             // Render markdown in output
  };

  // --- Model ---
  model?: string;                          // Model identifier
  fallback_model?: string;                 // Fallback if primary unavailable
  reasoning_effort?: "off" | "low" | "medium" | "high" | "max";

  // --- Execution Control ---
  sandbox?: "none" | "read_only" | "workspace_write" | "full_access";
  approval_bypass?: boolean;               // Skip all approval prompts
  approval_mode?: "default" | "auto_edit" | "plan" | "full_bypass";
  max_turns?: number;
  max_budget_usd?: number;
  timeout_seconds?: number;
  working_dir?: string;
  additional_dirs?: string[];
  debug?: boolean;
  quiet?: boolean;
  dry_run?: boolean;
  plan_mode?: boolean;
  config_file?: string;

  // --- Environment ---
  env?: Record<string, string>;            // Extra environment variables
  provider?: {
    api_base?: string;
    api_key?: string;                      // Passed via env, never in CLI args
    name?: string;
  };

  // --- Session ---
  session?: {
    resume_id?: string;                    // Resume a previous session
    continue_last?: boolean;               // Continue the most recent session
    session_id?: string;                   // Explicit session ID
    fork?: boolean;                        // Fork from an existing session
    list?: boolean;                        // List available sessions
    export_path?: string;                  // Export session to file
    import_path?: string;                  // Import session from file
  };

  // --- Tools ---
  tools?: {
    allowed?: string[];                    // Restrict to these tools
    disallowed?: string[];                 // Block these tools
  };
  mcp?: {
    config_path?: string;                  // MCP server config file
    strict?: boolean;
  };
}

Lower-Level API

The high-level functions (detect, plan, run, check, spawn) compose these building blocks. You can use them directly for advanced scenarios.

Detector

import { detectAll, detectAgent, isAvailable } from "agentslist";

const agents = await detectAll(db);              // All installed agents
const claude = await detectAgent("claude-code", db);  // Specific agent or null
const hasClaude = await isAvailable("claude-code", db);

Resolver

Pure function — no I/O. Maps ExecutionRequest + DetectedAgent + AgentDB to ExecutionPlan.

import { resolve } from "agentslist";
import type { ResolveOptions } from "agentslist";

const plan = resolve(request, agent, db);

// Protocol mode: use the agent's streaming protocol flags instead of oneshot flags
const plan = resolve(request, agent, db, { mode: "protocol" });

Executor

Spawns the CLI process and collects raw output.

import { execute } from "agentslist";

const raw = await execute(plan, {
  cwd: "/path/to/project",
  timeout_ms: 30_000,
});

console.log(raw.stdout);
console.log(raw.stderr);
console.log(raw.exit_code);      // number
console.log(raw.timed_out);      // boolean
console.log(raw.duration_ms);    // number

Parser

Normalizes raw CLI output into ParsedOutput.

import { parse } from "agentslist";

const output = parse(rawOutput, plan, versionRange?.output_parsing);

console.log(output.text);  // Extracted text
console.log(output.json);  // Parsed JSON (if applicable)
console.log(output.raw);   // Raw stdout

Three parsing strategies are selected automatically based on the execution plan:

Strategy When Behavior
plain_text Default / text output Trims stdout
json_object output.format: "json" Parses JSON, extracts text via json_response_path
ndjson_stream output.format: "stream_json" Parses newline-delimited JSON events, finds the final event

Reporter

import { preflightReport, isFullySupported, summarize } from "agentslist";

const report = preflightReport(request, agent, db);
const ok = isFullySupported(request, agent, db);   // boolean
const text = summarize(report);                     // Human-readable string

Protocol Parsers

Normalize agent-specific streaming protocols into AgentEvent:

import {
  getProtocolParser,
  createClaudeSdkParser,
  createCodexJsonrpcParser,
  createAcpParser,
  createPlainTextParser,
} from "agentslist";
Protocol Agent Description
claude_sdk Claude Code Structured JSON events
codex_app_server Codex CLI JSON-RPC 2.0 over stdio
codex_jsonrpc Codex CLI Legacy JSON-RPC
acp Agent Communication Protocol
plain_text Fallback Raw line-by-line stdout

Resolver Helpers (Browser-Safe)

Exported as raw .ts — no Node.js dependencies. Safe for browser/playground use.

import {
  resolveCapability,
  computeOverallCompatibility,
  capabilityIdToDbKey,
  dbKeyToCapabilityId,
  pushFlagValue,
  pushBooleanFlag,
  pushMultiValues,
} from "agentslist/resolver-helpers";

Model Helpers (Browser-Safe)

Pure functions for model resolution. Exported as raw .ts — no Node.js dependencies.

import {
  resolveModel,
  resolveModelToken,
  applyModelFallback,
  findBindingByToken,
  findCatalogEntry,
  generateModelWarnings,
  listModelBindings,
  findAgentsForModel,
  summarizeModelResolution,
} from "agentslist/model-helpers";
Function Description
resolveModel(token, fallback, models, catalog) Full resolution pipeline with fallback chain.
resolveModelToken(token, models, catalog) Resolve a single token against bindings.
applyModelFallback(resolution, fallback, models, catalog) Apply fallback when primary is blocked.
findBindingByToken(token, bindings) Find a binding that accepts a given token.
findCatalogEntry(modelId, catalog) Look up a model in the catalog by ID.
generateModelWarnings(binding, catalog, token, models) Generate warnings for a binding.
listModelBindings(models, catalog) Group bindings by status with catalog info.
findAgentsForModel(modelId, agentModelsMap) Cross-agent lookup (sync, takes a Map).
summarizeModelResolution(resolution) Human-readable summary string.

Errors

All errors extend AgentslistError:

Error When
AgentslistError Base class for all library errors.
AgentNotFoundError Agent id not in the database. Properties: agentId.
AgentNotInstalledError Agent binary not found on the system. Properties: agentId, binary.
VersionNotMatchedError Detected version has no matching range in the DB. Properties: agentId, version.
DBLoadError Failed to load the compatibility database. Properties: path.
ExecutionError Process spawn or execution failure. Properties: exitCode?, stderr?.
ParseError Output parsing failed. Properties: rawOutput?.
import { run, AgentNotInstalledError, ExecutionError } from "agentslist";

try {
  await run({ prompt: "...", working_dir: "." }, { agent: "codex" });
} catch (err) {
  if (err instanceof AgentNotInstalledError) {
    console.error(`${err.binary} is not installed`);
  } else if (err instanceof ExecutionError) {
    console.error(`Execution failed (exit ${err.exitCode}): ${err.stderr}`);
  }
}

Export Paths

// Main API — all functions, classes, types
import { detect, plan, run, check, spawn, AgentDB } from "agentslist";

// Model API
import { listModels, checkModel, findAgentsForModel } from "agentslist";

// Browser-safe helpers — no Node.js dependencies
import { resolveCapability, computeOverallCompatibility } from "agentslist/resolver-helpers";
import { resolveModel, resolveModelToken, listModelBindings } from "agentslist/model-helpers";

// Types only
import type {
  ExecutionRequest, ExecutionPlan, ExecutionResult, AgentEvent,
  ModelResolution, ModelCatalogEntry, ModelBinding, ModelCompatRange,
} from "agentslist/types";

License

Apache License 2.0. See the LICENSE file for details.