@leo-cmp/l-nexus
v0.16.0
Published
Central portátil de configuração e diretrizes para agentes de IA — skills, roles, guidelines e templates versionados
Downloads
3,591
Maintainers
Readme
l-nexus
l-nexus é um kit de contexto portátil para agentes de IA (Claude, Gemini, Codex, Copilot). Skills, roles, guidelines e templates versionados — instaláveis em qualquer projeto com um comando.
npx @leo-cmp/l-nexus installO que vem no pacote
| Componente | Descrição |
|-----------|-----------|
| Roles | Backend, frontend, fullstack, database, QA, tech-lead, product-analyst, project-planner, model-router |
| Skills | Planejamento, execução, revisão, TDD, debugging sistemático, verificação de evidências, handoff e configuração CLI |
| Subagentes | Templates e protocolo de isolamento para research, coder, reviewer e qa-tester |
| Guidelines | Regras centrais, delegação por terminal CLI e práticas específicas de stacks |
| Templates | plan.md, task.md, task-short.md, issue-local.md |
| Roteamento & CLI Delegation | Complexidade L1-L3, risco R1-R3, slots default/alt1/alt2/alt3/upgrade_alt1/upgrade_alt2 com effort, runners configuráveis e revisão independente |
| Orquestração multi-LLM | Role orchestrator + skill lnx-orchestrator: delega executor, tester e reviewer em terminais visíveis, coleta resultados estruturados e aplica gates de rework/upgrade |
| MCP | context7, github, sequential-thinking, chrome-devtools, daisyui-github, nudge |
| Circuit breakers | Max 5 skills/sessão, max 3 tentativas/critério, max 10 arquivos/task, loop detection |
| Memória entre sessões | session-memory.md + decisions.md (zero dependência externa) |
Estado da orquestração multi-LLM (beta)
A camada de orquestração — role orchestrator, skill lnx-orchestrator,
lnx-run.sh/lnx-pty.py, terminais visíveis e --io broker — é beta na
v1.0.0. Ela funciona e tem cobertura de teste, mas foi exercitada num conjunto
pequeno de CLIs e de ambientes. Se causar problema, pode ser removida ou
redesenhada numa versão seguinte.
O que não é beta e continua estável: complexidade/risco, catálogo de modelos, validação de roteamento, revisão independente, guarda de conteúdo protegido, install/update. Um projeto pode adotar a v1.0.0 e simplesmente não usar o orquestrador.
O que pode mudar sem cerimônia enquanto estiver beta:
- as flags de
lnx-run.she o layout de.lnx/runtime/; - os campos
interactive,autonomyeterminal_runnersdo catálogo; - os detalhes do modo
--io broker.
O que não vai mudar sem migração: o schema 2 da task e do
model-routing.yaml, porque projetos guardam esses arquivos.
Instalação
npx @leo-cmp/l-nexus installAtualizar
Para atualizar o l-nexus para a versão mais recente em um projeto existente (recria .agents/ e .mcp.json sem alterar seus dados em .ai/):
npx @leo-cmp/l-nexus updateVindo de uma versão anterior à 1.0.0
O update traz os templates de task no schema 2, mas não toca no seu
.ai/model-routing.yaml — ele é do projeto. Enquanto o routing estiver no
schema 1, uma task criada pelo template novo falha na validação com
requires routing schema_version 2.
Migre o routing uma vez (simule primeiro, depois aplique):
npx @leo-cmp/l-nexus migrate-routing .ai/model-routing.yaml
npx @leo-cmp/l-nexus migrate-routing .ai/model-routing.yaml --writeA migração adiciona apenas o que o schema 2 exige, preserva todos os seus modelos, políticas e comentários, e imprime o que precisa de decisão humana — por exemplo, o piso do tester é herdado do executor (nunca mais fraco), e cabe a você baixá-lo se quiser um tester mais barato.
Tasks já existentes no schema 1 continuam válidas e não precisam migrar. Para
adotar os slots numa task antiga, use migrate-task <task> --to 2 --write.
Guarda de conteúdo protegido
Em um repositório Git, a instalação tenta ativar um hook pre-commit que impede
que deleções dos caminhos 🔒 sejam commitadas. Em .ai/decisions.md, a guarda
também impede que a quantidade de decisões (cabeçalhos que começam com ## ,
representados por ^## ) diminua; editar ou riscar uma decisão mantendo seu
cabeçalho continua permitido.
A guarda protege a história Git, não a árvore de trabalho. Se um processo apagar arquivos no disco, eles continuam ausentes até serem restaurados; a guarda impede que a perda staged vire commit. A preservação durante uma atualização é responsabilidade do instalador, enquanto a guarda funciona como uma rede de segurança para a história.
Desfaça primeiro apenas o staging:
git restore --staged -- <caminho>Restaure do último commit somente quando também quiser substituir o conteúdo da árvore de trabalho:
git restore --source=HEAD --staged --worktree -- <caminho>Uma remoção intencional pode ignorar a guarda uma vez:
git commit --no-verifyHooks pre-commit existentes nunca são sobrescritos. O mesmo vale quando
core.hooksPath aponta para fora do projeto: nesse caso, a instalação avisa e
não escreve no diretório externo. Para ativar a proteção, encadeie manualmente
.agents/hooks/lnx-guard.sh no hook efetivo.
O stub instalado no diretório efetivo de hooks falha de forma segura quando a
guarda versionada está ausente ou não é executável, inclusive durante uma
atualização concorrente. A mensagem de bloqueio informa o arquivo pre-commit
efetivo: use git commit --no-verify para liberar somente o commit atual ou,
se o l-nexus não estiver mais em uso, remova esse stub.
Em worktrees vinculadas, rode o instalador na worktree principal. Os hooks ficam
no diretório Git compartilhado e, instalados a partir da principal, protegem
todas as worktrees. Por serem compartilhados e fail-closed, eles também bloqueiam
commits em uma worktree irmã cuja branch não contenha .agents/; nesse caso, as
saídas explícitas são git commit --no-verify ou a remoção do stub compartilhado.
Estrutura instalada no projeto
🔒 Arquivos Locais do Projeto: Criados uma única vez e nunca sobrescritos pelo
npx update.
⚡ Componentes do Framework: Atualizados automaticamente pelonpx update.
projeto/
├── ⚡ AGENTS.md ← ponto de entrada do agente (instruções e atalhos)
├── ⚡ CLAUDE.md ← idêntico ao AGENTS.md
├── ⚡ GEMINI.md ← ponto de entrada fino p/ runtimes que leem GEMINI.md
│ (preservado se o projeto já tiver o seu)
├── .ai/
│ ├── 🔒 project.md ← contexto e escopo do projeto (preservado)
│ ├── 🔒 stack.md ← stacks ativas do projeto (preservado)
│ ├── 🔒 model-routing.yaml ← catálogo de modelos e runners de CLI locais (preservado)
│ ├── 🔒 session-memory.md ← memória e handoff entre sessões (preservado)
│ ├── 🔒 decisions.md ← registro de decisões arquiteturais do projeto (preservado)
│ ├── 🔒 guidelines/domain/ ← regras de negócio locais (preservado)
│ ├── ⚡ roles/ ← personas especializadas de IA (atualizado)
│ ├── ⚡ subagents/ ← templates e protocolo de subagentes (atualizado)
│ ├── ⚡ templates/ ← templates de plan, task e issues (atualizado)
│ └── ⚡ guidelines/
│ ├── core/ ← execution, planning, cli-delegation, testing, etc. (atualizado)
│ └── stacks/ ← diretrizes por stack: Laravel, Tailwind, DaisyUI, etc. (atualizado)
├── ⚡ .agents/
│ ├── hooks/
│ │ └── lnx-guard.sh ← guarda versionada de conteúdo protegido (atualizado)
│ ├── scripts/
│ │ ├── lnx-run.sh ← delegação supervisionada em terminal visível (atualizado)
│ │ └── lnx-pty.py ← supervisor de PTY: deixa o agente falar com o agente
│ └── skills/ ← skills de fluxo (lnx-*), gating (TDD, Debugging) e stacks
├── .lnx/runtime/ ← estado transitório de execução (git-ignored)
├── ⚡ .claude/
│ └── skills -> ../.agents/skills
└── ⚡ .mcp.json ← servidores MCP locaisO stub não versionado que chama a guarda não faz parte dessa árvore copiada: ele reside no diretório efetivo de hooks determinado pelo Git.
Atalhos do Agente (Slash Commands)
Organizados pela hierarquia /lnx-<recurso>-<ação>:
| Atalho | Ação |
|--------|------|
| /lnx-projeto-iniciar | Bootstrap de projeto novo (project.md, stack.md, regras) |
| /lnx-projeto-revisar | Scan e mapeamento automático de projeto existente |
| /lnx-projeto-atualizar | Sincronizar regras e stack do projeto |
| /lnx-plano-criar | Criar plano de fase local (plan.md) |
| /lnx-task-criar | Criar tarefa detalhada (task_X_Y.md) |
| /lnx-task-executar | Executar próxima tarefa do plano (encaminha para o orquestrador quando a task já está roteada) |
| /lnx-orchestrator | Coordenar executor → tester → reviewer em terminais visíveis, com rework e upgrade |
| /lnx-task-revisar | Revisão de diff da tarefa (auto-review) |
| /lnx-configurar-roteamento | Configurar interativamente model-routing.yaml e CLIs |
| /lnx-nexus-atualizar | Atualizar pacote l-nexus via npx @leo-cmp/l-nexus update |
| /lnx-prompt-gerar | Gerar prompt limpo para nova sessão |
| /lnx-brainstorm-lite | Brainstorming rápido (3 perguntas máx) |
Requisitos
- Node.js e npm/npx para instalação e validação estruturada das tasks
- Unix (Linux/macOS/WSL); Linux é o ambiente prioritário
- Python 3 (stdlib) para o modo
--io broker, que permite o Orchestrator conversar com os agentes que abriu. Sem ele, a delegação ainda funciona em--io tty(só leitura) ou--io pipe - Git + GitHub CLI (
gh) opcional para integração com issues/PRs
Ver MODEL_REQUIREMENTS.md para configurar perfis, avaliações e política de revisão.
Roteamento e Revisão
Cada task registra separadamente:
- complexidade de implementação (
L1,L2,L3); - risco de uma implementação incorreta (
R1,R2,R3); - classificação funcional (
work_type, categorias, tecnologias, capabilities); - o contrato de roteamento, com modelo + effort por slot;
- modelo que criou a task;
- modelo que realmente executou, com o slot usado e a CLI;
- execuções de teste e reviews, com o commit avaliado.
R3 sempre exige revisão independente. R2 segue
project_policy.r2_review em .ai/model-routing.yaml. O catálogo é do projeto:
o l-nexus fornece perfis e política, mas não presume que uma marca ou versão
seja permanentemente superior.
Slots de roteamento
O Planner escolhe e persiste na task, para o executor (e, quando o gate se aplica, para tester e reviewer):
| Slot | Significado |
|---|---|
| default | preferência normal |
| alt1, alt2, alt3 | alternativas laterais: indisponibilidade, rate limit, custo, provedor, especialização, preferência humana — não são retry; alt3 fecha a fila lateral, para modelos de cota curta |
| upgrade_alt1, upgrade_alt2 | escalada vertical: só depois de esgotar o rework ou quando a tarefa se revelar materialmente maior |
Cada slot carrega seu próprio effort (default, low, high, max), porque
modelo + effort é a unidade real de execução. A elegibilidade é resolvida por
profile_by_variant[effort]: o mesmo modelo pode ser elegível em high e
inelegível em low.
Neutralidade
A arquitetura é model-neutral, provider-neutral, CLI-neutral e terminal-adapter-aware:
ROLE → MODEL ROUTING (slot + effort) → CLI RUNNER → TERMINAL RUNNERNenhum runtime é o orquestrador oficial, nenhum modelo tem CLI fixa e nenhum
emulador de terminal está preso à arquitetura. Tudo isso é configuração em
.ai/model-routing.yaml, que pertence ao projeto. Um teste do próprio repositório
falha se um nome de modelo, provedor ou CLI vazar para o código.
Orquestração com terminais visíveis (Linux-first)
Quando uma task já tem roteamento, o lnx-orchestrator delega cada papel em uma
janela de terminal que você acompanha:
Terminal principal Orchestrator
Terminal visível Executor → Tester → Reviewer (um por vez, sequencial)A detecção percorre terminal_runners.preference (tmux, gnome-terminal,
konsole, xfce4-terminal, kitty, alacritty, wezterm, tilix, terminator, xterm…),
e um emulador fora da lista entra via --terminal-cmd sem alterar o l-nexus. Se
nenhuma janela puder ser aberta, o l-nexus não finge que abriu: ele bloqueia
com o motivo exato ou roda inline no terminal atual. Agente principal nunca roda
em background escondido (&, nohup).
O agente conduz o agente
O ponto da orquestração não é o humano digitar em várias janelas: é o Orchestrator abrir e conduzir os outros agentes, enquanto você assiste.
lnx-run.sh start ... --io broker --detach # abre e devolve o controle
lnx-run.sh send <run-dir> --text "REWORK: ..." # o Orchestrator digita
lnx-run.sh wait-idle <run-dir> --quiet-for 4 # espera ele parar de escrever
lnx-run.sh read <run-dir> --plain --tail 40 # e lê, sem escape codesNada disso espera um formato de resposta. Cada agente responde do seu jeito, e as instruções do próprio projeto mudam esse formato de novo — qualquer padrão de texto fixado no l-nexus quebraria em outro runtime. Por isso a conclusão é detectada por quietude do output, não por conteúdo.
Isso exige ser dono do PTY. Um pipe tira o TTY e o agente interativo não desenha
nada; script dá TTY mas não dá entrada; injetar em tty alheio precisaria do
ioctl TIOCSTI, desabilitado nos kernels atuais. Por isso o supervisor do
l-nexus (lnx-pty.py, stdlib do Python) segura o PTY master e multiplexa o
teclado do humano com um FIFO de controle. status informa can_send, e um
modo sem canal nunca finge que aceita instrução.
No rework, se a sessão do executor ainda está viva, o Orchestrator manda a correção para ela — o contexto é preservado e não nasce uma janela por tentativa.
A janela nunca fecha sozinha (--hold keep é o padrão); fechar
automaticamente é opt-in. Isso não atrasa gate nenhum, porque o start decide
pelo arquivo de estado e não pela vida da janela. Ao fechar, o supervisor
derruba o agente junto e grava o resultado; se ele for morto sem gravar,
status responde orphaned em vez de mentir running.
O agente delegado roda dentro do projeto, então lê o AGENTS.md e para antes de
um comando destrutivo. Mas quem está do outro lado do cano é o Orchestrator, uma
LLM — então ele nunca responde essa confirmação. Ele bloqueia e mostra ao
humano qual janela espera; o teclado do humano continua ligado à sessão, e ele
responde direto lá.
A janela é experiência de uso; o contrato é o diretório de execução:
.lnx/runtime/<task-id>/<run-id>/
meta.json status exit-code output.log prompt.txt command.txt
control.in (FIFO) result.yamlstatus e exit-code são escritos atomicamente, então o orquestrador sabe com
segurança quando o agente terminou e qual foi o resultado — sem depender de ler
o texto da tela.
Valide uma task contra a política do projeto:
npx @leo-cmp/l-nexus validate-task \
.planning/PLAN_VN/tasks/task_X_Y.md \
--final-commit "$(git rev-parse HEAD)"Plano congelado
Quem escreve a task congela o plano ao terminar:
npx @leo-cmp/l-nexus validate-task .planning/PLAN_VN/tasks/task_X_Y.md --write-plan-hashA flag grava model_plan.plan_hash, o sha256 de uma serialização canônica do
bloco sem o próprio campo. Sem isso, a validação é circular: ela confere a
execução contra o plano como o plano está na hora da validação, e quem
executa pode editar o plano para caber na própria escolha. Houve caso real —
cota do revisor esgotada, um slot alt2 acrescentado ao plano, o rationale
reescrito para justificá-lo, e o validador aprovando um gate que nunca existiu.
Plano sem plan_hash valida com aviso, para não quebrar task antiga. Plano
com plan_hash divergente é erro. Avisos saem em canal próprio e nunca
mudam o exit code.
Sozinho, o plan_hash seria convenção: quem pode rodar --write-plan-hash
edita o plano, regrava o hash e segue. Por isso o validador também usa git
como testemunha. Ele procura no histórico do arquivo a última versão commitada
antes de a execução ser registrada — o plano como estava quando o trabalho
começou — e compara com o plano atual. Regravar o hash não ajuda: a comparação é
de conteúdo, e o histórico não se deixa reescrever sem force-push.
Enquanto nenhum executor foi registrado, replanejar é livre: o Planner corrige o
plano quantas vezes precisar. Depois disso, divergência é erro. Sem
repositório, sem o arquivo versionado, ou sem nenhuma versão commitada anterior
ao registro de execução, sai aviso — não há testemunho, e fingir que há
seria pior. Para o humano que replanejou de propósito uma task já em execução,
--allow-replan rebaixa o erro a aviso.
Independência dos gates
Três regras tornam o gate difícil de encenar, e as três são erro:
- um modelo não pode ocupar dois papéis do mesmo
model_plan— repetir dentro de um papel é permitido, atravessar papéis não; - quem assinou o teste que passou no commit final não assina a revisão dele;
- em R3, revisor diferente do executor e, com
r3_cross_provider, de outro provedor.
Há ainda um aviso quando todos os slots de um papel de gate resolvem para o mesmo provedor: o papel não tem alternativa legítima, e foi exatamente assim que o caso real começou.
Prova de ocorrência
As regras acima conferem forma: se o registro está bem preenchido, se aponta
para um slot que existe, se o revisor difere de quem executou. Nenhuma delas
pergunta se a execução aconteceu — um agente pode escrever verdict: approved
sem jamais ter chamado revisor nenhum.
Quem responde isso é o lnx-run.sh. A cada execução delegada ele grava um
diretório com meta.json, exit-code e log. Quem escreve esse diretório é o
script, não o agente medido, e é aí que está a diferença.
Cada entrada de tests[] e reviews[] pode declarar o run_id daquela
execução. Quando declara, o validador abre o registro e confere que ele existe,
que é desta task (o que pega run_id copiado de outra), que papel, modelo,
effort, slot e runner batem com o que a linha afirma, e que há exit-code —
porque gate fechado por execução que talvez ainda esteja rodando não é gate.
Ausente é aviso, e só quando o gate é obrigatório. Divergente é erro.
Mentir custava uma linha de YAML; agora custa fabricar uma árvore de arquivos com carimbos que o agente não emite.
Há ainda uma camada acima: quem atendeu não é necessariamente quem foi
pedido. Uma CLI com fallback troca de modelo sozinha quando o primário está
sobrecarregado, e um proxy troca quando a cota acaba. Quando o runner sabe
reportar o modelo que respondeu, o lnx-run.sh grava esse valor e o validador
recusa a entrada que declara outro. Nem toda CLI sabe: por isso o observador é
configurável por runner, e um runner sem ele produz gate que vale menos — o que
deve ser dito, não disfarçado.
Limite declarado: .lnx/ não entra no git, então isso vale na máquina que
executou — que é onde o gate roda, mas significa que CI não reconfere depois.
Sincronizar o catálogo com o kit
O .ai/model-routing.yaml pertence ao projeto e nunca é sobrescrito: o
install só copia quando ele não existe, e o migrate-routing migra schema, não
conteúdo. O efeito colateral é que nada propagava catálogo — já aconteceu de
um projeto ficar sete modelos à frente do kit, com a sincronização feita à mão.
A causa é que o arquivo mistura quatro donos. models é do mundo; work_routes,
profiles, routes e execution_policy são do kit; project_policy e
risk_domains.project são do projeto; cli_runners, terminal_runners e
runner_policy descrevem a máquina. Para proteger as duas últimas categorias,
congelou-se o arquivo inteiro.
npx @leo-cmp/l-nexus sync-routing # dry-run: diz o que mudaria
npx @leo-cmp/l-nexus sync-routing --write # aplicaEle troca as duas primeiras categorias e não encosta nas outras duas. O dry-run é
o padrão e resume por chave — quais modelos entram, saem ou mudam — em vez de
despejar setecentas linhas de diff. Seção local que o kit desconhece fica intacta
e é anunciada. Schema divergente é recusado com o aviso de rodar o
migrate-routing antes.
Os comentários do kit viajam junto com as seções que ele governa: a justificativa de uma rota vale tanto quanto a rota.
Para converter o front matter de uma task legada sem inventar identidades de executor ou revisor, simule primeiro e aplique explicitamente:
npx @leo-cmp/l-nexus migrate-task .planning/tasks/TASK-001.md
npx @leo-cmp/l-nexus migrate-task .planning/tasks/TASK-001.md --writeA migracao marca a task como R3/legacy-unclassified ate reclassificacao e
revisao. O corpo Markdown nao e alterado.
Para adotar os slots do schema 2 em uma task existente:
npx @leo-cmp/l-nexus migrate-task .planning/tasks/TASK-001.md --to 2 --writeA migracao reformata a task mas nao inventa modelo nem effort: ela marca
needs_manual_routing: true e o validador reprova ate um humano completar o
roteamento e remover a marca. Tasks no schema 1 continuam validas sem migrar.
Versão
A versão publicada está em VERSION e nas tags do repositório.
