Python Code Validator

Prova que o Python gerado por IA faz o que você pediu: declare a intenção como asserções e o servidor executa o código em um contêiner restrito, retornando uma correção somente quando todos os exemplos passam.

Documentação

Python Code Validator

Um servidor MCP que valida, repara e executa Python contra os exemplos que deve satisfazer — validate_python, repair_python e execute_python via HTTP em https://api.statemind.ai/mcp, com uma chave gratuita e sem conta.

Um serviço hospedado que prova que o Python gerado por IA faz o que você pediu. Declare a intenção — asserções ou linhas de doctest — e o código é executado contra ela dentro de um contêiner sem rede e com sistema de arquivos somente leitura; uma correção só volta quando todos os exemplos passam. Nos defeitos do QuixBugs, isso é 41% reparados e 77% recusados por não fazerem o que dizem, sem falsos alarmes nos programas corrigidos — onde ruff e mypy sinalizam o defeito em nenhum deles (os números).

As verificações que não precisam de intenção vêm com ele: diagnósticos de sintaxe e lint, uma política de segurança AST que também captura chamadas escondidas atrás de importações dinâmicas e buscas de atributos em tempo de execução, uma passada de bandit, uma varredura de credenciais e reparo determinístico — um veredito com uma pontuação. Perguntar a mesma coisa duas vezes em dez minutos é respondido pela primeira resposta e não custa nada (x-msvc-repeat: 1).

Este repositório contém o lado do cliente: a configuração MCP, o script de CI e o hook de pre-commit. O serviço em si roda em https://api.statemind.ai, então não há nada para instalar ou hospedar.

Uma chave, sem conta

curl -s -X POST https://api.statemind.ai/v1/keys
# {"api_key": "msvc_free_…", "tier": "free", "calls_per_day": 25, "modes": ["static"]}

25 verificações estáticas por dia, medidas por dia UTC, e algumas chaves por endereço: o suficiente para experimentar e rodar em um projeto pequeno, não um suprimento. Cada resposta traz o estado da cota (x-quota-remaining, x-quota-reset), para que um cliente possa recuar antes de ser cortado.

MCP

Registrado no registro oficial do MCP como ai.statemind/python-code-validator, um nome verificado contra o domínio que o serve, em vez de uma conta do GitHub. Qualquer cliente MCP o adiciona com um bloco:

{
  "mcpServers": {
    "python-code-validator": {
      "type": "http",
      "url": "https://api.statemind.ai/mcp",
      "headers": { "Authorization": "Bearer msvc_free_…" }
    }
  }
}
  • Claude Code: claude mcp add --transport http python-code-validator https://api.statemind.ai/mcp --header "Authorization: Bearer msvc_free_…"
  • Cursor: ~/.cursor/mcp.json, mesmo bloco.
  • VS Code / Copilot: .vscode/mcp.json sob "servers".

Um cliente que apenas lança um comando usa a ponte stdio deste repositório, que encaminha a mesma ferramenta via HTTPS:

{
  "mcpServers": {
    "python-code-validator": {
      "command": "python3",
      "args": ["/path/to/python-code-validator/mcp_stdio.py"]
    }
  }
}

Ou como um contêiner, que o Dockerfile aqui constrói:

docker build -t python-code-validator .
docker run -i --rm -e VALIDATOR_API_KEY python-code-validator

O Gemini CLI instala a mesma ponte como uma extensão, com o arquivo de instrução que faz com que ela seja usada:

gemini extensions install jkanselaar/python-code-validator

Três ferramentas, nomeadas pelo que fazem com o código:

ferramentaexecuta o códigochave
validate_pythonnãográtis
repair_python — também retorna fixed_codenãopago
execute_python — também o executa em um sandboxsimpago

A antiga ferramenta única python_code_validator, com seu argumento mode, ainda responde para clientes que já a configuraram, mas não é mais listada.

Dizendo o que o código deveria fazer

Toda verificação acima passa em uma função que calcula a resposta errada. A única coisa que a pega é a intenção, e o agente que pediu o código é o único que a tem — então passe-a adiante:

{"code": "def bitcount(n): …", "mode": "execute",
 "options": {"examples": "assert bitcount(127) == 7"}}

Linhas de doctest (>>> bitcount(127) e depois 7) funcionam da mesma forma, assim como exemplos >>> já escritos no código-fonte. execute_python os executa no sandbox: um que não se sustenta é um erro python:example-mismatch, e a busca de reparo retorna uma correção apenas quando todos os exemplos passam. No conjunto de defeitos do QuixBugs — bugs reais, entradas de teste ocultas decidindo a correção — isso repara 41% e recusa 77% por não fazerem o que dizem, sem falsos alarmes nos programas corrigidos.

Repetir uma chamada não custa nada: a mesma chave perguntando a mesma coisa — mesmo modo, mesmo código, mesmos exemplos — é respondida pela resposta que já obteve, marcada como x-msvc-repeat: 1, para que um agente que verifica seu trabalho a cada passo não seja cobrado por vereditos que não podem ter mudado.

Plugin do Claude Code

Uma instrução pode ser ignorada; um hook não. O plugin verifica cada arquivo Python que o Claude Code escreve ou edita, na vez em que foi escrito, e devolve os erros ao modelo em vez de a você:

/plugin marketplace add jkanselaar/python-code-validator
/plugin install python-code-validator@statemind

Nada para configurar: ele gera e mantém sua própria chave gratuita no primeiro uso. Um arquivo que volta aceito é silencioso, um rejeitado interrompe a vez com as linhas ofensoras nomeadas, e um arquivo idêntico não é perguntado duas vezes. Ele nunca encerra uma sessão por causa de seus próprios problemas — um serviço inacessível ou uma cota gasta deixa a vez continuar, e a cota diz como aumentá-la.

Defina VALIDATOR_API_KEY para usar uma chave paga em vez do nível gratuito, e VALIDATOR_URL para apontar para sua própria implantação. O plugin também carrega a habilidade validate-python, para a parte que um hook não pode fazer: declarar a intenção como exemplos e executar o código contra eles.

Hook do Cursor

O mesmo script, conectado ao postToolUse do Cursor, onde o veredito volta como contexto na conversa em vez de como código de saída:

mkdir -p .cursor/hooks
base=https://raw.githubusercontent.com/jkanselaar/python-code-validator/main
curl -sf $base/plugin/hooks/validate_written.py -o .cursor/hooks/validate_written.py
curl -sf $base/cursor/hooks.json -o .cursor/hooks.json

Hooks de projeto rodam a partir da raiz do projeto, por isso o comando em cursor/hooks.json é um caminho relativo a ela. Para um hook que se aplica a todos os projetos, coloque o script em ~/.cursor/hooks/ e o mesmo bloco em ~/.cursor/hooks.json com o comando python3 ./hooks/validate_written.py --cursor.

Fazendo o agente usá-lo

Configurar o servidor não é o que faz com que ele seja chamado: o arquivo de instrução é. AGENTS.md neste repositório é esse texto, escrito para ser colocado em qualquer projeto sob o nome que o cliente lê:

mkdir -p .github
curl -sf https://raw.githubusercontent.com/jkanselaar/python-code-validator/main/AGENTS.md \
  | tee AGENTS.md CLAUDE.md GEMINI.md .github/copilot-instructions.md >/dev/null

O Cursor lê regras com front matter, então essa é um arquivo separado — copie .cursor/rules/python-code-validator.mdc para .cursor/rules/ do projeto.

A versão curta, se você preferir adicionar uma linha às instruções que já tem:

Escreva o que o código deve fazer como exemplos assert antes de escrever o código, e passe-os em options.examples. Chame validate_python após cada edição e execute_python assim que uma função estiver terminada, não novamente até que o que ela faz tenha mudado. Quando uma chamada retornar fixed_code, aceite-a — o serviço o executou contra seus exemplos. Não apresente código que voltou valid: false.

CI

O serviço distribui o cliente, então um workflow não precisa de checkout deste repositório nem de segredo:

- run: |
    curl -sf https://api.statemind.ai/v1/client -o validate.py
    python3 validate.py --changed-against "origin/${{ github.base_ref }}"

Ou como uma action, do Marketplace:

permissions:
  contents: read
  pull-requests: write   # so the run can comment its result on the pull request
steps:
  - uses: jkanselaar/python-code-validator@v1.22.0
    with:
      api-key: ${{ secrets.VALIDATOR_API_KEY }}   # optional; free tier without it

O Python alterado é validado e as linhas ofensoras são anotadas no diff, falhando o job em erros de sintaxe e padrões inseguros. Arquivos que o serviço recusa de imediato (acima do limite de 200 kB) são ignorados com um aviso em vez de falhar a execução.

A execução também deixa um comentário no pull request, editado no lugar em pushes posteriores em vez de repetido: o que foi aceito, o que foi reparado e quanto da cota do dia resta. Sem pull-requests: write nada é escrito e o job não é afetado; comment: "false" desliga isso.

No nível gratuito, a action mantém sua chave no cache do workflow, uma por repositório por dia, então a cota pertence ao repositório em vez da execução. Com api-key definido, o cache é ignorado.

Pre-commit

repos:
  - repo: https://github.com/jkanselaar/python-code-validator
    rev: v1.22.0
    hooks:
      - id: python-code-validator

O cliente em si

validate.py é apenas biblioteca padrão, então também funciona como python validate.py file.py em um Makefile, um hook do git ou um contêiner:

$ python3 validate.py service.py
::error file=service.py,line=88,title=SyntaxError::invalid syntax
FAIL service.py score=0.66

0/1 files accepted

VALIDATOR_API_KEY é usado quando definido; caso contrário, o cliente gera uma chave gratuita — mantendo-a em VALIDATOR_KEY_FILE quando isso nomeia um caminho, que é como uma série de execuções compartilha uma cota. VALIDATOR_URL aponta para outra implantação. VALIDATOR_SOURCE nomeia o chamador, que é apenas contado: uma execução dentro de um workflow diz github-action por si só.

O selo

Um repositório cujo Python é verificado em cada pull request pode dizer isso:

[![Python validated](https://img.shields.io/badge/python-validated-2ea44f?logo=python&logoColor=white)](https://api.statemind.ai/?src=badge)

Python validated

HTTP

curl -s https://api.statemind.ai/v1/validate \
  -H "Authorization: Bearer $VALIDATOR_API_KEY" \
  -H 'content-type: application/json' \
  -d '{"code": "def f(:\n    pass\n", "mode": "static"}'

mode é static, repair ou execute; repair e execute precisam de uma chave configurada. O código enviado não é registrado.

Uma chamada recusada diz o que fazer a respeito, para que um chamador sem operador a quem perguntar possa resolver por si só:

{"error": "payment_required",
 "remedy": {"action": "upgrade_key", "hint": "A free key covers static only. …"}}

Pagando por chamadas

Uma chave gratuita cobre 25 verificações estáticas por dia, e um endereço recebe algumas chaves por dia, então a cota é um teste em vez de um suprimento. Além disso, uma chave carrega créditos: uma verificação estática custa 1, um reparo 3 e uma execução em sandbox 10, e uma chamada idêntica repetida em dez minutos é respondida pela primeira gratuitamente.

Créditos são comprados com cartão, sem fatura ou alguém a quem perguntar:

curl -s -X POST https://api.statemind.ai/v1/keys/checkout \
  -H 'content-type: application/json' \
  -d '{"api_key": "'"$VALIDATOR_API_KEY"'", "credits": 500}'

Isso responde com uma página de Stripe Checkout; os créditos estão na chave segundos após o cartão ser aprovado (500 créditos são €10). Um agente com uma carteira Gnosis pode, em vez disso, pagar em xDAI sem navegador — GET /v1/pricing declara ambas as rotas.

Exemplos

examples/ contém três arquivos e o cliente para enviá-los: um que passa em todas as verificações e ainda retorna o número errado, um que a política de segurança recusa, e um que volta aceito do sandbox.

Licença

MIT.