Uma arquitetura robusta, assíncrona e orientada a eventos para orquestração de Modelos Fundacionais Locais e em Nuvem via CLI.
O Council é um orquestrador CLI construído do zero em Python, que projeta um consenso automatizado (Multi-Agent System) entre instâncias distintas de LLMs. Em vez de depender de pesadas bibliotecas de abstração de IA (como LangChain ou AutoGen), o Council adota uma abordagem de infraestrutura agnóstica, conectando-se diretamente a ferramentas bash/CLIs independentes (claude, gemini, codex, ollama) e também a providers via API (ex: deepseek) de forma uniforme no fluxo.
Este projeto é um laboratório prático de Engenharia de Software e Arquitetura de Sistemas, demonstrando forte domínio em gerenciamento de processos do Sistema Operacional, manipulação de streams de dados IO sem bloqueio, e desenvolvimento de interfaces ricas baseadas em terminal (TUI).
O fluxo de agentes é configurável por arquivo JSON, permitindo que cada time defina qual IA assume cada papel (planejamento, crítica, implementação, revisão etc.) sem editar o código-fonte.
Guia para contribuir com o projeto: CONTRIBUTING.md.
Guia completo de instalação e operação (setup end-to-end): docs/SETUP.md.
O desenvolvimento do Council focou-se na resiliência e na separação de responsabilidades (SoC), abordando os seguintes desafios técnicos complexos:
Chamadas a LLMs são bloqueantes por natureza. Pípes padrão (como subprocess.communicate()) fariam o programa refém do tempo de geração do modelo, ofuscando e limitando o feedback visual do terminal.
- A Solução: Implementou-se uma leitura em tempo real (linha por linha, sem buffer) do descritor de arquivo
stdoutda ferramenta externa. Utilizando iteradores de leitura passados a callbacks injetados, construiu-se uma ponte limpa entre o modelo rodando no kernel (filho) e a interface do usuário (pai), permitindo exibição doLive Streamna tela milissegundos após o token ter sido retornado pelo LLM.
Como CLIs são stateless, cada chamada a um agente esquece a iteração isolada do agente anterior.
- A Solução: Uma classe de domínio
CouncilStategerencia a Memória da aplicação, encapsulando coleções de Turns e injetando na estrutura das prompts dinamicamente os cabeçalhos de papel e as respostas consolidadas de execuções anteriores no subshell, forçando a preservação do escopo do pipeline.
CLIs complexos detectam a presença do shell tty nativo. Invocações programáticas causam falhas como "stdin is not a terminal" se manuseadas incorretamente, além de interrupções por agentes tentando pedir validação do humano na tela.
- A Solução: Engenharia reversa para envio de metadados invisíveis/parametrizadores (ex: flags
-p, ou subcomandos headless comoexec) isolando e castrando os módulos gráficos ou de aprovação (Yolo Mode programático), forçando os clients a interpretarem o programa Python em canais canônicos absolutos de texto limpo. Fechamento proativo de buffers (stdin.close()) forçando envio EOF para evitar pipelines corrompidos (Dangling processes).
A biblioteca rich e o typer compõem a porta de entrada.
- A Solução: Emprego extensivo de
@contextmanagerpara isolar fluxos UI. Um Painel Dinâmico é capaz de renderizar as últimasNlinhas emitidas de um LLM como tela de log e se auto-destruir de forma limpa (transient=True), sendo trocado perfeitamente pelo Syntax Highlighter demarkdownpara a versão imutável do log validado. Tudo através de injeção de dependência rudimentar do injetor raiz (Orchestrator(state, executor, ui)).
| Tecnologia | Função no Projeto |
|---|---|
| Python 3.10+ | Core languange focado em Type Hinting modernos (typing_extensions.Annotated). |
| Typer | Roteamento nativo e performático de argumentos via Python types. |
| Rich | Controle de Buffer de frame do Terminal (Painéis, Syntax Highlighting, Spinners, Live Updates). |
| Textual | Interface TUI interativa para executar o mesmo fluxo multimodelo com painel de stream e resultados. |
| Subprocess | Integração em baixo nível de Pipes SO Popen (stdin, stdout, stderr). |
| OOP / SOLID | Padrões de classes dedicados a Responsabilidade Única (UI, Estado, Execução Pura). |
Por padrão, o Orchestrator executa a seguinte topologia seqüencial em pipeline para processamento da entrada:
Claude[Arquitetura]: Planeja os diagramas lógicos a partir do input primitivo.Gemini[Critique]: Audita as fragilidades, segurança falha e complexidades excessivas (Big-O).Claude[Consolidation]: Refatora as fraquezas sistêmicas do design original.Codex[Engineer]: Converte a macro visão consolidada em código-fonte direto ao ponto.Gemini[Reviewer]: Inspeciona falhas sintáticas ou de coesão, fechando o loop.
Se necessário, esse pipeline pode ser sobrescrito via --flow-config ou COUNCIL_FLOW_CONFIG.
O passo a passo completo da feature está em docs/FLOW_CONFIG.md.
Visão de execução ponta-a-ponta com diagrama Mermaid: docs/APPLICATION_FLOW.md.
Regras de seguranca aplicadas ao flow.json (campo command):
- O binario/provedor (primeiro token) precisa estar na allowlist:
claude,gemini,codex,ollama,deepseek. - Para comandos CLI, o binario precisa existir no
PATH. - Exceção:
deepseeké provider API-only (não requer binário local). - O primeiro token deve ser apenas nome de binario (caminho explicito como
/usr/bin/codexe bloqueado). - O parser rejeita
\n/\re operadores de shell perigosos (|,&&,;,`,$(,>,>>). - Fluxos de origem nao confiavel ainda exigem cautela, pois comandos allowlisted continuam executando no host local.
Provider DeepSeek (API):
- Use no
command:deepseek --model deepseek-chat(oudeepseek --model deepseek-reasoner). - Defina
DEEPSEEK_API_KEYno ambiente. - Opcional: sobrescreva endpoint com
DEEPSEEK_API_BASE_URL.
Resumo rápido:
- Crie seu fluxo com o editor visual (TUI) interativo ou o modo terminal assistido:
council flow edit flow.meu.json --editor tui
# ou
council flow edit flow.meu.json --editor simpleAlternativa manual: copie a partir do modelo base cp flow.example.json flow.meu.json e faça o parsing.
-
Ajuste o mapeamento de papéis para as IAs no JSON.
-
Execute com configuração customizada:
council run "Seu prompt" --flow-config flow.meu.json- Ou defina globalmente por ambiente:
export COUNCIL_FLOW_CONFIG=flow.meu.json
council run "Seu prompt"O ambiente não exige o uso do LangChain. O Council funciona com provedores definidos no seu flow.json, combinando CLIs locais (no PATH) e providers via API (ex: deepseek com DEEPSEEK_API_KEY).
# Geração do ambiente virtual restrito e ativado
python3 -m venv venv
source venv/bin/activate
# Instalação do pacote e dependências via pyproject
pip install -e .
# Dispara a orquestração enviando o STDIN global para os sub-nós
council run "Crie um algoritmo distribuido de map-reduce"
# Dispara com fluxo customizado (escolhendo IAs/papéis livremente)
council run "Crie um algoritmo distribuido de map-reduce" --flow-config flow.example.json
# Abre a TUI interativa (Textual) para rodar os fluxos
council tui
# Abre o Editor TUI para modificar a estrutura do fluxo (papéis, configs e prompts)
council flow edit flow.meu.json --editor tui
# Diagnostico explicito dos pré-requisitos exigidos pelo fluxo
council doctorOpcional com direnv (autoativação da venv ao entrar no diretório):
direnv allow
# opcional: cp .envrc.local.example .envrc.localNa TUI, cada etapa possui checkpoint humano: você pode continuar, enviar ajuste para o mesmo agente (reexecução) ou abortar o fluxo.
Detalhes completos de uso da TUI, atalhos, abas por etapa, persistência e cópia estão em docs/OPERATIONS.md.
- O estado da TUI fica em
~/.config/council/tui_state.json(ou equivalente viaCOUNCIL_HOME). - Esse arquivo armazena
last_flow_confige pode armazenar histórico de prompts (last_prompteprompt_history). - Para limpar dados sensíveis explicitamente:
council history clear- Para habilitar criptografia at-rest do histórico de prompts, defina uma senha no ambiente:
pip install -e ".[security]"
export COUNCIL_TUI_STATE_PASSPHRASE="sua-senha-forte"- Quando
COUNCIL_TUI_STATE_PASSPHRASEestiver definido, prompts não são persistidos em texto plano. - Para reduzir exposição da senha em ambientes sensíveis, use arquivo de segredo:
printf '%s' 'sua-senha-forte' > ~/.config/council/passphrase.txt
chmod 600 ~/.config/council/passphrase.txt
export COUNCIL_TUI_STATE_PASSPHRASE_FILE=~/.config/council/passphrase.txt- O Council persiste execuções completas em
COUNCIL_HOME/db/history.sqlite3(prompt, steps, outputs, duração e timestamps). - O arquivo do banco é endurecido com permissão
0o600e o diretórioCOUNCIL_HOME/dbcom0o700quando suportado pelo host. - Para inspecionar rapidamente os últimos runs:
council history runs --limit 20- O Council registra eventos de execução em
COUNCIL_HOME/council.logcom timestamp, nível e payload estruturado. - O arquivo de log usa permissão
0o600eCOUNCIL_HOMEé endurecido para0o700quando suportado pelo host. - O nível mínimo de log é configurável por
COUNCIL_LOG_LEVEL(DEBUG,INFO,WARNING/WARN,ERROR,CRITICAL). Valor inválido falha explicitamente. - Rotação por tamanho disponível via
COUNCIL_LOG_MAX_BYTES(default5242880) eCOUNCIL_LOG_BACKUP_COUNT(default5). - Valores inválidos em
COUNCIL_LOG_LEVEL,COUNCIL_LOG_MAX_BYTESouCOUNCIL_LOG_BACKUP_COUNTfalham na inicialização dos comandos (run,tui,doctor). - O comando
council doctortambém gera eventos de auditoria (invocação, warnings e resultado).
Para usar o Council em qualquer diretório sem levar os arquivos do projeto, instale como aplicativo de linha de comando:
pipx install .Depois disso, use:
council run "Seu prompt"
council tui
council flow edit
council doctorcouncil run e TUI fazem preflight automatico dos binarios do fluxo antes da orquestracao.
Resolução automática de fluxo quando --flow-config não for informado:
COUNCIL_FLOW_CONFIG./flow.json(diretório atual)~/.config/council/flow.json(ou equivalente no seu SO)- fluxo interno default
Construído com base em design system limpo de código e arquitetura adaptável.