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

effect-cursor-sdk

v0.4.1

Published

Effect-based wrapper around the Cursor SDK

Readme

effect-cursor-sdk

npm License MIT CI CodeRabbit Pull Request Reviews

Effect-native access to the new Cursor SDK.

effect-cursor-sdk wraps @cursor/sdk with Effect services, layers, scoped resource management, tagged errors, observability hooks, deterministic mocks, and ready-made runtimes. The upstream SDK remains the source of truth for Cursor-owned types; this package adds Effect ergonomics without creating a parallel model that can drift.

If you want to build with Cursor agents, and you are using Effect, this package is for you.

Philosophy

  • SDK-first: every public @cursor/sdk capability should be usable through this package.
  • Effect-native: APIs return Effect, Stream, Context.Service, and Layer values.
  • Type-preserving: SDK data types are re-exported instead of rebuilt.
  • Resource-safe: scoped helpers make it easy to dispose agents correctly.
  • Observable: SDK calls are wrapped in spans and metrics with secret redaction utilities.
  • Testable: mock layers and fixtures let applications test Cursor workflows without network calls.

Documentation

Feature Coverage

| SDK capability | Effect wrapper | | -------------------------------------------------------------------------------- | ---------------------------------------------- | | Agent.create, Agent.resume, Agent.prompt | CursorAgentService | | agent.send, reload, close, async dispose | CursorAgentService | | run.wait, stream, conversation, cancel, status listeners / streams, support checks | CursorRunService | | agent.listArtifacts, downloadArtifact | CursorArtifactService | | Agent.list, get, listRuns, getRun, messages | CursorInspectionService | | Agent.archive, unarchive, delete | CursorInspectionService | | Cursor.me, models, repositories | CursorInspectionService | | MCP servers, sub-agents, local/cloud options, model options | Defaults via CursorConfig / loadCursorConfig; merged into SDK AgentOptions at the boundary | | Local run event helpers and platform helpers | Re-exported from @cursor/sdk |

Use cases

If you are new to the Cursor SDK, take a look at the Cursor SDK Cookbook. This cookbook provides some (cool!) examples of what you could do with the SDK.

effect-cursor-sdk even uses itself to spin up a Cursor agent to create changesets for pull requests against main! 🤯

Install

bun add effect-cursor-sdk effect @cursor/sdk

effect is a peer dependency (Effect v4). @cursor/sdk is bundled with this package, but installing it in your app keeps SDK-owned types and versions explicit when you import from @cursor/sdk alongside the wrapper.

Requirements

  • Runtime: Bun or Node.js (examples and CI use Bun; Node works for library consumers).
  • Effect: ^4.0.0-beta (see Effect v4 — still pre-release on the Effect side).
  • Cursor SDK: @cursor/sdk ^1.0.x (pinned in this repo; see SDK coverage when upgrading).

Configuration

loadCursorConfig reads optional environment variables through Effect’s ConfigProvider (by default, process.env):

| Variable | Purpose | | --- | --- | | CURSOR_API_KEY | API key for Cursor (stored as Redacted until merged into SDK options). | | CURSOR_MODEL | Default model id (for example composer-2). | | CURSOR_LOCAL_CWD | Default working directory for local agents. |

All fields are optional at load time; missing CURSOR_API_KEY logs a warning and later SDK calls fail with authentication errors unless you pass overrides. Per-call overrides still win when using create, scoped, prompt, and resume.

For offline tests and CI, use mockLayer or makeMockRuntime — no API key required.

For development in this repo:

bun install
bun run typecheck
bun run test

Examples

The examples directory contains a guided learning path from a minimal first script to production-style Effect composition:

| Example | What it demonstrates | | --- | --- | | quickstart | First config-first local agent call with loadCursorConfig, scoped, and collectText. | | cli | A small terminal app with liveRuntime, offline makeMockRuntime, CLI overrides, and tagged error handling. | | basic-agent-workflow | Scoped agents, run status listeners, streaming, capability checks, and artifact listing/downloads. | | advanced-ops-dashboard | Inspection APIs, confirmation-gated lifecycle operations, parallel Effect composition, retries/timeouts, telemetry, redaction, and rich mocks. |

Run all example typechecks from the repo root:

bun run examples:typecheck

Quick Start

Load environment defaults with loadCursorConfig, then create agents with create (and scoped, prompt, resume as needed). The API key stays in Redacted form until the merge step; AgentOptions.apiKey remains a plain string at the SDK boundary.

import {
  CursorAgentService,
  CursorRunService,
  loadCursorConfig,
  liveLayer,
} from "effect-cursor-sdk";
import { Effect } from "effect";

