mate

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 18, 2026 License: MIT

README

mate

Go CLI coding assistant with TUI and Slack bot interfaces. Uses OpenAI-compatible LLM APIs for an agentic coding loop with tools — file operations, shell execution, code search, web fetching, and subagent delegation.

Features

  • TUI chat — streaming responses, syntax highlighting, session tree navigation
  • mate run — one-shot CLI prompting with stdin piping
  • Tool executionbash, read_file, write_file, edit_file, grep, glob, webfetch
  • Skills — markdown-based prompt templates loaded from directories (YAML frontmatter + body)
  • Prompt templates/template-name expansion in prompts
  • Subagent delegation — offload work to child agents with different models/tools
  • Slack bot — mention or DM the bot in Slack; streaming responses with cancellation
  • core.Run — framework for building custom agents with your own tools and interfaces
  • Session management — turn-based tree model, persisted to disk, mate clean for housekeeping

Installation

Requires Go 1.26+.

go install github.com/3-lines-studio/mate/cmd/mate@latest

Configuration

Configuration lives in ~/.config/mate/. The following files are read:

File Purpose
config.toml Providers, models, agent settings, subagents
AGENTS.md User-level conventions injected into the system prompt
SYSTEM.md System-level prefix (overrides AGENTS.md position)
secrets.toml API keys, tokens, service credentials
config.toml
[[providers]]
id = "openai"
base_url = "https://api.openai.com/v1"

[[models]]
id = "gpt-4o"
provider = "openai"
name = "gpt-4o"
description = "GPT-4o"
context_window = 128000
max_output_tokens = 16384

[[models]]
id = "claude-sonnet-4-20250514"
provider = "anthropic"
name = "claude-sonnet-4-20250514"
description = "Claude Sonnet 4"
context_window = 200000
max_output_tokens = 16384
thinking_type = "enabled"
reasoning_effort = "medium"

[agent]
model = "gpt-4o"
max_tool_rounds = 99
# tools = ["bash", "read_file"]  # uncomment to restrict tools
# interfaces = ["slack", "local"]  # order determines which interface starts

[[subagents]]
id = "thinker"
description = "Deep reasoning subagent"
model = "claude-sonnet-4-20250514"
tools = ["bash", "read_file", "write_file", "edit_file", "grep", "glob"]
prompt = "You are a deep-thinking reasoning subagent. Think step by step."

[session]
dir = "~/.config/mate/sessions"

[tui]
tools_expanded = false
show_thinking = false
Secrets (secrets.toml)

API keys, tokens, and service credentials. Keys are matched by provider ID, not array position:

[providers]
openai = "sk-..."
anthropic = "sk-ant-..."

[slack]
bot_token = "xoxb-..."
app_token = "xapp-..."

[services.picsel]
connection_string = "postgres://..."
AGENTS.md / SYSTEM.md

These markdown files are injected into the system prompt. SYSTEM.md goes at the top (before the tool rules block). AGENTS.md from ~/.config/mate/ provides user-level conventions; AGENTS.md from the project root provides project-level conventions.

Example ~/.config/mate/AGENTS.md:

# Your conventions
- Prefer early returns over nested ifs.
- Use kebab-case for TypeScript, snake_case for Go.

Example SYSTEM.md:

You are a senior software engineer. Write correct, idiomatic code.

Usage

TUI
mate
mate -v                  # verbose: log provider communication
mate -m gpt-4o           # override model
mate --debug-prompts     # print system prompt and tool defs, then exit

The TUI shows:

  • Streaming assistant responses with syntax-highlighted code blocks
  • Tool execution progress (bash, file ops, grep/glob)
  • Session tree sidebar (turn-based history, switch between branches)
  • Token usage per turn
  • Subagent delegation flow
CLI (mate run)
mate run "fix the null pointer bug"
echo "refactor this" | mate run
mate run /review-pr < pr.diff
git diff main | mate run "summarize these changes"

The --debug-prompts flag works with mate run too:

mate run --debug-prompts "hello"
Session cleanup
mate clean                # list sessions
mate clean --all          # delete all sessions
mate clean --older-than 7 # delete sessions older than 7 days
mate clean --dry-run      # show what would be deleted
Flags
Flag Applies to Description
-v, --verbose TUI, run, clean Log provider communication to stderr
--debug-prompts TUI, run Print system prompts and tool definitions, then exit
-m, --model TUI, run Override the configured model (e.g. -m gpt-4o)

Skills

Skills are markdown files with YAML frontmatter stored in skill directories. They're loaded from:

  1. ./skills/ (project-level)
  2. ./.mate/skills/ (project-level, hidden)
  3. ~/.config/mate/skills/ (user-level)

Each skill lives in its own directory with a SKILL.md file. The LLM discovers skills via the list_skills tool and loads them with load_skill.

Example skills/react/SKILL.md:

---
name: react
description: React component patterns and best practices
tools:
  - bash
  - read_file
---
# React patterns

- Use functional components with hooks.
- Prefer composition over inheritance.

Prompt templates

Templates are .md files in ~/.config/mate/prompts/. They support YAML frontmatter for metadata and positional arguments. Use /template-name in any prompt to expand a template.

Example ~/.config/mate/prompts/review.md:

---
description: Review a pull request diff
argument-hint: <focus areas>
---
Review the following diff. Focus on: $@

- Bugs and logic errors
- Performance issues
- Security concerns
- Code style and readability

Usage:

mate run "/review correctness, error handling" < pr.diff

Template placeholders: $1, $2, ... for positional args, $@ or $ARGUMENTS for all args joined.

Slack bot

Mate can run as a Slack bot responding to @-mentions and DMs.

Setup
  1. Create a Slack app with Socket Mode enabled
  2. Add scopes: app_mentions:read, chat:write, im:history, im:read, im:write
  3. Enable event subscriptions for app_mention and message.im
  4. Get the Bot Token (xoxb-...) and App-Level Token (xapp-...)
  5. Configure in ~/.config/mate/config.toml:
[agent]
interfaces = ["slack"]

And add tokens to ~/.config/mate/secrets.toml:

[slack]
bot_token = "xoxb-..."
app_token = "xapp-..."

When interfaces includes "slack" before "local", the Slack bot starts instead of the TUI. Run mate --local to force the local terminal interface.

Behavior
  • Thread-based sessions: each Slack thread gets its own session, persisted across restarts
  • Streaming updates: the bot edits its "thinking" message in real-time as the LLM responds
  • Cancellation: starting a new prompt in the same thread cancels the previous one (5s timeout)
  • Session cache: LRU cache of 50 sessions, evicted on overflow

Building custom agents

The core.Run framework lets you build your own CLI agent with custom tools and interfaces.

package main

import (
    "context"
    "encoding/json"

    "github.com/3-lines-studio/mate/core"
    "github.com/3-lines-studio/mate/tools"
)

func main() {
    myTool := tools.DefineTool[struct {
        Name string `json:"name"`
    }](
        "greet",
        "Greet someone by name",
        map[string]any{
            "type": "object",
            "properties": map[string]any{
                "name": map[string]any{
                    "type":        "string",
                    "description": "Name to greet",
                },
            },
            "required": []string{"name"},
        },
        func(ctx context.Context, p struct{ Name string }) (string, error) {
            return "Hello, " + p.Name + "!", nil
        },
    )

    core.Run(core.Definition{
        Name:  "my-agent",
        Tools: []tools.Tool{myTool},
    })
}

This gives you a complete CLI with:

  • All standard tools (bash, read/write/edit, grep, glob)
  • Config file at ~/.config/my-agent/config.toml
  • --local flag for terminal mode, or the configured interface (Slack, etc.)
  • Session management, subagents, skills, and prompt templates
ToolConfig

For tools that need runtime configuration (API keys, store directories), use ToolConfig:

core.Run(core.Definition{
    Name: "scraper",
    ToolConfig: func(services map[string]map[string]any, storeDir, configDir string) []tools.Tool {
        return []tools.Tool{makeScraperTool(services["scraper"])}
    },
})

Services are configured in secrets.toml under [services]:

[services.scraper]
api_key = "..."

License

MIT — see LICENSE.

Directories

Path Synopsis
cmd
mate command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL