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

scuttlerun

v0.2.1

Published

Multi-turn Claude session driver

Downloads

406

Readme

scuttlerun

npm version License: MIT

0.x. scuttlerun is in active development; minor versions may include breaking changes to the CLI surface, config schema, or transcript format until 1.0.

CLI-only. scuttlerun is intended to be used as a command-line tool. There is no supported programmatic API; modules under dist/ are implementation details and may change without notice.

A TypeScript CLI that drives multi-turn Claude sessions programmatically using the Claude Agent SDK. scuttlerun simulates a synthetic user powered by an LLM oracle, enabling headless, scriptable, fully-observable interactions with Claude — including interactive tools like AskUserQuestion.

Why scuttlerun?

The closest alternatives each leave a gap that scuttlerun fills:

  • claude -p / Claude Code one-shot mode — single-turn only; cannot answer AskUserQuestion, cannot follow up, cannot drive a back-and-forth conversation.
  • Raw Claude Agent SDK — gives you the loop, but no synthetic user, no YAML-driven session config, no built-in transcript format, no project scaffolding, no sandboxing defaults.

scuttlerun is a thin orchestration layer on top of the Agent SDK that adds those pieces. It is a session driver, not an eval framework — it produces transcripts; scoring/grading composes downstream (see docs/goals.md for the full positioning).

Demo: scuttlerun running an interactive session, with the synthetic user answering an AskUserQuestion call

Source: assets/demo.tape (re-record with vhs assets/demo.tape).

Installation

Prerequisites: Node.js 20 or later (LTS recommended; CI tests on 20, 22, 24).

From npm (recommended):

npm install -g scuttlerun
# or run without installing:
npx scuttlerun@latest <session.yaml>

From source:

git clone https://github.com/bkudria/scuttlerun.git
cd scuttlerun
npm install
npm run build
npm link          # makes `scuttlerun` available globally

Configuration

scuttlerun requires an Anthropic API key:

export ANTHROPIC_API_KEY=sk-ant-...

Get one at console.anthropic.com.

Quick Start

scuttlerun examples/simple.yaml

# Run with overrides
scuttlerun examples/multi-turn.yaml --timeout 120 --model claude-sonnet-4-6

Session Config

Sessions are defined in YAML. Only prompt is required — everything else has defaults.

version: "1"
prompt: |
  Write a haiku about the ocean and save it to ocean.txt

Config Reference

| Field | Type | Default | | ------------------ | ----------------------------------------------- | ---------------------------------------------------------------- | | version | string | "1" (config schema version; only "1" is currently accepted) | | prompt | string | (required) | | model | string | claude-haiku-4-5 | | max_turns | number | 50 | | max_budget_usd | number | — | | effort | low | medium | high | xhigh | max | high | | tools | string[] | [Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion, Skill] | | additional_tools | string[] | — (appended to tools after defaults apply; deduped first-wins) | | disallowed_tools | string[] | — | | permission_mode | string | bypassPermissions |

user (synthetic user)

| Field | Type | Default | | ------------------- | ------ | ------------------ | | user.persona | string | — | | user.oracle_model | string | claude-haiku-4-5 | | user.max_turns | number | 0 |

project (managed project scaffolding)

When present, scuttlerun populates the project temp directory.

| Field | Type | Default | | ------------------- | ------------------------ | ------- | | project.claude_md | string | — | | project.skills | string[] | — | | project.settings | object | — | | project.files | Record<string, string> | — | | project.git_init | boolean | false |

project.files keys are relative paths written inside the temp project dir; values are the file contents. Useful for materializing fixtures, test data, or example source files alongside scaffolded CLAUDE.md/skills/settings.

sdk (Agent SDK passthrough)

| Field | Type | Default | | --------------------- | ------------------------------------------------------------------- | ---------------------------------------------- | | sdk.system_prompt | string | {preset: "claude_code", append?: string} | {preset: "claude_code"} | | sdk.thinking | {type: "adaptive"} | {type: "enabled"} | {type: "disabled"} | — | | sdk.mcp_servers | object | — | | sdk.agents | object | — | | sdk.plugins | {type: "local", path: string}[] | — | | sdk.env | Record<string, string> | — | | sdk.setting_sources | string[] | ["project"] if project: present, else [] |

sandbox (OS-level isolation)

Enabled by default. Restricts the agent's filesystem and network access. When the sandbox is enabled, $HOME is redirected to <projectDir>/.home so tools (npm, pip, cargo) write caches inside the sandbox rather than your real home directory.

