CLIO Developer Guide
June 18, 2026 · View on GitHub
Complete guide to extending and contributing to CLIO
Table of Contents
- Introduction
- Architecture Overview
- Code Organization
- Development Setup
- Adding New Tools
- Adding New AI Providers
- Testing
- Code Standards
- Contribution Workflow
Introduction
Welcome!
CLIO is built with extensibility in mind. Whether you want to add new tools, integrate additional AI providers, or enhance existing features, this guide will help you contribute effectively.
Prerequisites
Before contributing, you should be familiar with:
- Perl: Object-oriented Perl, modules, references
- Terminal UI: ANSI escape codes, terminal interaction
- AI APIs: REST APIs, JSON, streaming responses
- Git: Branching, commits, pull requests
Development Philosophy
CLIO follows these principles:
- No CPAN Dependencies: Use core Perl modules only
- Tool-Powered: AI interacts through well-defined tools
- Action Transparency: Every operation shows what it's doing
- Session Persistence: State survives across restarts
- Professional UX: Terminal UI should be polished and usable
Architecture Overview
High-Level Design
graph TD
UI["User Interface<br/>Chat, Markdown, ANSI"]
Agent["Core AI Agent<br/>WorkflowOrchestrator, APIManager"]
Registry["Tool Registry<br/>Tool Executor"]
Session["Session Manager<br/>Persistence"]
Tools["Tools Layer<br/>FileOps | VersionControl | Terminal | Memory | etc."]
UI --> Agent
Agent --> Registry
Agent --> Session
Registry --> Tools
style UI fill:#e1f5ff
style Agent fill:#fff3e0
style Registry fill:#e8f5e9
style Session fill:#fce4ec
style Tools fill:#f3e5f5
Core Components
1. WorkflowOrchestrator (lib/CLIO/Core/WorkflowOrchestrator.pm)
- Main agent loop for interactive and non-interactive operation
- Orchestrates the full turn cycle: message building, API calls, tool execution
- Handles proactive context trimming before each API call
- Manages streaming responses and keypress interrupt detection
2. APIManager (lib/CLIO/Core/APIManager.pm)
- Abstracts AI provider APIs
- Handles authentication
- Manages streaming responses
- Error handling and retries
3. Tool Registry (lib/CLIO/Tools/Registry.pm)
- Registers all available tools
- Routes operations to appropriate tools
- Manages tool definitions for AI
4. Session Manager (lib/CLIO/Session/*.pm)
- Persists conversation history
- Manages session state
- Handles session resumption
5. UI Components (lib/CLIO/UI/*.pm)
- Chat: Chat interface and main interactive loop
- Markdown: Markdown rendering
- ANSI: ANSI escape code management
- Theme: Color schemes and templates
- Display: Display utilities
- ToolOutputFormatter: Tool output formatting
Data Flow
User Input Flow:
User Input → Chat → WorkflowOrchestrator → APIManager → AI Provider
↓
Tool Selection
↓
Tool Execution
↓
Result Collection
↓
AI Response Generation
↓
Markdown Rendering
↓
User Output
Tool Execution Flow:
AI Request → Tool Registry → Route to Tool → Execute Operation
↓
Return Result
↓
Action Description
↓
Back to AI Agent
Code Organization
Directory Structure
clio/
clio # Main executable
install.sh # Installation script
check-deps # Dependency checker
lib/CLIO/ # Core library
Core/ # Core components
APIManager.pm # AI provider integration, token management
WorkflowOrchestrator.pm # Main agent loop and tool orchestration
SimpleAIAgent.pm # Lightweight AI agent for internal tasks
ToolExecutor.pm # Tool invocation and secret redaction
Config.pm # Configuration management
Logger.pm # Logging utilities
PromptManager.pm # System prompt management
PromptBuilder.pm # Prompt construction utilities
InstructionsReader.pm # Custom instructions reader
ConversationManager.pm # Conversation history management
ModelRegistry.pm # AI model metadata and management
ToolCallExtractor.pm # Extract tool calls from AI responses
ToolErrorGuidance.pm # Contextual error recovery hints
ErrorContext.pm # Error taxonomy and structured context
AgentLoop.pm # Persistent agent execution loop
DeviceRegistry.pm # Named devices for remote execution
SkillManager.pm # AI skill management
SkillRepository.pm # Skill repository configuration
RepositoryLoader.pm # Load skills from Git repos
PerformanceMonitor.pm # Performance tracking
RateLimiter.pm # API rate limiting
PluginManager.pm # Plugin system
Defaults.pm # Default configuration values
API/ # API sub-modules
MessageValidator.pm # Message validation and proactive trimming
ResponseHandler.pm # AI provider response parsing
ReadLine.pm Editor.pm
HashtagParser.pm TabCompletion.pm
GitHubAuth.pm GitHubCopilotModelsAPI.pm CopilotUserAPI.pm
Tools/ # Tool implementations
Tool.pm # Base tool class
Registry.pm # Tool registry
FileOperations.pm # File tools (17 operations)
VersionControl.pm # Git tools (11 operations)
TerminalOperations.pm
MemoryOperations.pm
TodoList.pm
WebOperations.pm
CodeIntelligence.pm # Code analysis
Interact.pm # User interaction
SubAgentOperations.pm # Multi-agent
RemoteExecution.pm # Remote SSH execution
ApplyPatch.pm # Patch application
MCPBridge.pm # MCP tool bridge
UI/ # User interface
Chat.pm # Chat interface
Markdown.pm # Markdown renderer
ANSI.pm # ANSI codes
Theme.pm # Theming system
Display.pm # Display utilities
ToolOutputFormatter.pm # Tool output formatting
CommandHandler.pm # Slash command routing
ProgressSpinner.pm # Animated busy indicator
Multiplexer.pm # Multiplexer detection and pane management
StreamingController.pm # Streaming response display and pagination
PaginationManager.pm # Page-based output display
DiffRenderer.pm # Unified diff display with syntax coloring
Terminal.pm # Terminal capability detection
HostProtocol.pm # Structured protocol for GUI host apps
Multiplexer/ # Multiplexer drivers
Tmux.pm Screen.pm Zellij.pm
Commands/ # Slash command handlers
Base.pm # Base class with display delegation for all command modules
AI.pm API.pm Billing.pm Config.pm Context.pm
Device.pm File.pm Git.pm Log.pm Memory.pm
Mux.pm Profile.pm Project.pm Prompt.pm
Session.pm Skills.pm Spec.pm Stats.pm
SubAgent.pm System.pm Todo.pm Update.pm
API/ # API sub-command handlers
Auth.pm Config.pm Models.pm
Session/ # Session management
Manager.pm # Session manager
State.pm # Session state
TodoStore.pm # Todo persistence
ToolResultStore.pm # Large result storage
FileVault.pm # Targeted file backup for undo
Export.pm # Session export to HTML
Lock.pm # Session locking
Coordination/ # Multi-agent coordination
Broker.pm # Coordination server (auto-exits after 5 min idle)
Client.pm # Broker connection API
SubAgent.pm # Process spawning
Security/ # Auth/authz
Auth.pm # Authentication
Authz.pm # Authorization
PathAuthorizer.pm # File access control
Manager.pm # Security management
SecretRedactor.pm # PII/secret redaction
InvisibleCharFilter.pm # Invisible Unicode character defense
Memory/ # Context/memory
ShortTerm.pm # Conversation context
LongTerm.pm # Persistent memory
YaRN.pm # Context windowing
TokenEstimator.pm # Token counting
Profile/ # User personality profile
Analyzer.pm # Session history analysis
Manager.pm # Profile storage and injection
Providers/ # Native API providers
Base.pm # Provider base class
Google.pm # Google Gemini native API
MCP/ # Model Context Protocol
Manager.pm # MCP server management
Client.pm # MCP client
Auth/OAuth.pm # MCP OAuth 2.0 support
Transport/Stdio.pm Transport/HTTP.pm
Code/ # Code intelligence
TreeSitter.pm # Tree-sitter integration
Symbols.pm # Symbol extraction
Relations.pm # Code relations
Logging/ # Logging system
ToolLogger.pm # Tool operation logging
ProcessStats.pm # Process statistics
Util/ # Utilities
PathResolver.pm # Path resolution and tilde expansion
TextSanitizer.pm # Text sanitization
JSONRepair.pm # JSON repair for malformed AI output
JSON.pm # JSON module selection (XS > PP fallback)
GitIgnore.pm # Auto-manage .clio/ in .gitignore
InputHelpers.pm # Terminal input utilities
AnthropicXMLParser.pm # XML-format tool call parser
YAML.pm # Lightweight YAML parser
ConfigPath.pm # Config path resolution
Spec/ # OpenSpec integration
Manager.pm # Spec lifecycle management
Test/ # Testing utilities
MockAPI.pm # Mock API for tests
Compat/ # Compatibility layers
HTTP.pm Terminal.pm
docs/ # User documentation
styles/ # Color style files (25 themes)
tests/ # Test suites
sessions/ # Saved sessions (gitignored)
Module Naming Conventions
- Core modules:
CLIO::Core::*- System components - Tools:
CLIO::Tools::*- Tool implementations - UI:
CLIO::UI::*- User interface components - Session:
CLIO::Session::*- Session management - Coordination:
CLIO::Coordination::*- Multi-agent coordination - Security:
CLIO::Security::*- Authentication and authorization - Memory:
CLIO::Memory::*- Context and memory system - Providers:
CLIO::Providers::*- Native API provider modules - MCP:
CLIO::MCP::*- Model Context Protocol integration - Code:
CLIO::Code::*- Code intelligence and analysis - Util:
CLIO::Util::*- Utilities
File Naming
- Perl modules:
CamelCase.pm(e.g.,FileOperations.pm) - Scripts:
lowercase_underscore.sh - Documentation:
UPPERCASE.mdorCamelCase.md
Development Setup
Clone and Install
# Clone repository
git clone https://github.com/SyntheticAutonomicMind/CLIO.git
cd CLIO
# Install for development (user mode, no sudo)
./install.sh --user
# Or install system-wide
sudo ./install.sh
Running from Source
Without installing:
# Run directly from source
perl -I lib clio --new
# With debug output
perl -I lib clio --debug --new
With installed version:
clio --debug
Development Tools
Syntax checking:
# Check specific module
perl -I lib -c lib/CLIO/Tools/MyNewTool.pm
# Check all modules
find lib -name "*.pm" -exec perl -I lib -c {} \;
Testing:
# Run test suite (when implemented)
prove -I lib t/
# Manual testing
./clio --new
Adding New Tools
Tool Structure
Every tool inherits from CLIO::Tools::Tool and implements a standard interface.
Step-by-Step: Create a New Tool
1. Create the Tool Module
Create lib/CLIO/Tools/MyNewTool.pm:
package CLIO::Tools::MyNewTool;
use strict;
use warnings;
use feature 'say';
use parent 'CLIO::Tools::Tool';
=head1 NAME
CLIO::Tools::MyNewTool - Brief description
=head1 DESCRIPTION
Detailed description of what this tool does and when to use it.
=cut
sub new {
my ($class, %opts) = @_;
return $class->SUPER::new(
name => 'my_new_tool',
description => 'What this tool does and when to use it',
supported_operations => [qw(operation1 operation2)],
debug => $opts{debug} || 0,
);
}
sub route_operation {
my ($self, $operation, $params, $context) = @_;
if ($operation eq 'operation1') {
return $self->handle_operation1($params, $context);
}
elsif ($operation eq 'operation2') {
return $self->handle_operation2($params, $context);
}
else {
return $self->operation_error("Unknown operation: $operation");
}
}
sub get_additional_parameters {
my ($self) = @_;
return {
param1 => {
type => "string",
description => "Description of parameter 1",
},
param2 => {
type => "integer",
description => "Description of parameter 2",
},
};
}
sub handle_operation1 {
my ($self, $params, $context) = @_;
# Extract parameters
my $param1 = $params->{param1};
# Validate
unless ($param1) {
return $self->operation_error("Missing required parameter: param1");
}
# Set action description (CRITICAL for UX)
$self->set_action_description("Brief description of what this operation is doing");
# Do the work
my $result = "Result of operation1";
# Return success
return $self->operation_success($result);
}
sub handle_operation2 {
my ($self, $params, $context) = @_;
# Similar structure...
$self->set_action_description("Operation 2 description");
my $result = "Result of operation2";
return $self->operation_success($result);
}
1; # End of module MUST return true
2. Register the Tool
Edit lib/CLIO/Tools/Registry.pm:
use CLIO::Tools::MyNewTool;
Tool registration in WorkflowOrchestrator is data-driven. Add your tool to the @tool_defs array in _register_default_tools():
# In WorkflowOrchestrator::_register_default_tools()
my @tool_defs = (
# ... existing tools ...
{
name => 'my_new_tool',
class => 'CLIO::Tools::MyNewTool',
args => { debug => $self->{debug} },
},
);
Tools listed here are automatically subject to --enable/--disable filtering. If a tool should only register when a specific config key is set (like enable_remote for RemoteExecution), add a config_gate key:
{
name => 'my_new_tool',
class => 'CLIO::Tools::MyNewTool',
args => { debug => $self->{debug} },
config_gate => 'enable_my_tool', # only registers if this config key is truthy
},
3. Test Your Tool
# Syntax check
perl -I lib -c lib/CLIO/Tools/MyNewTool.pm
# Test in CLIO
./clio --new
# In conversation:
YOU: Use my_new_tool with operation1 and param1="test value"
Tool Best Practices
Action Descriptions:
Always set clear action descriptions:
$self->set_action_description("reading ./config.yaml (45 lines)");
$self->set_action_description("executing git status in ./");
$self->set_action_description("searching ./lib for pattern 'TODO'");
Format: <verb>ing <target> (<additional context>)
Error Handling:
eval {
# Operation that might fail
};
if ($@) {
my $error = $@;
log_error('MyNewTool', "Operation failed: $error");
return $self->operation_error($error);
}
Parameter Validation:
# Check required parameters
unless ($params->{required_param}) {
return $self->operation_error("Missing required parameter: required_param");
}
# Validate types
unless ($params->{count} =~ /^\d+$/) {
return $self->operation_error("Parameter 'count' must be an integer");
}
# Validate paths (for file operations)
use File::Spec;
my $safe_path = File::Spec->canonpath($params->{path});
Return Values:
# Success with result
return $self->operation_success($result_data);
# Success with message
return $self->operation_success($result_data, "Custom success message");
# Error
return $self->operation_error("Error message explaining what went wrong");
Adding New AI Providers
Provider Architecture
CLIO's provider system is built into APIManager.pm. Each provider is defined by its configuration (endpoints, headers, payload format) rather than a separate class. The _prepare_api_request method builds provider-specific payloads, and ResponseHandler.pm parses responses.
Key files to modify:
lib/CLIO/Core/APIManager.pm- Add provider config, endpoint logiclib/CLIO/Core/API/ResponseHandler.pm- Handle provider-specific response formatslib/CLIO/Core/ModelRegistry.pm- Add model definitions and metadatalib/CLIO/Core/Config.pm- Add provider defaults (base URL, etc.)
Step 1: Add provider config in Config.pm
Add your provider to _get_provider_defaults():
myprovider => {
base_url => 'https://api.myprovider.com/v1',
model => 'my-model-latest',
},
Step 2: Add endpoint logic in APIManager
In _prepare_api_request(), add a case for your provider to build the correct URL, headers, and payload format. Most providers follow the OpenAI chat completions format (/chat/completions endpoint with messages array).
Step 3: Add model metadata in ModelRegistry
Define available models with their context windows and capabilities:
'my-model-latest' => {
context_window => 128000,
supports_tools => 1,
supports_streaming => 1,
},
Step 4: Handle response quirks in ResponseHandler
If the provider returns tool calls, reasoning content, or error codes differently from the OpenAI format, add handling in ResponseHandler.pm.
Step 5: Add to PROVIDERS.md documentation
Reference implementation: See the MiniMax provider (commits 72e7080 through 93556e1) for a recent example of adding a new provider with Token Plan billing, static model lists, and reasoning content support.
Testing
Manual Testing
Basic functionality:
# Test tool execution
echo "list files in current directory" | ./clio --new --exit
# Test session persistence
./clio --new
# Have a conversation
# Exit and resume
./clio --resume
Edge cases:
# Large files
echo "read a 10MB file" | ./clio --new --exit
# Invalid input
echo "read a file that doesn't exist" | ./clio --new --exit
# Complex operations
echo "search for TODO in all Perl files, create a summary" | ./clio --new --exit
Automated Testing (Future)
Unit tests (t/unit/):
# t/unit/tools/file_operations.t
use Test::More tests => 5;
use CLIO::Tools::FileOperations;
my $tool = CLIO::Tools::FileOperations->new();
# Test read_file operation
my $result = $tool->route_operation('read_file', {
path => 'test_file.txt',
start_line => 1,
end_line => 10,
}, {});
ok($result->{success}, 'read_file succeeds');
like($result->{data}, qr/content/, 'read_file returns content');
done_testing();
Integration tests (t/integration/):
# t/integration/session_persistence.t
use Test::More;
use CLIO::Session::Manager;
# Create session
my $mgr = CLIO::Session::Manager->new();
my $session = $mgr->create();
# Add conversation
$session->add_message({ role => 'user', content => 'test' });
# Save
$mgr->save($session);
# Load
my $loaded = $mgr->load($session->id());
is($loaded->id(), $session->id(), 'Session ID preserved');
done_testing();
Code Standards
See Also: Developer Documentation Guide for complete POD documentation standards, code commenting guidelines, and technical writing best practices.
Perl Best Practices
Module Structure:
package CLIO::Module::Name;
use strict;
use warnings;
use feature 'say';
# POD documentation
=head1 NAME
CLIO::Module::Name - Brief description
=head1 DESCRIPTION
Detailed description.
=cut
# Code here
1; # Module MUST return true
Naming:
# Variables: snake_case
my $file_path = "/path/to/file";
my $line_count = 0;
# Subroutines: snake_case
sub read_file { ... }
sub parse_response { ... }
# Packages: CamelCase
package CLIO::Core::AIAgent;
# Constants: UPPERCASE
use constant MAX_RETRIES => 3;
Error Handling:
# Use eval for exception handling
eval {
# Code that might die
};
if ($@) {
my $error = $@;
log_error('MyModule', "Operation failed: $error");
# handle error
}
Logging:
use CLIO::Core::Logger qw(log_debug log_info log_warning log_error should_log);
# Debug logging (only emitted when --debug flag is set)
log_debug('MyModule', 'Processing request');
# Info, warning, error logging
log_info('MyModule', 'Starting operation');
log_warning('MyModule', 'Retrying after failure');
log_error('MyModule', "Fatal: $@");
# Conditional guard (use when constructing an expensive message)
log_debug('MyModule', 'Details: ' . $detail) if should_log('DEBUG');
No CPAN Dependencies:
# ✅ Use core modules
use JSON::PP; # Core since 5.14
use HTTP::Tiny; # Core since 5.14
use File::Spec; # Core
# ❌ Don't use CPAN modules
use Moo; # Not core
use LWP::UserAgent # Not core
Terminal and Process Safety:
When spawning child processes (shell commands, ssh, compilers, etc.), always use process groups to ensure cleanup on timeout or interrupt:
# CORRECT: use process groups so kill() reaches all descendants
use POSIX qw(setpgid WNOHANG);
my $pid = fork();
if ($pid == 0) {
# Child: create own process group
setpgid(0, 0);
exec($command) or die "exec failed: $!";
}
# Parent: kill the whole group on timeout/interrupt
kill('-TERM', $pid); # SIGTERM to process group (negative = group)
sleep(2);
kill('-KILL', $pid) if kill(0, $pid); # SIGKILL if still alive
waitpid($pid, WNOHANG);
NEVER use alarm() or local $SIG{ALRM} in tool execution code. Chat.pm's 1-second ALRM timer drives ESC interrupt detection. Clobbering it breaks keyboard responsiveness. For timeouts, use a fork+waitpid poll loop instead:
# CORRECT: poll loop with Time::HiRes (doesn't touch ALRM)
use Time::HiRes qw(time);
my $deadline = time() + $timeout;
while (1) {
my $done = waitpid($pid, WNOHANG);
last if $done;
last if time() > $deadline;
select(undef, undef, undef, 0.1); # 100ms poll interval
}
# WRONG: destroys the ESC interrupt timer
local $SIG{ALRM} = sub { kill 'TERM', $pid };
alarm($timeout);
waitpid($pid, 0);
alarm(0);
Documentation Standards
POD for modules:
=head1 NAME
CLIO::Tools::MyTool - Brief description
=head1 SYNOPSIS
use CLIO::Tools::MyTool;
my $tool = CLIO::Tools::MyTool->new();
my $result = $tool->route_operation('op', $params, $context);
=head1 DESCRIPTION
Detailed description of the module.
=head2 method_name
Description of what this method does.
Arguments:
- $arg1: Description
- $arg2: Description
Returns: Description of return value
=cut
Inline comments:
# Explain WHY, not WHAT
# Bad:
my $count = 0; # Initialize count to zero
# Good:
my $count = 0; # Track number of failed retries for exponential backoff
Contribution Workflow
Before Contributing
- Read The Unbroken Method:
cat ai-assisted/THE_UNBROKEN_METHOD.md - Check existing issues: Search for related work
- Discuss major changes: Open an issue first for large features
- Consider using CLIO: CLIO is developed using CLIO itself. Using CLIO for your contributions helps you understand the tool from a user's perspective and ensures your changes work well in practice.
Development Workflow
1. Fork and Clone:
# Fork on GitHub, then:
git clone https://github.com/YOUR_USERNAME/CLIO.git
cd CLIO
git remote add upstream https://github.com/SyntheticAutonomicMind/CLIO.git
2. Create Feature Branch:
git checkout -b feature/my-new-feature
3. Make Changes:
# Edit code
# Test changes
perl -I lib -c lib/CLIO/Tools/MyNewTool.pm
./clio --debug
4. Commit:
git add -A
git commit -m "feat(tools): add MyNewTool for X functionality
**Problem:**
[what was missing or broken]
**Solution:**
[how you fixed or built it]
**Testing:**
✅ Syntax: PASS (perl -c)
✅ Manual: [what you tested]
✅ Edge cases: [what you verified]"
Commit message format:
type(scope): brief description
**Problem:**
What was broken or missing
**Solution:**
How you fixed it
**Testing:**
What you tested
Types: feat, fix, refactor, docs, test, chore
5. Push and PR:
git push origin feature/my-new-feature
Then open a Pull Request on GitHub.
Code Review
Expect reviewers to check:
- Code quality and style
- Test coverage
- Documentation completeness
- No CPAN dependencies
- Action descriptions present
- Error handling
Be prepared to:
- Answer questions about design decisions
- Make requested changes
- Add tests if missing
- Update documentation
Resources
Documentation:
docs/SPECS/- Technical specifications (Architecture, Tools)docs/ARCHITECTURE.md- Architecture overviewdocs/ARCHITECTURE_REMOTE_EXECUTION.md- Remote execution design specdocs/COMMAND_OUTPUT_STANDARDS.md- Command output styling standardsdocs/DEVELOPER_DOCUMENTATION_GUIDE.md- Developer documentation standardsdocs/DOCUMENTATION_GUIDE.md- User-facing documentation standardsdocs/PERFORMANCE.md- Performance benchmarks and optimizationdocs/FORMULA_RENDERING.md- Mathematical formula renderingdocs/STYLE_GUIDE.md/docs/STYLE_QUICKREF.md- Color theme reference
Code Examples:
lib/CLIO/Tools/FileOperations.pm- Comprehensive tool examplelib/CLIO/Tools/TodoList.pm- State management examplelib/CLIO/UI/Markdown.pm- UI component example
Community:
Next Steps
- Set up your development environment
- Read existing code - Understand patterns
- Pick a small task - Start with documentation or minor feature
- Ask questions - Use GitHub Discussions
- Submit your first PR!
Welcome to CLIO development!