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

@computermotivators/paperclip-claude-cache

v2026.5.2-9.1

Published

Paperclip adapter for Anthropic Claude API with explicit prompt caching (cache_control breakpoints)

Readme

@paperclipai/adapter-claude-cached

Paperclip adapter that calls the Anthropic Messages API directly with explicit cache_control: { type: "ephemeral" } breakpoints on the system prompt and skills blocks — guaranteeing cache hits where the standard claude_local (Claude Code) adapter relies only on implicit caching.


Why this adapter?

| | claude_local | claude_cached | |---|---|---| | Runtime | Spawns claude CLI | Direct Anthropic SDK call | | Caching | Implicit (best-effort) | Explicit cache_control | | Tool ecosystem | Full Claude Code tools | Text/thinking only (extend for tools) | | cachedInputTokens telemetry | Via Claude Code output parsing | ✅ Native from API response | | Best for | Code-editing agents | Long system-prompt agents (Opus 4.x) |

Opus 4.5 list pricing (approximate):

  • Input: $15.00 / MTok
  • Cached read: $1.50 / MTok ← 10× cheaper
  • Cache write: $18.75 / MTok (one-time per 5-min TTL window)
  • Output: $75.00 / MTok

Installation

Drop this package into your Paperclip monorepo under packages/adapters/claude-cached/ and add it to pnpm-workspace.yaml if not already covered by a glob.

# pnpm-workspace.yaml
packages:
  - packages/adapters/*

Registration

1. Server (server/src/adapters/registry.ts)

import { execute as claudeCachedExecute, sessionCodec as claudeCachedSessionCodec, testEnvironment as claudeCachedTest } from "@paperclipai/adapter-claude-cached/server";
import { agentConfigurationDoc as claudeCachedDoc, models as claudeCachedModels } from "@paperclipai/adapter-claude-cached";

const claudeCachedAdapter: ServerAdapterModule = {
  type: "claude_cached",
  execute: claudeCachedExecute,
  testEnvironment: claudeCachedTest,
  sessionCodec: claudeCachedSessionCodec,
  models: claudeCachedModels,
  supportsLocalAgentJwt: true,
  agentConfigurationDoc: claudeCachedDoc,
};

// Add claudeCachedAdapter to the adaptersByType map alongside existing adapters.

2. UI (ui/src/adapters/registry.ts)

First, create ui/src/adapters/claude-cached/index.ts:

import type { UIAdapterModule } from "../types";
import { parseClaudeCachedStdoutLine, buildClaudeCachedConfig } from "@paperclipai/adapter-claude-cached/ui";
import { ClaudeCachedConfigFields } from "./config-fields";

export const claudeCachedUIAdapter: UIAdapterModule = {
  type: "claude_cached",
  label: "Claude (Cached API)",
  parseStdoutLine: parseClaudeCachedStdoutLine,
  ConfigFields: ClaudeCachedConfigFields,
  buildAdapterConfig: buildClaudeCachedConfig,
};

Then create ui/src/adapters/claude-cached/config-fields.tsx:

// Minimal config fields component — extend with your UI primitives as needed.
import React from "react";
import type { AdapterConfigFieldsProps } from "../types";

export function ClaudeCachedConfigFields({ values, set }: AdapterConfigFieldsProps) {
  return (
    <div>
      <label>API Key
        <input
          type="password"
          value={String(values["apiKey"] ?? "")}
          onChange={e => set("apiKey", e.target.value)}
          placeholder="${secrets.anthropic_api_key}"
        />
      </label>
      <label>Model
        <input
          value={String(values["model"] ?? "claude-opus-4-5")}
          onChange={e => set("model", e.target.value)}
        />
      </label>
      <label>Max tokens
        <input
          type="number"
          value={String(values["maxTokens"] ?? 8192)}
          onChange={e => set("maxTokens", Number(e.target.value))}
        />
      </label>
      <label>Max turns per heartbeat
        <input
          type="number"
          value={String(values["maxTurns"] ?? 10)}
          onChange={e => set("maxTurns", Number(e.target.value))}
        />
      </label>
    </div>
  );
}

Then register in ui/src/adapters/registry.ts:

import { claudeCachedUIAdapter } from "./claude-cached";
// Add to adaptersByType map

3. CLI (cli/src/adapters/registry.ts)

import { printClaudeCachedStreamEvent } from "@paperclipai/adapter-claude-cached/cli";

const claudeCachedCLIAdapter: CLIAdapterModule = {
  type: "claude_cached",
  formatStdoutEvent: printClaudeCachedStreamEvent,
};
// Add to adaptersByType map

Agent config example

{
  "name": "Research Analyst",
  "role": "analyst",
  "adapterType": "claude_cached",
  "adapterConfig": {
    "apiKey": "${secrets.anthropic_api_key}",
    "model": "claude-opus-4-5",
    "maxTokens": 8192,
    "maxTurns": 15,
    "thinkingBudget": 0,
    "timeoutSec": 0,
    "graceSec": 15,
    "systemPrompt": "You are {{agent.name}}, a research analyst at {{company.name}}. Your task: {{context.taskId}}. Wake reason: {{context.wakeReason}}."
  }
}

How caching works in this adapter

System message blocks sent to API
┌──────────────────────────────────────────────┐
│ Block 1: systemPrompt text                   │
│   cache_control: { type: "ephemeral" }  ◄── CACHED (TTL 5min)
├──────────────────────────────────────────────┤
│ Block 2: Skills content (if skillsDir set)   │
│   cache_control: { type: "ephemeral" }  ◄── CACHED (TTL 5min)
├──────────────────────────────────────────────┤
│ Conversation history (user/assistant turns)  │
│   (no cache_control — changes every turn)    │
└──────────────────────────────────────────────┘

On the first call in a 5-minute window: Anthropic writes the cache. On subsequent calls within 5 minutes: cache_read tokens are billed at $1.50/MTok instead of $15.00/MTok — a 10× reduction on the stable prefix.

The usage.cachedInputTokens field in AdapterExecutionResult is populated from cache_read_input_tokens in the API response and fed to Paperclip's budget tracking.


Limitations

  • No built-in tool dispatch (bash, file I/O, etc.). This is intentional — extend execute.ts with a tool-call loop if you need tools.
  • Cache TTL is 5 minutes (Anthropic's limit). Agents that sleep longer than 5 minutes between heartbeats will miss the cache window.
  • Conversation history is trimmed to the last 40 role-turns to avoid unbounded growth. Adjust the slice constant in execute.ts if needed.