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

channelcoder

v3.0.2

Published

A streamlined SDK and CLI for Claude Code - Channel your prompts to Claude

Readme

ChannelCoder

A streamlined SDK and CLI for Claude Code that channels your prompts with powerful features like multi-place variable interpolation, file-based prompts, and streaming support.

Installation

# Using npm
npm install channelcoder

# Using bun
bun add channelcoder

# Global CLI installation
npm install -g channelcoder

Quick Start

SDK Usage

import { claude } from 'channelcoder';

// Simple prompt
const result = await claude('What is TypeScript?');

// Template literals
const language = 'TypeScript';
await claude`Explain ${language} in simple terms`;

// File-based prompt with data
await claude('prompts/analyze.md', {
  data: { taskId: 'FEAT-123', priority: 'high' }
});

// With options
await claude('Review this code', {
  tools: ['Read', 'Grep'],
  system: 'You are a code reviewer'
});

CLI Usage

The CLI provides multiple commands for different execution modes:

# Interactive mode (default) - run Claude interactively
channelcoder interactive prompts/analyze.md -d taskId=FEAT-123

# Run mode - execute and print results
channelcoder run "Explain TypeScript"
channelcoder run prompts/analyze.md --data taskId=FEAT-123

# Stream mode - real-time streaming responses  
channelcoder stream "Write a story"
channelcoder stream prompts/generate.md

# Session management
channelcoder session list                    # List saved sessions
channelcoder session load my-session         # Load and continue a session
channelcoder session remove old-session      # Remove a session

# Worktree management
channelcoder worktree list                   # List git worktrees
channelcoder worktree create feature/new     # Create new worktree
channelcoder worktree remove feature/old     # Remove worktree

Features

🎯 Simple Function API

Mirrors Claude CLI's mental model with a simple function:

// Inline prompts
await claude('Explain quantum computing');

// File prompts (auto-detected by .md extension)
await claude('prompts/complex-analysis.md');

// With all the options you need
await claude('Debug this issue', {
  tools: ['Read', 'Bash'],
  resume: sessionId,
  maxTurns: 10
});

🔄 Variable Interpolation

Powerful multi-place variable support:

// In inline prompts
await claude('Analyze {code} for {issues}', {
  data: {
    code: 'const x = null',
    issues: ['null safety', 'type errors']
  }
});

// In file prompts
// prompts/review.md:
// Review {prTitle} with focus on {concerns ? concerns : "general quality"}
await claude('prompts/review.md', {
  data: { prTitle: 'Add auth system' }
});

🌊 Execution Modes

Different modes for different needs:

import { claude, interactive, stream, run, detached } from 'channelcoder';

// Run mode (default) - Get complete results programmatically
const result = await claude('Generate tests');
console.log(result.data);

// Stream mode - Real-time responses
for await (const chunk of stream('Write documentation')) {
  process.stdout.write(chunk.content);
}

// Interactive mode - Replace process (like running claude directly)
await interactive('Debug this error');
// ⚠️ Code after interactive() never executes!

// Detached mode - Background execution
const result3 = await detached('Long analysis task', {
  logFile: 'analysis.log'
});
console.log('Started background process:', result3.data?.pid);

// Detached streaming - Real-time background monitoring
const result4 = await detached('Generate comprehensive report', {
  logFile: 'report.log',
  stream: true  // Enables real-time JSON chunks in log file
});
// Monitor with: tail -f report.log | jq -r '.content'

🌿 Git Worktree Mode

Run Claude in isolated git worktrees for parallel development and clean experimentation:

// Simple worktree usage - auto-creates if doesn't exist
await claude('Implement new feature', { 
  worktree: 'feature/auth' 
});

// Standalone worktree function for complex workflows
await worktree('feature/payments', async (wt) => {
  console.log(`Working in: ${wt.path}`);
  await claude('Design payment system');
  await claude('Implement payment processing');
  return 'feature-complete';
}, {
  base: 'main',      // Create from main branch
  cleanup: false     // Keep worktree after execution
});

// Worktree utilities for advanced management
import { worktreeUtils } from 'channelcoder';

// List all worktrees
const worktrees = await worktreeUtils.list();

// Create/remove worktrees manually
await worktreeUtils.create('experiment/new-arch', { base: 'develop' });
await worktreeUtils.remove('feature/old');

// Check worktree existence
if (await worktreeUtils.exists('feature/auth')) {
  console.log('Auth worktree already exists');
}

Why Use Worktrees?

  1. Parallel Development: Work on multiple features without stashing/switching
  2. Clean Experiments: Test risky changes in isolated environments
  3. Context Preservation: Each worktree maintains its own file state
  4. Session Enhancement: Combine with sessions for branch-specific conversations

Worktree Options

interface WorktreeOptions {
  // Branch name (required for creation)
  branch?: string;
  
  // Base branch for new worktree
  base?: string;
  
  // Custom path (auto-generated if not provided)
  path?: string;
  
  // Remove worktree after execution (default: true for temporary)
  cleanup?: boolean;
  
  // Force creation vs. error if exists (default: false - upsert)
  create?: boolean;
}

Composing Features

Worktrees work seamlessly with other ChannelCoder features:

// Worktree + Session
const s = session();
await s.claude('Start OAuth feature', { worktree: 'feature/oauth' });
await s.claude('Add tests'); // Continues in same worktree

// Worktree + Docker
await claude('Test in total isolation', {
  worktree: 'experiment/risky',
  docker: true
});

// Worktree + Streaming
await worktree('feature/docs', async () => {
  for await (const chunk of stream('Generate documentation')) {
    process.stdout.write(chunk.content);
  }
});

🐳 Docker Mode

Run Claude in an isolated Docker container for enhanced security with dangerous permissions:

// Simple Docker mode - auto-detect Dockerfile
await claude('Risky operation', { docker: true });

// Specify Docker image
await claude('Analyze system', { 
  docker: { image: 'my-claude:latest' } 
});

// With custom mounts and environment
await claude('Process data', {
  docker: {
    image: 'claude-sandbox',
    mounts: ['./data:/data:ro'],
    env: { NODE_ENV: 'production' }
  }
});

Setting Up Docker Mode

  1. Create a Dockerfile with Claude CLI installed:
FROM node:20-slim
RUN npm install -g @anthropic-ai/claude-code
WORKDIR /workspace
  1. Build your image:
docker build -t my-claude .
  1. Use with channelcoder:
await claude('Task', { docker: { image: 'my-claude' } });

Auto-Detection

When using docker: true, channelcoder will:

  1. Look for a Dockerfile in your project
  2. Build an image automatically (with caching)
  3. Mount your working directory as /workspace

Docker Options

interface DockerOptions {
  // Auto-detect Dockerfile (default: true)
  auto?: boolean;
  
  // Docker image to use
  image?: string;
  
  // Path to Dockerfile (default: ./Dockerfile)
  dockerfile?: string;
  
  // Additional volume mounts
  mounts?: string[];  // Docker format: "host:container:mode"
  
  // Environment variables
  env?: Record<string, string>;
}

CLI Reference

channelcoder <command> [options]

Commands:
  run          Execute prompt and exit (print mode) - non-interactive
  interactive  Interactive mode with Claude (default)
  stream       Stream responses in real-time
  session      Manage conversation sessions
  worktree     Manage git worktrees

Global Options:
  -h, --help     Show help
  -v, --version  Show version

Run 'channelcoder <command> --help' for command-specific options

Command Details

channelcoder run [prompt-file] [options]

Execute a prompt and print the result without interaction.

Options:
  -p, --prompt <text>      Inline prompt instead of file
  -d, --data <key=value>   Data for interpolation (repeatable)
  -s, --system <prompt>    System prompt (text or .md file)
  -t, --tools <tools>      Allowed tools (e.g., "Read Write")
  --disallowed-tools       Disallowed tools (comma-separated)
  --append-system <text>   Append to system prompt
  --mcp-config <file>      Load MCP servers from JSON file
  --permission-tool <tool> MCP tool for permission prompts
  -r, --resume <id>        Resume conversation by session ID
  -c, --continue           Continue most recent conversation
  --max-turns <n>          Limit agentic turns
  --json                   Output JSON format
  -v, --verbose            Verbose output

channelcoder interactive [prompt-file] [options]

Launch Claude in interactive mode (default command).

Options: Same as 'run' command

channelcoder stream [prompt-file] [options]

Stream responses in real-time.

Options: Same as 'run' command

channelcoder session <subcommand>

Manage conversation sessions.

Subcommands:
  list       List all saved sessions
  load       Load and continue a session
  remove     Remove a saved session

channelcoder worktree <subcommand>

Manage git worktrees for isolated development.

Subcommands:
  list       List all worktrees
  create     Create a new worktree
  remove     Remove a worktree
  cleanup    Clean up orphaned worktrees

Advanced Features Documentation

For detailed guides on advanced features, see the /documentation folder:

Frontmatter Syntax

File-based prompts support YAML frontmatter for configuration. Here are the actually supported options:

