rb-claude-tmux 0.1.0
Claude Code CLI wrapper with tmux session management, subprocess execution, and OAuth token handling
Requires Python: >=3.10
Keywords: ai, anthropic, claude, cli, tmux

# claude-tmux

Python wrapper for Claude Code CLI with tmux session management, subprocess execution, and OAuth token handling.

## Features

- **Subprocess Execution**: Run Claude Code CLI in `--print` mode for programmatic access
- **Tmux Visibility**: Optionally run commands in tmux sessions for visibility and debugging
- **Conversation Continuity**: Automatic session management with `--continue` flag
- **OAuth Token Management**: Automatic detection and refresh of expired tokens
- **Multi-Agent Support**: Manage multiple independent Claude agents
- **Activity Timeouts**: Smart handling of long-running tasks with status checks
- **Stream JSON Parsing**: Extract responses from Claude's stream-json output format

## Installation

```bash
# Install from PyPI
pip install claude-tmux

# Or for development (from source)
pip install -e .
```

## Quick Start

```python
from claude_tmux import TmuxClaudeClient

# Create a client
client = TmuxClaudeClient(
    session_name="my-project",
    working_dir="/path/to/project",
    system_prompt_text="You are a helpful coding assistant.",
)

# Send a message
response = client.chat("Hello! What files are in this directory?")
print(response)

# Continue the conversation (uses same session)
response = client.chat("What does the main.py file do?")
print(response)
```

## Usage

### Basic Chat

```python
from claude_tmux import TmuxClaudeClient

client = TmuxClaudeClient(working_dir="/my/project")

# Simple chat
response = client.chat("Explain this codebase")

# Chat with context
response = client.chat(
    "Fix this bug",
    context="Error log: Connection refused on port 8080"
)

# Separate conversation threads
response = client.chat("Question 1", conversation_key="thread-a")
response = client.chat("Question 2", conversation_key="thread-b")
```

### With Tmux Visibility

```python
# Enable tmux for visibility during long operations
client = TmuxClaudeClient(
    session_name="debug-session",
    working_dir="/project",
    use_tmux=True,  # Commands run in tmux session
)

# You can attach to the tmux session to watch:
# tmux attach -t debug-session-run
```

### Custom System Prompt

```python
# From text
client = TmuxClaudeClient(
    system_prompt_text="You are a security auditor. Review code for vulnerabilities."
)

# From file
client = TmuxClaudeClient(
    system_prompt_file="/path/to/prompt.txt"
)
```

### MCP Server Configuration

```python
# Pass MCP config for custom tools
client = TmuxClaudeClient(
    mcp_config="/path/to/mcp-config.json"
)

# Or as a dict
client = TmuxClaudeClient(
    mcp_config={
        "mcpServers": {
            "custom-tools": {
                "command": "node",
                "args": ["/path/to/server.js"]
            }
        }
    }
)
```

### Session Management

```python
# List available sessions
sessions = client.list_sessions(limit=10)
for s in sessions:
    print(f"{s['id']}: {s['first_input'][:50]}...")

# Resume a specific session
client.select_session("abc123-session-id")
response = client.chat("Continue where we left off")

# Clear history (starts fresh)
client.clear_history()
```

### Process Control

```python
# Check if Claude is processing
if client.is_busy():
    status = client.get_status()
    print(f"Running for {status['duration']:.1f}s")

# Get last activity
chunk = client.get_last_chunk()
if chunk:
    print(f"Last activity: {chunk}")

# Interrupt a long-running operation
if client.is_busy():
    client.interrupt()
```

## Multi-Agent Management

```python
from claude_tmux import TmuxAgentManager

manager = TmuxAgentManager(base_session_name="project")

# Spawn specialized agents
review_agent = manager.spawn_agent(
    "reviewer",
    working_dir="/repo",
    system_prompt_text="You review pull requests."
)

docs_agent = manager.spawn_agent(
    "documenter",
    working_dir="/repo/docs",
    system_prompt_text="You write documentation."
)

# Use agents
review = review_agent.chat("Review the latest changes")
docs_agent.chat("Update the API docs")

# List active agents
print(manager.list_agents())  # ["reviewer", "documenter"]

# Get status of all agents
status = manager.get_all_status()

# Stop specific agent
manager.stop_agent("reviewer")

# Stop all agents
manager.stop_all()
```

## OAuth Token Management

```python
from claude_tmux import OAuthTokenManager, check_and_refresh_token

# Quick check and refresh
if check_and_refresh_token():
    print("Token is valid")

# More control
manager = OAuthTokenManager()

# Check expiry
if manager.is_token_expired():
    print("Token needs refresh")
    manager.refresh_token()

# Get expiry time
expiry = manager.get_expiry_time()
print(f"Token expires at: {expiry}")

# Ensure valid token (refresh if needed)
manager.ensure_valid_token()
```

## Configuration

### Environment Variables

The client respects these environment variables:

- `HOME`: Home directory for Claude credentials (~/.claude/)

### Timeout Settings

- **Status check interval**: 60 seconds of no output triggers a status prompt
- **Maximum runtime**: 30 minutes absolute limit
- **Maximum status checks**: 10 prompts before giving up

## API Reference

### TmuxClaudeClient

| Method | Description |
|--------|-------------|
| `chat(message, context, conversation_key)` | Send message and get response |
| `list_sessions(limit)` | List available Claude sessions |
| `select_session(session_id)` | Resume a specific session |
| `get_current_session()` | Get currently selected session |
| `clear_history(conversation_key)` | Clear conversation history |
| `is_busy()` | Check if processing |
| `get_status()` | Get processing status |
| `get_last_chunk(max_length)` | Get last output chunk |
| `interrupt()` | Interrupt current operation |

### TmuxAgentManager

| Method | Description |
|--------|-------------|
| `spawn_agent(agent_id, working_dir, ...)` | Create new agent |
| `get_agent(agent_id)` | Get existing agent |
| `stop_agent(agent_id)` | Stop and remove agent |
| `list_agents()` | List all agent IDs |
| `stop_all()` | Stop all agents |
| `get_agent_status(agent_id)` | Get agent status |
| `get_all_status()` | Get all agents' status |

### OAuthTokenManager

| Method | Description |
|--------|-------------|
| `is_token_expired(buffer_seconds)` | Check if token needs refresh |
| `get_expiry_time()` | Get token expiry timestamp |
| `refresh_token()` | Refresh the OAuth token |
| `ensure_valid_token()` | Check and refresh if needed |

## Requirements

- Python 3.10+
- **Linux or macOS** (uses Unix-specific APIs)
- Claude Code CLI installed and configured
- httpx (for OAuth token refresh)
- tmux (optional, for visibility mode)

## License

MIT