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

@powerhousedao/ph-clint-claude-subscription

v0.1.0-dev.1

Published

ph-clint plugin: authenticate against the Anthropic API using a Claude.ai Pro/Max subscription (OAuth) instead of an API key.

Downloads

316

Readme

@powerhousedao/ph-clint-claude-subscription

A ph-clint plugin that lets your CLI / agent authenticate against the Anthropic API with a Claude.ai Pro or Max subscription instead of (or alongside) a pay-as-you-go API key.

Under the hood, this uses the same OAuth flow as the official claude CLI: PKCE-protected authorization, refresh-token rotation, and the oauth-2025-04-20,claude-code-20250219 API beta header. Tokens are persisted to the ph-clint workspace store ({workdir}/.ph/{cliName}/claude-subscription.json) and refreshed on demand.

Important — Anthropic terms. Anthropic restricts subscription OAuth tokens to Claude-Code-shaped clients. The plugin enforces this for you: the outbound system prompt is rewritten so its first block is always the required preamble, regardless of what your agent passes. Using these tokens in unrelated products still violates the Anthropic Consumer ToS.


Install

pnpm add @powerhousedao/ph-clint-claude-subscription @ai-sdk/anthropic@^2

@ai-sdk/anthropic is an optional peer dependency — only required if you use createClaudeSubscriptionModel(). The OAuth + storage + command APIs work without it. The plugin is tested against @ai-sdk/[email protected].


For CLI developers

1. Add the auth commands to your CLI

// cli.ts
import { defineCli } from '@powerhousedao/ph-clint';
import { createClaudeAuthCommands } from '@powerhousedao/ph-clint-claude-subscription';
import { myCommands } from './commands/index.js';

export const cli = defineCli({
  name: 'my-cli',
  version: '0.1.0',
  description: 'My ph-clint CLI',
  commands: [
    ...myCommands,
    ...createClaudeAuthCommands(), // adds claude-login / claude-logout / claude-status
  ],
});

That's it — your users now have my-cli claude-login, claude-logout, and claude-status available.

2. Use the subscription session in your agent factory

The example below mirrors the real-world pattern: a demo-agent escape hatch, API-key fast path, subscription fallback, and a final demo-agent fallback if nothing is configured.

// agents/agent.ts
import { Agent } from '@mastra/core/agent';
import { createWorkdirStore } from '@powerhousedao/ph-clint';
import type { AgentSetupContext, AgentProvider } from '@powerhousedao/ph-clint';
import { createMastraHelpers } from '@powerhousedao/ph-clint/mastra';
import {
  createSession,
  createWorkdirTokenStore,
  createClaudeSubscriptionModel,
} from '@powerhousedao/ph-clint-claude-subscription';
import { CLI_NAME } from '../config.js';
import { createDemoAgent } from './demo-agent.js';

export async function createAgent(
  ctx: AgentSetupContext<Config>,
): Promise<AgentProvider> {
  // 1. Demo agent escape hatch (e.g. for offline development).
  if (ctx.config.model === 'clint/demo-agent') return createDemoAgent();

  const m = createMastraHelpers(ctx);
  const store = createWorkdirStore(ctx.workdir, CLI_NAME);

  const usingApiKey = Boolean(ctx.config.anthropicApiKey);
  const subscription = createSession({ store: createWorkdirTokenStore(store) });
  const usingSubscription =
    !usingApiKey && (await subscription.isAuthenticated());

  // 4. Nothing configured — fall back to demo and tell the user.
  if (!usingApiKey && !usingSubscription) {
    ctx.context.log?.info(
      '[agent] No API key and no Claude subscription session — ' +
        'run `my-cli claude-login` to authenticate with Pro/Max.',
    );
    return createDemoAgent();
  }

  // 2. API key wins when both are present.
  // 3. Otherwise use the subscription session.
  const model = usingSubscription
    ? await createClaudeSubscriptionModel({
        session: subscription,
        modelId: ctx.config.model, // e.g. 'anthropic/claude-sonnet-4-5'
      })
    : {
        id: ctx.config.model as `${string}/${string}`,
        apiKey: ctx.config.anthropicApiKey!,
      };

  const agent = new Agent({
    id: 'my-agent',
    name: 'My agent',
    instructions: m.getAgentInstructions('my-agent'),
    model,
    tools: () => m.getTools(),
  });
  return m.wrapAgent(agent, { maxSteps: 80 });
}