const program = Effect.gen(function* () {
  const agents = yield* CursorAgentService;
  const runs = yield* CursorRunService;

  const config = yield* loadCursorConfig;
  const agent = yield* agents.create(config, {
    // Override the given config optionally with custom values
    model: { id: "composer-2" },
    local: { cwd: process.cwd() },
  });

  const run = yield* agents.send(agent, "Explain this repository");
  const text = yield* runs.collectText(run);

  yield* agents.dispose(agent);
  return text;
}).pipe(Effect.provide(liveLayer));

Effect’s default ConfigProvider reads process.env, so you usually do not need to install a custom provider for this.

For advanced SDK-factory wiring in tests, you can still call agentOptionsFromConfig to merge config into plain AgentOptions before passing them to CursorSdkFactory.

Scoped Agents

Prefer scoped when an agent should be disposed automatically:

import { CursorAgentService, loadCursorConfig, liveLayer } from "effect-cursor-sdk";
import { Effect } from "effect";

const program = Effect.scoped(
  Effect.gen(function* () {
    const agents = yield* CursorAgentService;
    const config = yield* loadCursorConfig;
    const agent = yield* agents.scoped(config, {
      model: { id: "composer-2" },
      local: { cwd: process.cwd() },
    });

    return yield* agents.send(agent, "Find risky code paths");
  }),
).pipe(Effect.provide(liveLayer));

Resume an existing agent

Use resume with the agent id from a prior run or from CursorInspectionService.listAgents:

const config = yield* loadCursorConfig;
const agent = yield* agents.resume("bc_abc123", config, {
  local: { cwd: process.cwd() },
});

Cloud Agents

Cloud options are merged as SDK overrides on top of loaded config:

const config = yield* loadCursorConfig;
const agent = yield* agents.create(config, {
  model: { id: "composer-2" },
  cloud: {
    repos: [
      { url: "https://github.com/your-org/your-repo", startingRef: "main" },
    ],
    autoCreatePR: true,
  },
});

Streaming

CursorRunService.streamEvents preserves SDK event shapes and returns an Effect Stream.

import { Effect, Stream } from "effect";

const run = yield* agents.send(agent, "Refactor the auth module");

yield* runs.streamEvents(run).pipe(
  Stream.runForEach((event) => {
    if (event.type !== "assistant") {
      return Effect.void;
    }

    const text = event.message.content
      .filter((block) => block.type === "text")
      .map((block) => block.text)
      .join("");

    return Effect.sync(() => console.log(text));
  }),
);

Artifacts

List and download run outputs with CursorArtifactService after send completes. See the Artifacts recipe for path resolution and download patterns.

Inspection And Metadata

Use CursorInspectionService for agent/run listings, messages, lifecycle operations, account metadata, model discovery, and connected repositories.

const inspection = yield* CursorInspectionService;

const agents = yield* inspection.listAgents({ runtime: "cloud", includeArchived: true });
const models = yield* inspection.listModels();
const repos = yield* inspection.listRepositories();

Integrate deeper with Effect

Because every Cursor call is an Effect, you compose it like the rest of your program: parallel requests, timeouts, retries, logging, and layers all work the same way.

This agent garden snapshot loads your catalog in parallel, adds a resilient boundary around the batch, logs a safe summary (counts and IDs only — never log API keys), then asks Cursor for a one-shot triage opinion via prompt:

import {
  CursorAgentService,
  CursorInspectionService,
  loadCursorConfig,
  liveLayer,
} from "effect-cursor-sdk";
import { Effect, Schedule } from "effect";

const agentGardenSnapshot = Effect.gen(function* () {
  const inspection = yield* CursorInspectionService;
  const agents = yield* CursorAgentService;
  const config = yield* loadCursorConfig;

  const catalog = yield* Effect.all(
    {
      cloud: inspection.listAgents({ runtime: "cloud", includeArchived: false }),
      models: inspection.listModels(),
      repos: inspection.listRepositories(),
    },
    { concurrency: "unbounded" },
  ).pipe(
    Effect.retry(
      Schedule.exponential("150 millis").pipe(Schedule.both(Schedule.recurs(3))),
    ),
    Effect.timeout("45 seconds"),
  );

  yield* Effect.logInfo("Cursor catalog loaded", {
    cloudAgents: catalog.cloud.items.length,
    models: catalog.models.length,
    repos: catalog.repos.length,
  });

  const triage = yield* agents.prompt(
    [
      "You are helping on-call. Here is non-secret inventory:",
      `- Cloud agents (ids): ${catalog.cloud.items.map((a) => a.agentId).join(", ") || "(none)"}`,
      `- Models (ids): ${catalog.models.map((m) => m.id).join(", ") || "(none)"}`,
      `- Repos (urls): ${catalog.repos.map((r) => r.url).join(", ") || "(none)"}`,
      "In two short sentences: what should we verify first before trusting automation here?",
    ].join("\n"),
    config,
    {
      model: { id: "composer-2" },
    },
  );

  return triage.result;
}).pipe(Effect.provide(liveLayer));

