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
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
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.
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=1forç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:
| Linguagem | Extensões | Entidades |
|---|---|---|
| TypeScript | .ts .tsx .mts .cts | funções, classes, interfaces, tipos, enums, exports |
| JavaScript | .js .jsx .mjs .cjs .es6 | funções, classes, variáveis, exports |
| Python | .py .pyi | funções, classes, definições decoradas |
| Go | .go | funções, métodos, tipos, vars, consts |
| Rust | .rs | funções, structs, enums, impls, traits, mods, consts |
| Java | .java | classes, métodos, interfaces, enums, campos, construtores |
| C | .c .h | funções, structs, enums, unions, typedefs |
| C++ | .cpp .cc .cxx .hpp .hh .hxx | funções, classes, structs, enums, namespaces, templates |
| C# | .cs | classes, métodos, interfaces, enums, structs, propriedades |
| Ruby | .rb | métodos, classes, módulos |
| PHP | .php .inc .phtml .module | funções, classes, métodos, interfaces, traits, enums |
| Swift | .swift | funções, classes, protocolos, structs, enums, propriedades |
| Elixir | .ex .exs | módulos, funções, macros, guards, protocolos |
| Bash | .sh | funções |
| Fish | .fish | funções |
| Lua | .lua | funções (formas global, local, tabela e método) |
| HCL/Terraform | .hcl .tf .tfvars | blocos, atributos (nomes qualificados para blocos aninhados) |
| Kotlin | .kt .kts | classes, interfaces, objetos, funções, propriedades, companion objects |
| Fortran | .f90 .f95 .f03 .f08 .f .for | funções, sub-rotinas, módulos, programas |
| Vue | .vue | blocos template/script/style + entidades internas TS/JS |
| XML | .xml .plist .svg .csproj + mais 9 extensões MSBuild/recurso | elementos (aninhados, identidade por nome de tag) |
| ERB | .erb .html.erb | blocos, 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 .t | sub-rotinas, pacotes |
| Dart | .dart | classes, mixins, extensões, enums, aliases de tipo, funções |
| OCaml | .ml .mli | valores, módulos, tipos, classes, externals |
| Scala | .scala .sc .sbt .kojo .mill | classes, objetos, traits, enums, funções, vals, extensões |
| Nix | .nix | bindings, declarações inherit |
| Haskell | .hs | funções, assinaturas, tipos de dados, newtypes, classes, instâncias, sinônimos de tipo |
| Elm | .elm | declarações de valor, aliases de tipo, declarações de tipo, anotações de port, declarações infix |
| Clojure | .clj .cljs .cljc | vars, funções, macros, multimétodos, protocolos, registros, tipos |
| D | .d .di | módulos, funções, classes, structs, interfaces, unions, enums, templates, aliases, unittests |
| Zig | .zig | funções, testes, variáveis |
| SQL | .sql .psql .pgsql .ddl | tabelas, views, funções, índices, tipos, schemas, triggers, sequências |
Além disso, formatos de dados estruturados:
| Formato | Extensões | Entidades |
|---|---|---|
| JSON | .json | propriedades, objetos (caminhos RFC 6901) |
| YAML | .yml .yaml | seções, propriedades (caminhos de ponto) |
| TOML | .toml | seções, propriedades |
| EDN | .edn | entradas de mapa de nível superior (chaves de palavra-chave) |
| CSV | .csv .tsv | linhas (primeira coluna como identidade) |
| Markdown | .md .mdx | seções baseadas em títulos |
| LaTeX | .tex .latex .cls .sty | seçõ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:
- Correspondência exata de ID: mesma entidade antes/depois = modificada ou inalterada
- Correspondência de hash estrutural: mesma estrutura AST, nome diferente = renomeada ou movida (ignora espaços em branco/comentários)
- 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/grepcom 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
Licença
MIT OR Apache-2.0
