Documentação oficial desta página · v0.20.6
Plugins de Ambiente de Terminal
O Hermes roda comandos de shell através de um conjunto plugável de backends de
terminal. Os backends embutidos (local, Docker, Singularity, Modal, Daytona, Vercel
Sandbox, SSH) ficam no repositório principal, em tools/environments/. Fornecedores
terceiros de sandbox integram como plugins — um repositório de plugin independente
instalado em ~/.hermes/plugins/, que registra um backend selecionado pelo usuário
exatamente como um embutido, via terminal.backend no config.yaml.
Esta página espelha o guia de Plugins de Navegador — mesmo fluxo de registro, mesma semântica de escopo.
O que um provedor controla
Um backend registrado participa automaticamente de todas as superfícies do núcleo:
| Superfície | Movida por |
|---|---|
Despacho de comandos (terminal, execute_code, ferramentas de arquivo) | create_environment() |
Seletor de backend do hermes setup | display_name, description, setup_instructions(), post_setup() |
| Seletor de backend de terminal do painel (status da sondagem) | probe() |
hermes status / hermes doctor | doctor_checks() |
| Dicas de ambiente no prompt de sistema | is_remote, env_description |
| Pular aprovação de comando perigoso | skip_container_guards |
| Tratamento de caminho/cwd em contêiner | is_container |
| Tradução de caminho de arquivo de cache sincronizado | cache_path_base |
| Remoção de segredos dos subprocessos criados | strip_env_keys |
Isolamento de sandbox por sessão (container_persistent: false) | session_isolated_when_nonpersistent |
Declarar essas flags no provedor elimina a clássica classe de bug "o novo backend esqueceu o ponto de classificação N" — o núcleo consulta o registro em cada ponto, em vez de uma lista fixa de nomes.
Provedor mínimo
from agent.terminal_env_provider import TerminalEnvironmentProvider
class AcmeBoxEnvironment:
"""Precisa satisfazer o contrato duck-typed de BaseEnvironment."""
def __init__(self, cwd, timeout, task_id):
self.cwd, self.timeout, self.task_id = cwd, timeout, task_id
def execute(self, command, timeout=None, **kwargs):
... # roda o comando no sandbox
return {"output": "...", "exit_code": 0}
def cleanup(self):
... # desliga / desconecta
class AcmeBoxProvider(TerminalEnvironmentProvider):
name = "acmebox"
display_name = "AcmeBox"
is_remote = True # os comandos não rodam na máquina local
is_container = True # semântica de caminho/cwd no estilo contêiner
@property
def description(self):
return "Rode comandos em um sandbox na nuvem do AcmeBox."
@property
def cache_path_base(self):
return "~/.hermes" # onde caem os arquivos de cache sincronizados, ou None
@property
def strip_env_keys(self):
return frozenset({"ACMEBOX_TOKEN"})
def is_available(self):
import importlib.util, os
return (
importlib.util.find_spec("acmebox") is not None
and bool(os.getenv("ACMEBOX_TOKEN"))
)
def create_environment(self, *, cwd, timeout, task_id="default",
image=None, container_config=None, **kwargs):
return AcmeBoxEnvironment(cwd, timeout, task_id)
def register(ctx):
ctx.register_terminal_environment_provider(AcmeBoxProvider())
name: acmebox
version: 0.1.0
description: Backend de terminal do sandbox na nuvem AcmeBox
kind: backend
Ative, selecione e rode:
hermes plugins enable acmebox
hermes config set terminal.backend acmebox
Regras
- Nomes reservados. Registros que colidem com o nome de um backend embutido
(
local,docker,singularity,modal,managed_modal,daytona,vercel_sandbox,ssh) são rejeitados. Plugins estendem o conjunto de backends; nunca substituem os backends que estão na árvore do projeto. create_environmentprecisa aceitar**kwargse ignorar chaves desconhecidas — é o contrato de compatibilidade futura que permite a assinatura da fábrica evoluir sem quebrar plugins antigos.is_available()/probe()precisam ser baratos. Nada de chamadas de rede — eles rodam durante a checagem de requisitos e na pintura da interface.- Falhe de forma suave em todo lugar. Um atributo do provedor que levanta exceção é
tratado pelo núcleo com o valor padrão (por exemplo, um
skip_container_guardsque levanta exceção mantém a camada de aprovação LIGADA). Não use exceções como fluxo de controle. - Segredos vão em
strip_env_keys. O token do seu fornecedor nunca pode ser legível por um comando de shell escrito pelo modelo; listá-lo o remove de todo subprocesso criado, incondicionalmente, como acontece com o tratamento embutido deMODAL_*/DAYTONA_API_KEY.
Contrato do objeto de ambiente
create_environment() devolve um objeto que satisfaz a mesma interface duck-typed de
tools.environments.base.BaseEnvironment:
execute(command, timeout=None, ...)→{"output": str, "exit_code": int}cleanup()— libera recursos; chamado no encerramento da sessão / na coleta por ociosidade- Opcional: hooks de persistência espelhando os backends de nuvem embutidos
Herdar de BaseEnvironment é recomendado (você ganha de graça o encanamento
compartilhado de sincronia de arquivos e de processos em segundo plano), mas não é
obrigatório.
Semântica de isolamento de sessão
Se o seu sandbox é retomado pelo nome (uma VM durável à qual o backend se reconecta),
defina session_isolated_when_nonpersistent = True. Com
terminal.container_persistent: false, cada sessão passa a ter a sua própria identidade
de sandbox em vez de compartilhar uma — sem isso, duas execuções efêmeras independentes
poderiam se conectar à mesma VM viva e apagá-la uma debaixo da outra.