# Claif - Command Line Artificial Intelligence Framework
## Quickstart
```bash
# Install with all providers and query Claude
pip install claif[all]
claif query "Explain quantum computing in one sentence"
# Or install specific providers
pip install claif claif_cla # Just Claude
pip install claif claif_gem # Just Gemini
pip install claif claif_cod # Just Codex/OpenAI
# Stream responses in real-time
claif stream "Tell me a story" --provider gemini
# Query all providers in parallel
claif parallel "What is the meaning of life?" --compare
```
## What is Claif?
Claif is a unified Python framework for interacting with multiple AI language model providers through a consistent interface. It lets you seamlessly switch between Claude (Anthropic), Gemini (Google), and Codex (OpenAI) without changing your code.
**Key Features:**
- **Single API** for all AI providers - write once, use any model
- **Plugin-based architecture** - providers are discovered dynamically
- **Rich CLI** with Fire framework and beautiful terminal output
- **Full async support** for concurrent operations
- **Type-safe** with comprehensive hints throughout
- **MCP server** for tool integration
- **Auto-install** - missing provider CLIs are installed on first use
## Installation
### Basic Installation
```bash
# Core framework only
pip install claif
# With all providers (recommended)
pip install claif[all]
```
### Installing Specific Providers
```bash
# Claude provider (wraps Claude Code SDK)
pip install claif claif_cla
# Gemini provider (wraps Gemini CLI)
pip install claif claif_gem
# Codex provider (wraps OpenAI Codex CLI)
pip install claif claif_cod
```
### Installing Provider CLIs
Claif can auto-install missing CLIs, or you can install them manually:
```bash
# Auto-install all CLIs
claif install
# Or install specific CLIs
claif install claude
claif install gemini
claif install codex
# Install via npm (if preferred)
npm install -g @anthropic-ai/claude-code
npm install -g @google/gemini-cli
npm install -g @openai/codex
```
### Development Installation
```bash
git clone https://github.com/twardoch/claif.git
cd claif
pip install -e ".[dev,test]"
```
## CLI Usage
Claif provides a comprehensive command-line interface built with Fire that shows clean, focused output by default. Use `--verbose` for detailed logging.
### Basic Commands
```bash
# Query default provider (Claude)
claif query "What is Python?"
# Query specific provider
claif query "Explain recursion" --provider gemini
# Query with options
claif query "Write a haiku about coding" --temperature 0.7 --max-tokens 50
# Stream responses in real-time with live display
claif stream "Tell me a story" --provider claude
# Query a random provider
claif random "Tell me a programming joke"
# Query all providers in parallel
claif parallel "What is AI?" --compare # Side-by-side comparison
```
### Provider Management
```bash
# List providers with their status
claif providers list
# Check health of all providers
claif providers status
# Install provider CLIs
claif install # All providers
claif install claude # Specific provider
# Check installation status
claif status
```
### Configuration
```bash
# Show current configuration
claif config show
# Set configuration values
claif config set default_provider=gemini
claif config set cache_enabled=true
claif config set output_format=markdown
# Save configuration to file
claif config save
```
### MCP Server
```bash
# Start the MCP (Model Context Protocol) server
claif server --host localhost --port 8000 --reload
# The server provides tools:
# - claif_query: Query specific provider
# - claif_query_random: Query random provider
# - claif_query_all: Query all providers
# - claif_list_providers: List available providers
# - claif_health_check: Check provider health
```
## Python API Usage
### Basic Usage
```python
import asyncio
from claif import query, ClaifOptions, Provider
async def main():
# Simple query using default provider
async for message in query("Hello, world!"):
print(message.content)
# Query specific provider
options = ClaifOptions(provider=Provider.GEMINI)
async for message in query("Explain Python decorators", options):
print(f"[{message.role}]: {message.content}")
asyncio.run(main())
```
### Advanced Options
```python
from claif import query, ClaifOptions, Provider
options = ClaifOptions(
provider=Provider.CLAUDE,
model="claude-3-opus-20240229",
temperature=0.7,
max_tokens=1000,
system_prompt="You are an expert Python developer",
timeout=60,
cache=True,
verbose=False # Clean output by default
)
async def get_code_review():
async for message in query("Review this code: def fib(n): return fib(n-1) + fib(n-2)", options):
print(message.content)
asyncio.run(get_code_review())
```
### Parallel Queries
```python
from claif import query_all, query_random
# Query all providers in parallel
async def compare_providers():
async for results in query_all("What is machine learning?"):
for provider, messages in results.items():
print(f"\n{provider.value.upper()}:")
for msg in messages:
print(msg.content)
# Query random provider
async def get_random_response():
async for message in query_random("Tell me a programming joke"):
print(message.content)
asyncio.run(compare_providers())
```
### Using the Client Class
```python
from claif.client import ClaifClient
from claif import ClaifOptions, Provider
# Create client instance
client = ClaifClient()
# List available providers
providers = client.list_providers()
print(f"Available: {[p.value for p in providers]}")
# Query with auto-install
# If Claude CLI is missing, it will be installed automatically
options = ClaifOptions(provider=Provider.CLAUDE)
async def query_with_client():
async for message in client.query("Explain asyncio", options):
print(message.content)
asyncio.run(query_with_client())
```
## How It Works
### Architecture Overview
Claif uses a layered architecture that separates concerns and enables provider independence:
```
┌─────────────────────────────┐
│ User Application │
├─────────────────────────────┤
│ Claif CLI │ ← Fire-based CLI with rich output
├─────────────────────────────┤
│ Claif Client │ ← Async client with provider routing
├─────────────────────────────┤
│ Common Types/Utils │ ← Shared data structures and utilities
├─────────────────────────────┤
│ Provider Wrappers │ ← Simple adapters for provider packages
├─────┬─────┬─────┬──────────┤
│claif_cla│claif_gem│claif_cod│ ← Actual provider implementations
└─────┴─────┴─────┴──────────┘
```
### Core Components
#### Common Module (`src/claif/common/`)
**types.py** - Core data structures:
```python
class Message:
role: MessageRole # USER, ASSISTANT, SYSTEM
content: str | list[TextBlock | ToolUseBlock | ToolResultBlock]
class Provider(Enum):
CLAUDE = "claude"
GEMINI = "gemini"
CODEX = "codex"
class ClaifOptions:
provider: Provider | None
model: str | None
temperature: float | None
max_tokens: int | None
system_prompt: str | None
timeout: int | None
cache: bool = True
verbose: bool = False
```
**config.py** - Hierarchical configuration:
- Default values → Config files → Environment vars → CLI args
- Locations: `~/.claif/config.json`, `~/.config/claif/config.json`, `./claif.json`
- Provider-specific settings with API key management
**errors.py** - Exception hierarchy:
- `ClaifError` → Base exception
- `ProviderError` → Provider-specific failures
- `ConfigurationError` → Configuration issues
- `TransportError` → Communication errors
- `TimeoutError` → Operation timeouts
**install.py** - Auto-installation support:
```python
def install_provider(provider, package, exec_name):
# 1. Install npm package using bun
# 2. Bundle executable
# 3. Install to ~/.local/bin
```
#### Providers Module (`src/claif/providers/`)
Simple wrapper classes that delegate to provider packages:
```python
# claude.py
from claif_cla import query as claude_query
class ClaudeProvider:
async def query(self, prompt: str, options: ClaifOptions) -> AsyncIterator[Message]:
logger.debug(f"Querying Claude with prompt: {prompt[:50]}...")
async for message in claude_query(prompt, options):
yield message
```
Each provider:
- Imports the actual provider package (`claif_cla`, `claif_gem`, `claif_cod`)
- Implements the same `query` interface
- Handles provider-specific option conversion
#### Client Module (`src/claif/client.py`)
The main client with auto-install support:
```python
class ClaifClient:
def __init__(self):
self.providers = {
Provider.CLAUDE: ClaudeProvider(),
Provider.GEMINI: GeminiProvider(),
Provider.CODEX: CodexProvider(),
}
async def query(self, prompt: str, options: ClaifOptions) -> AsyncIterator[Message]:
try:
# Route to provider
async for message in provider.query(prompt, options):
yield message
except Exception as e:
if _is_cli_missing_error(e):
# Auto-install missing CLI
install_result = install_func()
if install_result.get("installed"):
# Retry query
async for message in provider.query(prompt, options):
yield message
```
Key features:
- Routes queries to appropriate providers
- Auto-installs missing provider CLIs
- Implements `query`, `query_random`, and `query_all`
- Handles errors with graceful fallbacks
#### CLI Module (`src/claif/cli.py`)
Fire-based CLI with rich terminal output:
```python
class ClaifCLI:
def __init__(self, config_file=None, verbose=False):
# Clean output by default
logger.remove()
if verbose:
logger.add(sys.stderr, level="DEBUG")
else:
# Only errors go to stderr in non-verbose mode
logger.add(sys.stderr, level="ERROR")
```
Main commands:
- `query` - Execute queries with options
- `stream` - Live streaming with rich.Live display
- `random` - Query random provider
- `parallel` - Query all providers (with `--compare` for side-by-side)
- `session` - Start provider-specific interactive session
- `install` - Install provider CLIs with bun bundling
- `config` - Manage settings
- `server` - Start MCP server
#### Server Module (`src/claif/server.py`)
FastMCP server implementation:
```python
server = FastMCP("Claif MCP Server")
@server.tool()
async def claif_query(prompt: str, provider: str = None) -> list[dict]:
"""Query specific AI provider."""
options = ClaifOptions(provider=Provider(provider) if provider else None)
messages = []
async for message in query(prompt, options):
messages.append(message.to_dict())
return messages
# Additional tools:
# - claif_query_random: Random provider selection
# - claif_query_all: Parallel queries
# - claif_list_providers: Available providers
# - claif_health_check: Provider status
```
#### Install Module (`src/claif/install.py`)
Handles CLI installation and bundling:
```python
def install_claude() -> dict:
"""Install Claude Code CLI."""
return install_provider(
provider="claude",
package="@anthropic-ai/claude-code",
exec_name="claude"
)
# Installation process:
# 1. Install npm package globally using bun
# 2. Bundle with bun compile for fast startup
# 3. Copy to ~/.local/bin
# 4. Handle platform-specific paths
```
Key features:
- Uses bun for fast npm installs
- Creates bundled executables
- Platform-aware installation paths
- Automatic PATH checking
### Configuration System
Hierarchical configuration loading:
1. **Default values** in `Config` dataclass
2. **Config files** (first found wins):
- `~/.claif/config.json`
- `~/.config/claif/config.json`
- `./claif.json`
3. **Environment variables**:
- `CLAIF_DEFAULT_PROVIDER`
- `CLAIF_VERBOSE`
- `CLAIF_CACHE_ENABLED`
- `CLAIF_SESSION_DIR`
4. **CLI arguments** (highest priority)
Example configuration:
```json
{
"default_provider": "claude",
"providers": {
"claude": {
"enabled": true,
"model": "claude-3-opus-20240229",
"api_key_env": "ANTHROPIC_API_KEY"
},
"gemini": {
"enabled": true,
"model": "gemini-2.5-pro",
"api_key_env": "GEMINI_API_KEY"
},
"codex": {
"enabled": true,
"model": "o4-mini"
}
},
"cache_enabled": true,
"cache_ttl": 3600,
"output_format": "text"
}
```
### Plugin System
Python's entry points for dynamic provider discovery:
```python
# In src/__init__.py
class PluginFinder:
"""Enables imports like: from claif import claude"""
def find_spec(cls, fullname, path, target=None):
if fullname.startswith("claif."):
# Look up via entry points
eps = metadata.entry_points(group="claif.plugins")
for ep in eps:
if ep.name == plugin_name:
return ModuleSpec(fullname, Loader())
```
Provider packages register themselves:
```toml
# In provider's pyproject.toml
[project.entry-points."claif.plugins"]
claude = "claif_cla"
gemini = "claif_gem"
codex = "claif_cod"
```
### Message Flow
1. **User Input** → CLI command or API call
2. **Options Parsing** → Create `ClaifOptions` with configuration
3. **Provider Selection** → Choose provider based on options
4. **Query Routing** → Client routes to appropriate provider wrapper
5. **CLI Check** → Auto-install if CLI missing
6. **Provider Execution** → Provider package handles actual call
7. **Response Streaming** → Yield `Message` objects as they arrive
8. **Output Formatting** → Display with rich or return structured data
### Code Structure
```
claif/
├── src/
│ ├── __init__.py # Plugin system initialization
│ └── claif/
│ ├── __init__.py # Public API exports
│ ├── common/ # Shared components
│ │ ├── __init__.py
│ │ ├── types.py # Core data structures
│ │ ├── config.py # Configuration management
│ │ ├── errors.py # Exception hierarchy
│ │ ├── install.py # CLI installation utilities
│ │ └── utils.py # Formatting and helpers
│ ├── providers/ # Provider wrappers
│ │ ├── __init__.py
│ │ ├── claude.py # Claude wrapper
│ │ ├── gemini.py # Gemini wrapper
│ │ └── codex.py # Codex wrapper
│ ├── client.py # Main client implementation
│ ├── cli.py # Fire CLI interface
│ ├── server.py # FastMCP server
│ └── install.py # Provider CLI installation
├── tests/ # Test suite
├── pyproject.toml # Package configuration
└── README.md # This file
```
### Key Implementation Details
**Async Everywhere**: All I/O operations use async/await for efficiency
**Message Types**: Flexible content that can be string or structured blocks:
```python
class Message:
role: MessageRole
content: str | list[TextBlock | ToolUseBlock | ToolResultBlock]
```
**Provider Adapters**: Thin wrappers that maintain provider-specific features:
```python
# Each provider wrapper is ~20 lines
# Imports provider package
# Converts options if needed
# Yields messages unchanged
```
**Auto-Install Logic**: Missing CLIs trigger automatic installation:
```python
if _is_cli_missing_error(e):
install_func = _get_provider_install_function(provider)
if install_func():
# Retry query with fresh provider instance
```
**Clean Output**: Logging configured to minimize noise:
```python
# Verbose OFF: Only errors to stderr
# Verbose ON: Full debug logging
# AI responses always go to stdout
```
## Installation Details: Bun and Node
Claif uses a hybrid approach for installing provider CLIs:
### Why Bun?
[Bun](https://bun.sh) is used for:
1. **Fast npm installs** - 10x faster than npm
2. **Binary bundling** - Creates standalone executables
3. **Cross-platform** - Works on Windows, macOS, Linux
4. **Minimal dependencies** - Single binary, no Node.js required
### Installation Process
```bash
# 1. Bun installs the npm package globally
bun add -g @anthropic-ai/claude-code
# 2. Bundle script creates optimized binary
bun build claude-wrapper.ts --compile --outfile dist/claude
# 3. Binary is copied to ~/.local/bin
cp dist/claude ~/.local/bin/
```
### Manual Installation Options
If you prefer Node.js:
```bash
# Using npm
npm install -g @anthropic-ai/claude-code
npm install -g @google/gemini-cli
npm install -g @openai/codex
# Using yarn
yarn global add @anthropic-ai/claude-code
# Using pnpm
pnpm add -g @anthropic-ai/claude-code
```
### Bundle Benefits
1. **Faster startup** - No Node.js initialization
2. **Smaller size** - Single file vs node_modules
3. **No conflicts** - Isolated from system Node.js
4. **Portable** - Copy binary anywhere
### Troubleshooting
```bash
# Check if CLIs are found
claif status
# Manually set CLI paths
export CLAUDE_CLI_PATH=/usr/local/bin/claude
export GEMINI_CLI_PATH=/usr/local/bin/gemini
export CODEX_CLI_PATH=/usr/local/bin/codex
# Skip auto-install and use existing CLIs
claif config set auto_install=false
```
## Why Use Claif?
### 1. **Provider Independence**
- Write once, use any AI model
- Switch providers with a single parameter
- Compare responses side-by-side
- No vendor lock-in
### 2. **Zero Friction**
- Auto-installs missing CLIs on first use
- Clean output - only show what matters
- Smart defaults that just work
- Async for speed
### 3. **Developer Experience**
- Full type hints and IDE support
- Rich CLI with progress indicators
- Comprehensive error messages
- Fast MCP server for tool integration
### 4. **Production Ready**
- Battle-tested error handling
- Timeout protection
- Response caching (coming soon)
- Configurable everything
### 5. **Extensible**
- Plugin architecture for new providers
- Clean API for custom integrations
- Well-documented codebase
- Active development
## Contributing
Based on the development guide in [CLAUDE.md](CLAUDE.md):
### Development Setup
```bash
# Clone the repository
git clone https://github.com/twardoch/claif.git
cd claif
# Install with dev dependencies
pip install -e ".[dev,test]"
# Install pre-commit hooks
pre-commit install
```
### Running Tests
```bash
# Run all tests
pytest
# Run with coverage
pytest --cov=src/claif --cov-report=html
# Run specific test
pytest tests/test_client.py -v
# Run integration tests (requires provider packages)
pytest tests/integration/ -v
```
### Code Quality
```bash
# Format code
ruff format src tests
# Lint code
ruff check src tests --fix
# Type checking
mypy src/claif
# Run all checks (as per CLAUDE.md)
fd -e py -x ruff format {}
fd -e py -x ruff check --fix --unsafe-fixes {}
python -m pytest
```
### Making Changes
1. **Check existing utilities** in `claif.common` before implementing
2. **Maintain API compatibility** - this is a plugin framework
3. **Add tests** for new functionality
4. **Update documentation** in docstrings and README
5. **Follow style** - 120 char lines, descriptive names
### Release Process
```bash
# Update version (uses hatch-vcs)
git tag v1.0.7
# Build distribution
python -m build
# Upload to PyPI
twine upload dist/*
```
## License
MIT License - see [LICENSE](LICENSE) file for details.
Copyright (c) 2025 Adam Twardoch
## Links
### Claif Ecosystem
**Core Framework:**
- [GitHub: twardoch/claif](https://github.com/twardoch/claif) - This repository
- [PyPI: claif](https://pypi.org/project/claif/) - Core package
- [Documentation](https://github.com/twardoch/claif#readme) - Full docs
- [Issues](https://github.com/twardoch/claif/issues) - Bug reports & features
**Provider Packages:**
- [claif_cla](https://github.com/twardoch/claif_cla/) - Claude provider (wraps claude-code-sdk)
- [claif_gem](https://github.com/twardoch/claif_gem/) - Gemini provider (wraps Gemini CLI)
- [claif_cod](https://github.com/twardoch/claif_cod/) - Codex provider (wraps OpenAI Codex CLI)
### Upstream Projects
**Provider CLIs:**
- [Claude Code](https://github.com/anthropics/claude-code) - Anthropic's official CLI
- [claude-code-sdk](https://github.com/anthropics/claude-code-sdk-python) - Python SDK for Claude
- [Gemini CLI](https://github.com/google-gemini/gemini-cli/) - Google's Gemini CLI
- [OpenAI Codex CLI](https://github.com/openai/codex) - OpenAI's code generation CLI
**Related Tools:**
- [Fire](https://github.com/google/python-fire) - Python CLI framework
- [Rich](https://github.com/Textualize/rich) - Terminal formatting
- [FastMCP](https://github.com/fixie-ai/fastmcp) - MCP server framework
- [Bun](https://bun.sh) - Fast JavaScript runtime used for bundling
### Resources
**Documentation:**
- [Anthropic Docs](https://docs.anthropic.com/) - Claude documentation
- [Google AI Studio](https://ai.google.dev/) - Gemini documentation
- [OpenAI Platform](https://platform.openai.com/) - OpenAI documentation
**Community:**
- [Discussions](https://github.com/twardoch/claif/discussions) - Q&A and ideas
- [Twitter: @adamtwar](https://twitter.com/adamtwar) - Author updates
**Articles & Tutorials:**
- [Building a Unified AI CLI](https://example.com) - Design decisions
- [Plugin Architecture in Python](https://example.com) - Technical deep dive
- [Async Patterns for AI APIs](https://example.com) - Performance guide
Raw data
{
"_id": null,
"home_page": null,
"name": "claif",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": "ai, artificial-intelligence, claif, claude, cli, codex, command-line, gemini, llm, lm-studio, openai, responses-api",
"author": null,
"author_email": "Adam Twardoch <adam+github@twardoch.com>",
"download_url": "https://files.pythonhosted.org/packages/66/eb/602e049cdf1dcd821dc639ad2c0d942b7d8f8ce669652bdadca0d953bded/claif-1.0.32.tar.gz",
"platform": null,
"description": "# Claif - Command Line Artificial Intelligence Framework\n\n## Quickstart\n\n```bash\n# Install with all providers and query Claude\npip install claif[all]\nclaif query \"Explain quantum computing in one sentence\"\n\n# Or install specific providers\npip install claif claif_cla # Just Claude\npip install claif claif_gem # Just Gemini \npip install claif claif_cod # Just Codex/OpenAI\n\n# Stream responses in real-time\nclaif stream \"Tell me a story\" --provider gemini\n\n# Query all providers in parallel\nclaif parallel \"What is the meaning of life?\" --compare\n```\n\n## What is Claif?\n\nClaif is a unified Python framework for interacting with multiple AI language model providers through a consistent interface. It lets you seamlessly switch between Claude (Anthropic), Gemini (Google), and Codex (OpenAI) without changing your code.\n\n**Key Features:**\n- **Single API** for all AI providers - write once, use any model\n- **Plugin-based architecture** - providers are discovered dynamically \n- **Rich CLI** with Fire framework and beautiful terminal output\n- **Full async support** for concurrent operations\n- **Type-safe** with comprehensive hints throughout\n- **MCP server** for tool integration\n- **Auto-install** - missing provider CLIs are installed on first use\n\n## Installation\n\n### Basic Installation\n\n```bash\n# Core framework only\npip install claif\n\n# With all providers (recommended)\npip install claif[all]\n```\n\n### Installing Specific Providers\n\n```bash\n# Claude provider (wraps Claude Code SDK)\npip install claif claif_cla\n\n# Gemini provider (wraps Gemini CLI) \npip install claif claif_gem\n\n# Codex provider (wraps OpenAI Codex CLI)\npip install claif claif_cod\n```\n\n### Installing Provider CLIs\n\nClaif can auto-install missing CLIs, or you can install them manually:\n\n```bash\n# Auto-install all CLIs\nclaif install\n\n# Or install specific CLIs\nclaif install claude\nclaif install gemini\nclaif install codex\n\n# Install via npm (if preferred)\nnpm install -g @anthropic-ai/claude-code\nnpm install -g @google/gemini-cli\nnpm install -g @openai/codex\n```\n\n### Development Installation\n\n```bash\ngit clone https://github.com/twardoch/claif.git\ncd claif\npip install -e \".[dev,test]\"\n```\n\n## CLI Usage\n\nClaif provides a comprehensive command-line interface built with Fire that shows clean, focused output by default. Use `--verbose` for detailed logging.\n\n### Basic Commands\n\n```bash\n# Query default provider (Claude)\nclaif query \"What is Python?\"\n\n# Query specific provider\nclaif query \"Explain recursion\" --provider gemini\n\n# Query with options\nclaif query \"Write a haiku about coding\" --temperature 0.7 --max-tokens 50\n\n# Stream responses in real-time with live display\nclaif stream \"Tell me a story\" --provider claude\n\n# Query a random provider\nclaif random \"Tell me a programming joke\"\n\n# Query all providers in parallel\nclaif parallel \"What is AI?\" --compare # Side-by-side comparison\n```\n\n### Provider Management\n\n```bash\n# List providers with their status\nclaif providers list\n\n# Check health of all providers\nclaif providers status\n\n# Install provider CLIs\nclaif install # All providers\nclaif install claude # Specific provider\n\n# Check installation status\nclaif status\n```\n\n### Configuration\n\n```bash\n# Show current configuration\nclaif config show\n\n# Set configuration values\nclaif config set default_provider=gemini\nclaif config set cache_enabled=true\nclaif config set output_format=markdown\n\n# Save configuration to file\nclaif config save\n```\n\n### MCP Server\n\n```bash\n# Start the MCP (Model Context Protocol) server\nclaif server --host localhost --port 8000 --reload\n\n# The server provides tools:\n# - claif_query: Query specific provider\n# - claif_query_random: Query random provider \n# - claif_query_all: Query all providers\n# - claif_list_providers: List available providers\n# - claif_health_check: Check provider health\n```\n\n## Python API Usage\n\n### Basic Usage\n\n```python\nimport asyncio\nfrom claif import query, ClaifOptions, Provider\n\nasync def main():\n # Simple query using default provider\n async for message in query(\"Hello, world!\"):\n print(message.content)\n \n # Query specific provider \n options = ClaifOptions(provider=Provider.GEMINI)\n async for message in query(\"Explain Python decorators\", options):\n print(f\"[{message.role}]: {message.content}\")\n\nasyncio.run(main())\n```\n\n### Advanced Options\n\n```python\nfrom claif import query, ClaifOptions, Provider\n\noptions = ClaifOptions(\n provider=Provider.CLAUDE,\n model=\"claude-3-opus-20240229\",\n temperature=0.7,\n max_tokens=1000,\n system_prompt=\"You are an expert Python developer\",\n timeout=60,\n cache=True,\n verbose=False # Clean output by default\n)\n\nasync def get_code_review():\n async for message in query(\"Review this code: def fib(n): return fib(n-1) + fib(n-2)\", options):\n print(message.content)\n\nasyncio.run(get_code_review())\n```\n\n### Parallel Queries\n\n```python\nfrom claif import query_all, query_random\n\n# Query all providers in parallel\nasync def compare_providers():\n async for results in query_all(\"What is machine learning?\"):\n for provider, messages in results.items():\n print(f\"\\n{provider.value.upper()}:\")\n for msg in messages:\n print(msg.content)\n\n# Query random provider\nasync def get_random_response():\n async for message in query_random(\"Tell me a programming joke\"):\n print(message.content)\n\nasyncio.run(compare_providers())\n```\n\n### Using the Client Class\n\n```python\nfrom claif.client import ClaifClient\nfrom claif import ClaifOptions, Provider\n\n# Create client instance\nclient = ClaifClient()\n\n# List available providers\nproviders = client.list_providers()\nprint(f\"Available: {[p.value for p in providers]}\")\n\n# Query with auto-install\n# If Claude CLI is missing, it will be installed automatically\noptions = ClaifOptions(provider=Provider.CLAUDE)\n\nasync def query_with_client():\n async for message in client.query(\"Explain asyncio\", options):\n print(message.content)\n\nasyncio.run(query_with_client())\n```\n\n## How It Works\n\n### Architecture Overview\n\nClaif uses a layered architecture that separates concerns and enables provider independence:\n\n```\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 User Application \u2502\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Claif CLI \u2502 \u2190 Fire-based CLI with rich output\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Claif Client \u2502 \u2190 Async client with provider routing\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Common Types/Utils \u2502 \u2190 Shared data structures and utilities\n\u251c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502 Provider Wrappers \u2502 \u2190 Simple adapters for provider packages\n\u251c\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u252c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2524\n\u2502claif_cla\u2502claif_gem\u2502claif_cod\u2502 \u2190 Actual provider implementations\n\u2514\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2534\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n```\n\n### Core Components\n\n#### Common Module (`src/claif/common/`)\n\n**types.py** - Core data structures:\n```python\nclass Message:\n role: MessageRole # USER, ASSISTANT, SYSTEM\n content: str | list[TextBlock | ToolUseBlock | ToolResultBlock]\n\nclass Provider(Enum):\n CLAUDE = \"claude\"\n GEMINI = \"gemini\" \n CODEX = \"codex\"\n\nclass ClaifOptions:\n provider: Provider | None\n model: str | None\n temperature: float | None\n max_tokens: int | None\n system_prompt: str | None\n timeout: int | None\n cache: bool = True\n verbose: bool = False\n```\n\n**config.py** - Hierarchical configuration:\n- Default values \u2192 Config files \u2192 Environment vars \u2192 CLI args\n- Locations: `~/.claif/config.json`, `~/.config/claif/config.json`, `./claif.json`\n- Provider-specific settings with API key management\n\n**errors.py** - Exception hierarchy:\n- `ClaifError` \u2192 Base exception\n- `ProviderError` \u2192 Provider-specific failures\n- `ConfigurationError` \u2192 Configuration issues \n- `TransportError` \u2192 Communication errors\n- `TimeoutError` \u2192 Operation timeouts\n\n**install.py** - Auto-installation support:\n```python\ndef install_provider(provider, package, exec_name):\n # 1. Install npm package using bun\n # 2. Bundle executable\n # 3. Install to ~/.local/bin\n```\n\n#### Providers Module (`src/claif/providers/`)\n\nSimple wrapper classes that delegate to provider packages:\n\n```python\n# claude.py\nfrom claif_cla import query as claude_query\n\nclass ClaudeProvider:\n async def query(self, prompt: str, options: ClaifOptions) -> AsyncIterator[Message]:\n logger.debug(f\"Querying Claude with prompt: {prompt[:50]}...\")\n async for message in claude_query(prompt, options):\n yield message\n```\n\nEach provider:\n- Imports the actual provider package (`claif_cla`, `claif_gem`, `claif_cod`)\n- Implements the same `query` interface\n- Handles provider-specific option conversion\n\n#### Client Module (`src/claif/client.py`)\n\nThe main client with auto-install support:\n\n```python\nclass ClaifClient:\n def __init__(self):\n self.providers = {\n Provider.CLAUDE: ClaudeProvider(),\n Provider.GEMINI: GeminiProvider(),\n Provider.CODEX: CodexProvider(),\n }\n \n async def query(self, prompt: str, options: ClaifOptions) -> AsyncIterator[Message]:\n try:\n # Route to provider\n async for message in provider.query(prompt, options):\n yield message\n except Exception as e:\n if _is_cli_missing_error(e):\n # Auto-install missing CLI\n install_result = install_func()\n if install_result.get(\"installed\"):\n # Retry query\n async for message in provider.query(prompt, options):\n yield message\n```\n\nKey features:\n- Routes queries to appropriate providers\n- Auto-installs missing provider CLIs\n- Implements `query`, `query_random`, and `query_all`\n- Handles errors with graceful fallbacks\n\n#### CLI Module (`src/claif/cli.py`)\n\nFire-based CLI with rich terminal output:\n\n```python\nclass ClaifCLI:\n def __init__(self, config_file=None, verbose=False):\n # Clean output by default\n logger.remove()\n if verbose:\n logger.add(sys.stderr, level=\"DEBUG\")\n else:\n # Only errors go to stderr in non-verbose mode\n logger.add(sys.stderr, level=\"ERROR\")\n```\n\nMain commands:\n- `query` - Execute queries with options\n- `stream` - Live streaming with rich.Live display\n- `random` - Query random provider\n- `parallel` - Query all providers (with `--compare` for side-by-side)\n- `session` - Start provider-specific interactive session\n- `install` - Install provider CLIs with bun bundling\n- `config` - Manage settings\n- `server` - Start MCP server\n\n#### Server Module (`src/claif/server.py`)\n\nFastMCP server implementation:\n\n```python\nserver = FastMCP(\"Claif MCP Server\")\n\n@server.tool()\nasync def claif_query(prompt: str, provider: str = None) -> list[dict]:\n \"\"\"Query specific AI provider.\"\"\"\n options = ClaifOptions(provider=Provider(provider) if provider else None)\n messages = []\n async for message in query(prompt, options):\n messages.append(message.to_dict())\n return messages\n\n# Additional tools:\n# - claif_query_random: Random provider selection\n# - claif_query_all: Parallel queries\n# - claif_list_providers: Available providers\n# - claif_health_check: Provider status\n```\n\n#### Install Module (`src/claif/install.py`)\n\nHandles CLI installation and bundling:\n\n```python\ndef install_claude() -> dict:\n \"\"\"Install Claude Code CLI.\"\"\"\n return install_provider(\n provider=\"claude\",\n package=\"@anthropic-ai/claude-code\", \n exec_name=\"claude\"\n )\n\n# Installation process:\n# 1. Install npm package globally using bun\n# 2. Bundle with bun compile for fast startup\n# 3. Copy to ~/.local/bin\n# 4. Handle platform-specific paths\n```\n\nKey features:\n- Uses bun for fast npm installs\n- Creates bundled executables\n- Platform-aware installation paths\n- Automatic PATH checking\n\n### Configuration System\n\nHierarchical configuration loading:\n\n1. **Default values** in `Config` dataclass\n2. **Config files** (first found wins):\n - `~/.claif/config.json`\n - `~/.config/claif/config.json`\n - `./claif.json`\n3. **Environment variables**: \n - `CLAIF_DEFAULT_PROVIDER`\n - `CLAIF_VERBOSE`\n - `CLAIF_CACHE_ENABLED`\n - `CLAIF_SESSION_DIR`\n4. **CLI arguments** (highest priority)\n\nExample configuration:\n\n```json\n{\n \"default_provider\": \"claude\",\n \"providers\": {\n \"claude\": {\n \"enabled\": true,\n \"model\": \"claude-3-opus-20240229\",\n \"api_key_env\": \"ANTHROPIC_API_KEY\"\n },\n \"gemini\": {\n \"enabled\": true,\n \"model\": \"gemini-2.5-pro\",\n \"api_key_env\": \"GEMINI_API_KEY\"\n },\n \"codex\": {\n \"enabled\": true,\n \"model\": \"o4-mini\"\n }\n },\n \"cache_enabled\": true,\n \"cache_ttl\": 3600,\n \"output_format\": \"text\"\n}\n```\n\n### Plugin System\n\nPython's entry points for dynamic provider discovery:\n\n```python\n# In src/__init__.py\nclass PluginFinder:\n \"\"\"Enables imports like: from claif import claude\"\"\"\n def find_spec(cls, fullname, path, target=None):\n if fullname.startswith(\"claif.\"):\n # Look up via entry points\n eps = metadata.entry_points(group=\"claif.plugins\")\n for ep in eps:\n if ep.name == plugin_name:\n return ModuleSpec(fullname, Loader())\n```\n\nProvider packages register themselves:\n\n```toml\n# In provider's pyproject.toml\n[project.entry-points.\"claif.plugins\"]\nclaude = \"claif_cla\"\ngemini = \"claif_gem\" \ncodex = \"claif_cod\"\n```\n\n### Message Flow\n\n1. **User Input** \u2192 CLI command or API call\n2. **Options Parsing** \u2192 Create `ClaifOptions` with configuration\n3. **Provider Selection** \u2192 Choose provider based on options\n4. **Query Routing** \u2192 Client routes to appropriate provider wrapper\n5. **CLI Check** \u2192 Auto-install if CLI missing\n6. **Provider Execution** \u2192 Provider package handles actual call\n7. **Response Streaming** \u2192 Yield `Message` objects as they arrive\n8. **Output Formatting** \u2192 Display with rich or return structured data\n\n### Code Structure\n\n```\nclaif/\n\u251c\u2500\u2500 src/\n\u2502 \u251c\u2500\u2500 __init__.py # Plugin system initialization\n\u2502 \u2514\u2500\u2500 claif/\n\u2502 \u251c\u2500\u2500 __init__.py # Public API exports\n\u2502 \u251c\u2500\u2500 common/ # Shared components\n\u2502 \u2502 \u251c\u2500\u2500 __init__.py \n\u2502 \u2502 \u251c\u2500\u2500 types.py # Core data structures\n\u2502 \u2502 \u251c\u2500\u2500 config.py # Configuration management\n\u2502 \u2502 \u251c\u2500\u2500 errors.py # Exception hierarchy\n\u2502 \u2502 \u251c\u2500\u2500 install.py # CLI installation utilities\n\u2502 \u2502 \u2514\u2500\u2500 utils.py # Formatting and helpers\n\u2502 \u251c\u2500\u2500 providers/ # Provider wrappers\n\u2502 \u2502 \u251c\u2500\u2500 __init__.py \n\u2502 \u2502 \u251c\u2500\u2500 claude.py # Claude wrapper\n\u2502 \u2502 \u251c\u2500\u2500 gemini.py # Gemini wrapper\n\u2502 \u2502 \u2514\u2500\u2500 codex.py # Codex wrapper\n\u2502 \u251c\u2500\u2500 client.py # Main client implementation\n\u2502 \u251c\u2500\u2500 cli.py # Fire CLI interface\n\u2502 \u251c\u2500\u2500 server.py # FastMCP server\n\u2502 \u2514\u2500\u2500 install.py # Provider CLI installation\n\u251c\u2500\u2500 tests/ # Test suite\n\u251c\u2500\u2500 pyproject.toml # Package configuration\n\u2514\u2500\u2500 README.md # This file\n```\n\n### Key Implementation Details\n\n**Async Everywhere**: All I/O operations use async/await for efficiency\n\n**Message Types**: Flexible content that can be string or structured blocks:\n```python\nclass Message:\n role: MessageRole\n content: str | list[TextBlock | ToolUseBlock | ToolResultBlock]\n```\n\n**Provider Adapters**: Thin wrappers that maintain provider-specific features:\n```python\n# Each provider wrapper is ~20 lines\n# Imports provider package\n# Converts options if needed \n# Yields messages unchanged\n```\n\n**Auto-Install Logic**: Missing CLIs trigger automatic installation:\n```python\nif _is_cli_missing_error(e):\n install_func = _get_provider_install_function(provider)\n if install_func():\n # Retry query with fresh provider instance\n```\n\n**Clean Output**: Logging configured to minimize noise:\n```python\n# Verbose OFF: Only errors to stderr\n# Verbose ON: Full debug logging\n# AI responses always go to stdout\n```\n\n## Installation Details: Bun and Node\n\nClaif uses a hybrid approach for installing provider CLIs:\n\n### Why Bun?\n\n[Bun](https://bun.sh) is used for:\n1. **Fast npm installs** - 10x faster than npm\n2. **Binary bundling** - Creates standalone executables\n3. **Cross-platform** - Works on Windows, macOS, Linux\n4. **Minimal dependencies** - Single binary, no Node.js required\n\n### Installation Process\n\n```bash\n# 1. Bun installs the npm package globally\nbun add -g @anthropic-ai/claude-code\n\n# 2. Bundle script creates optimized binary\nbun build claude-wrapper.ts --compile --outfile dist/claude\n\n# 3. Binary is copied to ~/.local/bin\ncp dist/claude ~/.local/bin/\n```\n\n### Manual Installation Options\n\nIf you prefer Node.js:\n```bash\n# Using npm\nnpm install -g @anthropic-ai/claude-code\nnpm install -g @google/gemini-cli \nnpm install -g @openai/codex\n\n# Using yarn\nyarn global add @anthropic-ai/claude-code\n\n# Using pnpm\npnpm add -g @anthropic-ai/claude-code\n```\n\n### Bundle Benefits\n\n1. **Faster startup** - No Node.js initialization\n2. **Smaller size** - Single file vs node_modules\n3. **No conflicts** - Isolated from system Node.js\n4. **Portable** - Copy binary anywhere\n\n### Troubleshooting\n\n```bash\n# Check if CLIs are found\nclaif status\n\n# Manually set CLI paths\nexport CLAUDE_CLI_PATH=/usr/local/bin/claude\nexport GEMINI_CLI_PATH=/usr/local/bin/gemini\nexport CODEX_CLI_PATH=/usr/local/bin/codex\n\n# Skip auto-install and use existing CLIs\nclaif config set auto_install=false\n```\n\n## Why Use Claif?\n\n### 1. **Provider Independence**\n- Write once, use any AI model\n- Switch providers with a single parameter\n- Compare responses side-by-side\n- No vendor lock-in\n\n### 2. **Zero Friction**\n- Auto-installs missing CLIs on first use\n- Clean output - only show what matters\n- Smart defaults that just work\n- Async for speed\n\n### 3. **Developer Experience** \n- Full type hints and IDE support\n- Rich CLI with progress indicators\n- Comprehensive error messages\n- Fast MCP server for tool integration\n\n### 4. **Production Ready**\n- Battle-tested error handling\n- Timeout protection\n- Response caching (coming soon)\n- Configurable everything\n\n### 5. **Extensible**\n- Plugin architecture for new providers\n- Clean API for custom integrations \n- Well-documented codebase\n- Active development\n\n## Contributing\n\nBased on the development guide in [CLAUDE.md](CLAUDE.md):\n\n### Development Setup\n\n```bash\n# Clone the repository\ngit clone https://github.com/twardoch/claif.git\ncd claif\n\n# Install with dev dependencies\npip install -e \".[dev,test]\"\n\n# Install pre-commit hooks\npre-commit install\n```\n\n### Running Tests\n\n```bash\n# Run all tests\npytest\n\n# Run with coverage\npytest --cov=src/claif --cov-report=html\n\n# Run specific test\npytest tests/test_client.py -v\n\n# Run integration tests (requires provider packages)\npytest tests/integration/ -v\n```\n\n### Code Quality\n\n```bash\n# Format code\nruff format src tests\n\n# Lint code \nruff check src tests --fix\n\n# Type checking\nmypy src/claif\n\n# Run all checks (as per CLAUDE.md)\nfd -e py -x ruff format {}\nfd -e py -x ruff check --fix --unsafe-fixes {}\npython -m pytest\n```\n\n### Making Changes\n\n1. **Check existing utilities** in `claif.common` before implementing\n2. **Maintain API compatibility** - this is a plugin framework\n3. **Add tests** for new functionality\n4. **Update documentation** in docstrings and README\n5. **Follow style** - 120 char lines, descriptive names\n\n### Release Process\n\n```bash\n# Update version (uses hatch-vcs)\ngit tag v1.0.7\n\n# Build distribution\npython -m build\n\n# Upload to PyPI\ntwine upload dist/*\n```\n\n## License\n\nMIT License - see [LICENSE](LICENSE) file for details.\n\nCopyright (c) 2025 Adam Twardoch\n\n## Links\n\n### Claif Ecosystem\n\n**Core Framework:**\n- [GitHub: twardoch/claif](https://github.com/twardoch/claif) - This repository\n- [PyPI: claif](https://pypi.org/project/claif/) - Core package\n- [Documentation](https://github.com/twardoch/claif#readme) - Full docs\n- [Issues](https://github.com/twardoch/claif/issues) - Bug reports & features\n\n**Provider Packages:**\n- [claif_cla](https://github.com/twardoch/claif_cla/) - Claude provider (wraps claude-code-sdk)\n- [claif_gem](https://github.com/twardoch/claif_gem/) - Gemini provider (wraps Gemini CLI) \n- [claif_cod](https://github.com/twardoch/claif_cod/) - Codex provider (wraps OpenAI Codex CLI)\n\n### Upstream Projects\n\n**Provider CLIs:**\n- [Claude Code](https://github.com/anthropics/claude-code) - Anthropic's official CLI\n- [claude-code-sdk](https://github.com/anthropics/claude-code-sdk-python) - Python SDK for Claude\n- [Gemini CLI](https://github.com/google-gemini/gemini-cli/) - Google's Gemini CLI\n- [OpenAI Codex CLI](https://github.com/openai/codex) - OpenAI's code generation CLI\n\n**Related Tools:**\n- [Fire](https://github.com/google/python-fire) - Python CLI framework\n- [Rich](https://github.com/Textualize/rich) - Terminal formatting\n- [FastMCP](https://github.com/fixie-ai/fastmcp) - MCP server framework\n- [Bun](https://bun.sh) - Fast JavaScript runtime used for bundling\n\n### Resources\n\n**Documentation:**\n- [Anthropic Docs](https://docs.anthropic.com/) - Claude documentation\n- [Google AI Studio](https://ai.google.dev/) - Gemini documentation\n- [OpenAI Platform](https://platform.openai.com/) - OpenAI documentation\n\n**Community:**\n- [Discussions](https://github.com/twardoch/claif/discussions) - Q&A and ideas\n- [Twitter: @adamtwar](https://twitter.com/adamtwar) - Author updates\n\n**Articles & Tutorials:**\n- [Building a Unified AI CLI](https://example.com) - Design decisions\n- [Plugin Architecture in Python](https://example.com) - Technical deep dive\n- [Async Patterns for AI APIs](https://example.com) - Performance guide",
"bugtrack_url": null,
"license": "MIT",
"summary": "A unified CLI and Python library for interacting with local and remote LLMs, compatible with the OpenAI Responses API.",
"version": "1.0.32",
"project_urls": {
"Documentation": "https://github.com/twardoch/claif#readme",
"Issues": "https://github.com/twardoch/claif/issues",
"Source": "https://github.com/twardoch/claif"
},
"split_keywords": [
"ai",
" artificial-intelligence",
" claif",
" claude",
" cli",
" codex",
" command-line",
" gemini",
" llm",
" lm-studio",
" openai",
" responses-api"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "1af720c326353a6dee614b4524dfccb4dcefece60cb238ab3bf21593ba269d09",
"md5": "35b3cac8fd3afb3626762311992dec80",
"sha256": "0d70b50b8a48b31ba88962f9fcccaab5225ed933dd3f1181922ba53135a83cdd"
},
"downloads": -1,
"filename": "claif-1.0.32-py3-none-any.whl",
"has_sig": false,
"md5_digest": "35b3cac8fd3afb3626762311992dec80",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 16035,
"upload_time": "2025-07-29T01:49:46",
"upload_time_iso_8601": "2025-07-29T01:49:46.986037Z",
"url": "https://files.pythonhosted.org/packages/1a/f7/20c326353a6dee614b4524dfccb4dcefece60cb238ab3bf21593ba269d09/claif-1.0.32-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "66eb602e049cdf1dcd821dc639ad2c0d942b7d8f8ce669652bdadca0d953bded",
"md5": "3513f5b2b97e16c5423fc52fc1927a77",
"sha256": "b4e3b01c5627c4c5333bde9de428d2f58f73e0cb79ae0b01a06a392abc1a9105"
},
"downloads": -1,
"filename": "claif-1.0.32.tar.gz",
"has_sig": false,
"md5_digest": "3513f5b2b97e16c5423fc52fc1927a77",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 48645,
"upload_time": "2025-07-29T01:49:45",
"upload_time_iso_8601": "2025-07-29T01:49:45.707019Z",
"url": "https://files.pythonhosted.org/packages/66/eb/602e049cdf1dcd821dc639ad2c0d942b7d8f8ce669652bdadca0d953bded/claif-1.0.32.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-29 01:49:45",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "twardoch",
"github_project": "claif#readme",
"travis_ci": false,
"coveralls": true,
"github_actions": true,
"lcname": "claif"
}