Pular para o conteúdo principal

De Assistente a Agente: Uma Mudanca de Paradigma

A maioria das ferramentas de IA para linha de comando funciona como assistentes: você pergunta, elas respondem. O ChatCLI vai alem, transformando a IA em um agente autônomo que não apenas responde, mas age. O sistema de Plugins e IA Agentiva materializa essa visão:
  • Você: Define o objetivo e fornece as ferramentas (plugins)
  • O Agente: Orquestra a execução, conectando percepcao, raciocinio e ação para resolver problemas complexos
Esta não e apenas uma funcionalidade — e a fundacao para um novo modo de interagir com seu ambiente de desenvolvimento.

Arquitetura do Sistema de Plugins

Descoberta e Carregamento Automático

O ChatCLI utiliza um gerenciador de plugins inteligente que:
1

Monitora o diretório

Monitora ~/.chatcli/plugins/ usando fsnotify
2

Detecta mudancas

Detecta mudancas em tempo real (criacao, modificacao, remocao de arquivos)
3

Aplica debounce

Aplica debounce de 500ms para evitar recarregamentos múltiplos
4

Valida o contrato

Válida o contrato de cada plugin antes de carrega-lo
5

Recarrega automaticamente

Recarrega automaticamente sem necessidade de reiniciar o ChatCLI
// Eventos que acionam hot reload:
// - Write:  Modificacao de arquivo existente
// - Create: Novo plugin adicionado
// - Remove: Plugin deletado
// - Rename: Plugin renomeado

Plugins Remotos (Server-Side)

Quando conectado a um servidor via chatcli connect, o client descobre automaticamente os plugins disponíveis no servidor. Esses plugins aparecem em /plugin list com a tag [remote] e são executados no servidor via gRPC — sem necessidade de instalar nada localmente.
> /plugin list
Plugins Instalados (12):
  @coder          - Suite de engenharia completa          [builtin]
  @read           - Leitura atômica de arquivo            [builtin]
  @search         - Busca regex em arquivos               [builtin]
  @tree           - Árvore de diretórios                  [builtin]
  @todo           - Plano de tarefas do agente            [builtin]
  @websearch      - Busca web (DuckDuckGo/SearxNG)        [builtin]
  @webfetch       - Fetch de páginas HTTP                 [builtin]
  @scheduler      - Scheduler durável de jobs             [builtin]
  @park           - Pausa o agente para retomar depois    [builtin]
  @hello          - Plugin de exemplo                    [local]
  @k8s-diagnose   - Diagnóstico de clusters K8s          [remote]
  @dockerhub      - Consulta tags do Docker Hub           [remote]
O agente pode usar plugins remotos da mesma forma que plugins locais — a execução e transparente. Ao desconectar, plugins remotos são removidos automaticamente da listagem.

Plugins Builtin

Alguns plugins essenciais já vem embutidos no binario do ChatCLI e aparecem com a tag [builtin]. Plugins builtin não precisam de instalação e não podem ser desinstalados. Se você instalar uma versão customizada em ~/.chatcli/plugins/ com o mesmo nome, ela prevalece sobre o builtin.
PluginDomínioDocumentação
@coderEngenharia completa (read, write, patch, multipatch, exec, test, git)Plugin @coder
@read, @search, @treeTools atômicos narrow para read-only opsTools Atômicos
@todoPlano de tarefas do agente (TodoWrite parity)Tools Atômicos
@websearch, @webfetchAcesso a web (DuckDuckGo/SearxNG + HTTP GET)Web Tools
@schedulerScheduler durável (schedule, wait, query, cancel)Scheduler
@parkPausa o agente para retomar (delay, until, for_url, for_cmd)Agent Park

Busca Flexivel de Plugins

O sistema aceita ambas as formas de invocação:
/agent @hello mundo
Internamente, o gerenciador normaliza automaticamente:
func (m *Manager) GetPlugin(name string) (Plugin, bool) {
    p, ok := m.plugins[name]
    if !ok {
        p, ok = m.plugins["@"+name]  // Fallback automático
    }
    return p, ok
}

Configuração do Agente

