Extensibility Guide¶
CLIver is designed with extensibility in mind, allowing you to customize its functionality, add new features, and integrate it seamlessly into your own Python applications. This guide covers how to extend CLIver and use it as a Python library.
Using CLIver as a Python Library¶
CLIver's core engine (TaskExecutor) is designed to be independent of the CLI layer. It has no dependencies on terminal I/O, prompt_toolkit, or Rich — making it suitable for embedding in web services, automation scripts, or other applications.
All features — LLM inference, tool calling, permissions, workflows, skills, and memory — work identically whether invoked from the CLI or from your own Python code.
Basic LLM Inference¶
from cliver import TaskExecutor
from cliver.config import ModelConfig, StdioMCPServerConfig
from cliver.model_capabilities import ModelCapability
# Example usage
async def run_example():
# Create configuration for Qwen model
llm_models = {
"qwen": ModelConfig(
name="qwen",
provider="ollama",
url="http://localhost:11434",
name_in_provider="qwen2.5:latest",
capabilities={ModelCapability.TEXT_TO_TEXT, ModelCapability.TOOL_CALLING},
)
}
# Create MCP server configuration using the proper Pydantic model
mcp_servers = {
"time": StdioMCPServerConfig(
name="time",
transport="stdio",
command="uvx",
args=["mcp-server-time", "--local-timezone=Asia/Shanghai"],
)
}
executor = TaskExecutor(
llm_models=llm_models,
mcp_servers={name: server.model_dump() for name, server in mcp_servers.items()},
default_model="qwen",
)
# Process a user query
user_input = "What time is it now ?"
result = await executor.process_user_input(user_input)
print("\n===\n")
print(result)
print("\n===\n")
if hasattr(result, "content") and result.content:
print("\nFinal answer:")
print(str(result.content))
print("\n===\n")
if __name__ == "__main__":
import asyncio
asyncio.run(run_example())
Streaming Responses¶
For real-time applications, you can stream responses from the LLM:
import asyncio
from cliver import TaskExecutor
from cliver.config import ModelConfig
from cliver.model_capabilities import ModelCapability
# Configure LLM models
llm_models = {
"qwen": ModelConfig(
name="qwen",
provider="ollama",
url="http://localhost:11434",
name_in_provider="qwen2.5:latest",
capabilities={ModelCapability.TEXT_TO_TEXT, ModelCapability.TOOL_CALLING},
)
}
executor = TaskExecutor(llm_models=llm_models, mcp_servers={}, default_model="qwen")
# Stream the response
async def stream_query():
async for chunk in executor.stream_user_input("Write a poem about programming"):
if hasattr(chunk, "content") and chunk.content:
print(chunk.content, end="", flush=True)
asyncio.run(stream_query())
Custom Commands¶
You can add custom commands to CLIver's CLI interface by creating command modules.
Creating a Custom Command¶
Create a Python file in the default config location, like: ~/.config/cliver/commands/my_command.py
import asyncio
import click
from langchain_core.messages import BaseMessage
from cliver.cli import Cliver, pass_cliver
from cliver.mcp_server_caller import MCPServersCaller
@click.group(name="my_command", help="My Command")
@click.pass_context
# here the function name is the same as the file name
def my_command(ctx: click.Context):
"""
Tasks for My Command
"""
if ctx.invoked_subcommand is None:
click.echo(ctx.get_help())
ctx.exit()
@my_command.command(name="sub_command", help="A sub command")
@click.argument("query", nargs=-1)
@pass_cliver
def sub_command(cliver: Cliver, query: str):
task_executor = cliver.task_executor
sentence = " ".join(query)
response = task_executor.process_user_input_sync(
user_input=sentence,
filter_tools=lambda tn, tools: [tool for tool in tools if "my_command" in str(tool)],
enhance_prompt=enhance_prompt,
)
if response:
if isinstance(response, str):
click.echo(response)
else:
if response.content:
click.echo(response.content)
def enhance_prompt(query: str, mcp_caller: MCPServersCaller) -> list[BaseMessage]:
return asyncio.run(mcp_caller.get_mcp_prompt("my-mcp-server", "auto_template", {"query": query}))
Next Steps¶
Now that you understand how to extend CLIver, explore Skills for creating specialized capabilities, Memory & Identity for agent personalization, or see the Roadmap for upcoming features.