An AI coding agent built from scratch β inspired by Claude Code CLI β with full multi-tool orchestration, streaming responses, sub-agent delegation, MCP server integration, and an interactive terminal UI.
This project is a learning initiative designed to understand and implement core concepts behind intelligent coding agents:
- How AI agents reason about problems and select appropriate tools
- Multi-tool orchestration β deciding which tools to use and in what order
- Iterative refinement β analyzing code, identifying issues, and autonomously refactoring
- Streaming capabilities β real-time response generation and token consumption
- Error handling & resilience β retry logic, exponential backoff, graceful degradation
- Async patterns β non-blocking operations for API calls and task orchestration
- Context management β intelligent conversation history with automatic compression
- Extensible tool system β plugin architecture with built-in, sub-agent, and MCP tools
- β Async OpenAI client with lazy initialization
- β Support for streaming and non-streaming responses
- β
Stream event architecture (
StreamEvent,TextDelta,TokenUsage) - β
Tool call streaming β incremental
TOOL_CALL_START,TOOL_CALL_DELTA,TOOL_CALL_COMPLETEevents - β
Error handling with retry logic:
- Rate limit handling with exponential backoff
- Connection error recovery
- API error catching and reporting
- β
Configurable API key via
.envfile - β Support for different LLM providers (configurable base URL)
- β Tool schema building from tool definitions
- β Event-based architecture for streaming responses
- β
Event types:
TEXT_DELTA,TOOL_CALL_START,TOOL_CALL_DELTA,TOOL_CALL_COMPLETE,MESSAGE_COMPLETE,ERROR - β Type-safe response events with usage tracking
- β Tool call delta tracking for incremental argument streaming
- β Consistent interface for both streaming and non-streaming modes
- β
Unified caller interface using
async for - β
Generator-based streaming with
yield - β Single entry point for different response modes
- β
Agentorchestrator with async context manager support - β
Event-driven architecture with
AgentEventandAgentEventType - β
Event lifecycle:
AGENT_STARTβTEXT_DELTAΓ N βTOOL_CALL_START/COMPLETEΓ N βTEXT_COMPLETEβAGENT_END - β
Error propagation through event system (
AGENT_ERROR) - β Full agentic loop with multi-turn tool calling
- β
Message context storage via
ContextManager - β Tool call event streaming with result tracking
- β Maximum turns enforcement with graceful error reporting
- β
Sessionclass orchestrating lifecycle of client, tools, context, and MCP - β UUID-based session identification with timestamps
- β Turn counting and tracking
- β User memory persistence across sessions (JSON-based)
- β Initialization lifecycle: MCP β Tool Discovery β Tool Registration β Context Setup
- β
Pydantic-based hierarchical configuration (
Config,ModelConfig,ShellEnvironmentPolicy,MCPServerConfig) - β Multi-level config loading β system-level β project-level β CLI overrides
- β
TOML-based configuration files (
.flux-cli/config.toml) - β
Auto-detection of
AGENT.mdfiles for developer instructions - β Configurable model, temperature, context window, max turns
- β Shell environment policy β secret masking, env variable setting
- β MCP server configuration with stdio and HTTP/SSE transport
- β Allowed tools restriction list
- β
--cwdCLI option for working directory - β Config validation on startup
- β
ContextManagerwith full message history tracking - β Token counting per message
- β System prompt construction with identity, environment, tool guidelines, security
- β Automatic context compression trigger (80% of context window)
- β Smart tool output pruning β protects recent outputs, prunes older ones
- β Compression-aware continuation with context restoration
- β
Usage tracking (
latest_usage+total_usage)
- β
ChatCompactorfor summarizing conversation history - β Smart history formatting for compression (truncates long tool outputs, assistant responses)
- β Structured compression output (original goal, completed actions, current state, remaining tasks)
- β Seamless continuation with "don't repeat completed actions" guard
- β Compression prompt with detailed template
- β
Abstract
Toolsbase class with Pydantic schema validation - β
ToolKindenum βREAD,WRITE,SHELL,NETWORK,MEMORY,MCP - β
ToolRegistrywith registration, lookup, MCP tool segregation - β
ToolInvocationβ parameter + cwd context for execution - β
ToolResultβ standardized result with output, error, metadata, diff, truncation flag - β
FileDiffβ unified diff generation for file operations - β
ToolConfirmationβ confirmation model for mutating operations - β
Automatic OpenAI schema generation from Pydantic models (
to_openai_schema()) - β
ToolDiscoveryManagerβ auto-discovers custom tools from.ai-agent/tools/directories - β Parameter validation with descriptive error messages
| Tool | Kind | Description |
|---|---|---|
read_file |
READ | Read text files with line numbers, offset/limit, binary detection |
write_file |
WRITE | Create/overwrite files with automatic parent directory creation |
edit |
WRITE | Precise surgical text replacement with uniqueness checks |
shell |
SHELL | Command execution with timeout, blocked command safety, environment control |
list_dir |
READ | Directory listing with hidden file toggle |
grep |
READ | Regex search across files with case-insensitive option |
glob |
READ | File pattern matching with recursive ** support |
web_search |
NETWORK | DuckDuckGo web search integration |
web_fetch |
NETWORK | HTTP fetch with automatic fallback to proxy on 403/5xx |
todos |
MEMORY | Session-scoped task tracking (add/complete/list/clear) |
memory |
MEMORY | Persistent user memory stored across sessions |
- β
SubAgentToolβ spawns child agents for specialized tasks - β
SubAgentDefinitionβ name, description, goal prompt, allowed tools, timeout - β
codebase_investigatorβ explores code structure using read/grep/glob/list_dir (read-only) - β
code_reviewerβ reviews code changes for bugs, security, improvements - β Isolated context execution with turn and timeout limits
- β Result aggregation β tool calls made, final response, termination reason
- β MCP server management with connect/disconnect lifecycle
- β Support for stdio transport (local processes) and SSE transport (remote servers)
- β Automatic tool registration from MCP server capabilities
- β Configurable startup timeout and environment variables
- β Health status tracking (disconnected/connecting/connected/error)
- β Graceful shutdown with resource cleanup
- β Click-based CLI with command-line argument parsing
- β Rich terminal output with custom theme styling (16+ semantic styles)
- β
Dual mode: single-prompt (
python main.py "prompt") and interactive mode - β
Interactive commands:
/exit,/helpsupport - β
Real-time streaming text display with
stream_assistant_delta() - β Tool call panels β rich panels with tool name, call ID, arguments table, status
- β Tool result rendering β syntax-highlighted code, diffs, shell output, search results
- β Per-tool-kind border styling (read=cyan, write=yellow, shell=magenta, etc.)
- β Welcome panel with model info, cwd, and available commands
- β Error suppression for clean shutdown (unclosed resource warnings)
- β Comprehensive system prompt generation with multiple sections
- β Identity & role definition
- β Environment context (date, OS, working directory, shell)
- β Tool usage guidelines with best practices
- β AGENTS.md specification integration
- β Security guidelines (secrets, path validation, prompt injection defense)
- β Operational guidelines (tone, primary workflows, error recovery)
- β Developer instructions (from config/AGENT.md)
- β User instructions support
- β User memory injection
- β Tool list auto-generation with descriptions
- β
utils/paths.pyβ path resolution, relative display, parent directory creation, binary file detection - β
utils/text.pyβ token counting (tiktoken), text truncation by tokens/lines/characters - β
utils/errors.pyβAgentErrorandConfigErrorwith structured error details
flux/
βββ main.py # CLI entry point with Click, interactive/single modes
βββ agent/
β βββ agent.py # Agent orchestrator with multi-turn agentic loops
β βββ events.py # AgentEvent, AgentEventType (lifecycle + tool call events)
β βββ session.py # Session: client + registry + context + MCP lifecycle
βββ client/
β βββ llm_client.py # AsyncOpenAI wrapper with streaming, retry, tool call support
β βββ response.py # StreamEvent, TextDelta, TokenUsage, ToolCall types
βββ config/
β βββ __init__.py
β βββ config.py # Pydantic Config, ModelConfig, ShellEnvironmentPolicy, MCPServerConfig
β βββ loader.py # TOML config loading, multi-level merge, AGENT.md detection
βββ context/
β βββ compaction.py # ChatCompactor β context summarization when limit is hit
β βββ manager.py # ContextManager β message history, tokens, pruning, compression
βββ prompts/
β βββ system.py # System prompt generation (identity, tools, security, guidelines)
βββ tools/
β βββ base.py # Tools ABC, ToolInvocation, ToolResult, FileDiff, ToolKind
β βββ registry.py # ToolRegistry, create_default_registry
β βββ discovery.py # ToolDiscoveryManager β custom tool auto-discovery
β βββ subagent.py # SubAgentTool, SubAgentDefinition, default definitions
β βββ builtin/
β β βββ __init__.py # Tool exports and get_all_builtin_tools()
β β βββ read_file.py # File reading with line numbers, offset, binary detection
β β βββ write_file.py # File creation/overwrite with diff tracking
β β βββ edit_file.py # Surgical text replacement with uniqueness validation
β β βββ shell.py # Command execution with timeout, safety blocks
β β βββ list_dir.py # Directory listing
β β βββ grep.py # Regex file search
β β βββ glob.py # Glob pattern file matching
β β βββ web_search.py # DuckDuckGo search integration
β β βββ web_fetch.py # HTTP fetch with proxy fallback
β β βββ todo.py # Session-scoped task tracking
β β βββ memory.py # Persistent user memory
β βββ mcp/
β βββ client.py # MCPClient β stdio/SSE transport, tool listing, invocation
β βββ mcp_manager.py # MCPManager β server lifecycle, tool registration
β βββ mcp_tool.py # MCPTool adapter β wraps MCP tools in Tool interface
βββ ui/
β βββ tui.py # TUI with Rich themes, tool panels, streaming, syntax highlighting
βββ utils/
β βββ errors.py # AgentError, ConfigError
β βββ paths.py # Path resolution, binary detection, directory creation
β βββ text.py # Token counting, text truncation
βββ .env # API keys and configuration (git-ignored)
βββ .gitignore
βββ README.md
See the Architecture Documentation.
- Python 3.10+
- OpenRouter API key (or other OpenAI-compatible API)
# Clone the repository
git clone https://github.com/yourusername/flux.git
cd flux
# Create virtual environment
python -m venv .venv
# Activate virtual environment
# On Windows:
.venv\Scripts\activate
# On macOS/Linux:
source .venv/bin/activate
# Install dependencies
pip install openai python-dotenv pydantic httpx rich click tiktoken platformdirs tomli duckduckgo-search fastmcpCreate a .env file in the project root:
API_KEY=your_api_key_here
BASE_URL=https://openrouter.ai/api/v1 # Optional, default for OpenRouterOr use a TOML config file at ~/.config/flux-cli/config.toml:
[model]
name = "mistralai/mistral-small-2603"
temperature = 1.0
context_window = 256000
max_turns = 100
[shell_environment]
exclude_patterns = ["*KEY", "*TOKEN", "*SECRET"]Project-level config goes in .flux-cli/config.toml relative to CWD.
# Single prompt mode
python main.py "Find all Python files and count the lines"
# Interactive mode (REPL)
python main.py
# Specify working directory
python main.py --cwd /path/to/project "Analyze this codebase"
# Interactive commands:
# /help - Show help
# /exit - Exit the CLIThe TUI (ui/tui.py) provides a rich terminal experience:
- Welcome Panel: Contextual startup info with model, CWD, and available commands
- Streaming Text: Real-time assistant response display
- Tool Call Panels: Each tool invocation gets a styled panel with:
- Tool name and short call ID
- Arguments table (ordered by most important params)
- Running/done status indicators
- Kind-based border styling (read=cyan, write=yellow, shell=magenta, network=blue, memory=green, mcp=cyan)
- Result Rendering:
read_fileβ Syntax-highlighted code with line numberswrite_file/editβ Unified diff displayshellβ Command echo + output with exit codegrepβ Match count summary + resultsweb_search/web_fetchβ Summary with status, results count
- Truncation Warnings: When tool output exceeds token limits
Why use yield in async functions? Creates a consistent interface where callers always use async for, regardless of streaming mode. Both streaming and non-streaming LLM responses yield events through the same channel.
Implemented retry logic with exponential backoff for:
- Rate limiting (429 errors)
- Connection issues
- API errors
Using Python type hints and Pydantic throughout to catch issues early:
AsyncGenerator[StreamEvent, None]AsyncOpenAI | None- Pydantic
BaseModelfor all tool parameters - Strict validation with descriptive error messages
API client is only created when first needed, reducing startup overhead.
Automatic conversation summarization when approaching context window limits. Uses a child LLM call to create a structured continuation prompt that preserves goal, completed actions, and remaining tasks.
Three-tier tool system:
- Built-in β core tools for file operations, code search, web access
- Sub-agents β spawned child agents with isolated context for specialized tasks
- MCP β external tool servers via Model Context Protocol
Configuration is merged from multiple sources with increasing priority:
System config β Project config β CLI arguments
- User Approval System: Implement tool call approval workflow for mutating operations
- Multi-turn Conversation Persistence: Full conversation history across CLI sessions
- Code-aware Editing: AST-based code operations for safer refactoring
- Plugin Hot-Reloading: Dynamic tool registration without restart
- Performance Optimizations: Token caching, response caching, parallel tool execution
- Testing Suite: Comprehensive unit and integration tests
- Configuration UI: Interactive config wizard for first-time setup
- Documentation Site: Full API docs with examples
Inspired by and learning from:
- Rivaan Ranawat β Tutor and educational content creator
This is a personal learning project, but feel free to fork and experiment!
Note: This project is actively being developed as a learning exercise. Expect API changes and refactoring as new features are added.