CommunityEscrita e Ediçãogithub.com

agent-sync

Vários agentes de código, um repositório, sem colisões — leases com TTL, reserva de ID livre de race condition, diário de execução e um quadro gerado sobre uma nuvem de conhecimento conectável. Incluído no pacote sshlg-skills.

O que é agent-sync?

O agent-sync é uma skill para ferramentas como Claude Code que resolve o problema fundamental de múltiplos agentes de IA trabalhando concorrentemente no mesmo repositório Git. Ele estabelece uma separação clara entre o plano de registro (Git) e o plano de coordenação (uma nuvem de conhecimento flexível), garantindo que fatos duráveis sejam sempre escritos primeiro no Git, enquanto informações sobre quem está fazendo o que agora são mantidas na nuvem com expiração automática (TTL). A skill oferece um sistema de leases seguro usando diferentes backends (local, Git ou nuvem), reserva de IDs sem race condition, journaling de execução, e guarda de arquivos compartilhados. Suporta Claude Code e outras plataformas, com hooks automáticos para Claude Code e modo 'ungated' para outras. Inclui comandos como `acquire`, `release`, `reserve`, `guard`, `status` e `check`, que juntos garantem que nenhum agente sobrescreva trabalho de outro, mesmo operando em paralelo entre máquinas.

Funciona com✓Claude Code~Codex CLI~Cursor
npx skills add ssheleg/agent-sync

Installed? Explore more Escrita e Edição skills: steipete/notion, langchain-ai/langchain, bytedance/podcast-generation · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

agent-sync — um projeto, muitos agentes, sem colisões

Dois planos e uma regra entre eles:

O Git é o plano de registro. A nuvem é o plano de coordenação. Um fato que deve sobreviver é escrito no Git primeiro e referenciado a partir da nuvem. Um fato sobre quem está fazendo o que agora vive na nuvem e expira.

Nenhum objeto na nuvem é o único lar de um fato durável. Tudo abaixo existe para manter isso verdade enquanto vários agentes escrevem ao mesmo tempo.

Quatro armadilhas — leia estas antes de qualquer outra coisa

1. A base de conhecimento nunca decide um lease. Ela não pode: doze anexos simultâneos a um documento do Outline retornaram doze sucessos e deixaram três linhas. Exclusão vem de algo com compare-and-swap real. O plano carrega o registro e nada mais. Medições completas em references/lease-protocol.md.

2. Saiba qual lease você tem e diga qual é. leaseBackend: "local" é uma criação de arquivo atômica — exclusiva entre processos em um sistema de arquivos, consultiva entre máquinas. leaseBackend: "git" empurra uma ref, e a rejeição de non-fast-forward do remoto é um compare-and-swap — exclusiva entre máquinas. acquire imprime qual. Um lease fingido é pior que nenhum lease: o outro agente para de verificar.

acquire também escreve a reivindicação no roadmap, e release restaura exatamente o que estava lá — uma linha, uma célula, recusado em caso de ambiguidade, git diff vazio após uma iteração. Leia references/roadmap.md antes de configurar claimTags ou fechar uma tarefa; fechar é uma declaração sobre o trabalho e continua sendo sua.

Trabalhe em um branch; o branch de integração é a base estável de outra pessoa. acquire escreve a reivindicação apenas lá; em qualquer outro branch, o titular permanece no plano de coordenação, onde status mostra a todos sem que ninguém precise buscar seu branch. Comprometido em um branch, uma reivindicação é invisível até o merge e transforma o roadmap compartilhado em um arquivo que dois branches editam. Finalize o trabalho com merge: conflitos calculados por git merge-tree antes que qualquer coisa seja tocada, nomeados e recusados se houver algum, o merge registrado em docs/MERGES.md (dias recentes completos, mais antigos compactados na escrita), o lease --key liberado. merges informa ao próximo agente o que chegou enquanto ele estava fora. Leia references/branching.md antes de fazer merge.

3. Hooks existem apenas no Claude Code. Em outros lugares, nada bloqueia uma edição guardada: execute guard você mesmo e registre a execução como ungated. Não descreva um projeto como protegido quando não está.

