
channelcoder
A streamlined SDK and CLI for Claude Code that channels your prompts with powerful features like multi-place variable interpolation, schema validation, and streaming support.
Repository Info
About This Server
A streamlined SDK and CLI for Claude Code that channels your prompts with powerful features like multi-place variable interpolation, schema validation, and streaming support.
Model Context Protocol (MCP) - This server can be integrated with AI applications to provide additional context and capabilities, enabling enhanced AI interactions and functionality.
Documentation
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?
- Parallel Development: Work on multiple features without stashing/switching
- Clean Experiments: Test risky changes in isolated environments
- Context Preservation: Each worktree maintains its own file state
- 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
- Create a Dockerfile with Claude CLI installed:
FROM node:20-slim
RUN npm install -g @anthropic-ai/claude-code
WORKDIR /workspace
- Build your image:
docker build -t my-claude .
- Use with channelcoder:
await claude('Task', { docker: { image: 'my-claude' } });
Auto-Detection
When using docker: true, channelcoder will:
- Look for a
Dockerfilein your project - Build an image automatically (with caching)
- 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:
- Docker Mode Guide - Run Claude in isolated containers with enhanced security
- Git Worktree Mode Guide - Parallel development in isolated git worktrees
- Session Management Guide - Multi-turn conversations with context preservation
- Stream Parser SDK Guide - Parse and monitor Claude's streaming output
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--jsonflag orclaude(prompt, { outputFormat: 'json' })stream- Use--streamflag orstream()functionverbose- Use--verboseflag orclaude(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 valuesnumber- Numeric valuesbooleanorbool- True/false valuesarrayortype[]- Arraysobject- Nested objectsany- 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 startedfile-based-usage.ts- Using file-based promptslaunch-modes.ts- Different execution modesdetached-streaming.ts- Background execution with real-time monitoringtask-monitor-tui.ts- NEW Real-time TUI using Stream Parser SDKdemo-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.
Quick Start
Clone the repository
git clone https://github.com/davidpp/channelcoderInstall dependencies
cd channelcoder
npm installFollow the documentation
Check the repository's README.md file for specific installation and usage instructions.
Repository Details
Recommended MCP Servers
Discord MCP
Enable AI assistants to seamlessly interact with Discord servers, channels, and messages.
Knit MCP
Connect AI agents to 200+ SaaS applications and automate workflows.
Apify MCP Server
Deploy and interact with Apify actors for web scraping and data extraction.
BrowserStack MCP
BrowserStack MCP Server for automated testing across multiple browsers.
Zapier MCP
A Zapier server that provides automation capabilities for various apps.