sem-mcp

Inteligência de código em nível de entidade para agentes

Documentação

Parte da stack Ataraxy Labs: infraestrutura nativa para agentes no desenvolvimento de software. Veja também: weave (driver de merge git em nível de entidade) · inspect (revisão de código semântica) · opensessions (sidebar tmux para agentes de codificação).

Leia o manifesto: https://ataraxy-labs.com/#thesis · Ensaios: https://ataraxy-labs.com/blogs · LLMs: https://ataraxy-labs.com/llms.txt

sem

Ataraxy-Labs%2Fsem | Trendshift

Controle de versão semântico construído sobre Git.
Em vez de linhas alteradas, o sem informa quais entidades mudaram: funções, métodos, classes.

Por que sem? · Instalação · Comandos · Agentes (MCP) · Consentimento na nuvem · Versões

Release Rust Tests License Languages

O sem é uma ferramenta de controle de versão semântico que funciona sobre o Git. Ele analisa seu código com tree-sitter, extrai cada função, classe e método como uma entidade, e faz o diff no nível de entidade em vez de linhas. Isso significa que você vê "a função blahh foi modificada" em vez de "as linhas x-y mudaram."

Funciona em qualquer repositório Git sem configuração.

Consultas com suporte na nuvem são opcionais por repositório: fazer login não envia um repositório nem uma consulta. Veja o fluxo de consentimento na nuvem para os estados de repositório público/privado, tela de pré-visualização, registro de auditoria local e controles de esquecimento.

sem diff

Instalação

curl -fsSL https://raw.githubusercontent.com/Ataraxy-Labs/sem/main/install.sh | sh

Ou via Homebrew:

brew install sem-cli

Ou via winget no Windows:

winget install AtaraxyLabs.sem

Ou via Scoop no Windows:

scoop install sem

Ou instale o wrapper npm em node_modules:

npm install --save-dev @ataraxy-labs/sem

Com Bun, confie no pacote para que seu script postinstall possa baixar o binário:

bun add -d @ataraxy-labs/sem
bun pm trust @ataraxy-labs/sem

Uma vez instalado, atualize para a versão mais recente a qualquer momento:

sem update

Ou via cargo, a partir do crates.io:

cargo install sem-cli

Ou compile o main mais recente a partir do código-fonte (requer Rust):

cargo install --git https://github.com/Ataraxy-Labs/sem sem-cli

Ou pegue um binário em GitHub Releases.

Ou execute via Docker:

docker build -t sem .
docker run --rm -it -u "$(id -u):$(id -g)" -v "$(pwd):/repo" sem diff

Conflito de nome com GNU Parallel