Variáveis de Ambiente

Configure o comportamento do agente através de variáveis de ambiente:
VariávelTipoPadrãoDescrição
CHATCLI_AGENT_PLUGIN_MAX_TURNSinteiro50Número máximo de iterações do ciclo ReAct. Evita loops infinitos (max: 200).
CHATCLI_AGENT_PLUGIN_TIMEOUTduracao15mTempo limite para execução de cada plugin. Aceita formato Go (30s, 5m, 1h).
CHATCLI_AGENT_CMD_TIMEOUTduracao10mTimeout para comandos shell executados via @command (max: 1h).
CHATCLI_AGENT_DENYLISTstring-Expressoes regulares separadas por ; para bloquear comandos perigosos.
CHATCLI_AGENT_ALLOW_SUDObooleanofalsePermite comandos sudo sem bloqueio automático (use com cautela).
CHATCLI_AGENT_PARALLEL_MODEbooleanofalseAtiva orquestracao multi-agent com agents paralelos.
CHATCLI_AGENT_MAX_WORKERSinteiro4Máximo de workers (goroutines) executando agents em paralelo.
CHATCLI_AGENT_WORKER_MAX_TURNSinteiro10Máximo de turnos do mini ReAct loop de cada worker agent.
CHATCLI_AGENT_WORKER_TIMEOUTduracao5mTimeout por worker agent individual.
Quando CHATCLI_AGENT_PARALLEL_MODE=true, o LLM orquestrador pode despachar 12 agents especialistas (FileAgent, CoderAgent, ShellAgent, GitAgent, SearchAgent, PlannerAgent, ReviewerAgent, TesterAgent, RefactorAgent, DiagnosticsAgent, FormatterAgent, DepsAgent) em paralelo. Veja a documentação completa.

O Ciclo ReAct: Raciocinio e Acao

O AgentMode implementa o framework ReAct (Reasoning and Acting), um loop iterativo transparente:
1

Raciocinio (Pensamento)

O agente analisa o objetivo e verbaliza seu plano:
<pensamento>
O objetivo e analisar a performance de uma função Go.
Isso requer profiling. Olhando minhas ferramentas, vejo
@go-bench-gen e @go-bench-run. O primeiro passo logico
e gerar o arquivo de benchmark.
</pensamento>
2

Acao (Chamada de Ferramenta)

A IA formaliza sua decisão em uma chamada estruturada:
<tool_call name="@go-bench-gen" args="main.go MinhaFunção" />
3

Execução (Invocação do Plugin)

O ChatCLI intercepta e executa o plugin:
Agente está usando a ferramenta: @go-bench-gen main.go MinhaFunção
   Timeout configurado: 15m
   Diretório: /home/user/projeto
4

Observacao (Feedback)

O resultado e formatado e retornado para a IA:
--- Resultado da Ferramenta ---
Arquivo gerado: main_bench_test.go
Benchmark criado: BenchmarkMinhaFunção
5

Reiteracao

O ciclo recomeca até que o objetivo seja alcancado ou o limite de turnos seja atingido.

Gerenciamento de Plugins com /plugin

Comandos Disponíveis

ComandoDescrição
/plugin listLista todos os plugins instalados com metadados
/plugin install <url>Instala plugin de um repositório Git (linguagens compilada)
/plugin show <nome>Exibe descrição e sintaxe de uso
/plugin inspect <nome>Mostra metadados brutos, caminho e permissões
/plugin uninstall <nome>Remove plugin do sistema
/plugin reloadForca recarregamento manual (raramente necessário)

Exemplo de Uso

> /plugin list
Plugins Instalados (3):
  @go-bench-gen  - Gera arquivos de benchmark Go
  @go-bench-run  - Executa benchmarks e profiling
  @dockerhub     - Consulta tags do Docker Hub

Instalação de Plugins

> /plugin install https://github.com/usuário/chatcli-plugin-k8s.git
Você está prestes a instalar código de terceiros que será executado em sua máquina. Revise o código-fonte antes de prosseguir.
Repositório: https://github.com/usuário/chatcli-plugin-k8s.git
Confirmar instalação? (s/N): s

Clonando repositório...
Detectado projeto Go, compilando...
Plugin @k8s instalado com sucesso!

Criando Plugins: O Guia Completo

O Contrato do Plugin

Todo plugin deve seguir estas regras:
1

Ser um Executável

  • Binario compilado (Go, Rust, C++) ou
  • Script com shebang (#!/usr/bin/env python3, #!/bin/bash)
  • Localizado em ~/.chatcli/plugins/
  • Permissao de execução obrigatoria (chmod +x)
ls -l ~/.chatcli/plugins/
-rwxr-xr-x  1 user  staff  2.3M  meu-plugin  # Correto (x = executável)
-rw-r--r--  1 user  staff  1.8M  outro       # Sem permissao de execução
2

Responder ao Contrato --metadata (Obrigatório)

Quando invocado com --metadata, o plugin DEVE imprimir um JSON válido para stdout:
{
  "name": "@meu-plugin",
  "description": "Descrição clara do que o plugin faz",
  "usage": "@meu-plugin <arg1> [--flag]",
  "version": "1.0.0"
}
Todos os campos são obrigatórios:
  • name: Deve comecar com @
  • description: Usado pela IA para decidir quando usar a ferramenta
  • usage: Sintaxe de invocação
  • version: Versionamento semantico
3

Implementar --schema (Opcional, mas Recomendado)

O schema ajuda a IA a entender os parâmetros do plugin:
{
  "parameters": [
    {
      "name": "cluster-name",
      "type": "string",
      "required": true,
      "description": "Nome do cluster Kubernetes"
    },
    {
      "name": "namespace",
      "type": "string",
      "required": false,
      "default": "default",
      "description": "Namespace alvo"
    }
  ]
}
4

Comunicação via I/O Padrão

CanalUsoDescrição
stdoutResultadoSaída principal enviada para a IA
stderrLogs/ProgressoMensagens de status, avisos e erros
stdinEntrada de dadosBlocos grandes de texto (ex: código gerado)
argsParâmetrosArgumentos de linha de comando
Regra de Ouro: stdout para apenas o resultado final, stderr para todo o resto (logs, progresso, erros).

Exemplo Completo: Plugin @hello em Go

Este exemplo demonstra todas as melhores praticas:
// ~/.chatcli/plugins-src/hello/main.go
package main

import (
    "encoding/json"
    "flag"
    "fmt"
    "os"
    "time"
)

// Metadata define a estrutura para --metadata
type Metadata struct {
    Name        string `json:"name"`
    Description string `json:"description"`
    Usage       string `json:"usage"`
    Version     string `json:"version"`
}

// Schema define a estrutura para --schema
type Schema struct {
    Parameters []Parameter `json:"parameters"`
}

type Parameter struct {
    Name        string `json:"name"`
    Type        string `json:"type"`
    Required    bool   `json:"required"`
    Description string `json:"description"`
    Default     string `json:"default,omitempty"`
}

// logf envia mensagens de progresso para stderr (visivel ao usuário)
func logf(format string, v ...interface{}) {
    fmt.Fprintf(os.Stderr, format, v...)
}

func main() {
    // Flags de descoberta
    metadataFlag := flag.Bool("metadata", false, "Exibe os metadados do plugin")
    schemaFlag := flag.Bool("schema", false, "Exibe o schema de parâmetros")
    flag.Parse()

    // Responder --metadata
    if *metadataFlag {
        meta := Metadata{
            Name:        "@hello",
            Description: "Plugin de exemplo que demonstra o fluxo stdout/stderr",
            Usage:       "@hello [seu-nome]",
            Version:     "1.0.0",
        }
        jsonMeta, _ := json.Marshal(meta)
        fmt.Println(string(jsonMeta)) // stdout para o ChatCLI
        return
    }

    // Responder --schema
    if *schemaFlag {
        schema := Schema{
            Parameters: []Parameter{
                {
                    Name:        "nome",
                    Type:        "string",
                    Required:    false,
                    Description: "Nome da pessoa a ser cumprimentada",
                    Default:     "Mundo",
                },
            },
        }
        jsonSchema, _ := json.Marshal(schema)
        fmt.Println(string(jsonSchema)) // stdout para o ChatCLI
        return
    }

    // Lógica principal do plugin
    logf("Plugin 'hello' iniciado!\n") // stderr = progresso visivel

    time.Sleep(2 * time.Second) // Simula trabalho
    logf("   Realizando uma tarefa demorada...\n")
    time.Sleep(2 * time.Second)

    name := "Mundo"
    if len(flag.Args()) > 0 {
        name = flag.Args()[0]
    }

    logf("Tarefa concluida!\n") // stderr = feedback de progresso

    // Resultado final para stdout (sera enviado para a IA)
    fmt.Printf("Ola, %s! A hora agora e %s.", name, time.Now().Format(time.RFC1123))
}

Compilacao e Instalação

1

Compilar

cd ~/.chatcli/plugins-src/hello
go build -o hello main.go
2

Dar permissao de execução (CRITICO!)

chmod +x hello
3

Mover para o diretório de plugins

mv hello ~/.chatcli/plugins/
4

Verificar instalação

> /plugin list
Plugins Instalados (1):
  @hello  - Plugin de exemplo que demonstra o fluxo stdout/stderr

Testando o Plugin

# Dentro do ChatCLI
> /agent @hello Edilson
# Saída no terminal (stderr):
Plugin 'hello' iniciado!
   Realizando uma tarefa demorada...
Tarefa concluida!
A IA responde com base no stdout do plugin. Exemplo: “O plugin retornou: Ola, Edilson! A hora agora e Mon, 02 Jan 2024 14:30:00 UTC.”

Debugging de Plugins

Execute /plugin list. Se o plugin não aparecer:
  1. Verifique permissões: ls -l ~/.chatcli/plugins/ — Deve mostrar -rwxr-xr-x (com ‘x’)
  2. Teste o contrato --metadata: ~/.chatcli/plugins/seu-plugin --metadata — Deve retornar JSON valido
  3. Ative logs de debug no .env:
LOG_LEVEL=debug
ENV=dev
Antes de usar no agente, teste diretamente:
  • Testar metadados: ~/.chatcli/plugins/seu-plugin --metadata
  • Testar schema: ~/.chatcli/plugins/seu-plugin --schema
  • Testar execução: ~/.chatcli/plugins/seu-plugin arg1 arg2
Se o plugin está sendo interrompido:
  • Aumentar timeout globalmente: export CHATCLI_AGENT_PLUGIN_TIMEOUT=30m
  • Ou no .env: CHATCLI_AGENT_PLUGIN_TIMEOUT=30m

Exemplo Avancado: Plugin Docker Hub

Este exemplo demonstra integração com API externa:
// chatcli-plugin-dockerhub/main.go
package main

import (
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "os"
    "strings"
    "time"
)

type Metadata struct {
    Name        string `json:"name"`
    Description string `json:"description"`
    Usage       string `json:"usage"`
    Version     string `json:"version"`
}

type DockerHubResponse struct {
    Results []struct {
        Name string `json:"name"`
    } `json:"results"`
}

func main() {
    if len(os.Args) > 1 && os.Args[1] == "--metadata" {
        meta := Metadata{
            Name:        "@dockerhub",
            Description: "Consulta tags disponíveis de uma imagem no Docker Hub",
            Usage:       "@dockerhub <imagem>",
            Version:     "1.0.0",
        }
        jsonMeta, _ := json.Marshal(meta)
        fmt.Println(string(jsonMeta))
        return
    }

    if len(os.Args) < 2 {
        fmt.Fprintln(os.Stderr, "Erro: Nome da imagem e obrigatório.")
        fmt.Fprintln(os.Stderr, "Uso: @dockerhub <imagem>")
        os.Exit(1)
    }

    imageName := os.Args[1]
    fmt.Fprintf(os.Stderr, "Consultando tags para '%s'...\n", imageName)

    // Chamada a API do Docker Hub
    url := fmt.Sprintf("https://hub.docker.com/v2/repositories/library/%s/tags?page_size=25", imageName)
    client := &http.Client{Timeout: 10 * time.Second}
    resp, err := client.Get(url)
    if err != nil {
        fmt.Fprintf(os.Stderr, "Erro na requisicao: %v\n", err)
        os.Exit(1)
    }
    defer resp.Body.Close()

    body, _ := io.ReadAll(resp.Body)
    var apiResponse DockerHubResponse
    if err := json.Unmarshal(body, &apiResponse); err != nil {
        fmt.Fprintf(os.Stderr, "Erro ao parsear resposta: %v\n", err)
        os.Exit(1)
    }

    // Extrair tags
    var tags []string
    for _, result := range apiResponse.Results {
        tags = append(tags, result.Name)
    }

    fmt.Fprintf(os.Stderr, "%d tags encontradas\n", len(tags))

    // Resultado final para stdout (para a IA)
    fmt.Println(strings.Join(tags, "\n"))
}

Caso de Uso

> /agent implante a ultima versão alpine do redis
O agente ira:
  1. Usar @dockerhub redis para listar tags
  2. Filtrar tags com “alpine”
  3. Selecionar a versão mais recente
  4. Executar docker run redis:<tag-alpine>
  5. Validar que o container está rodando

Linguagens Suportadas

Qualquer linguagem que possa criar um executável, interagir com I/O padrão (stdin/stdout/stderr) e processar argumentos de linha de comando.

Recomendações por Caso de Uso

LinguagemMelhor ParaVantagens
GoPlugins de produçãoBinarios estaticos, rapidos, portateis
RustPerformance críticaSegurança de memória, velocidade
PythonPrototipagem rapidaEcossistema rico, facil debugging
BashScripts de sistemaIntegração nativa com shell
Node.jsIntegração com APIsNPM, async/await

Segurança e Melhores Praticas

Validação de Entrada

Sempre valide argumentos antes de processar. Use os.Exit(1) para sinalizar erros ao ChatCLI.

Tratamento de Erros

Exit code diferente de 0 sinaliza erro para o ChatCLI. Envie mensagens de erro via stderr.

Timeouts Internos

Use context.WithTimeout para evitar que operações externas travem o plugin indefinidamente.

Logs Informativos

Envie progresso via stderr para que o usuário acompanhe a execução do plugin em tempo real.
// Validação de Entrada
if len(os.Args) < 2 {
    fmt.Fprintln(os.Stderr, "Erro: Argumentos insuficientes")
    os.Exit(1)
}

// Tratamento de Erros
if err != nil {
    fmt.Fprintf(os.Stderr, "Erro: %v\n", err)
    os.Exit(1) // Exit code != 0 sinaliza erro para o ChatCLI
}

// Timeouts Internos
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

Plugins no Modo /coder

O modo /coder e especializado em engenharia de software e utiliza o plugin @coder para executar suas ações. O @coder e um plugin builtin — já vem embutido no ChatCLI e funciona sem instalação. No /coder, a IA emite chamadas de ferramenta em um formato estrito:
  • Primeiro, escreve um bloco reasoning curto (2 a 6 linhas)
  • Em seguida, emite apenas um tool_call com args JSON
Exemplos de chamadas reais (que a IA emite no /coder):
<tool_call name="@coder" args='{"cmd":"tree","args":{"dir":"."}}'/>
<tool_call name="@coder" args='{"cmd":"read","args":{"file":"cli/agent_mode.go"}}'/>
<tool_call name="@coder" args='{"cmd":"test","args":{"dir":"."}}'/>
Veja mais em Modo Coder e Plugin @coder.

Próximos Passos

Exemplos de Plugins

Explore os plugins de exemplo no repositório

Crie seu Primeiro Plugin

Siga o template @hello nesta página para comecar

Compartilhe com a Comunidade

Publique plugins no GitHub para o ecossistema ChatCLI

Contribua

Contribua com plugins para o ecossistema ChatCLI

O sistema de plugins e a sua porta de entrada para a verdadeira automacao. Comece a construir suas ferramentas e transforme seu terminal em um colega de equipe.