shade-cli
O comando shade: cria, ensaia, testa, empacota e envia robôs da ShadeOne escritos com o
shade-sdk. O ciclo local roda sem conta; auth, deploy, releases e runs falam com a
plataforma pela chave de API, e shade mcp expõe o ciclo a um agente (Claude Code). Nunca importa o runtime no
próprio processo: o projeto roda em subprocesso, no venv dele (uv run na pasta), com o
shade-sdk que ele fixa.
uv tool install shade-cli
shade init cadastro-erp # starter de produção (--minimo para o enxuto)
cd cadastro-erp
uv run playwright install chromium
shade test # lint de contrato + pytest do projeto
shade run # ensaio: para antes de cada efetivar()
shade build # artefato determinístico em .shade/build/
Comandos
| Comando | Faz |
|---|---|
shade init <pasta> [--minimo] [--modelo lista|tarefa] [--editor vscode] [--id ID] [--nome NOME] [--sem-sync] |
o starter (produção por padrão) e o uv sync; nunca pergunta |
shade run [pasta] [--real [--sim]] [--entrada ARQ] [--item CHAVE] [--debug] [--trace] [--como-plataforma] [--headless] |
ensaio por padrão; --real pede TTY ou --sim |
shade test [pasta] |
lint (L1 a L8) e o pytest do projeto |
shade build [pasta] |
projeto.tar.gz (o mesmo pacote que a plataforma monta de uma gravação) e manifesto.json em .shade/build/; recusa o plugin de [plugins] que a imagem não tem, ou cujos hosts e credenciais o projeto não declara, e o estado de sessão do robô (a sessao_salva, ou um storage_state do Playwright) que o .gitignore não ignora |
shade doctor [pasta] |
Python, uv, Chromium do Playwright, Docker, o plugin do Claude Code e o shade-sdk do projeto |
shade docs [tópico] [--pasta P] |
a referência da versão do shade-sdk do projeto |
shade claude-code instalar |
instala (ou atualiza) o plugin do Claude Code desta versão da CLI: as skills /shade-* e o shade mcp |
shade inspecionar <url> [--pagina Nome] [--pasta P] |
abre a página no Chromium (contexto efêmero, rede só em [hosts] permitidos), grava o que você clica e preenche, e propõe Pagina com Alvos já conferidos pelo diagnóstico do SDK; Enter no terminal encerra (--headless varre a página sem janela) |
Com a chave de API
| Comando | Faz |
|---|---|
shade auth login [--url URL] |
lê a chave sem eco (ou de uma linha do stdin, sem terminal), confere com a plataforma e guarda URL, chave e workspace no keyring do sistema |
shade auth status |
de onde vem a conta, o workspace e os escopos da chave, conferidos agora |
shade auth logout |
apaga a conta do keyring |
shade deploy [pasta] [--criar] [--nao-esperar] [--prazo S] |
confere /sdk/compat, monta o artefato em memória, envia e acompanha recebida → conferida → em ensaio → aguardando aprovação; o robo.id novo pede --criar sem terminal |
shade releases list [pasta] [--robo ID] [--limite N] |
as versões do robô |
shade releases show <id> [--esperar] [--prazo S] |
uma versão; com --esperar, acompanha como o deploy |
shade releases ensaiar <id> [--esperar] [--prazo S] |
repete o ensaio que caiu por infraestrutura ou esperava credencial |
SHADE_API_KEY e SHADE_URL vencem o keyring (o caminho do CI). A chave nunca é argumento,
nunca vai para arquivo e sai redigida de todo texto. http:// só para localhost.
O deploy é idempotente: o mesmo código dá o mesmo sha256, e o servidor devolve a release que
já existe. Se a CLI cair no meio, repetir shade deploy (ou shade releases show <id> --esperar) retoma a mesma versão. O prazo da espera (10 min) sai 6 com esse comando.
Tudo o que a CLI escreve num projeto fica em .shade/ (que se ignora sozinho no git): o
git status do projeto continua limpo depois de qualquer comando, menos o init.
Servidor MCP (shade mcp)
shade mcp [--pasta P] sobe um servidor MCP local, por stdio, sem porta, para o Claude Code (ou
outro cliente MCP) escrever, testar e enviar o robô com ferramentas observáveis. Vem num extra:
uv tool install 'shade-cli[mcp]'
shade claude-code instalar # no Claude Code: o plugin registra o shade mcp
# em outro cliente MCP, ou sem o plugin, na pasta do projeto:
claude mcp add shade -- shade mcp
Use um dos dois: o plugin e o claude mcp add sobem o mesmo servidor duas vezes. Quem já tinha
o claude mcp add e instala o plugin tira o antigo com claude mcp remove shade.
O projeto é o shade.toml mais próximo do diretório em que o cliente sobe o servidor (ou
--pasta), fixo na sessão. A chave vem do keyring (shade auth login) ou de SHADE_API_KEY
e SHADE_URL. As ferramentas listadas são as que a chave e o projeto permitem: sem projeto, só
as da plataforma; sem chave, só as locais; chave só de leitura, nada que envie.
| Risco | Ferramentas | Precisa |
|---|---|---|
| local, sem rede | ler_manifesto, montar_artefato, rodar_lint |
o projeto |
| leitura da plataforma | listar_robos, ver_release, listar_runs, ver_run, listar_itens, ver_falha, buscar_eventos, ler_gravacao |
processes:read ou runs:read |
| navegação local | snapshot_da_pagina (árvore de acessibilidade e Alvos candidatos), conferir_seletor (em que elemento um Alvo cai) |
o projeto |
| executa código local | rodar_testes (shade test), rodar_ensaio (shade run em ensaio, headless) |
o projeto |
| envia sem pessoa | enviar_release (shade deploy, até aguardando_aprovacao) |
o projeto e releases:write |
Recursos: shade://sdk/referencia, shade://projeto/manifesto, shade://projeto/ultimo-ensaio,
shade://protocolo/runtime e shade://ferramentas/schema; cada um tem o equivalente em
ferramenta ou em shade docs.
O que o servidor garante, e o que não garante:
- Nenhuma ferramenta roda o robô em modo real, aprova nem ativa uma versão. O ensaio para
antes de cada
efetivar(); o--realfica no terminal, com você. - A resposta é o documento do
--json, comcomando= o nome da ferramenta, redigida pelo mesmo serializador: cada valor do.env, das credenciais declaradas, da chave e de variável com nome de segredo sai como[redigido], também URL-encoded e em base64. Nenhuma ferramenta lê.env, keyring, cookie ou o conteúdo de um trace; a captura da falha sai como caminho, tamanho e sha256. - O texto que veio do cliente (o log do run, a página, a gravação) chega só em
dados.cliente({"dados_do_cliente": true, "origem", "truncado", "conteudo"}), sem caractere de controle e com teto de 16 KiB e 200 linhas. É rótulo e teto, não barreira contra injeção: o modelo lê os mesmos tokens. Ids, estados e contagens ficam no topo, conferidos pela forma. Na gravação, todo valor digitado sai como[digitado]. - Caminhos são relativos ao projeto e presos a ele (
.., absoluto, symlink para fora e laço caem);.env*,.git/,*.peme.shade/credenciaissão recusados. Leitura até 256 KiB por arquivo, listagens até 500 entradas. - O navegador é sempre um Chromium headless num contexto novo (nunca o seu perfil, sem
service worker, sem download, sem o storage de outra chamada), com a rede só em
[hosts] permitidos, em HTTP e WebSocket, salto a salto nos redirecionamentos. IP privado, loopback, link-local,localhoste*.localsó passam listados por inteiro. O que a página pediu fora da lista volta embloqueados. Risco que fica: o DNS rebinding de um nome da lista.
Plugin do Claude Code
O plugin vem na wheel, na mesma versão das ferramentas que as skills encadeiam (o que cada skill faz está no README do plugin):
uv tool install 'shade-cli[mcp]'
shade claude-code instalar
O comando copia o plugin para ~/.shade/claude-code/, um marketplace local do Claude Code, e
roda claude plugin marketplace add ~/.shade/claude-code, claude plugin install shade@shadeone
e claude plugin update shade@shadeone (escopo user: vale em qualquer pasta). Pede o claude no
PATH. Para atualizar, uv tool upgrade shade-cli e o mesmo comando; o shade doctor avisa quando
o plugin ficou atrás da CLI. Para tirar: claude plugin uninstall shade@shadeone.
CI
A mesma sequência em qualquer CI: instalar a CLI numa versão exata, shade test, shade deploy. A chave vem de SHADE_API_KEY, num segredo do CI e no env do job, nunca em argumento nem
em arquivo. Sem terminal a CLI nunca pergunta (--criar diz que o robô novo é de propósito), e o
--json põe o resultado no stdout. A release fica aguardando a aprovação de uma pessoa: o CI não
ativa nada. A saída 6 (prazo da espera) não é falha: a release segue no servidor e o
erro.recuperacao do JSON traz shade releases show <id> --esperar.
GitHub. A Action shade-deploy (.github/actions/shade-deploy/) roda essa sequência e devolve
os outputs release_id, project_sha256 e estado, lidos do JSON. O shade init já gera o
workflow com ela (job publicar, na branch padrão):
- uses: SamuelPerroni/shade-one/.github/actions/shade-deploy@cli-v0.1.6
env:
SHADE_API_KEY: ${{ secrets.SHADE_API_KEY }}
with:
versao-da-cli: "0.1.6" # exata; sem latest
# pasta: robos/cadastro # onde está o shade.toml (padrão: a raiz)
# url-da-plataforma: https://... # sem ela, vale o SHADE_URL ou o padrão da CLI
O repositório do ShadeOne é privado: para outro repositório usar a Action, libere o acesso em Settings > Actions > General > Access do repositório do ShadeOne.
GitLab.
publicar:
image: ghcr.io/astral-sh/uv:python3.14-bookworm
script:
- uv tool install shade-cli==0.1.6
- export PATH="$(uv tool dir --bin):$PATH"
- uv sync --locked
- shade test --json
- shade deploy --json --criar | tee deploy.json
- python3 -c "import json; print(json.load(open('deploy.json'))['dados']['estado'])"
variables:
SHADE_API_KEY: $SHADE_API_KEY # variável mascarada do projeto
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
Azure Pipelines.
- script: |
pip install uv
uv tool install shade-cli==0.1.6
export PATH="$(uv tool dir --bin):$PATH"
uv sync --locked
shade test --json
shade deploy --json --criar
displayName: Publicar o robô
env:
SHADE_API_KEY: $(SHADE_API_KEY) # variável secreta: mapeie-a em env, o Azure não a expõe sozinho
Nos dois, o código de saída é o do shade: 1 gate reprovado, 3 chave, 6 prazo (retome com o
comando do JSON), 7 rede. Trate o 6 como aviso se quiser o comportamento da Action.
--json e códigos de saída
Com --json, um documento no stdout; progresso e logs no stderr, redigidos:
{"versao": 1, "comando": "build", "ok": false, "dados": {},
"erro": {"codigo": "lint_reprovado", "mensagem": "L3 robo.py:1 import fora do lock: yaml",
"recuperacao": "corrija o que o lint aponta (shade test mostra a lista inteira)"}}
| Código | Significado |
|---|---|
| 0 | ok (inclusive o deploy que acha a release existente, e a release que espera uma pessoa: aprovar ou preencher o cofre) |
| 1 | gate, lint ou teste reprovou; release reprovada na conferência ou no ensaio (e o defeito da própria CLI, com erro.codigo = "erro_interno") |
| 2 | uso inválido ou shade.toml inválido; robô novo sem --criar |
| 3 | chave ausente, recusada ou sem o escopo (401/403) |
| 4 | conflito de estado (409): ensaiar uma release reprovada, a release arquivada |
| 5 | incompatibilidade de versão: o shade-sdk do projeto não é o da imagem, ou o /sdk/compat não casa |
| 6 | o prazo da espera acabou; a release segue no servidor (erro.recuperacao traz a retomada) |
| 7 | rede ou servidor indisponível (5xx, 429) |
| 130 | interrompido (Ctrl-C, SIGTERM ou SIGHUP: o robô em andamento morre junto) |
Lint de contrato
| Regra | Efeito | O quê |
|---|---|---|
| L3 | reprova | import de pacote fora do lock da imagem e dos plugins da imagem que o projeto declara em [plugins] |
| L7 | reprova (avisa no run) |
credencial lida sem declaração, ou o valor dela chegando a goto, ao HTTP do Playwright, a shade_sdk.http ou a arquivo |
| L8 | reprova | entrada ausente ou inválida (main.py, [robo] classe, arquivo que não compila) |
| L1 | avisa | subprocess, os.system, os.exec*, os.fork, ctypes, multiprocessing |
| L2 | avisa | socket, http.client, urllib.request, requests, httpx, aiohttp |
| L4 | avisa | eval, exec, compile, import dinâmico |
| L5 | avisa | caminho literal fora do workdir |
| L6 | avisa | clique ou envio em alvo com cara de submissão fora de efetivar() |
O lint não é controle de segurança: quem isola o robô é o executor da plataforma.
Desenvolvimento
cd cli && uv sync
uv run pytest -q -m "not starter" # rápido
uv run pytest -q -m starter # os starters de verdade: uv sync, Chromium, ~45 s
src/shade_cli/imagem.py é a cópia do requirements.lock da imagem do run:
backend/tests/test_hu294_artefato_da_cli.py a confere, e confere que o artefato do
shade build passa no ler() do backend.
Metadata
Release files for shade-cli 0.1.16
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| shade_cli-0.1.16-py3-none-any.whl | Python 3 | none | any | Details |
Release files / shade_cli-0.1.16-py3-none-any.whl
| Download URL | shade_cli-0.1.16-py3-none-any.whl |
|---|---|
| Size | 174.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a32dfb1230d857cdcfe2bb987308ce269677609802ec38143d9064c073b7ff93
|
|
BLAKE2b-256 checksum How to use checksums |
c1b1450971cc5a8ed8d75312b3020816feaeaffe16526cd8c25c6b364d4c72a6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Security for shade-cli 0.1.16
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.