4. Analise liberalmente e nunca chame um log ilegível de uma corrida perdida. O armazenamento reescreve o que você escreveu — o Outline transforma um bullet - em * . Emita - , aceite -/*/+, conte qualquer coisa em formato de entrada que falhe e falhe ruidosamente acima de 2% não analisável. Relatar lost quando a verdade é ilegível nomeia um titular que não existe. Cuidado com um pré-filtro silencioso: um continue antes da regex esconde linhas ruins do contador criado para expô-las.

Trazendo isso para QUALQUER projeto — a cadeia completa

scaffold  → criar a arquitetura de documentação, apenas onde ela está ausente
adopt     → ler o repositório, propor uma configuração, não escrever nada
init      → escrever a configuração aprovada + o arquivo env ignorado pelo git
            (o operador cola o token — nunca você)
reconcile --set-baseline    → transformar o histórico em um backlog contado, uma vez
setup     → gerar o snapshot que descreve a fiação deste projeto
check     → validar tudo; não zero se não estiver saudável

check é o que torna a skill autossuficiente. Ela se recusa a chamar uma configuração saudável em uma regra que não protege nada (um registro, glob de guarda, padrão de reivindicação, gate ou fonte de mirror apontando para algo que não existe), em credenciais ausentes, em um arquivo env rastreado pelo git — o único erro irrecoverável aqui — em um snapshot desatualizado ou desconectado, e em um registro sem baseline. Ela nomeia cada um; todos falharam de verdade durante a adoção desta própria ferramenta.

Execute check após adotar, após alterar a configuração e no CI.

scaffold nunca sobrescreve. Ela sementeia um registro de decisão com uma linha de alocação e um AGENTS.md que aponta para o snapshot, e deixa todos os arquivos existentes intocados — uma ferramenta que reescreve as próprias convenções de um projeto na adoção é pior do que uma que não faz nada.

Projeto existente: comece com adopt

Execute adopt antes de init. Ela lê o repositório e imprime o que encontrou — registros de id, arquivos de registro, gates — mais as decisões que se recusa a tomar por você — e então propõe uma configuração.

python3 "$SKILL_DIR/scripts/agent_sync.py" adopt

Confirme os registros e arquivos guardados com o operador primeiro: um registro apontado para o arquivo errado torna cada verificação posterior confiantemente errada, e uma lista guardada que perde um arquivo compartilhado deixa o único lugar onde colisões acontecem desprotegido. Em um submódulo, ele não declara registros: as decisões pertencem ao repositório pai. Em seguida, siga a cadeia acima a partir de init.

Primeiro comando em um projeto: init

Nunca execute mais nada contra um projeto não inicializado. init é onde a pergunta de armazenamento é feita e respondida, uma vez, e registrada.

Pergunte ao operador estas duas coisas no chat — não adivinhe, não escolha um padrão:

  1. Onde o estado de coordenação deve viver?

    • Uma nuvem de conhecimento (outline) — o registro compartilhado, a conscientização e o quadro entre máquinas. Ela não decide leases; nada nela pode (armadilha 1);
    • Ou arquivos locais (fs) — sem credenciais e sem visibilidade para um agente em outra máquina: sem conscientização compartilhada, sem sinais entre repositórios, sem quadro compartilhado.

    O lease é decidido separadamente por leaseBackend (armadilha 2), e gated segue essa escolha, nunca o plano de registro. Relate a garantia que você realmente tem, não a mais forte que o plano de registro sugere.

  2. Se nuvem: a URL da instância. A URL é configuração, não um segredo, então você pode escrevê-la. O token não é — você nunca pergunta por ele no chat, nunca o lê de volta e nunca o coloca você mesmo.

Em seguida, execute-o com as respostas deles:

python3 "$SKILL_DIR/scripts/agent_sync.py" init --backend outline --url https://<instancia-deles>
python3 "$SKILL_DIR/scripts/agent_sync.py" init --backend fs

init escreve .claude/agent-sync.json (forma, comprometido), escreve .env.agent-sync com as chaves e uma linha de token vazia (identidade, modo 600), adiciona .env.agent-sync e .agent-sync/ ao .gitignore, e então imprime exatamente o que o operador deve fazer sozinho — criar o token em sua própria instância e colá-lo naquela linha. Nunca sobrescreve uma configuração ou arquivo env existente sem --force.

Transmita essas instruções finais ao operador literalmente. Colocar o token no arquivo é a etapa deles, e o design depende de que ele permaneça sendo deles.

Então, antes de cada sessão

python3 "$SKILL_DIR/scripts/agent_sync.py" status

Idempotente. Inspeciona, repara, relata, nomeia exatamente UMA próxima ação — e carrega o veredito de check, para que o comando que toda sessão executa e aquele que valida a configuração não possam dar duas respostas sobre um projeto.

Leia as duas seções de conscientização que ele imprime — elas são o ponto, não decoração.

  • Outras execuções trabalhando neste projeto agora. Quem detém o quê, neste minuto. Não assuma essas tarefas e não "apenas dê uma olhada" nos arquivos que eles cobrem. Um lease que você não pode ver o bloqueia; um lease que você pode ver o coordena.
  • Novo desde a última vez que você olhou. Movimentos de dependência entre repositórios que chegaram enquanto você estava fora. Uma dependência que se moveu pode desbloquear o que você planejou — ou invalidá-lo. Esta lista é marcada por execução, então permanece silenciosa até que algo realmente mude; quando fala, importa.

Um agente que pula este bloco redescobrirá trabalho que outra pessoa está fazendo e agirá com base em um estado de dependência que mudou há uma hora.

O que mais status decide: sem credenciais → modo degradado, relatado, e continua (um modo menor, não um erro); task-pipeline ausente → imprime a linha de instalação e para. Não improvise um fluxo substituto — sem esses estágios não há nada para se vincular.

npx sshlg-skills install

Os comandos

ComandoFaz
initExecute primeiro. Pergunte onde o estado vive, escreva config + arquivo env ignorado pelo git, imprima o passo do operador
statusInspecione, repare, relate, nomeie uma próxima ação
bootstrapCrie o contêiner da nuvem e imprima o id para colar no arquivo env
acquire <KEY>Pegue o lease em um id de tarefa. Imprime won ou lost <holder>
renew <KEY>Estenda o lease. O hook PostToolUse faz isso por você
release <KEY>Devolva o lease. Sempre faça isso, inclusive em caso de falha
reserve <REG>Reserve o próximo id em um registro (DEC, OQ, DEP, …). Imprime o id
release-id <REG> <ID>Devolva um id que você não acabou escrevendo no git
journal <text>Adicione uma linha ao diário desta execução
record <text>Adicione o que você realmente construiu — --decision DEC-…, --files a,b
reconcileIntenção (git) vs construído (nuvem). --set-baseline uma vez por projeto
signal <DEP-ID> <state>Mova uma dependência entre repositórios: filed/accepted/delivered/closed/refused
guard <path>Responda se esta execução pode escrever naquele caminho. Saída 0 = sim, 2 = não
boardRegere o quadro compartilhado e a página deste repositório. --mirror também renderiza os documentos git configurados no plano
whoamiImprima o id desta execução e seus leases mantidos
setupEscreva o snapshot gerado de como este projeto está conectado, para os agentes lerem
adoptInspecione um projeto existente e proponha uma configuração — não escreve nada
mergeFinalize este branch: alvo local fast-forwarded, conflitos verificados antes que qualquer coisa seja tocada, log de merge escrito, o lease --key liberado. --summary, --dry-run, --push
mergesO que chegou enquanto você estava no seu branch. --all inclui a cauda compactada
checkValide toda a configuração de ponta a ponta. Não zero quando não está saudável
scaffold [--full]Crie apenas o que está faltando, nunca uma linha sobre algo que existe. --full também sementeia o registro de perguntas, o índice, o quadro de dependências, o modelo de dados com seu registro de entidade e o gate de documentos
finish [--gates]O trabalho está concluído — todo repositório limpo, empurrado e apontado, nenhum lease mantido. check responde se o projeto está configurado corretamente; este responde se você terminou

$SKILL_DIR é o próprio diretório desta skill: ${CLAUDE_PLUGIN_ROOT}/skills/agent-sync no plugin do Claude Code, ~/.agents/skills/agent-sync em outros lugares. Resolva-o uma vez por sessão e reutilize-o — não adivinhe um caminho. Todo comando lê .claude/agent-sync.json da raiz do projeto e não precisa de argumentos além dos listados.

Uma identidade por sessão e como ela é decidida

Um lease só é um lease se dois agentes obtêm duas identidades. A ordem importa aqui e ambas as extremidades já morderam: derivar o id de CLAUDE_SESSION_ID sozinho deu a uma sessão duas identidades — ela adquiriu como uma e foi negada por seu próprio guarda como a outra — e manter um id por checkout deu a duas sessões uma identidade, o que é pior. A segunda é silenciosa: ambas as sessões adquirem, ambas são guardadas, e release pega um lease que o chamador nunca teve.

A ordem é: AGENT_SYNC_RUN_ID · CLAUDE_SESSION_ID · a sessão que iniciou este shell · compartilhado.

A terceira importa porque um comando shell simples não tem id de sessão e um hook tem. Então SessionStart carimba .agent-sync/sessions/<CLI pid> com a sessão que conhece, e um comando posterior se encontra percorrendo sua própria ancestralidade de processos até um pid carimbado. Por que isso e não análise de linha de comando: references/earned-rules.md.

Quando nenhum dos quatro pode ser estabelecido, a execução diz — "esta identidade é compartilhada com qualquer outra sessão neste checkout" — em vez de apresentar uma entrada compartilhada como separação.

Reivindicação — a forma que importa

acquire → faça o trabalho → release

Nunca pule release, inclusive em caso de falha: um lease abandonado bloqueia a tarefa até seu TTL expirar, e o próximo agente não pode distinguir "em andamento" de "caiu há uma hora".

O lease não é a reivindicação. O lease diz quem o detém agora e expira; a reivindicação durável é a tag no git, escrita por acquire e limpa por release. Um fato, um lar — não invente um terceiro lugar que registre propriedade.

Leia references/lease-protocol.md antes de alterar aquisição, expiração, roubo ou alocação de id.

Arquivos guardados

A configuração lista arquivos de registro que vários agentes escrevem. Antes de editar um:

python3 "$SKILL_DIR/scripts/agent_sync.py" guard docs/DECISIONS.md

Saída 2 é sobre esta execução: ela não detém lease — não que outra pessoa detenha aquele arquivo. Um lease cobre todos os arquivos guardados; segure um ou não escreva nenhum. Uma negação nomeia a outra execução e sua chave, porque "r-x detém um lease" ao lado de um caminho é repetido como "r-x detém este arquivo". Não edite mesmo assim e não "apenas corrija uma linha" — uma decisão sobrescrita parece exatamente uma decisão.

O hook PreToolUse do Claude Code executa isso por você. Em outros lugares, nada faz.

Reservando um id

Ler uma linha "Próximo ID livre" não é reservá-lo — dois agentes leem o mesmo número e ambos o usam.

python3 "$SKILL_DIR/scripts/agent_sync.py" reserve DEC   # → DEC-0216

A alocação é posicional sobre o log mesclado — todo fragmento, nunca apenas o desta execução — então todo agente calcula a mesma resposta. Reservado e não escrito no git? release-id ele, ou o número é um buraco que o quadro relata como vazamento.

Nada em um log é jamais editado ou excluído

Logs são reproduzidos em ordem, então uma edição reescreve silenciosamente uma conclusão sobre a qual outros agentes já agiram. Corrija anexando: libere um lease, release-id um id não utilizado, substitua uma entrada de 'construído' errada por uma posterior. Páginas geradas são a única exceção, e uma que perdeu sua marca agent-sync:generated

Habilidades Relacionadas