| Field | Type | Default | | ------------------------------------- | -------- | ----------------------------------------- | | sandbox.enabled | boolean | true | | sandbox.network.allowed_domains | string[] | [] (no network access) | | sandbox.network.allow_local_binding | boolean | false | | sandbox.filesystem.deny_read | string[] | [~/.ssh, ~/.aws, ~/.config/gcloud] | | sandbox.filesystem.allow_write | string[] | [] (cwd and /tmp are always writable) | | sandbox.filesystem.deny_write | string[] | [.env] |

Config Merging

Multiple YAML files are deep-merged (objects merge, arrays/scalars replace):

scuttlerun base.yaml scenario-override.yaml

Usage

scuttlerun <session.yaml> [override.yaml...] [options]
scuttlerun --version
scuttlerun --help

| Option | Description | | ------------------------ | ------------------------------------ | | --model <model> | Override agent model | | --oracle-model <model> | Override synthetic user model | | --prompt <text> | Override prompt | | --max-turns <n> | Override max agent turns | | --max-budget-usd <usd> | Override max session cost in USD | | --tools <tools> | Override tools (comma-separated) | | --effort <level> | Override effort level | | --timeout <seconds> | Session timeout (default: 300) | | -v, --verbose | Verbose logging to stderr | | -n, --dry-run | Validate and display resolved config |

Exit Codes

Shared taxonomy across scuttlerun/pincenez/craboodle. Codes 3 and 4 are craboodle-only; scuttlerun does not emit them.

| Code | Meaning | | ---- | --------------------------------------------------------------- | | 0 | Session completed normally | | 1 | Configuration error | | 2 | Runtime error (SDK failure, process crash, unhandled exception) | | 5 | Budget exceeded | | 6 | Timeout | | 7 | Max turns exceeded | | 130 | Interrupted (SIGINT) |

How It Works

scuttlerun wraps the Claude Agent SDK's query() with an async generator for multi-turn input. Two key mechanisms:

  1. canUseTool callback — Intercepts AskUserQuestion calls. An LLM oracle (Haiku by default) answers questions consistent with the configured persona.

  2. Turn policy — After each agent turn, the oracle decides whether the synthetic user should send a follow-up (reactive mode) or end the session (single mode).

Output

scuttlerun streams a YAML transcript to stdout as the session runs:

session: a1b2c3d4-e5f6-7890-abcd-ef1234567890
config: /path/to/session.yaml
project: /tmp/scuttlerun-project-xK3f9m
transcript: ~/.claude/projects/-tmp-.../a1b2c3.jsonl

conversation:
  - user: |
      Write a haiku about the ocean and save it to ocean.txt

  - assistant: |
      I'll write a haiku about the ocean.

  - tool: Write
    path: ocean.txt

  - assistant: |
      Done! I saved the haiku to ocean.txt.

turns: 2
tool_calls: 1
duration_s: 12.3

The output is valid YAML and machine-parseable (e.g. with yq).

Project directory — Always created in $TMPDIR as scuttlerun-project-<id>/, preserved after the session ends so you can inspect agent-created files. On the next run, scuttlerun garbage-collects its own scuttlerun-project-* directories that are older than 7 days; nothing else in $TMPDIR is touched.

SDK session file — Full conversation record in Claude Code's native JSONL format at ~/.claude/projects/<encoded-cwd>/<session-id>.jsonl. Queryable with jq.

Privacy

scuttlerun is a thin client around Anthropic APIs. Be aware:

  • What is sent to Anthropic. Prompts, tool inputs and outputs, conversation history, your configured persona, and oracle decisions are sent to Anthropic via the Claude Agent SDK (agent turns) and the Messages API (synthetic-user oracle). This includes any file contents the agent reads or writes during a session. Anthropic's handling of that data is governed by their Usage Policy and Privacy Policy.
  • What scuttlerun itself collects. Nothing. scuttlerun has no telemetry, analytics, crash reporting, or "phone home". The only network calls it makes are to Anthropic.
  • What stays local. The YAML transcript on stdout, the project temp directory under $TMPDIR/scuttlerun-project-*, and the SDK session JSONL under ~/.claude/projects/... are all written to your machine only. Nothing in those locations is uploaded.
  • Secrets. Your ANTHROPIC_API_KEY is read from the environment and forwarded to the SDK; it never appears in transcripts. The default sandbox denies the agent read access to ~/.ssh, ~/.aws, and ~/.config/gcloud, and denies write access to .env.

Examples

See examples/ for complete session configs (and examples/README.md for an index with a feature-coverage table):

Development

npm install
npm run build        # TypeScript compilation
npm run typecheck    # Type-check without emit (faster than build)
npm test             # Run all tests (vitest)
npm run test:watch   # Watch mode
npm run dev -- examples/simple.yaml   # Run via tsx

Contributing

See Also