O GNU Parallel inclui um binário sem (/usr/bin/sem) como um symlink para parallel. Se você tiver ambos instalados, eles entrarão em conflito. Execute sem --version para verificar qual você está usando. (#77)

Correções rápidas:

# Option 1: alias in your shell profile (~/.bashrc, ~/.zshrc)
alias sem="$HOME/.cargo/bin/sem"

# Option 2: make sure cargo bin comes first in PATH
export PATH="$HOME/.cargo/bin:$PATH"

# Option 3: if installed via Homebrew
export PATH="$(brew --prefix)/bin:$PATH"

Se você instalou via npm/bun, o binário fica em node_modules/.bin/sem e é invocado por meio de npx sem ou bunx sem, o que evita o conflito completamente.

Comandos

Funciona em qualquer repositório Git. Sem configuração necessária. Também funciona fora do Git para comparação arbitrária de arquivos.

O sem armazena seu cache de entidades SQLite fora do repositório, sob o diretório de cache do sistema operacional por padrão. Defina SEM_CACHE_DIR=/path/to/cache para substituir a raiz do cache; substituições locais do repositório são ignoradas para que os arquivos de cache não sujem a árvore de trabalho.

sem diff

Diff em nível de entidade com detecção de renomeação, hashing estrutural e realces inline em nível de palavra.

# Semantic diff of working changes
sem diff

# Staged changes only
sem diff --staged

# Specific commit
sem diff --commit abc1234

# Commit range
sem diff --from HEAD~5 --to HEAD

# Verbose mode (word-level inline diffs for each entity)
sem diff -v

# Plain text output (git status style)
sem diff --format plain

# JSON output (for AI agents, CI pipelines)
sem diff --format json

# Markdown output (for PRs, reports)
sem diff --format markdown

# Compare any two files (no git repo needed)
sem diff file1.ts file2.ts

# Read file changes from stdin (no git repo needed)
echo '[{"filePath":"src/main.rs","status":"modified","beforeContent":"...","afterContent":"..."}]' \
  | sem diff --stdin --format json

# Only specific file types
sem diff --file-exts .py .rs

sem impact

O grafo de dependências entre arquivos mostra o que quebra se uma entidade mudar.

# Full impact analysis
sem impact authenticateUser

# Direct dependencies only
sem impact authenticateUser --deps

# Direct dependents only
sem impact authenticateUser --dependents

# Affected tests only
sem impact authenticateUser --tests

# JSON output
sem impact authenticateUser --json

# Disambiguate by file
sem impact authenticateUser --file src/auth.ts

# Include default-excluded paths such as generated, fixture, vendor, benchmark, and build trees
sem impact authenticateUser --no-default-excludes

sem blame

Blame em nível de entidade mostrando quem modificou por último cada função, classe ou método.

sem blame src/auth.ts

# JSON output
sem blame src/auth.ts --json

sem log

Acompanhe como uma única entidade evoluiu através do histórico do git.

sem log authenticateUser

# Verbose mode (show content diff between versions)
sem log authenticateUser -v

# Limit commits scanned
sem log authenticateUser --limit 20

# JSON output
sem log authenticateUser --json

Sem entidade, o sem log analisa o histórico recente do repositório no nível de entidade: hotspots (funções/classes mais alteradas, com contagens de autores) e pares de co-mudança (entidades que mudam repetidamente nos mesmos commits: "se você tocar em uma, não esqueça da outra"):

sem log                 # repo hotspots + co-change pairs (last 50 commits)
sem log --limit 200     # deeper history
sem log --file src/auth.ts   # scoped to one file
sem log --json          # full data

sem entities

Lista todas as entidades sob um caminho de arquivo ou diretório. Sem caminho é o mesmo que ..

sem entities

sem entities .

sem entities src/auth.ts

# JSON output
sem entities --json
sem entities src/auth.ts --json

# Include default-excluded paths such as generated, fixture, vendor, benchmark, and build trees
sem entities --no-default-excludes

sem context

Contexto com orçamento de tokens para LLMs: a entidade, suas dependências e seus dependentes, ajustados a um orçamento estrito de tokens de conteúdo. Quando a própria assinatura alvo não cabe, a saída JSON relata target_omitted: true.

sem context authenticateUser

# Custom token budget
sem context authenticateUser --budget 4000

# JSON output
sem context authenticateUser --json

# Include default-excluded paths such as generated, fixture, vendor, benchmark, and build trees
sem context authenticateUser --no-default-excludes

sem find / callers / refs / grep

Consultas de inicialização a frio apoiadas por um índice de consulta em disco, mapeável por mmap (index.sem, armazenado ao lado do cache de entidades SQLite). A primeira chamada em um repositório constrói o índice; toda chamada depois disso o lê diretamente, sem daemon ou processo em segundo plano:

# Find where an entity is defined
sem find "function diff_command"

# Who calls it
sem callers diff_command

# What it calls
sem refs diff_command

# Text search across source files (rg-compatible file:line:text output,
# served from the index's trigram postings when one exists)
sem grep "TODO"

# JSON output on any of the above
sem find diff_command --json

Medido neste repositório (crates/) com time: a primeira sem find (índice ainda não construído) levou 185ms; a segunda chamada contra o mesmo repositório, uma vez que o índice existia, levou 7ms. Execute você mesmo; os números exatos dependerão da sua máquina e do tamanho do repositório. O ponto é a lacuna frio-vs-quente: nenhum daemon precisa permanecer ativo para que o número quente se mantenha.

sem graph

Imprime o grafo completo de dependências de entidades para o repositório atual, ou --json para a lista de arestas subjacente (o mesmo grafo sobre o qual sem impact e sem context são construídos):

sem graph
sem graph --json

sem stats

Contadores locais e cumulativos: quantos diffs o sem executou neste ambiente e quanto disso foi ruído filtrado. Nada aqui sai da sua máquina (veja Telemetria):

sem stats

Usar como diff padrão do Git

Substitua a saída de git diff por diffs em nível de entidade. Agentes e humanos recebem a saída do sem automaticamente sem mudar nenhum comando.

sem setup

Agora o git diff mostra mudanças em nível de entidade em vez de nível de linha. Sem prompts, sem configuração de agente necessária. Tudo que chama git diff recebe a saída do sem automaticamente. Também instala um hook de pre-commit que mostra o raio de impacto em nível de entidade das mudanças preparadas.

No macOS e Linux, o sem setup também registra um hook UserPromptSubmit do Claude Code (sem hook prompt-submit) para injeção de contexto no momento do prompt. Ele edita ~/.claude/settings.json de forma idempotente, faz backup primeiro e deixa quaisquer hooks que você já tenha intactos.

Para desativar e voltar ao git diff normal (também remove os hooks de sessão):

sem unsetup

Diffs em nível de entidade em todo pull request

Adicione a GitHub Action e cada PR recebe um comentário fixo mostrando quais funções, classes e métodos mudaram. Ele atualiza no lugar a cada push e destaca explicitamente PRs apenas cosméticos (formatação/comentários):

# .github/workflows/entity-diff.yml
name: Entity diff
on: pull_request
permissions:
  contents: read
  pull-requests: write
jobs:
  entity-diff:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: Ataraxy-Labs/sem/action@v0.23.1

Sem configuração, sem chaves de API, nunca falha seu build. Veja action/ para detalhes.

Aceleração na nuvem (para escala e equipes)

Local é sempre gratuito e sempre rápido: o índice em disco responde consultas do dia a dia em milissegundos de dígito único mesmo a partir de um processo frio, então não há nada para manter aquecido e nenhum login necessário. Você não paga para deixar seu laptop rápido.

A nuvem é para o que um laptop não pode fazer. Em um monorepo muito grande, a primeira construção do grafo local pode levar alguns segundos; um grafo de equipe compartilhado não deveria ser reconstruído por desenvolvedor; e o CI quer o grafo sem fazer checkout de nada. O sem login conecta esses casos à nuvem do sem, que mantém um grafo aquecido e pré-construído para seus repositórios registrados e atende as consultas pesadas a partir dele em vez de reconstruir localmente.

sem login                              # GitHub device flow, one time
sem impact myFunc --file src/foo.rs    # served from the cloud's warm graph

É totalmente opcional e transparente:

  • Não logado, ou a nuvem está inacessível? O sem calcula localmente e imprime exatamente a mesma saída. Sem falhas, sem diferença nos resultados.
  • SEM_LOCAL=1 força o cálculo local mesmo quando logado.
  • Repositórios pequenos não veem mudança, o local já é rápido. A vantagem é para bases de código grandes onde reconstruir o grafo a cada vez é o gargalo.

Comandos relacionados, todos no escopo da conta na nuvem:

sem logout          # log out
sem whoami          # show current cloud identity
sem cloud status    # cloud + telemetry state for this repo (offline; sends nothing)
sem cloud enable    # turn on cloud queries for a public repo (shows what's sent first)
sem cloud share     # same, with extra confirmation, for a private repo
sem cloud forget    # delete this repo's cloud index and unregister it
sem xref --json     # cross-repo dependencies across your indexed repos
sem repos           # where your code is stored: cloud-indexed repos + local caches

O sem cloud --help lista todos os subcomandos (list, preview, log, never incluídos); cada um é somente leitura ou requer confirmação explícita antes de enviar qualquer coisa.

Se sua equipe executa revisão de código através da nuvem do sem, o sem review listen <diff-id-or-url> executa um agente de codificação pré-configurado para participar dessa revisão como um ouvinte ao vivo que responde perguntas do revisor ancoradas em linhas específicas do diff.

O que ele analisa

32 linguagens de programação com extração completa de entidades via tree-sitter:

LinguagemExtensõesEntidades
TypeScript.ts .tsx .mts .ctsfunções, classes, interfaces, tipos, enums, exports
JavaScript.js .jsx .mjs .cjs .es6funções, classes, variáveis, exports
Python.py .pyifunções, classes, definições decoradas
Go.gofunções, métodos, tipos, vars, consts
Rust.rsfunções, structs, enums, impls, traits, mods, consts
Java.javaclasses, métodos, interfaces, enums, campos, construtores
C.c .hfunções, structs, enums, unions, typedefs
C++.cpp .cc .cxx .hpp .hh .hxxfunções, classes, structs, enums, namespaces, templates
C#.csclasses, métodos, interfaces, enums, structs, propriedades
Ruby.rbmétodos, classes, módulos
PHP.php .inc .phtml .modulefunções, classes, métodos, interfaces, traits, enums
Swift.swiftfunções, classes, protocolos, structs, enums, propriedades
Elixir.ex .exsmódulos, funções, macros, guards, protocolos
Bash.shfunções
Fish.fishfunções
Lua.luafunções (formas global, local, tabela e método)
HCL/Terraform.hcl .tf .tfvarsblocos, atributos (nomes qualificados para blocos aninhados)
Kotlin.kt .ktsclasses, interfaces, objetos, funções, propriedades, companion objects
Fortran.f90 .f95 .f03 .f08 .f .forfunções, sub-rotinas, módulos, programas
Vue.vueblocos template/script/style + entidades internas TS/JS
XML.xml .plist .svg .csproj + mais 9 extensões MSBuild/recursoelementos (aninhados, identidade por nome de tag)
ERB.erb .html.erbblocos, expressões, tags de código
Svelte.svelte .svelte.js .svelte.ts (+ variantes .test/.spec)blocos de componente + módulos JS/TS de rune
Perl.pl .pm .tsub-rotinas, pacotes
Dart.dartclasses, mixins, extensões, enums, aliases de tipo, funções
OCaml.ml .mlivalores, módulos, tipos, classes, externals
Scala.scala .sc .sbt .kojo .millclasses, objetos, traits, enums, funções, vals, extensões
Nix.nixbindings, declarações inherit
Haskell.hsfunções, assinaturas, tipos de dados, newtypes, classes, instâncias, sinônimos de tipo
Elm.elmdeclarações de valor, aliases de tipo, declarações de tipo, anotações de port, declarações infix
Clojure.clj .cljs .cljcvars, funções, macros, multimétodos, protocolos, registros, tipos
D.d .dimódulos, funções, classes, structs, interfaces, unions, enums, templates, aliases, unittests
Zig.zigfunções, testes, variáveis
SQL.sql .psql .pgsql .ddltabelas, views, funções, índices, tipos, schemas, triggers, sequências

Além disso, formatos de dados estruturados:

FormatoExtensõesEntidades
JSON.jsonpropriedades, objetos (caminhos RFC 6901)
YAML.yml .yamlseções, propriedades (caminhos de ponto)
TOML.tomlseções, propriedades
EDN.ednentradas de mapa de nível superior (chaves de palavra-chave)
CSV.csv .tsvlinhas (primeira coluna como identidade)
Markdown.md .mdxseções baseadas em títulos
LaTeX.tex .latex .cls .styseções (parte/capítulo/seção/…), além de teorema/lema/prova/figura/tabela/algoritmo e outros ambientes rastreados

Todo o resto recai na comparação de diffs baseada em chunks.

Extensões personalizadas e arquivos sem extensão

Para arquivos com extensões não padrão, crie um .semrc na raiz do seu projeto:

.xyz = cpp
.j = json
.mypy = python

sem também lê padrões .gitattributes (diff= e linguist-language=) se você já os tiver configurado. .semrc tem prioridade quando ambos definem a mesma extensão.

Para arquivos sem extensão alguma, sem detecta o idioma automaticamente a partir do conteúdo (linhas shebang, modelines vim e heurísticas estruturais como declarações package/import/use). Isso cobre mais de 30 idiomas sem necessidade de configuração.

Como funciona a correspondência

Correspondência de entidades em três fases:

  1. Correspondência exata de ID: mesma entidade antes/depois = modificada ou inalterada
  2. Correspondência de hash estrutural: mesma estrutura AST, nome diferente = renomeada ou movida (ignora espaços em branco/comentários)
  3. Similaridade difusa: sobreposição de tokens >80% = provável renomeação

Isso significa que sem detecta renomeações e movimentações, não apenas adições e exclusões. O hash estrutural também distingue alterações cosméticas (espaços em branco, formatação) de alterações reais de lógica.

Uso com agentes de IA (MCP)

No macOS e Linux, clientes no mesmo checkout compartilham um daemon de repositório ativo. Execute sem mcp --status para verificá-lo. Consulte o contrato de runtime compartilhado e benchmark reproduzível para isolamento de sessão, comportamento de fallback e limites atuais da plataforma.

sem mcp inicia um servidor Model Context Protocol via stdin/stdout. Não é um comando que você executa e lê você mesmo: é um servidor que seu agente de codificação inicia em segundo plano para que ele possa fazer perguntas ao sem enquanto trabalha. Essa é a razão pela qual mcp fica junto aos comandos normais. O agente obtém 8 ferramentas de nível de entidade que espelham a CLI: sem_entities, sem_diff, sem_blame, sem_impact, sem_log, sem_context, sem_find, sem_grep. (Se você também estiver usando sem cloud para revisão de código, mais quatro ferramentas permitem que um agente se anexe a uma revisão e responda perguntas do revisor em um loop: join_review, wait_for_branch, reply_to_branch, list_open_branches.)

Por que um agente quer isso: em vez de ler arquivos inteiros e queimar tokens, ele pode perguntar "o que quebra se eu mudar submitOrder" (sem_impact) ou "me dê apenas o contexto para refatorar esta função" (sem_context, que retorna o código-fonte da função mais seus chamadores e chamados) e obter uma resposta precisa e determinística do grafo de dependências em vez de um resultado de grep que pode perder um chamador.

Adicione uma vez e depois converse com seu agente normalmente. Ele chama as ferramentas por conta própria.

Claude Code:

claude mcp add sem -- sem mcp

Ou um comando que também instala a skill, para que o agente saiba quando recorrer ao sem:

npx @ataraxy-labs/sem-skill

Cursor, Claude Desktop ou qualquer cliente com uma configuração mcpServers:

{
  "mcpServers": {
    "sem": {
      "command": "sem",
      "args": ["mcp"]
    }
  }
}

Se sem não estiver no PATH do agente, use o caminho absoluto para o binário. Nenhuma instalação separada é necessária: sem mcp vem no mesmo binário que todos os outros comandos.

Saída JSON

sem diff --format json

Saída real, de uma alteração de lógica de uma linha em uma função Python:

{
  "summary": {
    "fileCount": 1,
    "added": 0,
    "modified": 1,
    "deleted": 0,
    "moved": 0,
    "renamed": 0,
    "reordered": 0,
    "binary": 0,
    "orphan": 0,
    "total": 1
  },
  "changes": [
    {
      "entityId": "auth.py::function::authenticate_user",
      "changeType": "modified",
      "entityType": "function",
      "entityName": "authenticate_user",
      "startLine": 1,
      "endLine": 6,
      "oldStartLine": 1,
      "oldEndLine": 4,
      "oldEntityName": null,
      "filePath": "auth.py",
      "oldFilePath": null,
      "oldParentId": null,
      "beforeContent": "def authenticate_user(username, password):\n    if not username or not password:\n        return False\n    return check_credentials(username, password)",
      "afterContent": "def authenticate_user(username, password):\n    if not username or not password:\n        return False\n    if not check_credentials(username, password):\n        return False\n    return True",
      "commitSha": null,
      "author": null,
      "structuralChange": true
    }
  ],
  "binaryChanges": []
}

Os buckets nomeados de tipo de alteração (added, modified, deleted, moved, renamed, reordered) sempre somam total. orphan é uma contagem de metadados transversal para alterações de nível de módulo, e essas alterações já estão incluídas nos buckets nomeados de tipo de alteração. beforeContent/afterContent carregam o código-fonte completo da entidade em ambos os lados da alteração; structuralChange é false quando o diff é apenas cosmético (espaços em branco, comentários).

Como biblioteca

sem-core pode ser usado como dependência de biblioteca Rust, a partir do crates.io:

[dependencies]
sem-core = "0.23"

Usado por weave (driver de merge semântico) e inspect (revisão de código em nível de entidade).

Arquitetura

  • tree-sitter para análise de código (Rust nativo, não WASM)
  • git2 para operações Git
  • rayon para processamento paralelo de arquivos
  • xxhash para hash estrutural
  • Um diretório de cache por repositório (cache de entidades SQLite + um índice de consulta mmap-able) dá suporte a find/callers/refs/grep com consultas de processo a frio e sem daemon em segundo plano
  • Sistema de plugins para adicionar novos idiomas e formatos (veja CONTRIBUTING.md)

Telemetria

Local por padrão: sem conta nomes de comandos (por exemplo, diff, impact) apenas na sua própria máquina, e nesse modo nada é enviado. Nenhum código, caminho de arquivo, nome de repositório ou identidade de usuário é registrado, e nenhuma chamada de rede é feita.

sem telemetry preview   # see current mode and exactly what would be sent
sem telemetry on        # opt in: also upload counts to help improve sem
sem telemetry off       # record nothing at all

SEM_NO_TELEMETRY=1 ou DO_NOT_TRACK=1 forçam o comportamento de não registrar nada, independentemente do modo. Builds de desenvolvimento (qualquer coisa executada a partir de um diretório cargo build target/) nunca registram, então trabalhar no próprio sem não polui os números.

Contribuindo

Quer adicionar um novo idioma? Veja CONTRIBUTING.md para um guia passo a passo.

Histórico de Estrelas

Star History Chart

Licença

MIT OR Apache-2.0