# Sidekick Sidekick is a simple but versatile agentic framework written in Go 1.25. It provides a robust architecture for building AI assistants with hierarchical orchestration, native Model Context Protocol (MCP) integration, and a rich terminal user interface (TUI). ## Features * **Hierarchical Orchestration:** Support for complex agent topologies, including coordinators and specialized subagents. * **Model Context Protocol (MCP):** Native integration for calling external tools via MCP, supporting `stdio`, `sse`, and `http` transports (via `mark3labs/mcp-go`). * **Intelligent Buffering:** Automatically buffers large tool outputs to prevent context window exhaustion, returning file pointers for significant payloads. * **Rich Terminal UI:** A beautiful, responsive TUI built with Charmbracelet's BubbleTea and Lipgloss, featuring status bars, role-based formatting, and dynamic viewports. * **Advanced Prompt Templating:** Define complex, multi-line system prompts using TOML. Support for Go's `text/template` engine allows you to compose modular prompts from reusable snippets. * **Internal Tools:** Built-in tools for file I/O (`read_file`, `write_file`, `grep_file`, `edit_file`) and an optional, secure `shell_exec` tool for running POSIX shell commands. * **Configuration Driven:** Easily configure models, agents, tools, and MCP servers via a declarative `config.toml` file. ## Internal Tools Sidekick includes a set of internal tools that are always available to agents. These tools provide common file operations and system access. ### File Tools - `read_file`: Read a file with optional line windowing. - `write_file`: Overwrite a file with new content. - `grep_file`: Regex search with surrounding context. - `edit_file`: Replace a string or block of lines in a file. ### shell_exec Tool The `shell_exec` tool allows an agent to run arbitrary POSIX shell commands and receive combined stdout/stderr output. **Security Warning:** This tool is extremely powerful and potentially dangerous. It is **disabled by default** and must be explicitly enabled for each agent in `config.toml`. To enable `shell_exec` for an agent, add `enable_shell_exec = true` to its configuration: ```toml [agents.coordinator] role = "COORDINATOR" model_id = "default" enable_shell_exec = true # Security: explicitly enabled toolsets = ["filesystem"] ``` ## Installation ### Prerequisites * Go 1.25 or higher. ### Installing the Library To use Sidekick as a framework in your own Go projects: ```bash go get codeberg.org/luxferre/sidekick-ng ``` ### Installing the TUI To install the Sidekick TUI binary globally: ```bash go install codeberg.org/luxferre/sidekick-ng/cmd/sidekick-tui@latest ``` Alternatively, you can build it locally from the source using the provided `Makefile`: ```bash make ``` Or manually: ```bash git clone https://codeberg.org/luxferre/sidekick-ng.git cd sidekick-ng go build -o bin/sidekick-tui ./cmd/sidekick-tui ``` ## Configuration Sidekick relies on two primary configuration files: `config.toml` for system settings and `prompts.toml` for advanced system prompt management. **Important:** When running the TUI, the binary expects `config.toml` and `prompts.toml` to be present in the directory from which the command is executed. ### `config.toml` This file defines your models, MCP servers, and agent profiles. ```toml tool_response_threshold = 10000 # Bytes after which tool results are buffered to files [models.default] model_id = "env:DEFAULT_MODEL_ID" endpoint = "env:DEFAULT_MODEL_ENDPOINT" api_key = "env:DEFAULT_MODEL_API_KEY" temperature = 0.0 max_tokens = 4096 [mcp_servers.filesystem] transport = "stdio" command = "npx" args = ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"] [mcp_servers.remote_tools] transport = "sse" url = "https://api.example.com/mcp" auth_token = "env:MCP_API_KEY" # Optional Bearer token headers = { "X-Custom-Header" = "value" } # Optional custom headers [agents.coordinator] role = "COORDINATOR" model_id = "default" system_prompt = "You are the primary coordinator agent." # This can be overridden by prompts.toml subagents = ["researcher"] toolsets = ["filesystem"] ``` ### `prompts.toml` Use this file to define complex, multi-line system prompts. If an entry here matches an agent's ID in `config.toml`, it will override the inline `system_prompt`. It uses Go's `text/template` engine, allowing you to compose prompts dynamically. ```toml base_identity = """ You are a highly capable agentic assistant built on the Sidekick framework. Always be professional, concise, and helpful. """ coordinator = """ {{template "base_identity"}} You are the COORDINATOR agent. Your primary responsibility is to understand the user's request and delegate tasks accordingly. """ ``` ## Usage ### Running the TUI 1. Ensure you have `config.toml` (and optionally `prompts.toml`) in your current directory. 2. Set any necessary environment variables defined in your config (e.g., `DEFAULT_MODEL_API_KEY`). 3. Run the TUI: ```bash ./bin/sidekick-tui ``` * **Input:** Type your messages at the bottom prompt. * **Send:** Press `Enter` to send a message. * **Quit:** Press `ctrl+c` to exit. * **Scrolling:** Use the mouse wheel or arrow keys to scroll through the conversation history. ### Running the Sidekick MCP Server Sidekick can also act as an MCP server, allowing other LLM-powered applications to leverage its agentic capabilities. 1. Configure the `mcp_listener` in `config.toml`: ```toml [mcp_listener] transport = "sse" # "stdio" or "sse"/"http" port = 8080 # for sse/http ``` 2. Run the MCP server: ```bash ./bin/sidekick-mcp ``` The server provides a `query` tool that routes requests to your coordinator agent, maintaining conversation history if provided. ### Using the Framework Programmatically ```go package main import ( "context" "fmt" "log" "codeberg.org/luxferre/sidekick-ng" ) func main() { // 1. Load Configuration cfg, err := sidekick.LoadConfig("config.toml") if err != nil { log.Fatal(err) } // 2. Load and Apply Prompts (Optional) tmpl, _ := sidekick.LoadPrompts("prompts.toml") // 3. Initialize Agent agentCfg := cfg.Agents["coordinator"] // Apply template override if exists if tmpl != nil && tmpl.Lookup("coordinator") != nil { if rendered, err := sidekick.RenderPrompt(tmpl, "coordinator"); err == nil { agentCfg.SystemPrompt = rendered } } agent := sidekick.NewAgent("coordinator", agentCfg, cfg) // 4. Run the Agent Loop ctx := context.Background() result, err := agent.Run(ctx, "What files are in the /tmp directory?") if err != nil { log.Fatal(err) } fmt.Println(result) } ``` ## Credits Created by Luxferre in 2026, released into the public domain with no warranties.