# claude-senator-mcp
> **ā under construction:** This project is under heavy construction and is not intended for public use / nor has it been published to npm. Information in the README below may be outdated, user discretion is advised.
<!--  -->
A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server for **inter-Claude communication and context sharing**. Enables Claude instances to collaborate, share context, and fork conversations without interruption.
[](https://www.typescriptlang.org/)
[](https://www.npmjs.com/package/claude-senator)
[](https://opensource.org/licenses/MIT)
[](https://nodejs.org/)
## Philosophy
**Simple for humans, rich for Claude.**
- **Human**: One-line commands that expand into ultra-rich context
- **Claude**: Dense collaboration intelligence with smart pointers
- **Architecture**: Zero-dependency file-based IPC with beautiful ASCII UI
## Install
Requirements:
- [Claude Code](https://claude.ai/code)
```bash
npm install -g claude-senator
```
**From shell:**
```bash
claude mcp add claude-senator -- npx claude-senator
```
**From inside Claude** (restart required):
```
Add this to our global mcp config: npx claude-senator
```
**From any manually configurable `mcp.json`**: (Cursor, Windsurf, etc.)
```json
{
"mcpServers": {
"claude-senator": {
"command": "npx",
"args": ["claude-senator"],
"env": {}
}
}
}
```
## Features
### šļø **Current: Inter-Claude Messaging System**
#### **3-Function Interface**
```bash
# Share context with other Claude instances
claude-senator send_context --target_pid 98471 --context_request "Help with documentation"
# Receive context from other Claude instances
claude-senator receive_context
# Live status of all Claude instances with collaboration recommendations
claude-senator status
```
#### **Smart Pointer Architecture**
Ultra-lightweight context sharing using pointers to existing `~/.claude/projects/` data rather than copying content:
```typescript
// Instead of copying data (expensive)
const heavyMessage = {
conversationHistory: [
/* 1000s of messages */
],
fileContents: [
/* large file contents */
],
};
// We use smart pointers (lightweight)
const smartMessage = {
ctx_pointers: {
projects_dir: `~/.claude/projects/${projectEncoded}`,
conversation_history: this.getConversationPointer(),
git_context: this.getGitContextString(),
active_files: this.getActiveFilesArray(),
},
};
```
#### **Beautiful ASCII UI**
```bash
āā šļø āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā ā Claude 98471 ⢠"Help with documentation..." ⢠~/.claude pointers sent
ā š Context shared ⢠Ready for collaboration
āā š 2 contexts processed ⢠Rich collaboration network active
```
### š **New: Context Forking System**
#### **Problem**
You have Claude deep in work (318s, 9.3k tokens) and want to ask questions without interrupting.
#### **Solution**
Context forking creates new Claude instances with inherited context while preserving the working Claude's state.
```bash
# Fork context from working Claude
claude-senator fork_claude --source_pid 98471 --query "What's the documentation structure?"
# Result: New session with full context + your question
# Working Claude continues uninterrupted
```
## Technical Architecture
### **Directory Structure**
```
/tmp/claude-senator/
āāā instances/ # Each Claude writes {pid}.json with status/info
āāā messages/ # Individual message files in JSONL format
āāā commands/ # Command injection files for input manipulation
```
### **Smart Pointer System**
References existing `~/.claude/projects/` data instead of copying:
```typescript
interface ContextPointers {
projects_dir: string; // `~/.claude/projects/${encoded_path}`
conversation_history: string; // Recent conversation file path
git_context: string; // Compact git state (branch@commit+dirty)
active_files: string[]; // Recently modified files
current_task: string; // What Claude is working on
collaboration_intent: string; // Why reaching out to other Claude
}
```
### **Message Format**
Ultra-dense messaging with context reconstruction:
```typescript
interface InterClaudeMessage {
id: string;
from: number; // Sender Claude PID
to: number | 'all'; // Target Claude PID or broadcast
type: 'ultra_dense_message';
content: string; // Human-readable request
timestamp: number;
options: {
claudeContext: {
h: string; // Human message
pid: number; // Claude PID
ts: number; // Timestamp
cwd: string; // Working directory
ctx_pointers: ContextPointers; // Smart pointers to data
};
};
}
```
## Implementation Details
### **Current Messaging System**
#### **SessionManager Core Methods**
##### `createMessage(humanMessage: string)`
Creates ultra-dense context messages with smart pointers:
- **Purpose**: Lightweight context sharing
- **Input**: Human message string
- **Output**: Smart pointer context object with collaboration intelligence
- **Used by**: `send_context` tool
```typescript
private createMessage(humanMessage: string): any {
const workingDir = process.cwd();
const claudeDir = join(homedir(), '.claude');
const projectEncoded = workingDir.replace(/\//g, '-').replace(/^-/, '');
const pid = process.ppid || process.pid;
return {
h: humanMessage,
pid: pid,
ts: Date.now(),
cwd: workingDir,
ctx_pointers: {
projects_dir: `~/.claude/projects/${projectEncoded}`,
conversation_history: this.getConversationPointer(),
git_context: this.getGitContextString(),
active_files: this.getActiveFilesArray(),
current_task: this.getCurrentTaskFromContext(),
collaboration_intent: this.determineCollaborationIntent(humanMessage)
}
};
}
```
##### `reconstructRichContext(message: any)`
Rebuilds full context from smart pointers:
- **Purpose**: Context reconstruction on receiving end
- **Input**: Message with smart pointers
- **Output**: Full context object with conversation history
- **Used by**: `receive_context` tool
```typescript
private reconstructRichContext(message: any): any {
const ctx = message.options?.claudeContext;
if (!ctx?.ctx_pointers) return null;
const pointers = ctx.ctx_pointers;
const reconstructed = {
sender_info: {
human_message: ctx.h,
pid: ctx.pid,
working_directory: ctx.cwd,
timestamp: ctx.ts
},
collaboration_context: {
current_task: pointers.current_task,
intent: pointers.collaboration_intent,
git_state: pointers.git_context,
active_files: pointers.active_files
},
shared_data_access: {
projects_dir: pointers.projects_dir,
conversation_history: pointers.conversation_history
}
};
// Load conversation history if pointer exists
if (pointers.conversation_history) {
reconstructed.conversation_snippet = this.loadConversationSnippet(pointers.conversation_history);
}
return reconstructed;
}
```
##### `generateRichContextDisplay(instance: any, activity: any)`
Creates real-time status with collaboration scoring:
- **Purpose**: Live context display without transmission
- **Input**: Claude instance data and activity
- **Output**: Rich context with collaboration readiness score
- **Used by**: `status` tool
```typescript
private generateRichContextDisplay(instance: any, activity: any): any {
const workingDir = instance.cwd || instance.projectPath || '/unknown';
const encodedPath = String(workingDir).replace(/\//g, '-').replace(/^-/, '');
const contextPointers = {
projectsDir: `~/.claude/projects/${encodedPath}`,
conversationHistory: this.getConversationPointer(workingDir),
gitContext: this.getGitContextString(workingDir),
activeFiles: this.getActiveFilesArray(workingDir),
currentTask: activity.task || 'Active',
collaborationIntent: this.determineCollaborationReadiness(activity, instance)
};
const collaborationMetrics = {
hasRecentActivity: activity.lastActivity > Date.now() - 300000,
hasActiveFiles: contextPointers.activeFiles.length > 0,
hasCleanGitState: !contextPointers.gitContext.includes('dirty'),
isWorkingOnKnownTask: activity.task && activity.task !== 'Active',
projectType: this.detectProjectType(workingDir)
};
return {
...contextPointers,
collaborationMetrics,
collaborationReason: this.getCollaborationReason(collaborationMetrics),
readinessScore: this.calculateReadinessScore(collaborationMetrics)
};
}
```
#### **Collaboration Scoring Algorithm**
```typescript
private calculateCollaborationScore(contextData: any): number {
const metrics = contextData.collaborationMetrics;
if (!metrics) return 0;
let score = 0;
if (metrics.hasRecentActivity) score += 0.3;
if (metrics.hasActiveFiles) score += 0.2;
if (metrics.hasCleanGitState) score += 0.2;
if (metrics.isWorkingOnKnownTask) score += 0.2;
if (metrics.projectType !== 'unknown') score += 0.1;
return Math.min(score, 1.0);
}
```
#### **Context Pointer Helpers**
```typescript
private getConversationPointer(): string | null {
const claudeDir = join(homedir(), '.claude');
const projectEncoded = process.cwd().replace(/\//g, '-').replace(/^-/, '');
const projectDir = join(claudeDir, 'projects', projectEncoded);
if (existsSync(projectDir)) {
const files = readdirSync(projectDir).filter(f => f.includes('conversation'));
if (files.length > 0) {
return `~/.claude/projects/${projectEncoded}/${files[files.length - 1]}`;
}
}
return null;
}
private getGitContextString(): string {
try {
const branch = execSync('git branch --show-current 2>/dev/null', { encoding: 'utf8' }).trim();
const commit = execSync('git rev-parse --short HEAD 2>/dev/null', { encoding: 'utf8' }).trim();
const status = execSync('git status --porcelain 2>/dev/null', { encoding: 'utf8' }).trim();
const dirty = status ? '+dirty' : '';
return `${branch}@${commit}${dirty}`;
} catch (error) {
return 'no-git';
}
}
private getActiveFilesArray(): string[] {
try {
const recentFiles = execSync('git diff --name-only HEAD~1 2>/dev/null', {
encoding: 'utf8'
}).trim().split('\n').filter(f => f);
return recentFiles.slice(0, 5);
} catch (error) {
return [];
}
}
```
### **New Context Forking System**
#### **Core Implementation**
```typescript
// New MCP tool
{
name: 'fork_claude',
description: 'Create new Claude session with full context from target Claude',
inputSchema: {
source_pid: { type: 'number', description: 'Claude to copy from' },
query: { type: 'string', description: 'Your question for the new Claude' }
}
}
// Implementation
case 'fork_claude': {
const sourcePid = args?.source_pid as number;
const query = args?.query as string;
// Find source Claude's conversation
const sourceActivity = this.sessionManager.parseLiveActivity(sourcePid);
const conversationPath = this.findConversationPath(sourcePid);
// Copy conversation to new session
const newSessionId = this.createForkedSession(conversationPath, query);
return {
content: [{
type: 'text',
text: `āā š Context Forked āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā šø Copied: ${sourceActivity.task} ⢠Full conversation history
ā š New session: ${newSessionId}
ā šÆ Ready for: "${query}"
āā ⨠Run: claude --session ${newSessionId} to start new Claude with context`
}]
};
}
```
#### **Session Creation**
```typescript
private createForkedSession(sourcePath: string, newQuery: string): string {
const timestamp = new Date().toISOString().replace(/[:.]/g, '');
const newSessionId = `fork_${timestamp}`;
const newSessionPath = join(homedir(), '.claude', 'sessions', newSessionId);
// Create new session directory
mkdirSync(newSessionPath, { recursive: true });
// Copy conversation history
if (existsSync(sourcePath)) {
const conversationContent = readFileSync(sourcePath, 'utf8');
const newConversationPath = join(newSessionPath, 'conversation.jsonl');
writeFileSync(newConversationPath, conversationContent);
// Add new query as next message
const queryMessage = {
type: 'user',
message: { content: newQuery },
timestamp: Date.now()
};
appendFileSync(newConversationPath, '\n' + JSON.stringify(queryMessage));
}
return newSessionId;
}
```
## Usage Examples
### **Basic Messaging Workflow**
```bash
# 1. Check who's available for collaboration
claude-senator status
# Output:
āā šļø āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā 3 Claudes active ⢠rich context network
ā š¢ Claude 98471 ⢠rust-project ⢠debugging memory leak ⢠main@a1b2c3
āā š Live status ⢠Smart pointer network active
# 2. Send context to specific Claude
claude-senator send_context --target_pid 98471 --context_request "Need help with async Rust debugging"
# Output:
āā šļø āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā ā Claude 98471 ⢠"Need help with async Rust debugging" ⢠~/.claude pointers sent
ā š Context shared ⢠Ready for collaboration
āā š Context transmitted ⢠Collaboration network active
# 3. Receive context from other Claudes
claude-senator receive_context
# Output:
āā šļø āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā "Debug memory leak in tokio runtime" ⢠debugging_assistance ⢠rust-project
ā š Rich context: git state, active files, current task
āā šØ 1 context processed ⢠Ready for collaboration
```
### **Context Forking Workflow**
```bash
# Scenario: Claude deep in documentation work, want to ask questions
claude-senator status
# Output shows Claude 98471 working on documentation (318s, 9.3k tokens)
āā šļø āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā 1 Claude active ⢠rich context network
ā š” Claude 98471 ⢠docs-project ⢠Writing API documentation ⢠main@x1y2z3
āā š Live status ⢠Smart pointer network active
# Fork context without interrupting
claude-senator fork_claude --source_pid 98471 --query "What's the current API documentation structure?"
# Output:
āā š Context Forked āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā šø Copied: Writing API documentation ⢠9.3k tokens ⢠Full conversation
ā š New session: fork_20250716_141509
ā šÆ Ready for: "What's the current API documentation structure?"
āā ⨠Run: claude --session fork_20250716_141509 to start new Claude
# Start new Claude with inherited context
claude --session fork_20250716_141509
# New Claude starts with full context + your question already asked
```
## Architecture Benefits
### **Zero Dependencies**
- No npm packages beyond @modelcontextprotocol/sdk
- No external services (Redis, databases, etc.)
- No system dependencies
- No elevated permissions
### **Token Efficiency**
- Smart pointers prevent data duplication
- Context reconstruction on-demand
- Minimal memory footprint
- Efficient git state tracking
### **Scalability**
- **2-20 Claudes**: Excellent performance (<10ms operations)
- **20-100 Claudes**: Good performance, minimal filesystem overhead
- **100+ Claudes**: May benefit from SQLite upgrade (see Future section)
### **Reliability**
- Each Claude owns its files (no shared writes)
- Automatic cleanup of dead instances
- Graceful error handling
- Self-healing directory structure
## UI Design Philosophy
### **3-Line ASCII Format**
```bash
āā šļø āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā [CONTENT LINE - exactly fits terminal width]
ā [STATUS LINE - shows current state and metrics]
āā [FOOTER LINE - shows next action or network status]
```
### **Truncation Rules**
- Content truncated to fit terminal width
- Important information prioritized
- Emoji indicators for quick scanning
- Consistent spacing and alignment
### **Tool-Specific Emoji**
- šļø Always at top (Claude Senator identity)
- š Context sharing operations
- šØ Message receiving
- š Context forking
- š Network activity
## File Structure
### **Core Files**
```
src/
āāā index.ts # MCP server and tool handlers
āāā session.ts # SessionManager - core messaging logic
āāā memory.ts # MemoryManager - conversation search
āāā injection.ts # CommandInjector - input manipulation
āāā types.ts # TypeScript interfaces
```
### **Key Classes**
#### **SessionManager** (src/session.ts)
- **Purpose**: Core messaging and context management
- **Key methods**: `createMessage`, `reconstructRichContext`, `generateRichContextDisplay`
- **Handles**: Smart pointers, context reconstruction, collaboration scoring
#### **MemoryManager** (src/memory.ts)
- **Purpose**: Conversation history search and analysis
- **Key methods**: TBD (future implementation)
- **Handles**: Historical context retrieval, memory patterns
#### **CommandInjector** (src/injection.ts)
- **Purpose**: Input manipulation and command routing
- **Key methods**: TBD (future implementation)
- **Handles**: Inter-Claude command injection, workflow automation
## Future Enhancements
### **Messaging System Extensions**
```typescript
// Planned tools
{
name: 'broadcast_context',
description: 'Send context to all active Claude instances'
}
{
name: 'handoff_context',
description: 'Transfer work to another Claude with full context'
}
{
name: 'sync_context',
description: 'Synchronize context across multiple Claude instances'
}
```
### **Context Forking Improvements**
```typescript
// Selective inheritance
{
name: 'fork_claude_selective',
inputSchema: {
source_pid: number,
query: string,
include_conversation: boolean,
include_files: boolean,
include_git_state: boolean
}
}
// Context merging
{
name: 'merge_context',
description: 'Merge insights from forked Claude back to parent'
}
```
### **Performance Optimizations**
- **Context Caching**: LRU cache for frequently accessed contexts
- **Compression**: Gzip compression for large conversation histories
- **Streaming**: Real-time context updates as work progresses
- **SQLite Upgrade**: For 100+ concurrent Claude instances
### **Integration Possibilities**
- **IDE Plugins**: VS Code, Cursor, Windsurf integration
- **CI/CD**: Automated context sharing in build pipelines
- **Monitoring**: Real-time collaboration network visualization
- **Analytics**: Context sharing patterns and optimization
## Project Split Guide
If splitting into separate projects:
### **Core Messaging** (claude-senator-messaging)
- **Files**: `src/session.ts` (lines 1-883, 1075-1451), `src/types.ts`
- **Dependencies**: `src/memory.ts` for conversation search
- **Features**: `send_context`, `receive_context`, `status`
- **Size**: ~1400 lines, full messaging system
### **Context Forking** (claude-senator-forking)
- **Files**: New implementation in `src/forking.ts`
- **Dependencies**: `src/session.ts` (conversation finding methods)
- **Features**: `fork_claude` tool
- **Size**: ~50 lines, minimal implementation
### **Shared Infrastructure** (claude-senator-core)
- **Files**: `src/types.ts`, directory management utilities
- **Purpose**: Common interfaces and utilities
- **Size**: ~200 lines, essential types and helpers
### **Migration Strategy**
1. **Extract core types**: Move interfaces to shared package
2. **Split session manager**: Separate messaging and forking logic
3. **Maintain compatibility**: Ensure both systems can coexist
4. **Document interfaces**: Clear APIs for integration
## Development
```bash
git clone https://github.com/yourusername/claude-senator
cd claude-senator
npm install
npm run build
npm test
```
### **Contributing**
- Fork the repository and create feature branches
- Test with multiple Claude instances before submitting PRs
- Follow TypeScript strict mode and MCP protocol standards
- Document any new smart pointer patterns
### **Testing**
- Test messaging between 2-5 Claude instances
- Verify context reconstruction accuracy
- Test forking with large conversation histories
- Validate ASCII UI formatting across terminals
## License
[MIT](LICENSE)
---
_Claude Senator enables unprecedented collaboration between Claude instances through smart context sharing and non-disruptive forking. Built for developers who need their AI assistants to work together as seamlessly as they do._