The session refreshes tokens automatically and the plugin enforces Anthropic's system-prompt compliance via its fetch interceptor — your agent code doesn't see the OAuth machinery at all.

Model ids

Pass the AI-SDK / Mastra-style provider-prefixed id:

  • 'anthropic/claude-sonnet-4-5'
  • 'anthropic/claude-haiku-4-5'
  • 'anthropic/claude-opus-4-5'

The plugin strips the anthropic/ prefix before talking to the API, so the bare id also works. Using the prefixed form keeps your config consistent between the API-key and subscription paths.


For end users

# Start the flow — opens a URL you authorize at claude.ai.
my-cli claude-login

# Paste the code shown on the redirect page back in.
my-cli claude-login --code 'abc123#state'

# Check session status.
my-cli claude-status

# Sign out.
my-cli claude-logout

Where tokens live. Tokens are stored in the ph-clint workspace store at {workdir}/.ph/{cliName}/claude-subscription.json, where {workdir} is your CLI's current workspace directory (resolved by ph-clint — usually the cwd you ran the CLI from, not ~). If you run claude-login in one directory and then run the agent from another, the agent won't see the tokens. Use the same workdir, or copy the file across.

Refresh happens on the next agent call after expiry — no manual intervention needed.


API

createClaudeAuthCommands(options?)

Returns three Commands ready to drop into defineCli({ commands }):

| id | description | | --------------- | ------------------------------------------------ | | claude-login | Two-step OAuth login. Run without --code first.| | claude-logout | Clear stored tokens. | | claude-status | Show whether a session is stored + when expires. |

Options:

  • prefix — change the command-id prefix (default 'claude').
  • redirectUri — override the OAuth redirect URI (default = the manual-paste callback used by claude.ai).
  • store — supply a custom TokenStore factory (default = workspace-backed).

createSession({ store })

Manages access tokens: reads from storage, refreshes when expired, dedupes concurrent refreshes. Use session.getAuthHeaders() to mint per-request Authorization + anthropic-beta headers.

createClaudeSubscriptionModel({ session, modelId })

Returns a LanguageModelV2 (from @ai-sdk/provider) wired to the session. Pass directly to Mastra's Agent({ model }) or any other AI-SDK consumer.

Accepts both 'anthropic/<id>' and bare '<id>' model strings; the anthropic/ prefix is stripped before the request is sent. The plugin's fetch interceptor also rewrites the outbound system prompt to be Anthropic-compliant — callers don't need to prepend anything.

Low-level OAuth helpers

createPkce(), buildAuthorizeUrl(), exchangeCode(), refreshTokens(), parseManualCode(), isExpired(). Useful if you want to build a custom auth flow (e.g. a TUI flow with a local HTTP listener instead of manual paste).


Troubleshooting

Cannot find package '@ai-sdk/anthropic' — declared as an optional peer. Install it: pnpm add @ai-sdk/anthropic@^2. Mastra ships internal aliased copies, but the unaliased name has to be in your CLI's own dependencies.

404 not_found_error: model: <id> — your model id isn't recognized. Use one of the documented Anthropic ids (e.g. claude-sonnet-4-5); the anthropic/-prefixed form is accepted and stripped automatically.

429 rate_limit_error with "Error" as the message and no retry-after — this is Anthropic rejecting a non-Claude-Code-shaped request, not a real rate limit. The plugin enforces compliance via its fetch interceptor; if you're seeing this, you're probably bypassing createClaudeSubscriptionModel (e.g. talking to the API directly with the session's auth headers). Send the system prompt as a two-block array whose first block is exactly "You are Claude Code, Anthropic's official CLI for Claude.".

Not signed in. Run claude-login... after a successful login — workdir mismatch. Tokens are scoped to the CLI's workdir; running claude-login in one directory and the agent in another will not share the session.


Why a separate package?

  • No new framework concepts. It composes with defineCli via plain commands and a plain agent-factory hook.
  • No core dependency. ph-clint stays auth-agnostic; this package owns one specific provider and ToS-bound behavior.
  • Easy to swap. A future ph-clint-openai-subscription (or whatever) can follow the same shape.