Swap liveLayer for mockLayer({ ... }) in tests and the same program shape exercises your orchestration without the network.

Errors

SDK failures are mapped into tagged errors such as CursorAuthenticationError, CursorRateLimitError, CursorConfigurationError, CursorAgentBusyError, CursorNetworkError, and CursorUnsupportedOperationError. The original SDK error is preserved as cause, with safe operation context and retryability where available.

const handled = program.pipe(
  Effect.catchTag("CursorRateLimitError", (error) =>
    Effect.logWarning(`Cursor rate limited request: ${error.message}`),
  ),
);

Observability

Live service methods are wrapped with operation spans such as cursor.agent.create, cursor.run.wait, and cursor.artifacts.download. The package also exports metrics for operation starts, failures, and stream events, plus redact for safe metadata handling.

Never log API keys, MCP credentials, authorization headers, or prompt image data. The provided redaction helper treats those as sensitive by default.

[!WARNING] The redaction helper is a best-effort redactor for logs and attributes — not a cryptographic guarantee; do not rely on it for compliance redaction without review.

Mocks And Tests

Use mockLayer for deterministic tests:

import { CursorAgentService, loadCursorConfig, mockLayer } from "effect-cursor-sdk";
import { Effect } from "effect";

const testProgram = Effect.gen(function* () {
  const agents = yield* CursorAgentService;
  const config = yield* loadCursorConfig;
  const agent = yield* agents.create(config, { model: { id: "composer-2" } });
  return yield* agents.send(agent, "Hello");
}).pipe(
  Effect.provide(
    mockLayer({
      result: { id: "run-1", status: "finished", result: "ok" },
    }),
  ),
);

API Surface

The main exports are:

  • Recipes — common compositions (prompt text, send + collect, pagination, lifecycle guards, artifacts) in RECIPES.md
  • Observability helpers (streamEventsTracked, collectTextTracked, catalog retry/timeout presets, log summaries)
  • CursorAgentService (create, scoped, prompt, resume with loadCursorConfig)
  • CursorRunService
  • CursorArtifactService
  • CursorInspectionService
  • CursorSdkFactory (low-level SDK adapter for tests and advanced overrides)
  • liveLayer, mockLayer, liveRuntime, makeMockRuntime
  • CursorConfig, cursorConfig, agentOptionsFromConfig, loadCursorConfig
  • tagged Cursor error classes and mapCursorError
  • SDK-owned types and utilities re-exported from @cursor/sdk

Use generated TypeScript declarations for exact signatures.

Quality Gates

bun run typecheck
bun run sdk-audit
bun run lint
bun run format:check
bun run test
bun run test:coverage
bun run build
bun run lint:package

After a @cursor/sdk bump, if sdk-audit fails, review docs/SDK_COVERAGE.md and refresh the baseline only when drift is intentional: bun run sdk-audit:refresh.

Coverage is measured with Vitest v8 coverage. The suite focuses on deterministic wrapper behavior; live SDK network paths should be validated separately with credentials and a disposable repository.

Deprecations

See DEPRECATIONS.md for the canonical list of deprecated APIs. Pair it with CHANGELOG.md for release-by-release notes.

Versioning and Publishing

Use conventional commits for readable history and changelog context:

feat: add cursor artifact helpers
fix: map cursor rate limit errors
docs: clarify runtime setup

User-facing changes should include a Changeset:

bun run changeset

Automated Changeset Agent

This repository also includes a Cursor-powered changeset agent for pull requests against main. The workflow in .github/workflows/changeset-agent.yml runs bun run changeset:agent, starts a scoped local Cursor SDK agent with this package, asks it to inspect the PR diff, and commits a missing .changeset/*.md file back to the PR branch when release impact exists.

The job runs only for same-repository, non-draft PRs because it needs both the CURSOR_API_KEY repository secret and write access to the PR branch. Forked PRs should add changesets manually or be handled from a trusted maintainer checkout.

Other, optional environment variables are CURSOR_MODEL for the Cursor model id and CHANGESET_BASE_REF for the diff base. See Changeset Agent for the full architecture, prompt contract, security model, and local usage.

On main, GitHub Actions uses Changesets to open a version PR when pending Changesets exist. After that PR is merged, the same workflow runs bun run release and publishes to NPM.

For local release preparation, apply pending Changesets and publish only after the package is approved for public release:

bun run version
bun run release

bun run release runs verify:publish (including sdk-audit) before publishing to NPM.