---
# System prompt - Sets the Claude system/assistant prompt
# Can be inline text or a path to a .md/.txt file
systemPrompt: "You are a helpful coding assistant"
# or
systemPrompt: "./system-prompts/analyst.md"

# Append to system prompt
appendSystemPrompt: "Always explain your reasoning"

# Allowed tools - Restrict which tools Claude can use
# These are passed to Claude CLI's --allowedTools flag
allowedTools:
  - "Read"                    # Read files
  - "Write"                   # Write files
  - "Edit"                    # Edit files
  - "Bash"                    # Run any bash command
  - "Bash(git:*)"            # Pattern: only git commands
  - "Bash(npm:test)"         # Specific: only npm test
  - "Grep"                   # Search file contents
  - "WebSearch"              # Search the web

# Disallowed tools - Prevent specific tools
disallowedTools:
  - "Bash(rm:*)"             # No rm commands
  - "Bash(git:push)"         # No git push

# MCP (Model Context Protocol) configuration
mcpConfig: "./mcp-servers.json"
permissionPromptTool: "mcp__auth__prompt"

# Input schema - Validates variables before interpolation
input:
  name: string               # Required string
  age?: number              # Optional number
  tags: string[]            # Array of strings
  config:                   # Nested object
    port: number
    host?: string

# Output schema - Validates Claude's response (SDK only)
output:
  success: boolean
  result:
    type: string
    enum: [feature, bug, chore]  # Enum constraint
  items: 
    - name: string
      done: boolean
---
Your prompt content here...

Note: The following options are passed via CLI or SDK, not frontmatter:

  • outputFormat - Use --json flag or claude(prompt, { outputFormat: 'json' })
  • stream - Use --stream flag or stream() function
  • verbose - Use --verbose flag or claude(prompt, { verbose: true })
  • timeout - SDK only: claude(prompt, { timeout: 30000 })

Frontmatter Validation

The frontmatter is validated using a Zod schema. Invalid keys will cause an error:

import { FrontmatterSchema, type Frontmatter } from 'channelcoder';

// Validate frontmatter programmatically
const result = FrontmatterSchema.safeParse({
  systemPrompt: "Valid",
  temperature: 0.7  // Error: unknown key
});

// TypeScript type for frontmatter
const config: Frontmatter = {
  systemPrompt: "Assistant prompt",
  appendSystemPrompt: "Be concise",
  allowedTools: ["Read", "Write"],
  disallowedTools: ["Bash(rm:*)"],
  mcpConfig: "./mcp-servers.json",
  permissionPromptTool: "mcp__auth__prompt",
  input: { name: "string" },
  output: { success: "boolean" }
};

Schema Definition Format

Schemas are defined using YAML notation that's automatically converted to Zod schemas:

---
input:
  name: string              # Basic types: string, number, boolean
  age?: number             # Optional with ?
  tags: string[]           # Arrays with []
  metadata:                # Nested objects
    created: string
    updated?: string
---

Supported types:

  • string - Text values
  • number - Numeric values
  • boolean or bool - True/false values
  • array or type[] - Arrays
  • object - Nested objects
  • any - Any value

Note: For programmatic SDK usage, you can also use Zod schemas directly in the validation utilities.

Examples

File-based Prompts

Create a prompt file analyze.md:

---
input:
  task: string
  details?: boolean
systemPrompt: "You are a helpful analyst"
allowedTools:
  - Read
  - Grep
---
# Analysis for {task}

{details ? "Provide detailed breakdown." : "Summary only."}

Run it:

channelcoder analyze.md -d task="Review PR" -d details=true

Inline Prompts

# Simple
channelcoder -p "Explain {concept}" -d concept="quantum computing"

# With tools
channelcoder -p "Find files containing {pattern}" \
   -d pattern="TODO" \
   -t "Read Grep"

# Streaming
channelcoder -p "Write a haiku about {topic}" \
   -d topic="coding" \
   --stream

# Resume conversation
channelcoder --resume abc123 -p "Continue with the implementation"

# Continue last conversation
channelcoder --continue -p "What about error handling?"

# Limit agentic turns
channelcoder analyze.md --max-turns 3

# MCP configuration
channelcoder query.md --mcp-config ./servers.json

# Disallow dangerous tools
channelcoder cleanup.md --disallowed-tools "Bash(rm:*),Bash(git:push)"

Complex Data

# Arrays and objects via JSON
channelcoder -p "Process items: {items}" \
   -d 'items=["apple","banana","orange"]'

# Complex nested data
channelcoder -p "Config: {config}" \
   -d 'config={"port":3000,"host":"localhost"}'

SDK Reference

