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: voce pergunta, elas respondem. O ChatCLI vai alem, transformando a IA em um agente autonomo que nao apenas responde, mas age. O sistema de Plugins e IA Agentiva materializa essa visao:
  • Voce: Define o objetivo e fornece as ferramentas (plugins)
  • O Agente: Orquestra a execucao, conectando percepcao, raciocinio e acao para resolver problemas complexos
Esta nao 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 Automatico

O ChatCLI utiliza um gerenciador de plugins inteligente que:
1

Monitora o diretorio

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 multiplos
4

Valida o contrato

Valida 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 disponiveis no servidor. Esses plugins aparecem em /plugin list com a tag [remote] e sao executados no servidor via gRPC — sem necessidade de instalar nada localmente.
> /plugin list
Plugins Instalados (4):
  @coder          - Suite de engenharia completa          [builtin]
  @hello          - Plugin de exemplo                    [local]
  @k8s-diagnose   - Diagnostico de clusters K8s          [remote]
  @dockerhub      - Consulta tags do Docker Hub           [remote]
O agente pode usar plugins remotos da mesma forma que plugins locais — a execucao e transparente. Ao desconectar, plugins remotos sao removidos automaticamente da listagem.

Plugins Builtin

Alguns plugins essenciais ja vem embutidos no binario do ChatCLI e aparecem com a tag [builtin]. O principal e o @coder, que fornece a suite de engenharia para o modo /coder. Plugins builtin nao precisam de instalacao e nao podem ser desinstalados. Se voce instalar uma versao customizada em ~/.chatcli/plugins/ com o mesmo nome, ela prevalece sobre o builtin.

Busca Flexivel de Plugins

O sistema aceita ambas as formas de invocacao:
/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 automatico
    }
    return p, ok
}

Configuracao do Agente

Variaveis de Ambiente

Configure o comportamento do agente atraves de variaveis de ambiente:
VariavelTipoPadraoDescricao
CHATCLI_AGENT_PLUGIN_MAX_TURNSinteiro50Numero maximo de iteracoes do ciclo ReAct. Evita loops infinitos (max: 200).
CHATCLI_AGENT_PLUGIN_TIMEOUTduracao15mTempo limite para execucao 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 automatico (use com cautela).
CHATCLI_AGENT_PARALLEL_MODEbooleanofalseAtiva orquestracao multi-agent com agents paralelos.
CHATCLI_AGENT_MAX_WORKERSinteiro4Maximo de workers (goroutines) executando agents em paralelo.
CHATCLI_AGENT_WORKER_MAX_TURNSinteiro10Maximo 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 documentacao 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 funcao 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 decisao em uma chamada estruturada:
<tool_call name="@go-bench-gen" args="main.go MinhaFuncao" />
3

Execucao (Invocacao do Plugin)

O ChatCLI intercepta e executa o plugin:
Agente esta usando a ferramenta: @go-bench-gen main.go MinhaFuncao
   Timeout configurado: 15m
   Diretorio: /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: BenchmarkMinhaFuncao
5

Reiteracao

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

Gerenciamento de Plugins com /plugin

Comandos Disponiveis

ComandoDescricao
/plugin listLista todos os plugins instalados com metadados
/plugin install <url>Instala plugin de um repositorio Git (linguagens compilada)
/plugin show <nome>Exibe descricao e sintaxe de uso
/plugin inspect <nome>Mostra metadados brutos, caminho e permissoes
/plugin uninstall <nome>Remove plugin do sistema
/plugin reloadForca recarregamento manual (raramente necessario)

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

Instalacao de Plugins

> /plugin install https://github.com/usuario/chatcli-plugin-k8s.git
Voce esta prestes a instalar codigo de terceiros que sera executado em sua maquina. Revise o codigo-fonte antes de prosseguir.
Repositorio: https://github.com/usuario/chatcli-plugin-k8s.git
Confirmar instalacao? (s/N): s

Clonando repositorio...
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 Executavel

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

Responder ao Contrato --metadata (Obrigatorio)

Quando invocado com --metadata, o plugin DEVE imprimir um JSON valido para stdout:
{
  "name": "@meu-plugin",
  "description": "Descricao clara do que o plugin faz",
  "usage": "@meu-plugin <arg1> [--flag]",
  "version": "1.0.0"
}
Todos os campos sao obrigatorios:
  • name: Deve comecar com @
  • description: Usado pela IA para decidir quando usar a ferramenta
  • usage: Sintaxe de invocacao
  • version: Versionamento semantico
3

Implementar --schema (Opcional, mas Recomendado)

O schema ajuda a IA a entender os parametros 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

Comunicacao via I/O Padrao

CanalUsoDescricao
stdoutResultadoSaida principal enviada para a IA
stderrLogs/ProgressoMensagens de status, avisos e erros
stdinEntrada de dadosBlocos grandes de texto (ex: codigo gerado)
argsParametrosArgumentos 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 usuario)
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 parametros")
    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
    }

    // Logica 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 Instalacao

1

Compilar

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

Dar permissao de execucao (CRITICO!)

chmod +x hello
3

Mover para o diretorio de plugins

mv hello ~/.chatcli/plugins/
4

Verificar instalacao

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

Testando o Plugin

# Dentro do ChatCLI
> /agent @hello Edilson
# Saida 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 nao aparecer:
  1. Verifique permissoes: 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 execucao: ~/.chatcli/plugins/seu-plugin arg1 arg2
Se o plugin esta 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 integracao 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 disponiveis 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 obrigatorio.")
        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 versao alpine do redis
O agente ira:
  1. Usar @dockerhub redis para listar tags
  2. Filtrar tags com “alpine”
  3. Selecionar a versao mais recente
  4. Executar docker run redis:<tag-alpine>
  5. Validar que o container esta rodando

Linguagens Suportadas

Qualquer linguagem que possa criar um executavel, interagir com I/O padrao (stdin/stdout/stderr) e processar argumentos de linha de comando.

Recomendacoes por Caso de Uso

LinguagemMelhor ParaVantagens
GoPlugins de producaoBinarios estaticos, rapidos, portateis
RustPerformance criticaSeguranca de memoria, velocidade
PythonPrototipagem rapidaEcossistema rico, facil debugging
BashScripts de sistemaIntegracao nativa com shell
Node.jsIntegracao com APIsNPM, async/await

Seguranca e Melhores Praticas

Validacao 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 operacoes externas travem o plugin indefinidamente.

Logs Informativos

Envie progresso via stderr para que o usuario acompanhe a execucao do plugin em tempo real.
// Validacao 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 acoes. O @coder e um plugin builtin — ja vem embutido no ChatCLI e funciona sem instalacao. 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.

Proximos Passos

Exemplos de Plugins

Explore os plugins de exemplo no repositorio

Crie seu Primeiro Plugin

Siga o template @hello nesta pagina 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.