# ssh-cli
[](https://crates.io/crates/ssh-cli)
[](https://docs.rs/ssh-cli)
[](https://blog.rust-lang.org/2025/02/20/Rust-1.85.0.html)
[](LICENSE)
[](CODE_OF_CONDUCT.md)
> Dê a qualquer LLM poder SSH remoto em um binário one-shot seguro.
- Read this document in [English](README.md).
- Instale com `cargo install ssh-cli --locked` para grafo alinhado ao lockfile.
- Atualize com `cargo install ssh-cli --locked --force`.
- Verifique com `ssh-cli --version`.
- Leia o histórico em [CHANGELOG.pt-BR.md](CHANGELOG.pt-BR.md).
- Integre agentes via [docs/AGENTS.pt-BR.md](docs/AGENTS.pt-BR.md) e [INTEGRATIONS.pt-BR.md](INTEGRATIONS.pt-BR.md).
- Siga o primeiro uso em [docs/HOW_TO_USE.pt-BR.md](docs/HOW_TO_USE.pt-BR.md).
- Copie receitas de [docs/COOKBOOK.pt-BR.md](docs/COOKBOOK.pt-BR.md).
- Confira plataformas em [docs/CROSS_PLATFORM.pt-BR.md](docs/CROSS_PLATFORM.pt-BR.md).
- Migre de 0.3.3+ em [docs/MIGRATION.pt-BR.md](docs/MIGRATION.pt-BR.md) (linha alvo **0.3.6**).
- Execute testes via [docs/TESTING.pt-BR.md](docs/TESTING.pt-BR.md).
- Consuma contratos JSON em [docs/schemas/README.md](docs/schemas/README.md).
- Ensine LLMs com [skills/ssh-cli-pt/SKILL.md](skills/ssh-cli-pt/SKILL.md).
## O que é?
### CLI SSH multi-host one-shot para agentes
- Entregue um binário Rust único sem runtime Node e sem daemon.
- Opere N hosts VPS a partir de storage XDG sem arquivos `.env`.
- Autentique com senha ou chave privada por host.
- Execute `exec`, `sudo-exec` e `su-exec` como processos one-shot.
- Capture stdout e stderr com JSON estruturado para orquestração.
- Detecte locale entre `en-US` e `pt-BR`.
- Desative telemetria completamente em todo build.
## Por que ssh-cli?
### Substitua processos SSH de longa duração por um binário que morre após rodar
- Evite processos Node residentes que mantêm sockets abertos entre tarefas.
- Corte RAM e CPU de sessões SSH de longa duração.
- Cadastre credenciais multi-host uma vez no XDG com escrita atômica.
- Alinhe packing de comando e semântica dual maxChars com o contrato one-shot para agentes.
- Confie em host keys via TOFU known_hosts em vez de always-trust.
- Encaminhe erros com códigos sysexits que agentes classificam com segurança.
## Superpoderes
### Capacidades que tornam agentes produtivos
- CRUD multi-host com `vps add|list|show|edit|remove|path|doctor|export|import`
- Execução remota one-shot com `exec`, `sudo-exec` e `su-exec`
- Packing seguro de `sudo` via `sh -c` e escape de shell
- Auth por chave privada com passphrase opcional
- Limites dual `max_command_chars` e `max_output_chars`
- Timeout com abort remoto best-effort
- Tunnel limitado via `--timeout-ms` obrigatório
- SCP upload e download
- Health-check com latência
- Completions para bash zsh fish powershell
- Segredos via flags stdin para evitar leak em argv
- **Cifragem at-rest por padrão** (ChaCha20-Poly1305) com auto `secrets.key` XDG
- UX de master-key: `secrets status|init|reencrypt`
- known_hosts TOFU e escrita atômica do config com flock
- Pins crypto para `cargo install --locked` limpo (GAP-014)
## Início rápido
### Instale e rode o primeiro comando remoto
```bash
cargo install ssh-cli --locked
ssh-cli secrets init # opcional; auto-cria master-key na 1ª gravação de segredo
--host prod.example.com \
--port 22 \
--user admin \
--password-stdin
ssh-cli connect prod
ssh-cli exec prod "hostname" --json
```
## Instalação
### Escolha o caminho de install do seu ambiente
- Prefira crates.io com lockfile: `cargo install ssh-cli --locked` (após publicar **0.3.6**; até lá use git/path para a superfície completa).
- Rebuild a partir do checkout: `cargo install --path . --locked`
- **Não** use install sem `--locked` salvo se validou o resolve crypto com os pins.
- Force upgrade após release: `cargo install ssh-cli --locked --force`
- Compile musl com feature de alocador no Alpine: `--features musl-allocator`
- Exija Rust MSRV 1.85.0 ou superior
## Uso
### Cadastre hosts e execute comandos one-shot
- **Cifragem at-rest por padrão** (ChaCha20-Poly1305): auto `secrets.key` na primeira gravação; override via `SSH_CLI_SECRETS_KEY` / `_FILE` / keyring; gerencie com `ssh-cli secrets status|init|reencrypt`. Opt-out: `SSH_CLI_ALLOW_PLAINTEXT_SECRETS=1` (só testes).
- Prefira `--password-stdin` / `--key` a segredos em argv.
- Adicione hosts com senha via `vps add --password` ou `--password-stdin`.
- Adicione hosts com chave via `vps add --key ~/.ssh/id_ed25519`.
- Marque o host ativo com `connect <name>`.
- Rode shells remotos com `exec <vps> "<cmd>"`.
- Eleve com `sudo-exec` ou `su-exec` quando configurado.
- Diagnostique paths XDG com `vps doctor --json`.
- Exporte inventário com segredos mascarados via `vps export`.
## Comandos
### Superfície de produto para humanos e agentes
| `ssh-cli vps add` | Cadastra host (senha ou chave) |
| `ssh-cli vps list [--json]` | Lista hosts com segredos mascarados |
| `ssh-cli vps show <name> [--json]` | Mostra um host com segredos mascarados |
| `ssh-cli vps edit <name>` | Altera campos do host |
| `ssh-cli vps remove <name>` | Remove host |
| `ssh-cli vps path` | Imprime caminho do `config.toml` |
| `ssh-cli vps doctor [--json]` | Mostra camada XDG, schema e paths |
| `ssh-cli vps export` | Exporta hosts (segredos mascarados por padrão) |
| `ssh-cli vps import --file` | Importa hosts de TOML |
| `ssh-cli connect <name>` | Grava arquivo irmão `active` |
| `ssh-cli exec <vps> <cmd>` | Comando remoto one-shot |
| `ssh-cli sudo-exec <vps> <cmd>` | sudo one-shot com packing seguro |
| `ssh-cli su-exec <vps> <cmd>` | Elevação `su -` one-shot |
| `ssh-cli scp upload|download` | Transferência de arquivos |
| `ssh-cli tunnel ... --timeout-ms N` | Port-forward local com deadline |
| `ssh-cli health-check [<vps>]` | Sonda de conectividade |
| `ssh-cli secrets status|init|reencrypt` | Master-key e cifragem at-rest (nunca imprime a chave) |
| `ssh-cli completions <shell>` | Scripts de completion de shell |
## Variáveis de ambiente
### Overrides permitidos para testes e locales
| `SSH_CLI_HOME` | Sobrescreve diretório base de config | `/tmp/ssh-cli-test` |
| `SSH_CLI_LANG` | Sobrescreve locale | `pt-BR` |
| `SSH_CLI_SECRETS_KEY` | Master-key em 64 hex (cifra at-rest) | *(nunca logue)* |
| `SSH_CLI_SECRETS_KEY_FILE` | Arquivo com master-key hex 64 | `~/.config/ssh-cli/secrets.key` |
| `SSH_CLI_USE_KEYRING` | Usa keyring do SO para master-key | `1` |
| `SSH_CLI_ALLOW_PLAINTEXT_SECRETS` | Opt-out da cifragem default (**só testes**) | `1` |
| `NO_COLOR` | Desativa cores ANSI | `1` |
| `CLICOLOR_FORCE` | Força cores ANSI | `1` |
| `RUST_LOG` | Filtro de tracing | `debug` |
- Prefira flags CLI a environment em runs de agentes em produção.
- Nunca coloque senhas SSH em variáveis de ambiente; use inventário + stdin.
- Variáveis de master-key cifraram **segredos no disco**, não substituem senha SSH.
## Padrões de integração
### Conecte agentes só com subprocessos one-shot
- Invoque `ssh-cli` como subprocesso com argv explícito.
- Prefira `--json` ou `--output-format json` para parsing de máquina.
- Mapeie exits não zero com semântica sysexits antes de retry.
- Cadastre hosts uma vez via `vps add` e chame `exec` por tarefa.
- Passe segredos com `--password-stdin` quando history de argv for arriscado.
- Leia [INTEGRATIONS.pt-BR.md](INTEGRATIONS.pt-BR.md) para notas por agente.
## Exit codes
### Códigos no estilo sysexits que agentes devem mapear antes de retry
| `0` | Sucesso |
| `1` | Erro genérico de runtime |
| `64` | Uso / argumentos inválidos |
| `65` | Erro de dados (JSON/TOML/schema) |
| `66` | VPS ou arquivo de entrada não encontrado |
| `73` | Não foi possível criar config/saída |
| `74` | IO ou conexão/timeout SSH |
| `77` | Autenticação rejeitada ou host-key / política sudo |
| `130` | SIGINT |
| `143` | SIGTERM |
- Prefira `--json` ou JSON automático quando stdout não é TTY (`--output-format` sobrescreve).
- Faça retry só em IO/timeout transitório (`74`), nunca em auth (`77`) ou uso (`64`).
## Performance
### Metas de cold start e memória
- Busque cold start abaixo de 100 ms em hosts Linux modernos.
- Mantenha memória do processo bem abaixo de uma sessão daemon Node de longa duração residente.
- Morra após cada comando para devolver RAM ao SO imediatamente.
- Evite tunnels longos sem `--timeout-ms`.
## Requisitos de memória
### Planeje capacidade para inventários multi-host
- O TOML de config cresce com contagem de hosts e paths.
- Buffers de saída respeitam `max_output_chars` por stream.
- O arquivo known_hosts cresce devagar com pares host:port únicos.
- Nenhum modelo de embedding e nenhum heap Node são necessários.
## FAQ de troubleshooting
### Corrija falhas comuns de install e runtime
- Install falha em drift crypto RC: rode com `--locked` ou use a linha **0.3.6+** (`scripts/verify_install_resolve.sh`).
- Auth falha em hosts só-chave: defina `--key` em `vps add` ou passe `--key` / `--password-stdin` no `exec`.
- Auth falha com chave com passphrase: use `--key-passphrase-stdin`.
- Host key mudou: confirme legitimidade e rode com `--replace-host-key`.
- Comando rejeitado por tamanho: aumente `max_command_chars` ou encurte o comando.
- Config com secrets cifrados sem chave: rode `ssh-cli secrets init` ou restaure `secrets.key` / env.
- sudo-exec desabilitado: remova `--disable-sudo` e defina `disable_sudo=false` no host.
- macOS Gatekeeper bloqueia o binário: rode `xattr -d com.apple.quarantine /path/to/ssh-cli`.
- Permissão negada no config: garanta `chmod 600` no `config.toml` e no `secrets.key` XDG.
## Contribuindo
- Leia [CONTRIBUTING.pt-BR.md](CONTRIBUTING.pt-BR.md) antes de abrir pull request.
- Siga o framework bilíngue de documentação em toda mudança de doc pública.
## Segurança
- Leia [SECURITY.pt-BR.md](SECURITY.pt-BR.md) para reporte privado de vulnerabilidades.
- Prefira flags stdin de segredo e arquivos de chave a senhas em argv.
## Changelog
- Leia o histórico em [CHANGELOG.pt-BR.md](CHANGELOG.pt-BR.md).
- Não cole notas de release neste README.
## Licença
- Dual-license sob MIT ou Apache-2.0.
- Veja [LICENSE](LICENSE), [LICENSE-MIT](LICENSE-MIT) e [LICENSE-APACHE](LICENSE-APACHE).