Basic Usage

import { claude } from 'channelcoder';

// Simple prompts
const result = await claude('Explain TypeScript');

// Template literals
const topic = 'async/await';
const result = await claude`Explain ${topic} with examples`;

// File-based prompts
const result = await claude('prompts/analyze.md', {
  data: { taskId: 'FEAT-123' }
});

Options

// All available options
const result = await claude('Your prompt', {
  // Data interpolation
  data: { key: 'value' },
  
  // System configuration
  system: 'You are a helpful assistant',
  appendSystem: 'Be concise',
  
  // Tool configuration
  tools: ['Read', 'Write', 'Bash(git:*)'],
  disallowedTools: ['Bash(rm:*)'],
  mcpConfig: './mcp-servers.json',
  permissionTool: 'mcp__auth__prompt',
  
  // Session management
  resume: 'session-id-here',
  continue: true,
  
  // Execution control
  maxTurns: 10,
  mode: 'run', // 'run' | 'stream' | 'interactive'
  includeEvents: true,
  
  // Background execution
  detached: true,        // Run in background
  logFile: 'output.log', // Log file for detached mode
  stream: true,          // Enable real-time streaming in detached mode
  
  // Other
  verbose: true,
  outputFormat: 'json',
  timeout: 60000
});

Streaming

import { stream } from 'channelcoder';

// Stream responses
for await (const chunk of stream('Generate a story')) {
  if (chunk.type === 'content') {
    process.stdout.write(chunk.content);
  }
}

Error Handling

const result = await claude('prompt.md', { data });

if (!result.success) {
  console.error('Error:', result.error);
  if (result.warnings) {
    console.warn('Warnings:', result.warnings);
  }
}

// Type-safe error handling
if (result.warnings?.includes('max turns reached')) {
  console.log('Hit maximum turn limit');
}

Interactive Mode

import { interactive } from 'channelcoder';

// Launch Claude interactively (replaces current process)
await interactive('Help me debug this issue');

// Code below this line will NEVER execute!
// The process is replaced by Claude using shell exec

Important: Interactive mode completely replaces your Node.js process with Claude:

  • No Node.js parent process remains in memory
  • Claude gets direct terminal control
  • Exit codes go directly to the shell
  • Perfect for long Claude sessions without memory overhead

Background Execution & Real-time Monitoring

ChannelCoder supports background execution with real-time monitoring capabilities:

import { detached, session } from 'channelcoder';

// Basic background execution
const result = await detached('Analyze large codebase', {
  logFile: 'analysis.log'
});
console.log('Background process started with PID:', result.data?.pid);

// Real-time streaming to log file
const result2 = await detached('Generate comprehensive report', {
  logFile: 'report.log',
  stream: true  // Enables real-time JSON streaming
});

// Monitor in real-time with Unix tools
// tail -f report.log | jq -r '.content'          # See content
// tail -f report.log | jq -r '.type'             # See chunk types
// watch -n 1 "wc -l report.log"                  # Monitor progress

Session Background Execution:

// Session with real-time file updates
const s = session({ 
  autoSave: true  // Session file updates in real-time
});

// Background execution with session context
await s.detached('Long-running analysis', {
  logFile: 'session-output.log',
  stream: true
});

// Monitor both Claude output AND session state
// tail -f session-output.log | jq -r '.content'   # Claude output
// watch -n 1 cat ~/.channelcoder/sessions/my-session.json  # Session state

Stream Parser SDK

ChannelCoder includes a powerful Stream Parser SDK for parsing Claude's stream-json output from detached sessions and log files:

import { parseLogFile, monitorLog, streamParser } from 'channelcoder';

// Parse a complete log file
const parsed = await parseLogFile('session.log');
console.log(parsed.content);        // All assistant messages
console.log(parsed.totalCost);      // Total cost
console.log(parsed.events.length);  // Number of events

// Monitor a log file in real-time
const cleanup = monitorLog('active.log', (event) => {
  if (streamParser.isAssistantEvent(event)) {
    console.log('Claude:', streamParser.extractAssistantText(event));
  } else if (streamParser.isToolUseEvent(event)) {
    console.log('Tool used:', event.tool);
  } else if (streamParser.isResultEvent(event)) {
    console.log('Completed! Cost:', event.cost_usd);
  }
});

// Clean up when done
cleanup();

// Low-level parsing
import { parseStreamEvent, eventToChunk } from 'channelcoder/streamParser';

const line = '{"type":"assistant","message":{...}}';
const event = parseStreamEvent(line);
const chunk = eventToChunk(event);

Type Guards for Event Handling:

import { 
  isSystemEvent, 
  isAssistantEvent, 
  isResultEvent,
  isToolUseEvent,
  isErrorEvent 
} from 'channelcoder';

// Type-safe event processing
function processEvent(event: ClaudeEvent) {
  if (isAssistantEvent(event)) {
    const text = streamParser.extractAssistantText(event);
    console.log('Assistant:', text);
  } else if (isToolUseEvent(event)) {
    console.log('Tool:', event.tool, event.input);
  } else if (isResultEvent(event)) {
    if (event.subtype === 'error') {
      console.error('Failed:', event.error);
    } else {
      console.log('Success! Cost: $', event.cost_usd);
    }
  }
}

See examples/task-monitor-tui.ts for a complete real-time monitoring TUI built with the Stream Parser SDK.

Session Management

ChannelCoder provides built-in session management for maintaining conversation context:

import { session } from 'channelcoder';

// Create a new session with auto-save
const s = session({ autoSave: true });

// Use like normal, but with automatic context tracking
await s.claude('What is TypeScript?');
await s.claude('Show me an example'); // Automatically continues conversation

// Save session for later
await s.save('learning-typescript');

// Load and continue a saved session
const saved = await session.load('learning-typescript');
await saved.claude('What about generics?');

// List all saved sessions
const sessions = await session.list();
// [{ name: 'learning-typescript', messageCount: 3, lastActive: Date, ... }]

// Access session data
console.log(s.id());         // Current session ID
console.log(s.messages());   // Conversation history

CLI Session Support:

# Start a new session
channelcoder prompts/debug.md --session my-debug

# Continue a session
channelcoder prompts/continue.md --load-session my-debug

# List all sessions
channelcoder --list-sessions

Session-Required Prompts:

---
session:
  required: true
systemPrompt: "You are debugging an ongoing issue"
---
Continue investigating the error we discussed.

Manual Session Management (without session wrapper):

// Resume a specific session by ID
await claude('Continue our discussion', {
  resume: 'session-id-here'
});

// Continue most recent session
await claude('Continue where we left off', {
  continue: true
});

Prompt File Format

ChannelCoder uses Markdown files with YAML frontmatter:

---
# Input validation (optional)
input:
  name: string
  age?: number
  tags: string[]

# Output schema (optional)
output:
  success: boolean
  message: string

# Claude options
systemPrompt: "path/to/system.md"  # or inline text
allowedTools:
  - Read
  - Write
  - "Bash(git:*)"  # With patterns
---

# Your prompt with {name} interpolation

Age: {age ? age : "not specified"}

Tags: {tags}

Requirements

  • Claude Code CLI installed and configured
  • Node.js 18+ or Bun runtime

Tips & Tricks

1. Tool Patterns

Allow specific command patterns:

channelcoder prompt.md -t "Bash(git:*) Read Write"

2. Conditional Content

Use JavaScript expressions in templates:

const isDev = true;
const items = ['a', 'b', 'c'];

await claude`
  ${isDev ? "Include debug info" : ""}
  Process ${items.length} items
`;

3. System Prompts

Can be inline or file paths:

# Inline
channelcoder -p "..." -s "Be concise"

# From file
channelcoder -p "..." -s "prompts/systems/expert.md"

4. Background Monitoring

Perfect for long-running tasks:

# Start background streaming process
channelcoder analysis.md --detached --stream --log analysis.log

# Monitor real-time progress (Unix composable)
tail -f analysis.log | jq -r '.content'           # Content only
tail -f analysis.log | jq -r 'select(.type=="tool_use").tool'  # Tool usage
watch -n 1 "grep -c content analysis.log"         # Progress counter

5. JSON Output

Perfect for automation:

result=$(cc prompt.md --json)
success=$(echo $result | jq -r '.success')

Examples

Check out the /examples directory for:

  • basic-usage.ts - Simple examples to get started
  • file-based-usage.ts - Using file-based prompts
  • launch-modes.ts - Different execution modes
  • detached-streaming.ts - Background execution with real-time monitoring
  • task-monitor-tui.ts - NEW Real-time TUI using Stream Parser SDK
  • demo-features.ts - Feature showcase (no execution)
  • release.ts - Real-world release automation

Run examples:

bun run example:quick     # Run basic examples
bun run examples/basic-usage.ts
bun run examples/launch-modes.ts run
bun run examples/release.ts

License

MIT

Contributing

Issues and PRs welcome at github.com/davidpp/channelcoder


Named after Claude Shannon, the father of information theory, ChannelCoder channels your prompts to Claude with maximum signal and minimum noise.